summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorteuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2008-10-07 18:56:51 +0000
committerteuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2008-10-07 18:56:51 +0000
commitd15ac949b5c12e39a0acaaa3bba917aa2866e975 (patch)
tree6faa4e8065b4dcb199853ad16d657f521ebceb22
parent3be68dfa4dd725e3364bc3aa98f2590205a6e80f (diff)
downloadlibgpod-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--ChangeLog6
-rw-r--r--src/itdb_plist.c90
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 <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)
{