From 390c14aec2ea65b16d13820846b4503adc6d290d Mon Sep 17 00:00:00 2001 From: Mike Alexander Date: Tue, 19 Nov 2013 03:47:07 +0000 Subject: [PATCH] Decompress zipped XML files ourself instead of letting libxml2 do it. As of version 2.9.1 it has a bug that causes it to fail to decompress certain files. See https://bugzilla.gnome.org/show_bug.cgi?id=712528 for more info. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@23412 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/backend/xml/io-gncxml-gen.c | 16 +++++++++++++ src/backend/xml/io-gncxml-gen.h | 5 +++++ src/backend/xml/io-gncxml-v2.c | 40 +++++++++++++++++++++++++++++++-- src/backend/xml/sixtp.c | 29 ++++++++++++++++++++++++ src/backend/xml/sixtp.h | 3 +++ 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/backend/xml/io-gncxml-gen.c b/src/backend/xml/io-gncxml-gen.c index 7043db0f3b..0ca1ccd925 100644 --- a/src/backend/xml/io-gncxml-gen.c +++ b/src/backend/xml/io-gncxml-gen.c @@ -41,3 +41,19 @@ gnc_xml_parse_file(sixtp *top_parser, const char *filename, return sixtp_parse_file(top_parser, filename, NULL, &gpdata, &parse_result); } + +gboolean +gnc_xml_parse_fd(sixtp *top_parser, FILE *fd, + gxpf_callback callback, gpointer parsedata, + gpointer bookdata) +{ + gpointer parse_result = NULL; + gxpf_data gpdata; + + gpdata.cb = callback; + gpdata.parsedata = parsedata; + gpdata.bookdata = bookdata; + + return sixtp_parse_fd(top_parser, fd, + NULL, &gpdata, &parse_result); +} diff --git a/src/backend/xml/io-gncxml-gen.h b/src/backend/xml/io-gncxml-gen.h index 3063d5ac05..adfdd8f15f 100644 --- a/src/backend/xml/io-gncxml-gen.h +++ b/src/backend/xml/io-gncxml-gen.h @@ -45,4 +45,9 @@ gnc_xml_parse_file(sixtp *top_parser, const char *filename, gxpf_callback callback, gpointer parsedata, gpointer bookdata); +gboolean +gnc_xml_parse_fd(sixtp *top_parser, FILE *fd, + gxpf_callback callback, gpointer parsedata, + gpointer bookdata); + #endif /* IO_GNCXML_GEN_H */ diff --git a/src/backend/xml/io-gncxml-v2.c b/src/backend/xml/io-gncxml-v2.c index cc02d95560..1058c313d4 100644 --- a/src/backend/xml/io-gncxml-v2.c +++ b/src/backend/xml/io-gncxml-v2.c @@ -99,6 +99,12 @@ struct file_backend const gchar *gnc_v2_xml_version_string = GNC_V2_STRING; extern const gchar *gnc_v2_book_version_string; /* see gnc-book-xml-v2 */ +/* Forward declarations */ +static FILE *try_gz_open (const char *filename, const char *perms, gboolean use_gzip, + gboolean compress); +static gboolean is_gzipped_file(const gchar *name); +static gboolean wait_for_gzip(FILE *file); + void run_callback(sixtp_gdv2 *data, const char *type) { @@ -774,8 +780,38 @@ qof_session_load_from_xml_file_v2_full( } else { - retval = gnc_xml_parse_file(top_parser, fbe->fullpath, - generic_callback, gd, book); + /* Even though libxml2 knows how to decompress zipped files, we do it + ourself since as of version 2.9.1 it has a bug that causes it to fail + to decompress certain files. + See https://bugzilla.gnome.org/show_bug.cgi?id=712528 for more info */ + gchar *filename = fbe->fullpath; +#ifdef G_OS_WIN32 + filename = g_win32_locale_filename_from_utf8(fbe->fulpath); + if (filename) + { +#endif + FILE *file; + gboolean is_compressed = is_gzipped_file(filename); + file = try_gz_open(filename, "r", is_compressed, FALSE); + if (file == NULL) + { + PWARN("Unable to open file %s", filename); + retval = FALSE; + } + else + { + retval = gnc_xml_parse_fd(top_parser, file, + generic_callback, gd, book); + fclose(file); + if (is_compressed) + wait_for_gzip(file); + } +#ifdef G_OS_WIN32 + g_free(filename); + else + retval = FALSE; + } +#endif } if (!retval) diff --git a/src/backend/xml/sixtp.c b/src/backend/xml/sixtp.c index 5c4e31de09..0377274699 100644 --- a/src/backend/xml/sixtp.c +++ b/src/backend/xml/sixtp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef _MSC_VER typedef int ssize_t; @@ -759,6 +760,34 @@ sixtp_parse_file(sixtp *sixtp, return ret; } +/* Call back function for libxml2 to read from compressed or uncompressed stream */ +static int +sixtp_parser_read(void *context, char *buffer, int len) +{ + int ret; + + ret = fread(&buffer[0], sizeof(char), len, (FILE *) context); + if (ret < 0) + g_warning("Error reading XML file"); + return ret; +} + +gboolean +sixtp_parse_fd(sixtp *sixtp, + FILE *fd, + gpointer data_for_top_level, + gpointer global_data, + gpointer *parse_result) +{ + gboolean ret; + xmlParserCtxtPtr context = xmlCreateIOParserCtxt( NULL, NULL, + sixtp_parser_read, NULL /*no close */, fd, + XML_CHAR_ENCODING_NONE); + ret = sixtp_parse_file_common(sixtp, context, data_for_top_level, + global_data, parse_result); + return ret; +} + gboolean sixtp_parse_buffer(sixtp *sixtp, char *bufp, diff --git a/src/backend/xml/sixtp.h b/src/backend/xml/sixtp.h index c0f2a116e0..49eb034859 100644 --- a/src/backend/xml/sixtp.h +++ b/src/backend/xml/sixtp.h @@ -185,6 +185,9 @@ xmlEntityPtr sixtp_sax_get_entity_handler(void *user_data, const xmlChar *name); gboolean sixtp_parse_file(sixtp *sixtp, const char *filename, gpointer data_for_top_level, gpointer global_data, gpointer *parse_result); +gboolean sixtp_parse_fd(sixtp *sixtp, FILE *fd, + gpointer data_for_top_level, gpointer global_data, + gpointer *parse_result); gboolean sixtp_parse_buffer(sixtp *sixtp, char *bufp, int bufsz, gpointer data_for_top_level, gpointer global_data, gpointer *parse_result);