root/ext/xmlrpc/libxmlrpc/xml_element.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xml_elem_free_non_recurse
  2. xml_elem_free
  3. xml_elem_new
  4. xml_elem_writefunc
  5. create_xml_escape
  6. xml_elem_entity_escape
  7. xml_element_serialize
  8. file_out_fptr
  9. simplestring_out_fptr
  10. xml_elem_serialize_to_string
  11. xml_elem_serialize_to_stream
  12. _xmlrpc_startElement
  13. _xmlrpc_endElement
  14. _xmlrpc_charHandler
  15. xml_elem_parse_buf

   1 /*
   2   This file is part of libXMLRPC - a C library for xml-encoded function calls.
   3 
   4   Author: Dan Libby (dan@libby.com)
   5   Epinions.com may be contacted at feedback@epinions-inc.com
   6 */
   7 
   8 /*
   9   Copyright 2000 Epinions, Inc.
  10 
  11   Subject to the following 3 conditions, Epinions, Inc.  permits you, free
  12   of charge, to (a) use, copy, distribute, modify, perform and display this
  13   software and associated documentation files (the "Software"), and (b)
  14   permit others to whom the Software is furnished to do so as well.
  15 
  16   1) The above copyright notice and this permission notice shall be included
  17   without modification in all copies or substantial portions of the
  18   Software.
  19 
  20   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
  21   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
  22   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
  23   PURPOSE OR NONINFRINGEMENT.
  24 
  25   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
  26   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
  27   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
  28   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH
  29   DAMAGES.
  30 
  31 */
  32 
  33 
  34 static const char rcsid[] = "#(@) $Id$";
  35 
  36 
  37 
  38 /****h* ABOUT/xml_element
  39  * NAME
  40  *   xml_element
  41  * AUTHOR
  42  *   Dan Libby, aka danda  (dan@libby.com)
  43  * CREATION DATE
  44  *   06/2000
  45  * HISTORY
  46  *   $Log$
  47  *   Revision 1.9.4.1.2.1  2008/12/09 17:22:12  iliaa
  48  *
  49  *   MFH: Fixed bug #46746 (xmlrpc_decode_request outputs non-suppressable error
  50  *   when given bad data).
  51  *
  52  *   Revision 1.9.4.1  2006/07/30 11:34:02  tony2001
  53  *   MFH: fix compile warnings (#38257)
  54  *
  55  *   Revision 1.9  2005/04/22 11:06:53  jorton
  56  *   Fixed bug #32797 (invalid C code in xmlrpc extension).
  57  *
  58  *   Revision 1.8  2005/03/28 00:07:24  edink
  59  *   Reshufle includes to make it compile on windows
  60  *
  61  *   Revision 1.7  2005/03/26 03:13:58  sniper
  62  *   - Made it possible to build ext/xmlrpc with libxml2
  63  *
  64  *   Revision 1.6  2004/06/01 20:16:06  iliaa
  65  *   Fixed bug #28597 (xmlrpc_encode_request() incorrectly encodes chars in
  66  *   200-210 range).
  67  *   Patch by: fernando dot nemec at folha dot com dot br
  68  *
  69  *   Revision 1.5  2003/12/16 21:00:21  sniper
  70  *   Fix some compile warnings (patch by Joe Orton)
  71  *
  72  *   Revision 1.4  2002/11/26 23:01:16  fmk
  73  *   removing unused variables
  74  *
  75  *   Revision 1.3  2002/07/05 04:43:53  danda
  76  *   merged in updates from SF project.  bring php repository up to date with xmlrpc-epi version 0.51
  77  *
  78  *   Revision 1.9  2002/07/03 20:54:30  danda
  79  *   root element should not have a parent. patch from anon SF user
  80  *
  81  *   Revision 1.8  2002/05/23 17:46:51  danda
  82  *   patch from mukund - fix non utf-8 encoding conversions
  83  *
  84  *   Revision 1.7  2002/02/13 20:58:50  danda
  85  *   patch to make source more windows friendly, contributed by Jeff Lawson
  86  *
  87  *   Revision 1.6  2002/01/08 01:06:55  danda
  88  *   enable <?xml version="1.0"?> format for parsers that are very picky.
  89  *
  90  *   Revision 1.5  2001/09/29 21:58:05  danda
  91  *   adding cvs log to history section
  92  *
  93  *   10/15/2000 -- danda -- adding robodoc documentation
  94  * TODO
  95  *   Nicer external API. Get rid of macros.  Make opaque types, etc.
  96  * PORTABILITY
  97  *   Coded on RedHat Linux 6.2.  Builds on Solaris x86.  Should build on just
  98  *   about anything with minor mods.
  99  * NOTES
 100  *   This code incorporates ideas from expat-ensor from http://xml.ensor.org.
 101  *
 102  *   It was coded primarily to act as a go-between for expat and xmlrpc. To this
 103  *   end, it stores xml elements, their sub-elements, and their attributes in an
 104  *   in-memory tree.  When expat is done parsing, the tree can be walked, thus
 105  *   retrieving the values.  The code can also be used to build a tree via API then
 106  *   write out the tree to a buffer, thus "serializing" the xml.
 107  *
 108  *   It turns out this is useful for other purposes, such as parsing config files.
 109  *   YMMV.
 110  *
 111  *   Some Features:
 112  *     - output option for xml escaping data.  Choices include no escaping, entity escaping,
 113  *       or CDATA sections.
 114  *     - output option for character encoding.  Defaults to (none) utf-8.
 115  *     - output option for verbosity/readability.  ultra-compact, newlines, pretty/level indented.
 116  *
 117  * BUGS
 118  *   there must be some.
 119  ******/
 120 
 121 #include "ext/xml/expat_compat.h"
 122 #ifdef _WIN32
 123 #include "xmlrpc_win32.h"
 124 #endif
 125 #include <stdlib.h>
 126 #include <string.h>
 127 #include <ctype.h>
 128 
 129 #include "xml_element.h"
 130 #include "queue.h"
 131 #include "encodings.h"
 132 
 133 #define my_free(thing)  if(thing) {free(thing); thing = NULL;}
 134 
 135 #define XML_DECL_START                 "<?xml"
 136 #define XML_DECL_START_LEN             sizeof(XML_DECL_START) - 1
 137 #define XML_DECL_VERSION               "version=\"1.0\""
 138 #define XML_DECL_VERSION_LEN           sizeof(XML_DECL_VERSION) - 1
 139 #define XML_DECL_ENCODING_ATTR         "encoding"
 140 #define XML_DECL_ENCODING_ATTR_LEN     sizeof(XML_DECL_ENCODING_ATTR) - 1
 141 #define XML_DECL_ENCODING_DEFAULT      "utf-8"
 142 #define XML_DECL_ENCODING_DEFAULT_LEN  sizeof(XML_DECL_ENCODING_DEFAULT) - 1
 143 #define XML_DECL_END                   "?>"
 144 #define XML_DECL_END_LEN               sizeof(XML_DECL_END) - 1
 145 #define START_TOKEN_BEGIN              "<"
 146 #define START_TOKEN_BEGIN_LEN          sizeof(START_TOKEN_BEGIN) - 1
 147 #define START_TOKEN_END                ">"
 148 #define START_TOKEN_END_LEN            sizeof(START_TOKEN_END) - 1
 149 #define EMPTY_START_TOKEN_END          "/>"
 150 #define EMPTY_START_TOKEN_END_LEN      sizeof(EMPTY_START_TOKEN_END) - 1
 151 #define END_TOKEN_BEGIN                "</"
 152 #define END_TOKEN_BEGIN_LEN            sizeof(END_TOKEN_BEGIN) - 1
 153 #define END_TOKEN_END                  ">"
 154 #define END_TOKEN_END_LEN              sizeof(END_TOKEN_END) - 1
 155 #define ATTR_DELIMITER                 "\""
 156 #define ATTR_DELIMITER_LEN             sizeof(ATTR_DELIMITER) - 1
 157 #define CDATA_BEGIN                    "<![CDATA["
 158 #define CDATA_BEGIN_LEN                sizeof(CDATA_BEGIN) - 1
 159 #define CDATA_END                      "]]>"
 160 #define CDATA_END_LEN                  sizeof(CDATA_END) - 1
 161 #define EQUALS                         "="
 162 #define EQUALS_LEN                     sizeof(EQUALS) - 1
 163 #define WHITESPACE                     " "
 164 #define WHITESPACE_LEN                 sizeof(WHITESPACE) - 1
 165 #define NEWLINE                        "\n"
 166 #define NEWLINE_LEN                    sizeof(NEWLINE) - 1
 167 #define MAX_VAL_BUF                    144
 168 #define SCALAR_STR                     "SCALAR"
 169 #define SCALAR_STR_LEN                 sizeof(SCALAR_STR) - 1
 170 #define VECTOR_STR                     "VECTOR"
 171 #define VECTOR_STR_LEN                 sizeof(VECTOR_STR) - 1
 172 #define RESPONSE_STR                   "RESPONSE"
 173 #define RESPONSE_STR_LEN               sizeof(RESPONSE_STR) - 1
 174 
 175 
 176 /*-----------------------------
 177 - Begin xml_element Functions -
 178 -----------------------------*/
 179 
 180 /****f* xml_element/xml_elem_free_non_recurse
 181  * NAME
 182  *   xml_elem_free_non_recurse
 183  * SYNOPSIS
 184  *   void xml_elem_free_non_recurse(xml_element* root)
 185  * FUNCTION
 186  *   free a single xml element.  child elements will not be freed.
 187  * INPUTS
 188  *   root - the element to free
 189  * RESULT
 190  *   void
 191  * NOTES
 192  * SEE ALSO
 193  *   xml_elem_free ()
 194  *   xml_elem_new ()
 195  * SOURCE
 196  */
 197 void xml_elem_free_non_recurse(xml_element* root) {
 198    if(root) {
 199       xml_element_attr* attrs = Q_Head(&root->attrs);
 200       while(attrs) {
 201          my_free(attrs->key);
 202          my_free(attrs->val);
 203          my_free(attrs);
 204          attrs = Q_Next(&root->attrs);
 205       }
 206 
 207       Q_Destroy(&root->children);
 208       Q_Destroy(&root->attrs);
 209       if(root->name) {
 210           free((char *)root->name);
 211           root->name = NULL;
 212       }
 213       simplestring_free(&root->text);
 214       my_free(root);
 215    }
 216 }
 217 /******/
 218 
 219 /****f* xml_element/xml_elem_free
 220  * NAME
 221  *   xml_elem_free
 222  * SYNOPSIS
 223  *   void xml_elem_free(xml_element* root)
 224  * FUNCTION
 225  *   free an xml element and all of its child elements
 226  * INPUTS
 227  *   root - the root of an xml tree you would like to free
 228  * RESULT
 229  *   void
 230  * NOTES
 231  * SEE ALSO
 232  *   xml_elem_free_non_recurse ()
 233  *   xml_elem_new ()
 234  * SOURCE
 235  */
 236 void xml_elem_free(xml_element* root) {
 237    if(root) {
 238       xml_element* kids = Q_Head(&root->children);
 239       while(kids) {
 240          xml_elem_free(kids);
 241          kids = Q_Next(&root->children);
 242       }
 243       xml_elem_free_non_recurse(root);
 244    }
 245 }
 246 /******/
 247 
 248 /****f* xml_element/xml_elem_new
 249  * NAME
 250  *   xml_elem_new
 251  * SYNOPSIS
 252  *   xml_element* xml_elem_new()
 253  * FUNCTION
 254  *   allocates and initializes a new xml_element
 255  * INPUTS
 256  *   none
 257  * RESULT
 258  *   xml_element* or NULL.  NULL indicates an out-of-memory condition.
 259  * NOTES
 260  * SEE ALSO
 261  *   xml_elem_free ()
 262  *   xml_elem_free_non_recurse ()
 263  * SOURCE
 264  */
 265 xml_element* xml_elem_new() {
 266    xml_element* elem = calloc(1, sizeof(xml_element));
 267    if(elem) {
 268       Q_Init(&elem->children);
 269       Q_Init(&elem->attrs);
 270       simplestring_init(&elem->text);
 271 
 272       /* init empty string in case we don't find any char data */
 273       simplestring_addn(&elem->text, "", 0);
 274    }
 275    return elem;
 276 }
 277 /******/
 278 
 279 static int xml_elem_writefunc(int (*fptr)(void *data, const char *text, int size), const char *text, void *data, int len)
 280 {
 281    return fptr && text ? fptr(data, text, len ? len : strlen(text)) : 0;
 282 }
 283 
 284 
 285 
 286 static int create_xml_escape(char *pString, unsigned char c)
 287 {
 288   int counter = 0;
 289 
 290   pString[counter++] = '&';
 291   pString[counter++] = '#';
 292   if(c >= 100) {
 293     pString[counter++] = c / 100 + '0';
 294     c = c % 100;
 295   }
 296   pString[counter++] = c / 10 + '0';
 297   c = c % 10;
 298 
 299   pString[counter++] = c + '0';
 300   pString[counter++] = ';';
 301   return counter;
 302 }
 303 
 304 #define non_ascii(c) (c > 127)
 305 #define non_print(c) (!isprint(c))
 306 #define markup(c) (c == '&' || c == '\"' || c == '>' || c == '<')
 307 #define entity_length(c) ( (c >= 100) ? 3 : ((c >= 10) ? 2 : 1) ) + 3; /* "&#" + c + ";" */
 308 
 309 /*
 310  * xml_elem_entity_escape
 311  *
 312  * Purpose:
 313  *   escape reserved xml chars and non utf-8 chars as xml entities
 314  * Comments:
 315  *   The return value may be a new string, or null if no
 316  *     conversion was performed. In the latter case, *newlen will
 317  *     be 0.
 318  * Flags (to escape)
 319  *  xml_elem_no_escaping             = 0x000,
 320  *  xml_elem_entity_escaping         = 0x002,   // escape xml special chars as entities
 321  *  xml_elem_non_ascii_escaping      = 0x008,   // escape chars above 127
 322  *  xml_elem_cdata_escaping          = 0x010,   // wrap in cdata
 323  */
 324 static char* xml_elem_entity_escape(const char* buf, int old_len, int *newlen, XML_ELEM_ESCAPING flags) {
 325   char *pRetval = 0;
 326   int iNewBufLen=0;
 327 
 328 #define should_escape(c, flag) ( ((flag & xml_elem_markup_escaping) && markup(c)) || \
 329                                  ((flag & xml_elem_non_ascii_escaping) && non_ascii(c)) || \
 330                                  ((flag & xml_elem_non_print_escaping) && non_print(c)) )
 331 
 332   if(buf && *buf) {
 333     const unsigned char *bufcopy;
 334     char *NewBuffer;
 335     int ToBeXmlEscaped=0;
 336     int iLength;
 337     bufcopy = buf;
 338     iLength= old_len ? old_len : strlen(buf);
 339     while(*bufcopy) {
 340       if( should_escape(*bufcopy, flags) ) {
 341         /* the length will increase by length of xml escape - the character length */
 342         iLength += entity_length(*bufcopy);
 343         ToBeXmlEscaped=1;
 344       }
 345       bufcopy++;
 346     }
 347 
 348     if(ToBeXmlEscaped) {
 349 
 350       NewBuffer= malloc(iLength+1);
 351       if(NewBuffer) {
 352         bufcopy=buf;
 353         while(*bufcopy) {
 354           if(should_escape(*bufcopy, flags)) {
 355             iNewBufLen += create_xml_escape(NewBuffer+iNewBufLen,*bufcopy);
 356           }
 357           else {
 358             NewBuffer[iNewBufLen++]=*bufcopy;
 359           }
 360           bufcopy++;
 361         }
 362         NewBuffer[iNewBufLen] = 0;
 363         pRetval = NewBuffer;
 364       }
 365     }
 366   }
 367 
 368   if(newlen) {
 369      *newlen = iNewBufLen;
 370   }
 371 
 372   return pRetval;
 373 }
 374 
 375 
 376 static void xml_element_serialize(xml_element *el, int (*fptr)(void *data, const char *text, int size), void *data, XML_ELEM_OUTPUT_OPTIONS options, int depth)
 377 {
 378    int i;
 379    static STRUCT_XML_ELEM_OUTPUT_OPTIONS default_opts = {xml_elem_pretty, xml_elem_markup_escaping | xml_elem_non_print_escaping, XML_DECL_ENCODING_DEFAULT};
 380    static char whitespace[] = "                                                                                               "
 381                               "                                                                                               "
 382                               "                                                                                               ";
 383    depth++;
 384 
 385    if(!el) {
 386       /* fprintf(stderr, "Nothing to write\n"); */
 387       return;
 388    }
 389    if(!options) {
 390       options = &default_opts;
 391    }
 392 
 393    /* print xml declaration if at root level */
 394    if(depth == 1) {
 395       xml_elem_writefunc(fptr, XML_DECL_START, data, XML_DECL_START_LEN);
 396       xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
 397       xml_elem_writefunc(fptr, XML_DECL_VERSION, data, XML_DECL_VERSION_LEN);
 398       if(options->encoding && *options->encoding) {
 399           xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
 400           xml_elem_writefunc(fptr, XML_DECL_ENCODING_ATTR, data, XML_DECL_ENCODING_ATTR_LEN);
 401           xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN);
 402           xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
 403           xml_elem_writefunc(fptr, options->encoding, data, 0);
 404           xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
 405       }
 406       xml_elem_writefunc(fptr, XML_DECL_END, data, XML_DECL_END_LEN);
 407       if(options->verbosity != xml_elem_no_white_space) {
 408          xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
 409       }
 410    }
 411 
 412    if(options->verbosity == xml_elem_pretty && depth > 2) {
 413          xml_elem_writefunc(fptr, whitespace, data, depth - 2);
 414    }
 415    /* begin element */
 416    xml_elem_writefunc(fptr,START_TOKEN_BEGIN, data, START_TOKEN_BEGIN_LEN);
 417    if(el->name) {
 418       xml_elem_writefunc(fptr, el->name, data, 0);
 419 
 420       /* write attrs, if any */
 421       if(Q_Size(&el->attrs)) {
 422          xml_element_attr* iter = Q_Head(&el->attrs);
 423          while( iter ) {
 424             xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
 425             xml_elem_writefunc(fptr, iter->key, data, 0);
 426             xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN);
 427             xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
 428             xml_elem_writefunc(fptr, iter->val, data, 0);
 429             xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
 430 
 431             iter = Q_Next(&el->attrs);
 432          }
 433       }
 434    }
 435    else {
 436       xml_elem_writefunc(fptr, "None", data, 0);
 437    }
 438    /* if no text and no children, use abbreviated form, eg: <foo/> */
 439    if(!el->text.len && !Q_Size(&el->children)) {
 440        xml_elem_writefunc(fptr, EMPTY_START_TOKEN_END, data, EMPTY_START_TOKEN_END_LEN);
 441    }
 442    /* otherwise, print element contents */
 443    else {
 444        xml_elem_writefunc(fptr, START_TOKEN_END, data, START_TOKEN_END_LEN);
 445 
 446        /* print text, if any */
 447        if(el->text.len) {
 448           char* escaped_str = el->text.str;
 449           int buflen = el->text.len;
 450 
 451           if(options->escaping && options->escaping != xml_elem_cdata_escaping) {
 452              escaped_str = xml_elem_entity_escape(el->text.str, buflen, &buflen, options->escaping );
 453              if(!escaped_str) {
 454                 escaped_str = el->text.str;
 455              }
 456           }
 457 
 458           if(options->escaping & xml_elem_cdata_escaping) {
 459              xml_elem_writefunc(fptr, CDATA_BEGIN, data, CDATA_BEGIN_LEN);
 460           }
 461 
 462           xml_elem_writefunc(fptr, escaped_str, data, buflen);
 463 
 464           if(escaped_str != el->text.str) {
 465              my_free(escaped_str);
 466           }
 467 
 468           if(options->escaping & xml_elem_cdata_escaping) {
 469              xml_elem_writefunc(fptr, CDATA_END, data, CDATA_END_LEN);
 470           }
 471        }
 472        /* no text, so print child elems */
 473        else {
 474           xml_element *kids = Q_Head(&el->children);
 475           i = 0;
 476           while( kids ) {
 477              if(i++ == 0) {
 478                 if(options->verbosity != xml_elem_no_white_space) {
 479                    xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
 480                 }
 481              }
 482              xml_element_serialize(kids, fptr, data, options, depth);
 483              kids = Q_Next(&el->children);
 484           }
 485           if(i) {
 486              if(options->verbosity == xml_elem_pretty && depth > 2) {
 487                    xml_elem_writefunc(fptr, whitespace, data, depth - 2);
 488              }
 489           }
 490        }
 491 
 492        xml_elem_writefunc(fptr, END_TOKEN_BEGIN, data, END_TOKEN_BEGIN_LEN);
 493        xml_elem_writefunc(fptr,el->name ? el->name : "None", data, 0);
 494        xml_elem_writefunc(fptr, END_TOKEN_END, data, END_TOKEN_END_LEN);
 495    }
 496    if(options->verbosity != xml_elem_no_white_space) {
 497       xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
 498    }
 499 }
 500 
 501 /* print buf to file */
 502 static int file_out_fptr(void *f, const char *text, int size)
 503 {
 504    fputs(text, (FILE *)f);
 505    return 0;
 506 }
 507 
 508 /* print buf to simplestring */
 509 static int simplestring_out_fptr(void *f, const char *text, int size)
 510 {
 511    simplestring* buf = (simplestring*)f;
 512    if(buf) {
 513       simplestring_addn(buf, text, size);
 514    }
 515    return 0;
 516 }
 517 
 518 /****f* xml_element/xml_elem_serialize_to_string
 519  * NAME
 520  *   xml_elem_serialize_to_string
 521  * SYNOPSIS
 522  *   void xml_element_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
 523  * FUNCTION
 524  *   writes element tree as XML into a newly allocated buffer
 525  * INPUTS
 526  *   el      - root element of tree
 527  *   options - options determining how output is written.  see XML_ELEM_OUTPUT_OPTIONS
 528  *   buf_len - length of returned buffer, if not null.
 529  * RESULT
 530  *   char* or NULL. Must be free'd by caller.
 531  * NOTES
 532  * SEE ALSO
 533  *   xml_elem_serialize_to_stream ()
 534  *   xml_elem_parse_buf ()
 535  * SOURCE
 536  */
 537 char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
 538 {
 539    simplestring buf;
 540    simplestring_init(&buf);
 541 
 542    xml_element_serialize(el, simplestring_out_fptr, (void *)&buf, options, 0);
 543 
 544    if(buf_len) {
 545       *buf_len = buf.len;
 546    }
 547 
 548    return buf.str;
 549 }
 550 /******/
 551 
 552 /****f* xml_element/xml_elem_serialize_to_stream
 553  * NAME
 554  *   xml_elem_serialize_to_stream
 555  * SYNOPSIS
 556  *   void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
 557  * FUNCTION
 558  *   writes element tree as XML into a stream (typically an opened file)
 559  * INPUTS
 560  *   el      - root element of tree
 561  *   output  - stream handle
 562  *   options - options determining how output is written.  see XML_ELEM_OUTPUT_OPTIONS
 563  * RESULT
 564  *   void
 565  * NOTES
 566  * SEE ALSO
 567  *   xml_elem_serialize_to_string ()
 568  *   xml_elem_parse_buf ()
 569  * SOURCE
 570  */
 571 void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
 572 {
 573    xml_element_serialize(el, file_out_fptr, (void *)output, options, 0);
 574 }
 575 /******/
 576 
 577 /*--------------------------*
 578 * End xml_element Functions *
 579 *--------------------------*/
 580 
 581 
 582 /*----------------------
 583 * Begin Expat Handlers *
 584 *---------------------*/
 585 
 586 typedef struct _xml_elem_data {
 587    xml_element*           root;
 588    xml_element*           current;
 589    XML_ELEM_INPUT_OPTIONS input_options;
 590    int                    needs_enc_conversion;
 591 } xml_elem_data;
 592 
 593 
 594 /* expat start of element handler */
 595 static void _xmlrpc_startElement(void *userData, const char *name, const char **attrs)
 596 {
 597    xml_element *c;
 598    xml_elem_data* mydata = (xml_elem_data*)userData;
 599    const char** p = attrs;
 600 
 601    if(mydata) {
 602       c = mydata->current;
 603 
 604       mydata->current = xml_elem_new();
 605       mydata->current->name = (char*)strdup(name);
 606       mydata->current->parent = c;
 607 
 608       /* init attrs */
 609       while(p && *p) {
 610          xml_element_attr* attr = malloc(sizeof(xml_element_attr));
 611          if(attr) {
 612             attr->key = strdup(*p);
 613             attr->val = strdup(*(p+1));
 614             Q_PushTail(&mydata->current->attrs, attr);
 615 
 616             p += 2;
 617          }
 618       }
 619    }
 620 }
 621 
 622 /* expat end of element handler */
 623 static void _xmlrpc_endElement(void *userData, const char *name)
 624 {
 625    xml_elem_data* mydata = (xml_elem_data*)userData;
 626 
 627    if(mydata && mydata->current && mydata->current->parent) {
 628       Q_PushTail(&mydata->current->parent->children, mydata->current);
 629 
 630       mydata->current = mydata->current->parent;
 631    }
 632 }
 633 
 634 /* expat char data handler */
 635 static void _xmlrpc_charHandler(void *userData,
 636                         const char *s,
 637                         int len)
 638 {
 639    xml_elem_data* mydata = (xml_elem_data*)userData;
 640    if(mydata && mydata->current) {
 641 
 642       /* Check if we need to decode utf-8 parser output to another encoding */
 643       if(mydata->needs_enc_conversion && mydata->input_options->encoding) {
 644          int new_len = 0;
 645          char* add_text = utf8_decode(s, len, &new_len, mydata->input_options->encoding);
 646          if(add_text) {
 647             len = new_len;
 648             simplestring_addn(&mydata->current->text, add_text, len);
 649             free(add_text);
 650             return;
 651          }
 652       }
 653       simplestring_addn(&mydata->current->text, s, len);
 654    }
 655 }
 656 /******/
 657 
 658 /*-------------------*
 659 * End Expat Handlers *
 660 *-------------------*/
 661 
 662 /*-------------------*
 663 * xml_elem_parse_buf *
 664 *-------------------*/
 665 
 666 /****f* xml_element/xml_elem_parse_buf
 667  * NAME
 668  *   xml_elem_parse_buf
 669  * SYNOPSIS
 670  *   xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
 671  * FUNCTION
 672  *   parse a buffer containing XML into an xml_element in-memory tree
 673  * INPUTS
 674  *   in_buf   - buffer containing XML document
 675  *   len      - length of buffer
 676  *   options  - input options. optional
 677  *   error    - error result data. optional. check if result is null.
 678  * RESULT
 679  *   void
 680  * NOTES
 681  *   The returned data must be free'd by caller
 682  * SEE ALSO
 683  *   xml_elem_serialize_to_string ()
 684  *   xml_elem_free ()
 685  * SOURCE
 686  */
 687 xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
 688 {
 689    xml_element* xReturn = NULL;
 690    char buf[100] = "";
 691    static STRUCT_XML_ELEM_INPUT_OPTIONS default_opts = {encoding_utf_8};
 692 
 693    if(!options) {
 694       options = &default_opts;
 695    }
 696 
 697    if(in_buf) {
 698       XML_Parser parser;
 699       xml_elem_data mydata = {0};
 700 
 701       parser = XML_ParserCreate(NULL);
 702 
 703       mydata.root = xml_elem_new();
 704       mydata.current = mydata.root;
 705       mydata.input_options = options;
 706       mydata.needs_enc_conversion = options->encoding && strcmp(options->encoding, encoding_utf_8);
 707 
 708       XML_SetElementHandler(parser, (XML_StartElementHandler)_xmlrpc_startElement, (XML_EndElementHandler)_xmlrpc_endElement);
 709       XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_xmlrpc_charHandler);
 710 
 711       /* pass the xml_elem_data struct along */
 712       XML_SetUserData(parser, (void*)&mydata);
 713 
 714       if(!len) {
 715          len = strlen(in_buf);
 716       }
 717 
 718       /* parse the XML */
 719       if(XML_Parse(parser, in_buf, len, 1) == 0) {
 720          enum XML_Error err_code = XML_GetErrorCode(parser);
 721          int line_num = XML_GetCurrentLineNumber(parser);
 722          int col_num = XML_GetCurrentColumnNumber(parser);
 723          long byte_idx = XML_GetCurrentByteIndex(parser);
 724 /*         int byte_total = XML_GetCurrentByteCount(parser); */
 725          const char * error_str = XML_ErrorString(err_code);
 726          if(byte_idx >= 0) {
 727              snprintf(buf,
 728                       sizeof(buf),
 729                       "\n\tdata beginning %ld before byte index: %s\n",
 730                       byte_idx > 10  ? 10 : byte_idx,
 731                       in_buf + (byte_idx > 10 ? byte_idx - 10 : byte_idx));
 732          }
 733 /*
 734          fprintf(stderr, "expat reports error code %i\n"
 735                 "\tdescription: %s\n"
 736                 "\tline: %i\n"
 737                 "\tcolumn: %i\n"
 738                 "\tbyte index: %ld\n"
 739                 "\ttotal bytes: %i\n%s ",
 740                 err_code, error_str, line_num,
 741                 col_num, byte_idx, byte_total, buf);
 742 */
 743 
 744           /* error condition */
 745           if(error) {
 746               error->parser_code = (long)err_code;
 747               error->line = line_num;
 748               error->column = col_num;
 749               error->byte_index = byte_idx;
 750               error->parser_error = error_str;
 751           }
 752       }
 753       else {
 754          xReturn = (xml_element*)Q_Head(&mydata.root->children);
 755          xReturn->parent = NULL;
 756       }
 757 
 758       XML_ParserFree(parser);
 759 
 760 
 761       xml_elem_free_non_recurse(mydata.root);
 762    }
 763 
 764    return xReturn;
 765 }
 766 
 767 /******/

/* [<][>][^][v][top][bottom][index][help] */