Logo Search packages:      
Sourcecode: easyh10 version File versions  Download package

h10db.c

/*
 *      High-level interface for H10 database.
 *
 *      Copyright (c) 2005 Nyaochi
 *          Copyright (c) 2005 Toby Corkindale (iRiver.pm).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
 * http://www.gnu.org/copyleft/gpl.html .
 *
 */

/* $Id: h10db.c,v 1.33 2005/10/20 16:09:32 nyaochi Exp $ */

#ifdef      HAVE_CONFIG_H
#include <config.h>
#endif/*HAVE_CONFIG_H*/

#include <os.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <memory.h>
#include <string.h>
#include <ucs2char.h>
#include "bufferedfile.h"
#include "serialize.h"
#include "crc.h"
#include <h10db.h>

#define     COMP(a, b)  ((a)>(b))-((a)<(b))


static const ucs2_char_t ucs2cs_upd_filename[] = {'H','1','0','D','B','.','u','p','d',0};
static const ucs2_char_t ucs2cs_hdr_filename[] = {'H','1','0','D','B','.','h','d','r',0};

/* This global variable is referred by comparison functions. */
static const h10db_dat_t* g_h10db_dat = NULL;

/*
 * uint32 comparison function for sorting indexes
 */
static int uint32comp(uint32_t x, uint32_t y)
{
      return COMP(x, y);
}

/*
 * UCS2 comparison function for sorting indexes
 */
static int ucs2comp(ucs2_char_t* x, ucs2_char_t* y)
{
      /* It seems to be safer to move elements latter that have empty value. */
      /* We must ignore case during sorting, or H10 fails to recognize music files. */
      if (!x || !*x) {
            return ((!y || !*y) ? 0 : 1);
      } else {
            return ((!y || !*y) ? -1 : ucs2icmp(x, y));
      }
}

#define     IMPLEMENT_SORTCOMP(_func, _comp, _field) \
static int _func (const void *_x, const void *_y) \
{ \
      int ret = 0; \
      const h10db_idx_t* xi = (const h10db_idx_t*)_x; \
      const h10db_idx_t* yi = (const h10db_idx_t*)_y; \
      const h10db_dat_t* x = &g_h10db_dat[xi->index]; \
      const h10db_dat_t* y = &g_h10db_dat[yi->index]; \
\
      /* Move invalid elements latter. */ \
      ret = COMP(x->status, y->status); \
      if (ret == 0) { \
            /* Make a comparison with a specified field and function. */ \
            ret = _comp (x->_field, y->_field); \
            if (ret == 0) { \
                  /* Use ascending order of index numbers when the two elements are found to be identical. */ \
                  ret = COMP(xi->index, yi->index); \
            } \
      } \
      return ret; \
}

IMPLEMENT_SORTCOMP(sortcomp00, uint32comp, unknown2)
IMPLEMENT_SORTCOMP(sortcomp01, ucs2comp, file_path)
IMPLEMENT_SORTCOMP(sortcomp02, ucs2comp, file_name)
IMPLEMENT_SORTCOMP(sortcomp03, uint32comp, media_type)
IMPLEMENT_SORTCOMP(sortcomp04, ucs2comp, title)
IMPLEMENT_SORTCOMP(sortcomp05, ucs2comp, artist)
IMPLEMENT_SORTCOMP(sortcomp06, ucs2comp, album)
IMPLEMENT_SORTCOMP(sortcomp07, ucs2comp, genre)
IMPLEMENT_SORTCOMP(sortcomp08, uint32comp, rating)
IMPLEMENT_SORTCOMP(sortcomp09, uint32comp, revision)
IMPLEMENT_SORTCOMP(sortcomp10, uint32comp, recent_play)
IMPLEMENT_SORTCOMP(sortcomp11, uint32comp, unknown4)
IMPLEMENT_SORTCOMP(sortcomp12, uint32comp, number)
IMPLEMENT_SORTCOMP(sortcomp13, uint32comp, year)
IMPLEMENT_SORTCOMP(sortcomp14, uint32comp, filesize)
IMPLEMENT_SORTCOMP(sortcomp15, uint32comp, duration)
IMPLEMENT_SORTCOMP(sortcomp16, uint32comp, samplerate)
IMPLEMENT_SORTCOMP(sortcomp17, uint32comp, bitrate)
IMPLEMENT_SORTCOMP(sortcomp18, uint32comp, unknown5)
IMPLEMENT_SORTCOMP(sortcomp19, ucs2comp, unknown6)
IMPLEMENT_SORTCOMP(sortcomp20, uint32comp, unknown7)
IMPLEMENT_SORTCOMP(sortcomp21, ucs2comp, unknown8)

