Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_element.c, revision 1.1

1.1     ! misho       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: xml_element.c 271367 2008-12-17 00:30:27Z iliaa $";
        !            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: /******/

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>