From 7c03e237b228032da14b655f79822894b955789b Mon Sep 17 00:00:00 2001 From: "J. Alex Aycinena" Date: Sun, 29 Jan 2012 01:12:30 +0000 Subject: [PATCH] Update xml file backend to recognize a newer version file on load attempt, not load, and alert user of need to upgrade Gnucash. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@21908 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/backend/xml/gnc-backend-xml.c | 37 +++++----- src/backend/xml/gnc-backend-xml.h | 10 +++ src/backend/xml/io-example-account.c | 3 +- src/backend/xml/io-example-account.h | 2 +- src/backend/xml/io-gncxml-v1.c | 4 +- src/backend/xml/io-gncxml-v2.c | 35 ++++++---- src/backend/xml/io-gncxml-v2.h | 4 +- src/backend/xml/sixtp.c | 70 ++++++++++--------- src/backend/xml/sixtp.h | 6 +- src/backend/xml/test/test-date-converting.c | 3 + src/backend/xml/test/test-dom-converters1.c | 3 + src/backend/xml/test/test-kvp-frames.c | 2 + src/backend/xml/test/test-string-converters.c | 3 + src/backend/xml/test/test-xml-account.c | 3 + src/backend/xml/test/test-xml-commodity.c | 3 + src/backend/xml/test/test-xml-pricedb.c | 3 + src/gnome-utils/gnc-file.c | 13 +++- src/libqof/qof/qofbackend.h | 2 + src/libqof/qof/qofsession.c | 1 + 19 files changed, 134 insertions(+), 73 deletions(-) diff --git a/src/backend/xml/gnc-backend-xml.c b/src/backend/xml/gnc-backend-xml.c index 2b8f1f2b3f..69e8f2df01 100644 --- a/src/backend/xml/gnc-backend-xml.c +++ b/src/backend/xml/gnc-backend-xml.c @@ -99,15 +99,6 @@ typedef int ssize_t; static QofLogModule log_module = GNC_MOD_BACKEND; -typedef enum -{ - GNC_BOOK_NOT_OURS, - GNC_BOOK_BIN_FILE, - GNC_BOOK_XML1_FILE, - GNC_BOOK_XML2_FILE, - GNC_BOOK_XML2_FILE_NO_ENCODING, -} QofBookFileType; - static gboolean save_may_clobber_data (QofBackend *bend); /* ================================================================= */ @@ -561,7 +552,10 @@ static QofBookFileType gnc_xml_be_determine_file_type(const char *path) { gboolean with_encoding; - if (gnc_is_xml_data_file_v2(path, &with_encoding)) + QofBookFileType v2type; + + v2type = gnc_is_xml_data_file_v2(path, &with_encoding); + if (v2type == GNC_BOOK_XML2_FILE) { if (with_encoding) { @@ -572,7 +566,11 @@ gnc_xml_be_determine_file_type(const char *path) return GNC_BOOK_XML2_FILE_NO_ENCODING; } } - else if (gnc_is_xml_data_file(path)) + else if (v2type == GNC_BOOK_POST_XML2_0_0_FILE) + { + return GNC_BOOK_POST_XML2_0_0_FILE; + } + else if (v2type == GNC_BOOK_XML1_FILE) { return GNC_BOOK_XML1_FILE; } @@ -586,6 +584,7 @@ gnc_determine_file_type (const char *uri) int rc; FILE *t; gchar *filename; + QofBookFileType xml_type; gboolean result; if (!uri) @@ -619,12 +618,10 @@ gnc_determine_file_type (const char *uri) result = TRUE; goto det_exit; } - if (gnc_is_xml_data_file_v2(filename, NULL)) - { - result = TRUE; - goto det_exit; - } - else if (gnc_is_xml_data_file(filename)) + xml_type = gnc_is_xml_data_file_v2(filename, NULL); + if ((xml_type == GNC_BOOK_XML2_FILE) || + (xml_type == GNC_BOOK_XML1_FILE) || + (xml_type == GNC_BOOK_POST_XML2_0_0_FILE)) { result = TRUE; goto det_exit; @@ -1117,7 +1114,7 @@ gnc_xml_be_load_from_file (QofBackend *bend, QofBook *book, QofBackendLoadType l switch (gnc_xml_be_determine_file_type(be->fullpath)) { case GNC_BOOK_XML2_FILE: - rc = qof_session_load_from_xml_file_v2 (be, book); + rc = qof_session_load_from_xml_file_v2 (be, book, GNC_BOOK_XML2_FILE); if (FALSE == rc) { PWARN( "Syntax error in Xml File %s", be->fullpath ); @@ -1137,6 +1134,10 @@ gnc_xml_be_load_from_file (QofBackend *bend, QofBook *book, QofBackendLoadType l error = ERR_FILEIO_PARSE_ERROR; } break; + case GNC_BOOK_POST_XML2_0_0_FILE: + error = ERR_BACKEND_TOO_NEW; + PWARN( "Version of Xml file %s is newer than what we can read", be->fullpath ); + break; default: /* If file type wasn't known, check errno again to give the user some more useful feedback for some particular error diff --git a/src/backend/xml/gnc-backend-xml.h b/src/backend/xml/gnc-backend-xml.h index 959956a363..4d69c89158 100644 --- a/src/backend/xml/gnc-backend-xml.h +++ b/src/backend/xml/gnc-backend-xml.h @@ -43,6 +43,16 @@ typedef enum XML_RETAIN_ALL } XMLFileRetentionType; +typedef enum +{ + GNC_BOOK_NOT_OURS, + GNC_BOOK_BIN_FILE, + GNC_BOOK_XML1_FILE, + GNC_BOOK_XML2_FILE, + GNC_BOOK_XML2_FILE_NO_ENCODING, + GNC_BOOK_POST_XML2_0_0_FILE +} QofBookFileType; + struct FileBackend_struct { QofBackend be; diff --git a/src/backend/xml/io-example-account.c b/src/backend/xml/io-example-account.c index b734a49d84..f1b2d9a125 100644 --- a/src/backend/xml/io-example-account.c +++ b/src/backend/xml/io-example-account.c @@ -498,8 +498,9 @@ gnc_load_example_account_list(const char *dirname) /***********************************************************************/ +/* gboolean gnc_is_example_account_xml(const gchar *name) { return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL); -} +} */ diff --git a/src/backend/xml/io-example-account.h b/src/backend/xml/io-example-account.h index 41a4349805..914f308655 100644 --- a/src/backend/xml/io-example-account.h +++ b/src/backend/xml/io-example-account.h @@ -53,6 +53,6 @@ GncExampleAccount *gnc_read_example_account(const gchar *filename); void gnc_free_example_account_list(GSList *list); GSList* gnc_load_example_account_list(const char *dirname); -gboolean gnc_is_example_account_xml(const gchar *name); +/* gboolean gnc_is_example_account_xml(const gchar *name); */ #endif /* IO_EXAMPLE_ACCOUNT_H */ diff --git a/src/backend/xml/io-gncxml-v1.c b/src/backend/xml/io-gncxml-v1.c index 4b71b3f67b..6e22f4a26a 100644 --- a/src/backend/xml/io-gncxml-v1.c +++ b/src/backend/xml/io-gncxml-v1.c @@ -412,7 +412,9 @@ qof_session_load_from_xml_file(QofBook *book, const char *filename) gboolean gnc_is_xml_data_file(const gchar *filename) { - return gnc_is_our_xml_file(filename, "gnc", NULL); + if ((gnc_is_our_xml_file(filename, NULL)) == GNC_BOOK_XML1_FILE) + return TRUE; + return FALSE; } /* ================================================================== */ diff --git a/src/backend/xml/io-gncxml-v2.c b/src/backend/xml/io-gncxml-v2.c index 51b829a458..3ea6af8df3 100644 --- a/src/backend/xml/io-gncxml-v2.c +++ b/src/backend/xml/io-gncxml-v2.c @@ -95,6 +95,8 @@ struct file_backend }; #define GNC_V2_STRING "gnc-v2" +/* non-static because they are used in sixtp.c */ +const gchar *gnc_v2_xml_version_string = GNC_V2_STRING; extern const gchar *gnc_v2_book_version_string; /* see gnc-book-xml-v2 */ void @@ -679,7 +681,8 @@ gnc_sixtp_gdv2_new ( static gboolean qof_session_load_from_xml_file_v2_full( FileBackend *fbe, QofBook *book, - sixtp_push_handler push_handler, gpointer push_user_data) + sixtp_push_handler push_handler, gpointer push_user_data, + QofBookFileType type) { Account *root; QofBackend *be = &fbe->be; @@ -689,6 +692,7 @@ qof_session_load_from_xml_file_v2_full( sixtp *book_parser; struct file_backend be_data; gboolean retval; + char *v2type; gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage); @@ -696,14 +700,20 @@ qof_session_load_from_xml_file_v2_full( main_parser = sixtp_new(); book_parser = sixtp_new(); + if (type == GNC_BOOK_XML2_FILE) + v2type = g_strdup(GNC_V2_STRING); + if (!sixtp_add_some_sub_parsers( top_parser, TRUE, - GNC_V2_STRING, main_parser, + v2type, main_parser, NULL, NULL)) { + g_free(v2type); goto bail; } + g_free(v2type); + if (!sixtp_add_some_sub_parsers( main_parser, TRUE, COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(), @@ -819,9 +829,10 @@ bail: } gboolean -qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book) +qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book, + QofBookFileType type) { - return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL); + return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL, type); } /***********************************************************************/ @@ -1620,12 +1631,9 @@ is_gzipped_file(const gchar *name) return FALSE; } -gboolean +QofBookFileType gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding) { - if (gnc_is_our_xml_file(name, GNC_V2_STRING, with_encoding)) - return TRUE; - if (is_gzipped_file(name)) { gzFile *file = NULL; @@ -1647,19 +1655,18 @@ gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding) file = gzopen(name, "r"); #endif if (file == NULL) - return FALSE; + return GNC_BOOK_NOT_OURS; num_read = gzread(file, first_chunk, sizeof(first_chunk) - 1); gzclose(file); if (num_read < 1) - return FALSE; + return GNC_BOOK_NOT_OURS; - return gnc_is_our_first_xml_chunk(first_chunk, GNC_V2_STRING, - with_encoding); + return gnc_is_our_first_xml_chunk(first_chunk, with_encoding); } - return FALSE; + return (gnc_is_our_xml_file(name, with_encoding)); } @@ -2095,7 +2102,7 @@ gnc_xml2_parse_with_subst (FileBackend *fbe, QofBook *book, GHashTable *subst) success = qof_session_load_from_xml_file_v2_full( fbe, book, (sixtp_push_handler) parse_with_subst_push_handler, - push_data); + push_data, GNC_BOOK_XML2_FILE); if (success) qof_book_kvp_changed(book); diff --git a/src/backend/xml/io-gncxml-v2.h b/src/backend/xml/io-gncxml-v2.h index 36d9858240..6fc7145b47 100644 --- a/src/backend/xml/io-gncxml-v2.h +++ b/src/backend/xml/io-gncxml-v2.h @@ -128,7 +128,7 @@ typedef struct void run_callback(sixtp_gdv2 *data, const char *type); /** read in an account group from a file */ -gboolean qof_session_load_from_xml_file_v2(FileBackend *, QofBook *); +gboolean qof_session_load_from_xml_file_v2(FileBackend *, QofBook *, QofBookFileType); /* write all book info to a file */ gboolean gnc_book_write_to_xml_filehandle_v2(QofBook *book, FILE *fh); @@ -142,7 +142,7 @@ gboolean gnc_book_write_accounts_to_xml_file_v2(QofBackend * be, QofBook *book, /** The is_gncxml_file() routine checks to see if the first few * chars of the file look like gnc-xml data. */ -gboolean gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding); +QofBookFileType gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding); /** Write a name-space declaration for the provided namespace data type * within the GNC XML namespace at http://www.gnucash.org/XML. diff --git a/src/backend/xml/sixtp.c b/src/backend/xml/sixtp.c index 34ccf22cc5..31e6d291ad 100644 --- a/src/backend/xml/sixtp.c +++ b/src/backend/xml/sixtp.c @@ -41,6 +41,8 @@ typedef int ssize_t; #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "gnc.backend.file.sixtp" +extern const gchar *gnc_v2_xml_version_string; /* see io-gncxml-v2.c */ + /************************************************************************/ gboolean is_child_result_from_node_named(sixtp_child_result *cr, const char *tag) @@ -860,21 +862,19 @@ search_for(unsigned char marker, char **cursor) } } -gboolean -gnc_is_our_xml_file(const char *filename, const char *first_tag, - gboolean *with_encoding) +QofBookFileType +gnc_is_our_xml_file(const char *filename, gboolean *with_encoding) { FILE *f = NULL; char first_chunk[256]; ssize_t num_read; - g_return_val_if_fail(filename, FALSE); - g_return_val_if_fail(first_tag, FALSE); + g_return_val_if_fail(filename, GNC_BOOK_NOT_OURS); f = g_fopen(filename, "r"); if (f == NULL) { - return FALSE; + return GNC_BOOK_NOT_OURS; } num_read = fread(first_chunk, sizeof(char), sizeof(first_chunk) - 1, f); @@ -882,17 +882,16 @@ gnc_is_our_xml_file(const char *filename, const char *first_tag, if (num_read == 0) { - return FALSE; + return GNC_BOOK_NOT_OURS; } first_chunk[num_read] = '\0'; - return gnc_is_our_first_xml_chunk(first_chunk, first_tag, with_encoding); + return gnc_is_our_first_xml_chunk(first_chunk, with_encoding); } -gboolean -gnc_is_our_first_xml_chunk(char *chunk, const char *first_tag, - gboolean *with_encoding) +QofBookFileType +gnc_is_our_first_xml_chunk(char *chunk, gboolean *with_encoding) { char *cursor = NULL; @@ -905,51 +904,58 @@ gnc_is_our_first_xml_chunk(char *chunk, const char *first_tag, if (!eat_whitespace(&cursor)) { - return FALSE; + return GNC_BOOK_NOT_OURS; } if (strncmp(cursor, "', &cursor)) { - return FALSE; + return GNC_BOOK_NOT_OURS; } if (!eat_whitespace(&cursor)) { - return FALSE; + return GNC_BOOK_NOT_OURS; } - tag_compare = g_strdup_printf("<%s", first_tag); + tag_compare = g_strdup_printf("<%s\n", gnc_v2_xml_version_string); - result = (strncmp(cursor, tag_compare, strlen(tag_compare)) == 0); - g_free (tag_compare); - - if (result && with_encoding) + if (strncmp(cursor, tag_compare, strlen(tag_compare)) == 0) { - *cursor = '\0'; - cursor = chunk; - while (search_for('e', &cursor)) + if (with_encoding) { - if (strncmp(cursor, "ncoding=", 8) == 0) + *cursor = '\0'; + cursor = chunk; + while (search_for('e', &cursor)) { - *with_encoding = TRUE; - break; + if (strncmp(cursor, "ncoding=", 8) == 0) + { + *with_encoding = TRUE; + break; + } } } + g_free (tag_compare); + return GNC_BOOK_XML2_FILE; } - return result; - } - else - { - return FALSE; + g_free (tag_compare); + + if (strncmp(cursor, "\n", strlen("\n")) == 0) + return GNC_BOOK_XML1_FILE; + + /* If it doesn't match any of the above but has 'Save As."); + "It will be marked read-only until you do File>Save As, " + "but data may be lost in writing to the old version."); gnc_warning_dialog (parent, "%s", fmt); uh_oh = TRUE; break; @@ -458,6 +459,16 @@ show_session_error (QofBackendError io_error, gnc_error_dialog (parent, "%s", fmt); break; + case ERR_FILEIO_FILE_UPGRADE: + fmt = _("This file is from an older version of GnuCash and will be " + "upgraded when saved by this version. You will not be able " + "to read the saved file from the older version of Gnucash " + "(it will report an \"error parsing the file\"). If you wish " + "to preserve the old version, exit without saving."); + gnc_warning_dialog (parent, "%s", fmt); + uh_oh = FALSE; + break; + default: PERR("FIXME: Unhandled error %d", io_error); fmt = _("An unknown I/O error (%d) occurred."); diff --git a/src/libqof/qof/qofbackend.h b/src/libqof/qof/qofbackend.h index 2c8f6d73a9..13aed89c4d 100644 --- a/src/libqof/qof/qofbackend.h +++ b/src/libqof/qof/qofbackend.h @@ -98,6 +98,8 @@ typedef enum ERR_FILEIO_FILE_EACCES, /**< No read access permission for the given file */ ERR_FILEIO_RESERVED_WRITE, /**< User attempt to write to a directory reserved for internal use by GnuCash */ + ERR_FILEIO_FILE_UPGRADE, /**< file will be upgraded and not be able to be + read by prior versions - warn users*/ /* network errors */ ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */ diff --git a/src/libqof/qof/qofsession.c b/src/libqof/qof/qofsession.c index 9ce5052d8a..db203e3beb 100644 --- a/src/libqof/qof/qofsession.c +++ b/src/libqof/qof/qofsession.c @@ -1257,6 +1257,7 @@ qof_session_load (QofSession *session, if ((err != ERR_BACKEND_NO_ERR) && (err != ERR_FILEIO_FILE_TOO_OLD) && (err != ERR_FILEIO_NO_ENCODING) && + (err != ERR_FILEIO_FILE_UPGRADE) && (err != ERR_SQL_DB_TOO_OLD) && (err != ERR_SQL_DB_TOO_NEW)) {