Revision: 1980
          http://gtkpod.svn.sourceforge.net/gtkpod/?rev=1980&view=rev
Author:   teuf
Date:     2008-05-25 03:38:09 -0700 (Sun, 25 May 2008)

Log Message:
-----------
* configure.ac: check libxml presence
* src/Makefile.am: add new files, remove obsolete ones
* src/itdb_plist.h: 
* src/itdb_plist.c: plist parser, this parses a plist XML file to a
GHashTable of GValue *. This parser should be generic, ie it
doesn't know it's parsing SysInfoExtended, it only cares about it
being a plist file
* src/itdb_sysinfo_extended_parser.h:
* src/itdb_sysinfo_extended_parser.c: convert the parsed plist data
to data structures usable by libgpod
* src/itdb_device.h:
* src/itdb_device.c: parses SysInfoExtended in addition to SysInfo
* src/itdb_sysinfo.c: this hacky parser is obsoleted by the new
(much more complete) SysInfoExtended parser, so it's removed
* tests/Makefile.am:
* tests/test-sysinfo-extended-parsing.c: small test program for the
new parser

Modified Paths:
--------------
    libgpod/trunk/ChangeLog
    libgpod/trunk/configure.ac
    libgpod/trunk/src/Makefile.am
    libgpod/trunk/src/itdb_device.c
    libgpod/trunk/src/itdb_device.h
    libgpod/trunk/tests/Makefile.am

Added Paths:
-----------
    libgpod/trunk/src/itdb_plist.c
    libgpod/trunk/src/itdb_plist.h
    libgpod/trunk/src/itdb_sysinfo_extended_parser.c
    libgpod/trunk/src/itdb_sysinfo_extended_parser.h
    libgpod/trunk/tests/test-sysinfo-extended-parsing.c

Removed Paths:
-------------
    libgpod/trunk/src/itdb_sysinfo.c

Modified: libgpod/trunk/ChangeLog
===================================================================
--- libgpod/trunk/ChangeLog     2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/ChangeLog     2008-05-25 10:38:09 UTC (rev 1980)
@@ -1,5 +1,25 @@
 2008-05-25  Christophe Fergeau <teuf at gnome.org>
 
+       * configure.ac: check libxml presence
+       * src/Makefile.am: add new files, remove obsolete ones
+       * src/itdb_plist.h: 
+       * src/itdb_plist.c: plist parser, this parses a plist XML file to a
+       GHashTable of GValue *. This parser should be generic, ie it
+       doesn't know it's parsing SysInfoExtended, it only cares about it
+       being a plist file
+       * src/itdb_sysinfo_extended_parser.h:
+       * src/itdb_sysinfo_extended_parser.c: convert the parsed plist data
+       to data structures usable by libgpod
+       * src/itdb_device.h:
+       * src/itdb_device.c: parses SysInfoExtended in addition to SysInfo
+       * src/itdb_sysinfo.c: this hacky parser is obsoleted by the new
+       (much more complete) SysInfoExtended parser, so it's removed
+       * tests/Makefile.am:
+       * tests/test-sysinfo-extended-parsing.c: small test program for the
+       new parser
+
+2008-05-25  Christophe Fergeau <teuf at gnome.org>
+
        Patch from Ian Stewart <ian.stewart at ozemail.com.au>
 
        * src/itdb_itunesdb.c: add jump letter support (mhod53)

Modified: libgpod/trunk/configure.ac
===================================================================
--- libgpod/trunk/configure.ac  2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/configure.ac  2008-05-25 10:38:09 UTC (rev 1980)
@@ -128,6 +128,17 @@
 AC_SUBST(TAGLIB_LIBS)
 AM_CONDITIONAL(HAVE_TAGLIB, test x"$have_taglib" = xyes)
 
+dnl **************************************************
+dnl * libxml is used to parse the plist files (aka SysInfoExtended)
+dnl **************************************************
+PKG_CHECK_MODULES(LIBXML, libxml-2.0, have_libxml=yes, have_libxml=no)
+if test x"$have_libxml" = xyes; then
+   AH_TEMPLATE([HAVE_LIBXML], [Whether libxml is installed, it's only used in 
a test program])
+   AC_DEFINE_UNQUOTED(HAVE_LIBXML, 1)
+fi
+AC_SUBST(LIBXML_CFLAGS)
+AC_SUBST(LIBXML_LIBS)
+AM_CONDITIONAL(HAVE_LIBXML, test x"$have_libxml" = xyes)
 
 dnl **************************************************
 dnl * GDKPIXBUF is optional

Modified: libgpod/trunk/src/Makefile.am
===================================================================
--- libgpod/trunk/src/Makefile.am       2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/src/Makefile.am       2008-05-25 10:38:09 UTC (rev 1980)
@@ -12,8 +12,9 @@
        itdb_itunesdb.c         \
        itdb_photoalbum.c       \
        itdb_playlist.c         \
+       itdb_plist.c            \
        itdb_sha1.c             \
-       itdb_sysinfo.c          \
+       itdb_sysinfo_extended_parser.c \
        itdb_track.c            \
        ithumb-writer.c         \
        pixmaps.c               \
@@ -32,13 +33,15 @@
        db-parse-context.h      \
        itdb_device.h           \
        itdb_endianness.h       \
+       itdb_plist.h            \
        itdb_private.h          \
        itdb_sha1.h             \
+       itdb_sysinfo_extended_parser.h \
        pixmaps.h               \
        sha1.h
 
-INCLUDES=$(LIBGPOD_CFLAGS)
-LIBS=$(LIBGPOD_LIBS)
+INCLUDES=$(LIBGPOD_CFLAGS) $(LIBXML_CFLAGS)
+LIBS=$(LIBGPOD_LIBS) $(LIBXML_LIBS)
 
 uninstall-hook:
        -rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libgpodincludedir)

Modified: libgpod/trunk/src/itdb_device.c
===================================================================
--- libgpod/trunk/src/itdb_device.c     2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/src/itdb_device.c     2008-05-25 10:38:09 UTC (rev 1980)
@@ -387,6 +387,8 @@
        g_free (device->mountpoint);
        if (device->sysinfo)
            g_hash_table_destroy (device->sysinfo);