typedef int (*sortcomp_t)(const void *x, const void *y);

static sortcomp_t g_sortcomps[H10DB_NUM_DAT_FIELDS] =
{
      sortcomp00, sortcomp01, sortcomp02, sortcomp03, sortcomp04, sortcomp05,
      sortcomp06, sortcomp07, sortcomp08, sortcomp09, sortcomp10, sortcomp11,
      sortcomp12, sortcomp13, sortcomp14, sortcomp15, sortcomp16, sortcomp17,
      sortcomp18, sortcomp19, sortcomp20, sortcomp21, 
};





/*
 * Functions for calculating various check values
 */
static uint32_t uin32check(uint32_t value)
{
      return (uint32_t)value;
}

static uint32_t ucs2crc(const ucs2_char_t* value)
{
      if (value) {
            uint32_t crc = 0;
            ucs2_char_t* value_lowercase = ucs2dup(value);
            ucs2lwr(value_lowercase);
            ucs2big2little(value_lowercase);
            crc = (uint32_t)crcSlow(
                  (const char *)value_lowercase,
                  (int)ucs2len(value_lowercase) * sizeof(ucs2_char_t)
                  );
            ucs2free(value_lowercase);
            return crc;
      } else {
            return 0;
      }
}


#define     IMPLEMENT_CHECKFUNC(_func, _calc, _field) \
static uint32_t _func (const h10db_dat_t* entry) \
{ \
      return _calc (entry->_field); \
}

IMPLEMENT_CHECKFUNC(checkfunc00, uin32check, unknown2)
IMPLEMENT_CHECKFUNC(checkfunc01, ucs2crc, file_path)
IMPLEMENT_CHECKFUNC(checkfunc02, ucs2crc, file_name)
IMPLEMENT_CHECKFUNC(checkfunc03, uin32check, media_type)
IMPLEMENT_CHECKFUNC(checkfunc04, ucs2crc, title)
IMPLEMENT_CHECKFUNC(checkfunc05, ucs2crc, artist)
IMPLEMENT_CHECKFUNC(checkfunc06, ucs2crc, album)
IMPLEMENT_CHECKFUNC(checkfunc07, ucs2crc, genre)
IMPLEMENT_CHECKFUNC(checkfunc08, uin32check, rating)
IMPLEMENT_CHECKFUNC(checkfunc09, uin32check, revision)
IMPLEMENT_CHECKFUNC(checkfunc10, uin32check, recent_play)
IMPLEMENT_CHECKFUNC(checkfunc11, uin32check, unknown4)
IMPLEMENT_CHECKFUNC(checkfunc12, uin32check, number)
IMPLEMENT_CHECKFUNC(checkfunc13, uin32check, year)
IMPLEMENT_CHECKFUNC(checkfunc14, uin32check, filesize)
IMPLEMENT_CHECKFUNC(checkfunc15, uin32check, duration)
IMPLEMENT_CHECKFUNC(checkfunc16, uin32check, samplerate)
IMPLEMENT_CHECKFUNC(checkfunc17, uin32check, bitrate)
IMPLEMENT_CHECKFUNC(checkfunc18, uin32check, unknown5)
IMPLEMENT_CHECKFUNC(checkfunc19, ucs2crc, unknown6)
IMPLEMENT_CHECKFUNC(checkfunc20, uin32check, unknown7)
IMPLEMENT_CHECKFUNC(checkfunc21, ucs2crc, unknown8)

typedef uint32_t (*checkfunc_t)(const h10db_dat_t* entry);

static checkfunc_t g_checkfuncs[H10DB_NUM_DAT_FIELDS] =
{
      checkfunc00, checkfunc01, checkfunc02, checkfunc03, checkfunc04, checkfunc05,
      checkfunc06, checkfunc07, checkfunc08, checkfunc09, checkfunc10, checkfunc11,
      checkfunc12, checkfunc13, checkfunc14, checkfunc15, checkfunc16, checkfunc17,
      checkfunc18, checkfunc19, checkfunc20, checkfunc21, 
};

uint32_t h10db_dat_calculate_checkvalue(const h10db_dat_t* item, int field_index)
{
      return g_checkfuncs[field_index](item);
}





static ucs2_char_t *combine_path(ucs2_char_t *dst, size_t size, const ucs2_char_t *path, const ucs2_char_t *file)
{
      if (path) {
            ucs2cpy(dst, path);
            ucs2cat(dst, file);
      } else {
            ucs2cpy(dst, file);
      }
      return dst;
}

