summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJorg Schuler <jcsjcs@users.sourceforge.net>2006-03-12 09:59:14 +0000
committerJorg Schuler <jcsjcs@users.sourceforge.net>2006-03-12 09:59:14 +0000
commit71a445ee1a060a1be0f12d645da36c8d972f1513 (patch)
tree064435c59e45d45d70bd4e441ee3609eafc28119 /src
parentbaf2d222fb8bc1870f2e73adf468b3261d5943aa (diff)
downloadlibgpod-71a445ee1a060a1be0f12d645da36c8d972f1513.tar.gz
libgpod-71a445ee1a060a1be0f12d645da36c8d972f1513.tar.xz
libgpod-71a445ee1a060a1be0f12d645da36c8d972f1513.zip
* itdb.h: added movie_flag and lyrics_flag to Itdb_Track
* itdb.h, itdb_itunesdb.c, itdb_private.h: added support for mobile phone reversed-endian iTunesDB. Please note that you have to rename the folder iTunes_Control to iPod_Control manually. to write reversed-endian files, itdb->reversed must be set to TRUE. When reading an iTunesDB the endianess is detected automatically and itdb->reversed set appropriately. Only the inversed iTunesDBs, 'Play Counts', and OTG playlist files are read yet. The ArtworkDB and thumbnail files cannot be parsed yet. git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1218 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'src')
-rw-r--r--src/itdb.h30
-rw-r--r--src/itdb_itunesdb.c817
-rw-r--r--src/itdb_private.h12
3 files changed, 665 insertions, 194 deletions
diff --git a/src/itdb.h b/src/itdb.h
index d91aae0..875b814 100644
--- a/src/itdb.h
+++ b/src/itdb.h
@@ -1,4 +1,4 @@
-/* Time-stamp: <2005-11-29 00:56:25 jcs>
+/* Time-stamp: <2006-03-12 00:00:25 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -398,6 +398,8 @@ struct _Itdb_iTunesDB
IpodDevice *device;
gint musicdirs; /* number of /iPod_Control/Music/F.. dirs */
guint32 version;
+ gboolean reversed; /* this iTunesDB has to be written in reversed
+ endian order (e.g. mobile phone iTunesDBs) */
guint64 id;
/* below is for use by application */
guint64 usertype;
@@ -413,7 +415,10 @@ struct _Itdb_Playlist
{
Itdb_iTunesDB *itdb; /* pointer to iTunesDB (for convenience) */
gchar *name; /* name of playlist in UTF8 */
- guint32 type; /* ITDB_PL_TYPE_NORM/_MPL */
+ guint8 type; /* ITDB_PL_TYPE_NORM/_MPL */
+ guint8 flag1; /* unknown, usually set to 0 */
+ guint8 flag2; /* unknown, always set to 0 */
+ guint8 flag3; /* unknown, always set to 0 */
gint num; /* number of tracks in playlist */
GList *members; /* tracks in playlist (Track *) */
gboolean is_spl; /* smart playlist? */
@@ -547,6 +552,9 @@ struct _Itdb_Track
gint32 tracks; /* number of tracks */
gint32 bitrate; /* bitrate */
guint16 samplerate; /* samplerate (CD: 44100) */
+ guint16 samplerate_low; /* in the iTunesDB the samplerate is
+ multiplied by 0x10000 -- these are the
+ lower 16 bit, which are usually 0 */
gint32 year; /* year */
gint32 volume; /* volume adjustment */
guint32 soundcheck; /* volume adjustment "soundcheck" */
@@ -563,14 +571,15 @@ struct _Itdb_Track
playcount. */
guint32 recent_playcount; /* times track was played since last sync */
gboolean transferred; /* has file been transferred to iPod? */
- gint16 BPM; /* supposed to vary the playback speed */
+ gint16 BPM; /* supposed to vary the playback speed */
guint8 app_rating; /* star rating set by appl. (not
* iPod). If the rating set on the iPod
and the rating field above differ, the
original rating is copied here and the
new rating is stored above. */
- guint16 type; /* CBR MP3s are type 0x100, VBR MP3s are
- type 0x101, AAC are type 0x0 */
+ guint8 type1; /* CBR MP3s and AAC are 0x00, VBR MP3s are
+ 0x01 */
+ guint8 type2; /* MP3s are 0x01, AAC are 0x00 */
guint8 compilation;
guint32 starttime;
guint32 stoptime;
@@ -605,7 +614,6 @@ struct _Itdb_Track
here. itdb will set this when adding
a track */
- guint16 unk060; /* unknown */
guint16 unk126; /* unknown, but always seems to be 0xffff for
MP3/AAC songs, 0x0 for uncompressed songs
(like WAVE format), 0x1 for Audible. itdb
@@ -643,10 +651,12 @@ struct _Itdb_Track
about the track will be shown. */
guint64 dbid2; /* not clear. if not set, itdb will set this to
the same value as dbid when adding a track */
- guint32 unk176; /* unknown - added in dbversion 0x0c, first
- values observed in 0x0d. Observed to be
- 0x00010000 for non-podcasts and 0x00020000
- for a podcast. */
+ guint8 lyrics_flag; /* set to 0x01 if lyrics are present in MP3 tag
+ ("ULST"), 0x00 otherwise */
+ guint8 movie_flag; /* set to 0x01 if it's a movie file, 0x00
+ otherwise */
+ guint8 unk178; /* unknown (sometimes 0x01) */
+ guint8 unk179; /* unknown (always 0x00 so far) */
guint32 unk180, unk184;
guint32 samplecount;/* Number of samples in the song. First observed
in dbversion 0x0d, and only for AAC and WAV
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index cbea6f3..8a2587e 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -1,4 +1,4 @@
-/* Time-stamp: <2006-02-14 22:10:45 jcs>
+/* Time-stamp: <2006-03-12 00:59:00 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -219,6 +219,7 @@ static FContents *fcontents_read (const gchar *fname, GError **error)
g_return_val_if_fail (fname, NULL);
cts = g_new0 (FContents, 1);
+ cts->reversed = FALSE;
if (g_file_get_contents (fname, &cts->contents, &cts->length, error))
{
@@ -394,6 +395,40 @@ static gboolean cmp_n_bytes_seek (FContents *cts, const gchar *data,
}
+/* Compare 4 bytes of @header with 4 bytes at @seek taking into
+ * consideration the status of cts->reversed */
+static gboolean check_header_seek (FContents *cts, const gchar *data,
+ glong seek)
+{
+ gchar rdata[4];
+ gint i, offset, sign;
+
+ g_return_val_if_fail (cts, FALSE);
+ g_return_val_if_fail (data, FALSE);
+ /* reverse data for compare if necessary */
+ if (cts->reversed)
+ {
+ offset = 3;
+ sign = -1;
+ }
+ else
+ {
+ offset = 0;
+ sign = 1;
+ }
+ for (i=0; i<4; ++i)
+ {
+ rdata[i] = data[offset + sign*i];
+ }
+
+ return cmp_n_bytes_seek (cts, rdata, seek, 4);
+}
+
+
+/* ------------------------------------------------------------
+ Not Endian Dependent
+ ------------------------------------------------------------ */
+
/* Returns the 1-byte number stored at position @seek. On error the
* GError in @cts is set. */
static guint8 get8int (FContents *cts, glong seek)
@@ -407,9 +442,14 @@ static guint8 get8int (FContents *cts, glong seek)
return n;
}
+
+/* ------------------------------------------------------------
+ Little Endian
+ ------------------------------------------------------------ */
+
/* Get the 2-byte-number stored at position "seek" in little endian
encoding. On error the GError in @cts is set. */
-static guint16 get16lint (FContents *cts, glong seek)
+static guint16 raw_get16lint (FContents *cts, glong seek)
{
guint16 n=0;
@@ -424,7 +464,7 @@ static guint16 get16lint (FContents *cts, glong seek)
/* Get the 3-byte-number stored at position "seek" in little endian
encoding. On error the GError in @cts is set. */
-static guint32 get24lint (FContents *cts, glong seek)
+static guint32 raw_get24lint (FContents *cts, glong seek)
{
guint32 n=0;
@@ -440,7 +480,7 @@ static guint32 get24lint (FContents *cts, glong seek)
/* Get the 4-byte-number stored at position "seek" in little endian
encoding. On error the GError in @cts is set. */
-static guint32 get32lint (FContents *cts, glong seek)
+static guint32 raw_get32lint (FContents *cts, glong seek)
{
guint32 n=0;
@@ -454,7 +494,7 @@ static guint32 get32lint (FContents *cts, glong seek)
}
/* Get 4 byte floating number */
-static float get32lfloat (FContents *cts, glong seek)
+static float raw_get32lfloat (FContents *cts, glong seek)
{
union
{
@@ -464,46 +504,97 @@ static float get32lfloat (FContents *cts, glong seek)
g_return_val_if_fail (sizeof (float) == 4, 0);
- flt.i = get32lint (cts, seek);
+ flt.i = raw_get32lint (cts, seek);
return flt.f;
}
-/* Get the 4-byte-number stored at position "seek" in big endian
+/* Get the 8-byte-number stored at position "seek" in little endian
encoding. On error the GError in @cts is set. */
-static guint32 get32bint (FContents *cts, glong seek)
+static guint64 raw_get64lint (FContents *cts, glong seek)
+{
+ guint64 n=0;
+
+ if (check_seek (cts, seek, 8))
+ {
+ g_return_val_if_fail (cts->contents, 0);
+ memcpy (&n, &cts->contents[seek], 8);
+ n = GUINT64_FROM_LE (n);
+ }
+ return n;
+}
+
+
+/* ------------------------------------------------------------
+ Big Endian
+ ------------------------------------------------------------ */
+
+/* Get the 2-byte-number stored at position "seek" in little endian
+ encoding. On error the GError in @cts is set. */
+static guint16 raw_get16bint (FContents *cts, glong seek)
+{
+ guint16 n=0;
+
+ if (check_seek (cts, seek, 2))
+ {
+ g_return_val_if_fail (cts->contents, 0);
+ memcpy (&n, &cts->contents[seek], 2);
+ n = GUINT16_FROM_BE (n);
+ }
+ return n;
+}
+
+/* Get the 3-byte-number stored at position "seek" in big endian
+ encoding. On error the GError in @cts is set. */
+static guint32 raw_get24bint (FContents *cts, glong seek)
{
guint32 n=0;
- if (check_seek (cts, seek, 4))
+ if (check_seek (cts, seek, 3))
{
g_return_val_if_fail (cts->contents, 0);
- memcpy (&n, &cts->contents[seek], 4);
- n = GUINT32_FROM_BE (n);
+ n = ((guint32)get8int (cts, seek+2)) +
+ (((guint32)get8int (cts, seek+1)) >> 8) +
+ (((guint32)get8int (cts, seek+0)) >> 16);
}
return n;
}
-/* Get the 8-byte-number stored at position "seek" in little endian
+/* Get the 4-byte-number stored at position "seek" in big endian
encoding. On error the GError in @cts is set. */
-static guint64 get64lint (FContents *cts, glong seek)
+static guint32 raw_get32bint (FContents *cts, glong seek)
{
- guint64 n=0;
+ guint32 n=0;
- if (check_seek (cts, seek, 8))
+ if (check_seek (cts, seek, 4))
{
g_return_val_if_fail (cts->contents, 0);
- memcpy (&n, &cts->contents[seek], 8);
- n = GUINT64_FROM_LE (n);
+ memcpy (&n, &cts->contents[seek], 4);
+ n = GUINT32_FROM_BE (n);
}
return n;
}
+/* Get 4 byte floating number */
+static float raw_get32bfloat (FContents *cts, glong seek)
+{
+ union
+ {
+ guint32 i;
+ float f;
+ } flt;
+
+ g_return_val_if_fail (sizeof (float) == 4, 0);
+
+ flt.i = raw_get32bint (cts, seek);
+
+ return flt.f;
+}
/* Get the 8-byte-number stored at position "seek" in big endian
encoding. On error the GError in @cts is set. */
-static guint64 get64bint (FContents *cts, glong seek)
+static guint64 raw_get64bint (FContents *cts, glong seek)
{
guint64 n=0;
@@ -516,6 +607,115 @@ static guint64 get64bint (FContents *cts, glong seek)
return n;
}
+
+/* ------------------------------------------------------------
+ Reversed Endian Sensitive (little endian)
+ ------------------------------------------------------------ */
+
+/* The following functions take into consideration the state of
+ * cts->reversed and call either raw_getnnlint or raw_getnnbint */
+static guint16 get16lint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get16lint (cts, seek);
+ else
+ return raw_get16bint (cts, seek);
+}
+
+static guint32 get24lint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get24lint (cts, seek);
+ else
+ return raw_get24bint (cts, seek);
+}
+#if 0
+static guint32 get24bint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get24bint (cts, seek);
+ else
+ return raw_get24lint (cts, seek);
+}
+#endif
+static guint32 get32lint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get32lint (cts, seek);
+ else
+ return raw_get32bint (cts, seek);
+}
+
+static float get32lfloat (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get32lfloat (cts, seek);
+ else
+ return raw_get32bfloat (cts, seek);
+}
+
+static guint64 get64lint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get64lint (cts, seek);
+ else
+ return raw_get64bint (cts, seek);
+}
+
+
+
+/* ------------------------------------------------------------
+ Reversed Endian Sensitive (big endian)
+ ------------------------------------------------------------ */
+
+#if 0
+static guint16 get16bint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get16bint (cts, seek);
+ else
+ return raw_get16lint (cts, seek);
+}
+#endif
+static guint32 get32bint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get32bint (cts, seek);
+ else
+ return raw_get32lint (cts, seek);
+}
+
+#if 0
+static float get32bfloat (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get32bfloat (cts, seek);
+ else
+ return raw_get32lfloat (cts, seek);
+}
+#endif
+
+static guint64 get64bint (FContents *cts, glong seek)
+{
+ g_return_val_if_fail (cts, 0);
+ if (!cts->reversed)
+ return raw_get64bint (cts, seek);
+ else
+ return raw_get64lint (cts, seek);
+}
+
+
+
+
/* Fix little endian UTF16 String to correct byteorder if necessary
* (all strings in the Itdb_iTunesDB are little endian except for the ones
* in smart playlists). */
@@ -589,22 +789,32 @@ static gboolean playcounts_read (FImport *fimp, FContents *cts)
g_return_val_if_fail (fimp, FALSE);
g_return_val_if_fail (cts, FALSE);
- if (!cmp_n_bytes_seek (cts, "mhdp", 0, 4))
+ if (!check_header_seek (cts, "mhdp", 0))
{
if (cts->error)
{
g_propagate_error (&fimp->error, cts->error);
+ return FALSE;
}
- else
- { /* set error */
- g_return_val_if_fail (cts->filename, FALSE);
- g_set_error (&fimp->error,
- ITDB_FILE_ERROR,
- ITDB_FILE_ERROR_CORRUPT,
- _("Not a Play Counts file: '%s' (missing mhdp header)."),
- cts->filename);
+ cts->reversed = TRUE;
+ if (!check_header_seek (cts, "mhdp", 0))
+ {
+ if (cts->error)
+ {
+ g_propagate_error (&fimp->error, cts->error);
+ return FALSE;
+ }
+ else
+ { /* set error */
+ g_return_val_if_fail (cts->filename, FALSE);
+ g_set_error (&fimp->error,
+ ITDB_FILE_ERROR,
+ ITDB_FILE_ERROR_CORRUPT,
+ _("Not a Play Counts file: '%s' (missing mhdp header)."),
+ cts->filename);
+ return FALSE;
+ }
}
- return FALSE;
}
header_length = get32lint (cts, 4);
CHECK_ERROR (fimp, FALSE);
@@ -825,7 +1035,7 @@ static void itdb_free_fimp (FImport *fimp)
{
if (fimp)
{
- if (fimp->itunesdb) fcontents_free (fimp->itunesdb);
+ if (fimp->fcontents) fcontents_free (fimp->fcontents);
g_list_free (fimp->pos_glist);
playcounts_free (fimp);
g_free (fimp);
@@ -927,7 +1137,7 @@ static gint32 get_mhod_type (FContents *cts, glong seek, guint32 *ml)
if (ml) *ml = -1;
- if (cmp_n_bytes_seek (cts, "mhod", seek, 4))
+ if (check_header_seek (cts, "mhod", seek))
{
guint32 len = get32lint (cts, seek+8); /* total length */
if (cts->error) return -1;
@@ -960,6 +1170,7 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
gint32 xl;
guint32 mhod_len;
gint32 header_length;
+ guint32 string_type;
gulong seek;
result.valid = FALSE;
@@ -988,8 +1199,12 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
}
return result;
}
+
+ if (!check_seek (cts, mhod_seek, mhod_len))
+ return result;
+
+
header_length = get32lint (cts, mhod_seek+4); /* header length */
- if (cts->error) return result;
seek = mhod_seek + header_length;
@@ -1004,7 +1219,6 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
case MHOD_ID_PLAYLIST:
/* return the position indicator */
result.data.track_pos = get32lint (cts, mhod_seek+24);
- if (cts->error) return result; /* *ml==-1, result.valid==FALSE */
break;
case MHOD_ID_TITLE:
case MHOD_ID_PATH:
@@ -1018,28 +1232,40 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
case MHOD_ID_GROUPING:
case MHOD_ID_DESCRIPTION:
case MHOD_ID_SUBTITLE:
+ /* type of string: 0x02: UTF8, 0x01 or 0x00: UTF16 LE */
+ string_type = get32lint (cts, seek);
xl = get32lint (cts, seek+4); /* length of string */
- if (cts->error) return result; /* *ml==-1, result.valid==FALSE */
g_return_val_if_fail (xl < G_MAXUINT - 2, result);
- entry_utf16 = g_new0 (gunichar2, (xl+2)/2);
- if (seek_get_n_bytes (cts, (gchar *)entry_utf16, seek+16, xl))
+ if (string_type != 0x02)
{
- fixup_little_utf16 (entry_utf16);
- result.data.string = g_utf16_to_utf8 (entry_utf16, -1,
- NULL, NULL, NULL);
- g_free (entry_utf16);
+ entry_utf16 = g_new0 (gunichar2, (xl+2)/2);
+ if (seek_get_n_bytes (cts, (gchar *)entry_utf16, seek+16, xl))
+ {
+ fixup_little_utf16 (entry_utf16);
+ result.data.string = g_utf16_to_utf8 (entry_utf16, -1,
+ NULL, NULL, NULL);
+ g_free (entry_utf16);
+ }
+ else
+ { /* error */
+ g_free (entry_utf16);
+ return result; /* *ml==-1, result.valid==FALSE */
+ }
}
else
- { /* error */
- g_free (entry_utf16);
- return result; /* *ml==-1, result.valid==FALSE */
+ {
+ result.data.string = g_new0 (gchar, xl+1);
+ if (!seek_get_n_bytes (cts, result.data.string, seek+16, xl))
+ { /* error */
+ g_free (entry_utf16);
+ return result; /* *ml==-1, result.valid==FALSE */
+ }
}
break;
case MHOD_ID_PODCASTURL:
case MHOD_ID_PODCASTRSS:
/* length of string */
xl = mhod_len - header_length;
- if (cts->error) return result; /* *ml==-1, result.valid==FALSE */
g_return_val_if_fail (xl < G_MAXUINT - 1, result);
result.data.string = g_new0 (gchar, xl+1);
if (!seek_get_n_bytes (cts, result.data.string, seek, xl))
@@ -1075,7 +1301,7 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
result.data.splpref->limitsort |= 0x80000000;
break;
case MHOD_ID_SPLRULES: /* Rules for smart playlist */
- if (cmp_n_bytes_seek (cts, "SLst", seek, 4))
+ if (check_header_seek (cts, "SLst", seek))
{
/* !!! for some reason the SLst part is the only part of the
iTunesDB with big-endian encoding, including UTF16
@@ -1098,7 +1324,7 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml)
result.data.splrules->rules, splr);
if (!check_seek (cts, seek, 56))
goto splrules_error;
- splr->field = get32bint (cts, seek);
+ splr->field = get32bint (cts, seek);
splr->action = get32bint (cts, seek+4);
seek += 52;
length = get32bint (cts, seek);
@@ -1307,7 +1533,7 @@ static glong find_next_a_in_b (FContents *cts,
/* printf ("offset: %lx, b_len: %lx, bseek+offset: %lx\n", */
/* offset, b_len, b_seek+offset); */
} while ((offset < b_len-4) &&
- !cmp_n_bytes_seek (cts, a, b_seek+offset, 4));
+ !check_header_seek (cts, a, b_seek+offset));
if (cts->error) return -1;
if (offset >= b_len) return -1;
@@ -1333,17 +1559,22 @@ static glong find_mhsd (FContents *cts, guint32 type)
guint32 i, len, mhsd_num;
glong seek;
- if (!cmp_n_bytes_seek (cts, "mhbd", 0, 4))
+ if (!check_header_seek (cts, "mhbd", 0))
{
- if (!cts->error)
- { /* set error */
- g_set_error (&cts->error,
- ITDB_FILE_ERROR,
- ITDB_FILE_ERROR_CORRUPT,
- _("Not a iTunesDB: '%s' (missing mhdb header)."),
- cts->filename);
+ cts->reversed = TRUE;
+ if (cts->error) return 0;
+ if (!check_header_seek (cts, "mhbd", 0))
+ {
+ if (!cts->error)
+ { /* set error */
+ g_set_error (&cts->error,
+ ITDB_FILE_ERROR,
+ ITDB_FILE_ERROR_CORRUPT,
+ _("Not a iTunesDB: '%s' (missing mhdb header)."),
+ cts->filename);
+ }
+ return 0;
}
- return 0;
}
len = get32lint (cts, 4);
if (cts->error) return 0;
@@ -1370,7 +1601,7 @@ static glong find_mhsd (FContents *cts, guint32 type)
guint32 mhsd_type;
seek += len;
- if (!cmp_n_bytes_seek (cts, "mhsd", seek, 4))
+ if (!check_header_seek (cts, "mhsd", seek))
{
if (!cts->error)
{ /* set error */
@@ -1420,9 +1651,9 @@ static glong get_mhip (FImport *fimp, Itdb_Playlist *plitem,
g_return_val_if_fail (fimp, -1);
g_return_val_if_fail (plitem, -1);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
- if (!cmp_n_bytes_seek (cts, "mhip", mhip_seek, 4))
+ if (!check_header_seek (cts, "mhip", mhip_seek))
{
CHECK_ERROR (fimp, -1);
return -1;
@@ -1549,9 +1780,9 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek)
g_return_val_if_fail (fimp->pos_glist == NULL, -1);
g_return_val_if_fail (fimp->pos_len == 0, -1);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
- if (!cmp_n_bytes_seek (cts, "mhyp", mhyp_seek, 4))
+ if (!check_header_seek (cts, "mhyp", mhyp_seek))
{
if (cts->error)
g_propagate_error (&fimp->error, cts->error);
@@ -1583,7 +1814,10 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek)
/* Some Playlists have added 256 to their type -- I don't know what
it's for, so we just ignore it for now -> & 0xff */
- plitem->type = get32lint (cts, mhyp_seek+20) & 0xff;
+ plitem->type = get8int (cts, mhyp_seek+20);
+ plitem->flag1 = get8int (cts, mhyp_seek+20);
+ plitem->flag2 = get8int (cts, mhyp_seek+20);
+ plitem->flag3 = get8int (cts, mhyp_seek+20);
plitem->timestamp = get32lint (cts, mhyp_seek+24);
plitem->id = get64lint (cts, mhyp_seek+28);
plitem->mhodcount = get32lint (cts, mhyp_seek+36);
@@ -1739,9 +1973,9 @@ static glong get_mhit (FImport *fimp, glong mhit_seek)
g_return_val_if_fail (fimp, -1);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
- if (!cmp_n_bytes_seek (cts, "mhit", seek, 4))
+ if (!check_header_seek (cts, "mhit", seek))
{
if (cts->error)
g_propagate_error (&fimp->error, cts->error);
@@ -1776,10 +2010,12 @@ static glong get_mhit (FImport *fimp, glong mhit_seek)
if (header_len >= 0x9c)
{
+ guint32 val32;
track->id = get32lint(cts, seek+16); /* iPod ID */
track->visible = get32lint (cts, seek+20);
seek_get_n_bytes (cts, track->filetype_marker, seek+24, 4);
- track->type = get16lint (cts, seek+28);
+ track->type1 = get8int (cts, seek+28);
+ track->type2 = get8int (cts, seek+29);
track->compilation = get8int (cts, seek+30);
track->rating = get8int (cts, seek+31);
track->time_added = get32lint(cts, seek+32); /* time added */
@@ -1789,8 +2025,9 @@ static glong get_mhit (FImport *fimp, glong mhit_seek)
track->tracks = get32lint(cts, seek+48); /* nr of tracks */
track->year = get32lint(cts, seek+52); /* year */
track->bitrate = get32lint(cts, seek+56); /* bitrate */
- track->unk060 = get32lint(cts, seek+60); /* unknown */
- track->samplerate = get16lint(cts,seek+62); /* sample rate */
+ val32 = get32lint (cts, seek+60);
+ track->samplerate = val32 >> 16; /* sample rate */
+ track->samplerate_low = val32 & 0xffff; /* remaining bits */
track->volume = get32lint(cts, seek+64); /* volume adjust */
track->starttime = get32lint (cts, seek+68);
track->stoptime = get32lint (cts, seek+72);
@@ -1830,7 +2067,10 @@ static glong get_mhit (FImport *fimp, glong mhit_seek)
track->flag3 = get8int (cts, seek+166);
track->flag4 = get8int (cts, seek+167);
track->dbid2 = get64lint (cts, seek+168);
- track->unk176 = get32lint (cts, seek+176);
+ track->lyrics_flag = get8int (cts, seek+176);
+ track->movie_flag = get8int (cts, seek+177);
+ track->unk178 = get8int (cts, seek+178);
+ track->unk179 = get8int (cts, seek+179);
track->unk180 = get32lint (cts, seek+180);
track->unk184 = get32lint (cts, seek+184);
track->samplecount = get32lint (cts, seek+188);
@@ -1980,22 +2220,26 @@ static gboolean process_OTG_file (FImport *fimp, FContents *cts,
if (!plname) plname = _("OTG Playlist");
- if (!cmp_n_bytes_seek (cts, "mhpo", 0, 4))
+ if (!check_header_seek (cts, "mhpo", 0))
{
if (cts->error)
{
g_propagate_error (&fimp->error, cts->error);
+ return FALSE;
}
- else
- { /* set error */
+ cts->reversed = TRUE;
+ if (!check_header_seek (cts, "mhpo", 0))
+ {
+ /* cts->error can't be set as already checked above */
+ /* set error */
g_return_val_if_fail (cts->filename, FALSE);
g_set_error (&fimp->error,
ITDB_FILE_ERROR,
ITDB_FILE_ERROR_CORRUPT,
_("Not a OTG playlist file: '%s' (missing mhpo header)."),
cts->filename);
+ return FALSE;
}
- return FALSE;
}
header_length = get32lint (cts, 4);
CHECK_ERROR (fimp, FALSE);
@@ -2128,13 +2372,13 @@ static gboolean parse_tracks (FImport *fimp, glong mhsd_seek)
g_return_val_if_fail (fimp, FALSE);
g_return_val_if_fail (fimp->itdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb->filename, FALSE);
+ g_return_val_if_fail (fimp->fcontents, FALSE);
+ g_return_val_if_fail (fimp->fcontents->filename, FALSE);
g_return_val_if_fail (mhsd_seek >= 0, FALSE);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
- g_return_val_if_fail (cmp_n_bytes_seek (cts, "mhsd", mhsd_seek, 4),
+ g_return_val_if_fail (check_header_seek (cts, "mhsd", mhsd_seek),
FALSE);
/* The mhlt header should be the next after the mhsd header. In
@@ -2188,13 +2432,13 @@ static gboolean parse_playlists (FImport *fimp, glong mhsd_seek)
g_return_val_if_fail (fimp, FALSE);
g_return_val_if_fail (fimp->itdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb->filename, FALSE);
+ g_return_val_if_fail (fimp->fcontents, FALSE);
+ g_return_val_if_fail (fimp->fcontents->filename, FALSE);
g_return_val_if_fail (mhsd_seek >= 0, FALSE);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
- g_return_val_if_fail (cmp_n_bytes_seek (cts, "mhsd", mhsd_seek, 4),
+ g_return_val_if_fail (check_header_seek (cts, "mhsd", mhsd_seek),
FALSE);
/* The mhlp header should be the next after the mhsd header. In
@@ -2248,10 +2492,10 @@ static gboolean parse_fimp (FImport *fimp)
g_return_val_if_fail (fimp, FALSE);
g_return_val_if_fail (fimp->itdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb, FALSE);
- g_return_val_if_fail (fimp->itunesdb->filename, FALSE);
+ g_return_val_if_fail (fimp->fcontents, FALSE);
+ g_return_val_if_fail (fimp->fcontents->filename, FALSE);
- cts = fimp->itunesdb;
+ cts = fimp->fcontents;
/* get the positions of the various mhsd */
/* type 1: track list */
@@ -2281,6 +2525,9 @@ static gboolean parse_fimp (FImport *fimp)
return FALSE;
}
+ /* copy the 'reversed endian flag' */
+ fimp->itdb->reversed = cts->reversed;
+
parse_tracks (fimp, mhsd_1);
if (fimp->error) return FALSE;
@@ -2375,9 +2622,9 @@ Itdb_iTunesDB *itdb_parse_file (const gchar *filename, GError **error)
itdb->filename = g_strdup (filename);
fimp->itdb = itdb;
- fimp->itunesdb = fcontents_read (filename, error);
+ fimp->fcontents = fcontents_read (filename, error);
- if (fimp->itunesdb)
+ if (fimp->fcontents)
{
if (playcounts_init (fimp))
{
@@ -2464,31 +2711,70 @@ static void put_string (WContents *cts, gchar *string)
put_data (cts, string, strlen(string));
}
-
-/* Write 1-byte integer @n to @cts */
-static void put8int (WContents *cts, guint8 n)
+/* Write 4-byte long @header identifcation taking into account
+ * possible reversed endianess */
+static void put_header (WContents *cts, gchar *header)
{
- put_data (cts, (gchar *)&n, 1);
+ gchar rdata[4];
+ gint i, offset, sign;
+
+ g_return_if_fail (cts);
+ g_return_if_fail (header);
+ g_return_if_fail (strlen (header) == 4);
+
+ /* reverse data for write if necessary */
+ if (cts->reversed)
+ {
+ offset = 3;
+ sign = -1;
+ }
+ else
+ {
+ offset = 0;
+ sign = 1;
+ }
+ for (i=0; i<4; ++i)
+ {
+ rdata[i] = header[offset + sign*i];
+ }
+
+ put_data (cts, rdata, 4);
}
+
+/* ------------------------------------------------------------
+ Little Endian
+ ------------------------------------------------------------ */
+
/* Write 2-byte integer @n to @cts in little endian order. */
-static void put16lint (WContents *cts, guint16 n)
+static void raw_put16lint (WContents *cts, guint16 n)
{
n = GUINT16_TO_LE (n);
put_data (cts, (gchar *)&n, 2);
}
+/* Write 3-byte integer @n to @cts in big endian order. */
+static void raw_put24lint (WContents *cts, guint32 n)
+{
+ gchar buf[3] ;
+ buf[2] = (n >> 16) & 0xff ;
+ buf[1] = (n >> 8) & 0xff ;
+ buf[0] = (n >> 0) & 0xff ;
+ put_data (cts, buf, 3);
+}
+
+
/* Write 4-byte integer @n to @cts in little endian order. */
-static void put32lint (WContents *cts, guint32 n)
+static void raw_put32lint (WContents *cts, guint32 n)
{
n = GUINT32_TO_LE (n);
put_data (cts, (gchar *)&n, 4);
}
/* Write 4 byte floating number */
-static void put32lfloat (WContents *cts, float f)
+static void raw_put32lfloat (WContents *cts, float f)
{
union
{
@@ -2498,30 +2784,46 @@ static void put32lfloat (WContents *cts, float f)
if (sizeof (float) != 4)
{
- put32lint (cts, 0);
+ raw_put32lint (cts, 0);
g_return_if_reached ();
}
flt.f = f;
- put32lint (cts, flt.i);
+ raw_put32lint (cts, flt.i);
}
-/* Append @n times 2-byte-long zeros */
-static void put16_n0 (WContents *cts, gulong n)
+/* Write 4-byte integer @n to @cts at position @seek in little
+ endian order. */
+static void raw_put32lint_seek (WContents *cts, guint32 n, gulong seek)
{
- g_return_if_fail (cts);
+ n = GUINT32_TO_LE (n);
+ put_data_seek (cts, (gchar *)&n, 4, seek);
+}
- if (n>0)
- {
- wcontents_maybe_expand (cts, 2*n, cts->pos);
- memset (&cts->contents[cts->pos], 0, 2*n);
- cts->pos += 2*n;
- }
+
+/* Write 8-byte integer @n to @cts in big little order. */
+static void raw_put64lint (WContents *cts, guint64 n)
+{
+ n = GUINT64_TO_LE (n);
+ put_data (cts, (gchar *)&n, 8);
}
+
+/* ------------------------------------------------------------
+ Big Endian
+ ------------------------------------------------------------ */
+
+/* Write 2-byte integer @n to @cts in big endian order. */
+static void raw_put16bint (WContents *cts, guint16 n)
+{
+ n = GUINT16_TO_BE (n);
+ put_data (cts, (gchar *)&n, 2);
+}
+
+
/* Write 3-byte integer @n to @cts in big endian order. */
-static void put24bint (WContents *cts, guint32 n)
+static void raw_put24bint (WContents *cts, guint32 n)
{
gchar buf[3] ;
buf[0] = (n >> 16) & 0xff ;
@@ -2530,58 +2832,74 @@ static void put24bint (WContents *cts, guint32 n)
put_data (cts, buf, 3);
}
+/* Write 4-byte integer @n to @cts in big endian order. */
+static void raw_put32bint (WContents *cts, guint32 n)
+{
+ n = GUINT32_TO_BE (n);
+ put_data (cts, (gchar *)&n, 4);
+}
-/* Write 4-byte integer @n to @cts at position @seek in little
+
+/* Write 4-byte integer @n to @cts at position @seek in big
endian order. */
-static void put32lint_seek (WContents *cts, guint32 n, gulong seek)
+static void raw_put32bint_seek (WContents *cts, guint32 n, gulong seek)
{
- n = GUINT32_TO_LE (n);
+ n = GUINT32_TO_BE (n);
put_data_seek (cts, (gchar *)&n, 4, seek);
}
-/* Write 8-byte integer @n to @cts in big little order. */
-static void put64lint (WContents *cts, guint64 n)
+/* Write 4 byte floating number */
+static void raw_put32bfloat (WContents *cts, float f)
{
- n = GUINT64_TO_LE (n);
- put_data (cts, (gchar *)&n, 8);
-}
+ union
+ {
+ guint32 i;
+ float f;
+ } flt;
+ if (sizeof (float) != 4)
+ {
+ raw_put32bint (cts, 0);
+ g_return_if_reached ();
+ }
-/* Write 4-byte integer @n to @cts in big endian order. */
-static void put32bint (WContents *cts, guint32 n)
-{
- n = GUINT32_TO_BE (n);
- put_data (cts, (gchar *)&n, 4);
+ flt.f = f;
+ raw_put32bint (cts, flt.i);
}
/* Write 8-byte integer @n to cts in big endian order. */
-static void put64bint (WContents *cts, guint64 n)
+static void raw_put64bint (WContents *cts, guint64 n)
{
n = GUINT64_TO_BE (n);
put_data (cts, (gchar *)&n, 8);
}
-#if 0
-/* Write 4-byte integer @n to @cts at position @seek in big endian
- order. */
-static void put32bint_seek (WContents *cts, guint32 n, gulong seek)
+/* ------------------------------------------------------------
+ Not Endian Dependent
+ ------------------------------------------------------------ */
+
+/* Write 1-byte integer @n to @cts */
+static void put8int (WContents *cts, guint8 n)
{
- n = GUINT32_TO_BE (n);
- put_data_seek (cts, (gchar *)&n, 4, seek);
+ put_data (cts, (gchar *)&n, 1);
}
-/* Write 8-byte integer @n to @cts at position @seek in big endian
- order. */
-static void put64bint_seek (WContents *cts, guint64 n, gulong seek)
+
+/* Append @n times 2-byte-long zeros */
+static void put16_n0 (WContents *cts, gulong n)
{
- n = GUINT64_TO_BE (n);
- put_data_seek (cts, (gchar *)&n, 8, seek);
-}
-#endif
+ g_return_if_fail (cts);
+ if (n>0)
+ {
+ wcontents_maybe_expand (cts, 2*n, cts->pos);
+ memset (&cts->contents[cts->pos], 0, 2*n);
+ cts->pos += 2*n;
+ }
+}
/* Append @n times 4-byte-long zeros */
static void put32_n0 (WContents *cts, gulong n)
@@ -2597,6 +2915,112 @@ static void put32_n0 (WContents *cts, gulong n)
}
+/* ------------------------------------------------------------
+ Reversed Endian Sensitive (little endian)
+ ------------------------------------------------------------ */
+
+static void put16lint (WContents *cts, guint16 n)
+{
+ if (!cts->reversed)
+ raw_put16lint (cts, n);
+ else
+ raw_put16bint (cts, n);
+}
+#if 0
+static void put24lint (WContents *cts, guint32 n)
+{
+ if (!cts->reversed)
+ raw_put24lint (cts, n);
+ else
+ raw_put24bint (cts, n);
+}
+#endif
+static void put32lint (WContents *cts, guint32 n)
+{
+ if (!cts->reversed)
+ raw_put32lint (cts, n);
+ else
+ raw_put32bint (cts, n);
+}
+
+static void put32lfloat (WContents *cts, float f)
+{
+ if (!cts->reversed)
+ raw_put32lfloat (cts, f);
+ else
+ raw_put32bfloat (cts, f);
+}
+
+static void put32lint_seek (WContents *cts, guint32 n, gulong seek)
+{
+ if (!cts->reversed)
+ raw_put32lint_seek (cts, n, seek);
+ else
+ raw_put32bint_seek (cts, n, seek);
+}
+
+
+static void put64lint (WContents *cts, guint64 n)
+{
+ if (!cts->reversed)
+ raw_put64lint (cts, n);
+ else
+ raw_put64bint (cts, n);
+}
+
+/* ------------------------------------------------------------
+ Reversed Endian Sensitive (big endian)
+ ------------------------------------------------------------ */
+#if 0
+static void put16bint (WContents *cts, guint16 n)
+{
+ if (cts->reversed)
+ raw_put16lint (cts, n);
+ else
+ raw_put16bint (cts, n);
+}
+#endif
+static void put24bint (WContents *cts, guint32 n)
+{
+ if (cts->reversed)
+ raw_put24lint (cts, n);
+ else
+ raw_put24bint (cts, n);
+}
+
+static void put32bint (WContents *cts, guint32 n)
+{
+ if (cts->reversed)
+ raw_put32lint (cts, n);
+ else
+ raw_put32bint (cts, n);
+}
+#if 0
+static void put32bfloat (WContents *cts, float f)
+{
+ if (cts->reversed)
+ raw_put32lfloat (cts, f);
+ else
+ raw_put32bfloat (cts, f);
+}
+
+static void put32bint_seek (WContents *cts, guint32 n, gulong seek)
+{
+ if (cts->reversed)
+ raw_put32lint_seek (cts, n, seek);
+ else
+ raw_put32bint_seek (cts, n, seek);
+}
+#endif
+static void put64bint (WContents *cts, guint64 n)
+{
+ if (cts->reversed)
+ raw_put64lint (cts, n);
+ else
+ raw_put64bint (cts, n);
+}
+
+
/* Write out the mhbd header. Size will be written later */
static void mk_mhbd (FExport *fexp, guint32 children)
@@ -2605,11 +3029,11 @@ static void mk_mhbd (FExport *fexp, guint32 children)
g_return_if_fail (fexp);
g_return_if_fail (fexp->itdb);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhbd");
+ put_header (cts, "mhbd");
put32lint (cts, 104); /* header size */
put32lint (cts, -1); /* size of whole mhdb -- fill in later */
put32lint (cts, 1); /* ? */
@@ -2642,11 +3066,11 @@ static void mk_mhsd (FExport *fexp, guint32 type)
g_return_if_fail (fexp);
g_return_if_fail (fexp->itdb);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhsd");
+ put_header (cts, "mhsd");
put32lint (cts, 96); /* Headersize */
put32lint (cts, -1); /* size of whole mhsd -- fill in later */
put32lint (cts, type); /* type: 1 = track, 2 = playlist */
@@ -2661,11 +3085,11 @@ static void mk_mhlt (FExport *fexp, guint32 num)
g_return_if_fail (fexp);
g_return_if_fail (fexp->itdb);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhlt");
+ put_header (cts, "mhlt");
put32lint (cts, 92); /* Headersize */
put32lint (cts, num); /* tracks in this itunesdb */
put32_n0 (cts, 20); /* dummy space */
@@ -2678,7 +3102,7 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
g_return_if_fail (cts);
g_return_if_fail (track);
- put_string (cts, "mhit");
+ put_header (cts, "mhit");
put32lint (cts, 0xf4); /* header size */
put32lint (cts, -1); /* size of whole mhit -- fill in later */
put32lint (cts, -1); /* nr of mhods in this mhit -- later */
@@ -2686,7 +3110,8 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
put32lint (cts, track->visible);
put_data (cts, track->filetype_marker, 4);
- put16lint (cts, track->type);
+ put8int (cts, track->type1);
+ put8int (cts, track->type2);
put8int (cts, track->compilation);
put8int (cts, track->rating);
put32lint (cts, track->time_added); /* timestamp */
@@ -2696,8 +3121,8 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
put32lint (cts, track->tracks); /* number of tracks */
put32lint (cts, track->year); /* the year */
put32lint (cts, track->bitrate); /* bitrate */
- put16lint (cts, track->unk060); /* unknown */
- put16lint (cts, track->samplerate);
+ put32lint (cts, (((guint32)track->samplerate)<<16) |
+ ((guint32)track->samplerate_low));
put32lint (cts, track->volume); /* volume adjust */
put32lint (cts, track->starttime);
put32lint (cts, track->stoptime);
@@ -2733,7 +3158,10 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
put8int (cts, track->flag3);
put8int (cts, track->flag4);
put64lint (cts, track->dbid2);
- put32lint (cts, track->unk176);
+ put8int (cts, track->lyrics_flag);
+ put8int (cts, track->movie_flag);
+ put8int (cts, track->unk178);
+ put8int (cts, track->unk179);
put32lint (cts, track->unk180);
put32lint (cts, track->unk184);
put32lint (cts, track->samplecount);
@@ -2792,40 +3220,61 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
case MHOD_ID_DESCRIPTION:
case MHOD_ID_SUBTITLE:
g_return_if_fail (mhod->data.string);
+ /* normal iTunesDBs seem to take utf16 strings), endian-inversed
+ iTunesDBs seem to take utf8 strings */
+ if (!cts->reversed)
{
/* convert to utf16 */
gunichar2 *entry_utf16 = g_utf8_to_utf16 (mhod->data.string, -1,
NULL, NULL, NULL);
guint32 len = utf16_strlen (entry_utf16);
fixup_little_utf16 (entry_utf16);
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, 2*len+40); /* size of header + body */
- put32lint (cts, mhod->type); /* type of the mhod */
+ put32lint (cts, mhod->type);/* type of the mhod */
put32_n0 (cts, 2); /* unknown */
/* end of header, start of data */
- put32lint (cts, 1); /* always 1 for these MHOD_IDs*/
+ put32lint (cts, 1); /* string type UTF16 */
put32lint (cts, 2*len); /* size of string */
put32_n0 (cts, 2); /* unknown */
put_data (cts, (gchar *)entry_utf16, 2*len);/* the string */
g_free (entry_utf16);
}
+ else
+ {
+ guint32 len = strlen (mhod->data.string);
+ put_header (cts, "mhod"); /* header */
+ put32lint (cts, 24); /* size of header */
+ put32lint (cts, len+40); /* size of header + body */
+ put32lint (cts, mhod->type);/* type of the mhod */
+ put32_n0 (cts, 2); /* unknown */
+ /* end of header, start of data */
+ put32lint (cts, 2); /* string type UTF 8 */
+ put32lint (cts, len); /* size of string */
+ put8int (cts, 1); /* unknown */
+ put8int (cts, 0); /* unknown */
+ put8int (cts, 0); /* unknown */
+ put8int (cts, 0); /* unknown */
+ put32lint (cts, 0); /* unknown */
+ put_string (cts, mhod->data.string);/* the string */
+ }
break;
case MHOD_ID_PODCASTURL:
case MHOD_ID_PODCASTRSS:
g_return_if_fail (mhod->data.string);
{
guint32 len = strlen (mhod->data.string);
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, 24+len); /* size of header + data */
put32lint (cts, mhod->type); /* type of the mhod */
put32_n0 (cts, 2); /* unknown */
- put_string (cts, mhod->data.string); /* the string */
+ put_header (cts, mhod->data.string); /* the string */
}
break;
case MHOD_ID_PLAYLIST:
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, 44); /* size of header + body */
put32lint (cts, mhod->type); /* type of the entry */
@@ -2838,7 +3287,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
g_return_if_fail (mhod->data.chapterdata_track);
{
Itdb_Track *track = mhod->data.chapterdata_track;
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, 24+track->chapterdata_raw_length); /*size */
put32lint (cts, mhod->type); /* type of the entry */
@@ -2849,7 +3298,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
break;
case MHOD_ID_SPLPREF:
g_return_if_fail (mhod->data.splpref);
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, 96); /* size of header + body */
put32lint (cts, mhod->type);/* type of the entry */
@@ -2879,7 +3328,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
GList *gl;
gint numrules = g_list_length (mhod->data.splrules->rules);
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 24); /* size of header */
put32lint (cts, -1); /* total length, fix later */
put32lint (cts, mhod->type);/* type of the entry */
@@ -2887,7 +3336,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
/* end of header, start of data */
/* For some reason this is the only part of the iTunesDB
that uses big endian */
- put_string (cts, "SLst"); /* header */
+ put_header (cts, "SLst"); /* header */
put32bint (cts, mhod->data.splrules->unk004); /* unknown*/
put32bint (cts, numrules);
put32bint (cts, mhod->data.splrules->match_operator);
@@ -2948,11 +3397,11 @@ static void mk_mhlp (FExport *fexp)
WContents *cts;
g_return_if_fail (fexp);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhlp"); /* header */
+ put_header (cts, "mhlp"); /* header */
put32lint (cts, 92); /* size of header */
/* playlists on iPod (including main!) */
put32lint (cts, g_list_length (fexp->itdb->playlists));
@@ -2973,12 +3422,12 @@ static void mk_long_mhod_id_playlist (FExport *fexp, Itdb_Playlist *pl)
WContents *cts;
g_return_if_fail (fexp);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
g_return_if_fail (pl);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhod"); /* header */
+ put_header (cts, "mhod"); /* header */
put32lint (cts, 0x18); /* size of header ? */
put32lint (cts, 0x0288); /* size of header + body */
put32lint (cts, MHOD_ID_PLAYLIST); /* type of the entry */
@@ -3025,11 +3474,11 @@ static void mk_mhip (FExport *fexp,
WContents *cts;
g_return_if_fail (fexp);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
- put_string (cts, "mhip");
+ put_header (cts, "mhip");
put32lint (cts, 76); /* 4 */
put32lint (cts, -1); /* fill in later */ /* 8 */
put32lint (cts, childcount); /* 12 */
@@ -3052,9 +3501,9 @@ static gboolean write_mhsd_tracks (FExport *fexp)
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
- g_return_val_if_fail (fexp->itunesdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
mhsd_seek = cts->pos; /* get position of mhsd header */
mk_mhsd (fexp, 1); /* write header: type 1: tracks */
@@ -3198,10 +3647,10 @@ static gboolean write_playlist_mhips (FExport *fexp,
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
- g_return_val_if_fail (fexp->itunesdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
g_return_val_if_fail (pl, FALSE);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
for (gl=pl->members; gl; gl=gl->next)
{
@@ -3259,9 +3708,9 @@ void write_one_podcast_group (gpointer key, gpointer value,
g_return_if_fail (memberlist);
g_return_if_fail (fexp);
g_return_if_fail (fexp->itdb);
- g_return_if_fail (fexp->itunesdb);
+ g_return_if_fail (fexp->wcontents);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
itdb = fexp->itdb;
mhip_seek = cts->pos;
@@ -3308,10 +3757,10 @@ static gboolean write_podcast_mhips (FExport *fexp,
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
- g_return_val_if_fail (fexp->itunesdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
g_return_val_if_fail (pl, FALSE);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
/* Create a list wit all available album names because we have to
group the podcasts according to albums */
@@ -3360,17 +3809,17 @@ static gboolean write_playlist (FExport *fexp,
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
- g_return_val_if_fail (fexp->itunesdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
g_return_val_if_fail (pl, FALSE);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
mhyp_seek = cts->pos;
#if ITUNESDB_DEBUG
fprintf(stderr, "Playlist: %s (%d tracks)\n", pl->name, g_list_length (pl->members));
#endif
- put_string (cts, "mhyp"); /* header */
+ put_header (cts, "mhyp"); /* header */
put32lint (cts, 108); /* length */
put32lint (cts, -1); /* size -> later */
if (pl->is_spl)
@@ -3379,7 +3828,10 @@ static gboolean write_playlist (FExport *fexp,
put32lint (cts, 2); /* nr of mhods */
/* number of tracks in plist */
put32lint (cts, -1); /* number of mhips -> later */
- put32lint (cts, pl->type); /* 1 = main, 0 = visible */
+ put8int (cts, pl->type); /* 1 = main, 0 = visible */
+ put8int (cts, pl->flag1); /* unknown */
+ put8int (cts, pl->flag2); /* unknown */
+ put8int (cts, pl->flag3); /* unknown */
put32lint (cts, pl->timestamp);/* some timestamp */
put64lint (cts, pl->id); /* 64 bit ID */
pl->mhodcount = 1; /* we only write one mhod type < 50 */
@@ -3432,10 +3884,10 @@ static gboolean write_mhsd_playlists (FExport *fexp, guint32 mhsd_type)
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
- g_return_val_if_fail (fexp->itunesdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
g_return_val_if_fail ((mhsd_type == 2) || (mhsd_type == 3), FALSE);
- cts = fexp->itunesdb;
+ cts = fexp->wcontents;
mhsd_seek = cts->pos; /* get position of mhsd header */
mk_mhsd (fexp, mhsd_type); /* write header */
/* write header with nr. of playlists */
@@ -3596,8 +4048,11 @@ gboolean itdb_write_file (Itdb_iTunesDB *itdb, const gchar *filename,
fexp = g_new0 (FExport, 1);
fexp->itdb = itdb;
- fexp->itunesdb = wcontents_new (filename);
- cts = fexp->itunesdb;
+ fexp->wcontents = wcontents_new (filename);
+ cts = fexp->wcontents;
+
+ /* copy endianess flag */
+ cts->reversed = itdb->reversed;
reassign_ids (fexp);
@@ -3889,8 +4344,8 @@ gboolean itdb_shuffle_write_file (Itdb_iTunesDB *itdb,
fexp = g_new0 (FExport, 1);
fexp->itdb = itdb;
- fexp->itunesdb = wcontents_new (filename);
- cts = fexp->itunesdb;
+ fexp->wcontents = wcontents_new (filename);
+ cts = fexp->wcontents;
reassign_ids (fexp);
diff --git a/src/itdb_private.h b/src/itdb_private.h
index 82ba9ad..5eacc3d 100644
--- a/src/itdb_private.h
+++ b/src/itdb_private.h
@@ -1,4 +1,4 @@
-/* Time-stamp: <2005-10-15 22:14:26 jcs>
+/* Time-stamp: <2006-03-11 01:27:48 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -57,6 +57,9 @@ typedef struct
{
gchar *filename;
gchar *contents;
+ /* indicate that endian order is reversed as in the case of the
+ iTunesDBs for mobile phones */
+ gboolean reversed;
gsize length;
GError *error;
} FContents;
@@ -67,7 +70,7 @@ typedef struct
typedef struct
{
Itdb_iTunesDB *itdb;
- FContents *itunesdb;
+ FContents *fcontents;
GList *pos_glist; /* temporary list to store position indicators */
gint32 pos_len; /* current length of above list */
GList *playcounts; /* contents of Play Counts file */
@@ -97,6 +100,9 @@ typedef struct
{
gchar *filename;
gchar *contents; /* pointer to contents */
+ /* indicate that endian order is reversed as in the case of the
+ iTunesDBs for mobile phones */
+ gboolean reversed;
gulong pos; /* current write position ("end of file") */
gulong total; /* current total size of *contents array */
GError *error; /* place to report errors to */
@@ -111,7 +117,7 @@ typedef struct
typedef struct
{
Itdb_iTunesDB *itdb;
- WContents *itunesdb;
+ WContents *wcontents;
guint32 next_id; /* next free ID to use */
GError *error; /* where to report errors to */
} FExport;