+        if (device->sysinfo_extended)
+            itdb_sysinfo_properties_free (device->sysinfo_extended);
        g_free (device);
     }
 }
@@ -428,7 +430,33 @@
     else return 0;
 }
 
+static void itdb_device_read_sysinfo_extended (Itdb_Device *device)
+{
+    const gchar *p_sysinfo_ex[] = {"SysInfoExtended", NULL};
+    gchar *dev_path, *sysinfo_ex_path;
 
+    if (device->sysinfo_extended != NULL) {
+        itdb_sysinfo_properties_free (device->sysinfo_extended);
+        device->sysinfo_extended = NULL;
+    }
+
+    dev_path = itdb_get_device_dir (device->mountpoint);
+    if (!dev_path) return;
+
+    sysinfo_ex_path = itdb_resolve_path (dev_path, p_sysinfo_ex);
+    g_free (dev_path);
+    if (!sysinfo_ex_path) return;
+    device->sysinfo_extended = itdb_sysinfo_extended_parse (sysinfo_ex_path);
+    g_free (sysinfo_ex_path);
+
+    if ((device->sysinfo != NULL) && (device->sysinfo_extended != NULL)) {
+        const char *fwid;
+        fwid = itdb_sysinfo_properties_get_firewire_id 
(device->sysinfo_extended);
+        g_hash_table_insert (device->sysinfo, g_strdup ("FirewireGuid"),
+                             g_strdup (fwid));
+    }
+}
+
 /** 
  * itdb_device_read_sysinfo:
  * @device: an #Itdb_Device
@@ -490,7 +518,7 @@
     }
     g_free (dev_path);
 
-    itdb_device_read_sysinfo_xml (device, NULL);
+    itdb_device_read_sysinfo_extended (device);
 
     /* indicate that sysinfo is identical to what is on the iPod */
     device->sysinfo_changed = FALSE;

Modified: libgpod/trunk/src/itdb_device.h
===================================================================
--- libgpod/trunk/src/itdb_device.h     2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/src/itdb_device.h     2008-05-25 10:38:09 UTC (rev 1980)
@@ -40,6 +40,7 @@
 #endif
 
 #include "itdb.h"
+#include "itdb_sysinfo_extended_parser.h"
 
 #include <glib.h>
 
@@ -85,6 +86,8 @@
                           */
     GHashTable *sysinfo;  /* hash with value/key pairs of all entries
                           * in Device/SysInfo */
