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

h10db_dat.c

/*
 *      H10DB.dat parser and writer.
 *
 *      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_dat.c,v 1.10 2005/09/13 10:07:46 nyaochi Exp $ */

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

#include <os.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ucs2char.h>
#include "bufferedfile.h"
#include "serialize.h"

#include <h10db.h>

static void fprints(FILE *fp, const char *format, const ucs2_char_t* value)
{
      char *mbs = ucs2dupmbs(value);
      if (mbs) {
            fprintf(fp, format, mbs);
            ucs2free(mbs);
      }
}

static void fprintt(FILE *fp, const char *format, uint32_t value)
{
      static time_t basetime = 0;   /* Basetime (static variable). */
      time_t timer = 0;

      /* Initialize basetime (Sat Jan 01 00:00:00 2000) for the first time. */
      if (basetime == 0) {
            struct tm bt;
            memset(&bt, 0, sizeof(bt));
            bt.tm_year = 2000 - 1900;
            bt.tm_mon = 1 - 1;
            bt.tm_mday = 1;
            bt.tm_hour = 0;
            bt.tm_min = 0;
            bt.tm_sec = 0;
            basetime = mktime(&bt);
      }

      timer = basetime + (time_t)value;
      fprintf(fp, format, asctime(gmtime(&timer)));
}



void h10db_dat_init(h10db_dat_t* item)
{
      memset(item, 0, sizeof(*item));
}

void h10db_dat_finish(h10db_dat_t* item)
{
      ucs2free(item->file_path);
      ucs2free(item->file_name);
      ucs2free(item->title);
      ucs2free(item->artist);
      ucs2free(item->album);
      ucs2free(item->genre);
      ucs2free(item->unknown6);
      ucs2free(item->unknown8);
      h10db_dat_init(item);
}

void h10db_dat_swap(h10db_dat_t* x, h10db_dat_t* y)
{
      h10db_dat_t tmp;
      memcpy(&tmp, x, sizeof(*x));
      memcpy(x, y, sizeof(*y));
      memcpy(y, &tmp, sizeof(tmp));
}

static uint32_t h10db_dat_offset(h10db_field_offsets_t offsets, int i, struct bfile *bfp, long base, int is_storing)
{
      if (offsets) {
            if (is_storing) {
                  offsets[i] = (uint16_t)(bf_tell(bfp) - base);
            } else {
                  if (offsets[i] != (uint16_t)(bf_tell(bfp) - base)) {
                        return (1 << i);
                  }
            }
      }
      return 0;
}

