24 #include <glib/gstdio.h> 31 #include <sys/types.h> 35 # define g_fopen fopen 39 #include "sixtp-parsers.h" 40 #include "sixtp-stack.h" 43 #define G_LOG_DOMAIN "gnc.backend.file.sixtp" 44 static QofLogModule log_module =
"gnc.backend.file.sixtp";
46 extern const gchar* gnc_v2_xml_version_string;
50 is_child_result_from_node_named (sixtp_child_result* cr,
const char* tag)
52 return ((cr->type == SIXTP_CHILD_RESULT_NODE)
54 (g_strcmp0 (cr->tag, tag) == 0));
58 sixtp_child_free_data (sixtp_child_result* result)
60 if (result->data) g_free (result->data);
64 sixtp_child_result_destroy (sixtp_child_result* r)
66 if (r->should_cleanup && r->cleanup_handler)
68 r->cleanup_handler (r);
70 if (r->type == SIXTP_CHILD_RESULT_NODE) g_free (r->tag);
75 sixtp_child_result_print (sixtp_child_result* cr, FILE* f)
77 fprintf (f,
"((tag %s) (data %p))",
78 cr->tag ? cr->tag :
"(null)",
86 sixtp_set_start (
sixtp* parser, sixtp_start_handler start_handler)
88 parser->start_handler = start_handler;
92 sixtp_set_before_child (
sixtp* parser, sixtp_before_child_handler handler)
94 parser->before_child = handler;
98 sixtp_set_after_child (
sixtp* parser, sixtp_after_child_handler handler)
100 parser->after_child = handler;
104 sixtp_set_end (
sixtp* parser, sixtp_end_handler end_handler)
106 parser->end_handler = end_handler;
110 sixtp_set_chars (
sixtp* parser, sixtp_characters_handler char_handler)
112 parser->characters_handler = char_handler;
116 sixtp_set_cleanup_result (
sixtp* parser, sixtp_result_handler handler)
118 parser->cleanup_result = handler;
122 sixtp_set_cleanup_chars (
sixtp* parser, sixtp_result_handler handler)
124 parser->cleanup_chars = handler;
128 sixtp_set_fail (
sixtp* parser,
129 sixtp_fail_handler handler)
131 parser->fail_handler = handler;
135 sixtp_set_result_fail (
sixtp* parser, sixtp_result_handler handler)
137 parser->result_fail_handler = handler;
141 sixtp_set_chars_fail (
sixtp* parser, sixtp_result_handler handler)
143 parser->chars_fail_handler = handler;
153 s->child_parsers = g_hash_table_new (g_str_hash, g_str_equal);
154 if (!s->child_parsers)
164 sixtp_set_any (
sixtp* tochange,
int cleanup, ...)
167 sixtp_handler_type type;
171 PWARN (
"Null tochange passed");
175 va_start (ap, cleanup);
179 type =
static_cast<decltype (type)
> (va_arg (ap,
int));
183 case SIXTP_NO_MORE_HANDLERS:
187 case SIXTP_START_HANDLER_ID:
188 sixtp_set_start (tochange, va_arg (ap, sixtp_start_handler));
191 case SIXTP_BEFORE_CHILD_HANDLER_ID:
192 sixtp_set_before_child (tochange,
193 va_arg (ap, sixtp_before_child_handler));
196 case SIXTP_AFTER_CHILD_HANDLER_ID:
197 sixtp_set_after_child (tochange,
198 va_arg (ap, sixtp_after_child_handler));
201 case SIXTP_END_HANDLER_ID:
202 sixtp_set_end (tochange, va_arg (ap, sixtp_end_handler));
205 case SIXTP_CHARACTERS_HANDLER_ID:
206 sixtp_set_chars (tochange, va_arg (ap, sixtp_characters_handler));
209 case SIXTP_FAIL_HANDLER_ID:
210 sixtp_set_fail (tochange, va_arg (ap, sixtp_fail_handler));
213 case SIXTP_CLEANUP_RESULT_ID:
214 sixtp_set_cleanup_result (tochange,
215 va_arg (ap, sixtp_result_handler));
218 case SIXTP_CLEANUP_CHARS_ID:
219 sixtp_set_cleanup_chars (tochange,
220 va_arg (ap, sixtp_result_handler));
223 case SIXTP_RESULT_FAIL_ID:
224 sixtp_set_result_fail (tochange, va_arg (ap, sixtp_result_handler));
227 case SIXTP_CHARS_FAIL_ID:
228 sixtp_set_chars_fail (tochange, va_arg (ap, sixtp_result_handler));
233 g_critical (
"Bogus sixtp type %d", type);
236 sixtp_destroy (tochange);
247 static void sixtp_destroy_child (gpointer key, gpointer value,
251 sixtp_destroy_node (
sixtp* sp, GHashTable* corpses)
253 g_return_if_fail (sp);
254 g_return_if_fail (corpses);
255 g_hash_table_foreach (sp->child_parsers, sixtp_destroy_child, corpses);
256 g_hash_table_destroy (sp->child_parsers);
261 sixtp_destroy_child (gpointer key, gpointer value, gpointer user_data)
263 GHashTable* corpses = (GHashTable*) user_data;
266 gpointer lookup_value;
268 DEBUG (
"Killing sixtp child under key <%s>", key ? (
char*) key :
"(null)");
272 g_critical (
"no corpses in sixtp_destroy_child <%s>",
273 key ? (
char*) key :
"(null)");
279 g_critical (
"no child in sixtp_destroy_child <%s>",
280 key ? (
char*) key :
"");
286 if (!g_hash_table_lookup_extended (corpses, (gconstpointer) child,
287 &lookup_key, &lookup_value))
290 g_hash_table_insert (corpses, child, (gpointer) 1);
291 sixtp_destroy_node (child, corpses);
296 sixtp_destroy (
sixtp* sp)
299 g_return_if_fail (sp);
300 corpses = g_hash_table_new (g_direct_hash, g_direct_equal);
301 sixtp_destroy_node (sp, corpses);
302 g_hash_table_destroy (corpses);
309 sixtp_add_sub_parser (
sixtp* parser,
const gchar* tag,
sixtp* sub_parser)
311 g_return_val_if_fail (parser, FALSE);
312 g_return_val_if_fail (tag, FALSE);
313 g_return_val_if_fail (sub_parser, FALSE);
315 g_hash_table_insert (parser->child_parsers,
316 g_strdup (tag), (gpointer) sub_parser);
325 sixtp_add_some_sub_parsers (
sixtp* tochange,
int cleanup, ...)
332 va_start (ap, cleanup);
343 tag = va_arg (ap,
char*);
349 handler = va_arg (ap,
sixtp*);
352 PWARN (
"Handler for tag %s is null",
353 tag ? tag :
"(null)");
357 sixtp_destroy (tochange);
370 sixtp_destroy (handler);
374 sixtp_add_sub_parser (tochange, tag, handler);
386 sixtp_sax_start_handler (
void* user_data,
388 const xmlChar** attrs)
392 sixtp* current_parser = NULL;
393 sixtp* next_parser = NULL;
394 gchar* next_parser_tag = NULL;
395 gboolean lookup_success = FALSE;
399 current_parser = current_frame->parser;
404 g_hash_table_lookup_extended (current_parser->child_parsers,
406 reinterpret_cast<void**> (&next_parser_tag),
407 reinterpret_cast<void**
> (&next_parser));
413 lookup_success = g_hash_table_lookup_extended (
414 current_parser->child_parsers, SIXTP_MAGIC_CATCHER,
415 reinterpret_cast<void**> (&next_parser_tag),
416 reinterpret_cast<void**> (&next_parser));
419 g_critical (
"Tag <%s> not allowed in current context.",
420 name ? (
char*) name :
"(null)");
421 pdata->parsing_ok = FALSE;
422 next_parser = pdata->bad_xml_parser;
426 if (current_frame->parser->before_child)
428 GSList* parent_data_from_children = NULL;
429 gpointer parent_data_for_children = NULL;
431 if (g_slist_length (pdata->stack) > 1)
436 parent_data_from_children = static_cast<decltype (parent_data_from_children)>
437 (parent_frame->data_from_children);
441 current_frame->parser->before_child (current_frame->data_for_children,
442 current_frame->data_from_children,
443 parent_data_from_children,
444 parent_data_for_children,
446 & (current_frame->frame_data),
452 new_frame = sixtp_stack_frame_new (next_parser, g_strdup ((
char*) name));
454 new_frame->line = xmlSAX2GetLineNumber (pdata->saxParserCtxt);
455 new_frame->col = xmlSAX2GetColumnNumber (pdata->saxParserCtxt);
457 pdata->stack = g_slist_prepend (pdata->stack, (gpointer) new_frame);
459 if (next_parser->start_handler)
462 next_parser->start_handler (current_frame->data_from_children,
463 current_frame->data_for_children,
465 &new_frame->data_for_children,
466 &new_frame->frame_data,
473 sixtp_sax_characters_handler (
void* user_data,
const xmlChar* text,
int len)
479 if (frame->parser->characters_handler)
481 gpointer result = NULL;
484 frame->parser->characters_handler (frame->data_from_children,
485 frame->data_for_children,
490 if (pdata->parsing_ok && result)
493 sixtp_child_result* child_data = g_new0 (sixtp_child_result, 1);
495 child_data->type = SIXTP_CHILD_RESULT_CHARS;
496 child_data->tag = NULL;
497 child_data->data = result;
498 child_data->should_cleanup = TRUE;
499 child_data->cleanup_handler = frame->parser->cleanup_chars;
500 child_data->fail_handler = frame->parser->chars_fail_handler;
501 frame->data_from_children = g_slist_prepend (frame->data_from_children,
508 sixtp_sax_end_handler (
void* user_data,
const xmlChar* name)
513 sixtp_child_result* child_result_data = NULL;
514 gchar* end_tag = NULL;
521 if (g_strcmp0 (current_frame->tag, (gchar*) name) != 0)
523 PWARN (
"bad closing tag (start <%s>, end <%s>)", current_frame->tag, name);
524 pdata->parsing_ok = FALSE;
527 if (g_strcmp0 (parent_frame->tag, (gchar*) name) == 0)
529 pdata->stack = sixtp_pop_and_destroy_frame (pdata->stack);
532 PWARN (
"found matching start <%s> tag up one level", name);
537 if (current_frame->parser->end_handler)
540 current_frame->parser->end_handler (current_frame->data_for_children,
541 current_frame->data_from_children,
542 parent_frame->data_from_children,
543 parent_frame->data_for_children,
545 ¤t_frame->frame_data,
549 if (current_frame->frame_data)
552 child_result_data = g_new (sixtp_child_result, 1);
554 child_result_data->type = SIXTP_CHILD_RESULT_NODE;
555 child_result_data->tag = g_strdup (current_frame->tag);
556 child_result_data->data = current_frame->frame_data;
557 child_result_data->should_cleanup = TRUE;
558 child_result_data->cleanup_handler = current_frame->parser->cleanup_result;
559 child_result_data->fail_handler =
560 current_frame->parser->result_fail_handler;
561 parent_frame->data_from_children =
562 g_slist_prepend (parent_frame->data_from_children, child_result_data);
566 end_tag = current_frame->tag;
568 DEBUG (
"Finished with end of <%s>", end_tag ? end_tag :
"(null)");
572 pdata->stack = sixtp_pop_and_destroy_frame (pdata->stack);
578 ((g_slist_length (pdata->stack) > 1) ? (pdata->stack->next->data) : NULL);
580 if (current_frame->parser->after_child)
583 GSList* parent_data_from_children = NULL;
584 gpointer parent_data_for_children = NULL;
591 parent_data_from_children = static_cast<decltype (parent_data_from_children)>
592 (parent_frame->data_for_children);
596 current_frame->parser->after_child (current_frame->data_for_children,
597 current_frame->data_from_children,
598 parent_data_from_children,
599 parent_data_for_children,
601 & (current_frame->frame_data),
611 sixtp_sax_get_entity_handler (
void* user_data,
const xmlChar* name)
613 return xmlGetPredefinedEntity (name);
629 GSList** stack = & (sax_data->stack);
631 g_critical (
"parse failed at:");
632 sixtp_print_frame_stack (sax_data->stack, stderr);
639 if (current_frame->parser->fail_handler)
641 GSList* sibling_data;
642 gpointer parent_data;
644 if ((*stack)->next == NULL)
654 parent_data = parent_frame->data_for_children;
655 sibling_data = parent_frame->data_from_children;
658 current_frame->parser->fail_handler (current_frame->data_for_children,
659 current_frame->data_from_children,
662 sax_data->global_data,
663 ¤t_frame->frame_data,
668 for (lp = current_frame->data_from_children; lp; lp = lp->next)
670 sixtp_child_result* cresult = (sixtp_child_result*) lp->data;
671 if (cresult->fail_handler)
673 cresult->fail_handler (cresult);
677 if ((*stack)->next == NULL)
684 *stack = sixtp_pop_and_destroy_frame (*stack);
689 gnc_bad_xml_end_handler (gpointer data_for_children,
690 GSList* data_from_children, GSList* sibling_data,
691 gpointer parent_data, gpointer global_data,
692 gpointer* result,
const gchar* tag)
699 xmlParserCtxtPtr xml_context,
700 gpointer data_for_top_level,
701 gpointer global_data,
702 gpointer* parse_result)
704 sixtp_parser_context* ctxt;
707 if (! (ctxt = sixtp_context_new (
sixtp, global_data, data_for_top_level)))
709 g_critical (
"sixtp_context_new returned null");
713 ctxt->data.saxParserCtxt = xml_context;
714 ctxt->data.saxParserCtxt->sax = &ctxt->handler;
715 ctxt->data.saxParserCtxt->userData = &ctxt->data;
716 ctxt->data.bad_xml_parser = sixtp_dom_parser_new (gnc_bad_xml_end_handler,
718 parse_ret = xmlParseDocument (ctxt->data.saxParserCtxt);
721 sixtp_context_run_end_handler (ctxt);
723 if (parse_ret == 0 && ctxt->data.parsing_ok)
726 *parse_result = ctxt->top_frame->frame_data;
727 sixtp_context_destroy (ctxt);
733 *parse_result = NULL;
734 if (g_slist_length (ctxt->data.stack) > 1)
735 sixtp_handle_catastrophe (&ctxt->data);
736 sixtp_context_destroy (ctxt);
743 const char* filename,
744 gpointer data_for_top_level,
745 gpointer global_data,
746 gpointer* parse_result)
749 xmlParserCtxtPtr context;
753 gchar* conv_name = g_win32_locale_filename_from_utf8 (filename);
756 PWARN (
"Could not convert '%s' to system codepage", filename);
759 context = xmlCreateFileParserCtxt (conv_name);
763 context = xmlCreateFileParserCtxt (filename);
765 ret = sixtp_parse_file_common (
sixtp, context, data_for_top_level,
766 global_data, parse_result);
772 sixtp_parser_read (
void* context,
char* buffer,
int len)
776 ret = fread (&buffer[0],
sizeof (
char), len, (FILE*) context);
778 PWARN (
"Error reading XML file");
785 gpointer data_for_top_level,
786 gpointer global_data,
787 gpointer* parse_result)
790 xmlParserCtxtPtr context = xmlCreateIOParserCtxt (NULL, NULL,
791 sixtp_parser_read, NULL , fd,
792 XML_CHAR_ENCODING_NONE);
793 ret = sixtp_parse_file_common (
sixtp, context, data_for_top_level,
794 global_data, parse_result);
802 gpointer data_for_top_level,
803 gpointer global_data,
804 gpointer* parse_result)
807 xmlParserCtxtPtr context = xmlCreateMemoryParserCtxt (bufp, bufsz);
808 ret = sixtp_parse_file_common (
sixtp, context, data_for_top_level,
809 global_data, parse_result);
815 sixtp_push_handler push_handler,
816 gpointer push_user_data,
817 gpointer data_for_top_level,
818 gpointer global_data,
819 gpointer* parse_result)
821 sixtp_parser_context* ctxt;
822 xmlParserCtxtPtr xml_context;
826 g_critical (
"No push handler specified");
830 if (! (ctxt = sixtp_context_new (
sixtp, global_data, data_for_top_level)))
832 g_critical (
"sixtp_context_new returned null");
836 xml_context = xmlCreatePushParserCtxt (&ctxt->handler, &ctxt->data,
838 ctxt->data.saxParserCtxt = xml_context;
839 ctxt->data.bad_xml_parser = sixtp_dom_parser_new (gnc_bad_xml_end_handler,
842 (*push_handler) (xml_context, push_user_data);
844 sixtp_context_run_end_handler (ctxt);
846 if (ctxt->data.parsing_ok)
849 *parse_result = ctxt->top_frame->frame_data;
850 sixtp_context_destroy (ctxt);
856 *parse_result = NULL;
857 if (g_slist_length (ctxt->data.stack) > 1)
858 sixtp_handle_catastrophe (&ctxt->data);
859 sixtp_context_destroy (ctxt);
866 eat_whitespace (
char** cursor)
868 while (**cursor && isspace (**cursor))
873 if (**cursor ==
'\0')
884 search_for (
unsigned char marker,
char** cursor)
886 while (**cursor &&** cursor != marker)
891 if (**cursor ==
'\0')
903 gnc_is_our_xml_file (
const char* filename, gboolean* with_encoding)
906 char first_chunk[256];
909 g_return_val_if_fail (filename, GNC_BOOK_NOT_OURS);
911 f = g_fopen (filename,
"r");
914 return GNC_BOOK_NOT_OURS;
917 num_read = fread (first_chunk,
sizeof (
char),
sizeof (first_chunk) - 1, f);
922 return GNC_BOOK_NOT_OURS;
925 first_chunk[num_read] =
'\0';
927 return gnc_is_our_first_xml_chunk (first_chunk, with_encoding);
931 gnc_is_our_first_xml_chunk (
char* chunk, gboolean* with_encoding)
938 *with_encoding = FALSE;
943 if (!eat_whitespace (&cursor))
945 return GNC_BOOK_NOT_OURS;
948 if (strncmp (cursor,
"<?xml", 5) == 0)
950 if (!search_for (
'>', &cursor))
952 return GNC_BOOK_NOT_OURS;
955 if (!eat_whitespace (&cursor))
957 return GNC_BOOK_NOT_OURS;
962 return GNC_BOOK_NOT_OURS;
965 n = strlen (gnc_v2_xml_version_string);
966 if ((strncmp (cursor + 1, gnc_v2_xml_version_string, n) == 0)
967 && isspace (* (cursor + 1 + n)))
973 while (search_for (
'e', &cursor))
975 if (strncmp (cursor,
"ncoding=", 8) == 0)
977 *with_encoding = TRUE;
982 return GNC_BOOK_XML2_FILE;
985 if (strncmp (cursor,
"<gnc>", strlen (
"<gnc>")) == 0)
986 return GNC_BOOK_XML1_FILE;
990 if (strncmp (cursor,
"<gnc-v", strlen (
"<gnc-v")) == 0)
991 return GNC_BOOK_POST_XML2_0_0_FILE;
993 return GNC_BOOK_NOT_OURS;
996 return GNC_BOOK_NOT_OURS;
1000 sixtp_run_callback (
sixtp_gdv2* data,
const char* type)
1002 if (data->countCallback)
1004 data->countCallback (data, type);
#define DEBUG(format, args...)
Print a debugging message.
#define PWARN(format, args...)
Log a warning.