From e36402aead91c157dbefd577cdf463759c2aa045 Mon Sep 17 00:00:00 2001 From: teuf Date: Sun, 25 May 2008 10:38:09 +0000 Subject: * 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 git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1980 f01d2545-417e-4e96-918e-98f8d0dbbcb6 --- ChangeLog | 20 ++ configure.ac | 11 + src/Makefile.am | 9 +- src/itdb_device.c | 30 ++- src/itdb_device.h | 5 +- src/itdb_plist.c | 326 +++++++++++++++++++++++ src/itdb_plist.h | 42 +++ src/itdb_sysinfo.c | 269 ------------------- src/itdb_sysinfo_extended_parser.c | 486 ++++++++++++++++++++++++++++++++++ src/itdb_sysinfo_extended_parser.h | 49 ++++ tests/Makefile.am | 3 + tests/test-sysinfo-extended-parsing.c | 24 ++ 12 files changed, 999 insertions(+), 275 deletions(-) create mode 100644 src/itdb_plist.c create mode 100644 src/itdb_plist.h delete mode 100644 src/itdb_sysinfo.c create mode 100644 src/itdb_sysinfo_extended_parser.c create mode 100644 src/itdb_sysinfo_extended_parser.h create mode 100644 tests/test-sysinfo-extended-parsing.c diff --git a/ChangeLog b/ChangeLog index d74482e..71ae1ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2008-05-25 Christophe Fergeau + + * 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 Patch from Ian Stewart diff --git a/configure.ac b/configure.ac index 9eee413..e1d7171 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,17 @@ AC_SUBST(TAGLIB_CFLAGS) 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 diff --git a/src/Makefile.am b/src/Makefile.am index 5c606f2..f5b65a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,8 +12,9 @@ libgpod_la_SOURCES = \ 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 @@ noinst_HEADERS = \ 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) diff --git a/src/itdb_device.c b/src/itdb_device.c index 3b5e7e3..4f3fe50 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -387,6 +387,8 @@ void itdb_device_free (Itdb_Device *device) 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,6 +430,32 @@ G_GNUC_INTERNAL guint64 device_time_time_t_to_mac (Itdb_Device *device, time_t t 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: @@ -490,7 +518,7 @@ gboolean itdb_device_read_sysinfo (Itdb_Device *device) } 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; diff --git a/src/itdb_device.h b/src/itdb_device.h index c21be94..0f4a8a7 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -40,6 +40,7 @@ #endif #include "itdb.h" +#include "itdb_sysinfo_extended_parser.h" #include @@ -85,6 +86,8 @@ struct _Itdb_Device */ 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 @@ struct _Itdb_ArtworkFormat 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 diff --git a/src/itdb_plist.c b/src/itdb_plist.c new file mode 100644 index 0000000..bb6d89d --- /dev/null +++ b/src/itdb_plist.c @@ -0,0 +1,326 @@ +/* +| Copyright (C) 2008 Christophe Fergeau +| 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 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: + * - => G_TYPE_STRING (char*) + * - => G_TYPE_DOUBLE (double) + * - => G_TYPE_INT (gint) + * - , => G_TYPE_BOOLEAN (gboolean) + * - => G_TYPE_GSTRING (GString *) + * - => G_TYPE_HASH_TABLE (GHashTable *) + * - => G_TYPE_HASH_TABLE (GHashTable *) + */ +#include +#include +#include +#include +#include +#include + +#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 (" %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; +} diff --git a/src/itdb_plist.h b/src/itdb_plist.h new file mode 100644 index 0000000..50b5618 --- /dev/null +++ b/src/itdb_plist.h @@ -0,0 +1,42 @@ +/* +| Copyright (C) 2008 Christophe Fergeau +| 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 + +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 diff --git a/src/itdb_sysinfo.c b/src/itdb_sysinfo.c deleted file mode 100644 index 45a4057..0000000 --- a/src/itdb_sysinfo.c +++ /dev/null @@ -1,269 +0,0 @@ -/* -| Copyright (C) 2002-2007 Jorg Schuler -| 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 - -#include - -#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; -} diff --git a/src/itdb_sysinfo_extended_parser.c b/src/itdb_sysinfo_extended_parser.c new file mode 100644 index 0000000..84af19d --- /dev/null +++ b/src/itdb_sysinfo_extended_parser.c @@ -0,0 +1,486 @@ +/* +| Copyright (C) 2008 Christophe Fergeau +| 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 + * because I was too lazy to parse them ;) + */ +#include +#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; +} diff --git a/src/itdb_sysinfo_extended_parser.h b/src/itdb_sysinfo_extended_parser.h new file mode 100644 index 0000000..df067f5 --- /dev/null +++ b/src/itdb_sysinfo_extended_parser.h @@ -0,0 +1,49 @@ +/* +| Copyright (C) 2008 Christophe Fergeau +| 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 + +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 diff --git a/tests/Makefile.am b/tests/Makefile.am index 17c9cb7..f9e003b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,9 +37,12 @@ test_checksum_SOURCES = test-checksum.c 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"\" diff --git a/tests/test-sysinfo-extended-parsing.c b/tests/test-sysinfo-extended-parsing.c new file mode 100644 index 0000000..86731d1 --- /dev/null +++ b/tests/test-sysinfo-extended-parsing.c @@ -0,0 +1,24 @@ +#include "itdb_sysinfo_extended_parser.h" + +#include +#include + +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; +} + -- cgit