int h10db_dat_serialize(struct bfile *bfp, h10db_dat_t* item, h10db_field_offsets_t offsets, h10db_fd_t* fd, int is_storing)
{
      /*
       * In reading, use offset values to make a best effort to sync with the data layout.
       * In writing, store offset values in H10DB.hdr with UCS-2 string length guard.
       *
       * The reason why I have to preserve carefully offsets and max_length is that some string
       * fields seem to be terminated not only by L'\0' but L"\0" (00 00 00 00), which will
       * cause unsyncronization problem.
       */
      int i = 0, ret = 0;
      uint32_t check = 0;
      uint32_t field_length[H10DB_NUM_DAT_FIELDS];
      long base = bf_tell(bfp);

      if (is_storing) {
            /* Maximum length of each field. */
            for (i = 0;i < H10DB_NUM_DAT_FIELDS;i++) {
                  field_length[i] = fd[i].max_length;
                  if (fd[i].field_type == 2) {
                        /* This is ugly, but we must follow the strange spec of field descriptor. */
                        field_length[i] /= sizeof(uint32_t);
                  }
            }
      } else {
            /* Length of each field calculated by offsets. */
            for (i = 0;i < H10DB_NUM_DAT_FIELDS-1;i++) {
                  field_length[i] = offsets[i+1] - offsets[i];
                  /* Convert size in bytes to the number of elments. */
                  switch (fd[i].field_type) {
                  case 1:
                        field_length[i] /= sizeof(ucs2_char_t);
                        break;
                  case 2:
                        field_length[i] /= sizeof(uint32_t);
                  }
            }
            /* We don't know the length of last elements in advance. */
            field_length[i] = 0;
      }

      ret |= serialize_uint32(bfp, &item->status, is_storing);
      ret |= serialize_uint32(bfp, &item->unknown1, is_storing);
      check |= h10db_dat_offset(offsets, 0, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->unknown2, is_storing);
      check |= h10db_dat_offset(offsets, 1, bfp, base, is_storing);
    ret |= serialize_ucs2le_limited(bfp, &item->file_path, field_length[1], is_storing);
      check |= h10db_dat_offset(offsets, 2, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->file_name, field_length[2], is_storing);
      check |= h10db_dat_offset(offsets, 3, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->media_type, is_storing);
      check |= h10db_dat_offset(offsets, 4, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->title, field_length[4], is_storing);
      check |= h10db_dat_offset(offsets, 5, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->artist, field_length[5], is_storing);
      check |= h10db_dat_offset(offsets, 6, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->album, field_length[6], is_storing);
      check |= h10db_dat_offset(offsets, 7, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->genre, field_length[7], is_storing);
      check |= h10db_dat_offset(offsets, 8, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->rating, is_storing);
      check |= h10db_dat_offset(offsets, 9, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->revision, is_storing);
      check |= h10db_dat_offset(offsets, 10, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->recent_play, is_storing);
      check |= h10db_dat_offset(offsets, 11, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->unknown4, is_storing);
      check |= h10db_dat_offset(offsets, 12, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->number, is_storing);
      check |= h10db_dat_offset(offsets, 13, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->year, is_storing);
      check |= h10db_dat_offset(offsets, 14, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->filesize, is_storing);
      check |= h10db_dat_offset(offsets, 15, bfp, base, is_storing);

      if (fd[15].field_type == 1) {
            /* H10 firmware version < 2.03 */
            /* UCS2-LE string <-> uint32_t conversion. */
            if (is_storing) {
                  size_t length = 0;
                  ucs2_char_t duration[128];
                  memset(duration, 0, sizeof(duration));
                  itoucs2(item->duration, duration, 10);
                  length = ucs2len(duration);
                  if (length > field_length[15]) {
                        length = field_length[15];
                  }
                  ret |= serialize_ucs2le_fixed(bfp, duration, length, is_storing);
            } else {
                  ucs2_char_t duration[128];
                  memset(duration, 0, sizeof(duration));
                  ret |= serialize_ucs2le_fixed(bfp, duration, field_length[15], is_storing);
                  item->duration = (uint32_t)ucs2toi(duration);
            }
            check |= h10db_dat_offset(offsets, 16, bfp, base, is_storing);
      } else {
            /* H10 firmware version >= 2.04 */
            ret |= serialize_uint32(bfp, &item->duration, is_storing);
            check |= h10db_dat_offset(offsets, 16, bfp, base, is_storing);
      }

      ret |= serialize_uint32(bfp, &item->samplerate, is_storing);
      check |= h10db_dat_offset(offsets, 17, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->bitrate, is_storing);
      check |= h10db_dat_offset(offsets, 18, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->unknown5, is_storing);
      check |= h10db_dat_offset(offsets, 19, bfp, base, is_storing);
      ret |= serialize_ucs2le_limited(bfp, &item->unknown6, field_length[19], is_storing);
      check |= h10db_dat_offset(offsets, 20, bfp, base, is_storing);
      ret |= serialize_uint32(bfp, &item->unknown7, is_storing);
      check |= h10db_dat_offset(offsets, 21, bfp, base, is_storing);
      ret |= serialize_ucs2le(bfp, &item->unknown8, is_storing);

      return (int)((ret << H10DB_NUM_DAT_FIELDS) | check);
}

void h10db_dat_repr(FILE *fp, const h10db_dat_t* item)
{
      fprintf(fp, "inactive: %d\n", item->status);
      fprintf(fp, "unknown1: %d\n", item->unknown1);
      fprintf(fp, "unknown2: %d\n", item->unknown2);
      fprints(fp, "file_path: %s\n", item->file_path);
      fprints(fp, "file_name: %s\n", item->file_name);
      fprintf(fp, "media_type: %d\n", item->media_type);
      if (is_ucs2surrogate(*item->title)) {
            ucs2_char_t* p = item->title;
            uint32_t value = (*p++ - 0xD800) & 0x07FF;
            if (is_ucs2surrogate(*p)) {
                  value |= (((*p++ - 0xD800) & 0x07FF) << 11);
            }
            fprintf(fp, "title (htn=%d): ", value);
            fprints(fp, "%s\n", p);
      } else {
            fprints(fp, "title: %s\n", item->title);
      }
      fprints(fp, "artist: %s\n", item->artist);
      fprints(fp, "album: %s\n", item->album);
      fprints(fp, "genre: %s\n", item->genre);
      fprintf(fp, "rating: %d\n", item->rating);
      fprintf(fp, "revision: %d\n", item->revision);
      fprintt(fp, "recent_play: %s", item->recent_play);
      fprintf(fp, "unknown4: %d\n", item->unknown4);
      fprintf(fp, "number: %d\n", item->number);
      fprintf(fp, "filesize: %d\n", item->filesize);
      fprintf(fp, "duration: %d\n", item->duration);
      fprintf(fp, "samplerate: %d\n", item->samplerate);
      fprintf(fp, "bitrate: %d\n", item->bitrate);
      fprintf(fp, "unknown5: %d\n", item->unknown5);
      fprintf(fp, "unknown6: %s\n", item->unknown6);
      fprintf(fp, "unknown7: %d\n", item->unknown7);
      fprintf(fp, "unknown8: %s\n", item->unknown8);
}

