2 This file is part of PulseAudio.
4 Copyright 2009 Nokia Corporation
5 Contact: Maemo Multimedia <multimedia@maemo.org>
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <sys/types.h>
34 #include <pulse/xmalloc.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/hashmap.h>
43 typedef struct simple_data {
50 typedef struct entry {
55 void pa_datum_free(pa_datum *d) {
63 static int compare_func(const void *a, const void *b) {
64 const pa_datum *aa, *bb;
66 aa = (const pa_datum*)a;
67 bb = (const pa_datum*)b;
69 if (aa->size != bb->size)
70 return aa->size > bb->size ? 1 : -1;
72 return memcmp(aa->data, bb->data, aa->size);
75 /* pa_idxset_string_hash_func modified for our use */
76 static unsigned hash_func(const void *p) {
82 d = (const pa_datum*)p;
85 for (i = 0; i < d->size; i++) {
86 hash = 31 * hash + (unsigned) *c;
93 static entry* new_entry(const pa_datum *key, const pa_datum *data) {
99 e = pa_xnew0(entry, 1);
100 e->key.data = key->size > 0 ? pa_xmemdup(key->data, key->size) : NULL;
101 e->key.size = key->size;
102 e->data.data = data->size > 0 ? pa_xmemdup(data->data, data->size) : NULL;
103 e->data.size = data->size;
107 static void free_entry(entry *e) {
110 pa_xfree(e->key.data);
112 pa_xfree(e->data.data);
117 static int read_uint(FILE *f, uint32_t *res) {
123 items = fread(&values, sizeof(values), sizeof(uint8_t), f);
125 if (feof(f)) /* EOF */
131 for (i = 0; i < 4; ++i) {
133 *res += (tmp << (i*8));
139 static int read_data(FILE *f, void **data, ssize_t *length) {
141 uint32_t data_len = 0;
148 if ((items = read_uint(f, &data_len)) <= 0)
152 *data = pa_xmalloc0(data_len);
153 items = fread(*data, data_len, 1, f);
155 if (feof(f)) /* EOF */
163 } else { /* no data? */
176 static int fill_data(simple_data *db, FILE *f) {
181 pa_bool_t append = FALSE;
182 enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY;
192 while (!read_data(f, &d, &l)) {
208 entry *e = pa_xnew0(entry, 1);
209 e->key.data = key.data;
210 e->key.size = key.size;
211 e->data.data = data.data;
212 e->data.size = data.size;
213 pa_hashmap_put(db->map, &e->key, e);
220 pa_log_warn("read error. %s", pa_cstrerror(errno));
221 pa_database_clear((pa_database*)db);
224 if (field == FIELD_DATA && d)
227 return pa_hashmap_size(db->map);
230 pa_database* pa_database_open(const char *fn, pa_bool_t for_write) {
237 path = pa_sprintf_malloc("%s."CANONICAL_HOST".simple", fn);
240 f = fopen(path, "r");
242 if (f || errno == ENOENT) { /* file not found is ok */
243 db = pa_xnew0(simple_data, 1);
244 db->map = pa_hashmap_new(hash_func, compare_func);
245 db->filename = pa_xstrdup(path);
246 db->tmp_filename = pa_sprintf_malloc(".%s.tmp", db->filename);
247 db->read_only = !for_write;
261 return (pa_database*) db;
264 void pa_database_close(pa_database *database) {
265 simple_data *db = (simple_data*)database;
268 pa_database_sync(database);
269 pa_database_clear(database);
270 pa_xfree(db->filename);
271 pa_xfree(db->tmp_filename);
272 pa_hashmap_free(db->map, NULL, NULL);
276 pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) {
277 simple_data *db = (simple_data*)database;
284 e = pa_hashmap_get(db->map, key);
289 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
290 data->size = e->data.size;
295 int pa_database_set(pa_database *database, const pa_datum *key, const pa_datum* data, pa_bool_t overwrite) {
296 simple_data *db = (simple_data*)database;
307 e = new_entry(key, data);
309 if (pa_hashmap_put(db->map, &e->key, e) < 0) {
310 /* entry with same key exists in hashmap */
313 r = pa_hashmap_remove(db->map, key);
314 pa_hashmap_put(db->map, &e->key, e);
316 /* wont't overwrite, so clean new entry */
327 int pa_database_unset(pa_database *database, const pa_datum *key) {
328 simple_data *db = (simple_data*)database;
334 e = pa_hashmap_remove(db->map, key);
343 int pa_database_clear(pa_database *database) {
344 simple_data *db = (simple_data*)database;
349 while ((e = pa_hashmap_steal_first(db->map)))
355 signed pa_database_size(pa_database *database) {
356 simple_data *db = (simple_data*)database;
359 return (signed) pa_hashmap_size(db->map);
362 pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) {
363 simple_data *db = (simple_data*)database;
369 e = pa_hashmap_first(db->map);
374 key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
375 key->size = e->key.size;
378 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
379 data->size = e->data.size;
385 pa_datum* pa_database_next(pa_database *database, const pa_datum *key, pa_datum *next, pa_datum *data) {
386 simple_data *db = (simple_data*)database;
396 return pa_database_first(database, next, data);
398 search = pa_hashmap_get(db->map, key);
403 while ((e = pa_hashmap_iterate(db->map, &state, NULL))) {
414 next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
415 next->size = e->key.size;
418 data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
419 data->size = e->data.size;
425 static int write_uint(FILE *f, const uint32_t num) {
431 for (i = 0; i < 4; i++)
432 values[i] = (num >> (i*8)) & 0xFF;
434 items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
442 static int write_data(FILE *f, void *data, const size_t length) {
447 if ((items = write_uint(f, len)) <= 0)
450 items = fwrite(data, length, 1, f);
452 if (ferror(f) || items != 1)
458 static int write_entry(FILE *f, const entry *e) {
462 if (write_data(f, e->key.data, e->key.size) < 0)
464 if (write_data(f, e->data.data, e->data.size) < 0)
470 int pa_database_sync(pa_database *database) {
471 simple_data *db = (simple_data*)database;
483 f = fopen(db->tmp_filename, "w");
489 while((e = pa_hashmap_iterate(db->map, &state, NULL))) {
490 if (write_entry(f, e) < 0) {
491 pa_log_warn("error while writing to file. %s", pa_cstrerror(errno));
499 if (rename(db->tmp_filename, db->filename) < 0) {
500 pa_log_warn("error while renaming file. %s", pa_cstrerror(errno));