mas01cr@498: extern "C" { mas01cr@498: #include "audioDB_API.h" mas01cr@509: } mas01cr@498: #include "audioDB-internals.h" mas01cr@498: mas01cr@498: static bool audiodb_check_header(adb_header_t *header) { mas01cr@498: /* FIXME: use syslog() or write to stderr or something to give the mas01cr@498: poor user some diagnostics. */ mas01cr@509: if(header->magic == ADB_OLD_MAGIC) { mas01cr@498: return false; mas01cr@498: } mas01cr@509: if(header->magic != ADB_MAGIC) { mas01cr@498: return false; mas01cr@498: } mas01cr@509: if(header->version != ADB_FORMAT_VERSION) { mas01cr@498: return false; mas01cr@498: } mas01cr@509: if(header->headerSize != ADB_HEADER_SIZE) { mas01cr@498: return false; mas01cr@498: } mas01cr@498: return true; mas01cr@498: } mas01cr@498: mas01cr@498: static int audiodb_collect_keys(adb_t *adb) { mas01cr@498: char *key_table = 0; mas01cr@498: size_t key_table_length = 0; mas01cr@498: mas01cr@498: if(adb->header->length > 0) { mas01cr@498: unsigned nfiles = adb->header->numFiles; mas01cr@509: key_table_length = align_page_up(nfiles * ADB_FILETABLE_ENTRY_SIZE); mas01cr@596: malloc_and_fill_or_goto_error(char *, key_table, adb->header->fileTableOffset, key_table_length); mas01cr@498: for (unsigned int k = 0; k < nfiles; k++) { mas01cr@509: adb->keys->push_back(key_table + k*ADB_FILETABLE_ENTRY_SIZE); mas01cr@509: (*adb->keymap)[(key_table + k*ADB_FILETABLE_ENTRY_SIZE)] = k; mas01cr@498: } mas01cr@592: free(key_table); mas01cr@498: } mas01cr@498: mas01cr@498: return 0; mas01cr@498: mas01cr@498: error: mas01cr@596: maybe_free(key_table); mas01cr@498: return 1; mas01cr@498: } mas01cr@498: mas01cr@498: static int audiodb_collect_track_lengths(adb_t *adb) { mas01cr@498: uint32_t *track_table = 0; mas01cr@498: size_t track_table_length = 0; mas01cr@498: if(adb->header->length > 0) { mas01cr@498: unsigned nfiles = adb->header->numFiles; mas01cr@509: track_table_length = align_page_up(nfiles * ADB_TRACKTABLE_ENTRY_SIZE); mas01cr@596: malloc_and_fill_or_goto_error(uint32_t *, track_table, adb->header->trackTableOffset, track_table_length); mas01cr@498: off_t offset = 0; mas01cr@498: for (unsigned int k = 0; k < nfiles; k++) { mas01cr@498: uint32_t track_length = track_table[k]; mas01cr@498: adb->track_lengths->push_back(track_length); mas01cr@498: adb->track_offsets->push_back(offset); mas01cr@498: offset += track_length * adb->header->dim * sizeof(double); mas01cr@498: } mas01cr@592: free(track_table); mas01cr@498: } mas01cr@498: mas01cr@498: return 0; mas01cr@498: mas01cr@498: error: mas01cr@596: maybe_free(track_table); mas01cr@498: return 1; mas01cr@498: } mas01cr@498: mas01cr@693: static int audiodb_init_rng(adb_t *adb) { mas01cr@693: gsl_rng *rng = gsl_rng_alloc(gsl_rng_mt19937); mas01cr@693: if(!rng) { mas01cr@693: return 1; mas01cr@693: } mas01cr@693: /* FIXME: maybe we should use a real source of entropy? */ mas01cr@693: uint32_t seed = 0; mas01cr@693: #ifdef WIN32 mas01cr@693: seed = time(NULL); mas01cr@693: #else mas01cr@693: struct timeval tv; mas01cr@693: if(gettimeofday(&tv, NULL) == -1) { mas01cr@693: return 1; mas01cr@693: } mas01cr@693: /* usec field should be less than than 2^20. We want to mix the mas01cr@693: usec field, highly-variable, into the high bits of the seconds mas01cr@693: field, which will be static between closely-spaced runs. -- CSR, mas01cr@693: 2010-01-05 */ mas01cr@693: seed = tv.tv_sec ^ (tv.tv_usec << 12); mas01cr@693: #endif mas01cr@693: gsl_rng_set(rng, seed); mas01cr@693: adb->rng = rng; mas01cr@693: return 0; mas01cr@693: } mas01cr@693: mas01cr@498: adb_t *audiodb_open(const char *path, int flags) { mas01cr@498: adb_t *adb = 0; mas01cr@498: int fd = -1; mas01cr@498: mas01cr@498: flags &= (O_RDONLY|O_RDWR); mas01cr@498: fd = open(path, flags); mas01cr@498: if(fd == -1) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: if(acquire_lock(fd, flags == O_RDWR)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: mas01cr@498: adb = (adb_t *) calloc(1, sizeof(adb_t)); mas01cr@498: if(!adb) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->fd = fd; mas01cr@498: adb->flags = flags; mas01cr@498: adb->path = (char *) malloc(1+strlen(path)); mas01cr@498: if(!(adb->path)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: strcpy(adb->path, path); mas01cr@498: mas01cr@498: adb->header = (adb_header_t *) malloc(sizeof(adb_header_t)); mas01cr@498: if(!(adb->header)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@509: if(read(fd, (char *) adb->header, ADB_HEADER_SIZE) != ADB_HEADER_SIZE) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: if(!audiodb_check_header(adb->header)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: mas01cr@498: adb->keys = new std::vector; mas01cr@498: if(!adb->keys) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->keymap = new std::map; mas01cr@498: if(!adb->keymap) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: if(audiodb_collect_keys(adb)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->track_lengths = new std::vector; mas01cr@498: if(!adb->track_lengths) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->track_lengths->reserve(adb->header->numFiles); mas01cr@498: adb->track_offsets = new std::vector; mas01cr@498: if(!adb->track_offsets) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->track_offsets->reserve(adb->header->numFiles); mas01cr@498: if(audiodb_collect_track_lengths(adb)) { mas01cr@498: goto error; mas01cr@498: } mas01cr@498: adb->cached_lsh = 0; mas01cr@693: if(audiodb_init_rng(adb)) { mas01cr@693: goto error; mas01cr@693: } mas01cr@498: return adb; mas01cr@498: mas01cr@498: error: mas01cr@498: if(adb) { mas01cr@596: maybe_free(adb->header); mas01cr@596: maybe_free(adb->path); mas01cr@498: if(adb->keys) { mas01cr@498: delete adb->keys; mas01cr@498: } mas01cr@498: if(adb->keymap) { mas01cr@498: delete adb->keymap; mas01cr@498: } mas01cr@498: if(adb->track_lengths) { mas01cr@498: delete adb->track_lengths; mas01cr@498: } mas01cr@693: if(adb->rng) { mas01cr@693: gsl_rng_free(adb->rng); mas01cr@693: } mas01cr@498: free(adb); mas01cr@498: } mas01cr@498: if(fd != -1) { mas01cr@498: close(fd); mas01cr@498: } mas01cr@498: return NULL; mas01cr@498: }