+    SysInfoIpodProperties *sysinfo_extended; /* parsed content of 
+                                              * SysInfoExtended, can be NULL */
     gboolean sysinfo_changed; /* Has the sysinfo hash been changed by
                                 the user (itdb_set_sysinfo) */
     gint timezone_shift;  /* difference in seconds between the current
@@ -109,8 +112,6 @@
 G_GNUC_INTERNAL const Itdb_ArtworkFormat *itdb_device_get_artwork_formats 
(Itdb_Device *device);
 G_GNUC_INTERNAL gint itdb_device_musicdirs_number (Itdb_Device *device);
 G_GNUC_INTERNAL void itdb_device_autodetect_endianess (Itdb_Device *device);
-G_GNUC_INTERNAL gboolean itdb_device_read_sysinfo_xml (Itdb_Device *device, 
-                                                      GError **error);
 G_GNUC_INTERNAL guint64 itdb_device_get_firewire_id (Itdb_Device *device);
 
 G_END_DECLS

Added: libgpod/trunk/src/itdb_plist.c
===================================================================
--- libgpod/trunk/src/itdb_plist.c                              (rev 0)
+++ libgpod/trunk/src/itdb_plist.c      2008-05-25 10:38:09 UTC (rev 1980)
@@ -0,0 +1,326 @@
+/*
+|  Copyright (C) 2008 Christophe Fergeau <[EMAIL PROTECTED]>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  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!
+|
+|  $Id$
+*/
+
+/* This file implements a generic plist parser. A plist file is an
+ * Apple-specific XML format which is used to serialize (simple) data
+ * structures to disk, see http://en.wikipedia.org/wiki/Property_list
+ * 
+ * This parser should handle most plist files, with those limitations :
+ *      - no support for <date> tags
+ *      - no support for <array> containing "unamed" elements (ie with no
+ *      <key> tag)
+ *
+ * The plist file is parsed using libxml, and the parsed result is stored 
+ * in GValue. The types are mapped in the following way:
+ *      - <string> => G_TYPE_STRING (char*)
+ *      - <real> => G_TYPE_DOUBLE (double)
+ *      - <integer> => G_TYPE_INT (gint)
+ *      - <true/>, <false/> => G_TYPE_BOOLEAN (gboolean)
+ *      - <data> => G_TYPE_GSTRING (GString *)
+ *      - <array> => G_TYPE_HASH_TABLE (GHashTable *)
+ *      - <dict> => G_TYPE_HASH_TABLE (GHashTable *)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "itdb_plist.h"
+
+#ifdef DEBUG_SYSINFO_PARSING
+#define DEBUG g_print
+#else
+#define DEBUG(...)
+#endif
+
+static GValue *parse_node (xmlNode *a_node);
+
+static void 
+value_free (GValue *val)
+{
+    g_value_unset (val);
+    g_free (val);
+}
+
+static GValue * 
+parse_integer(xmlNode *a_node)
+{
+    char *str_val;
+    gint int_val;
+    GValue *value;
+
+    str_val = (char *)xmlNodeGetContent(a_node);
+    int_val = strtol (str_val, NULL, 0);
+    xmlFree (str_val);
+
+    value = g_new0(GValue, 1);
+    g_value_init(value, G_TYPE_INT);
+    g_value_set_int (value, int_val);
+
+    return value;
+}
+
+static GValue * 
+parse_string(xmlNode *a_node)
+{
+    char *str_val;
+    GValue *value;
+
+    str_val = (char *)xmlNodeGetContent(a_node);
+
+    value = g_new0(GValue, 1);
+    g_value_init(value, G_TYPE_STRING);
+    g_value_set_string (value, str_val);
+
+    xmlFree (str_val);
+
+    return value;
+}
+
+static GValue *
+parse_real(xmlNode *a_node)
+{
+    char *str_val;
+    gfloat double_val;
+    GValue *value;
+
+    str_val = (char *)xmlNodeGetContent(a_node);
+    double_val = g_ascii_strtod (str_val, NULL);
+    xmlFree (str_val);
+
+    value = g_new0(GValue, 1);
+    g_value_init(value, G_TYPE_DOUBLE);
+    g_value_set_double (value, double_val);
+
+    return value;
+}
+
+static GValue *
+parse_boolean (xmlNode *a_node)
+{
+    gboolean bool_val;
+    GValue *value;
+
+    if (strcmp ((char *)a_node->name, "true") == 0) {
+        bool_val = TRUE;
+    } else if (strcmp ((char *)a_node->name, "false") == 0) {
+        bool_val = FALSE;
+    } else {
+        DEBUG ("unexpected boolean value\n");
+        return NULL;
+    }
+
+    value = g_new0 (GValue, 1);
+    g_value_init (value, G_TYPE_BOOLEAN);
+    g_value_set_boolean (value, bool_val);
+
+    return value;
+}
+
+static GValue *
+parse_data (xmlNode *a_node)
+{
+    char *str_val;
+    guchar *raw_data;
+    gsize len;
+    GString *data_val;
+    GValue *value;
+
+    str_val = (char *)xmlNodeGetContent(a_node);
+    raw_data = g_base64_decode (str_val, &len);
+    xmlFree (str_val);
+    data_val = g_string_new_len ((char *)raw_data, len);
+    g_free (raw_data);
+
+    value = g_new0(GValue, 1);
+    g_value_init(value, G_TYPE_GSTRING);
+    g_value_take_boxed (value, data_val);
+
+    return value;
+}
+
+static xmlNode *
+parse_one_dict_entry (xmlNode *a_node, GHashTable *dict)
+{
+    xmlNode *cur_node = a_node;
+    xmlChar *key_name;
+    GValue *value;
+
+    while ((cur_node != NULL) && (xmlStrcmp(cur_node->name, (xmlChar *)"key") 
!= 0)) {
+        if (!xmlNodeIsText (cur_node)) {
+            DEBUG ("skipping %s\n", cur_node->name);
+        }
+        cur_node = cur_node->next;
+    }
+    if (cur_node == NULL) {
+        return NULL;
+    }
+    key_name = xmlNodeGetContent(cur_node);
+    cur_node = cur_node->next;
+    while ((cur_node != NULL) && xmlNodeIsText(cur_node)) {
+        cur_node = cur_node->next;
+    }
+    if (cur_node == NULL) {
+        DEBUG ("<key> %s with no corresponding value node", key_name);
+        xmlFree (key_name);
+        return NULL;
+    }
+
+    value = parse_node (cur_node);
+    if (value != NULL) {
+        g_hash_table_insert (dict, g_strdup ((char *)key_name), value);
+    }
+    xmlFree (key_name);
+
+    return cur_node->next;
+}
+
+static GValue * 
+parse_dict (xmlNode *a_node)
+{
+    xmlNode *cur_node = a_node->children;
+    GValue *value;
+    GHashTable *dict;
+
+    dict = g_hash_table_new_full (g_str_hash, g_str_equal, 
+                                  g_free, (GDestroyNotify)value_free);
+
+    while (cur_node != NULL) {
+        cur_node = parse_one_dict_entry (cur_node, dict);
+    }
+
+    value = g_new0 (GValue, 1);
+    value = g_value_init (value, G_TYPE_HASH_TABLE);
+    g_value_take_boxed (value, dict);
+
+    return value;
+}
+
+typedef GValue *(*ParseCallback) (xmlNode *);
+struct Parser {
+    const char * const type_name;
+    ParseCallback parser;
+};
+
+static struct Parser parsers[] = { {"integer", parse_integer},
+                                   {"real",    parse_real},
+                                   {"string",  parse_string},
+                                   {"true",    parse_boolean},
+                                   {"false",   parse_boolean},
+                                   {"data",    parse_data},
+                                   {"dict",    parse_dict}, 
+                                   {"array",   parse_dict},
+                                   {NULL,      NULL} };
+
+static GValue *parse_node (xmlNode *a_node)
+{
+    guint i = 0;
+    g_return_val_if_fail (a_node != NULL, FALSE);
+    while (parsers[i].type_name != NULL) {        
+        if (xmlStrcmp (a_node->name, (xmlChar *)parsers[i].type_name) == 0) {
+            if (parsers[i].parser != NULL) {
+                return parsers[i].parser (a_node);
+            }
+        }
+        i++;
+    }
+    DEBUG ("no parser for <%s>\n", a_node->name);
+    return NULL;
+}
+
+static GValue *
+itdb_plist_parse (xmlNode * a_node)
+{
+    xmlNode *cur_node;
+    if (a_node == NULL) {
+        DEBUG ("empty file\n");
+        return NULL;
+    }
+    if (xmlStrcmp (a_node->name, (xmlChar *)"plist") != 0) {
+        DEBUG ("not a plist file\n");
+        return NULL;
+    }
+    cur_node = a_node->xmlChildrenNode;
+    while ((cur_node != NULL) && (xmlNodeIsText (cur_node))) {
+        cur_node = cur_node->next;
+    }
+    if (cur_node != NULL) {
+        return parse_node (cur_node);
+    }
+    return NULL;
+}
+
+GValue *
+itdb_plist_parse_from_file (const char *filename)
+{
+    xmlDoc *doc = NULL;
+    xmlNode *root_element = NULL;
+    GValue *parsed_doc;
+
+    doc = xmlReadFile(filename, NULL, 0);
+
+    if (doc == NULL) {
+        printf("error: could not parse file %s\n", filename);
+        return NULL;
+    }
+
+    root_element = xmlDocGetRootElement(doc);
+
+    parsed_doc = itdb_plist_parse (root_element);
+
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+
+    return parsed_doc;
+}
+
+GValue *
+itdb_plist_parse_from_memory (const char *data, gsize len)
+{
+    xmlDoc *doc = NULL;
+    xmlNode *root_element = NULL;
+    GValue *parsed_doc;
+
+    doc = xmlReadMemory(data, len, "noname.xml", NULL, 0);
+
+    if (doc == NULL) {
+        printf("error: could not parse data from memory\n");
+        return NULL;
+    }
+
+    root_element = xmlDocGetRootElement(doc);
+
+    parsed_doc = itdb_plist_parse (root_element);
+
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+
+    return parsed_doc;
+}

Added: libgpod/trunk/src/itdb_plist.h
===================================================================
--- libgpod/trunk/src/itdb_plist.h                              (rev 0)
+++ libgpod/trunk/src/itdb_plist.h      2008-05-25 10:38:09 UTC (rev 1980)
@@ -0,0 +1,42 @@
+/*
+|  Copyright (C) 2008 Christophe Fergeau <[EMAIL PROTECTED]>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  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!
+|
+|  $Id$
+*/
+
+#ifndef __ITDB_PLIST_H__
+#define __ITDB_PLIST_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL GValue *itdb_plist_parse_from_file (const char *filename);
+G_GNUC_INTERNAL GValue *itdb_plist_parse_from_memory (const char *data, 
+                                                      gsize len); 
+
+G_END_DECLS
+
+#endif

