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

easyh10_database.c

/*
 *      EasyH10 database update routine.
 *
 *      Copyright (c) 2005 Nyaochi
 *
 * 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 Gen eral 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: easyh10_database.c,v 1.40 2005/10/20 17:13:09 nyaochi Exp $ */

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

#include <os.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ucs2char.h>

#include <h10db.h>
#include "easyh10.h"
#include <getmediainfo.h>
#include <playlist.h>
#include "filepathutil.h"

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

struct tag_media_target_file {
      ucs2_char_t path[MAX_PATH];
      ucs2_char_t file[MAX_PATH];
      media_info info;
      int entry;
      time_t actual_timestamp;
      time_t previous_timestamp;
      int update;
};
typedef struct tag_media_target_file media_target_file_t;

struct tag_findfile_dat {
      media_target_file_t* targets;
      int num_targets;
      void *instance;
      update_progress_callback proc;
};
typedef struct tag_findfile_dat findfile_dat_t;

struct tag_update_dat {
      void *instance;
      update_progress_callback proc;
      double idx_progress_coeff;
      double idx_progress_const;
};
typedef struct tag_update_dat update_dat_t;

static const ucs2_char_t ucs2cs_mp3[] = {'.','m','p','3',0};
static const ucs2_char_t ucs2cs_wma[] = {'.','w','m','a',0};
static const ucs2_char_t ucs2cs_wav[] = {'.','w','a','v',0};



static int found_file(void *instance, const ucs2_char_t* found_path, const ucs2_char_t* found_file)
{
      findfile_dat_t* ffd = (findfile_dat_t*)instance;

      if (filepathutil_hasext(found_file, ucs2cs_mp3) ||
            filepathutil_hasext(found_file, ucs2cs_wma) ||
            filepathutil_hasext(found_file, ucs2cs_wav)) {
            /* Music (MP3/WMA/WAV) file. */
            media_target_file_t* new_target = NULL;

            /* Expand the target array. */
            ffd->targets = (media_target_file_t*)realloc(
                  ffd->targets,
                  sizeof(media_target_file_t) * (ffd->num_targets+1)
                  );
            new_target = &ffd->targets[ffd->num_targets++];

            /* Set path and file. */
            ucs2cpy(new_target->path, found_path);
            ucs2cpy(new_target->file, found_file);
            /* Initialize index with -1. */
            new_target->entry = -1;
            new_target->update = 1;
            getmediainfo_init(&new_target->info);

      } else {
            /* Exit if the filename does not have .mp3 or .wma */
            return 0;
      }

      /* Report progress. */
      if (ffd->proc) {
            ffd->proc(
                  ffd->instance,
                  EASYH10P_ENUMTARGETS_FILE,
                  ffd->num_targets,
                  (void*)(const ucs2_char_t*)found_file
                  );
      }

      return 0;
}