static ucs2_char_t *get_filepart(ucs2_char_t *dst, size_t mbs_size, ucs2_char_t* src, size_t ucs_size)
{
      ucs2_char_t *wcstr = ucs2dup(src);
      ucs2_char_t *p = ucs2rchr(wcstr, 0x005C); /* '\' hard coded (no reason for '/'). */
      if (p) {
            p++;
      } else {
            p = wcstr;
      }
      ucs2cpy(dst, p);
      return dst;
}





int h10db_generate_idx(
      h10db_idx_t** idx_ptr, int field_index,
      const h10db_dat_t* h10db_dat, int num_dat_entries,
      const h10db_fd_t* h10db_fd
)
{
      h10db_idx_t* idx = (h10db_idx_t *)calloc(num_dat_entries, sizeof(h10db_idx_t));
      if (idx) {
            int i;

            /* Initialize all elements. */
            for (i = 0;i < num_dat_entries;i++) {
                  idx[i].status = h10db_dat[i].status;
                  idx[i].index = i;
                  idx[i].check_value = h10db_dat_calculate_checkvalue(&h10db_dat[i], field_index);
            }

            /* Sort the elements according to the field value. */
            g_h10db_dat = h10db_dat;      /* Ugly but would be more ugly if I don't use the global variable. */
            qsort(idx, num_dat_entries, sizeof(h10db_idx_t), g_sortcomps[field_index]);

            *idx_ptr = idx;
            return 0;
      } else {
            return H10DBE_OUTOFMEMORY;
      }
}

static uint32_t count_invalid_entries(const h10db_dat_t* h10db_dat, int num_dat_entries)
{
      int i;
      uint32_t ret = 0;
      for (i = 0;i < num_dat_entries;i++) {
            if (h10db_dat[i].status == 1) {
                  ret++;
            }
      }
      return ret;
}

00276 h10db_t* h10db_new(int flags)
{
      h10db_t* h10db = (h10db_t*)malloc(sizeof(h10db_t));
      if (h10db) {
            h10db->type = (h10db_type_t*)malloc(sizeof(h10db_type_t));
            h10db->hdr = (h10db_hdr_t*)malloc(sizeof(h10db_hdr_t));
            if (h10db->type && h10db->hdr) {
                  h10db_type_init(h10db->type, flags);

                  h10db->dat = NULL;
                  h10db->idx = NULL;
                  
                  /* Disabled H10DB.upd usage. */
                  h10db->upd = NULL;
#ifdef      H10DB_USE_UPD
                  if (flags & H10DB_FLAG_INCREMENTAL) {
                        h10db->upd = (h10db_upd_t*)malloc(sizeof(h10db_upd_t));
                        if (h10db->upd) {
                              h10db_upd_read(h10db->upd, NULL);   /* Not reading but initialization. */
                        }
                        /* We don't care for the case (h10db->upd == NULL). */
                  } else {
                        h10db->upd = NULL;
                  }
#endif

                  h10db->flags = flags;

                  h10db->progress_func = NULL;
                  h10db->error_func = NULL;
                  h10db->instance = NULL;

                  /* Initialize hdr using template */
                  h10db_hdr_init(
                        h10db->hdr,
                        h10db_model_get_maxentries(h10db->type),
                        h10db_model_get_padding(h10db->type),
                        h10db_model_has_hdr_unknown5(h10db->type)
                        );
                  h10db->hdr->num_dat_entries = 0;
                  h10db->hdr->num_dat_inactive_entries = 0;
            } else {
                  free(h10db);
                  h10db = NULL;
            }
      }
      return h10db;
}

00325 void h10db_delete(h10db_t* h10db)
{
      int i;

      if (h10db) {
            if (h10db->hdr) {
                  if (h10db->dat) {
                        h10db_dat_delete(h10db->dat, h10db->hdr->num_dat_entries);
                  }
                  if (h10db->idx) {
                        for (i = 0;i < (int)h10db->hdr->num_dat_fields;i++) {
                              free(h10db->idx[i]);
                        }
                        free(h10db->idx);
                  }
                  if (h10db->upd) {
                        free(h10db->upd);
                  }
                  h10db_hdr_finish(h10db->hdr);
                  free(h10db->hdr);
                  free(h10db->type);
            }
            free(h10db);
      }
}

00351 void h10db_set_instance(h10db_t* h10db, void *instance)
{
      h10db->instance = instance;
}

00356 void h10db_set_progress_callback(h10db_t* h10db, h10db_progress_callback pfn)
{
      h10db->progress_func = pfn;
}

