Initial support to decode old, ambiguous data files, missing an encoding declaration, with the help of the user.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13781 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Andreas Köhler 2006-04-14 17:38:57 +00:00
parent d9c78bd0fe
commit 14ce276877
19 changed files with 3311 additions and 22 deletions

View File

@ -1,3 +1,28 @@
2006-04-14 Andreas Köhler <andi5.py@gmx.net>
* lib/libqof/qof/qofbackend.h:
* lib/libqof/qof/qofsession.c:
* src/backend/file/gnc-backend-file.[ch]:
* src/backend/file/io-example-account.[ch]:
* src/backend/file/io-gncxml-v1.c:
* src/backend/file/test/test-xml2-is-file.c: Add
ERR_FILEIO_NO_ENCODING and test whether xml data file declares
encoding.
* src/backend/file/sixtp.[ch]: Add parsing in push mode.
* src/backend/file/io-gncxml-v2.[ch]: Add analysis of data file to
find ambiguous words because of missing encoding, and parsing of
it with string substitutions.
* src/gnome-utils/druid-gnc-xml-import.[ch]:
* src/gnome-utils/glade/druid-gnc-xml-import.glade: Add Code and
GUI for a druid that enables the user to select from different
encodings for each ambiguous word.
* src/gnome-utils/gnc-file.c: Hook the druid into the file loading
process and reload the file if it was successful.
2006-04-14 Derek Atkins <derek@ihtfp.com>
* src/engine/Transaction.c:

View File

