view open.cpp @ 596:6ad0a6e67d4c

Take advantage of those new handy _or_goto_error macros Use them in various places where previously we either elided the error checking (various lseek() calls) or used a combination of calls (replaced by malloc_and_fill_or_goto_error()). In the process, fix what is probably a bug (or else introduce one, but I don't think so): audiodb_track_id_datum() computed the offset into the timesTable wrongly, forgetting to multiply by 2. (TODO: this should be easily testable using the API). Now all of LIBOBJS can be produced by my (Debian's) mingw32 cross-compiler, except for lshlib.o.
author mas01cr
date Tue, 11 Aug 2009 21:42:49 +0000
parents cfa74bcc1249
children b1723ae7675e
line wrap: on
line source
extern "C" {
#include "audioDB_API.h"
}
#include "audioDB-internals.h"

static bool audiodb_check_header(adb_header_t *header) {
  /* FIXME: use syslog() or write to stderr or something to give the
     poor user some diagnostics. */
  if(header->magic == ADB_OLD_MAGIC) {
    return false;
  }
  if(header->magic != ADB_MAGIC) {
    return false;
  }
  if(header->version != ADB_FORMAT_VERSION) {
    return false;
  }
  if(header->headerSize != ADB_HEADER_SIZE) {
    return false;
  }
  return true;
}

static int audiodb_collect_keys(adb_t *adb) {
  char *key_table = 0;
  size_t key_table_length = 0;

  if(adb->header->length > 0) {
    unsigned nfiles = adb->header->numFiles;
    key_table_length = align_page_up(nfiles * ADB_FILETABLE_ENTRY_SIZE);
    malloc_and_fill_or_goto_error(char *, key_table, adb->header->fileTableOffset, key_table_length);
    for (unsigned int k = 0; k < nfiles; k++) {
      adb->keys->push_back(key_table + k*ADB_FILETABLE_ENTRY_SIZE);
      (*adb->keymap)[(key_table + k*ADB_FILETABLE_ENTRY_SIZE)] = k;
    }
    free(key_table);
  }

  return 0;

 error:
  maybe_free(key_table);
  return 1;
}

static int audiodb_collect_track_lengths(adb_t *adb) {
  uint32_t *track_table = 0;
  size_t track_table_length = 0;
  if(adb->header->length > 0) {
    unsigned nfiles = adb->header->numFiles;
    track_table_length = align_page_up(nfiles * ADB_TRACKTABLE_ENTRY_SIZE);
    malloc_and_fill_or_goto_error(uint32_t *, track_table, adb->header->trackTableOffset, track_table_length);
    off_t offset = 0;
    for (unsigned int k = 0; k < nfiles; k++) {
      uint32_t track_length = track_table[k];
      adb->track_lengths->push_back(track_length);
      adb->track_offsets->push_back(offset);
      offset += track_length * adb->header->dim * sizeof(double);
    }
    free(track_table);
  }

  return 0;

 error:
  maybe_free(track_table);
  return 1;
}

adb_t *audiodb_open(const char *path, int flags) {
  adb_t *adb = 0;
  int fd = -1;

  flags &= (O_RDONLY|O_RDWR);
  fd = open(path, flags);
  if(fd == -1) {
    goto error;
  }
  if(acquire_lock(fd, flags == O_RDWR)) {
    goto error;
  }

  adb = (adb_t *) calloc(1, sizeof(adb_t));
  if(!adb) {
    goto error;
  }
  adb->fd = fd;
  adb->flags = flags;
  adb->path = (char *) malloc(1+strlen(path));
  if(!(adb->path)) {
    goto error;
  }
  strcpy(adb->path, path);

  adb->header = (adb_header_t *) malloc(sizeof(adb_header_t));
  if(!(adb->header)) {
    goto error;
  }
  if(read(fd, (char *) adb->header, ADB_HEADER_SIZE) != ADB_HEADER_SIZE) {
    goto error;
  }
  if(!audiodb_check_header(adb->header)) {
    goto error;
  }

  adb->keys = new std::vector<std::string>;
  if(!adb->keys) {
    goto error;
  }
  adb->keymap = new std::map<std::string,uint32_t>;
  if(!adb->keymap) {
    goto error;
  }
  if(audiodb_collect_keys(adb)) {
    goto error;
  }
  adb->track_lengths = new std::vector<uint32_t>;
  if(!adb->track_lengths) {
    goto error;
  }
  adb->track_lengths->reserve(adb->header->numFiles);
  adb->track_offsets = new std::vector<off_t>;
  if(!adb->track_offsets) {
    goto error;
  }
  adb->track_offsets->reserve(adb->header->numFiles);
  if(audiodb_collect_track_lengths(adb)) {
    goto error;
  }
  adb->cached_lsh = 0;
  return adb;

 error:
  if(adb) {
    maybe_free(adb->header);
    maybe_free(adb->path);
    if(adb->keys) {
      delete adb->keys;
    }
    if(adb->keymap) {
      delete adb->keymap;
    }
    if(adb->track_lengths) {
      delete adb->track_lengths;
    }
    free(adb);
  }
  if(fd != -1) {
    close(fd);
  }
  return NULL;
}