static int h10db_progress(h10db_t* h10db, int msg, int progress, int max_progress)
{
      if (h10db->progress_func) {
            return h10db->progress_func(h10db->instance, msg, progress, max_progress);
      } else {
            return 0;
      }
}

static int h10db_read_progress(void *instance, size_t offset, size_t size)
{
      h10db_t* h10db = (h10db_t*)instance;
      if (h10db->progress_func) {
            return h10db->progress_func(h10db->instance, h10db->msg, (int)offset, (int)size);
      }
      return 0;
}

00379 int h10db_read(h10db_t* h10db, const ucs2_char_t *path)
{
      int ret, i, num_valid_idx = 0, idx_count = 0;
      struct bfile *bfp = NULL;
      ucs2_char_t filename[MAX_PATH+1];
      ucs2_char_t filepart[MAX_PATH+1];

      /* Notify the start of H10 database reading. */
      h10db_progress(h10db, H10DB_PROGRESS_READ_START, 0, 0);

      /* Open H10DB.hdr */
      h10db->msg = H10DB_PROGRESS_READ_HDR;
      combine_path(filename, MAX_PATH, path, ucs2cs_hdr_filename);
      bfp = bf_open(filename, 0, h10db, h10db_read_progress);
      if (!bfp) {
            return H10DBE_HDR_OPENR;
      } else {
            /* Notify the start of H10DB.hdr parsing. */
            h10db_progress(h10db, H10DB_PROGRESS_PARSE_HDR, 0, 1);

            /* Parse H10DB.hdr */
            ret = h10db_hdr_serialize(bfp, h10db->hdr, 0, 0);
            bf_close(bfp);
            if (ret != 0) {
                  return H10DBE_HDR_READ;
            }

            /* Successful parse of H10DB.hdr */
            h10db_progress(h10db, H10DB_PROGRESS_PARSE_HDR, 1, 1);
      }

      /* Open H10DB.dat */
      h10db->msg = H10DB_PROGRESS_READ_DAT;
      get_filepart(filepart, MAX_PATH, h10db->hdr->pathname_dat, H10DB_PATHLENGTH);
      combine_path(filename, MAX_PATH, path, filepart);
      bfp = bf_open(filename, 0, h10db, h10db_read_progress);
      if (!bfp) {
            return H10DBE_DAT_OPENR;
      } else {
            uint32_t num_dat = 0;

            /* Notify the start of H10DB.dat parsing. */
            h10db_progress(h10db, H10DB_PROGRESS_PARSE_DAT, 0, 1);

            /* Parse H10DB.dat */
            ret = (int)h10db_dat_read(bfp, &h10db->dat, &num_dat, h10db->hdr);
            bf_close(bfp);
            if (ret != 0) {
                  return ret;
            }

            /* Check the consistency of number of read entries. */
            if (num_dat != h10db->hdr->num_dat_entries) {
                  return H10DBE_DBINCONSISTENCY;
            }

            /* Successful parse of H10DB.dat */
            h10db_progress(h10db, H10DB_PROGRESS_PARSE_DAT, 1, 1);
      }

      /* Allocate the array of h10db_idx_t */
      h10db->idx = (h10db_idx_t**)calloc(h10db->hdr->num_dat_fields, sizeof(h10db_idx_t*));
      if (!h10db->idx) {
            return H10DBE_OUTOFMEMORY;
      }

      /* Count the number of valid indexes (only for progress report). */
      for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
            if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                  num_valid_idx++;
            }
      }

      /* Open and parse all H10DB_*.idx */
      idx_count = 0;
      for (i = 0;i < (int)h10db->hdr->num_dat_fields;i++) {
            if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                  /* Notify the start of an index file parsing. */
                  h10db_progress(h10db, H10DB_PROGRESS_IDX_COUNT, idx_count++, num_valid_idx);

                  /* Open the idx file. */
                  h10db->msg = H10DB_PROGRESS_READ_IDX;
                  get_filepart(filepart, MAX_PATH, h10db->hdr->fd[i].index_pathname, H10DB_PATHLENGTH);
                  combine_path(filename, MAX_PATH, path, filepart);
                  bfp = bf_open(filename, 0, h10db, h10db_read_progress);
                  if (!bfp) {
                        return H10DBE_IDX_OPENR;
                  } else {
                        int num_idx_elems = 0;
                        h10db_idx_t* h10db_idx = NULL;

                        /* Notify the start of an index file parsing. */
                        h10db_progress(h10db, H10DB_PROGRESS_PARSE_IDX, 0, 1);
                        ret = h10db_idx_read(bfp, &h10db->idx[i], &num_idx_elems);
                        bf_close(bfp);
                        if (ret != 0) {
                              return ret;
                        }

                        /* Check the consistency of number of read entries. */
                        if (num_idx_elems != h10db->hdr->num_dat_entries) {
                              return H10DBE_DBINCONSISTENCY;
                        }

                        /* Successful parse of an index. */
                        h10db_progress(h10db, H10DB_PROGRESS_PARSE_IDX, 1, 1);
                  }
            }
      }
      /* Notify the finish of all index files. */
      h10db_progress(h10db, H10DB_PROGRESS_IDX_COUNT, idx_count, num_valid_idx);

      /* Disabled the usage of H10DB.upd. */