static int taginfo_from_pathfile(media_info* info, const ucs2_char_t *path, const ucs2_char_t *file, const ucs2_char_t* path_to_music, const char *pattern)
{
      const ucs2_char_t *p = NULL, *q = NULL;
      int type = 0;

      /* Currently, only a set of patterns are implemented. */
      if (strcmp(pattern, "{ARTIST}\\{ALBUM+}\\{TITLE}") == 0) {
            type = 1;
      } else if (strcmp(pattern, "{ARTIST}\\{ALBUM+}\\{NUMBER}{TITLE}") == 0) {
            type = 2;
      } else if (strcmp(pattern, "{ARTIST}\\{ALBUM+}\\") == 0) {
            type = 3;
      } else if (strcmp(pattern, "{ARTIST}\\") == 0) {
            type = 4;
      } else if (strcmp(pattern, "{GENRE}\\{ARTIST}\\{ALBUM+}\\{TITLE}") == 0) {
            type = 5;
      } else if (strcmp(pattern, "{GENRE}\\{ARTIST}\\{ALBUM+}\\{NUMBER}{TITLE}") == 0) {
            type = 6;
      } else if (strcmp(pattern, "{GENRE}\\{ARTIST}\\{ALBUM+}\\") == 0) {
            type = 7;
      } else if (strcmp(pattern, "{GENRE}\\{ARTIST}\\") == 0) {
            type = 8;
      }

      if (type != 0) {
            /* Clear fields according to the type. */
            if (type != 3 && type != 4 && type != 7 && type != 8) {
                  ucs2free(info->title);  info->title = NULL;
            }
            if (type != 4 && type != 8) {
                  ucs2free(info->album);  info->album = NULL;
            }
            if (4 <= type) {
                  ucs2free(info->genre);  info->genre = NULL;
            }
            ucs2free(info->artist); info->artist = NULL;

            /* Obtain path name to the music. */
            p = ucs2str(path, path_to_music);
            if (!p) {
                  return 1;
            }
            p += ucs2len(path_to_music);

            /* Obtain genre, artist, and album values from the path if necessary. */
            if (1 <= type && type <= 4) {
                  q = filepathutil_skip_one_directory(p);
                  if (q) {
                        info->artist = ucs2ndup(p, (q-p) - 1);
                        if (type != 4) {
                              info->album = ucs2dup(q);
                              filepathutil_removeslash(info->album);
                              filepathutil_replace_slash(info->album, (ucs2_char_t)' ');
                        }
                  }
            } else if (5 <= type && type <= 8) {
                  q = filepathutil_skip_one_directory(p);
                  if (q) {
                        info->genre = ucs2ndup(p, (q-p) - 1);
                        p = q;
                        q = filepathutil_skip_one_directory(p);
                        if (q) {
                              info->artist = ucs2ndup(p, (q-p) - 1);
                              if (type != 8) {
                                    info->album = ucs2dup(q);
                                    filepathutil_removeslash(info->album);
                                    filepathutil_replace_slash(info->album, (ucs2_char_t)' ');
                              }
                        }
                  }
            }

            if (type == 1 || type == 5) {
                  /* Use filename as a title. */
                  info->title = ucs2dup(file);
                  filepathutil_remove_extension(info->title);
            } else if (type == 2 || type == 6) {
                  /* Use filename as a title and track number. */
                  info->tracknumer = 0;
                  p = file;
                  if (0x0030 <= *p && *p <= 0x0039) {
                        p++;
                        if (0x0030 <= *p && *p <= 0x0039) {
                              /* The filename begins with two numerical letters. */
                              p++;

                              /* Obtain track number. */
                              info->tracknumer = (uint32_t)ucs2toi(file);

                              /* Skip space and '_' letters. */
                              while (*p == 0x0020 || *p == 0x005F) {
                                    p++;
                              }

                              /* Obtain track title. */
                              info->title = ucs2dup(p);
                              filepathutil_remove_extension(info->title);
                              if (!info->title[0]) {
                                    /* If track title becomes empty (e.g., 01.mp3), set the filename. */
                                    ucs2free(info->title);
                                    info->title = ucs2dup(file);
                                    filepathutil_remove_extension(info->title);
                              }
                        } else {
                              /* The filename begins with one numerical letter. */
                              info->title = ucs2dup(file);
                              filepathutil_remove_extension(info->title);
                        }
                  } else {
                        /* The filename does not begin with a numerical letter. */
                        info->title = ucs2dup(file);
                        filepathutil_remove_extension(info->title);
                  }
            }
      } else {
            return 1;
      }

      return 0;
}