@ -116,6 +116,7 @@ typedef enum {
ERR_FILEIO_BACKUP_ERROR, /**< couldn't make a backup of the file */
ERR_FILEIO_WRITE_ERROR, /**< couldn't write to the file */
ERR_FILEIO_READ_ERROR, /**< Could not open the file for reading. */
ERR_FILEIO_NO_ENCODING, /**< file does not specify encoding */
/* network errors */
ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */

View File

@ -1113,6 +1113,7 @@ qof_session_load (QofSession *session,
err = qof_session_get_error(session);
if ((err != ERR_BACKEND_NO_ERR) &&
(err != ERR_FILEIO_FILE_TOO_OLD) &&
(err != ERR_FILEIO_NO_ENCODING) &&
(err != ERR_SQL_DB_TOO_OLD))
{
/* Something broke, put back the old stuff */

View File

@ -408,8 +408,13 @@ is_gzipped_file(const gchar *name)
static QofBookFileType
gnc_file_be_determine_file_type(const char *path)
{
if (gnc_is_xml_data_file_v2(path)) {
return GNC_BOOK_XML2_FILE;
gboolean with_encoding;
if (gnc_is_xml_data_file_v2(path, &with_encoding)) {
if (with_encoding) {
return GNC_BOOK_XML2_FILE;
} else {
return GNC_BOOK_XML2_FILE_NO_ENCODING;
}
} else if (gnc_is_xml_data_file(path)) {
return GNC_BOOK_XML1_FILE;
} else if (is_gzipped_file(path)) {
@ -435,10 +440,10 @@ gnc_determine_file_type (const char *path)
rc = stat(path, &sbuf);
if(rc < 0) { return FALSE; }
if (sbuf.st_size == 0) { PINFO (" empty file"); return TRUE; }
if(gnc_is_xml_data_file_v2(path)) { return TRUE; }
else if(gnc_is_xml_data_file(path)) { return TRUE; }
else if(is_gzipped_file(path)) { return TRUE; }
else if(gnc_is_bin_file(path)) { return TRUE; }
if(gnc_is_xml_data_file_v2(path, NULL)) { return TRUE; }
else if(gnc_is_xml_data_file(path)) { return TRUE; }
else if(is_gzipped_file(path)) { return TRUE; }
else if(gnc_is_bin_file(path)) { return TRUE; }
PINFO (" %s is not a gnc file", path);
return FALSE;
}
@ -873,6 +878,9 @@ gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
case GNC_BOOK_XML2_FILE_NO_ENCODING:
error = ERR_FILEIO_NO_ENCODING;
break;
case GNC_BOOK_XML1_FILE:
rc = qof_session_load_from_xml_file (book, be->fullpath);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;

View File

@ -57,6 +57,7 @@ typedef enum
GNC_BOOK_BIN_FILE,
GNC_BOOK_XML1_FILE,
GNC_BOOK_XML2_FILE,
GNC_BOOK_XML2_FILE_NO_ENCODING,
QSF_GNC_OBJECT,
QSF_OBJECT,
QSF_MAP,

View File

@ -481,5 +481,5 @@ gnc_load_example_account_list(QofBook *book, const char *dirname)
gboolean
gnc_is_example_account_xml(const gchar *name)
{
return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING);
return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL);
}

View File

@ -51,8 +51,6 @@ GncExampleAccount *gnc_read_example_account(QofBook *book,
const gchar *filename);
gboolean gnc_is_xml_data_file_v2(const gchar *filename);
void gnc_free_example_account_list(GSList *list);
GSList* gnc_load_example_account_list(QofBook *book,
const char *dirname);

View File

@ -403,7 +403,7 @@ 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");
return gnc_is_our_xml_file(filename, "gnc", NULL);
}
/* ================================================================== */

View File

@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
#include <zlib.h>
#include <errno.h>
#include "gnc-engine.h"
#include "gnc-pricedb-p.h"
@ -646,16 +647,19 @@ gnc_sixtp_gdv2_new (
return gd;
}
gboolean
qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
static gboolean
qof_session_load_from_xml_file_v2_full(
FileBackend *fbe, QofBook *book,
sixtp_push_handler push_handler, gpointer push_user_data)
{
AccountGroup *grp;
AccountGroup *grp;
QofBackend *be = &fbe->be;
sixtp_gdv2 *gd;
sixtp *top_parser;
sixtp *main_parser;
sixtp *book_parser;
struct file_backend be_data;
gboolean retval;
gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
@ -717,9 +721,22 @@ qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
xaccLogDisable ();
xaccDisableDataScrubbing();
if(!gnc_xml_parse_file(top_parser, fbe->fullpath,
generic_callback, gd, book))
{
if (push_handler) {
gpointer parse_result = NULL;
gxpf_data gpdata;
gpdata.cb = generic_callback;
gpdata.parsedata = gd;
gpdata.bookdata = book;
retval = sixtp_parse_push(top_parser, push_handler, push_user_data,
NULL, &gpdata, &parse_result);
} else {
retval = gnc_xml_parse_file(top_parser, fbe->fullpath,
generic_callback, gd, book);
}
if (!retval) {
sixtp_destroy(top_parser);
xaccLogEnable ();
xaccEnableDataScrubbing();
@ -766,6 +783,12 @@ qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
return FALSE;
}
gboolean
qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
{
return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL);
}
/***********************************************************************/
static void
@ -1359,7 +1382,391 @@ gnc_book_write_accounts_to_xml_file_v2(
/***********************************************************************/
gboolean
gnc_is_xml_data_file_v2(const gchar *name)
gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding)
{
return gnc_is_our_xml_file(name, GNC_V2_STRING);
return gnc_is_our_xml_file(name, GNC_V2_STRING, with_encoding);
}
static void
replace_character_references(gchar *string)
{
gchar *cursor, *semicolon, *tail;
glong number;
for (cursor = strstr(string, "&#");
cursor && *cursor;
cursor = strstr(cursor, "&#")) {
semicolon = strchr(cursor, ';');
if (semicolon && *semicolon) {
/* parse number */
errno = 0;
if (*(cursor+2) == 'x') {
number = strtol(cursor+3, &tail, 16);
} else {
number = strtol(cursor+2, &tail, 10);
}
if (errno || tail != semicolon || number < 0 || number > 255) {
PWARN("Illegal character reference");
return;
}
/* overwrite '&' with the specified character */
*cursor = (gchar) number;
cursor++;
if (*(semicolon+1)) {
/* move text after semicolon the the left */
tail = g_strdup(semicolon+1);
strcpy(cursor, tail);
g_free(tail);
} else {
/* cut here */
*cursor = '\0';
}
} else {
PWARN("Unclosed character reference");
return;
}
}
}
static void
conv_free(conv_type *conv) {
if (conv) {
g_free(conv->utf8_string);
g_free(conv);
}
}
static void
conv_list_free(GList *conv_list) {
g_list_foreach(conv_list, (GFunc) conv_free, NULL);
g_list_free(conv_list);
}
typedef struct {
GQuark encoding;
GIConv iconv;
} iconv_item_type;
gint
gnc_xml2_find_ambiguous(const gchar *filename, GList *encodings,
GHashTable **unique, GHashTable **ambiguous,
GList **impossible, GError **error)
{
GIOChannel *channel=NULL;
GIOStatus status;
GList *iconv_list=NULL, *conv_list=NULL, *iter;
iconv_item_type *iconv_item=NULL, *ascii=NULL;
const gchar *enc;
GHashTable *processed=NULL;
gint n_impossible = 0;
gboolean clean_return = FALSE;
channel = g_io_channel_new_file(filename, "r", error);
if (*error) {
PWARN("Unable to open file %s", filename);
goto cleanup_find_ambs;
}
status = g_io_channel_set_encoding(channel, NULL, error);
if (status != G_IO_STATUS_NORMAL) {
PWARN("Error on unsetting encoding on IOChannel");
goto cleanup_find_ambs;
}
/* we need ascii */
ascii = g_new(iconv_item_type, 1);
ascii->encoding = g_quark_from_string("ASCII");
ascii->iconv = g_iconv_open("UTF-8", "ASCII");
if (ascii->iconv == (GIConv) -1) {
PWARN("Unable to open ASCII ICONV conversion descriptor");
goto cleanup_find_ambs;
}
/* call iconv_open on encodings */
for (iter = encodings; iter; iter = iter->next) {
iconv_item = g_new(iconv_item_type, 1);
iconv_item->encoding = GPOINTER_TO_UINT (iter->data);
if (iconv_item->encoding == ascii->encoding) {
continue;
}
enc = g_quark_to_string(iconv_item->encoding);
iconv_item->iconv = g_iconv_open("UTF-8", enc);
if (iconv_item->iconv == (GIConv) -1) {
PWARN("Unable to open IConv conversion descriptor for '%s'", enc);
goto cleanup_find_ambs;
} else {
iconv_list = g_list_prepend(iconv_list, iconv_item);
}
}
/* prepare data containers */
if (unique)
*unique = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) conv_free);
if (ambiguous)
*ambiguous = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) conv_list_free);
if (impossible)
*impossible = NULL;
processed = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
/* loop through lines */
while (1) {
gchar *line, *word, *utf8;
gchar **word_array, **word_cursor;
conv_type *conv;
status = g_io_channel_read_line(channel, &line, NULL, NULL, error);
if (status == G_IO_STATUS_EOF) {
break;
}
if (status == G_IO_STATUS_AGAIN) {
continue;
}
if (status != G_IO_STATUS_NORMAL) {
goto cleanup_find_ambs;
}
g_strchomp(line);
replace_character_references(line);
word_array = g_strsplit_set(line, "> <", 0);
g_free(line);
/* loop through words */
for (word_cursor = word_array; *word_cursor; word_cursor++) {
word = *word_cursor;
if (!word)
continue;
utf8 = g_convert_with_iconv(word, -1, ascii->iconv,
NULL, NULL, error);
if (utf8) {
/* pure ascii */
g_free(utf8);
continue;
}
g_error_free(*error);
*error = NULL;
if (g_hash_table_lookup_extended(processed, word, NULL, NULL)) {
/* already processed */
continue;
}
/* loop through encodings */
conv_list = NULL;
for (iter = iconv_list; iter; iter = iter->next) {
iconv_item = iter->data;
utf8 = g_convert_with_iconv(word, -1, iconv_item->iconv,
NULL, NULL, error);
if (utf8) {
conv = g_new(conv_type, 1);
conv->encoding = iconv_item->encoding;
conv->utf8_string = utf8;
conv_list = g_list_prepend(conv_list, conv);
} else {
g_error_free(*error);
*error = NULL;
}
}
/* no successful conversion */
if (!conv_list) {
if (impossible)
*impossible = g_list_append(*impossible, g_strdup(word));
n_impossible++;
}
/* more than one successful conversion */
else if (conv_list->next) {
if (ambiguous) {
g_hash_table_insert(*ambiguous, g_strdup(word), conv_list);
} else {
conv_list_free(conv_list);
}
}
/* only one successful conversion */
else {
if (unique) {
g_hash_table_insert(*unique, g_strdup(word), conv);
} else {
conv_free(conv);
}
g_list_free(conv_list);
}
g_hash_table_insert(processed, g_strdup(word), NULL);
}
g_strfreev(word_array);
}
clean_return = TRUE;
cleanup_find_ambs:
if (iconv_list) {
for (iter = iconv_list; iter; iter = iter->next) {
if (iter->data) {
g_iconv_close(((iconv_item_type*) iter->data)->iconv);
g_free(iter->data);
}
}
g_list_free(iconv_list);
}
if (processed)
g_hash_table_destroy(processed);
if (ascii)
g_free(ascii);
if (channel)
g_io_channel_unref(channel);
return (clean_return) ? n_impossible : -1;
}
typedef struct {
gchar *filename;
GHashTable *subst;
} push_data_type;
static void
parse_with_subst_push_handler (xmlParserCtxtPtr xml_context,
push_data_type *push_data)
{
GIOChannel *channel=NULL;
GIOStatus status;
GIConv ascii=(GIConv)-1;
GString *output=NULL;
GError *error=NULL;
channel = g_io_channel_new_file(push_data->filename, "r", &error);
if (error) {
PWARN("Unable to open file %s", push_data->filename);
goto cleanup_push_handler;
}
status = g_io_channel_set_encoding(channel, NULL, &error);
if (status != G_IO_STATUS_NORMAL) {
PWARN("Error on unsetting encoding on IOChannel");
goto cleanup_push_handler;
}
ascii = g_iconv_open("UTF-8", "ASCII");
if (ascii == (GIConv) -1) {
PWARN("Unable to open ASCII ICONV conversion descriptor");
goto cleanup_push_handler;
}
/* loop through lines */
while (1) {
gchar *line, *word, *repl, *utf8;
gint pos, len;
gchar *start, *cursor;
status = g_io_channel_read_line(channel, &line, NULL, NULL, &error);
if (status == G_IO_STATUS_EOF) {
break;
}
if (status == G_IO_STATUS_AGAIN) {
continue;
}
if (status != G_IO_STATUS_NORMAL) {
goto cleanup_push_handler;
}
replace_character_references(line);
output = g_string_new(line);
g_free(line);
/* loop through words */
cursor = output->str;
pos = 0;
while (1) {
/* ignore delimiters */
while (*cursor=='>' || *cursor==' ' || *cursor=='<' ||
*cursor=='\n') {
cursor++;
pos += 1;
}
if (!*cursor)
/* welcome to EOL */
break;
/* search for a delimiter */
start = cursor;
len = 0;
while (*cursor && *cursor!='>' && *cursor!=' ' && *cursor!='<' &&
*cursor!='\n') {
cursor++;
len++;
}
utf8 = g_convert_with_iconv(start, len, ascii, NULL, NULL, &error);
if (utf8) {
/* pure ascii */
g_free(utf8);
pos += len;
} else {
g_error_free(error);
error = NULL;
word = g_strndup(start, len);
repl = g_hash_table_lookup(push_data->subst, word);
g_free(word);
if (repl) {
/* there is a replacement */
output = g_string_insert(g_string_erase(output, pos, len),
pos, repl);
pos += strlen(repl);
cursor = output->str + pos;
} else {
/* there is no replacement, return immediately */
goto cleanup_push_handler;
}
}
}
if (xmlParseChunk(xml_context, output->str, output->len, 0) != 0) {
goto cleanup_push_handler;
}
}
/* last chunk */
xmlParseChunk(xml_context, "", 0, 1);
cleanup_push_handler:
if (output)
g_string_free(output, TRUE);
if (ascii != (GIConv) -1)
g_iconv_close(ascii);
if (channel)
g_io_channel_unref(channel);
}
gboolean
gnc_xml2_parse_with_subst (FileBackend *fbe, QofBook *book, GHashTable *subst)
{
push_data_type *push_data;
gboolean success;
push_data = g_new(push_data_type, 1);
push_data->filename = fbe->fullpath;
push_data->subst = subst;
success = qof_session_load_from_xml_file_v2_full(
fbe, book, (sixtp_push_handler) parse_with_subst_push_handler,
push_data);
if (success)
qof_book_kvp_changed(book);
return success;
}