Deleted: libgpod/trunk/src/itdb_sysinfo.c
===================================================================
--- libgpod/trunk/src/itdb_sysinfo.c    2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/src/itdb_sysinfo.c    2008-05-25 10:38:09 UTC (rev 1980)
@@ -1,269 +0,0 @@
-/*
-|  Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
-|  Part of the gtkpod project.
-|
-|  URL: http://www.gtkpod.org/
-|  URL: http://gtkpod.sourceforge.net/
-|
-|  Part of this code is based on ipod-device.c from the libipoddevice
-|  project (http://64.14.94.162/index.php/Libipoddevice).
-|
-|  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!
-|
-|  $Id$
-*/
-
-#include <string.h>
-
-#include <glib.h>
-
-#include "itdb_device.h"
-
-enum ParsingState {
-    LOOKING_FOR_KEY_TAG,
-    PARSING_KEY_TAG,
-    LOOKING_FOR_FW_DATA,
-    PARSING_FW_DATA,
-    DONE
-};
-
-struct _SysInfoParseContext {
-    enum ParsingState state;
-    char *text;
-    Itdb_Device *device;
-};
-typedef struct _SysInfoParseContext SysInfoParseContext;
-
-
-static void parse_start_element (GMarkupParseContext *context,
-                                 const gchar *element_name,
-                                 const gchar **attribute_names,
-                                 const gchar **attribute_values,
-                                 gpointer user_data,
-                                 GError **error)
-{
-    SysInfoParseContext *sysinfo = (SysInfoParseContext *)user_data;
-
-#ifdef DEBUG
-    g_print ("start: %s\n", element_name);
-#endif
-    switch (sysinfo->state) {
-    case DONE:
-        break;
-    case LOOKING_FOR_FW_DATA:
-        if (strcmp (element_name, "string") == 0) {
-            sysinfo->state = PARSING_FW_DATA;
-            break;
-        }
-        /* Fallback to default case if we didn't find the tag we expected */
-    case LOOKING_FOR_KEY_TAG:
-    default:
-        if (strcmp (element_name, "key") == 0) {
-            sysinfo->state = PARSING_KEY_TAG;
-        } else {
-            sysinfo->state = LOOKING_FOR_KEY_TAG;
-        }
-        break;
-    }
-}
-
-static void parse_end_element (GMarkupParseContext *context,
-                              const gchar *element_name,
-                              gpointer user_data,
-                              GError **error)
-{
-    SysInfoParseContext *sysinfo = (SysInfoParseContext *)user_data;
-
-#ifdef DEBUG
-    g_print ("end: %s\n", element_name);
-#endif
-
-    switch (sysinfo->state) {
-    case PARSING_KEY_TAG:
-        if (sysinfo->text == NULL) {
-            sysinfo->state = LOOKING_FOR_KEY_TAG;
-            break;
-        }
-        if (strcmp (sysinfo->text, "FireWireGUID") == 0) {
-            sysinfo->state = LOOKING_FOR_FW_DATA;
-        } else {
-            sysinfo->state = LOOKING_FOR_KEY_TAG;
-        }
-        g_free (sysinfo->text);
-        sysinfo->text = NULL;
-        break;
-    case PARSING_FW_DATA:
-        if (sysinfo->text == NULL) {
-            sysinfo->state = LOOKING_FOR_KEY_TAG;
-        }
-       /* Use FirewireGuid instead of FireWireGUID to be coherent with what
-        * the SysInfo file used to contain
-        */
-       g_hash_table_insert (sysinfo->device->sysinfo,
-                            g_strdup ("FirewireGuid"),
-                            sysinfo->text);
-       sysinfo->text = NULL;
-        sysinfo->state = DONE;
-        break;
-    case LOOKING_FOR_KEY_TAG:
-    case LOOKING_FOR_FW_DATA:
-    case DONE:
-        break;
-
-    }
-}
-
-static void parse_text  (GMarkupParseContext *context,
-                        const gchar *text,
-                        gsize text_len,
-                        gpointer user_data,
-                        GError **error)
-{
-#ifdef DEBUG
-    char *str = g_strndup (text, text_len);
-    g_print ("text: %s\n", str);
-    g_free (str);
-#endif
-
-    SysInfoParseContext *sysinfo = (SysInfoParseContext *)user_data;
-    switch (sysinfo->state) {
-    case DONE:
-        break;
-    case PARSING_FW_DATA:
-    case PARSING_KEY_TAG:
-        g_free (sysinfo->text);
-        sysinfo->text = g_strndup (text, text_len);
-        break;
-    default:
-        g_free (sysinfo->text);
-        sysinfo->text = NULL;
-        break;
-    }
-}
-
-static void parse_error (GMarkupParseContext *context,
-                        GError *error,
-                        gpointer user_data)
-{
-    gint line;
-    gint row;
-    g_markup_parse_context_get_position (context, &line, &row);
-    g_warning ("error at line %i row %i", line, row);
-}
-
-static char *
-get_sysinfo_extended_path (Itdb_Device *device)
-{
-    const gchar *p_sysinfo[] = {"SysInfoExtended", NULL};
-    gchar *dev_path, *sysinfo_path;
-
-    dev_path = itdb_get_device_dir (device->mountpoint);
-
-    if (!dev_path) {
-       return NULL;
-    }
-
-    sysinfo_path = itdb_resolve_path (dev_path, p_sysinfo);
-    g_free (dev_path);
-    return sysinfo_path;
-}
-
-static void init_gmarkup_parser (GMarkupParser *parser)
-{
-    parser->start_element = parse_start_element;
-    parser->end_element = parse_end_element;
-    parser->text = parse_text;
-    parser->error = parse_error;
-}
-
-
-static gboolean parse_sysinfo_xml (Itdb_Device *device, 
-                                  const char *xml, gsize len,
-                                  GError **error)
-{
-    GMarkupParseContext *ctx;
-    GMarkupParser parser = {0, };
-    gboolean success;
-
-    SysInfoParseContext sysinfo = {0, };
-    sysinfo.state = LOOKING_FOR_KEY_TAG;
-    sysinfo.device = device;
-
-    init_gmarkup_parser (&parser);
-    ctx = g_markup_parse_context_new (&parser, 0, &sysinfo, NULL);
-    success = g_markup_parse_context_parse (ctx, xml, len, error);
-    if (!success) {
-        g_markup_parse_context_free (ctx);
-        return FALSE;
-    }
-    success = g_markup_parse_context_end_parse (ctx, error);
-    if (!success) {
-        g_markup_parse_context_free (ctx);
-        return FALSE;
-    }
-    g_markup_parse_context_free (ctx);
-
-    return TRUE;
-}
-
-/**
- * itdb_device_read_sysinfo_xml:
- * @device: an #Itdb_Device 
- * @error: return location for a #GError or NULL
- *
- * Parses a SysInfoExtended file located in iPod_Control/Device on the 
- * passed-in @device. This file contains a detailed description of the iPod 
- * capabilities/characteristics. In particular, it contains the iPod Firewire 
- * ID which is necessary to build the checksum of the iTunesDB.
- * That file is automatically parsed when @device mount point is set 
- * if it can be found.
- *
- * If a SysInfoExtended file could be successfully read, TRUE is returned. 
- * Otherwise it returns FALSE and sets @error.
- *
- * Return value: TRUE on success, FALSE if an error occurred
- *
- **/
-gboolean
-itdb_device_read_sysinfo_xml (Itdb_Device *device, GError **error)
-{
-    gboolean success;
-    char *sysinfo_path;
-    char *xml_data;
-    gsize len;
-
-    sysinfo_path = get_sysinfo_extended_path (device);
-    if (sysinfo_path == NULL) {
-       g_set_error (error, ITDB_FILE_ERROR, ITDB_FILE_ERROR_NOTFOUND,
-                    "Couldn't find SysInfoExtended file");
-       return FALSE;
-    }
-    success = g_file_get_contents (sysinfo_path, &xml_data, &len, error);
-    g_free (sysinfo_path);
-
-    if (!success) {
-        return FALSE;
-    }
-    
-    success = parse_sysinfo_xml (device, xml_data, len, error);
-    g_free (xml_data);
-    
-    return success;
-}

