From d15ac949b5c12e39a0acaaa3bba917aa2866e975 Mon Sep 17 00:00:00 2001 From: teuf Date: Tue, 7 Oct 2008 18:56:51 +0000 Subject: Add array support to the plist parser The SysInfoExtended file on the ipod used to contain the artwork formats in tags containing tags as well as the value. This is not valid according to the plist DTD, and this was fixed with the 4th generation Nanos (but not with the 120GB ipod classic). libgpod was written using invalid (wrt to the XML DTD) files, and thus handled elements as if they were elements (because of the tags). This was wrong, and prevented it from parsing the fixed SysInfoExtended file on the new Nanos. This changeset implements support for tags (ignoring tags like in the process so as not to fail with older SysInfoExtended files) git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@2135 f01d2545-417e-4e96-918e-98f8d0dbbcb6 --- ChangeLog | 6 ++++ src/itdb_plist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index f36c01b..e0fb880 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-10-07 Christophe Fergeau + + * src/itdb_plist.c: add support for tags to the plist + parser, this is needed to support SysInfoExtended files as found on + on the 4g nanos + 2008-10-05 Christophe Fergeau * src/itdb_device.c: add serial number for the 8GB Silver Nano 4g diff --git a/src/itdb_plist.c b/src/itdb_plist.c index f6f1dfd..a0ea8f4 100644 --- a/src/itdb_plist.c +++ b/src/itdb_plist.c @@ -32,8 +32,6 @@ * * This parser should handle most plist files, with those limitations : * - no support for tags - * - no support for containing "unamed" elements (ie with no - * tag) * * The plist file is parsed using libxml, and the parsed result is stored * in GValue. The types are mapped in the following way: @@ -42,7 +40,7 @@ * - => G_TYPE_INT (gint) * - , => G_TYPE_BOOLEAN (gboolean) * - => G_TYPE_GSTRING (GString *) - * - => G_TYPE_HASH_TABLE (GHashTable *) + * - => G_TYPE_VALUE_ARRAY (GValueArray *) * - => G_TYPE_HASH_TABLE (GHashTable *) */ #ifdef HAVE_CONFIG_H @@ -248,6 +246,7 @@ parse_dict (xmlNode *a_node, GError **error) cur_node = parse_one_dict_entry (cur_node, dict, error); } if ((error != NULL) && (*error != NULL)) { + g_hash_table_destroy (dict); return NULL; } value = g_new0 (GValue, 1); @@ -256,39 +255,92 @@ parse_dict (xmlNode *a_node, GError **error) return value; } - + typedef GValue *(*ParseCallback) (xmlNode *, GError **); +static ParseCallback get_parser_for_type (const xmlChar *type); + +static GValue * +parse_array (xmlNode *a_node, GError **error) +{ + xmlNode *cur_node = a_node->children; + GValue *value; + GValueArray *array; + + array = g_value_array_new (4); + + while (cur_node != NULL) { + if (get_parser_for_type (cur_node->name) != NULL) { + GValue *cur_value; + cur_value = parse_node (cur_node, error); + if (cur_value != NULL) { + array = g_value_array_append (array, cur_value); + g_value_unset (cur_value); + g_free (cur_value); + } + } + /* When an array contains an element enclosed in "unknown" tags (ie + * non-type ones), we silently skip them since early + * SysInfoExtended files used to have values enclosed within + * tags. + */ + cur_node = cur_node->next; + } + + if ((error != NULL) && (*error != NULL)) { + g_value_array_free (array); + return NULL; + } + value = g_new0 (GValue, 1); + value = g_value_init (value, G_TYPE_VALUE_ARRAY); + g_value_take_boxed (value, array); + + return value; +} + 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, GError **error) +static const 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_array}, + {NULL, NULL} }; + +static ParseCallback get_parser_for_type (const xmlChar *type) { 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 (xmlStrcmp (type, (xmlChar *)parsers[i].type_name) == 0) { if (parsers[i].parser != NULL) { - return parsers[i].parser (a_node, error); + return parsers[i].parser; } } i++; } - DEBUG ("no parser for <%s>\n", a_node->name); return NULL; } +static GValue *parse_node (xmlNode *a_node, GError **error) +{ + ParseCallback parser; + + g_return_val_if_fail (a_node != NULL, NULL); + parser = get_parser_for_type (a_node->name); + if (parser != NULL) { + return parser (a_node, error); + } else { + DEBUG ("no parser for <%s>\n", a_node->name); + return NULL; + } +} + static GValue * itdb_plist_parse (xmlNode * a_node, GError **error) { -- cgit