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
This commit is contained in:
J. Alex Aycinena 2012-01-29 01:12:30 +00:00
parent c2458bfc68
commit 7c03e237b2
19 changed files with 134 additions and 73 deletions

View File

@ -99,15 +99,6 @@ typedef int ssize_t;
static QofLogModule log_module = GNC_MOD_BACKEND; 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); static gboolean save_may_clobber_data (QofBackend *bend);
/* ================================================================= */ /* ================================================================= */
@ -561,7 +552,10 @@ static QofBookFileType
gnc_xml_be_determine_file_type(const char *path) gnc_xml_be_determine_file_type(const char *path)
{ {
gboolean with_encoding; 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) if (with_encoding)
{ {
@ -572,7 +566,11 @@ gnc_xml_be_determine_file_type(const char *path)
return GNC_BOOK_XML2_FILE_NO_ENCODING; 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; return GNC_BOOK_XML1_FILE;
} }
@ -586,6 +584,7 @@ gnc_determine_file_type (const char *uri)
int rc; int rc;
FILE *t; FILE *t;
gchar *filename; gchar *filename;
QofBookFileType xml_type;
gboolean result; gboolean result;
if (!uri) if (!uri)
@ -619,12 +618,10 @@ gnc_determine_file_type (const char *uri)
result = TRUE; result = TRUE;
goto det_exit; goto det_exit;
} }
if (gnc_is_xml_data_file_v2(filename, NULL)) xml_type = gnc_is_xml_data_file_v2(filename, NULL);
{ if ((xml_type == GNC_BOOK_XML2_FILE) ||
result = TRUE; (xml_type == GNC_BOOK_XML1_FILE) ||
goto det_exit; (xml_type == GNC_BOOK_POST_XML2_0_0_FILE))
}
else if (gnc_is_xml_data_file(filename))
{ {
result = TRUE; result = TRUE;
goto det_exit; 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)) switch (gnc_xml_be_determine_file_type(be->fullpath))
{ {
case GNC_BOOK_XML2_FILE: 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) if (FALSE == rc)
{ {
PWARN( "Syntax error in Xml File %s", be->fullpath ); 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; error = ERR_FILEIO_PARSE_ERROR;
} }
break; 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: default:
/* If file type wasn't known, check errno again to give the /* If file type wasn't known, check errno again to give the
user some more useful feedback for some particular error user some more useful feedback for some particular error

View File

@ -43,6 +43,16 @@ typedef enum
XML_RETAIN_ALL XML_RETAIN_ALL
} XMLFileRetentionType; } 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 struct FileBackend_struct
{ {
QofBackend be; QofBackend be;

View File

@ -498,8 +498,9 @@ gnc_load_example_account_list(const char *dirname)
/***********************************************************************/ /***********************************************************************/
/*
gboolean gboolean
gnc_is_example_account_xml(const gchar *name) gnc_is_example_account_xml(const gchar *name)
{ {
return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL); return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL);
} } */

View File

@ -53,6 +53,6 @@ GncExampleAccount *gnc_read_example_account(const gchar *filename);
void gnc_free_example_account_list(GSList *list); void gnc_free_example_account_list(GSList *list);
GSList* gnc_load_example_account_list(const char *dirname); 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 */ #endif /* IO_EXAMPLE_ACCOUNT_H */

View File

@ -412,7 +412,9 @@ qof_session_load_from_xml_file(QofBook *book, const char *filename)
gboolean gboolean
gnc_is_xml_data_file(const gchar *filename) 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;
} }
/* ================================================================== */ /* ================================================================== */

View File