void h10db_dat_validate(FILE *fp, const h10db_dat_t* item)
{
      if (item->status != 0 && item->status != 1)
            fprintf(fp, "Validation failed: status\n");
      if (item->unknown1 != 0)
            fprintf(fp, "Validation failed: unknown1\n");
      if (item->unknown2 != 0)
            fprintf(fp, "Validation failed: unknown2\n");
      if (5 < item->rating)
            fprintf(fp, "Validation failed: rating\n");
      /*if (item->unknown4 != 0)
            fprintf(fp, "Validation failed: unknown4\n");*/
      /*if (item->unknown5 != 0)
            fprintf(fp, "Validation failed: unknown5\n");*/
      if (item->unknown7 != 0)
            fprintf(fp, "Validation failed: unknown7\n");
}


int h10db_dat_read(struct bfile *bfp, h10db_dat_t** array_ptr, uint32_t* num_ptr, const h10db_hdr_t* _hdr)
{
      uint32_t num = 0;
      h10db_dat_t* array = NULL;
      h10db_hdr_t* hdr = (h10db_hdr_t*)_hdr;

      while (!bf_eof(bfp)) {
            int check = 0;
            h10db_dat_t item;

            if (hdr) {
                  long offset = bf_tell(bfp);
                  if (hdr->dat_entry_offset[num] != offset) {
                        /* Force to syncronize the entry. */
                        bf_seek(bfp, hdr->dat_entry_offset[num]);
                        //return H10DBE_DAT_ENTRYOFFSET;
                        /*fprintf(stdout, "WARNING: Entry-offset validation failed: entry = %d\n", num);*/
                  }
            }

            h10db_dat_init(&item);
            check = h10db_dat_serialize(bfp, &item, hdr ? hdr->dat_field_offset[num] : NULL, hdr->fd, 0);
            if (bf_eof(bfp)) {
                  h10db_dat_finish(&item);
                  break;
            }
            if (check != 0) {
                  return H10DBE_DAT_FIELDOFFSET;
                  /*fprintf(
                        stdout,
                        "WARNING: Read error or field-offset validation failed: entry = %d, check = 0x%08X\n",
                        num,
                        (uint32_t)check
                        );*/
            }


            array = realloc(array, sizeof(h10db_dat_t) * (num+1));
            if (!array) {
                  return H10DBE_OUTOFMEMORY;
            }
            h10db_dat_init(&array[num]);
            h10db_dat_swap(&array[num], &item);
            h10db_dat_finish(&item);
            num++;
      }

      if (hdr) {
            long offset = bf_tell(bfp);
            if (hdr->dat_entry_offset[num] != offset) {
                  return H10DBE_DAT_ENTRYOFFSET;
                  /*fprintf(stdout, "WARNING: Entry-offset validation failed: the last entry = %d\n", num);*/
            }
      }

      *array_ptr = array;
      *num_ptr = num;
      return 0;
}

int h10db_dat_write(struct bfile *bfp, const h10db_dat_t* array, int num, h10db_hdr_t* hdr)
{
      int i;
      for (i = 0;i < num;i++)  {
            int check = 0;
            if (hdr) {
                  hdr->dat_entry_offset[i] = (uint32_t)bf_tell(bfp);
            }
            check = h10db_dat_serialize(bfp, (h10db_dat_t*)&array[i], hdr ? hdr->dat_field_offset[i] : NULL, hdr->fd, 1);
            if (check != 0) {
                  return H10DBE_DAT_WRITE;
            }
      }
      if (hdr) {
            hdr->dat_size = hdr->dat_entry_offset[i] = (uint32_t)bf_tell(bfp);
      }
      return 0;
}

void h10db_dat_delete(h10db_dat_t* array, int num)
{
      int i;
      for (i = 0;i < num;i++) {
            h10db_dat_finish(&array[i]);
      }
      free(array);
}

Generated by  Doxygen 1.6.0   Back to index