#ifdef      H10DB_USE_UPD
      /* Open and parse H10DB.upd */
      if (h10db->flags & H10DB_FLAG_INCREMENTAL) {
            free(h10db->upd);
            h10db->upd = (h10db_upd_t*)malloc(sizeof(h10db_upd_t));
            if (h10db->upd) {
                  combine_path(filename, MAX_PATH, path, ucs2cs_upd_filename);
                  bfp = bf_open(filename, 0, h10db, h10db_read_progress);
                  h10db_progress(h10db, H10DB_PROGRESS_PARSE_UPD, 0, 1);
                  h10db_upd_read(h10db->upd, bfp);    /* Don't care about H10DB.upd error. */
                  h10db_progress(h10db, H10DB_PROGRESS_PARSE_UPD, 1, 1);
            }
            /* We don't issue an error but continue. */
      }
#endif

      /* Notify the end of H10 database reading. */
      h10db_progress(h10db, H10DB_PROGRESS_READ_END, 0, 0);

      return 0;
}

static int h10db_write_progress(void *instance, size_t offset, size_t size)
{
      h10db_t* h10db = (h10db_t*)instance;
      if (h10db->progress_func) {
            return h10db->progress_func(h10db->instance, h10db->msg, (int)offset, (int)size);
      }
      return 0;
}

00523 int h10db_write(h10db_t* h10db, const ucs2_char_t *path)
{
      int ret, i, num_valid_idx = 0, idx_count = 0;
      struct bfile *bfp = NULL;
      ucs2_char_t filename[MAX_PATH+1];
      ucs2_char_t filepart[MAX_PATH+1];

      /* Notify the start of database writing. */
      h10db_progress(h10db, H10DB_PROGRESS_WRITE_START, 0, 0);

      /* Count the number of valid indexes (only for progress report). */
      for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
            if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                  num_valid_idx++;
            }
      }

      /* Generate *.idx files. */
      idx_count = 0;
      for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
            h10db_idx_t* idx = h10db->idx[i];
            if (idx) {
                  if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                        /* Notify the current progress. */
                        h10db_progress(h10db, H10DB_PROGRESS_IDX_COUNT, idx_count++, num_valid_idx);

                        /* Open H10DB_*.idx. */
                        h10db->msg = H10DB_PROGRESS_WRITE_IDX;
                        get_filepart(filepart, MAX_PATH, h10db->hdr->fd[i].index_pathname, H10DB_PATHLENGTH);
                        combine_path(filename, MAX_PATH, path, filepart);
                        bfp = bf_open(filename, 1, h10db, h10db_write_progress);
                        if (!bfp) {
                              return H10DBE_IDX_OPENW;
                        } else {
                              /* Notify the start of an index file writing. */
                              h10db_progress(h10db, H10DB_PROGRESS_GENERATE_IDX, 0, 1);

                              ret = h10db_idx_write(bfp, idx, h10db->hdr->num_dat_entries);
                              bf_close(bfp);
                              if (ret != 0) {
                                    return ret;
                              }

                              /* Notify the end of writing. */
                              h10db_progress(h10db, H10DB_PROGRESS_GENERATE_IDX, 1, 1);
                        }
                  }
            }
      }
      /* Notify the end of index writing. */
      h10db_progress(h10db, H10DB_PROGRESS_IDX_COUNT, idx_count, num_valid_idx);

      /* Open H10DB.dat */
      h10db->msg = H10DB_PROGRESS_WRITE_DAT;
      get_filepart(filepart, MAX_PATH, h10db->hdr->pathname_dat, H10DB_PATHLENGTH);
      combine_path(filename, MAX_PATH, path, filepart);
      bfp = bf_open(filename, 1, h10db, h10db_write_progress);
      if (!bfp) {
            return H10DBE_DAT_OPENW;
      } else {
            h10db_progress(h10db, H10DB_PROGRESS_GENERATE_DAT, 0, 1);

            /* Write H10DB.dat */
            ret = h10db_dat_write(bfp, h10db->dat, h10db->hdr->num_dat_entries, h10db->hdr);
            bf_close(bfp);
            if (ret != 0) {
                  return ret;
            }

            h10db_progress(h10db, H10DB_PROGRESS_GENERATE_DAT, 1, 1);
      }

      /* Generate H10DB.hdr */
      h10db->msg = H10DB_PROGRESS_WRITE_HDR;
      get_filepart(filepart, MAX_PATH, h10db->hdr->pathname_hdr, H10DB_PATHLENGTH);
      combine_path(filename, MAX_PATH, path, filepart);
      bfp = bf_open(filename, 1, h10db, h10db_write_progress);
      if (!bfp) {
            return H10DBE_HDR_OPENW;
      } else {
            h10db->hdr->num_dat_inactive_entries = count_invalid_entries(h10db->dat, h10db->hdr->num_dat_entries);
            h10db_progress(h10db, H10DB_PROGRESS_WRITE_HDR, 0, 1);

            ret = h10db_hdr_serialize(bfp, h10db->hdr, 1, 0);
            bf_close(bfp);
            if (ret != 0) {
                  return H10DBE_HDR_WRITE;
            }

            h10db_progress(h10db, H10DB_PROGRESS_WRITE_HDR, 1, 1);
      }

      /* Disabled the usage of H10DB.upd. */
