diff options
author | teuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2008-10-07 18:56:51 +0000 |
---|---|---|
committer | teuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2008-10-07 18:56:51 +0000 |
commit | d15ac949b5c12e39a0acaaa3bba917aa2866e975 (patch) | |
tree | 6faa4e8065b4dcb199853ad16d657f521ebceb22 | |
parent | 3be68dfa4dd725e3364bc3aa98f2590205a6e80f (diff) | |
download | libgpod-d15ac949b5c12e39a0acaaa3bba917aa2866e975.tar.gz libgpod-d15ac949b5c12e39a0acaaa3bba917aa2866e975.tar.xz libgpod-d15ac949b5c12e39a0acaaa3bba917aa2866e975.zip |
Add array support to the plist parser
The SysInfoExtended file on the ipod used to contain the artwork formats in
<array> tags containing <key> 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
<array> elements as if they were <dict> elements (because of the <key> tags).
This was wrong, and prevented it from parsing the fixed SysInfoExtended file
on the new Nanos. This changeset implements support for <array> tags (ignoring
tags like <key> 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
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | src/itdb_plist.c | 90 |
2 files changed, 77 insertions, 19 deletions
@@ -1,3 +1,9 @@ +2008-10-07 Christophe Fergeau <teuf@gnome.org> + + * src/itdb_plist.c: add support for <array> tags to the plist + parser, this is needed to support SysInfoExtended files as found on + on the 4g nanos + 2008-10-05 Christophe Fergeau <teuf@gnome.org> * 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 <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: @@ -42,7 +40,7 @@ * - <integer> => G_TYPE_INT (gint) * - <true/>, <false/> => G_TYPE_BOOLEAN (gboolean) * - <data> => G_TYPE_GSTRING (GString *) - * - <array> => G_TYPE_HASH_TABLE (GHashTable *) + * - <array> => G_TYPE_VALUE_ARRAY (GValueArray *) * - <dict> => 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 <key> values enclosed within + * <array> 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) { |