View File

@ -142,11 +142,57 @@ 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 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.
*/
void gnc_xml2_write_namespace_decl (FILE *out, const char *namespace);
typedef struct {
GQuark encoding;
gchar *utf8_string;
} conv_type;
/** Read a file as plain byte stream to find words that are not completely ASCII.
* On error, @unique, @ambiguous and @impossible will be filled up to that point,
* @error may contain an io channel error, -1 will be returned.
*
* @param filename Name of the file to read.
*
* @param encodings List of encodings to check words for, each begin one a GQuark
* in a pointer.
*
* @param unique Location used for a hash table for unique solutions, if not
* NULL. The byte sequence is the key, successful_conversion the value.
*
* @param ambiguous Location used for a hash table for ambiguous byte sequences,
* if not NULL. The byte sequences is the key, a list of successful_conversions
* the value.
*
* @param impossible Location used for a list for undecodable byte sequences,
* if not NULL.
*
* @param error Location to return an io channel error.
*
* @return Size of impossible, -1 on error.
*/
gint gnc_xml2_find_ambiguous(
const gchar *filename, GList *encodings, GHashTable **unique,
GHashTable **ambiguous, GList **impossible, GError **error);
typedef gint (*find_ambiguous_handler)(
const gchar *filename, GList *encodings, GHashTable **unique,
GHashTable **ambiguous, GList **impossible, GError **error);
/** Parse a file in push mode, but replace byte sequences in the file given a
* hash table of substitutions
*
* @param subst hash table with keys and values of type gchar*
*/
gboolean gnc_xml2_parse_with_subst (
FileBackend *fbe, QofBook *book, GHashTable *subst);
typedef gboolean (*parse_with_subst_handler)(
FileBackend *fbe, QofBook *book, GHashTable *subst);
#endif /* __IO_GNCXML_V2_H__ */