#ifdef      H10DB_USE_UPD
      /* Write H10DB.upd */
      h10db->msg = H10DB_PROGRESS_WRITE_UPD;
      if (h10db->upd && (h10db->flags & H10DB_FLAG_INCREMENTAL)) {
            combine_path(filename, MAX_PATH, path, ucs2cs_upd_filename);
            bfp = bf_open(filename, 1, h10db, h10db_write_progress);
            if (!bfp) {
                  return H10DBE_UPD_OPENW;
            } else {
                  h10db_progress(h10db, H10DB_PROGRESS_GENERATE_UPD, 0, 1);
                  h10db_progress(h10db, H10DB_PROGRESS_GENERATE_UPD, 1, 1);
                  h10db_upd_write(h10db->upd, bfp);   /* Don't care about error as for H10DB.upd. */
            }
      }
#endif

      h10db_progress(h10db, H10DB_PROGRESS_WRITE_END, 0, 0);

      return 0;
}

h10db_type_t* h10db_access_type(h10db_t* h10db)
{
      return h10db->type;
}

int h10db_load_model(h10db_t* h10db, const ucs2_char_t *filename)
{
      int ret = 0;
      struct bfile *bfp = NULL;
      h10db->msg = H10DB_PROGRESS_READ_TEMPLATE;
      bfp = bf_open(filename, 0, h10db, h10db_read_progress);
      if (!bfp) {
            return H10DBE_MODEL_OPENR;
      } else {
            uint32_t chunk_size;

            /* Read "TYPE" chunk and store the value to h10db->type. */
            ret = h10db_type_read(bfp, h10db->type);
            if (ret != 0) {
                  bf_close(bfp);
                  return ret;
            }

            /* Find "DHDR" chunk. */
            if (bf_seek(bfp, 0) != 0) {
                  return H10DBE_MODEL_READ;
            }
            ret = h10db_model_findchunk(bfp, "DHDR", &chunk_size);
            if (ret != 0) {
                  bf_close(bfp);
                  return ret;             
            }

            h10db_hdr_finish(h10db->hdr);

            h10db_hdr_init(
                  h10db->hdr,
                  h10db_model_get_maxentries(h10db->type),
                  h10db_model_get_padding(h10db->type),
                  h10db_model_has_hdr_unknown5(h10db->type)
                  );

            /* Read the content. */
            ret = h10db_hdr_serialize(bfp, h10db->hdr, 0, 1);
            if (ret != 0) {
                  bf_close(bfp);
                  return ret;             
            }
      }

      return 0;
}

int h10db_store_model(h10db_t* h10db, const ucs2_char_t *filename)
{
      int ret = 0;
      long pos = 0, offset = 0;
      struct bfile *bfp = NULL;
      h10db->msg = H10DB_PROGRESS_WRITE_TEMPLATE;
      bfp = bf_open(filename, 1, h10db, h10db_write_progress);
      if (!bfp) {
            return H10DBE_MODEL_OPENW;
      } else {
            uint32_t version = 1;
            ret |= h10db_model_writechunk(bfp, "MDEL", sizeof(uint32_t), NULL);
            ret |= serialize_uint32(bfp, &version, 1);

            ret |= h10db_type_write(bfp, h10db->type);

            ret |= h10db_model_writechunk(bfp, "DHDR", 0, &offset);
            pos = bf_tell(bfp);
            ret |= h10db_hdr_serialize(bfp, h10db->hdr, 1, 1);
            ret |= h10db_model_writechunksize(bfp, offset, bf_tell(bfp) - pos);
            bf_close(bfp);
            if (ret != 0) {
                  return ret;
            }
      }
      return 0;
}