static int progress(void *instance, int msg, int progress, int max_progress)
{
      int ret = 0;
      update_dat_t *ud = (update_dat_t *)instance;
      
      /* Does nothing if callback is not specified. */
      if (!ud->proc) {
            return 0;
      }

      if (max_progress == 0) {
            progress = 0;
            max_progress = 1;
      }

      switch (msg) {
      case H10DB_PROGRESS_IDX_COUNT:
            if (max_progress > 0) {
                  ud->idx_progress_coeff = 1.0 / max_progress;
                  ud->idx_progress_const = 100.0 * progress * ud->idx_progress_coeff;
            } else {
                  ud->idx_progress_coeff = 1.0;
                  ud->idx_progress_const = 0.0;
            }
            break;

      case H10DB_PROGRESS_READ_START:
            ret = ud->proc(ud->instance, EASYH10P_READ_START, 0, NULL);
            break;
      case H10DB_PROGRESS_READ_HDR:
            ret = ud->proc(ud->instance, EASYH10P_READ_HDR, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_READ_DAT:
            ret = ud->proc(ud->instance, EASYH10P_READ_DAT, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_READ_IDX:
            ret = ud->proc(ud->instance, EASYH10P_READ_IDX, (int)(ud->idx_progress_const + ud->idx_progress_coeff * (progress * 100 / max_progress)), NULL);
            break;
      case H10DB_PROGRESS_READ_UPD:
            ret = ud->proc(ud->instance, EASYH10P_READ_UPD, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_READ_END:
            ret = ud->proc(ud->instance, EASYH10P_READ_END, 0, NULL);
            break;

      case H10DB_PROGRESS_WRITE_START:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_START, 0, NULL);
            break;
      case H10DB_PROGRESS_WRITE_HDR:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_HDR, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_WRITE_DAT:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_DAT, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_WRITE_IDX:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_IDX, (int)(ud->idx_progress_const + ud->idx_progress_coeff * (progress * 100 / max_progress)), NULL);
            break;
      case H10DB_PROGRESS_WRITE_UPD:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_UPD, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_WRITE_END:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_END, 0, NULL);
            break;

      case H10DB_PROGRESS_UPDATE_START:
            ret = ud->proc(ud->instance, EASYH10P_UPDATE_START, 0, NULL);
            break;
      case H10DB_PROGRESS_UPDATE_CLEAN:
            if (progress == 1) {
                  ret = ud->proc(ud->instance, EASYH10P_DB_NUM_UNUSED, max_progress, NULL);
            } else {
                  ret = ud->proc(ud->instance, EASYH10P_UPDATE_CLEAN, 0, NULL);
            }
            break;
      case H10DB_PROGRESS_UPDATE_IDX:
            ret = ud->proc(ud->instance, EASYH10P_UPDATE_IDX, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_UPDATE_END:
            ret = ud->proc(ud->instance, EASYH10P_UPDATE_END, 0, NULL);
            break;

      case H10DB_PROGRESS_READ_TEMPLATE:
            ret = ud->proc(ud->instance, EASYH10P_READ_MODEL, progress * 100 / max_progress, NULL);
            break;
      case H10DB_PROGRESS_WRITE_TEMPLATE:
            ret = ud->proc(ud->instance, EASYH10P_WRITE_MODEL, progress * 100 / max_progress, NULL);
            break;

      }
      return ret;
}


struct tag_sorting_track {
      int order;
      int index;
      ucs2_char_t* head_artist;
      media_info* info;
};
typedef struct tag_sorting_track sorting_track_t;

static int compare_string(const ucs2_char_t* x, const ucs2_char_t* y)
{
      if (!x || !*x) {
            return ((!y || !*y) ? 0 : 1);
      } else {
            return ((!y || !*y) ? -1 : ucs2icmp(x, y));
      }
}

static int compare_titlename(const void* _x, const void* _y)
{
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;
      return compare_string(x->info->title, y->info->title);
}

static int compare_filename(const void* _x, const void* _y)
{
      int ret = 0;
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;
      ret = compare_string(x->info->pathname, y->info->pathname);
      if (ret == 0) {
            return compare_string(x->info->filename, y->info->filename);
      }
      return ret;
}

static int compare_album_tracknumber(const void* _x, const void* _y)
{
      int ret = 0;
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;

      /* Just compare album names in case of omnibus albums with different artists. */
      ret = compare_string(x->info->album, y->info->album);
      if (ret == 0) {
            ret = COMP(x->info->tracknumer, y->info->tracknumer);
            if (ret == 0) {
                  /* If the track numbers are identical, we rely on the filenames. */
                  return compare_string(x->info->filename, y->info->filename);
            }
      }
      return ret;
}

static int compare_artist_tracknumber(const void* _x, const void* _y)
{
      int ret = 0;
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;

      /* Compare head artist names (for omnibus albums). */
      ret = compare_string(x->head_artist, y->head_artist);
      if (ret == 0) {
            ret = compare_string(x->info->album, y->info->album);
            if (ret == 0) {
                  ret = COMP(x->info->tracknumer, y->info->tracknumer);
                  if (ret == 0) {
                        /* If the track numbers are identical, we rely on the filenames. */
                        return compare_string(x->info->filename, y->info->filename);
                  }
            }
      }
      return ret;
}

static int compare_allrandom(const void* _x, const void* _y)
{
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;
      return COMP(x->order, y->order);
}

static int compare_albumrandom(const void* _x, const void* _y)
{
      int ret = 0;
      const sorting_track_t* x = (const sorting_track_t*)_x;
      const sorting_track_t* y = (const sorting_track_t*)_y;
      ret = compare_string(x->info->album, y->info->album);
      if (ret == 0) {
            return COMP(x->order, y->order);
      }
      return ret;
}

static void set_head_of_album(sorting_track_t* array, int num)
{
      int i;
      ucs2_char_t* head_artist = NULL;

      for (i = 0;i < num;i++) {
            array[i].head_artist = NULL;
      }

      if (num > 0) {
            head_artist = array[0].info->artist;
            array[0].head_artist = head_artist;

            for (i = 1;i < num;i++) {
                  if (compare_string(array[i-1].info->album, array[i].info->album) != 0) {
                        head_artist = array[i].info->artist;
                  }
                  array[i].head_artist = head_artist;
            }
      }
}

struct tag_ordinal_element {
      int index;
      int ordinal_number;
      const ucs2_char_t* str;
};
typedef struct tag_ordinal_element ordinal_element_t;

static int compare_ordinal_element(const void* _x, const void* _y)
{
      const ordinal_element_t* x = (const ordinal_element_t*)_x;
      const ordinal_element_t* y = (const ordinal_element_t*)_y;
      return compare_string(x->str, y->str);
}

static void allocate_ordinal_numbers(ordinal_element_t* array, int num)
{
      int i, ordinal_number = -1;
      const ucs2_char_t* prev_str = NULL;

      qsort(array, num, sizeof(ordinal_element_t), compare_ordinal_element);

      for (i = 0;i < num;i++) {
            if (!prev_str || ucs2icmp(prev_str, array[i].str) != 0) {
                  ordinal_number++;
            }
            array[i].ordinal_number = ordinal_number;
            prev_str = array[i].str;
      }
}

static uint32_t translate_dbflag(uint32_t easyh10_flag)
{
      uint32_t h10db_flag = 0;

      if (easyh10_flag & EASYH10_DATABASE_INCREMENTAL) {
            h10db_flag |= H10DB_FLAG_INCREMENTAL;
      }
      if (easyh10_flag & EASYH10_DATABASE_CLEAN) {
            h10db_flag |= H10DB_UPDATEF_CLEAN;
      }
      h10db_flag |= (easyh10_flag & 0x0000FFFF);
      return h10db_flag;
}

static int dummy_progress_callback(void *instance, int phase, int param_int, void *param_ptr)
{
      return 0;
}

static void dummy_error_callback(void *instance, int code, void *param)
{
}

int easyh10_database(
      const ucs2_char_t* path_to_root,
      const ucs2_char_t* path_to_db,
      const ucs2_char_t* path_to_music,
      const ucs2_char_t* model_filename,
      const char *info_extractor,
      int flags,
      void *instance,
      update_progress_callback progress_proc,
      easyh10_error_callback error_proc
      )
{
      int i, j, ret = 0, h10db_flags = 0, order_type = 0, num_updates = 0;
      findfile_dat_t ffd;
      update_dat_t ud;
      h10db_t* h10db = NULL;

      /* Set dummy progress callback if progress_proc was NULL. */
      if (!progress_proc) {
            progress_proc = dummy_progress_callback;
      }

      /* Set dummy error callback if error_proc was NULL. */
      if (!error_proc) {
            error_proc = dummy_error_callback;
      }

      /* Enumerate music and playlist files in the music folder. */
      progress_proc(instance, EASYH10P_ENUMTARGETS_START, 0, NULL);
      ffd.num_targets = 0;
      ffd.targets = NULL;
      ffd.instance = instance;
      ffd.proc = progress_proc;
      find_file(path_to_music, 1, found_file, &ffd);

      progress_proc(instance, EASYH10P_ENUMTARGETS_END, ffd.num_targets, NULL);

      /* Create an instance of h10db_t. */
      h10db_flags = translate_dbflag(flags);
      h10db = h10db_new(h10db_flags);
      if (!h10db) {
            error_proc(instance, EASYH10_ERROR_INITLIBH10DB, NULL);
            goto database_error;
      }
      ud.instance = instance;
      ud.proc = progress_proc;
      h10db_set_instance(h10db, &ud);
      h10db_set_progress_callback(h10db, progress);

      /* Load model definition. */
      if (model_filename) {
            char type_message[80];
            char model_message[256];

            progress_proc(instance, EASYH10P_READ_MODEL_START, 0, (void*)model_filename);
            ret = h10db_load_model(h10db, model_filename);
            if (ret != 0) {
                  error_proc(instance, EASYH10_ERROR_LOADTEMPLATE, &ret);
                  goto database_error;
            }

            /* Generate progress message. */
            switch (h10db_get_type(h10db)) {
            case H10DB_FIRMWARE_UMS:
                  strcpy(type_message, "H10 (UMS)");
                  break;
            case H10DB_FIRMWARE_MTP:
                  strcpy(type_message, "H10 (MTP)");
                  break;
            case H10DB_FIRMWARE_MTP_2_50:
                  strcpy(type_message, "H10 (MTP2)");
                  break;
            default:
                  strcpy(type_message, "H10 (Unknown)");
                  break;
            }

            sprintf(
                  model_message,
                  "%s %dGB firmware %d.%02d - %d.%02d",
                  type_message,
                  h10db_get_capacity(h10db),
                  h10db_get_fw_major_min(h10db), h10db_get_fw_minor_min(h10db),
                  h10db_get_fw_major_max(h10db), h10db_get_fw_minor_max(h10db)
                  );

            progress_proc(instance, EASYH10P_READ_MODEL_END, 0, model_message);
      }

      if (flags & EASYH10_DATABASE_NEW) {
            /* Just expand h10db_dat array. */
            h10db_resize(h10db, ffd.num_targets);
            /* Initialize all entries. */
            for (i = 0;i < ffd.num_targets;i++) {
                  media_target_file_t* target = &ffd.targets[i];
                  h10db_dat_t* item = h10db_access_item(h10db, i);
                  ucs2_char_t path[MAX_PATH];

                  target->entry = i;
                  h10db_dat_init(item);

                  ucs2cpy(path, filepathutil_skiproot(target->path, path_to_root));
                  filepathutil_encode(path);
                  h10db_set_filepath(h10db, i, path);
                  h10db_set_filename(h10db, i, target->file);
            }
      } else {
            int num_found_entries = 0, num_disappeared_entries = 0, num_new_entries = 0;

            /* Read the database from the path specified. */
            ret = h10db_read(h10db, path_to_db);
            if (ret != 0) {
                  error_proc(instance, EASYH10_ERROR_READDB, &ret);
                  goto database_error;
            }

            /* Decode flipped field strings (only for right-to-left mode). */
            if (flags & EASYH10_DATABASE_RIGHTTOLEFT) {
                  for (i = 0;i < h10db_get_size(h10db);i++) {
                        h10db_righttoleft_decode_fields(h10db, i);
                  }
            }

            /* Walk through all the entries in the databse. */
            for (i = 0;i < h10db_get_size(h10db);i++) {
                  h10db_dat_t* item = h10db_access_item(h10db, i);

                  /* No interest for inactive entries. */
                  if (item->status == 0) {
                        int found = 0;
                        /* Search the file in media_targets (slow implementation). */
                        for (j = 0;j < ffd.num_targets;j++) {
                              media_target_file_t* target = &ffd.targets[j];
                              ucs2_char_t* path = ucs2dup(item->file_path);
                              filepathutil_decode(path);
                              found = (ucs2icmp(filepathutil_skiproot(target->path, path_to_root), path) == 0) && (ucs2icmp(target->file, item->file_name) == 0);
                              ucs2free(path);

                              if (found) {
                                    /* Store the entry number */
                                    target->entry = i;
                                    num_found_entries++;
                                    break;
                              }
                        }
                        if (!found) {
                              /* Inactivate this entry. */
                              item->status = 1;
                              num_disappeared_entries++;
                        }
                  }
            }

            /* Calculate number of new enties to the database. */
            num_new_entries = ffd.num_targets - num_found_entries;

            progress_proc(instance, EASYH10P_DB_NUM_EXISTING, num_found_entries, NULL);
            progress_proc(instance, EASYH10P_DB_NUM_NEW, num_new_entries, NULL);
            progress_proc(instance, EASYH10P_DB_NUM_DISAPPEARED, num_disappeared_entries, NULL);

            if (num_new_entries > 0) {
                  /* Expand h10db_dat array for new entries. */
                  int entry = h10db_get_size(h10db);
                  h10db_resize(h10db, entry + num_new_entries);

                  /* Initialize new entries. */
                  for (i = 0;i < ffd.num_targets;i++) {
                        media_target_file_t* target = &ffd.targets[i];
                        if (target->entry < 0) {
                              ucs2_char_t path[MAX_PATH];
                              h10db_dat_t* item = h10db_access_item(h10db, entry);
                              target->entry = entry;

                              ucs2cpy(path, filepathutil_skiproot(target->path, path_to_root));
                              filepathutil_encode(path);

                              h10db_dat_init(item);
                              h10db_set_filepath(h10db, entry, path);
                              h10db_set_filename(h10db, entry, target->file);

                              entry++;
                        }
                  }
            }
      }


      /* Number of updated media_targets */
      num_updates = ffd.num_targets;

      for (i = 0;i < ffd.num_targets;i++) {
            ucs2_char_t filename[MAX_PATH];
            media_target_file_t* target = &ffd.targets[i];
            uint32_t mt_previous = 0, mt_current = 0;

            filepathutil_combinepath(filename, MAX_PATH, target->path, target->file);
            mt_current = (uint32_t)ucs2stat_mtime(filename);
            mt_previous = h10db_get_unknown4(h10db, target->entry);
            if ((flags & EASYH10_DATABASE_INCREMENTAL) &&
                  mt_current && mt_previous && mt_current == mt_previous) {
                  target->update = 0;
                  num_updates--;
            } else {
                  target->update = 1;
            }
            h10db_set_unknown4(h10db, target->entry, mt_current);
      }

      progress_proc(instance, EASYH10P_DB_NUM_OBTAIN, num_updates, NULL);

      /* Create h10db_dat for each target file. */
      j = 0;
      progress_proc(instance, EASYH10P_GETINFO_START, num_updates, NULL);
      for (i = 0;i < ffd.num_targets;i++) {
            media_target_file_t* target = &ffd.targets[i];
            if (target->update) {
                  progress_proc(instance, EASYH10P_GETINFO_FILE, ++j, (void*)target->file);

                  /* Obtain media information from tag. */
                  if (filepathutil_hasext(target->file, ucs2cs_mp3)) {
                        gettag_mp3(&target->info, target->path, target->file);
                  } else if (filepathutil_hasext(target->file, ucs2cs_wma)) {
                        gettag_wma(&target->info, target->path, target->file);
                  } else if (filepathutil_hasext(target->file, ucs2cs_wav)) {
                        gettag_wav(&target->info, target->path, target->file);
                  }

                  if (info_extractor && *info_extractor) {
                        /* Replace media information with information from path/file name. */
                        taginfo_from_pathfile(&target->info, target->path, target->file, path_to_music, info_extractor);
                  }

                  gettag_set_info(h10db, target->entry, &target->info);
            } else {
                  gettag_get_info(h10db, target->entry, &target->info);
                  gettag_set_info(h10db, target->entry, &target->info);
            }
      }
      progress_proc(instance, EASYH10P_GETINFO_END, j, NULL);

      /* Change track number according to the user's demand. */
      order_type = (flags & EASYH10_DATABASE_ORDERUNMASK);

      /* We cannot use "default" ordering when right-to-left mode. */
      if ((flags & EASYH10_DATABASE_RIGHTTOLEFT) && order_type == EASYH10_DATABASE_ORDER_LEAVE) {
            order_type = EASYH10_DATABASE_ORDER_TRACKNUMBER;
      }

      if (order_type) {
            int num = ffd.num_targets;
            sorting_track_t* array = (sorting_track_t*)malloc(sizeof(sorting_track_t) * ffd.num_targets);
            if (!array) {
                  error_proc(instance, EASYH10_ERROR_OUTOFMEMORY, NULL);
                  goto database_error;
            }

            /* Initialize random seed. */
            srand((unsigned int)time(NULL));

            for (i = 0;i < ffd.num_targets;i++) {
                  array[i].index = i;
                  array[i].info = &ffd.targets[i].info;
                  array[i].head_artist = NULL;
                  array[i].order = rand();
            }

            switch (order_type) {
            case EASYH10_DATABASE_ORDER_TRACKNAME:
                  qsort(array, num, sizeof(sorting_track_t), compare_titlename);
                  break;
            case EASYH10_DATABASE_ORDER_FILENAME:
                  qsort(array, num, sizeof(sorting_track_t), compare_filename);
                  break;
            case EASYH10_DATABASE_ORDER_TRACKNUMBER:
                  qsort(array, num, sizeof(sorting_track_t), compare_album_tracknumber);
                  set_head_of_album(array, num);
                  qsort(array, num, sizeof(sorting_track_t), compare_artist_tracknumber);
                  break;
            case EASYH10_DATABASE_ORDER_COMPLETERANDOM:
                  qsort(array, num, sizeof(sorting_track_t), compare_allrandom);
                  break;
            case EASYH10_DATABASE_ORDER_ALBUMRANDOM:
                  qsort(array, num, sizeof(sorting_track_t), compare_album_tracknumber);
                  set_head_of_album(array, num);
                  qsort(array, num, sizeof(sorting_track_t), compare_artist_tracknumber);
                  break;
            case EASYH10_DATABASE_ORDER_ALLRANDOM:
                  qsort(array, num, sizeof(sorting_track_t), compare_allrandom);
                  break;
            }

            /* Modify the title and track number. */
            if (order_type == EASYH10_DATABASE_ORDER_ALBUMRANDOM) {
                  for (i = 0;i < ffd.num_targets;i++) {
                        ffd.targets[array[i].index].info.tracknumer = (uint32_t)i;
                  }
                  for (i = 0;i < ffd.num_targets;i++) {
                        gettag_force_order(h10db, ffd.targets[i].entry, ffd.targets[i].info.tracknumer, ffd.num_targets);
                        h10db_set_tracknumber(h10db, ffd.targets[i].entry, (uint32_t)rand());
                  }
            } else if (order_type == EASYH10_DATABASE_ORDER_ALLRANDOM) {
                  for (i = 0;i < ffd.num_targets;i++) {
                        int j = array[i].index;
                        uint32_t tracknumber = h10db_get_tracknumber(h10db, ffd.targets[j].entry);
                        gettag_force_order(h10db, ffd.targets[j].entry, (uint32_t)i, ffd.num_targets);
                        h10db_set_tracknumber(h10db, ffd.targets[j].entry, tracknumber);
                  }
            } else {
                  for (i = 0;i < ffd.num_targets;i++) {
                        ffd.targets[array[i].index].info.tracknumer = (uint32_t)i;
                  }
                  for (i = 0;i < ffd.num_targets;i++) {
                        gettag_force_order(h10db, ffd.targets[i].entry, ffd.targets[i].info.tracknumer, ffd.num_targets);
                  }
            }

            free(array);
      }

      /* Allocate ordinal numbers for artist, album, and genre names (only for right-to-left mode). */
      if (flags & EASYH10_DATABASE_RIGHTTOLEFT) {
            int num = ffd.num_targets;
            ordinal_element_t* array = (ordinal_element_t*)malloc(sizeof(ordinal_element_t) * num);

            /* Allocate ordinal numbers for artist names. */
            for (i = 0;i < num;i++) {
                  array[i].index = i;
                  array[i].str = h10db_get_artist(h10db, i);
            }
            allocate_ordinal_numbers(array, num);
            for (i = 0;i < num;i++) {
                  ucs2_char_t* new_str = gettag_insert_ordinalnumber(array[i].str, array[i].ordinal_number, num);
                  h10db_set_artist(h10db, array[i].index, new_str);
                  ucs2free(new_str);
            }

            /* Allocate ordinal numbers for album names. */
            for (i = 0;i < num;i++) {
                  array[i].index = i;
                  array[i].str = h10db_get_album(h10db, i);
            }
            allocate_ordinal_numbers(array, num);
            for (i = 0;i < num;i++) {
                  ucs2_char_t* new_str = gettag_insert_ordinalnumber(array[i].str, array[i].ordinal_number, num);
                  h10db_set_album(h10db, array[i].index, new_str);
                  ucs2free(new_str);
            }

            /* Allocate ordinal numbers for genre names. */
            for (i = 0;i < num;i++) {
                  array[i].index = i;
                  array[i].str = h10db_get_genre(h10db, i);
            }
            allocate_ordinal_numbers(array, num);
            for (i = 0;i < num;i++) {
                  ucs2_char_t* new_str = gettag_insert_ordinalnumber(array[i].str, array[i].ordinal_number, num);
                  h10db_set_genre(h10db, array[i].index, new_str);
                  ucs2free(new_str);
            }
      }

      /* Fit fields for each dat entry. */
      for (i = 0;i < h10db_get_size(h10db);i++) {
            h10db_fit_fields(h10db, i);
      }

      /* Flip field strings (only for right-to-left mode). */
      if (flags & EASYH10_DATABASE_RIGHTTOLEFT) {
            for (i = 0;i < h10db_get_size(h10db);i++) {
                  h10db_righttoleft_encode_fields(h10db, i);
            }
      }

      /* Update the database. */
      ret = h10db_update(h10db, h10db_flags);
      if (ret != 0) {
            error_proc(instance, EASYH10_ERROR_UPDATEDB, &ret);
            goto database_error;
      }

      /* Write the database. */
      ret = h10db_write(h10db, path_to_db);
      if (ret != 0) {
            error_proc(instance, EASYH10_ERROR_WRITEDB, &ret);
            goto database_error;
      }

      /* Exit with success. */
      h10db_delete(h10db);
      free(ffd.targets);
      return 0;

database_error:
      h10db_delete(h10db);
      free(ffd.targets);
      return 1;   
}

Generated by  Doxygen 1.6.0   Back to index