View File

@ -748,6 +748,52 @@ sixtp_parse_buffer(sixtp *sixtp,
return ret;
}
gboolean
sixtp_parse_push (sixtp *sixtp,
sixtp_push_handler push_handler,
gpointer push_user_data,
gpointer data_for_top_level,
gpointer global_data,
gpointer *parse_result)
{
sixtp_parser_context *ctxt;
xmlParserCtxtPtr xml_context;
if (!push_handler) {
PERR("No push handler specified");
return FALSE;
}
if (!(ctxt = sixtp_context_new(sixtp, global_data, data_for_top_level))) {
PERR("sixtp_context_new returned null");
return FALSE;
}
xml_context = xmlCreatePushParserCtxt(&ctxt->handler, &ctxt->data,
NULL, 0, NULL);
ctxt->data.saxParserCtxt = xml_context;
ctxt->data.bad_xml_parser = sixtp_dom_parser_new(gnc_bad_xml_end_handler,
NULL, NULL);
(*push_handler)(xml_context, push_user_data);
sixtp_context_run_end_handler(ctxt);
if (ctxt->data.parsing_ok) {
if (parse_result)
*parse_result = ctxt->top_frame->frame_data;
sixtp_context_destroy(ctxt);
return TRUE;
} else {
if (parse_result)
*parse_result = NULL;
if (g_slist_length(ctxt->data.stack) > 1)
sixtp_handle_catastrophe(&ctxt->data);
sixtp_context_destroy(ctxt);
return FALSE;
}
}
/***********************************************************************/
static gboolean
eat_whitespace(unsigned char **cursor)
@ -787,7 +833,8 @@ search_for(unsigned char marker, unsigned char **cursor)
}
gboolean
gnc_is_our_xml_file(const char *filename, const char *first_tag)
gnc_is_our_xml_file(const char *filename, const char *first_tag,
gboolean *with_encoding)
{
FILE *f = NULL;
char first_chunk[256];
@ -796,6 +843,10 @@ gnc_is_our_xml_file(const char *filename, const char *first_tag)
g_return_val_if_fail(filename, FALSE);
g_return_val_if_fail(first_tag, FALSE);
if (with_encoding) {
*with_encoding = FALSE;
}
f = fopen(filename, "r");
if (f == NULL) {
@ -838,6 +889,18 @@ gnc_is_our_xml_file(const char *filename, const char *first_tag)
result = (strncmp(cursor, tag_compare, strlen(tag_compare)) == 0);
g_free (tag_compare);
if (result && with_encoding) {
*cursor = '\0';
cursor = first_chunk;
while (search_for('e', &cursor)) {
if (strncmp(cursor, "ncoding=", 8) == 0) {
*with_encoding = TRUE;
break;
}
}
}
return result;
}
else

View File

@ -86,6 +86,9 @@ typedef void (*sixtp_fail_handler)(gpointer data_for_children,
gpointer *result,
const gchar *tag);
typedef void (*sixtp_push_handler)(xmlParserCtxtPtr xml_context,
gpointer user_data);
typedef struct sixtp
{
/* If you change this, don't forget to modify all the copy/etc. functions */
@ -180,6 +183,9 @@ gboolean sixtp_parse_file(sixtp *sixtp, const char *filename,
gboolean sixtp_parse_buffer(sixtp *sixtp, char *bufp, int bufsz,
gpointer data_for_top_level, gpointer global_data,
gpointer *parse_result);
gboolean sixtp_parse_push(sixtp *sixtp, sixtp_push_handler push_handler,
gpointer push_user_data, gpointer data_for_top_level,
gpointer global_data, gpointer *parse_result);
void sixtp_set_start(sixtp *parser, sixtp_start_handler start_handler);
void sixtp_set_before_child(sixtp *parser, sixtp_before_child_handler handler);
@ -198,7 +204,8 @@ sixtp* sixtp_add_some_sub_parsers(sixtp *tochange, gboolean cleanup, ...);
gboolean sixtp_add_sub_parser(sixtp *parser, const gchar* tag,
sixtp *sub_parser);
gboolean gnc_is_our_xml_file(const char *filename, const char *first_tag);
gboolean gnc_is_our_xml_file(const char *filename, const char *first_tag,
gboolean *with_encoding);
#endif /* _SIXTP_H_ */

View File

@ -22,7 +22,7 @@ main(int argc, char **argv)
filename = malloc(strlen(directory) + 1 + strlen(FILENAME) + 1);
sprintf(filename, "%s/%s", directory, FILENAME);
do_test(gnc_is_xml_data_file_v2(filename), "gnc_is_xml_data_file_v2");
do_test(gnc_is_xml_data_file_v2(filename, NULL), "gnc_is_xml_data_file_v2");
print_test_results();
exit(get_rv());

View File

@ -48,6 +48,7 @@ libgncmod_gnome_utils_la_SOURCES = \
dialog-utils.c \
druid-utils.c \
druid-gconf-setup.c \
druid-gnc-xml-import.c \
gnc-account-sel.c \
gnc-amount-edit.c \
gnc-commodity-edit.c \
@ -116,6 +117,7 @@ gncinclude_HEADERS = \
dialog-utils.h \
druid-utils.h \
druid-gconf-setup.h \
druid-gnc-xml-import.h \
gnc-account-sel.h \
gnc-amount-edit.h \
gnc-commodity-edit.h \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/*
* druid-gnc-xml-import.h --
* Copyright (C) 2006 Andreas Koehler <andi5.py@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact:
*
* Free Software Foundation Voice: +1-617-542-5942
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
* Boston, MA 02110-1301, USA gnu@gnu.org
*/
#ifndef DRUID_GNC_XML_IMPORT_H
#define DRUID_GNC_XML_IMPORT_H
#include "qof.h"
gboolean gnc_xml_convert_single_file (const gchar *filename);
/* this is NOT fully implemented */
void gnc_xml_merge_files (void);
#endif /* DRUID_GNC_XML_IMPORT_H */

View File

@ -6,6 +6,7 @@ glade_DATA = \
druid-provider-multifile.glade \
exchange-dialog.glade \
druid-gconf-setup.glade \
druid-gnc-xml-import.glade \
gnc-date-format.glade \
gnc-gui-query.glade \
preferences.glade \

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#include <g-wrap-wct.h>
#include "dialog-utils.h"
#include "druid-gnc-xml-import.h"
#include "gnc-commodity.h"
#include "gnc-component-manager.h"
#include "gnc-engine.h"
@ -740,6 +741,22 @@ gnc_post_file_open (const char * filename)
/* check for i/o error, put up appropriate error dialog */
io_err = qof_session_get_error (new_session);
if (io_err == ERR_FILEIO_NO_ENCODING) {
qof_session_pop_error (new_session);
if (gnc_xml_convert_single_file (newfile)) {
/* try to load once again */
gnc_window_show_progress(_("Reading file..."), 0.0);
qof_session_load (new_session, gnc_window_show_progress);
gnc_window_show_progress(NULL, -1.0);
xaccLogEnable();
io_err = qof_session_get_error (new_session);
}
else {
io_err = ERR_FILEIO_PARSE_ERROR;
}
}
uh_oh = show_session_error (io_err, newfile, GNC_FILE_DIALOG_OPEN);
new_group = gnc_book_get_group (qof_session_get_book (new_session));