Added: libgpod/trunk/src/itdb_sysinfo_extended_parser.c
===================================================================
--- libgpod/trunk/src/itdb_sysinfo_extended_parser.c                            
(rev 0)
+++ libgpod/trunk/src/itdb_sysinfo_extended_parser.c    2008-05-25 10:38:09 UTC 
(rev 1980)
@@ -0,0 +1,486 @@
+/*
+|  Copyright (C) 2008 Christophe Fergeau <[EMAIL PROTECTED]>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  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!
+|
+|  $Id$
+*/
+
+/*
+ * The code in this file is used to convert the output of the plist parser
+ * (a GValue *) and to convert it to data structures usable by libgpod.
+ * This is that code which interprets the generic parsed plist data as a
+ * SysInfoExtended file. The SysInfoExtended data is used to fill a
+ * SysInfoIpodProperties structure and several SysInfoImageFormat structs.
+ *
+ * I tried to make the filling of the structures quite generic, if some
+ * field isn't parsed (which is quite possible since I gathered the various
+ * fields names using a few sample files), all is needed to add it is to
+ * add a field to the appropriate structure (SysInfoIpodProperties or
+ * SysInfoImageFormat) and to add that field to the appropriate
+ * _fields_mapping structure. Those _fields_mapping structures are then
+ * used to convert from a GValue to the struct, but they are also used by
+ * the _dump and _free functions, so there's no need to modify them when
+ * you add a new field.
+ *
+ * If DEBUG_PARSING is defined when building that file, the fields that
+ * were found in the SysInfoExtended file but which were not used to build
+ * the data structures defined in that file will be dumped to stdout. It's
+ * normal to get a few unhandled fields, I left out on purpose a few <dict> 
+ * because I was too lazy to parse them ;)
+ */
+#include <glib-object.h>
+#include "itdb_sysinfo_extended_parser.h"
+#include "itdb_plist.h"
+
+struct _SysInfoIpodProperties {
+        char *build_id;
+        char *connected_bus;
+        gint max_transfer_speed;
+        gint family_id;
+        char *product_type;
+        char *firewire_guid;
+        char *firewire_version;
+        GList *artwork_formats;
+        GList *photo_formats;
+        GList *chapter_image_formats;
+        gboolean podcasts_supported;
+        char *min_itunes_version;
+        gboolean playlist_folders_supported;
+        char *serial_number;
+        gint updater_family_id;
+        char *visible_build_id;
+        gint oem_id;
+        gint oem_u;
+        gint db_version;
+        char *min_build_id;
+        char *language;
+        gboolean voice_memos_supported;
+        gint update_method;
+        gint max_fw_blocks;
+        gint fw_part_size;
+        gboolean auto_reboot_after_firmware_update;
+        char *volume_format;
+        gboolean forced_disk_mode;
+        gboolean bang_folder;
+        gboolean corrupt_data_partition;
+        gboolean corrupt_firmware_partition;
+        gboolean can_flash_backlight;
+        gboolean can_hibernate;
+        gboolean came_with_cd;
+        gboolean supports_sparse_artwork;
+        gint max_thumb_file_size;
+        gint ram;
+        gint hotplug_state;
+        gint battery_poll_interval;
+        gboolean sort_fields_supported;
+        gboolean vcard_with_jpeg_supported;
+        gint max_file_size_in_gb;
+        gint max_tracks;
+        gint games_platform_id;
+        gint games_platform_version;
+        gint rental_clock_bias;
+};
+
+struct _SysInfoImageFormat {
+        gint format_id;
+        gint display_width;
+        gint render_width;
+        gint render_height;
+        char *pixel_format;
+        gboolean interlaced;
+        gboolean crop;
+        gboolean align_row_bytes;
+        gint rotation;
+        char *back_color;
+        gint color_adjustment;
+        gdouble gamma;
+        gint associated_format;
+};
+typedef struct _SysInfoImageFormat SysInfoImageFormat;
+
+static gint get_int (GHashTable *dict, const char *key)
+{
+        GValue *val;
+
+        val = g_hash_table_lookup (dict, key);
+        if (val == NULL) {
+                return 0;
+        }
+        if (!G_VALUE_HOLDS_INT (val)) {
+                return 0;
+        }
+        return g_value_get_int (val);
+}
+
+static gdouble get_double (GHashTable *dict, const char *key)
+{
+        GValue *val;
+
+        val = g_hash_table_lookup (dict, key);
+        if (val == NULL) {
+                return 0;
+        }
+        if (!G_VALUE_HOLDS_DOUBLE (val)) {
+                return 0;
+        }
+        return g_value_get_double (val);
+}
+
+static gboolean get_boolean (GHashTable *dict, const char *key)
+{
+        GValue *val;
+
+        val = g_hash_table_lookup (dict, key);
+        if (val == NULL) {
+                return FALSE;
+        }
+        if (!G_VALUE_HOLDS_BOOLEAN (val)) {
+                return FALSE;
+        }
+        return g_value_get_boolean (val);
+}
+
+static char *get_string (GHashTable *dict, const char *key)
+{
+        GValue *val;
+
+        val = g_hash_table_lookup (dict, key);
+        if (val == NULL) {
+                return NULL;
+        }
+        if (!G_VALUE_HOLDS_STRING (val)) {
+                return NULL;
+        }
+        return g_value_dup_string (val);
+}
+
+struct _DictFieldMapping {
+    const char* name;
+    GType type;
+    guint offset;
+};
+
+typedef struct _DictFieldMapping DictFieldMapping;
+static const DictFieldMapping sysinfo_ipod_properties_fields_mapping[] = {
+    { "BuildID",                       G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, build_id) },
+    { "ConnectedBus",                  G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties,  connected_bus) },
+    { "MaxTransferSpeed",              G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, max_transfer_speed) },
+    { "FamilyID",                      G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, family_id) },
+    { "ProductType",                   G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, product_type) },
+    { "FireWireGUID",                  G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, firewire_guid) },
+    { "FireWireVersion",               G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, firewire_version) },
+    { "PodcastsSupported",             G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, podcasts_supported) },
+    { "MinITunesVersion",              G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, min_itunes_version) },
+    { "PlaylistFoldersSupported",      G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, playlist_folders_supported) },
+    { "SerialNumber",                  G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, serial_number) },
+    { "UpdaterFamilyID",               G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, updater_family_id) },
+    { "VisibleBuildID",                G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, visible_build_id) },
+    { "OEMID",                         G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, oem_id) },
+    { "OEMU",                          G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, oem_u) },
+    { "DBVersion",                     G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, db_version) },
+    { "MinBuildID",                    G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, min_build_id) },
+    { "Language",                      G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, language) },
+    { "VoiceMemosSupported",           G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, voice_memos_supported) },
+    { "UpdateMethod",                  G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, update_method) },
+    { "MaxFWBlocks",                   G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, max_fw_blocks) },
+    { "FWPartSize",                    G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, fw_part_size) },
+    { "AutoRebootAfterFirmwareUpdate", G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, auto_reboot_after_firmware_update) },
+    { "VolumeFormat",                  G_TYPE_STRING,  G_STRUCT_OFFSET 
(SysInfoIpodProperties, volume_format) },
+    { "ForcedDiskMode",                G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, forced_disk_mode) },
+    { "BangFolder",                    G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, bang_folder) },
+    { "CorruptDataPartition",          G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, corrupt_data_partition) },
+    { "CorruptFirmwarePartition",      G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, corrupt_firmware_partition) },
+    { "CanFlashBacklight",             G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, can_flash_backlight) },
+    { "CanHibernate",                  G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, can_hibernate) },
+    { "CameWithCD",                    G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, came_with_cd) },
+    { "SupportsSparseArtwork",         G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, supports_sparse_artwork) },
+    { "MaxThumbFileSize",              G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, max_thumb_file_size) },
+    { "RAM",                           G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, ram) },
+    { "HotPlugState",                  G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, hotplug_state) },
+    { "BatteryPollInterval",           G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, battery_poll_interval) },
+    { "SortFieldsSupported",           G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, sort_fields_supported) },
+    { "vCardWithJPEGSupported",        G_TYPE_BOOLEAN, G_STRUCT_OFFSET 
(SysInfoIpodProperties, vcard_with_jpeg_supported) },
+    { "MaxFileSizeInGB",               G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, max_file_size_in_gb) },
+    { "MaxTracks",                     G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, max_tracks) },
+    { "GamesPlatformID",               G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, games_platform_id) },
+    { "GamesPlatformVersion",          G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, games_platform_version) },
+    { "RentalClockBias",               G_TYPE_INT,     G_STRUCT_OFFSET 
(SysInfoIpodProperties, rental_clock_bias) },
+    { NULL,                            G_TYPE_NONE,    0 }
+};
+
+static const DictFieldMapping sysinfo_image_format_fields_mapping[] = {
+    { "FormatId",         G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
format_id) },
+    { "DisplayWidth",     G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
display_width) },
+    { "RenderWidth",      G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
render_width) },
+    { "RenderHeight",     G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
render_height) },
+    { "PixelFormat",      G_TYPE_STRING,  G_STRUCT_OFFSET (SysInfoImageFormat, 
pixel_format) },
+    { "Interlaced",       G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, 
interlaced) },
+    { "Crop",             G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, 
crop) },
+    { "AlignRowBytes",    G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, 
align_row_bytes) },
+    { "Rotation",         G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
rotation) },
+    { "BackColor",        G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
back_color) },
+    { "ColorAdjustment",  G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
color_adjustment) },
+    { "GammaAdjustment",  G_TYPE_DOUBLE,  G_STRUCT_OFFSET (SysInfoImageFormat, 
gamma) },
+    { "AssociatedFormat", G_TYPE_INT,     G_STRUCT_OFFSET (SysInfoImageFormat, 
associated_format) },
+    { NULL,               G_TYPE_NONE,    0 }
+};
+
+#ifdef DEBUG_PARSING
+static void dump_key_name (gpointer key, gpointer val, gpointer data)
+{
+    g_print ("%s ", (char *)key);
+}
+#endif
+
+static void dict_to_struct (GHashTable *dict, 
+                            const DictFieldMapping *mapping, 
+                            void *struct_ptr)
+{
+    const DictFieldMapping *it = mapping;
+    g_return_if_fail (it != NULL);
+    while (it->name != NULL) {
+        switch (it->type) {
+            case G_TYPE_INT: {
+                gint *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                *field = get_int (dict, it->name);
+                break;
+            }
+                
+            case G_TYPE_BOOLEAN: {
+                gboolean *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                *field = get_boolean (dict, it->name);
+                break;
+            }
+
+            case G_TYPE_STRING: {
+                gchar **field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                *field = get_string (dict, it->name);
+                break;
+            }
+
+            case G_TYPE_DOUBLE: {
+                gdouble *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                *field = get_double (dict, it->name);
+                break;
+            }
+        }
+        g_hash_table_remove (dict, it->name);
+        ++it;
+    }
+#ifdef DEBUG_PARSING
+    if (g_hash_table_size (dict) != 0) {
+        g_print ("Unused keys:\n");
+        g_hash_table_foreach (dict, dump_key_name, NULL);
+        g_print ("\n");
+    }
+#endif
+}
+
+static void free_struct (const DictFieldMapping *mapping, 
+                         void *struct_ptr)
+{
+    const DictFieldMapping *it = mapping;
+    while (it->name != NULL) {
+        if (it->type == G_TYPE_STRING) {
+                gchar **field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                g_free (*field);
+        }
+        ++it;
+    }
+    g_free (struct_ptr);
+}
+
+static void free_image_format (SysInfoImageFormat *format)
+{
+    free_struct (sysinfo_image_format_fields_mapping, format);
+}
+
+void itdb_sysinfo_properties_free (SysInfoIpodProperties *props)
+{
+    g_list_foreach (props->artwork_formats, (GFunc)free_image_format, NULL);
+    g_list_free (props->artwork_formats);
+    g_list_foreach (props->photo_formats, (GFunc)free_image_format, NULL);
+    g_list_free (props->photo_formats);
+    g_list_foreach (props->chapter_image_formats, (GFunc)free_image_format, 
NULL);
+    g_list_free (props->chapter_image_formats);
+    free_struct (sysinfo_ipod_properties_fields_mapping, props);
+}
+
+static void dump_struct (const DictFieldMapping *mapping, 
+                         void *struct_ptr)
+{
+    const DictFieldMapping *it = mapping;
+    g_return_if_fail (it != NULL);
+    while (it->name != NULL) {
+        switch (it->type) {
+            case G_TYPE_INT: {
+                gint *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                g_print ("%s: %d\n", it->name, *field);
+                break;
+            }
+                
+            case G_TYPE_BOOLEAN: {
+                gboolean *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                g_print ("%s: %s\n", it->name, (*field)?"true":"false");
+                break;
+            }
+
+            case G_TYPE_STRING: {
+                gchar **field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                g_print ("%s: %s\n", it->name, *field);
+                break;
+            }
+
+            case G_TYPE_DOUBLE: {
+                gdouble *field;
+                field = G_STRUCT_MEMBER_P (struct_ptr, it->offset);
+                g_print ("%s: %f\n", it->name, *field);
+                break;
+            }
+        }
+        ++it;
+    }
+}
+
+static void dump_image_format (SysInfoImageFormat *format)
+{
+    dump_struct (sysinfo_image_format_fields_mapping, format);
+}
+
+void itdb_sysinfo_properties_dump (SysInfoIpodProperties *props)
+{
+    dump_struct (sysinfo_ipod_properties_fields_mapping, props);
+    g_list_foreach (props->artwork_formats, (GFunc)dump_image_format, NULL);
+    g_list_foreach (props->photo_formats, (GFunc)dump_image_format, NULL);
+    g_list_foreach (props->chapter_image_formats, (GFunc)dump_image_format, 
NULL);
+}
+
+static SysInfoImageFormat *g_value_to_image_format (GValue *value)
+{
+    GHashTable *dict;
+    SysInfoImageFormat *img_spec;
+
+    g_return_val_if_fail (G_VALUE_HOLDS (value, G_TYPE_HASH_TABLE), NULL);
+    dict = g_value_get_boxed (value);
+    g_return_val_if_fail (dict != NULL, NULL);
+   
+    img_spec = g_new0 (SysInfoImageFormat, 1);
+    if (img_spec == NULL) {
+        return NULL;             
+    }
+    
+    dict_to_struct (dict, sysinfo_image_format_fields_mapping, img_spec);
+
+    return img_spec;
+}
+
+static void process_one (gpointer key, gpointer value, gpointer user_data)
+{
+    GList **img_formats = user_data;
+    SysInfoImageFormat *format;
+
+    format = g_value_to_image_format (value);
+    if (format != NULL) {
+        *img_formats = g_list_prepend (*img_formats, format);
+    }
+}
+static GList *parse_one_formats_list (GHashTable *sysinfo_dict, 
+                                      const char *key)
+{
+    GValue *to_parse;
+    GList *formats = NULL;
+
+    to_parse = g_hash_table_lookup (sysinfo_dict, key);
+    if (to_parse == NULL) {
+        return NULL;
+    }
+    if (!G_VALUE_HOLDS (to_parse, G_TYPE_HASH_TABLE)) {
+        return NULL;
+    }
+    g_hash_table_foreach (g_value_get_boxed (to_parse), process_one, &formats);
+    g_hash_table_remove (sysinfo_dict, key);
+    return formats;
+}
+
+static SysInfoIpodProperties *g_value_to_ipod_properties (GValue *value)
+{
+    GHashTable *sysinfo_dict;
+    SysInfoIpodProperties *props;
+
+    g_return_val_if_fail (G_VALUE_HOLDS (value, G_TYPE_HASH_TABLE), NULL);
+    sysinfo_dict = g_value_get_boxed (value);
+ 
+    props = g_new0 (SysInfoIpodProperties, 1);
+    props->artwork_formats = parse_one_formats_list (sysinfo_dict, 
+                                                     "AlbumArt");
+    props->photo_formats = parse_one_formats_list (sysinfo_dict, 
+                                                   "ImageSpecifications");
+    props->chapter_image_formats = parse_one_formats_list (sysinfo_dict, 
+                                                           
"ChapterImageSpecs");
+    dict_to_struct (sysinfo_dict, 
+                    sysinfo_ipod_properties_fields_mapping, 
+                    props);
+
+    return props;
+}
+
+SysInfoIpodProperties *itdb_sysinfo_extended_parse (const char *filename)
+{
+    GValue *parsed_doc;
+    SysInfoIpodProperties *props;
+
+    g_return_val_if_fail (filename != NULL, NULL);
+
+    parsed_doc = itdb_plist_parse_from_file (filename);
+    if (parsed_doc == NULL) {
+        return NULL;
+    }
+    props = g_value_to_ipod_properties (parsed_doc);
+    g_value_unset (parsed_doc);
+    g_free (parsed_doc);
+
+    return props;
+}
+
+const char *
+itdb_sysinfo_properties_get_serial_number (const SysInfoIpodProperties *props)
+{
+    g_return_val_if_fail (props != NULL, NULL);
+    return props->serial_number;
+}
+
+const char *
+itdb_sysinfo_properties_get_firewire_id (const SysInfoIpodProperties *props)
+{
+    g_return_val_if_fail (props != NULL, NULL);
+    return props->firewire_guid;
+}

