summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlavio Stanchina <fstanchina@users.sourceforge.net>2005-10-10 20:40:45 +0000
committerFlavio Stanchina <fstanchina@users.sourceforge.net>2005-10-10 20:40:45 +0000
commit5191d5305df522f29ebf112fdd0cdf89b6fcb870 (patch)
treec221a35f2709820cb0d26fb7dd4745167a5b2480
parentf532f816cc4e478523932dc3ce914b840f5c06bb (diff)
downloadlibgpod-5191d5305df522f29ebf112fdd0cdf89b6fcb870.tar.gz
libgpod-5191d5305df522f29ebf112fdd0cdf89b6fcb870.tar.xz
libgpod-5191d5305df522f29ebf112fdd0cdf89b6fcb870.zip
Added a few structures (notably MHBA and MHIA) to support the Photo Database.
Split 'gint32 image_dimensions' into 'gint16 image_height, image_width'. git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1115 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r--src/db-artwork-debug.c57
-rw-r--r--src/db-artwork-debug.h6
-rw-r--r--src/db-artwork-parser.c99
-rw-r--r--src/db-artwork-writer.c11
-rw-r--r--src/db-image-parser.c12
-rw-r--r--src/db-itunes-parser.h56
6 files changed, 208 insertions, 33 deletions
diff --git a/src/db-artwork-debug.c b/src/db-artwork-debug.c
index d8ccb96..90e4107 100644
--- a/src/db-artwork-debug.c
+++ b/src/db-artwork-debug.c
@@ -39,6 +39,15 @@ dump_mhif (MhifHeader *mhif)
g_print ("\tImage size: %d bytes\n", GINT_FROM_LE (mhif->image_size));
}
+G_GNUC_INTERNAL void
+dump_mhia (MhiaHeader *mhia)
+{
+ g_print ("MHIA (%d):\n", sizeof (MhiaHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhia->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhia->total_len));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhia->unknown1));
+ g_print ("\tImage ID: %08x\n", GINT_FROM_LE (mhia->image_id));
+}
static char *
get_utf16_string (void* buffer, gint length)
@@ -60,15 +69,31 @@ get_utf16_string (void* buffer, gint length)
}
+G_GNUC_INTERNAL void
+dump_mhod_type_1 (MhodHeaderArtworkType1 *mhod1)
+{
+ g_print ("MHOD [artwork type 1] (%d):\n", sizeof (MhodHeaderArtworkType1));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhod1->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhod1->total_len));
+ g_print ("\tType: %08x\n", GINT_FROM_LE (mhod1->type));
+ g_print ("\tUnknown1: %08x\n", GINT_FROM_LE (mhod1->unknown1));
+ g_print ("\tUnknown2: %08x\n", GINT_FROM_LE (mhod1->unknown2));
+ g_print ("\tString length: %u\n", GINT_FROM_LE (mhod1->string_len));
+ g_print ("\tUnknown3: %08x\n", GINT_FROM_LE (mhod1->unknown3));
+ g_print ("\tUnknown4: %08x\n", GINT_FROM_LE (mhod1->unknown4));
+ /* FIXME: do I need to translate UTF-8 to local encoding? */
+ g_print ("\tString: \"%.*s\"\n", GINT_FROM_LE (mhod1->string_len), mhod1->string);
+}
+
G_GNUC_INTERNAL void
dump_mhod_type_3 (MhodHeaderArtworkType3 *mhod3)
{
gchar *str;
- g_print ("MHOD (%d):\n", sizeof (MhodHeaderArtworkType3));
+ g_print ("MHOD [artwork type 3] (%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 ("\tType: %08x\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));
@@ -82,6 +107,9 @@ dump_mhod_type_3 (MhodHeaderArtworkType3 *mhod3)
G_GNUC_INTERNAL void
dump_mhni (MhniHeader *mhni)
{
+ unsigned int width = GINT16_FROM_LE (mhni->image_width);
+ unsigned int height = GINT16_FROM_LE (mhni->image_height);
+
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));
@@ -92,7 +120,7 @@ dump_mhni (MhniHeader *mhni)
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_print ("\tImage dimensions: %ux%u\n", width, height);
}
G_GNUC_INTERNAL void
@@ -101,7 +129,7 @@ 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 ("\tType: %08x\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));
}
@@ -163,7 +191,7 @@ dump_mhsd (MhsdHeader *mhsd)
G_GNUC_INTERNAL void
dump_mhfd (MhfdHeader *mhfd)
{
- g_print ("MHFD (%d): \n", sizeof (MhfdHeader));
+ 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));
@@ -179,4 +207,23 @@ dump_mhfd (MhfdHeader *mhfd)
g_print ("\tUnknown10: %08x\n", GINT_FROM_LE (mhfd->unknown10));
g_print ("\tUnknown11: %08x\n", GINT_FROM_LE (mhfd->unknown11));
}
+
+G_GNUC_INTERNAL void
+dump_mhba (MhbaHeader *mhba)
+{
+ int i;
+
+ g_print ("MHBA (%d):\n", sizeof (MhbaHeader));
+ g_print ("\tHeader length: %d\n", GINT_FROM_LE (mhba->header_len));
+ g_print ("\tTotal length: %d\n", GINT_FROM_LE (mhba->total_len));
+ g_print ("\tNumber of Data Objects: %d\n", GINT_FROM_LE (mhba->num_mhods));
+ g_print ("\tNumber of pictures in the album: %d\n", GINT_FROM_LE (mhba->num_mhias));
+ g_print ("\tPlaylist ID: %08x\n", GINT_FROM_LE (mhba->playlist_id));
+ g_print ("\tUnknown2: %08x\n", GINT_FROM_LE (mhba->unknown2));
+ g_print ("\tUnknown3: %08x\n", GINT_FROM_LE (mhba->unknown3));
+ for (i = 0; i < 7; i++)
+ g_print ("\tUnknown[%d]: %08x\n", i, GINT_FROM_LE (mhba->unknown[i]));
+ g_print ("\tPrev playlist ID: %08x\n", GINT_FROM_LE (mhba->prev_playlist_id));
+}
+
#endif
diff --git a/src/db-artwork-debug.h b/src/db-artwork-debug.h
index fe9dd70..df35058 100644
--- a/src/db-artwork-debug.h
+++ b/src/db-artwork-debug.h
@@ -30,6 +30,8 @@
#ifdef DEBUG_ARTWORKDB
extern G_GNUC_INTERNAL void dump_mhif (MhifHeader *mhif);
+extern G_GNUC_INTERNAL void dump_mhia (MhiaHeader *mhia);
+extern G_GNUC_INTERNAL void dump_mhod_type_1 (MhodHeaderArtworkType1 *mhod);
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);
@@ -37,8 +39,11 @@ 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);
+extern G_GNUC_INTERNAL void dump_mhba (MhbaHeader *mhba);
#else
#define dump_mhif(x)
+#define dump_mhia(x)
+#define dump_mhod_type_1(x)
#define dump_mhod_type_3(x)
#define dump_mhni(x)
#define dump_mhod(x)
@@ -46,6 +51,7 @@ extern G_GNUC_INTERNAL void dump_mhfd (MhfdHeader *mhfd);
#define dump_mhl(x,y)
#define dump_mhsd(x)
#define dump_mhfd(x)
+#define dump_mhba(x)
#endif
#endif
diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c
index 99473e8..2b05eaa 100644
--- a/src/db-artwork-parser.c
+++ b/src/db-artwork-parser.c
@@ -64,6 +64,20 @@ parse_mhif (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
return 0;
}
+static int
+parse_mhia (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
+{
+ MhiaHeader *mhia;
+
+ mhia = db_parse_context_get_m_header (ctx, MhiaHeader, "mhia");
+ if (mhia == NULL) {
+ return -1;
+ }
+ dump_mhia (mhia);
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhia->total_len));
+ return 0;
+}
+
#ifdef DEBUG_ARTWORKDB
static int
parse_mhod_3 (DBParseContext *ctx, GError *error)
@@ -81,11 +95,11 @@ parse_mhod_3 (DBParseContext *ctx, GError *error)
return -1;
}
mhod3 = (MhodHeaderArtworkType3*)mhod;
- dump_mhod_type_3 (mhod3);
- if ((GINT_FROM_LE (mhod3->type) & 0xff) != MHOD_TYPE_ALBUM) {
+ if ((GINT_FROM_LE (mhod3->type) & 0x00FFFFFF) != MHOD_ARTWORK_TYPE_FILE_NAME) {
return -1;
}
+ dump_mhod_type_3 (mhod3);
return 0;
}
#endif
@@ -111,6 +125,9 @@ parse_mhni (DBParseContext *ctx, iPodSong *song, GError *error)
/* No information useful to us in mhod type 3, do not parse
* it in non-debug mode
+ * FIXME: really? it contains the thumbnail file name!
+ * we infer it from the correlation id, but is this
+ * always The Right Thing to do?
*/
mhod_ctx = db_parse_context_get_sub_context (ctx, ctx->header_len);
if (mhod_ctx == NULL) {
@@ -133,24 +150,35 @@ parse_mhod (DBParseContext *ctx, iPodSong *song, GError *error)
{
MhodHeader *mhod;
DBParseContext *mhni_ctx;
+ int type;
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;
+ /* The MHODs found in the ArtworkDB and Photo Database files are
+ * significantly different than those found in the iTunesDB.
+ * For example, the "type" is split like this:
+ * - low 3 bytes are actual type;
+ * - high byte is padding length of string (0-3).
+ */
+ type = GINT_FROM_LE (mhod->type) & 0x00FFFFFF;
+ if (type == MHOD_ARTWORK_TYPE_ALBUM_NAME)
+ dump_mhod_type_1 ((MhodHeaderArtworkType1 *)mhod);
+ else
+ dump_mhod (mhod);
+
+ /* if this is a container... */
+ if (type == MHOD_ARTWORK_TYPE_THUMBNAIL) {
+ 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);
}
- parse_mhni (mhni_ctx, song, NULL);
- g_free (mhni_ctx);
return 0;
}
@@ -205,6 +233,47 @@ parse_mhii (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
static int
+parse_mhba (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
+{
+ MhbaHeader *mhba;
+ DBParseContext *mhod_ctx;
+ DBParseContext *mhia_ctx;
+ int num_children;
+ off_t cur_offset;
+
+ mhba = db_parse_context_get_m_header (ctx, MhbaHeader, "mhba");
+ if (mhba == NULL) {
+ return -1;
+ }
+ db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhba->total_len));
+
+ dump_mhba (mhba);
+
+ cur_offset = ctx->header_len;
+ mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ num_children = GINT_FROM_LE (mhba->num_mhods);
+ while ((num_children > 0) && (mhod_ctx != NULL)) {
+ parse_mhod (mhod_ctx, NULL, NULL);
+ num_children--;
+ cur_offset += mhod_ctx->total_len;
+ g_free (mhod_ctx);
+ mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ }
+ mhia_ctx = db_parse_context_get_sub_context (ctx, cur_offset);
+ num_children = GINT_FROM_LE (mhba->num_mhias);
+ while ((num_children > 0) && (mhia_ctx != NULL)) {
+ parse_mhia (mhia_ctx, db, NULL);
+ num_children--;
+ cur_offset += mhia_ctx->total_len;
+ g_free (mhia_ctx);
+ mhia_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)
{
@@ -265,7 +334,7 @@ parse_mhsd (DBParseContext *ctx, Itdb_iTunesDB *db, GError **error)
case MHSD_ALBUM_LIST: {
DBParseContext *mhla_context;
mhla_context = db_parse_context_get_next_child (ctx);
- parse_mhl (mhla_context, db, NULL, "mhla", NULL);
+ parse_mhl (mhla_context, db, NULL, "mhla", parse_mhba);
g_free (mhla_context);
break;
}
@@ -304,6 +373,10 @@ parse_mhfd (DBParseContext *ctx, Itdb_iTunesDB *db, GError **error)
dump_mhfd (mhfd);
cur_pos = ctx->header_len;
+ /* The mhfd record always has 3 mhsd children, so it's hardcoded here.
+ * It could be replaced with a loop using the nb_children field from
+ * the mhfd record. [explanation by Christophe]
+ */
mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos);
if (mhsd_context == NULL) {
return -1;
diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c
index ca46417..655d05b 100644
--- a/src/db-artwork-writer.c
+++ b/src/db-artwork-writer.c
@@ -328,7 +328,6 @@ write_mhni (Itdb_Image *image, iPodBuffer *buffer)
unsigned int total_bytes;
int bytes_written;
iPodBuffer *sub_buffer;
- unsigned int dim;
if (image == NULL) {
return -1;
@@ -351,12 +350,10 @@ write_mhni (Itdb_Image *image, iPodBuffer *buffer)
mhni->correlation_id = GINT_TO_LE (IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID);
break;
}
- dim = image->width & 0xffff;
- dim <<= 16;
- dim |= image->height & 0xffff;
- mhni->image_dimensions = GINT_TO_LE (dim);
- mhni->image_size = GINT_TO_LE (image->size);
- mhni->ithmb_offset = GINT_TO_LE (image->offset);
+ mhni->image_width = GINT16_TO_LE (image->width);
+ mhni->image_height = GINT16_TO_LE (image->height);
+ mhni->image_size = GINT32_TO_LE (image->size);
+ mhni->ithmb_offset = GINT32_TO_LE (image->offset);
sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes);
if (sub_buffer == NULL) {
diff --git a/src/db-image-parser.c b/src/db-image-parser.c
index 3842135..2d8e8dc 100644
--- a/src/db-image-parser.c
+++ b/src/db-image-parser.c
@@ -154,10 +154,10 @@ ipod_image_new_from_mhni (MhniHeader *mhni, const char *mount_point)
}
img->filename = ipod_image_get_ithmb_filename (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);
+ img->size = GINT32_FROM_LE (mhni->image_size);
+ img->offset = GINT32_FROM_LE (mhni->ithmb_offset);
+ img->width = GINT16_FROM_LE (mhni->image_width);
+ img->height = GINT16_FROM_LE (mhni->image_height);
switch (mhni->correlation_id) {
case IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID:
@@ -169,8 +169,8 @@ ipod_image_new_from_mhni (MhniHeader *mhni, const char *mount_point)
img->type = ITDB_IMAGE_NOW_PLAYING;
break;
default:
- g_print ("Unrecognized image size: %08x\n",
- GINT_FROM_LE (mhni->image_dimensions));
+ g_print ("Unrecognized image size: %ux%u\n",
+ img->width, img->height);
g_free (img);
return NULL;
}
diff --git a/src/db-itunes-parser.h b/src/db-itunes-parser.h
index bf5f7f2..54ef6b5 100644
--- a/src/db-itunes-parser.h
+++ b/src/db-itunes-parser.h
@@ -61,12 +61,15 @@ typedef struct _MhliHeader MhliHeader;
typedef struct _MhiiHeader MhiiHeader;
typedef struct _MhniHeader MhniHeader;
typedef struct _MhlaHeader MhlaHeader;
+typedef struct _MhbaHeader MhbaHeader;
typedef struct _MhlfHeader MhlfHeader;
typedef struct _MhifHeader MhifHeader;
+typedef struct _MhiaHeader MhiaHeader;
typedef struct _MhitHeader471 MhitHeader471;
/* MHOD typedef mess */
typedef struct _MhodHeaderString MhodHeaderString;
+typedef struct _MhodHeaderArtworkType1 MhodHeaderArtworkType1;
typedef struct _MhodHeaderArtworkType3 MhodHeaderArtworkType3;
typedef struct _MhodHeaderSmartPlaylistData MhodHeaderSmartPlaylistData;
typedef struct _MhodHeaderSmartPlaylistRuleString MhodHeaderSmartPlaylistRuleString;
@@ -311,11 +314,35 @@ struct _MhodHeaderString {
gint32 unknown2;
gint32 position;
gint32 string_len;
- gint32 encoding;
+ gint32 unknown3; /* It was thought that this was string encoding:
+ * 0 == UTF-16, 1 == UTF-8, however, recent iTunesDB
+ * files have had this set to 1 even with UTF-16 strings.
+ * Therefore this is definitely incorrect, and the
+ * correct meaning has not yet been discovered yet. */
gint32 unknown4;
unsigned char string[];
};
+enum MhodArtworkType {
+ MHOD_ARTWORK_TYPE_ALBUM_NAME = 1, /* string: album name (in the Photo Database) */
+ MHOD_ARTWORK_TYPE_THUMBNAIL = 2, /* container: thumbnail image */
+ MHOD_ARTWORK_TYPE_FILE_NAME = 3, /* string: file name */
+ MHOD_ARTWORK_TYPE_IMAGE = 5 /* container: full resolution image (in the Photo Database) */
+};
+
+struct _MhodHeaderArtworkType1 {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 type; /* low 3 bytes are type (always 1); high byte is padding length (0-3) */
+ gint32 unknown1;
+ gint32 unknown2;
+ gint32 string_len;
+ gint32 unknown3; /* might be the string encoding */
+ gint32 unknown4; /* always zero? */
+ unsigned char string[];
+};
+
struct _MhodHeaderArtworkType3 {
unsigned char header_id[4];
gint32 header_len;
@@ -507,7 +534,8 @@ struct _MhniHeader {
gint32 ithmb_offset;
gint32 image_size;
gint32 unknown3;
- gint32 image_dimensions;
+ gint16 image_height;
+ gint16 image_width;
unsigned char padding[];
};
@@ -518,6 +546,21 @@ struct _MhlaHeader {
unsigned char padding[];
};
+struct _MhbaHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len;
+ gint32 num_mhods; /* number of Data Objects in the List, probably always 1 */
+ gint32 num_mhias; /* number of pictures in the album */
+ gint32 playlist_id; /* starts out at $64 and increments by 1 */
+ gint32 unknown2; /* unknown, seems to be always 0 */
+ gint32 unknown3; /* unknown, but is 0x10000 for the Photo Library and 0x60000 for normal albums
+ * (maybe not a 4 byte field?) */
+ gint32 unknown[7]; /* more zeroes */
+ gint32 prev_playlist_id; /* the id of the previous playlist */
+ unsigned char padding[];
+};
+
struct _MhlfHeader {
unsigned char header_id[4];
gint32 header_len;
@@ -535,6 +578,15 @@ struct _MhifHeader {
unsigned char padding[];
};
+struct _MhiaHeader {
+ unsigned char header_id[4];
+ gint32 header_len;
+ gint32 total_len; /* probably the size of the header and all child records;
+ * as there aren't any child records this is equal to header length */
+ gint32 unknown1; /* seems to be zero */
+ gint32 image_id; /* the id of the mhii record this mhia refers to */
+ unsigned char padding[];
+};
#endif /* PARSE_DB_H */