From 7c02b00752e03bbaa82978e9d26d34c9bf1bfb3e Mon Sep 17 00:00:00 2001 From: Jorg Schuler Date: Mon, 19 Sep 2005 12:33:24 +0000 Subject: * read iTunesStats file if present (corresponds to Play Counts file on the Shuffle). git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1094 f01d2545-417e-4e96-918e-98f8d0dbbcb6 --- ChangeLog | 8 ++- src/itdb_itunesdb.c | 147 +++++++++++++++++++++++++++++++++++++++++++++------- src/itdb_private.h | 7 ++- 3 files changed, 139 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 96fa166..2f0477b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,14 @@ -2005-09-17 Jorg Schuler +2005-09-19 Jorg Schuler * added additional fields to Itdb_Track that are present since version 0x0c of the iTunesDB. Write long mhit version. + * applied patch provided by Christophe Fergeau + for artwork database support (read-only). + + * read iTunesStats file if present (corresponds to Play Counts + file on the Shuffle). + 2005-09-17 Jorg Schuler * renamed fdesc to filetype diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c index 9ed1b52..9e8e65d 100644 --- a/src/itdb_itunesdb.c +++ b/src/itdb_itunesdb.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2005-09-19 17:56:57 jcs> +/* Time-stamp: <2005-09-19 21:31:28 jcs> | | Copyright (C) 2002-2005 Jorg Schuler | Part of the gtkpod project. @@ -395,7 +395,7 @@ static guint16 get16lint (FContents *cts, glong seek) { guint32 n=0; - if (check_seek (cts, seek, 4)) + if (check_seek (cts, seek, 2)) { g_return_val_if_fail (cts->contents, 0); memcpy (&n, &cts->contents[seek], 4); @@ -406,6 +406,22 @@ static guint16 get16lint (FContents *cts, glong seek) return n; } +/* 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) +{ + guint32 n=0; + + if (check_seek (cts, seek, 3)) + { + g_return_val_if_fail (cts->contents, 0); + n = ((guint32)get8int (cts, seek+0)) + + (((guint32)get8int (cts, seek+1)) >> 8) + + (((guint32)get8int (cts, seek+2)) >> 16); + } + return n; +} + /* 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) @@ -646,30 +662,92 @@ static gboolean playcounts_read (FImport *fimp, FContents *cts) /* unk16 only exists if the entry length is at least 0x14 */ if (entry_length >= 0x14) { - playcount->unk16 = get32lint (cts, seek+16); + playcount->pc_unk16 = get32lint (cts, seek+16); CHECK_ERROR (fimp, FALSE); } else { - playcount->unk16 = 0; + playcount->pc_unk16 = 0; } } return TRUE; } +/* called by init_playcounts */ +static gboolean itunesstats_read (FImport *fimp, FContents *cts) +{ + guint32 entry_num, i=0; + glong seek; + + g_return_val_if_fail (fimp, FALSE); + g_return_val_if_fail (cts, FALSE); + + /* number of entries */ + entry_num = get32lint (cts, 0); + CHECK_ERROR (fimp, FALSE); + + seek = 6; + for (i=0; ierror, + ITDB_FILE_ERROR, + ITDB_FILE_ERROR_CORRUPT, + _("iTunesStats file ('%s'): entry length smaller than expected (%d<18)."), + cts->filename, entry_length); + return FALSE; + } + + fimp->playcounts = g_list_append (fimp->playcounts, playcount); + /* NOTE: + * + * The iPod (firmware 1.3, 2.0, ...?) doesn't seem to use the + * timezone information correctly -- no matter what you set + * iPod's timezone to, it will always record as if it were set + * to UTC -- we need to subtract the difference between + * current timezone and UTC to get a correct + * display. -- this should be done by the application were + * necessary */ + playcount->bookmark_time = get24lint (cts, seek+3); + CHECK_ERROR (fimp, FALSE); + playcount->st_unk06 = get24lint (cts, seek+6); + CHECK_ERROR (fimp, FALSE); + playcount->st_unk09 = get24lint (cts, seek+9); + CHECK_ERROR (fimp, FALSE); + playcount->playcount = get24lint (cts, seek+12); + CHECK_ERROR (fimp, FALSE); + playcount->skipped = get24lint (cts, seek+15); + CHECK_ERROR (fimp, FALSE); + + playcount->rating = NO_PLAYCOUNT; + + seek += entry_length; + } + return TRUE; +} + + /* Read the Play Count file (formed by adding "Play Counts" to the * directory component of fimp->itdb->itdb_filename) and set up the - * GList *playcounts. + * GList *playcounts. If no Play Count file is present, attempt to + * read the iTunesStats file instead, which is used on the Shuffle for + * the same purpose. + * * Returns TRUE on success (also when no Play Count * file is found as this is not an error) and FALSE otherwise, in * which case fimp->error is set accordingly. */ static gboolean playcounts_init (FImport *fimp) { - const gchar *db[] = {"Play Counts", NULL}; - gchar *plcname, *dirname; - gboolean result=FALSE; + const gchar *plc[] = {"Play Counts", NULL}; + const gchar *ist[] = {"iTunesStats", NULL}; + gchar *plcname, *dirname, *istname; + gboolean result=TRUE; struct stat filestat; FContents *cts; @@ -681,25 +759,54 @@ static gboolean playcounts_init (FImport *fimp) dirname = g_path_get_dirname (fimp->itdb->filename); - plcname = itdb_resolve_path (dirname, db); + plcname = itdb_resolve_path (dirname, plc); + istname = itdb_resolve_path (dirname, ist); g_free (dirname); /* skip if no playcounts file is present */ - if (!plcname) return TRUE; - - /* skip if playcounts file has zero-length (often happens after - * dosfsck) */ - stat (plcname, &filestat); - if (filestat.st_size < 0x60) return TRUE; /* check for header length */ - - cts = fcontents_read (plcname, &fimp->error); - if (cts) + if (plcname) { - result = playcounts_read (fimp, cts); - fcontents_free (cts); + /* skip if playcounts file has zero-length (often happens after + * dosfsck) */ + stat (plcname, &filestat); + if (filestat.st_size >= 0x60) + { + cts = fcontents_read (plcname, &fimp->error); + if (cts) + { + result = playcounts_read (fimp, cts); + fcontents_free (cts); + } + else + { + result = FALSE; + } + } + } + else if (istname) + { + /* skip if iTunesStats file has zero-length (often happens after + * dosfsck) */ + stat (plcname, &filestat); + if (filestat.st_size >= 0x06) + { + cts = fcontents_read (istname, &fimp->error); + if (cts) + { + result = itunesstats_read (fimp, cts); + fcontents_free (cts); + } + else + { + result = FALSE; + } + } } + g_free (plcname); + g_free (istname); + return result; } diff --git a/src/itdb_private.h b/src/itdb_private.h index 72e8558..fa94d5f 100644 --- a/src/itdb_private.h +++ b/src/itdb_private.h @@ -1,4 +1,4 @@ -/* Time-stamp: <2005-07-09 15:48:29 jcs> +/* Time-stamp: <2005-09-19 21:30:34 jcs> | | Copyright (C) 2002-2005 Jorg Schuler | Part of the gtkpod project. @@ -61,10 +61,13 @@ typedef struct /* data of playcounts GList above */ struct playcount { guint32 playcount; + guint32 skipped; /* skipped (only for Shuffle's iTunesStats */ guint32 time_played; guint32 bookmark_time; gint32 rating; - gint32 unk16; + gint32 pc_unk16; /* unknown field in Play Counts file */ + gint32 st_unk06; /* unknown field in iTunesStats file */ + gint32 st_unk09; /* unknown field in iTunesStats file */ }; /* value to indicate that playcount was not set in struct playcount -- cgit