Added: libgpod/trunk/src/itdb_sysinfo_extended_parser.h
===================================================================
--- libgpod/trunk/src/itdb_sysinfo_extended_parser.h                            
(rev 0)
+++ libgpod/trunk/src/itdb_sysinfo_extended_parser.h    2008-05-25 10:38:09 UTC 
(rev 1980)
@@ -0,0 +1,49 @@
+/*
+|  Copyright (C) 2008 Christophe Fergeau <[EMAIL PROTECTED]>
+|  Part of the gtkpod project.
+| 
+|  URL: http://www.gtkpod.org/
+|  URL: http://gtkpod.sourceforge.net/
+|
+|  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!
+|
+|  $Id$
+*/
+#ifndef __ITDB_SYSINFO_EXTENDED_PARSER_H__
+#define __ITDB_SYSINFO_EXTENDED_PARSER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SysInfoIpodProperties SysInfoIpodProperties;
+
+void itdb_sysinfo_properties_dump (SysInfoIpodProperties *props);
+SysInfoIpodProperties *itdb_sysinfo_extended_parse (const char *filename);
+void itdb_sysinfo_properties_free (SysInfoIpodProperties *props);
+
+const char *
+itdb_sysinfo_properties_get_serial_number (const SysInfoIpodProperties *props);
+
+const char *
+itdb_sysinfo_properties_get_firewire_id (const SysInfoIpodProperties *props);
+
+G_END_DECLS
+
+#endif

