+ return r;
+}
+
+static void entry_free(struct entry* e) {
+ pa_assert(e);
+
+ pa_xfree(e->port);
+ pa_xfree(e);
+}
+
+static bool entry_write(struct userdata *u, const char *name, const struct entry *e) {
+ pa_tagstruct *t;
+ pa_datum key, data;
+ bool r;
+
+ pa_assert(u);
+ pa_assert(name);
+ pa_assert(e);
+
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu8(t, e->version);
+ pa_tagstruct_put_boolean(t, e->port_valid);
+ pa_tagstruct_puts(t, e->port);
+
+ key.data = (char *) name;
+ key.size = strlen(name);
+
+ data.data = (void*)pa_tagstruct_data(t, &data.size);
+
+ r = (pa_database_set(u->database, &key, &data, true) == 0);
+
+ pa_tagstruct_free(t);
+
+ return r;
+}
+
+static struct entry* entry_read(struct userdata *u, const char *name) {
+ pa_datum key, data;
+ struct entry *e = NULL;
+ pa_tagstruct *t = NULL;
+ const char* port;
+
+ pa_assert(u);
+ pa_assert(name);
+
+ key.data = (char*) name;
+ key.size = strlen(name);
+
+ pa_zero(data);
+
+ if (!pa_database_get(u->database, &key, &data))
+ goto fail;
+
+ t = pa_tagstruct_new(data.data, data.size);
+ e = entry_new();
+
+ if (pa_tagstruct_getu8(t, &e->version) < 0 ||
+ e->version > ENTRY_VERSION ||
+ pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
+ pa_tagstruct_gets(t, &port) < 0) {
+
+ goto fail;
+ }
+
+ if (!pa_tagstruct_eof(t))
+ goto fail;
+
+ e->port = pa_xstrdup(port);
+
+ pa_tagstruct_free(t);
+ pa_datum_free(&data);
+
+ return e;
+
+fail:
+
+ pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
+
+ if (e)
+ entry_free(e);
+ if (t)
+ pa_tagstruct_free(t);
+
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+{
+ struct perportentry *ppe;
+ pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
+ if (legacy_entry_read(u, &data, &e, &ppe)) {
+ bool written = false;
+
+ pa_log_debug("Success. Saving new format for key: %s", name);
+ written = entry_write(u, name, e);
+
+ /* Now convert the legacy entry into per-port entries */
+ if (0 == strncmp("sink:", name, 5)) {
+ pa_sink *sink;
+
+ if ((sink = pa_namereg_get(u->core, name+5, PA_NAMEREG_SINK))) {
+ /* Write a "null" port entry. The read code will automatically try this
+ * if it cannot find a specific port-named entry. */
+ written = perportentry_write(u, name, NULL, ppe) || written;
+ }
+ } else if (0 == strncmp("source:", name, 7)) {
+ pa_source *source;
+
+ if ((source = pa_namereg_get(u->core, name+7, PA_NAMEREG_SOURCE))) {
+ /* Write a "null" port entry. The read code will automatically try this
+ * if it cannot find a specific port-named entry. */
+ written = perportentry_write(u, name, NULL, ppe) || written;
+ }
+ }
+ perportentry_free(ppe);
+
+ if (written)
+ /* NB The device type doesn't matter when we pass in an invalid index. */
+ trigger_save(u, PA_DEVICE_TYPE_SINK, PA_INVALID_INDEX);
+
+ pa_datum_free(&data);
+ return e;
+ }
+ pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
+}
+#endif
+
+ pa_datum_free(&data);
+ return NULL;
+}
+
+static struct entry* entry_copy(const struct entry *e) {
+ struct entry* r;
+
+ pa_assert(e);
+ r = entry_new();
+ r->version = e->version;
+ r->port_valid = e->port_valid;
+ r->port = pa_xstrdup(e->port);
+
+ return r;
+}
+
+static bool entries_equal(const struct entry *a, const struct entry *b) {
+
+ pa_assert(a && b);
+
+ if (a->port_valid != b->port_valid ||
+ (a->port_valid && !pa_streq(a->port, b->port)))
+ return false;
+
+ return true;
+}
+
+static struct perportentry* perportentry_new(bool add_pcm_format) {
+ struct perportentry *r = pa_xnew0(struct perportentry, 1);
+ r->version = PERPORTENTRY_VERSION;