@ -95,6 +95,8 @@ struct file_backend
}; };
#define GNC_V2_STRING "gnc-v2" #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 */ extern const gchar *gnc_v2_book_version_string; /* see gnc-book-xml-v2 */
void void
@ -679,7 +681,8 @@ gnc_sixtp_gdv2_new (
static gboolean static gboolean
qof_session_load_from_xml_file_v2_full( qof_session_load_from_xml_file_v2_full(
FileBackend *fbe, QofBook *book, 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; Account *root;
QofBackend *be = &fbe->be; QofBackend *be = &fbe->be;
@ -689,6 +692,7 @@ qof_session_load_from_xml_file_v2_full(
sixtp *book_parser; sixtp *book_parser;
struct file_backend be_data; struct file_backend be_data;
gboolean retval; gboolean retval;
char *v2type;
gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage); 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(); main_parser = sixtp_new();
book_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( if (!sixtp_add_some_sub_parsers(
top_parser, TRUE, top_parser, TRUE,
GNC_V2_STRING, main_parser, v2type, main_parser,
NULL, NULL)) NULL, NULL))
{ {
g_free(v2type);
goto bail; goto bail;
} }
g_free(v2type);
if (!sixtp_add_some_sub_parsers( if (!sixtp_add_some_sub_parsers(
main_parser, TRUE, main_parser, TRUE,
COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(), COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(),
@ -819,9 +829,10 @@ bail:
} }
gboolean 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; return FALSE;
} }
gboolean QofBookFileType
gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding) 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)) if (is_gzipped_file(name))
{ {
gzFile *file = NULL; gzFile *file = NULL;
@ -1647,19 +1655,18 @@ gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding)
file = gzopen(name, "r"); file = gzopen(name, "r");
#endif #endif
if (file == NULL) if (file == NULL)
return FALSE; return GNC_BOOK_NOT_OURS;
num_read = gzread(file, first_chunk, sizeof(first_chunk) - 1); num_read = gzread(file, first_chunk, sizeof(first_chunk) - 1);
gzclose(file); gzclose(file);
if (num_read < 1) if (num_read < 1)
return FALSE; return GNC_BOOK_NOT_OURS;
return gnc_is_our_first_xml_chunk(first_chunk, GNC_V2_STRING, return gnc_is_our_first_xml_chunk(first_chunk, with_encoding);
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( success = qof_session_load_from_xml_file_v2_full(
fbe, book, (sixtp_push_handler) parse_with_subst_push_handler, fbe, book, (sixtp_push_handler) parse_with_subst_push_handler,
push_data); push_data, GNC_BOOK_XML2_FILE);
if (success) if (success)
qof_book_kvp_changed(book); qof_book_kvp_changed(book);

View File

@ -128,7 +128,7 @@ typedef struct
void run_callback(sixtp_gdv2 *data, const char *type); void run_callback(sixtp_gdv2 *data, const char *type);
/** read in an account group from a file */ /** 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 */ /* write all book info to a file */
gboolean gnc_book_write_to_xml_filehandle_v2(QofBook *book, FILE *fh); 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 /** The is_gncxml_file() routine checks to see if the first few
* chars of the file look like gnc-xml data. * 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 /** Write a name-space declaration for the provided namespace data type
* within the GNC XML namespace at http://www.gnucash.org/XML. * within the GNC XML namespace at http://www.gnucash.org/XML.

View File

@ -41,6 +41,8 @@ typedef int ssize_t;
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "gnc.backend.file.sixtp" #define G_LOG_DOMAIN "gnc.backend.file.sixtp"
extern const gchar *gnc_v2_xml_version_string; /* see io-gncxml-v2.c */
/************************************************************************/ /************************************************************************/
gboolean gboolean
is_child_result_from_node_named(sixtp_child_result *cr, const char *tag) 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 QofBookFileType
gnc_is_our_xml_file(const char *filename, const char *first_tag, gnc_is_our_xml_file(const char *filename, gboolean *with_encoding)
gboolean *with_encoding)
{ {
FILE *f = NULL; FILE *f = NULL;
char first_chunk[256]; char first_chunk[256];
ssize_t num_read; ssize_t num_read;
g_return_val_if_fail(filename, FALSE); g_return_val_if_fail(filename, GNC_BOOK_NOT_OURS);
g_return_val_if_fail(first_tag, FALSE);
f = g_fopen(filename, "r"); f = g_fopen(filename, "r");
if (f == NULL) if (f == NULL)
{ {
return FALSE; return GNC_BOOK_NOT_OURS;
} }
num_read = fread(first_chunk, sizeof(char), sizeof(first_chunk) - 1, f); 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) if (num_read == 0)
{ {
return FALSE; return GNC_BOOK_NOT_OURS;
} }
first_chunk[num_read] = '\0'; 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 QofBookFileType
gnc_is_our_first_xml_chunk(char *chunk, const char *first_tag, gnc_is_our_first_xml_chunk(char *chunk, gboolean *with_encoding)
gboolean *with_encoding)
{ {
char *cursor = NULL; char *cursor = NULL;
@ -905,51 +904,58 @@ gnc_is_our_first_xml_chunk(char *chunk, const char *first_tag,
if (!eat_whitespace(&cursor)) if (!eat_whitespace(&cursor))
{ {
return FALSE; return GNC_BOOK_NOT_OURS;
} }
if (strncmp(cursor, "<?xml", 5) == 0) if (strncmp(cursor, "<?xml", 5) == 0)
{ {
char *tag_compare; char *tag_compare;
gboolean result;
if (!search_for('>', &cursor)) if (!search_for('>', &cursor))
{ {
return FALSE; return GNC_BOOK_NOT_OURS;
} }
if (!eat_whitespace(&cursor)) 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); if (strncmp(cursor, tag_compare, strlen(tag_compare)) == 0)
g_free (tag_compare);
if (result && with_encoding)
{ {
*cursor = '\0'; if (with_encoding)
cursor = chunk;
while (search_for('e', &cursor))
{ {
if (strncmp(cursor, "ncoding=", 8) == 0) *cursor = '\0';
cursor = chunk;
while (search_for('e', &cursor))
{ {
*with_encoding = TRUE; if (strncmp(cursor, "ncoding=", 8) == 0)
break; {
*with_encoding = TRUE;
break;
}
} }
} }
g_free (tag_compare);
return GNC_BOOK_XML2_FILE;
} }
return result; g_free (tag_compare);
}
else if (strncmp(cursor, "<gnc>\n", strlen("<gnc>\n")) == 0)
{ return GNC_BOOK_XML1_FILE;
return FALSE;
/* If it doesn't match any of the above but has '<gnc-v...', it must */
/* be a later version */
if (strncmp(cursor, "<gnc-v", strlen("<gnc-v")) == 0)
return GNC_BOOK_POST_XML2_0_0_FILE;
return GNC_BOOK_NOT_OURS;
} }
return FALSE; return GNC_BOOK_NOT_OURS;
} }
/************************* END OF FILE *********************************/ /************************* END OF FILE *********************************/

View File

@ -31,6 +31,7 @@
#include "gnc-xml-helper.h" #include "gnc-xml-helper.h"
#include "gnc-engine.h" #include "gnc-engine.h"
#include "gnc-backend-xml.h"
typedef struct _sixtp_child_result sixtp_child_result; typedef struct _sixtp_child_result sixtp_child_result;
@ -208,11 +209,10 @@ sixtp* sixtp_add_some_sub_parsers(sixtp *tochange, gboolean cleanup, ...);
gboolean sixtp_add_sub_parser(sixtp *parser, const gchar* tag, gboolean sixtp_add_sub_parser(sixtp *parser, const gchar* tag,
sixtp *sub_parser); sixtp *sub_parser);
gboolean gnc_is_our_xml_file(const char *filename, const char *first_tag, QofBookFileType gnc_is_our_xml_file(const char *filename,
gboolean *with_encoding); gboolean *with_encoding);
gboolean gnc_is_our_first_xml_chunk(char *chunk, const char *first_tag, QofBookFileType gnc_is_our_first_xml_chunk(char *chunk, gboolean *with_encoding);
gboolean *with_encoding);
#endif /* _SIXTP_H_ */ #endif /* _SIXTP_H_ */

View File

@ -10,6 +10,9 @@
#include "sixtp-utils.h" #include "sixtp-utils.h"
#include "sixtp-dom-generators.h" #include "sixtp-dom-generators.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {

View File

@ -43,6 +43,9 @@
#include "gnc-commodity.h" #include "gnc-commodity.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static void static void
test_dom_tree_to_commodity_ref(void) test_dom_tree_to_commodity_ref(void)
{ {

View File

@ -11,6 +11,8 @@
#include "sixtp-dom-generators.h" #include "sixtp-dom-generators.h"
#include "sixtp-dom-parsers.h" #include "sixtp-dom-parsers.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static void static void
test_kvp_get_slot(int run, test_kvp_get_slot(int run,

View File

@ -11,6 +11,9 @@
#include "test-engine-stuff.h" #include "test-engine-stuff.h"
#include "test-file-stuff.h" #include "test-file-stuff.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static void static void
test_binary() test_binary()
{ {

View File

@ -43,6 +43,9 @@
#include "Account.h" #include "Account.h"
#include "Scrub.h" #include "Scrub.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static QofBook *sixbook; static QofBook *sixbook;
static gchar* static gchar*

View File

@ -24,6 +24,9 @@
#include "Account.h" #include "Account.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static QofBook *book; static QofBook *book;
static gchar* static gchar*

View File

@ -42,6 +42,9 @@
#include "test-engine-stuff.h" #include "test-engine-stuff.h"
#include "test-file-stuff.h" #include "test-file-stuff.h"
#define GNC_V2_STRING "gnc-v2"
const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
static QofSession *session; static QofSession *session;
struct pricedb_data_struct struct pricedb_data_struct

View File

@ -421,7 +421,8 @@ show_session_error (QofBackendError io_error,
case ERR_SQL_DB_TOO_NEW: case ERR_SQL_DB_TOO_NEW:
fmt = _("This database is from a newer version of GnuCash. " fmt = _("This database is from a newer version of GnuCash. "
"This version can read it, but cannot safely save to it. " "This version can read it, but cannot safely save to it. "
"It will be marked read-only until you do File>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); gnc_warning_dialog (parent, "%s", fmt);
uh_oh = TRUE; uh_oh = TRUE;
break; break;
@ -458,6 +459,16 @@ show_session_error (QofBackendError io_error,
gnc_error_dialog (parent, "%s", fmt); gnc_error_dialog (parent, "%s", fmt);
break; 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: default:
PERR("FIXME: Unhandled error %d", io_error); PERR("FIXME: Unhandled error %d", io_error);
fmt = _("An unknown I/O error (%d) occurred."); fmt = _("An unknown I/O error (%d) occurred.");

View File

@ -98,6 +98,8 @@ typedef enum
ERR_FILEIO_FILE_EACCES, /**< No read access permission for the given file */ ERR_FILEIO_FILE_EACCES, /**< No read access permission for the given file */
ERR_FILEIO_RESERVED_WRITE, /**< User attempt to write to a directory reserved ERR_FILEIO_RESERVED_WRITE, /**< User attempt to write to a directory reserved
for internal use by GnuCash */ 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 */ /* network errors */
ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */ ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */

View File

@ -1257,6 +1257,7 @@ qof_session_load (QofSession *session,
if ((err != ERR_BACKEND_NO_ERR) && if ((err != ERR_BACKEND_NO_ERR) &&
(err != ERR_FILEIO_FILE_TOO_OLD) && (err != ERR_FILEIO_FILE_TOO_OLD) &&
(err != ERR_FILEIO_NO_ENCODING) && (err != ERR_FILEIO_NO_ENCODING) &&
(err != ERR_FILEIO_FILE_UPGRADE) &&
(err != ERR_SQL_DB_TOO_OLD) && (err != ERR_SQL_DB_TOO_OLD) &&
(err != ERR_SQL_DB_TOO_NEW)) (err != ERR_SQL_DB_TOO_NEW))
{ {