Modified: libgpod/trunk/tests/Makefile.am
===================================================================
--- libgpod/trunk/tests/Makefile.am     2008-05-25 09:07:13 UTC (rev 1979)
+++ libgpod/trunk/tests/Makefile.am     2008-05-25 10:38:09 UTC (rev 1980)
@@ -37,9 +37,12 @@
 
 test_firewire_id_SOURCES = test-fw-id.c
 
+test_sysinfo_extended_parsing_SOURCES = test-sysinfo-extended-parsing.c
+
 get_timezone_SOURCES = get-timezone.c
 
 noinst_PROGRAMS=test-itdb test-ls test-checksum test-firewire-id \
+               test-sysinfo-extended-parsing                    \
                $(TESTTHUMBS) $(TESTTAGLIB) $(TESTMISC)
 
 INCLUDES=$(LIBGPOD_CFLAGS) -I$(top_srcdir)/src 
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"

Added: libgpod/trunk/tests/test-sysinfo-extended-parsing.c
===================================================================
--- libgpod/trunk/tests/test-sysinfo-extended-parsing.c                         
(rev 0)
+++ libgpod/trunk/tests/test-sysinfo-extended-parsing.c 2008-05-25 10:38:09 UTC 
(rev 1980)
@@ -0,0 +1,24 @@
+#include "itdb_sysinfo_extended_parser.h"
+
+#include <glib.h>
+#include <glib-object.h>
+
+int main (int argc, char **argv)
+{
+    SysInfoIpodProperties *props;
+
+    if (argc != 2)
+        return(1);
+
+    g_type_init ();
+    props = itdb_sysinfo_extended_parse (argv[1]);
+    if (props == NULL) {
+        g_print ("Couldn't parse %s\n", argv[1]);
+    }
+    itdb_sysinfo_properties_dump (props);
+    itdb_sysinfo_properties_free (props);
+    props = NULL;
+
+    return 0;
+}
+


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2

Reply via email to