00718 int h10db_update(h10db_t* h10db, int flags)
{
      int ret, i, num_deleted = 0, num_valid_idx = 0, idx_count = 0;

      h10db_progress(h10db, H10DB_PROGRESS_UPDATE_START, 0, 0);

      /* Clean unused entries if indicated. */
      if (flags & H10DB_UPDATEF_CLEAN) {
            h10db_progress(h10db, H10DB_PROGRESS_UPDATE_CLEAN, 0, 1);

            for (i = 0;;) {
                  h10db_dat_t* dat = NULL;
                  if (i >= h10db_get_size(h10db)) {
                        break;
                  }

                  /* Delete inactive entries. */
                  if (h10db->dat[i].status != 0) {
                        /* Destroy this item. */
                        h10db_dat_finish(&h10db->dat[i]);

                        /* Chink the deleted space. */
                        memmove(
                              &h10db->dat[i],
                              &h10db->dat[i+1],
                              sizeof(h10db_dat_t) * (h10db_get_size(h10db) - (i+1))
                              );
                        h10db_resize(h10db, h10db_get_size(h10db)-1);
                        h10db->hdr->num_dat_inactive_entries--;
                        num_deleted++;

                        /* Stay the current position. */
                  } else {
                        /* Move to next position. */
                        i++;
                  }
            }

            h10db_progress(h10db, H10DB_PROGRESS_UPDATE_CLEAN, 1, num_deleted);
      }

      /* Count the number of inactive entries. */
      h10db->hdr->num_dat_inactive_entries = count_invalid_entries(h10db->dat, h10db->hdr->num_dat_entries);

      /* Free allocated indexes. */
      free(h10db->idx);

      /* Allocate new indexes */
      h10db->idx = (h10db_idx_t**)calloc(h10db->hdr->num_dat_fields, sizeof(h10db_idx_t*));
      if (!h10db->idx) {
            return H10DBE_OUTOFMEMORY;          
      }           

      /* Count the number of valid indexes (only for progress report). */
      for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
            if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                  num_valid_idx++;
            }
      }

      /* Generate *.idx files. */
      for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
            h10db_progress(h10db, H10DB_PROGRESS_UPDATE_IDX, idx_count++, num_valid_idx);
            if (h10db->hdr->fd[i].has_index && h10db->hdr->fd[i].index_pathname) {
                  free(h10db->idx[i]);
                  ret = h10db_generate_idx(
                        &h10db->idx[i],
                        i,
                        h10db->dat,
                        h10db->hdr->num_dat_entries,
                        &h10db->hdr->fd[i]
                        );
                  if (ret != 0) {
                        return ret;
                  }
            }
      }
      h10db_progress(h10db, H10DB_PROGRESS_UPDATE_IDX, idx_count, num_valid_idx);

      h10db_progress(h10db, H10DB_PROGRESS_UPDATE_END, 0, 0);

      return 0;
}

00802 int h10db_get_size(h10db_t* h10db)
{
      return (h10db && h10db->hdr) ? h10db->hdr->num_dat_entries : -1;
}

00807 int h10db_resize(h10db_t* h10db, int size)
{
      h10db->dat = (h10db_dat_t*)realloc(h10db->dat, sizeof(h10db_dat_t) * size);
      return h10db->hdr->num_dat_entries = h10db->dat ? size : 0;
}

h10db_dat_t* h10db_access_item(h10db_t* h10db, int index)
{
      return (h10db && h10db->hdr && 0 <= index && index < h10db_get_size(h10db)) ?
            &h10db->dat[index] : NULL;
}

int h10db_is_updated_item(h10db_t* h10db, int index, const ucs2_char_t *filename)
{
      if (h10db->upd && (h10db->flags & H10DB_FLAG_INCREMENTAL)) {
            h10db_dat_t* item = h10db_access_item(h10db, index);
            return item ? h10db_upd_is_updated(h10db->upd, (uint32_t)index, item, filename) : 0;
      } else {
            return 1;
      }
}

