summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJorg Schuler <jcsjcs@users.sourceforge.net>2005-09-19 10:30:50 +0000
committerJorg Schuler <jcsjcs@users.sourceforge.net>2005-09-19 10:30:50 +0000
commit7278b29a031119ce8da1ea6022de8b70b49ee577 (patch)
treeb98944ba47d504e70fdb04bf7f858c7be365b4d7 /src
parentdb92f98a83f98715538b6c91c0dfd6694d9ef079 (diff)
downloadlibgpod-tmz-7278b29a031119ce8da1ea6022de8b70b49ee577.tar.gz
libgpod-tmz-7278b29a031119ce8da1ea6022de8b70b49ee577.tar.xz
libgpod-tmz-7278b29a031119ce8da1ea6022de8b70b49ee577.zip
* applied patch provided by Christophe Fergeau <teuf at gnome.org>
for artwork database support (read-only). git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1093 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am12
-rw-r--r--src/db-artwork-debug.c182
-rw-r--r--src/db-artwork-debug.h51
-rw-r--r--src/db-artwork-parser.c398
-rw-r--r--src/db-artwork-parser.h39
-rw-r--r--src/db-image-parser.c220
-rw-r--r--src/db-image-parser.h34
-rw-r--r--src/db-itunes-parser.h540
-rw-r--r--src/db-parse-context.c196
-rw-r--r--src/db-parse-context.h53
-rw-r--r--src/itdb.h33
-rw-r--r--src/itdb_itunesdb.c15
12 files changed, 1770 insertions, 3 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e0998fd..1a46d92 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,7 +5,17 @@ libgpod_la_SOURCES = \
itdb_itunesdb.c \
itdb_playlist.c \
itdb_private.h \
- itdb_track.c
+ itdb_track.c \
+ db-artwork-parser.c \
+ db-artwork-parser.h \
+ db-parse-context.c \
+ db-parse-context.h \
+ db-artwork-debug.c \
+ db-artwork-debug.h \
+ db-image-parser.c \
+ db-image-parser.h
+
+
libgpod_la_headers = itdb.h
libgpod_la_noinst_headers = itdb_private.h
libgpod_la_LDFLAGS = -version-info $(LIBGPOD_CURRENT):$(LIBGPOD_REVISION):$(LIBGPOD_AGE) \
diff --git a/src/db-artwork-debug.c b/src/db-artwork-debug.c
new file mode 100644
index 0000000..d8ccb96
--- /dev/null
+++ b/src/db-artwork-debug.c
@@ -0,0 +1,182 @@
+/*
+ * 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 "db-artwork-debug.h"
+
+#ifdef DEBUG_ARTWORKDB
+G_GNUC_INTERNAL void
+dump_mhif (MhifHeader *mhif)
+{
+
+ g_print ("MHIF (%d):\n", sizeof (MhifHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhif->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhif->total_len));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhif->unknown1));
+ g_print ("\tCorrelation ID: %d (=> F%d_1.ithmb)\n",
+ GINT_FROM_LE (mhif->correlation_id),
+ GINT_FROM_LE (mhif->correlation_id));
+ g_print ("\tImage size: %d bytes\n", GINT_FROM_LE (mhif->image_size));
+}
+
+
+static char *
+get_utf16_string (void* buffer, gint length)
+{
+ char *result;
+ gunichar2 *tmp;
+ int i;
+ /* Byte-swap the utf16 characters if necessary (I'm relying
+ * on gcc to optimize most of this code away on LE platforms)
+ */
+ tmp = g_memdup (buffer, length);
+ for (i = 0; i < length/2; i++) {
+ tmp[i] = GINT16_FROM_LE (tmp[i]);
+ }
+ result = g_utf16_to_utf8 (tmp, length/2, NULL, NULL, NULL);
+ g_free (tmp);
+
+ return result;
+
+}
+
+G_GNUC_INTERNAL void
+dump_mhod_type_3 (MhodHeaderArtworkType3 *mhod3)
+{
+ gchar *str;
+
+ g_print ("MHOD (%d):\n", sizeof (MhodHeaderArtworkType3));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhod3->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhod3->total_len));
+ g_print ("\tType: %d\n", GINT_FROM_LE (mhod3->type));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhod3->unknown1));
+ g_print ("\tUnknown2: %08x\n", GINT_FROM_LE (mhod3->unknown2));
+ g_print ("\tString length: %u\n", GINT_FROM_LE (mhod3->string_len));
+ g_print ("\tMHOD version: %u\n", GINT_FROM_LE (mhod3->mhod_version));
+ g_print ("\tUnknown4: %08x\n", GINT_FROM_LE (mhod3->unknown4));
+ str = get_utf16_string (mhod3->string, mhod3->string_len);
+ g_print ("\tString: %s\n", str);
+ g_free (str);
+}
+
+G_GNUC_INTERNAL void
+dump_mhni (MhniHeader *mhni)
+{
+ g_print ("MHNI (%d):\n", sizeof (MhniHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhni->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhni->total_len));
+ g_print ("\tNumber of children: %08x\n", GINT_FROM_LE (mhni->num_children));
+ g_print ("\tCorrelation ID: %d (=> F%d_1.ithmb)\n",
+ GINT_FROM_LE (mhni->correlation_id),
+ GINT_FROM_LE (mhni->correlation_id));
+ g_print ("\tithmb offset: %u bytes\n", GINT_FROM_LE (mhni->ithmb_offset));
+ g_print ("\tImage size: %u bytes\n", GINT_FROM_LE (mhni->image_size));
+ g_print ("\tUnknown3: %08x\n", GINT_FROM_LE (mhni->unknown3));
+ g_print ("\tImage dimensions: %08x\n", GINT_FROM_LE (mhni->image_dimensions));
+}
+
+G_GNUC_INTERNAL void
+dump_mhod (MhodHeader *mhod)
+{
+ g_print ("MHOD (%d):\n", sizeof (MhodHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhod->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhod->total_len));
+ g_print ("\tType: %d\n", GINT_FROM_LE (mhod->type));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhod->unknown1));
+ g_print ("\tUnknown2: %08x\n", GINT_FROM_LE (mhod->unknown2));
+}
+
+G_GNUC_INTERNAL void
+dump_mhii (MhiiHeader *mhii)
+{
+ g_print ("MHII (%d):\n", sizeof (MhiiHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhii->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhii->total_len));
+ g_print ("\tNumber of children: %d\n", GINT_FROM_LE (mhii->num_children));
+ g_print ("\tImage ID: %08x\n", GINT_FROM_LE (mhii->image_id));
+ g_print ("\tSong ID: %016llx\n", GINT64_FROM_LE (mhii->song_id));
+ g_print ("\tUnknown4: %08x\n", GINT_FROM_LE (mhii->unknown4));
+ g_print ("\tUnknown5: %08x\n", GINT_FROM_LE (mhii->unknown5));
+ g_print ("\tUnknown6: %08x\n", GINT_FROM_LE (mhii->unknown6));
+ g_print ("\tUnknown7: %08x\n", GINT_FROM_LE (mhii->unknown7));
+ g_print ("\tUnknown8: %08x\n", GINT_FROM_LE (mhii->unknown8));
+ g_print ("\tImage size: %d bytes\n", GINT_FROM_LE (mhii->orig_img_size));
+}
+
+G_GNUC_INTERNAL void
+dump_mhl (MhlHeader *mhl, const char *id)
+{
+ GString *str;
+
+ str = g_string_new (id);
+ g_string_ascii_up (str);
+ g_print ("%s (%d):\n", str->str, sizeof (MhlHeader));
+ g_print ("\tHeader size: %d\n", GINT_FROM_LE (mhl->header_len));
+ g_print ("\tNumber of items: %d\n", GINT_FROM_LE (mhl->num_children));
+ g_string_free (str, TRUE);
+}
+
+G_GNUC_INTERNAL void
+dump_mhsd (MhsdHeader *mhsd)
+{
+ g_print ("MHSD (%d):\n", sizeof (MhsdHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhsd->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhsd->total_len));
+ g_print ("\tIndex: %d ", GINT_FROM_LE (mhsd->index));
+ switch (GINT_FROM_LE (mhsd->index)) {
+ case MHSD_IMAGE_LIST:
+ g_print ("(Image list)\n");
+ break;
+ case MHSD_ALBUM_LIST:
+ g_print ("(Album list)\n");
+ break;
+ case MHSD_FILE_LIST:
+ g_print ("(File list)\n");
+ break;
+
+ default:
+ g_print ("(Unknown index\n");
+ break;
+ }
+}
+
+G_GNUC_INTERNAL void
+dump_mhfd (MhfdHeader *mhfd)
+{
+ g_print ("MHFD (%d): \n", sizeof (MhfdHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhfd->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhfd->total_len));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhfd->unknown1));
+ g_print ("\tUnknown2: %08x\n", GINT_FROM_LE (mhfd->unknown2));
+ g_print ("\tNumber of children: %d\n", GINT_FROM_LE (mhfd->num_children));
+ g_print ("\tUnknown3: %08x\n", GINT_FROM_LE (mhfd->unknown3));
+ g_print ("\tUnknown4: %08x\n", GINT_FROM_LE (mhfd->unknown4));
+ g_print ("\tUnknown5: %016llx\n", GINT64_FROM_LE (mhfd->unknown5));
+ g_print ("\tUnknown6: %016llx\n", GINT64_FROM_LE (mhfd->unknown6));
+ g_print ("\tUnknown7: %08x\n", GINT_FROM_LE (mhfd->unknown7));
+ g_print ("\tUnknown8: %08x\n", GINT_FROM_LE (mhfd->unknown8));
+ g_print ("\tUnknown9: %08x\n", GINT_FROM_LE (mhfd->unknown9));
+ g_print ("\tUnknown10: %08x\n", GINT_FROM_LE (mhfd->unknown10));
+ g_print ("\tUnknown11: %08x\n", GINT_FROM_LE (mhfd->unknown11));
+}
+#endif
diff --git a/src/db-artwork-debug.h b/src/db-artwork-debug.h
new file mode 100644
index 0000000..fe9dd70
--- /dev/null
+++ b/src/db-artwork-debug.h
@@ -0,0 +1,51 @@
+/*
+ * 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!
+ *
+ */
+#ifndef DB_ARTWORK_DEBUG_H
+#define DB_ARTWORK_DEBUG_H
+
+#include "db-itunes-parser.h"
+
+/*#define DEBUG_ARTWORKDB*/
+
+#ifdef DEBUG_ARTWORKDB
+extern G_GNUC_INTERNAL void dump_mhif (MhifHeader *mhif);
+extern G_GNUC_INTERNAL void dump_mhod_type_3 (MhodHeaderArtworkType3 *mhod);
+extern G_GNUC_INTERNAL void dump_mhni (MhniHeader *mhni);
+extern G_GNUC_INTERNAL void dump_mhod (MhodHeader *mhod);
+extern G_GNUC_INTERNAL void dump_mhii (MhiiHeader *mhii);
+extern G_GNUC_INTERNAL void dump_mhl (MhlHeader *mhl, const char *id);
+extern G_GNUC_INTERNAL void dump_mhsd (MhsdHeader *mhsd);
+extern G_GNUC_INTERNAL void dump_mhfd (MhfdHeader *mhfd);
+#else
+#define dump_mhif(x)
+#define dump_mhod_type_3(x)
+#define dump_mhni(x)
+#define dump_mhod(x)
+#define dump_mhii(x)
+#define dump_mhl(x,y)
+#define dump_mhsd(x)
+#define dump_mhfd(x)
+#endif
+
+#endif
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;
+}
diff --git a/src/db-artwork-parser.h b/src/db-artwork-parser.h
new file mode 100644
index 0000000..06b0e09
--- /dev/null
+++ b/src/db-artwork-parser.h
@@ -0,0 +1,39 @@
+/*
+ * 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!
+ *
+ */
+
+
+#ifndef DB_PHOTO_PARSER_H
+#define DB_PHOTO_PARSER_H
+
+#include "itdb.h"
+
+#define iPodSong Itdb_Track
+
+int ipod_parse_photo_db (const char *filename);
+int ipod_parse_artwork_db (Itdb_iTunesDB *db);
+int ipod_write_artwork_db (Itdb_iTunesDB *db);
+
+G_GNUC_INTERNAL char *ipod_db_get_artwork_db_path (Itdb_iTunesDB *db);
+
+#endif
diff --git a/src/db-image-parser.c b/src/db-image-parser.c
new file mode 100644
index 0000000..a87485f
--- /dev/null
+++ b/src/db-image-parser.c
@@ -0,0 +1,220 @@
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "db-image-parser.h"
+
+#define RED_BITS 5
+#define RED_SHIFT 11
+#define RED_MASK (((1 << RED_BITS)-1) << RED_SHIFT)
+
+#define GREEN_BITS 6
+#define GREEN_SHIFT 5
+#define GREEN_MASK (((1 << GREEN_BITS)-1) << GREEN_SHIFT)
+
+#define BLUE_BITS 5
+#define BLUE_SHIFT 0
+#define BLUE_MASK (((1 << BLUE_BITS)-1) << BLUE_SHIFT)
+
+
+static unsigned char *
+unpack_RGB_565 (gushort *pixels, unsigned int bytes_len)
+{
+ unsigned char *result;
+ unsigned int i;
+
+ result = g_malloc ((bytes_len/2) * 3);
+ if (result == NULL) {
+ return NULL;
+ }
+ for (i = 0; i < bytes_len/2; i++) {
+ gushort cur_pixel;
+
+ cur_pixel = GINT16_FROM_LE (pixels[i]);
+ /* Unpack pixels */
+ result[3*i] = (pixels[i] & RED_MASK) >> RED_SHIFT;
+ result[3*i+1] = (pixels[i] & GREEN_MASK) >> GREEN_SHIFT;
+ result[3*i+2] = (pixels[i] & BLUE_MASK) >> BLUE_SHIFT;
+
+ /* Normalize color values so that they use a [0..255] range */
+ result[3*i] <<= (8 - RED_BITS);
+ result[3*i+1] <<= (8 - GREEN_BITS);
+ result[3*i+2] <<= (8 - BLUE_BITS);
+ }
+
+ return result;
+}
+
+#if 0
+G_GNUC_UNUSED static void
+pack_RGB_565 (GdkPixbuf *pixbuf, gushort **pixels565, unsigned int *bytes_len)
+{
+ guchar *pixels;
+ gushort *result;
+ gint row_stride;
+ gint channels;
+ gint width;
+ gint height;
+ gint w;
+ gint h;
+
+ g_object_get (G_OBJECT (pixbuf),
+ "rowstride", &row_stride, "n-channels", &channels,
+ "height", &height, "width", &width,
+ "pixels", &pixels, NULL);
+
+ result = g_malloc0 (width * height * 2);
+
+ for (h = 0; h < height; h++) {
+ for (w = 0; w < width; w++) {
+ gint r;
+ gint g;
+ gint b;
+
+ r = pixels[(h*row_stride + w)*channels];
+ g = pixels[(h*row_stride + w)*channels + 1];
+ b = pixels[(h*row_stride + w)*channels + 2];
+ r >>= (8 - RED_BITS);
+ g >>= (8 - GREEN_BITS);
+ b >>= (8 - BLUE_BITS);
+ r = (r << RED_SHIFT) & RED_MASK;
+ g = (g << GREEN_SHIFT) & GREEN_MASK;
+ b = (b << BLUE_SHIFT) & BLUE_MASK;
+ result[h*height + w] = (GINT16_TO_LE (r | g | b));
+ }
+ }
+
+ *pixels565 = result;
+ *bytes_len = width * height * 2;
+}
+#endif
+
+static unsigned char *
+get_pixel_data (Itdb_Image *image)
+{
+ unsigned char *result;
+ FILE *f;
+ int res;
+
+ f = NULL;
+ result = g_malloc (image->size);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ f = fopen (image->filename, "r");
+ if (f == NULL) {
+ g_print ("Failed to open %s: %s\n",
+ image->filename, strerror (errno));
+ goto end;
+ }
+
+ res = fseek (f, image->offset, SEEK_SET);
+ if (res != 0) {
+ g_print ("Seek to %lu failed on %s: %s\n",
+ image->offset, image->filename, strerror (errno));
+ goto end;
+ }
+
+ res = fread (result, image->size, 1, f);
+ if (res != 1) {
+ g_print ("Failed to read %u bytes from %s: %s\n",
+ image->size, image->filename, strerror (errno));
+ goto end;
+ }
+ fclose (f);
+
+ return result;
+
+ end:
+ if (f != NULL) {
+ fclose (f);
+ }
+ g_free (result);
+
+ return NULL;
+}
+
+unsigned char *
+itdb_image_get_rgb_data (Itdb_Image *image)
+{
+ void *pixels565;
+ void *pixels;
+
+ pixels565 = get_pixel_data (image);
+ if (pixels565 == NULL) {
+ return NULL;
+ }
+
+ pixels = unpack_RGB_565 (pixels565, image->size);
+ g_free (pixels565);
+
+ return pixels;
+
+ /* return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, FALSE,
+ 8, image->width, image->height,
+ image->width * 3,
+ (GdkPixbufDestroyNotify)g_free,
+ NULL);
+ */
+}
+
+G_GNUC_INTERNAL Itdb_Image *
+ipod_image_new_from_mhni (MhniHeader *mhni, const char *mount_point)
+{
+ Itdb_Image *img;
+
+ img = g_new0 (Itdb_Image, 1);
+ if (img == NULL) {
+ return NULL;
+ }
+ img->filename = g_strdup_printf ("%s/iPod_Control/Artwork/F%04u_1.ithmb", mount_point, GINT_FROM_LE (mhni->correlation_id));
+ img->size = GINT_FROM_LE (mhni->image_size);
+ img->offset = GINT_FROM_LE (mhni->ithmb_offset);
+ img->width = (GINT_FROM_LE (mhni->image_dimensions) & 0xffff0000) >> 16;
+ img->height = (GINT_FROM_LE (mhni->image_dimensions) & 0x0000ffff);
+
+ return img;
+}
+
+G_GNUC_INTERNAL Itdb_Image *
+ipod_image_new_from_mhii (MhiiHeader *mhii)
+{
+ Itdb_Image *img;
+
+ img = g_new0 (Itdb_Image, 1);
+ if (img == NULL) {
+ return NULL;
+ }
+ img->size = GINT_FROM_LE (mhii->orig_img_size);
+ img->id = GINT_FROM_LE (mhii->image_id);
+
+ return img;
+}
diff --git a/src/db-image-parser.h b/src/db-image-parser.h
new file mode 100644
index 0000000..0c36cc4
--- /dev/null
+++ b/src/db-image-parser.h
@@ -0,0 +1,34 @@
+/*
+ * 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!
+ *
+ */
+
+#ifndef IMAGE_PARSER_H
+#define IMAGE_PARSER_H
+
+#include "db-itunes-parser.h"
+#include "itdb.h"
+
+Itdb_Image *ipod_image_new_from_mhni (MhniHeader *mhni, const char *mount_point);
+Itdb_Image *ipod_image_new_from_mhii (MhiiHeader *mhii);
+
+#endif
diff --git a/src/db-itunes-parser.h b/src/db-itunes-parser.h
new file mode 100644
index 0000000..bf5f7f2
--- /dev/null
+++ b/src/db-itunes-parser.h
@@ -0,0 +1,540 @@
+/*
+ * 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!
+ *
+ */
+
+
+#ifndef DB_PARSER_H
+#define DB_PARSER_H
+
+#include <glib.h>
+/*#include "ipod-db-parser.h"*/
+
+#define ITUNESDB_MAX_SIZE 10 * 1024 * 1024
+
+struct _MHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+};
+
+typedef struct _MHeader MHeader;
+
+struct _MhlHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_children;
+ unsigned char padding[];
+};
+
+typedef struct _MhlHeader MhlHeader;
+
+
+typedef struct _MhbdHeader MhbdHeader;
+typedef struct _MhsdHeader MhsdHeader;
+typedef struct _MhltHeader MhltHeader;
+typedef struct _MhlpHeader MhlpHeader;
+typedef struct _MhypHeader MhypHeader;
+typedef struct _MhipHeader MhipHeader;
+typedef struct _MhitHeader MhitHeader;
+typedef struct _MhodHeader MhodHeader;
+typedef struct _MhfdHeader MhfdHeader;
+typedef struct _MhliHeader MhliHeader;
+typedef struct _MhiiHeader MhiiHeader;
+typedef struct _MhniHeader MhniHeader;
+typedef struct _MhlaHeader MhlaHeader;
+typedef struct _MhlfHeader MhlfHeader;
+typedef struct _MhifHeader MhifHeader;
+
+typedef struct _MhitHeader471 MhitHeader471;
+/* MHOD typedef mess */
+typedef struct _MhodHeaderString MhodHeaderString;
+typedef struct _MhodHeaderArtworkType3 MhodHeaderArtworkType3;
+typedef struct _MhodHeaderSmartPlaylistData MhodHeaderSmartPlaylistData;
+typedef struct _MhodHeaderSmartPlaylistRuleString MhodHeaderSmartPlaylistRuleString;
+typedef struct _MhodHeaderSmartPlaylistRuleNonString MhodHeaderSmartPlaylistRuleNonString;
+typedef struct _MhodHeaderSmartPlaylistRule MhodHeaderSmartPlaylistRule;
+
+struct _MhbdHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 unknown1;
+ gint32 version;
+ gint32 num_children;
+ gint64 db_id;
+ gint32 unknown2;
+ unsigned char padding[];
+};
+
+enum MhsdIndexType {
+ MHSD_TRACK_LIST = 1,
+ MHSD_PLAYLIST_LIST = 2
+};
+
+enum MhsdPhotoIndexType {
+ MHSD_IMAGE_LIST = 1,
+ MHSD_ALBUM_LIST = 2,
+ MHSD_FILE_LIST = 3
+};
+
+struct _MhsdHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 index;
+ unsigned char padding[];
+};
+
+struct _MhltHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_songs;
+ unsigned char padding[];
+};
+
+struct _MhlpHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_playlists;
+ unsigned char padding[];
+};
+
+struct _MhypHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_mhod;
+ gint32 num_items;
+ gint32 hidden;
+ gint32 timestamp;
+ gint32 playlist_id;
+ gint32 unknown3;
+ gint32 unknown4;
+ gint32 unknown5;
+ unsigned char padding[];
+};
+
+struct _MhipHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 unknown1;
+ gint32 correlation_id;
+ gint32 unknown2;
+ gint32 track_id;
+ gint32 timestamp;
+ unsigned char padding[];
+};
+
+/* MHIT header as written by iTunes 4.7.1, the added fields (from unknown17 to
+ * the end of the struct) are pretty useless, so we don't use this struct
+ */
+struct _MhitHeader471 {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_mhod;
+ gint32 track_id;
+ gint32 visible;
+ gint32 filetype;
+ /* FIXME: endianness issue with the order of the 3 fields above ? */
+ gint16 type;
+ gchar compilation;
+ gchar rating;
+ gint32 date_added;
+ gint32 size;
+ gint32 length;
+ gint32 track_number;
+ gint32 track_total;
+ gint32 year;
+ gint32 bitrate;
+ /* FIXME: endianness issue with the order of the 2 fields above ? */
+ gint16 unknown;
+ gint16 sample_rate;
+ gint32 volume;
+ gint32 start_time;
+ gint32 stop_time;
+ gint32 sound_check;
+ gint32 play_count;
+ gint32 play_count2;
+ gint32 last_played;
+ gint32 disc_number;
+ gint32 disc_total;
+ gint32 user_id;
+ gint32 last_modified;
+ gint32 bookmark_time;
+ gint64 song_id;
+ /* FIXME: endianness issue with the order of the 5 fields above ? */
+ gchar checked;
+ gchar app_rating;
+ gint16 bpm;
+ gint16 artwork_count;
+ gint16 unknown9;
+ gint32 artwork_size;
+ gint32 unknown11;
+ gint32 sample_rate2;
+ gint32 unknown13;
+ gint32 unknown14;
+ gint32 unknown15;
+ gint32 unknown16;
+ gint32 unknown17;
+ gint32 unknown18;
+ gint32 unknown19;
+ gint64 song_id2;
+ gint32 unknown20;
+ gint32 unknown21;
+ gint32 unknown22;
+ gint32 unknown23;
+ gint32 unknown24;
+ gint32 unknown25;
+ gint32 unknown26;
+ gint32 unknown27;
+ gint32 unknown28;
+ gint32 unknown29;
+ gint32 unknown30;
+ gint32 unknown31;
+ gint32 unknown32;
+ gint32 unknown33;
+ gint32 unknown34;
+ gint32 unknown35;
+ gint32 unknown36;
+ unsigned char padding[];
+};
+
+struct _MhitHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_mhod;
+ gint32 track_id;
+ gint32 visible;
+ gint32 filetype;
+ /* FIXME: endianness issue with the order of the 3 fields above ? */
+ gint16 type;
+ gchar compilation;
+ gchar rating;
+ gint32 date_added;
+ gint32 size;
+ gint32 length;
+ gint32 track_number;
+ gint32 track_total;
+ gint32 year;
+ gint32 bitrate;
+ /* FIXME: endianness issue with the order of the 2 fields above ? */
+ gint16 unknown;
+ gint16 sample_rate;
+ gint32 volume;
+ gint32 start_time;
+ gint32 stop_time;
+ gint32 sound_check;
+ gint32 play_count;
+ gint32 play_count2;
+ gint32 last_played;
+ gint32 disc_number;
+ gint32 disc_total;
+ gint32 user_id;
+ gint32 last_modified;
+ gint32 bookmark_time;
+ gint64 song_id;
+ /* FIXME: endianness issue with the order of the 5 fields above ? */
+ gchar checked;
+ gchar app_rating;
+ gint16 bpm;
+ gint16 artwork_count;
+ gint16 unknown9;
+ gint32 artwork_size;
+ gint32 unknown11;
+ gint32 sample_rate2;
+ gint32 unknown13;
+ gint32 unknown14;
+ gint32 unknown15;
+ gint32 unknown16;
+ unsigned char padding[];
+};
+
+enum MhodEncoding {
+ MHOD_ENCODING_UTF16 = 0,
+ MHOD_ENCODING_UTF8 = 1
+};
+
+enum MhodType {
+ MHOD_TYPE_TITLE = 1,
+ MHOD_TYPE_LOCATION = 2,
+ MHOD_TYPE_ALBUM = 3,
+ MHOD_TYPE_ARTIST = 4,
+ MHOD_TYPE_GENRE = 5,
+ MHOD_TYPE_FILETYPE = 6,
+ MHOD_TYPE_EQ_SETTING = 7,
+ MHOD_TYPE_COMMENT = 8,
+ MHOD_TYPE_COMPOSER = 12,
+ MHOD_TYPE_GROUPING = 13,
+ MHOD_TYPE_SMART_PLAYLIST_DATA = 50,
+ MHOD_TYPE_SMART_PLAYLIST_RULES = 51,
+ MHOD_TYPE_LIBRARY_PLAYLIST_INDEX = 52,
+ MHOD_TYPE_100 = 100
+};
+
+struct _MhodHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type;
+ gint32 unknown1;
+ gint32 unknown2;
+};
+
+struct _MhodHeaderString {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type; /* < 50 */
+ gint32 unknown1;
+ gint32 unknown2;
+ gint32 position;
+ gint32 string_len;
+ gint32 encoding;
+ gint32 unknown4;
+ unsigned char string[];
+};
+
+struct _MhodHeaderArtworkType3 {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type; /* 3 */
+ gint32 unknown1;
+ gint32 unknown2;
+ gint32 string_len;
+ gint32 mhod_version;
+ gint32 unknown4;
+ gunichar2 string[];
+};
+
+enum MhodLimitType {
+ MHOD_LIMIT_MINUTES = 1,
+ MHOD_LIMIT_MEGABYTES = 2,
+ MHOD_LIMIT_SONGS = 3,
+ MHOD_LIMIT_HOURS = 4,
+ MHOD_LIMIT_GIGABYTES = 5
+};
+
+enum MhodLimitSortType {
+ MHOD_LIMIT_SORT_RANDOM = 0x02,
+ MHOD_LIMIT_SORT_SONG_NAME = 0x03,
+ MHOD_LIMIT_SORT_ALBUM = 0x04,
+ MHOD_LIMIT_SORT_ARTIST = 0x05,
+ MHOD_LIMIT_SORT_GENRE = 0x07,
+ MHOD_LIMIT_SORT_MOST_RECENTLY_ADDED = 0x10,
+ MHOD_LIMIT_SORT_MOST_OFTEN_PLAYED = 0x14,
+ MHOD_LIMIT_SORT_MOST_RECENTLY_PLAYED = 0x15,
+ MHOD_LIMIT_SORT_HIGHEST_RATING = 0x17
+};
+
+struct _MhodHeaderSmartPlaylistData {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type; /* 50 */
+ gint32 unknown1;
+ gint32 unknown2;
+ gchar live_update;
+ gchar rules_enable;
+ gchar limit_enable;
+ gchar limit_type;
+ gchar limit_sort;
+ gchar unknow3[3];
+ gint32 limit;
+ gchar match_checked_only;
+ gchar reverse_limit_sort;
+ unsigned char padding[];
+};
+
+
+enum MhodSmartPlaylistRuleFieldType {
+ MHOD_FIELD_SONG_NAME = 0x02,
+ MHOD_FIELD_ALBUM = 0x03,
+ MHOD_FIELD_ARTIST = 0x04,
+ MHOD_FIELD_BITRATE = 0x05,
+ MHOD_FIELD_SAMPLE_RATE = 0x06,
+ MHOD_FIELD_YEAR = 0x07,
+ MHOD_FIELD_GENRE = 0x08,
+ MHOD_FIELD_KIND = 0x09,
+ MHOD_FIELD_DATE_MODIFIED = 0x0a,
+ MHOD_FIELD_TRACK_NUMBER = 0x0b,
+ MHOD_FIELD_SIZE = 0x0c,
+ MHOD_FIELD_TIME = 0x0d,
+ MHOD_FIELD_COMMENT = 0x0e,
+ MHOD_FIELD_DATE_ADDED = 0x10,
+ MHOD_FIELD_COMPOSER = 0x12,
+ MHOD_FIELD_PLAY_COUNT = 0x16,
+ MHOD_FIELD_LAST_PLAYED = 0x17,
+ MHOD_FIELD_DISC_NUMBER = 0x18,
+ MHOD_FIELD_RATING = 0x19,
+ MHOD_FIELD_COMPILATION = 0x1f,
+ MHOD_FIELD_BPM = 0x23,
+ MHOD_FIELD_GROUPING = 0x27,
+ MHOD_FIELD_PLAYLIST = 0x28
+};
+
+enum MhodSmartPlaylistRuleAction {
+ MHOD_RULE_IS = 1 << 0,
+ MHOD_RULE_CONTAINS = 1 << 1,
+ MHOD_RULE_BEGINS_WITH = 1 << 2,
+ MHOD_RULE_ENDS_WITH = 1 << 3,
+ MHOD_RULE_GREATER_THAN = 1 << 4,
+ MHOD_RULE_GREATER_THAN_OR_EQUAL_TO = 1 << 5,
+ MHOD_RULE_LESS_THAN = 1 << 6,
+ MHOD_RULE_LESS_THAN_OR_EQUAL_TO = 1 << 7,
+ MHOD_RULE_IN_THE_RANGE = 1 << 8,
+ MHOD_RULE_IS_THE_LAST = 1 << 9,
+ MHOD_RULE_NOT = 1 << 24,
+ MHOD_RULE_STRING = 1 << 25
+};
+
+
+struct _MhodHeaderSmartPlaylistRuleString {
+ /* Big endian fields */
+ gint32 field;
+ gint32 action;
+ gchar padding[44];
+ gint32 string_len;
+ gchar string[];
+};
+
+struct _MhodHeaderSmartPlaylistRuleNonString {
+ /* Big endian fields */
+ gint32 field;
+ gint32 action;
+ gchar padding[44];
+ gint32 length;
+ guint64 from_value;
+ gint64 from_date;
+ guint64 from_unit;
+ guint64 to_value;
+ gint64 to_date;
+ guint64 to_unit;
+ gchar unknown[20];
+};
+
+struct _MhodHeaderSmartPlaylistRule {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type; /* 51 */
+ gint32 unknown1;
+ gint32 unknown2;
+ gchar rules_id[4];
+ /* Fields stored in big-endian from there */
+ gint32 unknown5;
+ gint32 number_of_rules;
+ gint32 rules_operator;
+ gchar padding[120];
+ union {
+ MhodHeaderSmartPlaylistRuleString rule_string;
+ MhodHeaderSmartPlaylistRuleNonString rule_non_string;
+ } rule;
+};
+
+
+
+struct _MhfdHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 unknown1;
+ gint32 unknown2;
+ gint32 num_children;
+ gint32 unknown3;
+ gint32 unknown4;
+ gint64 unknown5;
+ gint64 unknown6;
+ gint32 unknown7;
+ gint32 unknown8;
+ gint32 unknown9;
+ gint32 unknown10;
+ gint32 unknown11;
+ unsigned char padding[];
+};
+
+struct _MhliHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_children;
+ unsigned char padding[];
+};
+
+struct _MhiiHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_children;
+ gint32 image_id;
+ gint64 song_id;
+ gint32 unknown4;
+ gint32 unknown5;
+ gint32 unknown6;
+ gint32 unknown7;
+ gint32 unknown8;
+ gint32 orig_img_size;
+ unsigned char padding[];
+};
+
+struct _MhniHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_children;
+ gint32 correlation_id;
+ gint32 ithmb_offset;
+ gint32 image_size;
+ gint32 unknown3;
+ gint32 image_dimensions;
+ unsigned char padding[];
+};
+
+struct _MhlaHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_children;
+ unsigned char padding[];
+};
+
+struct _MhlfHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 num_files;
+ unsigned char padding[];
+};
+
+struct _MhifHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 unknown1;
+ gint32 correlation_id;
+ gint32 image_size;
+ unsigned char padding[];
+};
+
+
+
+#endif /* PARSE_DB_H */
diff --git a/src/db-parse-context.c b/src/db-parse-context.c
new file mode 100644
index 0000000..4f4264e
--- /dev/null
+++ b/src/db-parse-context.c
@@ -0,0 +1,196 @@
+/*
+ * 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 <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "db-parse-context.h"
+#include "db-itunes-parser.h"
+
+DBParseContext *
+db_parse_context_new (const unsigned char *buffer, off_t len)
+{
+ DBParseContext *result;
+
+ result = g_new0 (DBParseContext, 1);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->buffer = buffer;
+ result->cur_pos = buffer;
+ result->total_len = len;
+
+ return result;
+}
+
+
+static void
+db_parse_context_set_header_len (DBParseContext *ctx, off_t len)
+{
+ /* FIXME: this can probably happen in malformed itunesdb files,
+ * don't g_assert on this, only output a warning
+ */
+ g_assert ((ctx->cur_pos - ctx->buffer) <= len);
+ g_assert (len <= ctx->total_len);
+ ctx->header_len = len;
+}
+
+void
+db_parse_context_set_total_len (DBParseContext *ctx, off_t len)
+{
+ /* FIXME: this can probably happen in malformed itunesdb files,
+ * don't g_assert on this, only output a warning
+ */
+ g_assert ((ctx->cur_pos - ctx->buffer) <= len);
+ if (ctx->header_len != 0) {
+ g_assert (len >= ctx->header_len);
+ }
+ ctx->total_len = len;
+}
+
+
+off_t
+db_parse_context_get_remaining_length (DBParseContext *ctx)
+{
+ if (ctx->header_len != 0) {
+ return ctx->header_len - (ctx->cur_pos - ctx->buffer);
+ } else {
+ return ctx->total_len - (ctx->cur_pos - ctx->buffer);
+ }
+}
+
+DBParseContext *
+db_parse_context_get_sub_context (DBParseContext *ctx, off_t offset)
+{
+ if (offset >= ctx->total_len) {
+ return NULL;
+ }
+ return db_parse_context_new (&ctx->buffer[offset],
+ ctx->total_len - offset);
+}
+
+
+DBParseContext *
+db_parse_context_get_next_child (DBParseContext *ctx)
+{
+ if (ctx->header_len == 0) {
+ return NULL;
+ }
+ if (ctx->header_len >= ctx->total_len) {
+ return NULL;
+ }
+
+ return db_parse_context_get_sub_context (ctx, ctx->header_len);
+}
+
+void *
+db_parse_context_get_m_header_internal (DBParseContext *ctx, const char *id, off_t size)
+{
+ MHeader *h;
+
+ if (db_parse_context_get_remaining_length (ctx) < 8) {
+ return NULL;
+ }
+
+ h = (MHeader *)ctx->cur_pos;
+ if (strncmp (id, (char *)h->header_id, 4) != 0) {
+ return NULL;
+ }
+
+ /* FIXME: this test sucks for compat: if a field is smaller than
+ * expected, we probably should create a buffer of the appropriate
+ * size inited to 0, copy the data that is available in it and use
+ * that buffer in the rest of the code (maybe it's harmful to have
+ * some fields at 0 in some headers though...)
+ */
+ if (GINT_FROM_LE (h->header_len) < size) {
+ return NULL;
+ }
+
+ db_parse_context_set_header_len (ctx, GINT_FROM_LE (h->header_len));
+
+ return h;
+}
+
+DBParseContext *
+db_parse_context_new_from_file (const char *filename)
+{
+ int fd;
+ struct stat stat_buf;
+ int result;
+ unsigned char *buffer;
+ DBParseContext *ctx;
+
+ buffer = NULL;
+ ctx = NULL;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1) {
+ g_print ("Failed to open %s: %s\n",
+ filename, strerror (errno));
+ return NULL;
+ }
+
+ result = fstat (fd, &stat_buf);
+ if (result == -1) {
+ g_print ("Failed to read %s size: %s\n",
+ filename, strerror (errno));
+ goto error;
+ }
+
+ if (!S_ISREG (stat_buf.st_mode)) {
+ g_print ("%s is not a regular file\n", filename);
+ goto error;
+ }
+
+ if (stat_buf.st_size > ITUNESDB_MAX_SIZE) {
+ g_print ("%s is too big to be an buffer file\n", filename);
+ goto error;
+ }
+
+ buffer = mmap (NULL, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (buffer == MAP_FAILED) {
+ g_print ("Error while mmap'ing %s: %s\n",
+ filename, strerror (errno));
+ goto error;
+ }
+
+ ctx = db_parse_context_new (buffer, stat_buf.st_size);
+ if (ctx == NULL) {
+ munmap (buffer, stat_buf.st_size);
+ }
+ error:
+ close (fd);
+ return ctx;
+}
diff --git a/src/db-parse-context.h b/src/db-parse-context.h
new file mode 100644
index 0000000..b442c36
--- /dev/null
+++ b/src/db-parse-context.h
@@ -0,0 +1,53 @@
+/*
+ * 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!
+ *
+ */
+
+
+#ifndef DB_PARSE_CONTEXT
+#define DB_PARSE_CONTEXT
+
+#include <sys/types.h>
+
+struct _DBParseContext {
+ const unsigned char *buffer;
+ const unsigned char *cur_pos;
+ off_t header_len;
+ off_t total_len;
+};
+
+typedef struct _DBParseContext DBParseContext;
+
+
+#define db_parse_context_get_m_header(ctx, type, id) (type *)db_parse_context_get_m_header_internal (ctx, id, sizeof (type))
+
+G_GNUC_INTERNAL DBParseContext *db_parse_context_new (const unsigned char *buffer, off_t len) G_GNUC_INTERNAL;
+G_GNUC_INTERNAL void db_parse_context_set_total_len (DBParseContext *ctx, off_t len) G_GNUC_INTERNAL;
+G_GNUC_INTERNAL off_t db_parse_context_get_remaining_length (DBParseContext *ctx) G_GNUC_INTERNAL;
+G_GNUC_INTERNAL DBParseContext *db_parse_context_get_sub_context (DBParseContext *ctx,
+ off_t offset) G_GNUC_INTERNAL;
+G_GNUC_INTERNAL DBParseContext *db_parse_context_get_next_child (DBParseContext *ctx) G_GNUC_INTERNAL;
+G_GNUC_INTERNAL void *db_parse_context_get_m_header_internal (DBParseContext *ctx, const char *id, off_t size) G_GNUC_INTERNAL;
+
+G_GNUC_INTERNAL DBParseContext *db_parse_context_new_from_file (const char *filename) G_GNUC_INTERNAL;
+
+#endif
diff --git a/src/itdb.h b/src/itdb.h
index 91f1cc8..a2fbe0b 100644
--- a/src/itdb.h
+++ b/src/itdb.h
@@ -1,4 +1,4 @@
-/* Time-stamp: <2005-09-19 17:50:40 jcs>
+/* Time-stamp: <2005-09-19 19:14:40 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -40,10 +40,10 @@
# include <config.h>
#endif
+#include <sys/types.h>
#include <time.h>
#include <glib.h>
-
/* one star is how much (track->rating) */
#define ITDB_RATING_STEP 20
@@ -307,6 +307,27 @@ typedef struct SPLRules
GList *rules;
} SPLRules;
+/* This structure can represent two slightly different images:
+ * - an image before it's transferred to the iPod (it will then be scaled
+ * as necessary to generate the 2 thumbnails needed by the iPod),
+ * for such images, filename points to a 'real' image file, offset is
+ * not significant, size, width and height may or may not be set
+ * and id corresponds to the image id to write in mhii records of the
+ * photo database
+ *
+ * - a thumbnail (big or small) stored on a database in the iPod.
+ * For such images, id isn't significant, filename point to a .ithmb file
+ * on the iPod
+ */
+struct _Itdb_Image {
+ char *filename;
+ off_t offset;
+ size_t size;
+ unsigned int width;
+ unsigned int height;
+ unsigned int id;
+};
+typedef struct _Itdb_Image Itdb_Image;
typedef void (* ItdbUserDataDestroyFunc) (gpointer userdata);
typedef gpointer (* ItdbUserDataDuplicateFunc) (gpointer userdata);
@@ -484,6 +505,11 @@ typedef struct
guint32 unk208, unk212, unk216, unk220, unk224;
guint32 unk228, unk232, unk236, unk240;
+ /* This is for Cover Art support */
+ Itdb_Image *full_size_thumbnail;
+ Itdb_Image *now_playing_thumbnail;
+ Itdb_Image *orig_image;
+
/* below is for use by application */
guint64 usertype;
gpointer userdata;
@@ -586,6 +612,9 @@ gboolean itdb_splr_eval (Itdb_iTunesDB *itdb, SPLRule *splr, Itdb_Track *track);
void itdb_spl_update (Itdb_iTunesDB *itdb, Itdb_Playlist *spl);
void itdb_spl_update_all (Itdb_iTunesDB *itdb);
+/* thumbnails functions */
+unsigned char *itdb_image_get_rgb_data (Itdb_Image *image);
+
/* time functions */
guint64 itdb_time_get_mac_time (void);
time_t itdb_time_mac_to_host (guint64 mactime);
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index ad6d747..9ed1b52 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -120,6 +120,7 @@
#include <errno.h>
#include <stdio.h>
#include "itdb_private.h"
+#include "db-artwork-parser.h"
#include <glib/gi18n-lib.h>
#define ITUNESDB_DEBUG 0
@@ -1981,6 +1982,19 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error)
itdb->mountpoint = g_strdup (mp);
}
g_free (filename);
+
+ /* We don't test the return value of ipod_parse_artwork_db since the
+ * database content will be consistent even if we fail to get the
+ * various thumbnails, we ignore the error since older ipods don't have
+ * thumbnails.
+ * FIXME: this probably should go into itdb_parse_file, but I don't
+ * understand its purpose, and ipod_parse_artwork_db needs the
+ * mountpoint field from the itdb, which may not be available in the
+ * other function
+ */
+ ipod_parse_artwork_db (itdb);
+
+
}
else
{
@@ -2034,6 +2048,7 @@ Itdb_iTunesDB *itdb_parse_file (const gchar *filename, GError **error)
g_propagate_error (error, fimp->error);
}
itdb_free_fimp (fimp);
+
return itdb;
}