summaryrefslogtreecommitdiffstats
path: root/src/db-artwork-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db-artwork-parser.c')
-rw-r--r--src/db-artwork-parser.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c
new file mode 100644
index 0000000..69f3b83
--- /dev/null
+++ b/src/db-artwork-parser.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2005 Christophe Fergeau
+ *
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * iTunes and iPod are trademarks of Apple
+ *
+ * This product is not supported/written/published by Apple!
+ *
+ */
+
+#include "itdb.h"
+#include "db-artwork-debug.h"
+#include "db-artwork-parser.h"
+#include "db-image-parser.h"
+#include "db-itunes-parser.h"
+#include "db-parse-context.h"
+/*#include "image-parser.h"*/
+
+typedef int (*ParseListItem)(DBParseContext *ctx, Itdb_iTunesDB *db, GError *error);
+
+static Itdb_Track *
+get_song_by_dbid (Itdb_iTunesDB *db, guint64 id)
+{
+ GList *it;
+
+ for (it = db->tracks; it != NULL; it = it->next) {
+ Itdb_Track *song;
+
+ song = (Itdb_Track*)it->data;
+ if (song->dbid == id) {
+ return song;
+ }
+ }
+ return NULL;
+}
+
+
+static int
+parse_mhif (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
+{
+ MhifHeader *mhif;
+
+ mhif = db_parse_context_get_m_header (ctx, MhifHeader, "mhif");
+ if (mhif == NULL) {
+ return -1;
+ }
+ dump_mhif (mhif);
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhif->total_len));
+ return 0;
+}
+
+#ifdef DEBUG_ARTWORKDB
+static int
+parse_mhod_3 (DBParseContext *ctx, GError *error)
+{
+ MhodHeader *mhod;
+ MhodHeaderArtworkType3 *mhod3;
+
+ mhod = db_parse_context_get_m_header (ctx, MhodHeader, "mhod");
+ if (mhod == NULL) {
+ return -1;
+ }
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhod->total_len));
+
+ if (GINT_FROM_LE (mhod->total_len) < sizeof (MhodHeaderArtworkType3)){
+ return -1;
+ }
+ mhod3 = (MhodHeaderArtworkType3*)mhod;
+ dump_mhod_type_3 (mhod3);
+ if ((GINT_FROM_LE (mhod3->type) & 0xff) != MHOD_TYPE_ALBUM) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+#define FULL_THUMB_SIDE_LEN 0x8c
+#define NOW_PLAYING_THUMB_SIDE_LEN 0x38
+
+static int
+parse_mhni (DBParseContext *ctx, iPodSong *song, GError *error)
+{
+ MhniHeader *mhni;
+ int width;
+ int height;
+
+ mhni = db_parse_context_get_m_header (ctx, MhniHeader, "mhni");
+ if (mhni == NULL) {
+ return -1;
+ }
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhni->total_len));
+
+ dump_mhni (mhni);
+#ifdef DEBUG_ARTWORKDB
+ {
+ DBParseContext *mhod_ctx;
+
+ /* No information useful to us in mhod type 3, do not parse
+ * it in non-debug mode
+ */
+ mhod_ctx = db_parse_context_get_sub_context (ctx, ctx->header_len);
+ if (mhod_ctx == NULL) {
+ return -1;
+ }
+ parse_mhod_3 (mhod_ctx, NULL);
+ g_free (mhod_ctx);
+ }
+#else
+ width = (GINT_FROM_LE (mhni->image_dimensions) & 0xffff0000) >> 16;
+ height = (GINT_FROM_LE (mhni->image_dimensions) & 0x0000ffff);
+
+ if ((width == FULL_THUMB_SIDE_LEN) || (width == FULL_THUMB_SIDE_LEN)) {
+ song->full_size_thumbnail = ipod_image_new_from_mhni (mhni, song->itdb->mountpoint);
+ } else if ((width == NOW_PLAYING_THUMB_SIDE_LEN) || (width == NOW_PLAYING_THUMB_SIDE_LEN)) {
+ song->now_playing_thumbnail = ipod_image_new_from_mhni (mhni, song->itdb->mountpoint);
+ } else {
+ g_print ("Unrecognized image size: %08x\n",
+ GINT_FROM_LE (mhni->image_dimensions));
+ }
+#endif
+ return 0;
+}
+
+static int
+parse_mhod (DBParseContext *ctx, iPodSong *song, GError *error)
+{
+ MhodHeader *mhod;
+ DBParseContext *mhni_ctx;
+
+ mhod = db_parse_context_get_m_header (ctx, MhodHeader, "mhod");
+ if (mhod == NULL) {
+ return -1;
+ }
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhod->total_len));
+ dump_mhod (mhod);
+
+ if (GINT_FROM_LE (mhod->type) != MHOD_TYPE_LOCATION) {
+ return -1;
+ }
+
+ mhni_ctx = db_parse_context_get_sub_context (ctx, ctx->header_len);
+ if (mhni_ctx == NULL) {
+ return -1;
+ }
+ parse_mhni (mhni_ctx, song, NULL);
+ g_free (mhni_ctx);
+
+ return 0;
+}
+
+
+static int
+parse_mhii (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
+{
+ MhiiHeader *mhii;
+ DBParseContext *mhod_ctx;
+ int num_children;
+ off_t cur_offset;
+ iPodSong *song;
+
+ mhii = db_parse_context_get_m_header (ctx, MhiiHeader, "mhii");
+ if (mhii == NULL) {
+ return -1;
+ }
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhii->total_len));
+
+ dump_mhii (mhii);
+
+#ifdef DEBUG_ARTWORKDB
+ song = NULL;
+#else
+ song = get_song_by_dbid (db, GINT64_FROM_LE (mhii->song_id));
+ if (song == NULL) {
+ return -1;
+ }
+
+ song->orig_image = ipod_image_new_from_mhii (mhii);
+#endif
+
+ cur_offset = ctx->header_len;
+ mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ num_children = GINT_FROM_LE (mhii->num_children);
+ while ((num_children > 0) && (mhod_ctx != NULL)) {
+ parse_mhod (mhod_ctx, song, NULL);
+ num_children--;
+ cur_offset += mhod_ctx->total_len;
+ g_free (mhod_ctx);
+ mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ }
+
+ return 0;
+}
+
+
+static int
+parse_mhl (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error,
+ const char *id, ParseListItem parse_child)
+{
+ MhlHeader *mhl;
+ int num_children;
+ DBParseContext *mhi_ctx;
+ off_t cur_offset;
+
+ mhl = db_parse_context_get_m_header (ctx, MhlHeader, id);
+ if (mhl == NULL) {
+ return -1;
+ }
+
+ dump_mhl (mhl, id);
+
+ num_children = GINT_FROM_LE (mhl->num_children);
+ if (num_children < 0) {
+ return -1;
+ }
+
+ cur_offset = ctx->header_len;
+ mhi_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ while ((num_children > 0) && (mhi_ctx != NULL)) {
+ if (parse_child != NULL) {
+ parse_child (mhi_ctx, db, NULL);
+ }
+ num_children--;
+ cur_offset += mhi_ctx->total_len;
+ g_free (mhi_ctx);
+ mhi_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ }
+
+ return 0;
+
+}
+
+
+static int
+parse_mhsd (DBParseContext *ctx, Itdb_iTunesDB *db, GError **error)
+{
+ MhsdHeader *mhsd;
+
+ mhsd = db_parse_context_get_m_header (ctx, MhsdHeader, "mhsd");
+ if (mhsd == NULL) {
+ return -1;
+ }
+
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhsd->total_len));
+ dump_mhsd (mhsd);
+ switch (GINT_FROM_LE (mhsd->index)) {
+ case MHSD_IMAGE_LIST: {
+ DBParseContext *mhli_context;
+ mhli_context = db_parse_context_get_next_child (ctx);
+ parse_mhl (mhli_context, db, NULL, "mhli", parse_mhii);
+ g_free (mhli_context);
+ break;
+ }
+ case MHSD_ALBUM_LIST: {
+ DBParseContext *mhla_context;
+ mhla_context = db_parse_context_get_next_child (ctx);
+ parse_mhl (mhla_context, db, NULL, "mhla", NULL);
+ g_free (mhla_context);
+ break;
+ }
+ case MHSD_FILE_LIST: {
+ DBParseContext *mhlf_context;
+ mhlf_context = db_parse_context_get_next_child (ctx);
+ parse_mhl (mhlf_context, db, NULL, "mhlf", parse_mhif);
+ g_free (mhlf_context);
+ break;
+ }
+ default:
+ g_warning ("Unexpected mhsd index: %d\n",
+ GINT_FROM_LE (mhsd->index));
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+/* Database Object */
+static int
+parse_mhfd (DBParseContext *ctx, Itdb_iTunesDB *db, GError **error)
+{
+ MhfdHeader *mhfd;
+ DBParseContext *mhsd_context;
+ unsigned int cur_pos;
+
+ mhfd = db_parse_context_get_m_header (ctx, MhfdHeader, "mhfd");
+ if (mhfd == NULL) {
+ return -1;
+ }
+
+ /* Sanity check */
+ g_assert (GINT_FROM_LE (mhfd->total_len) == ctx->total_len);
+ dump_mhfd (mhfd);
+ cur_pos = ctx->header_len;
+
+ mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos);
+ if (mhsd_context == NULL) {
+ return -1;
+ }
+ parse_mhsd (mhsd_context, db, NULL);
+ cur_pos += mhsd_context->total_len;
+ g_free (mhsd_context);
+
+ mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos);
+ if (mhsd_context == NULL) {
+ return -1;
+ }
+ parse_mhsd (mhsd_context, db, NULL);
+ cur_pos += mhsd_context->total_len;
+ g_free (mhsd_context);
+
+ mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos);
+ if (mhsd_context == NULL) {
+ return -1;
+ }
+ parse_mhsd (mhsd_context, db, NULL);
+ cur_pos += mhsd_context->total_len;
+ g_free (mhsd_context);
+
+ return 0;
+}
+
+
+G_GNUC_INTERNAL char *
+ipod_db_get_artwork_db_path (Itdb_iTunesDB *db)
+{
+ return g_build_filename (G_DIR_SEPARATOR_S, db->mountpoint,
+ "iPod_Control", "Artwork", "ArtworkDB",
+ NULL);
+}
+
+
+static char *
+ipod_db_get_photo_db_path (const char *mount_point)
+{
+ g_return_val_if_fail (mount_point != NULL, NULL);
+ return g_build_filename (G_DIR_SEPARATOR_S, mount_point,
+ "Photos", "Photo Database",
+ NULL);
+}
+
+
+int
+ipod_parse_artwork_db (Itdb_iTunesDB *db)
+{
+ DBParseContext *ctx;
+ char *filename;
+
+ filename = ipod_db_get_artwork_db_path (db);
+ ctx = db_parse_context_new_from_file (filename);
+ g_free (filename);
+ if (ctx == NULL) {
+ goto error;
+ }
+
+ parse_mhfd (ctx, db, NULL);
+ g_free (ctx);
+ return 0;
+
+ error:
+ /* FIXME: needs to destroy ctx and to release the mmap'ed memory*/
+ return -1;
+}
+
+int
+ipod_parse_photo_db (const char *mount_point)
+{
+ DBParseContext *ctx;
+ char *filename;
+
+ filename = ipod_db_get_photo_db_path (mount_point);
+ if (filename == NULL) {
+ return -1;
+ }
+ ctx = db_parse_context_new_from_file (filename);
+ g_free (filename);
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ parse_mhfd (ctx, NULL, NULL);
+ g_free (ctx);
+ return 0;
+}