int h10db_set_filepath(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->file_path);
            return (item->file_path = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_filename(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->file_name);
            return (item->file_name = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_title(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->title);
            return (item->title = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_artist(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->artist);
            return (item->artist = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_album(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->album);
            return (item->album = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_genre(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->genre);
            return (item->genre = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_unknown6(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->unknown6);
            return (item->unknown6 = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_unknown8(h10db_t* h10db, int index, const ucs2_char_t* value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2free(item->unknown8);
            return (item->unknown8 = ucs2dup(value)) ? 0 : -1;
      } else {
            return -1;
      }
}

int h10db_set_tracknumber(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->number = value;
      return 0;
}
int h10db_set_year(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->year = value;
      return 0;
}
int h10db_set_filesize(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->filesize = value;
      return 0;
}
int h10db_set_duration(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->duration = value;
      return 0;
}
int h10db_set_samplerate(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->samplerate = value;
      return 0;
}
int h10db_set_bitrate(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->bitrate = value;
      return 0;
}

int h10db_set_unknown4(h10db_t* h10db, int index, uint32_t value)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->unknown4 = value;
      return 0;
}

int h10db_set_unknown5(h10db_t* h10db, int index, uint32_t tracknumber)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (!item) {
            return -1;
      }
      item->unknown5 = tracknumber;
      return 0;
}

const ucs2_char_t* h10db_get_filepath(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->file_path : NULL;
}

const ucs2_char_t* h10db_get_filename(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->file_name : NULL;
}

const ucs2_char_t* h10db_get_title(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->title : NULL;
}

const ucs2_char_t* h10db_get_artist(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->artist : NULL;
}

const ucs2_char_t* h10db_get_album(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->album : NULL;
}

const ucs2_char_t* h10db_get_genre(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->genre : NULL;
}

const ucs2_char_t* h10db_get_unknown6(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->unknown6 : NULL;
}

const ucs2_char_t* h10db_get_unknown8(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->unknown8 : NULL;
}

uint32_t h10db_get_tracknumber(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->number : 0;
}

uint32_t h10db_get_year(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->year : 0;
}

uint32_t h10db_get_filesize(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->filesize : 0;
}

uint32_t h10db_get_duration(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->duration : 0;
}

uint32_t h10db_get_samplerate(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->samplerate : 0;
}

uint32_t h10db_get_bitrate(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->bitrate : 0;
}

uint32_t h10db_get_unknown4(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->unknown4 : 0;
}

uint32_t h10db_get_unknown5(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      return item ? item->unknown5 : 0;
}

static void fit_field(ucs2_char_t* value, int length)
{
      ucs2strip(value);
      if (length < ucs2len(value)) {
            value[length] = 0;
            ucs2strip(value);
      }
}

void h10db_fit_fields(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            fit_field(item->file_path, h10db->hdr->fd[1].max_length-1);
            fit_field(item->file_name, h10db->hdr->fd[2].max_length-1);
            fit_field(item->title, h10db->hdr->fd[4].max_length-1);
            fit_field(item->artist, h10db->hdr->fd[5].max_length-1);
            fit_field(item->album, h10db->hdr->fd[6].max_length-1);
            fit_field(item->genre, h10db->hdr->fd[7].max_length-1);
            fit_field(item->unknown6, h10db->hdr->fd[19].max_length-1);
            fit_field(item->unknown8, h10db->hdr->fd[21].max_length-1);
      }
}

static ucs2_char_t* skip_ordinalnumber(ucs2_char_t* str)
{
      if (str) {
            while (is_ucs2surrogate(*str)) {
                  str++;
            }
      }
      return str;
}

void h10db_righttoleft_encode_fields(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2_char_t*p = NULL;
            p = skip_ordinalnumber(item->title);
            ucs2righttoleft_encode(p);
            p = skip_ordinalnumber(item->artist);
            ucs2righttoleft_encode(p);
            p = skip_ordinalnumber(item->album);
            ucs2righttoleft_encode(p);
            p = skip_ordinalnumber(item->genre);
            ucs2righttoleft_encode(p);
      }
}

void h10db_righttoleft_decode_fields(h10db_t* h10db, int index)
{
      h10db_dat_t* item = h10db_access_item(h10db, index);
      if (item && h10db->hdr) {
            ucs2_char_t*p = NULL;
            p = skip_ordinalnumber(item->title);
            ucs2righttoleft_decode(p);
            p = skip_ordinalnumber(item->artist);
            ucs2righttoleft_decode(p);
            p = skip_ordinalnumber(item->album);
            ucs2righttoleft_decode(p);
            p = skip_ordinalnumber(item->genre);
            ucs2righttoleft_decode(p);
      }
}

Generated by  Doxygen 1.6.0   Back to index