LCOV - code coverage report
Current view: top level - libgnucash/backend/xml - sixtp.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 60.7 % 405 246
Test Date: 2025-02-07 16:25:45 Functions: 71.1 % 38 27
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************
       2                 :             :  * sixtp.c -- functions for XML parsing                             *
       3                 :             :  * Copyright (c) 2001 Gnumatic, Inc.                                *
       4                 :             :  *                                                                  *
       5                 :             :  * This program is free software; you can redistribute it and/or    *
       6                 :             :  * modify it under the terms of the GNU General Public License as   *
       7                 :             :  * published by the Free Software Foundation; either version 2 of   *
       8                 :             :  * the License, or (at your option) any later version.              *
       9                 :             :  *                                                                  *
      10                 :             :  * This program is distributed in the hope that it will be useful,  *
      11                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      12                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      13                 :             :  * GNU General Public License for more details.                     *
      14                 :             :  *                                                                  *
      15                 :             :  * You should have received a copy of the GNU General Public License*
      16                 :             :  * along with this program; if not, contact:                        *
      17                 :             :  *                                                                  *
      18                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      19                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      20                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      21                 :             :  *                                                                  *
      22                 :             :  ********************************************************************/
      23                 :             : #include <glib.h>
      24                 :             : #include <glib/gstdio.h>
      25                 :             : 
      26                 :             : #include <config.h>
      27                 :             : #include <string.h>
      28                 :             : #include <ctype.h>
      29                 :             : #include <stdarg.h>
      30                 :             : #include <stdio.h>
      31                 :             : #include <sys/types.h>
      32                 :             : #include <qoflog.h>
      33                 :             : #ifdef _MSC_VER
      34                 :             :     typedef int ssize_t;
      35                 :             : # define g_fopen fopen
      36                 :             : #endif
      37                 :             : 
      38                 :             : #include "sixtp.h"
      39                 :             : #include "sixtp-parsers.h"
      40                 :             : #include "sixtp-stack.h"
      41                 :             : 
      42                 :             : #undef G_LOG_DOMAIN
      43                 :             : #define G_LOG_DOMAIN "gnc.backend.file.sixtp"
      44                 :             : static QofLogModule log_module = "gnc.backend.file.sixtp";
      45                 :             : 
      46                 :             : extern const gchar* gnc_v2_xml_version_string;        /* see io-gncxml-v2.c */
      47                 :             : 
      48                 :             : /************************************************************************/
      49                 :             : gboolean
      50                 :           0 : is_child_result_from_node_named (sixtp_child_result* cr, const char* tag)
      51                 :             : {
      52                 :           0 :     return ((cr->type == SIXTP_CHILD_RESULT_NODE)
      53                 :           0 :             &&
      54                 :           0 :             (g_strcmp0 (cr->tag, tag) == 0));
      55                 :             : }
      56                 :             : 
      57                 :             : void
      58                 :           0 : sixtp_child_free_data (sixtp_child_result* result)
      59                 :             : {
      60                 :           0 :     if (result->data) g_free (result->data);
      61                 :           0 : }
      62                 :             : 
      63                 :             : void
      64                 :        3113 : sixtp_child_result_destroy (sixtp_child_result* r)
      65                 :             : {
      66                 :        3113 :     if (r->should_cleanup && r->cleanup_handler)
      67                 :             :     {
      68                 :         746 :         r->cleanup_handler (r);
      69                 :             :     }
      70                 :        3113 :     if (r->type == SIXTP_CHILD_RESULT_NODE) g_free (r->tag);
      71                 :        3113 :     g_free (r);
      72                 :        3113 : }
      73                 :             : 
      74                 :             : void
      75                 :           0 : sixtp_child_result_print (sixtp_child_result* cr, FILE* f)
      76                 :             : {
      77                 :           0 :     fprintf (f, "((tag %s) (data %p))",
      78                 :           0 :              cr->tag ? cr->tag : "(null)",
      79                 :             :              cr->data);
      80                 :           0 : }
      81                 :             : 
      82                 :             : /************************************************************************/
      83                 :             : 
      84                 :             : 
      85                 :             : void
      86                 :        1089 : sixtp_set_start (sixtp* parser, sixtp_start_handler start_handler)
      87                 :             : {
      88                 :        1089 :     parser->start_handler = start_handler;
      89                 :        1089 : }
      90                 :             : 
      91                 :             : void
      92                 :           0 : sixtp_set_before_child (sixtp* parser, sixtp_before_child_handler handler)
      93                 :             : {
      94                 :           0 :     parser->before_child = handler;
      95                 :           0 : }
      96                 :             : 
      97                 :             : void
      98                 :          62 : sixtp_set_after_child (sixtp* parser, sixtp_after_child_handler handler)
      99                 :             : {
     100                 :          62 :     parser->after_child = handler;
     101                 :          62 : }
     102                 :             : 
     103                 :             : void
     104                 :        1089 : sixtp_set_end (sixtp* parser, sixtp_end_handler end_handler)
     105                 :             : {
     106                 :        1089 :     parser->end_handler = end_handler;
     107                 :        1089 : }
     108                 :             : 
     109                 :             : void
     110                 :        1089 : sixtp_set_chars (sixtp* parser, sixtp_characters_handler char_handler)
     111                 :             : {
     112                 :        1089 :     parser->characters_handler = char_handler;
     113                 :        1089 : }
     114                 :             : 
     115                 :             : void
     116                 :         124 : sixtp_set_cleanup_result (sixtp* parser, sixtp_result_handler handler)
     117                 :             : {
     118                 :         124 :     parser->cleanup_result = handler;
     119                 :         124 : }
     120                 :             : 
     121                 :             : void
     122                 :           0 : sixtp_set_cleanup_chars (sixtp* parser, sixtp_result_handler handler)
     123                 :             : {
     124                 :           0 :     parser->cleanup_chars = handler;
     125                 :           0 : }
     126                 :             : 
     127                 :             : void
     128                 :        1027 : sixtp_set_fail (sixtp* parser,
     129                 :             :                 sixtp_fail_handler handler)
     130                 :             : {
     131                 :        1027 :     parser->fail_handler = handler;
     132                 :        1027 : }
     133                 :             : 
     134                 :             : void
     135                 :         124 : sixtp_set_result_fail (sixtp* parser, sixtp_result_handler handler)
     136                 :             : {
     137                 :         124 :     parser->result_fail_handler = handler;
     138                 :         124 : }
     139                 :             : 
     140                 :             : void
     141                 :           0 : sixtp_set_chars_fail (sixtp* parser, sixtp_result_handler handler)
     142                 :             : {
     143                 :           0 :     parser->chars_fail_handler = handler;
     144                 :           0 : }
     145                 :             : 
     146                 :             : sixtp*
     147                 :        1240 : sixtp_new (void)
     148                 :             : {
     149                 :        1240 :     sixtp* s = g_new0 (sixtp, 1);
     150                 :             : 
     151                 :        1240 :     if (s)
     152                 :             :     {
     153                 :        1240 :         s->child_parsers = g_hash_table_new (g_str_hash, g_str_equal);
     154                 :        1240 :         if (!s->child_parsers)
     155                 :             :         {
     156                 :           0 :             g_free (s);
     157                 :           0 :             s = NULL;
     158                 :             :         }
     159                 :             :     }
     160                 :        1240 :     return (s);
     161                 :             : }
     162                 :             : 
     163                 :             : sixtp*
     164                 :        1089 : sixtp_set_any (sixtp* tochange, int cleanup, ...)
     165                 :             : {
     166                 :             :     va_list ap;
     167                 :             :     sixtp_handler_type type;
     168                 :             : 
     169                 :        1089 :     if (!tochange)
     170                 :             :     {
     171                 :           0 :         PWARN ("Null tochange passed");
     172                 :           0 :         return NULL;
     173                 :             :     }
     174                 :             : 
     175                 :        1089 :     va_start (ap, cleanup);
     176                 :             : 
     177                 :             :     do
     178                 :             :     {
     179                 :        5507 :         type = static_cast<decltype (type)> (va_arg (ap, int));
     180                 :             : 
     181                 :        5507 :         switch (type)
     182                 :             :         {
     183                 :        1089 :         case SIXTP_NO_MORE_HANDLERS:
     184                 :        1089 :             va_end (ap);
     185                 :        1089 :             return tochange;
     186                 :             : 
     187                 :        1089 :         case SIXTP_START_HANDLER_ID:
     188                 :        1089 :             sixtp_set_start (tochange, va_arg (ap, sixtp_start_handler));
     189                 :        1089 :             break;
     190                 :             : 
     191                 :           0 :         case SIXTP_BEFORE_CHILD_HANDLER_ID:
     192                 :           0 :             sixtp_set_before_child (tochange,
     193                 :             :                                     va_arg (ap, sixtp_before_child_handler));
     194                 :           0 :             break;
     195                 :             : 
     196                 :          62 :         case SIXTP_AFTER_CHILD_HANDLER_ID:
     197                 :          62 :             sixtp_set_after_child (tochange,
     198                 :             :                                    va_arg (ap, sixtp_after_child_handler));
     199                 :          62 :             break;
     200                 :             : 
     201                 :        1027 :         case SIXTP_END_HANDLER_ID:
     202                 :        1027 :             sixtp_set_end (tochange, va_arg (ap, sixtp_end_handler));
     203                 :        1027 :             break;
     204                 :             : 
     205                 :        1089 :         case SIXTP_CHARACTERS_HANDLER_ID:
     206                 :        1089 :             sixtp_set_chars (tochange, va_arg (ap, sixtp_characters_handler));
     207                 :        1089 :             break;
     208                 :             : 
     209                 :        1027 :         case SIXTP_FAIL_HANDLER_ID:
     210                 :        1027 :             sixtp_set_fail (tochange, va_arg (ap, sixtp_fail_handler));
     211                 :        1027 :             break;
     212                 :             : 
     213                 :          62 :         case SIXTP_CLEANUP_RESULT_ID:
     214                 :          62 :             sixtp_set_cleanup_result (tochange,
     215                 :             :                                       va_arg (ap, sixtp_result_handler));
     216                 :          62 :             break;
     217                 :             : 
     218                 :           0 :         case SIXTP_CLEANUP_CHARS_ID:
     219                 :           0 :             sixtp_set_cleanup_chars (tochange,
     220                 :             :                                      va_arg (ap, sixtp_result_handler));
     221                 :           0 :             break;
     222                 :             : 
     223                 :          62 :         case SIXTP_RESULT_FAIL_ID:
     224                 :          62 :             sixtp_set_result_fail (tochange, va_arg (ap, sixtp_result_handler));
     225                 :          62 :             break;
     226                 :             : 
     227                 :           0 :         case SIXTP_CHARS_FAIL_ID:
     228                 :           0 :             sixtp_set_chars_fail (tochange, va_arg (ap, sixtp_result_handler));
     229                 :           0 :             break;
     230                 :             : 
     231                 :           0 :         default:
     232                 :           0 :             va_end (ap);
     233                 :           0 :             g_critical ("Bogus sixtp type %d", type);
     234                 :           0 :             if (cleanup)
     235                 :             :             {
     236                 :           0 :                 sixtp_destroy (tochange);
     237                 :             :             }
     238                 :           0 :             return NULL;
     239                 :             :         }
     240                 :             :     }
     241                 :             :     while (1);
     242                 :             : 
     243                 :             :     va_end (ap);
     244                 :             :     return tochange;
     245                 :             : }
     246                 :             : 
     247                 :             : static void sixtp_destroy_child (gpointer key, gpointer value,
     248                 :             :                                  gpointer user_data);
     249                 :             : 
     250                 :             : static void
     251                 :         711 : sixtp_destroy_node (sixtp* sp, GHashTable* corpses)
     252                 :             : {
     253                 :         711 :     g_return_if_fail (sp);
     254                 :         711 :     g_return_if_fail (corpses);
     255                 :         711 :     g_hash_table_foreach (sp->child_parsers, sixtp_destroy_child, corpses);
     256                 :         711 :     g_hash_table_destroy (sp->child_parsers);
     257                 :         711 :     g_free (sp);
     258                 :             : }
     259                 :             : 
     260                 :             : static void
     261                 :        1236 : sixtp_destroy_child (gpointer key, gpointer value, gpointer user_data)
     262                 :             : {
     263                 :        1236 :     GHashTable* corpses = (GHashTable*) user_data;
     264                 :        1236 :     sixtp* child = (sixtp*) value;
     265                 :             :     gpointer lookup_key;
     266                 :             :     gpointer lookup_value;
     267                 :             : 
     268                 :        1236 :     DEBUG ("Killing sixtp child under key <%s>", key ? (char*) key : "(null)");
     269                 :             : 
     270                 :        1236 :     if (!corpses)
     271                 :             :     {
     272                 :           0 :         g_critical ("no corpses in sixtp_destroy_child <%s>",
     273                 :             :                     key ? (char*) key : "(null)");
     274                 :           0 :         g_free (key);
     275                 :           0 :         return;
     276                 :             :     }
     277                 :        1236 :     if (!child)
     278                 :             :     {
     279                 :           0 :         g_critical ("no child in sixtp_destroy_child <%s>",
     280                 :             :                     key ? (char*) key : "");
     281                 :           0 :         g_free (key);
     282                 :           0 :         return;
     283                 :             :     }
     284                 :        1236 :     g_free (key);
     285                 :             : 
     286                 :        1236 :     if (!g_hash_table_lookup_extended (corpses, (gconstpointer) child,
     287                 :             :                                        &lookup_key, &lookup_value))
     288                 :             :     {
     289                 :             :         /* haven't killed this one yet. */
     290                 :         670 :         g_hash_table_insert (corpses, child, (gpointer) 1);
     291                 :         670 :         sixtp_destroy_node (child, corpses);
     292                 :             :     }
     293                 :             : }
     294                 :             : 
     295                 :             : void
     296                 :          41 : sixtp_destroy (sixtp* sp)
     297                 :             : {
     298                 :             :     GHashTable* corpses;
     299                 :          41 :     g_return_if_fail (sp);
     300                 :          41 :     corpses = g_hash_table_new (g_direct_hash, g_direct_equal);
     301                 :          41 :     sixtp_destroy_node (sp, corpses);
     302                 :          41 :     g_hash_table_destroy (corpses);
     303                 :             : }
     304                 :             : 
     305                 :             : 
     306                 :             : /***********************************************************************/
     307                 :             : 
     308                 :             : gboolean
     309                 :        1935 : sixtp_add_sub_parser (sixtp* parser, const gchar* tag, sixtp* sub_parser)
     310                 :             : {
     311                 :        1935 :     g_return_val_if_fail (parser, FALSE);
     312                 :        1935 :     g_return_val_if_fail (tag, FALSE);
     313                 :        1935 :     g_return_val_if_fail (sub_parser, FALSE);
     314                 :             : 
     315                 :        1935 :     g_hash_table_insert (parser->child_parsers,
     316                 :        1935 :                          g_strdup (tag), (gpointer) sub_parser);
     317                 :        1935 :     return (TRUE);
     318                 :             : }
     319                 :             : 
     320                 :             : /*
     321                 :             :  * This is a bit complex because of having to make sure to
     322                 :             :  * cleanup things we haven't looked at on an error condition
     323                 :             :  */
     324                 :             : sixtp*
     325                 :         340 : sixtp_add_some_sub_parsers (sixtp* tochange, int cleanup, ...)
     326                 :             : {
     327                 :             :     int have_error;
     328                 :             :     va_list ap;
     329                 :             :     char* tag;
     330                 :             :     sixtp* handler;
     331                 :             : 
     332                 :         340 :     va_start (ap, cleanup);
     333                 :             : 
     334                 :         340 :     have_error = 0;
     335                 :             : 
     336                 :         340 :     if (!tochange)
     337                 :             :     {
     338                 :           0 :         have_error = 1;
     339                 :             :     }
     340                 :             : 
     341                 :             :     do
     342                 :             :     {
     343                 :        1186 :         tag = va_arg (ap, char*);
     344                 :        1186 :         if (!tag)
     345                 :             :         {
     346                 :         340 :             break;
     347                 :             :         }
     348                 :             : 
     349                 :         846 :         handler = va_arg (ap, sixtp*);
     350                 :         846 :         if (!handler)
     351                 :             :         {
     352                 :           0 :             PWARN ("Handler for tag %s is null",
     353                 :             :                        tag ? tag : "(null)");
     354                 :             : 
     355                 :           0 :             if (cleanup)
     356                 :             :             {
     357                 :           0 :                 sixtp_destroy (tochange);
     358                 :           0 :                 tochange = NULL;
     359                 :           0 :                 have_error = 1;
     360                 :             :             }
     361                 :             :             else
     362                 :             :             {
     363                 :           0 :                 va_end (ap);
     364                 :           0 :                 return NULL;
     365                 :             :             }
     366                 :             :         }
     367                 :             : 
     368                 :         846 :         if (have_error)
     369                 :             :         {
     370                 :           0 :             sixtp_destroy (handler);
     371                 :             :         }
     372                 :             :         else
     373                 :             :         {
     374                 :         846 :             sixtp_add_sub_parser (tochange, tag, handler);
     375                 :             :         }
     376                 :             :     }
     377                 :             :     while (1);
     378                 :             : 
     379                 :         340 :     va_end (ap);
     380                 :         340 :     return tochange;
     381                 :             : }
     382                 :             : 
     383                 :             : /************************************************************************/
     384                 :             : 
     385                 :             : void
     386                 :       50438 : sixtp_sax_start_handler (void* user_data,
     387                 :             :                          const xmlChar* name,
     388                 :             :                          const xmlChar** attrs)
     389                 :             : {
     390                 :       50438 :     sixtp_sax_data* pdata = (sixtp_sax_data*) user_data;
     391                 :       50438 :     sixtp_stack_frame* current_frame = NULL;
     392                 :       50438 :     sixtp* current_parser = NULL;
     393                 :       50438 :     sixtp* next_parser = NULL;
     394                 :       50438 :     gchar* next_parser_tag = NULL;
     395                 :       50438 :     gboolean lookup_success = FALSE;
     396                 :       50438 :     sixtp_stack_frame* new_frame = NULL;
     397                 :             : 
     398                 :       50438 :     current_frame = (sixtp_stack_frame*) pdata->stack->data;
     399                 :       50438 :     current_parser = current_frame->parser;
     400                 :             : 
     401                 :             :     /* Use an extended lookup so we can get *our* copy of the key.
     402                 :             :        Since we've strduped it, we know its lifetime... */
     403                 :             :     lookup_success =
     404                 :       50438 :         g_hash_table_lookup_extended (current_parser->child_parsers,
     405                 :             :                                       name,
     406                 :             :                                       reinterpret_cast<void**> (&next_parser_tag),
     407                 :             :                                       reinterpret_cast<void**> (&next_parser));
     408                 :             : 
     409                 :             : 
     410                 :       50438 :     if (!lookup_success)
     411                 :             :     {
     412                 :             :         /* magic catch all value */
     413                 :       47319 :         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));
     417                 :       47319 :         if (!lookup_success)
     418                 :             :         {
     419                 :           0 :             g_critical ("Tag <%s> not allowed in current context.",
     420                 :             :                         name ? (char*) name : "(null)");
     421                 :           0 :             pdata->parsing_ok = FALSE;
     422                 :           0 :             next_parser = pdata->bad_xml_parser;
     423                 :             :         }
     424                 :             :     }
     425                 :             : 
     426                 :       50438 :     if (current_frame->parser->before_child)
     427                 :             :     {
     428                 :           0 :         GSList* parent_data_from_children = NULL;
     429                 :           0 :         gpointer parent_data_for_children = NULL;
     430                 :             : 
     431                 :           0 :         if (g_slist_length (pdata->stack) > 1)
     432                 :             :         {
     433                 :             :             /* we're not in the top level node */
     434                 :           0 :             sixtp_stack_frame* parent_frame =
     435                 :           0 :                 (sixtp_stack_frame*) pdata->stack->next->data;
     436                 :           0 :             parent_data_from_children = static_cast<decltype (parent_data_from_children)>
     437                 :             :                                         (parent_frame->data_from_children);
     438                 :             :         }
     439                 :             : 
     440                 :           0 :         pdata->parsing_ok &=
     441                 :           0 :             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,
     445                 :             :                                                  pdata->global_data,
     446                 :             :                                                  & (current_frame->frame_data),
     447                 :           0 :                                                  current_frame->tag,
     448                 :             :                                                  (gchar*) name);
     449                 :             :     }
     450                 :             : 
     451                 :             :     /* now allocate the new stack frame and shift to it */
     452                 :       50438 :     new_frame = sixtp_stack_frame_new (next_parser, g_strdup ((char*) name));
     453                 :             : 
     454                 :       50438 :     new_frame->line = xmlSAX2GetLineNumber (pdata->saxParserCtxt);
     455                 :       50438 :     new_frame->col  = xmlSAX2GetColumnNumber (pdata->saxParserCtxt);
     456                 :             : 
     457                 :       50438 :     pdata->stack = g_slist_prepend (pdata->stack, (gpointer) new_frame);
     458                 :             : 
     459                 :       50438 :     if (next_parser->start_handler)
     460                 :             :     {
     461                 :       50362 :         pdata->parsing_ok &=
     462                 :       50362 :             next_parser->start_handler (current_frame->data_from_children,
     463                 :             :                                         current_frame->data_for_children,
     464                 :             :                                         pdata->global_data,
     465                 :             :                                         &new_frame->data_for_children,
     466                 :             :                                         &new_frame->frame_data,
     467                 :             :                                         (gchar*) name,
     468                 :             :                                         (gchar**)attrs);
     469                 :             :     }
     470                 :       50438 : }
     471                 :             : 
     472                 :             : void
     473                 :      106046 : sixtp_sax_characters_handler (void* user_data, const xmlChar* text, int len)
     474                 :             : {
     475                 :      106046 :     sixtp_sax_data* pdata = (sixtp_sax_data*) user_data;
     476                 :             :     sixtp_stack_frame* frame;
     477                 :             : 
     478                 :      106046 :     frame = (sixtp_stack_frame*) pdata->stack->data;
     479                 :      106046 :     if (frame->parser->characters_handler)
     480                 :             :     {
     481                 :      103672 :         gpointer result = NULL;
     482                 :             : 
     483                 :      103672 :         pdata->parsing_ok &=
     484                 :      103672 :             frame->parser->characters_handler (frame->data_from_children,
     485                 :             :                                                frame->data_for_children,
     486                 :             :                                                pdata->global_data,
     487                 :             :                                                &result,
     488                 :             :                                                (gchar*) text,
     489                 :             :                                                len);
     490                 :      103672 :         if (pdata->parsing_ok && result)
     491                 :             :         {
     492                 :             :             /* push the result onto the current "child" list. */
     493                 :           0 :             sixtp_child_result* child_data = g_new0 (sixtp_child_result, 1);
     494                 :             : 
     495                 :           0 :             child_data->type = SIXTP_CHILD_RESULT_CHARS;
     496                 :           0 :             child_data->tag = NULL;
     497                 :           0 :             child_data->data = result;
     498                 :           0 :             child_data->should_cleanup = TRUE;
     499                 :           0 :             child_data->cleanup_handler = frame->parser->cleanup_chars;
     500                 :           0 :             child_data->fail_handler = frame->parser->chars_fail_handler;
     501                 :           0 :             frame->data_from_children = g_slist_prepend (frame->data_from_children,
     502                 :             :                                                          child_data);
     503                 :             :         }
     504                 :             :     }
     505                 :      106046 : }
     506                 :             : 
     507                 :             : void
     508                 :       50438 : sixtp_sax_end_handler (void* user_data, const xmlChar* name)
     509                 :             : {
     510                 :       50438 :     sixtp_sax_data* pdata = (sixtp_sax_data*) user_data;
     511                 :             :     sixtp_stack_frame* current_frame;
     512                 :             :     sixtp_stack_frame* parent_frame;
     513                 :       50438 :     sixtp_child_result* child_result_data = NULL;
     514                 :       50438 :     gchar* end_tag = NULL;
     515                 :             : 
     516                 :       50438 :     current_frame = (sixtp_stack_frame*) pdata->stack->data;
     517                 :       50438 :     parent_frame = (sixtp_stack_frame*) pdata->stack->next->data;
     518                 :             : 
     519                 :             :     /* time to make sure we got the right closing tag.  Is this really
     520                 :             :        necessary? */
     521                 :       50438 :     if (g_strcmp0 (current_frame->tag, (gchar*) name) != 0)
     522                 :             :     {
     523                 :           0 :         PWARN ("bad closing tag (start <%s>, end <%s>)", current_frame->tag, name);
     524                 :           0 :         pdata->parsing_ok = FALSE;
     525                 :             : 
     526                 :             :         /* See if we're just off by one and try to recover */
     527                 :           0 :         if (g_strcmp0 (parent_frame->tag, (gchar*) name) == 0)
     528                 :             :         {
     529                 :           0 :             pdata->stack = sixtp_pop_and_destroy_frame (pdata->stack);
     530                 :           0 :             current_frame = (sixtp_stack_frame*) pdata->stack->data;
     531                 :           0 :             parent_frame = (sixtp_stack_frame*) pdata->stack->next->data;
     532                 :           0 :             PWARN ("found matching start <%s> tag up one level", name);
     533                 :             :         }
     534                 :             :     }
     535                 :             : 
     536                 :             :     /* tag's OK, proceed. */
     537                 :       50438 :     if (current_frame->parser->end_handler)
     538                 :             :     {
     539                 :       50362 :         pdata->parsing_ok &=
     540                 :       50362 :             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,
     544                 :             :                                                 pdata->global_data,
     545                 :             :                                                 &current_frame->frame_data,
     546                 :       50362 :                                                 current_frame->tag);
     547                 :             :     }
     548                 :             : 
     549                 :       50438 :     if (current_frame->frame_data)
     550                 :             :     {
     551                 :             :         /* push the result onto the parent's child result list. */
     552                 :        3113 :         child_result_data = g_new (sixtp_child_result, 1);
     553                 :             : 
     554                 :        3113 :         child_result_data->type = SIXTP_CHILD_RESULT_NODE;
     555                 :        3113 :         child_result_data->tag = g_strdup (current_frame->tag);
     556                 :        3113 :         child_result_data->data = current_frame->frame_data;
     557                 :        3113 :         child_result_data->should_cleanup = TRUE;
     558                 :        3113 :         child_result_data->cleanup_handler = current_frame->parser->cleanup_result;
     559                 :        3113 :         child_result_data->fail_handler =
     560                 :        3113 :             current_frame->parser->result_fail_handler;
     561                 :        3113 :         parent_frame->data_from_children =
     562                 :        3113 :             g_slist_prepend (parent_frame->data_from_children, child_result_data);
     563                 :             :     }
     564                 :             : 
     565                 :             :     /* grab it before it goes away - we own the reference */
     566                 :       50438 :     end_tag = current_frame->tag;
     567                 :             : 
     568                 :       50438 :     DEBUG ("Finished with end of <%s>", end_tag ? end_tag : "(null)");
     569                 :             : 
     570                 :             :     /*sixtp_print_frame_stack(pdata->stack, stderr);*/
     571                 :             : 
     572                 :       50438 :     pdata->stack = sixtp_pop_and_destroy_frame (pdata->stack);
     573                 :             : 
     574                 :             :     /* reset pointer after stack pop */
     575                 :       50438 :     current_frame = (sixtp_stack_frame*) pdata->stack->data;
     576                 :             :     /* reset the parent, checking to see if we're at the top level node */
     577                 :         166 :     parent_frame = (sixtp_stack_frame*)
     578                 :       50438 :                    ((g_slist_length (pdata->stack) > 1) ? (pdata->stack->next->data) : NULL);
     579                 :             : 
     580                 :       50438 :     if (current_frame->parser->after_child)
     581                 :             :     {
     582                 :             :         /* reset pointer after stack pop */
     583                 :         746 :         GSList* parent_data_from_children = NULL;
     584                 :         746 :         gpointer parent_data_for_children = NULL;
     585                 :             : 
     586                 :         746 :         if (parent_frame)
     587                 :             :         {
     588                 :             :             /* we're not in the top level node */
     589                 :         746 :             sixtp_stack_frame* parent_frame =
     590                 :         746 :                 (sixtp_stack_frame*) pdata->stack->next->data;
     591                 :         746 :             parent_data_from_children = static_cast<decltype (parent_data_from_children)>
     592                 :             :                                         (parent_frame->data_for_children);
     593                 :             :         }
     594                 :             : 
     595                 :         746 :         pdata->parsing_ok &=
     596                 :         746 :             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,
     600                 :             :                                                 pdata->global_data,
     601                 :             :                                                 & (current_frame->frame_data),
     602                 :         746 :                                                 current_frame->tag,
     603                 :             :                                                 end_tag,
     604                 :             :                                                 child_result_data);
     605                 :             :     }
     606                 :             : 
     607                 :       50438 :     g_free (end_tag);
     608                 :       50438 : }
     609                 :             : 
     610                 :             : xmlEntityPtr
     611                 :           0 : sixtp_sax_get_entity_handler (void* user_data, const xmlChar* name)
     612                 :             : {
     613                 :           0 :     return xmlGetPredefinedEntity (name);
     614                 :             : }
     615                 :             : 
     616                 :             : 
     617                 :             : void
     618                 :           0 : sixtp_handle_catastrophe (sixtp_sax_data* sax_data)
     619                 :             : {
     620                 :             :     /* Something has gone wrong.  To handle it, we have to traverse the
     621                 :             :        stack, calling, at each level, the frame failure handler (the
     622                 :             :        handler for the current, unfinished block) and then the sibling
     623                 :             :        handlers.  The order is reverse chronological - oldest child
     624                 :             :        results cleaned up last.  This holds overall as well, stack
     625                 :             :        frames are cleaned up in their order on the stack which will be
     626                 :             :        youngest to oldest.  */
     627                 :             : 
     628                 :             :     GSList* lp;
     629                 :           0 :     GSList** stack = & (sax_data->stack);
     630                 :             : 
     631                 :           0 :     g_critical ("parse failed at:");
     632                 :           0 :     sixtp_print_frame_stack (sax_data->stack, stderr);
     633                 :             : 
     634                 :           0 :     while (*stack)
     635                 :             :     {
     636                 :           0 :         sixtp_stack_frame* current_frame = (sixtp_stack_frame*) (*stack)->data;
     637                 :             : 
     638                 :             :         /* cleanup the current frame */
     639                 :           0 :         if (current_frame->parser->fail_handler)
     640                 :             :         {
     641                 :             :             GSList* sibling_data;
     642                 :             :             gpointer parent_data;
     643                 :             : 
     644                 :           0 :             if ((*stack)->next == NULL)
     645                 :             :             {
     646                 :             :                 /* This is the top of the stack... */
     647                 :           0 :                 parent_data = NULL;
     648                 :           0 :                 sibling_data = NULL;
     649                 :             :             }
     650                 :             :             else
     651                 :             :             {
     652                 :           0 :                 sixtp_stack_frame* parent_frame =
     653                 :           0 :                     (sixtp_stack_frame*) (*stack)->next->data;
     654                 :           0 :                 parent_data = parent_frame->data_for_children;
     655                 :           0 :                 sibling_data = parent_frame->data_from_children;
     656                 :             :             }
     657                 :             : 
     658                 :           0 :             current_frame->parser->fail_handler (current_frame->data_for_children,
     659                 :             :                                                  current_frame->data_from_children,
     660                 :             :                                                  sibling_data,
     661                 :             :                                                  parent_data,
     662                 :             :                                                  sax_data->global_data,
     663                 :             :                                                  &current_frame->frame_data,
     664                 :           0 :                                                  current_frame->tag);
     665                 :             :         }
     666                 :             : 
     667                 :             :         /* now cleanup any children's results */
     668                 :           0 :         for (lp = current_frame->data_from_children; lp; lp = lp->next)
     669                 :             :         {
     670                 :           0 :             sixtp_child_result* cresult = (sixtp_child_result*) lp->data;
     671                 :           0 :             if (cresult->fail_handler)
     672                 :             :             {
     673                 :           0 :                 cresult->fail_handler (cresult);
     674                 :             :             }
     675                 :             :         }
     676                 :             : 
     677                 :           0 :         if ((*stack)->next == NULL)
     678                 :             :         {
     679                 :             :             /* This is the top of the stack. The top frame seems to want to
     680                 :             :              * be destroyed by sixtp_context_destroy. */
     681                 :           0 :             break;
     682                 :             :         }
     683                 :             : 
     684                 :           0 :         *stack = sixtp_pop_and_destroy_frame (*stack);
     685                 :             :     }
     686                 :           0 : }
     687                 :             : 
     688                 :             : static gboolean
     689                 :           0 : 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)
     693                 :             : {
     694                 :           0 :     return TRUE;
     695                 :             : }
     696                 :             : 
     697                 :             : static gboolean
     698                 :         166 : sixtp_parse_file_common (sixtp* sixtp,
     699                 :             :                          xmlParserCtxtPtr xml_context,
     700                 :             :                          gpointer data_for_top_level,
     701                 :             :                          gpointer global_data,
     702                 :             :                          gpointer* parse_result)
     703                 :             : {
     704                 :             :     sixtp_parser_context* ctxt;
     705                 :             :     int parse_ret;
     706                 :             : 
     707                 :         166 :     if (! (ctxt = sixtp_context_new (sixtp, global_data, data_for_top_level)))
     708                 :             :     {
     709                 :           0 :         g_critical ("sixtp_context_new returned null");
     710                 :           0 :         return FALSE;
     711                 :             :     }
     712                 :             : 
     713                 :         166 :     ctxt->data.saxParserCtxt = xml_context;
     714                 :         166 :     ctxt->data.saxParserCtxt->sax = &ctxt->handler;
     715                 :         166 :     ctxt->data.saxParserCtxt->userData = &ctxt->data;
     716                 :         166 :     ctxt->data.bad_xml_parser = sixtp_dom_parser_new (gnc_bad_xml_end_handler,
     717                 :             :                                                       NULL, NULL);
     718                 :         166 :     parse_ret = xmlParseDocument (ctxt->data.saxParserCtxt);
     719                 :             :     //xmlSAXUserParseFile(&ctxt->handler, &ctxt->data, filename);
     720                 :             : 
     721                 :         166 :     sixtp_context_run_end_handler (ctxt);
     722                 :             : 
     723                 :         166 :     if (parse_ret == 0 && ctxt->data.parsing_ok)
     724                 :             :     {
     725                 :         166 :         if (parse_result)
     726                 :         166 :             *parse_result = ctxt->top_frame->frame_data;
     727                 :         166 :         sixtp_context_destroy (ctxt);
     728                 :         166 :         return TRUE;
     729                 :             :     }
     730                 :             :     else
     731                 :             :     {
     732                 :           0 :         if (parse_result)
     733                 :           0 :             *parse_result = NULL;
     734                 :           0 :         if (g_slist_length (ctxt->data.stack) > 1)
     735                 :           0 :             sixtp_handle_catastrophe (&ctxt->data);
     736                 :           0 :         sixtp_context_destroy (ctxt);
     737                 :           0 :         return FALSE;
     738                 :             :     }
     739                 :             : }
     740                 :             : 
     741                 :             : gboolean
     742                 :         145 : sixtp_parse_file (sixtp* sixtp,
     743                 :             :                   const char* filename,
     744                 :             :                   gpointer data_for_top_level,
     745                 :             :                   gpointer global_data,
     746                 :             :                   gpointer* parse_result)
     747                 :             : {
     748                 :             :     gboolean ret;
     749                 :             :     xmlParserCtxtPtr context;
     750                 :             : 
     751                 :             : #ifdef G_OS_WIN32
     752                 :             :     {
     753                 :             :         gchar* conv_name = g_win32_locale_filename_from_utf8 (filename);
     754                 :             :         if (!conv_name)
     755                 :             :         {
     756                 :             :             PWARN ("Could not convert '%s' to system codepage", filename);
     757                 :             :             return FALSE;
     758                 :             :         }
     759                 :             :         context = xmlCreateFileParserCtxt (conv_name);
     760                 :             :         g_free (conv_name);
     761                 :             :     }
     762                 :             : #else
     763                 :         145 :     context = xmlCreateFileParserCtxt (filename);
     764                 :             : #endif
     765                 :         145 :     ret = sixtp_parse_file_common (sixtp, context, data_for_top_level,
     766                 :             :                                    global_data, parse_result);
     767                 :         145 :     return ret;
     768                 :             : }
     769                 :             : 
     770                 :             : /* Call back function for libxml2 to read from compressed or uncompressed stream */
     771                 :             : static int
     772                 :         389 : sixtp_parser_read (void* context, char* buffer, int len)
     773                 :             : {
     774                 :             :     int ret;
     775                 :             : 
     776                 :         389 :     ret = fread (&buffer[0], sizeof (char), len, (FILE*) context);
     777                 :         389 :     if (ret < 0)
     778                 :           0 :         PWARN ("Error reading XML file");
     779                 :         389 :     return ret;
     780                 :             : }
     781                 :             : 
     782                 :             : gboolean
     783                 :          21 : sixtp_parse_fd (sixtp* sixtp,
     784                 :             :                 FILE* fd,
     785                 :             :                 gpointer data_for_top_level,
     786                 :             :                 gpointer global_data,
     787                 :             :                 gpointer* parse_result)
     788                 :             : {
     789                 :             :     gboolean ret;
     790                 :          21 :     xmlParserCtxtPtr context = xmlCreateIOParserCtxt (NULL, NULL,
     791                 :             :                                                       sixtp_parser_read, NULL /*no close */, fd,
     792                 :             :                                                       XML_CHAR_ENCODING_NONE);
     793                 :          21 :     ret = sixtp_parse_file_common (sixtp, context, data_for_top_level,
     794                 :             :                                    global_data, parse_result);
     795                 :          21 :     return ret;
     796                 :             : }
     797                 :             : 
     798                 :             : gboolean
     799                 :           0 : sixtp_parse_buffer (sixtp* sixtp,
     800                 :             :                     char* bufp,
     801                 :             :                     int bufsz,
     802                 :             :                     gpointer data_for_top_level,
     803                 :             :                     gpointer global_data,
     804                 :             :                     gpointer* parse_result)
     805                 :             : {
     806                 :             :     gboolean ret;
     807                 :           0 :     xmlParserCtxtPtr context = xmlCreateMemoryParserCtxt (bufp, bufsz);
     808                 :           0 :     ret = sixtp_parse_file_common (sixtp, context, data_for_top_level,
     809                 :             :                                    global_data, parse_result);
     810                 :           0 :     return ret;
     811                 :             : }
     812                 :             : 
     813                 :             : gboolean
     814                 :           0 : sixtp_parse_push (sixtp* sixtp,
     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)
     820                 :             : {
     821                 :             :     sixtp_parser_context* ctxt;
     822                 :             :     xmlParserCtxtPtr xml_context;
     823                 :             : 
     824                 :           0 :     if (!push_handler)
     825                 :             :     {
     826                 :           0 :         g_critical ("No push handler specified");
     827                 :           0 :         return FALSE;
     828                 :             :     }
     829                 :             : 
     830                 :           0 :     if (! (ctxt = sixtp_context_new (sixtp, global_data, data_for_top_level)))
     831                 :             :     {
     832                 :           0 :         g_critical ("sixtp_context_new returned null");
     833                 :           0 :         return FALSE;
     834                 :             :     }
     835                 :             : 
     836                 :           0 :     xml_context = xmlCreatePushParserCtxt (&ctxt->handler, &ctxt->data,
     837                 :             :                                            NULL, 0, NULL);
     838                 :           0 :     ctxt->data.saxParserCtxt = xml_context;
     839                 :           0 :     ctxt->data.bad_xml_parser = sixtp_dom_parser_new (gnc_bad_xml_end_handler,
     840                 :             :                                                       NULL, NULL);
     841                 :             : 
     842                 :           0 :     (*push_handler) (xml_context, push_user_data);
     843                 :             : 
     844                 :           0 :     sixtp_context_run_end_handler (ctxt);
     845                 :             : 
     846                 :           0 :     if (ctxt->data.parsing_ok)
     847                 :             :     {
     848                 :           0 :         if (parse_result)
     849                 :           0 :             *parse_result = ctxt->top_frame->frame_data;
     850                 :           0 :         sixtp_context_destroy (ctxt);
     851                 :           0 :         return TRUE;
     852                 :             :     }
     853                 :             :     else
     854                 :             :     {
     855                 :           0 :         if (parse_result)
     856                 :           0 :             *parse_result = NULL;
     857                 :           0 :         if (g_slist_length (ctxt->data.stack) > 1)
     858                 :           0 :             sixtp_handle_catastrophe (&ctxt->data);
     859                 :           0 :         sixtp_context_destroy (ctxt);
     860                 :           0 :         return FALSE;
     861                 :             :     }
     862                 :             : }
     863                 :             : 
     864                 :             : /***********************************************************************/
     865                 :             : static gboolean
     866                 :          86 : eat_whitespace (char** cursor)
     867                 :             : {
     868                 :         129 :     while (**cursor && isspace (**cursor))
     869                 :             :     {
     870                 :          43 :         (*cursor)++;
     871                 :             :     }
     872                 :             : 
     873                 :          86 :     if (**cursor == '\0')
     874                 :             :     {
     875                 :           0 :         return FALSE;
     876                 :             :     }
     877                 :             :     else
     878                 :             :     {
     879                 :          86 :         return TRUE;
     880                 :             :     }
     881                 :             : }
     882                 :             : 
     883                 :             : static gboolean
     884                 :          85 : search_for (unsigned char marker, char** cursor)
     885                 :             : {
     886                 :        2118 :     while (**cursor &&** cursor != marker)
     887                 :             :     {
     888                 :        2033 :         (*cursor)++;
     889                 :             :     }
     890                 :             : 
     891                 :          85 :     if (**cursor == '\0')
     892                 :             :     {
     893                 :           0 :         return FALSE;
     894                 :             :     }
     895                 :             :     else
     896                 :             :     {
     897                 :          85 :         (*cursor)++;
     898                 :          85 :         return TRUE;
     899                 :             :     }
     900                 :             : }
     901                 :             : 
     902                 :             : QofBookFileType
     903                 :          39 : gnc_is_our_xml_file (const char* filename, gboolean* with_encoding)
     904                 :             : {
     905                 :          39 :     FILE* f = NULL;
     906                 :             :     char first_chunk[256];
     907                 :             :     ssize_t num_read;
     908                 :             : 
     909                 :          39 :     g_return_val_if_fail (filename, GNC_BOOK_NOT_OURS);
     910                 :             : 
     911                 :          39 :     f = g_fopen (filename, "r");
     912                 :          39 :     if (f == NULL)
     913                 :             :     {
     914                 :           0 :         return GNC_BOOK_NOT_OURS;
     915                 :             :     }
     916                 :             : 
     917                 :          39 :     num_read = fread (first_chunk, sizeof (char), sizeof (first_chunk) - 1, f);
     918                 :          39 :     fclose (f);
     919                 :             : 
     920                 :          39 :     if (num_read == 0)
     921                 :             :     {
     922                 :           0 :         return GNC_BOOK_NOT_OURS;
     923                 :             :     }
     924                 :             : 
     925                 :          39 :     first_chunk[num_read] = '\0';
     926                 :             : 
     927                 :          39 :     return gnc_is_our_first_xml_chunk (first_chunk, with_encoding);
     928                 :             : }
     929                 :             : 
     930                 :             : QofBookFileType
     931                 :          43 : gnc_is_our_first_xml_chunk (char* chunk, gboolean* with_encoding)
     932                 :             : {
     933                 :          43 :     char* cursor = NULL;
     934                 :             :     size_t n;
     935                 :             : 
     936                 :          43 :     if (with_encoding)
     937                 :             :     {
     938                 :          21 :         *with_encoding = FALSE;
     939                 :             :     }
     940                 :             : 
     941                 :          43 :     cursor = chunk;
     942                 :             : 
     943                 :          43 :     if (!eat_whitespace (&cursor))
     944                 :             :     {
     945                 :           0 :         return GNC_BOOK_NOT_OURS;
     946                 :             :     }
     947                 :             : 
     948                 :          43 :     if (strncmp (cursor, "<?xml", 5) == 0)
     949                 :             :     {
     950                 :          43 :         if (!search_for ('>', &cursor))
     951                 :             :         {
     952                 :           0 :             return GNC_BOOK_NOT_OURS;
     953                 :             :         }
     954                 :             : 
     955                 :          43 :         if (!eat_whitespace (&cursor))
     956                 :             :         {
     957                 :           0 :             return GNC_BOOK_NOT_OURS;
     958                 :             :         }
     959                 :             : 
     960                 :          43 :         if (*cursor != '<')
     961                 :             :         {
     962                 :           0 :             return GNC_BOOK_NOT_OURS;
     963                 :             :         }
     964                 :             : 
     965                 :          43 :         n = strlen (gnc_v2_xml_version_string);
     966                 :          43 :         if ((strncmp (cursor + 1, gnc_v2_xml_version_string, n) == 0)
     967                 :          43 :             && isspace (* (cursor + 1 + n)))
     968                 :             :         {
     969                 :          43 :             if (with_encoding)
     970                 :             :             {
     971                 :          21 :                 *cursor = '\0';
     972                 :          21 :                 cursor = chunk;
     973                 :          42 :                 while (search_for ('e', &cursor))
     974                 :             :                 {
     975                 :          42 :                     if (strncmp (cursor, "ncoding=", 8) == 0)
     976                 :             :                     {
     977                 :          21 :                         *with_encoding = TRUE;
     978                 :          21 :                         break;
     979                 :             :                     }
     980                 :             :                 }
     981                 :             :             }
     982                 :          43 :             return GNC_BOOK_XML2_FILE;
     983                 :             :         }
     984                 :             : 
     985                 :           0 :         if (strncmp (cursor, "<gnc>", strlen ("<gnc>")) == 0)
     986                 :           0 :             return GNC_BOOK_XML1_FILE;
     987                 :             : 
     988                 :             :         /* If it doesn't match any of the above but has '<gnc-v...', it must */
     989                 :             :         /* be a later version */
     990                 :           0 :         if (strncmp (cursor, "<gnc-v", strlen ("<gnc-v")) == 0)
     991                 :           0 :             return GNC_BOOK_POST_XML2_0_0_FILE;
     992                 :             : 
     993                 :           0 :         return GNC_BOOK_NOT_OURS;
     994                 :             :     }
     995                 :             : 
     996                 :           0 :     return GNC_BOOK_NOT_OURS;
     997                 :             : }
     998                 :             : 
     999                 :             : void
    1000                 :        2324 : sixtp_run_callback (sixtp_gdv2* data, const char* type)
    1001                 :             : {
    1002                 :        2324 :     if (data->countCallback)
    1003                 :             :     {
    1004                 :        1906 :         data->countCallback (data, type);
    1005                 :             :     }
    1006                 :        2324 : }
    1007                 :             : 
    1008                 :             : /************************* END OF FILE *********************************/
        

Generated by: LCOV version 2.0-1