Annotation of embedaddon/libxml2/c14n.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * "Canonical XML" implementation 
                      3:  * http://www.w3.org/TR/xml-c14n
                      4:  * 
                      5:  * "Exclusive XML Canonicalization" implementation
                      6:  * http://www.w3.org/TR/xml-exc-c14n
                      7:  *
                      8:  * See Copyright for the status of this software.
                      9:  * 
                     10:  * Author: Aleksey Sanin <aleksey@aleksey.com>
                     11:  */
                     12: #define IN_LIBXML
                     13: #include "libxml.h"
                     14: #ifdef LIBXML_C14N_ENABLED
                     15: #ifdef LIBXML_OUTPUT_ENABLED
                     16: 
                     17: #ifdef HAVE_STDLIB_H
                     18: #include <stdlib.h>
                     19: #endif
                     20: #include <string.h>
                     21: 
                     22: #include <libxml/tree.h>
                     23: #include <libxml/parser.h>
                     24: #include <libxml/uri.h>
                     25: #include <libxml/xmlerror.h>
                     26: #include <libxml/globals.h>
                     27: #include <libxml/xpathInternals.h>
                     28: #include <libxml/c14n.h>
                     29: 
                     30: /************************************************************************
                     31:  *                                                                     *
                     32:  *             Some declaration better left private ATM                *
                     33:  *                                                                     *
                     34:  ************************************************************************/
                     35: 
                     36: typedef enum {
                     37:     XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
                     38:     XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
                     39:     XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
                     40: } xmlC14NPosition;
                     41: 
                     42: typedef struct _xmlC14NVisibleNsStack {
                     43:     int nsCurEnd;           /* number of nodes in the set */
                     44:     int nsPrevStart;        /* the begginning of the stack for previous visible node */
                     45:     int nsPrevEnd;          /* the end of the stack for previous visible node */
                     46:     int nsMax;              /* size of the array as allocated */
                     47:     xmlNsPtr   *nsTab;     /* array of ns in no particular order */          
                     48:     xmlNodePtr *nodeTab;   /* array of nodes in no particular order */
                     49: } xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
                     50: 
                     51: typedef struct _xmlC14NCtx {
                     52:     /* input parameters */
                     53:     xmlDocPtr doc;
                     54:     xmlC14NIsVisibleCallback is_visible_callback;
                     55:     void* user_data;    
                     56:     int with_comments;
                     57:     xmlOutputBufferPtr buf;
                     58: 
                     59:     /* position in the XML document */
                     60:     xmlC14NPosition pos;
                     61:     int parent_is_doc;
                     62:     xmlC14NVisibleNsStackPtr ns_rendered;
                     63:     
                     64:     /* C14N mode */
                     65:     xmlC14NMode mode;
                     66: 
                     67:     /* exclusive canonicalization */
                     68:     xmlChar **inclusive_ns_prefixes;
                     69: 
                     70:     /* error number */
                     71:     int error;
                     72: } xmlC14NCtx, *xmlC14NCtxPtr;
                     73: 
                     74: static xmlC14NVisibleNsStackPtr        xmlC14NVisibleNsStackCreate     (void);
                     75: static void     xmlC14NVisibleNsStackDestroy   (xmlC14NVisibleNsStackPtr cur);
                     76: static void     xmlC14NVisibleNsStackAdd           (xmlC14NVisibleNsStackPtr cur, 
                     77:                                                  xmlNsPtr ns,
                     78:                                                  xmlNodePtr node);
                     79: static void                    xmlC14NVisibleNsStackSave       (xmlC14NVisibleNsStackPtr cur,
                     80:                                                                 xmlC14NVisibleNsStackPtr state);
                     81: static void                    xmlC14NVisibleNsStackRestore    (xmlC14NVisibleNsStackPtr cur,
                     82:                                                                 xmlC14NVisibleNsStackPtr state);
                     83: static void                    xmlC14NVisibleNsStackShift      (xmlC14NVisibleNsStackPtr cur);
                     84: static int                     xmlC14NVisibleNsStackFind       (xmlC14NVisibleNsStackPtr cur, 
                     85:                                                                 xmlNsPtr ns);
                     86: static int                     xmlExcC14NVisibleNsStackFind    (xmlC14NVisibleNsStackPtr cur, 
                     87:                                                                 xmlNsPtr ns,
                     88:                                                                 xmlC14NCtxPtr ctx);
                     89: 
                     90: static int                     xmlC14NIsNodeInNodeset          (xmlNodeSetPtr nodes,
                     91:                                                                 xmlNodePtr node,
                     92:                                                                 xmlNodePtr parent);
                     93: 
                     94: 
                     95: 
                     96: static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
                     97: static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
                     98: typedef enum {
                     99:     XMLC14N_NORMALIZE_ATTR = 0,
                    100:     XMLC14N_NORMALIZE_COMMENT = 1,
                    101:     XMLC14N_NORMALIZE_PI = 2,
                    102:     XMLC14N_NORMALIZE_TEXT = 3
                    103: } xmlC14NNormalizationMode;
                    104: 
                    105: static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
                    106:                                        xmlC14NNormalizationMode mode);
                    107: 
                    108: #define        xmlC11NNormalizeAttr( a ) \
                    109:     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
                    110: #define        xmlC11NNormalizeComment( a ) \
                    111:     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
                    112: #define        xmlC11NNormalizePI( a ) \
                    113:     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
                    114: #define        xmlC11NNormalizeText( a ) \
                    115:     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
                    116: 
                    117: #define        xmlC14NIsVisible( ctx, node, parent ) \
                    118:      (((ctx)->is_visible_callback != NULL) ? \
                    119:        (ctx)->is_visible_callback((ctx)->user_data, \
                    120:                (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
                    121: 
                    122: #define        xmlC14NIsExclusive( ctx ) \
                    123:     ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 )
                    124: 
                    125: /************************************************************************
                    126:  *                                                                     *
                    127:  *             Some factorized error routines                          *
                    128:  *                                                                     *
                    129:  ************************************************************************/
                    130: 
                    131: /**
                    132:  * xmlC14NErrMemory:
                    133:  * @extra:  extra informations
                    134:  *
                    135:  * Handle a redefinition of memory error
                    136:  */
                    137: static void
                    138: xmlC14NErrMemory(const char *extra)
                    139: {
                    140:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    141:                    XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
                    142:                    NULL, NULL, 0, 0,
                    143:                    "Memory allocation failed : %s\n", extra);
                    144: }
                    145: 
                    146: /**
                    147:  * xmlC14NErrParam:
                    148:  * @extra:  extra informations
                    149:  *
                    150:  * Handle a redefinition of param error
                    151:  */
                    152: static void
                    153: xmlC14NErrParam(const char *extra)
                    154: {
                    155:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    156:                    XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
                    157:                    NULL, NULL, 0, 0,
                    158:                    "Invalid parameter : %s\n", extra);
                    159: }
                    160: 
                    161: /**
                    162:  * xmlC14NErrInternal:
                    163:  * @extra:  extra informations
                    164:  *
                    165:  * Handle a redefinition of internal error
                    166:  */
                    167: static void
                    168: xmlC14NErrInternal(const char *extra)
                    169: {
                    170:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    171:                    XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
                    172:                    NULL, NULL, 0, 0,
                    173:                    "Internal error : %s\n", extra);
                    174: }
                    175: 
                    176: /**
                    177:  * xmlC14NErrInvalidNode:
                    178:  * @extra:  extra informations
                    179:  *
                    180:  * Handle a redefinition of invalid node error
                    181:  */
                    182: static void
                    183: xmlC14NErrInvalidNode(const char *node_type, const char *extra)
                    184: {
                    185:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    186:                    XML_C14N_INVALID_NODE, XML_ERR_ERROR, NULL, 0, extra,
                    187:                    NULL, NULL, 0, 0,
                    188:                    "Node %s is invalid here : %s\n", node_type, extra);
                    189: }
                    190: 
                    191: /**
                    192:  * xmlC14NErrUnknownNode:
                    193:  * @extra:  extra informations
                    194:  *
                    195:  * Handle a redefinition of unknown node error
                    196:  */
                    197: static void
                    198: xmlC14NErrUnknownNode(int node_type, const char *extra)
                    199: {
                    200:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    201:                    XML_C14N_UNKNOW_NODE, XML_ERR_ERROR, NULL, 0, extra,
                    202:                    NULL, NULL, 0, 0,
                    203:                    "Unknown node type %d found : %s\n", node_type, extra);
                    204: }
                    205: 
                    206: /**
                    207:  * xmlC14NErrRelativeNamespace:
                    208:  * @extra:  extra informations
                    209:  *
                    210:  * Handle a redefinition of relative namespace error
                    211:  */
                    212: static void
                    213: xmlC14NErrRelativeNamespace(const char *ns_uri)
                    214: {
                    215:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
                    216:                    XML_C14N_RELATIVE_NAMESPACE, XML_ERR_ERROR, NULL, 0, NULL,
                    217:                    NULL, NULL, 0, 0,
                    218:                    "Relative namespace UR is invalid here : %s\n", ns_uri);
                    219: }
                    220: 
                    221: 
                    222: 
                    223: /**
                    224:  * xmlC14NErr:
                    225:  * @ctxt:  a C14N evaluation context
                    226:  * @node:  the context node
                    227:  * @error:  the erorr code
                    228:  * @msg:  the message
                    229:  * @extra:  extra informations
                    230:  *
                    231:  * Handle a redefinition of attribute error
                    232:  */
                    233: static void
                    234: xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error,
                    235:            const char * msg)
                    236: {
                    237:     if (ctxt != NULL)
                    238:         ctxt->error = error;
                    239:     __xmlRaiseError(NULL, NULL, NULL,
                    240:                    ctxt, node, XML_FROM_C14N, error,
                    241:                    XML_ERR_ERROR, NULL, 0,
                    242:                    NULL, NULL, NULL, 0, 0, "%s", msg);
                    243: }
                    244: 
                    245: /************************************************************************
                    246:  *                                                                     *
                    247:  *             The implementation internals                            *
                    248:  *                                                                     *
                    249:  ************************************************************************/
                    250: #define XML_NAMESPACES_DEFAULT         16
                    251: 
                    252: static int                     
                    253: xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
                    254:     if((nodes != NULL) && (node != NULL)) {
                    255:        if(node->type != XML_NAMESPACE_DECL) {
                    256:            return(xmlXPathNodeSetContains(nodes, node));
                    257:        } else {
                    258:            xmlNs ns;
                    259:            
                    260:            memcpy(&ns, node, sizeof(ns)); 
                    261:            
                    262:            /* this is a libxml hack! check xpath.c for details */
                    263:            if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) {
                    264:                ns.next = (xmlNsPtr)parent->parent;
                    265:            } else {
                    266:                ns.next = (xmlNsPtr)parent; 
                    267:            }
                    268: 
                    269:            /* 
                    270:             * If the input is an XPath node-set, then the node-set must explicitly 
                    271:             * contain every node to be rendered to the canonical form.
                    272:             */
                    273:            return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
                    274:        }
                    275:     }
                    276:     return(1);
                    277: }
                    278: 
                    279: static xmlC14NVisibleNsStackPtr
                    280: xmlC14NVisibleNsStackCreate(void) {
                    281:     xmlC14NVisibleNsStackPtr ret;
                    282: 
                    283:     ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
                    284:     if (ret == NULL) {
                    285:         xmlC14NErrMemory("creating namespaces stack");
                    286:        return(NULL);
                    287:     }
                    288:     memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
                    289:     return(ret);
                    290: }
                    291: 
                    292: static void
                    293: xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
                    294:     if(cur == NULL) {
                    295:         xmlC14NErrParam("destroying namespaces stack");
                    296:         return;
                    297:     }
                    298:     if(cur->nsTab != NULL) {
                    299:        memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
                    300:        xmlFree(cur->nsTab);
                    301:     }
                    302:     if(cur->nodeTab != NULL) {
                    303:        memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
                    304:        xmlFree(cur->nodeTab);
                    305:     }
                    306:     memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
                    307:     xmlFree(cur);
                    308:     
                    309: }
                    310: 
                    311: static void 
                    312: xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
                    313:     if((cur == NULL) || 
                    314:        ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
                    315:        ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
                    316:         xmlC14NErrParam("adding namespace to stack");
                    317:        return;
                    318:     }
                    319: 
                    320:     if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
                    321:         cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
                    322:         cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
                    323:        if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
                    324:            xmlC14NErrMemory("adding node to stack");
                    325:            return;
                    326:        }
                    327:        memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
                    328:        memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
                    329:         cur->nsMax = XML_NAMESPACES_DEFAULT;
                    330:     } else if(cur->nsMax == cur->nsCurEnd) {
                    331:        void *tmp;      
                    332:        int tmpSize;
                    333:        
                    334:        tmpSize = 2 * cur->nsMax;
                    335:        tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
                    336:        if (tmp == NULL) {
                    337:            xmlC14NErrMemory("adding node to stack");
                    338:            return;
                    339:        }
                    340:        cur->nsTab = (xmlNsPtr*)tmp;
                    341: 
                    342:        tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
                    343:        if (tmp == NULL) {
                    344:            xmlC14NErrMemory("adding node to stack");
                    345:            return;
                    346:        }
                    347:        cur->nodeTab = (xmlNodePtr*)tmp;
                    348: 
                    349:        cur->nsMax = tmpSize;
                    350:     }
                    351:     cur->nsTab[cur->nsCurEnd] = ns;
                    352:     cur->nodeTab[cur->nsCurEnd] = node;
                    353: 
                    354:     ++cur->nsCurEnd;
                    355: }
                    356: 
                    357: static void
                    358: xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
                    359:     if((cur == NULL) || (state == NULL)) {
                    360:         xmlC14NErrParam("saving namespaces stack");
                    361:        return;
                    362:     }
                    363:     
                    364:     state->nsCurEnd = cur->nsCurEnd;
                    365:     state->nsPrevStart = cur->nsPrevStart;
                    366:     state->nsPrevEnd = cur->nsPrevEnd;
                    367: }
                    368: 
                    369: static void
                    370: xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
                    371:     if((cur == NULL) || (state == NULL)) {
                    372:         xmlC14NErrParam("restoring namespaces stack");
                    373:        return;
                    374:     }
                    375:     cur->nsCurEnd = state->nsCurEnd;
                    376:     cur->nsPrevStart = state->nsPrevStart;
                    377:     cur->nsPrevEnd = state->nsPrevEnd;
                    378: }
                    379: 
                    380: static void 
                    381: xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
                    382:     if(cur == NULL) {
                    383:         xmlC14NErrParam("shifting namespaces stack");
                    384:        return;
                    385:     }
                    386:     cur->nsPrevStart = cur->nsPrevEnd;
                    387:     cur->nsPrevEnd = cur->nsCurEnd;
                    388: }
                    389: 
                    390: static int
                    391: xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
                    392:     if (str1 == str2) return(1);
                    393:     if (str1 == NULL) return((*str2) == '\0');
                    394:     if (str2 == NULL) return((*str1) == '\0');
                    395:     do {
                    396:        if (*str1++ != *str2) return(0);
                    397:     } while (*str2++);
                    398:     return(1);
                    399: }
                    400: 
                    401: /**
                    402:  * xmlC14NVisibleNsStackFind:
                    403:  * @ctx:               the C14N context 
                    404:  * @ns:                        the namespace to check
                    405:  *
                    406:  * Checks whether the given namespace was already rendered or not
                    407:  *
                    408:  * Returns 1 if we already wrote this namespace or 0 otherwise
                    409:  */
                    410: static int
                    411: xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
                    412: {
                    413:     int i;
                    414:     const xmlChar *prefix;
                    415:     const xmlChar *href;
                    416:     int has_empty_ns;
                    417:         
                    418:     if(cur == NULL) {
                    419:         xmlC14NErrParam("searching namespaces stack (c14n)");
                    420:         return (0);
                    421:     }
                    422: 
                    423:     /*
                    424:      * if the default namespace xmlns="" is not defined yet then 
                    425:      * we do not want to print it out
                    426:      */
                    427:     prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
                    428:     href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
                    429:     has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
                    430: 
                    431:     if (cur->nsTab != NULL) {
                    432:        int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
                    433:         for (i = cur->nsCurEnd - 1; i >= start; --i) {
                    434:             xmlNsPtr ns1 = cur->nsTab[i];
                    435:            
                    436:            if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
                    437:                return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
                    438:            }
                    439:         }
                    440:     }
                    441:     return(has_empty_ns);
                    442: }
                    443: 
                    444: static int                     
                    445: xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
                    446:     int i;
                    447:     const xmlChar *prefix;
                    448:     const xmlChar *href;
                    449:     int has_empty_ns;
                    450:         
                    451:     if(cur == NULL) {
                    452:         xmlC14NErrParam("searching namespaces stack (exc c14n)");
                    453:         return (0);
                    454:     }
                    455: 
                    456:     /*
                    457:      * if the default namespace xmlns="" is not defined yet then 
                    458:      * we do not want to print it out
                    459:      */
                    460:     prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
                    461:     href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
                    462:     has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
                    463: 
                    464:     if (cur->nsTab != NULL) {
                    465:        int start = 0;
                    466:         for (i = cur->nsCurEnd - 1; i >= start; --i) {
                    467:             xmlNsPtr ns1 = cur->nsTab[i];
                    468:            
                    469:            if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
                    470:                if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
                    471:                    return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
                    472:                } else {
                    473:                    return(0);
                    474:                }
                    475:            }
                    476:         }
                    477:     }
                    478:     return(has_empty_ns);
                    479: }
                    480: 
                    481: 
                    482: 
                    483: 
                    484: /**
                    485:  * xmlC14NIsXmlNs:
                    486:  * @ns:                the namespace to check
                    487:  *             
                    488:  * Checks whether the given namespace is a default "xml:" namespace
                    489:  * with href="http://www.w3.org/XML/1998/namespace"
                    490:  *
                    491:  * Returns 1 if the node is default or 0 otherwise
                    492:  */
                    493: 
                    494: /* todo: make it a define? */
                    495: static int
                    496: xmlC14NIsXmlNs(xmlNsPtr ns)
                    497: {
                    498:     return ((ns != NULL) &&
                    499:             (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
                    500:             (xmlStrEqual(ns->href, XML_XML_NAMESPACE)));
                    501: }
                    502: 
                    503: 
                    504: /**
                    505:  * xmlC14NNsCompare:
                    506:  * @ns1:               the pointer to first namespace
                    507:  * @ns2:               the pointer to second namespace
                    508:  *
                    509:  * Compares the namespaces by names (prefixes).
                    510:  *
                    511:  * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
                    512:  */
                    513: static int
                    514: xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
                    515: {
                    516:     if (ns1 == ns2)
                    517:         return (0);
                    518:     if (ns1 == NULL)
                    519:         return (-1);
                    520:     if (ns2 == NULL)
                    521:         return (1);
                    522: 
                    523:     return (xmlStrcmp(ns1->prefix, ns2->prefix));
                    524: }
                    525: 
                    526: 
                    527: /**
                    528:  * xmlC14NPrintNamespaces:
                    529:  * @ns:                        the pointer to namespace
                    530:  * @ctx:               the C14N context
                    531:  *
                    532:  * Prints the given namespace to the output buffer from C14N context.
                    533:  *
                    534:  * Returns 1 on success or 0 on fail.
                    535:  */
                    536: static int
                    537: xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
                    538: {
                    539: 
                    540:     if ((ns == NULL) || (ctx == NULL)) {
                    541:         xmlC14NErrParam("writing namespaces");
                    542:         return 0;
                    543:     }
                    544: 
                    545:     if (ns->prefix != NULL) {
                    546:         xmlOutputBufferWriteString(ctx->buf, " xmlns:");
                    547:         xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
                    548:         xmlOutputBufferWriteString(ctx->buf, "=\"");
                    549:     } else {
                    550:         xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
                    551:     }
                    552:     if(ns->href != NULL) {
                    553:        xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
                    554:     }
                    555:     xmlOutputBufferWriteString(ctx->buf, "\"");
                    556:     return (1);
                    557: }
                    558: 
                    559: /**
                    560:  * xmlC14NProcessNamespacesAxis:
                    561:  * @ctx:               the C14N context
                    562:  * @node:              the current node
                    563:  *
                    564:  * Prints out canonical namespace axis of the current node to the
                    565:  * buffer from C14N context as follows 
                    566:  *
                    567:  * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
                    568:  *
                    569:  * Namespace Axis
                    570:  * Consider a list L containing only namespace nodes in the 
                    571:  * axis and in the node-set in lexicographic order (ascending). To begin 
                    572:  * processing L, if the first node is not the default namespace node (a node 
                    573:  * with no namespace URI and no local name), then generate a space followed 
                    574:  * by xmlns="" if and only if the following conditions are met:
                    575:  *    - the element E that owns the axis is in the node-set
                    576:  *    - The nearest ancestor element of E in the node-set has a default 
                    577:  *         namespace node in the node-set (default namespace nodes always 
                    578:  *      have non-empty values in XPath)
                    579:  * The latter condition eliminates unnecessary occurrences of xmlns="" in 
                    580:  * the canonical form since an element only receives an xmlns="" if its 
                    581:  * default namespace is empty and if it has an immediate parent in the 
                    582:  * canonical form that has a non-empty default namespace. To finish 
                    583:  * processing  L, simply process every namespace node in L, except omit 
                    584:  * namespace node with local name xml, which defines the xml prefix, 
                    585:  * if its string value is http://www.w3.org/XML/1998/namespace.
                    586:  *
                    587:  * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
                    588:  * Canonical XML applied to a document subset requires the search of the 
                    589:  * ancestor nodes of each orphan element node for attributes in the xml 
                    590:  * namespace, such as xml:lang and xml:space. These are copied into the 
                    591:  * element node except if a declaration of the same attribute is already 
                    592:  * in the attribute axis of the element (whether or not it is included in 
                    593:  * the document subset). This search and copying are omitted from the 
                    594:  * Exclusive XML Canonicalization method.
                    595:  *
                    596:  * Returns 0 on success or -1 on fail.
                    597:  */
                    598: static int
                    599: xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
                    600: {
                    601:     xmlNodePtr n;
                    602:     xmlNsPtr ns, tmp;
                    603:     xmlListPtr list;
                    604:     int already_rendered;
                    605:     int has_empty_ns = 0;
                    606:     
                    607:     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
                    608:         xmlC14NErrParam("processing namespaces axis (c14n)");
                    609:         return (-1);
                    610:     }
                    611: 
                    612:     /*
                    613:      * Create a sorted list to store element namespaces
                    614:      */
                    615:     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
                    616:     if (list == NULL) {
                    617:         xmlC14NErrInternal("creating namespaces list (c14n)");
                    618:         return (-1);
                    619:     }
                    620: 
                    621:     /* check all namespaces */
                    622:     for(n = cur; n != NULL; n = n->parent) {
                    623:        for(ns = n->nsDef; ns != NULL; ns = ns->next) {
                    624:            tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
                    625:            
                    626:            if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
                    627:                already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
                    628:                if(visible) {
                    629:                    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
                    630:                }
                    631:                if(!already_rendered) {
                    632:                    xmlListInsert(list, ns); 
                    633:                }
                    634:                if(xmlStrlen(ns->prefix) == 0) {
                    635:                    has_empty_ns = 1;
                    636:                }
                    637:            }
                    638:        }
                    639:     }
                    640:        
                    641:     /**
                    642:      * if the first node is not the default namespace node (a node with no 
                    643:      * namespace URI and no local name), then generate a space followed by 
                    644:      * xmlns="" if and only if the following conditions are met:
                    645:      *  - the element E that owns the axis is in the node-set
                    646:      *  - the nearest ancestor element of E in the node-set has a default 
                    647:      *     namespace node in the node-set (default namespace nodes always 
                    648:      *     have non-empty values in XPath)
                    649:      */
                    650:     if(visible && !has_empty_ns) {
                    651:         static xmlNs ns_default;
                    652: 
                    653:         memset(&ns_default, 0, sizeof(ns_default));
                    654:         if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
                    655:            xmlC14NPrintNamespaces(&ns_default, ctx);
                    656:        }
                    657:     }
                    658:        
                    659:     
                    660:     /* 
                    661:      * print out all elements from list 
                    662:      */
                    663:     xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
                    664: 
                    665:     /* 
                    666:      * Cleanup
                    667:      */
                    668:     xmlListDelete(list);
                    669:     return (0);
                    670: }
                    671: 
                    672: 
                    673: /**
                    674:  * xmlExcC14NProcessNamespacesAxis:
                    675:  * @ctx:               the C14N context
                    676:  * @node:              the current node
                    677:  *
                    678:  * Prints out exclusive canonical namespace axis of the current node to the
                    679:  * buffer from C14N context as follows 
                    680:  *
                    681:  * Exclusive XML Canonicalization
                    682:  * http://www.w3.org/TR/xml-exc-c14n
                    683:  *
                    684:  * If the element node is in the XPath subset then output the node in 
                    685:  * accordance with Canonical XML except for namespace nodes which are 
                    686:  * rendered as follows:
                    687:  *
                    688:  * 1. Render each namespace node iff:
                    689:  *    * it is visibly utilized by the immediate parent element or one of 
                    690:  *      its attributes, or is present in InclusiveNamespaces PrefixList, and
                    691:  *    * its prefix and value do not appear in ns_rendered. ns_rendered is 
                    692:  *      obtained by popping the state stack in order to obtain a list of 
                    693:  *      prefixes and their values which have already been rendered by 
                    694:  *      an output ancestor of the namespace node's parent element.
                    695:  * 2. Append the rendered namespace node to the list ns_rendered of namespace 
                    696:  * nodes rendered by output ancestors. Push ns_rendered on state stack and 
                    697:  * recurse.
                    698:  * 3. After the recursion returns, pop thestate stack.
                    699:  *
                    700:  *
                    701:  * Returns 0 on success or -1 on fail.
                    702:  */
                    703: static int
                    704: xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
                    705: {
                    706:     xmlNsPtr ns;
                    707:     xmlListPtr list;
                    708:     xmlAttrPtr attr;
                    709:     int already_rendered;
                    710:     int has_empty_ns = 0;
                    711:     int has_visibly_utilized_empty_ns = 0;
                    712:     int has_empty_ns_in_inclusive_list = 0;
                    713:         
                    714:     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
                    715:         xmlC14NErrParam("processing namespaces axis (exc c14n)");
                    716:         return (-1);
                    717:     }
                    718: 
                    719:     if(!xmlC14NIsExclusive(ctx)) {
                    720:         xmlC14NErrParam("processing namespaces axis (exc c14n)");
                    721:         return (-1);
                    722: 
                    723:     }
                    724: 
                    725:     /*
                    726:      * Create a sorted list to store element namespaces
                    727:      */
                    728:     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
                    729:     if (list == NULL) {
                    730:         xmlC14NErrInternal("creating namespaces list (exc c14n)");
                    731:         return (-1);
                    732:     }
                    733: 
                    734:     /* 
                    735:      * process inclusive namespaces:
                    736:      * All namespace nodes appearing on inclusive ns list are 
                    737:      * handled as provided in Canonical XML
                    738:      */
                    739:     if(ctx->inclusive_ns_prefixes != NULL) {
                    740:        xmlChar *prefix; 
                    741:        int i;
                    742:        
                    743:        for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
                    744:            prefix = ctx->inclusive_ns_prefixes[i];
                    745:            /*
                    746:             * Special values for namespace with empty prefix
                    747:             */
                    748:             if (xmlStrEqual(prefix, BAD_CAST "#default")
                    749:                 || xmlStrEqual(prefix, BAD_CAST "")) {
                    750:                 prefix = NULL;
                    751:                has_empty_ns_in_inclusive_list = 1;
                    752:             }
                    753:        
                    754:            ns = xmlSearchNs(cur->doc, cur, prefix);        
                    755:            if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
                    756:                already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
                    757:                if(visible) {
                    758:                    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
                    759:                }
                    760:                if(!already_rendered) {
                    761:                    xmlListInsert(list, ns); 
                    762:                }
                    763:                if(xmlStrlen(ns->prefix) == 0) {
                    764:                    has_empty_ns = 1;
                    765:                }
                    766:            }
                    767:        }
                    768:     }
                    769:     
                    770:     /* add node namespace */
                    771:     if(cur->ns != NULL) {
                    772:        ns = cur->ns;
                    773:     } else {
                    774:         ns = xmlSearchNs(cur->doc, cur, NULL);
                    775:        has_visibly_utilized_empty_ns = 1;
                    776:     }
                    777:     if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
                    778:        if(visible && xmlC14NIsVisible(ctx, ns, cur)) { 
                    779:            if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
                    780:                xmlListInsert(list, ns);
                    781:            }
                    782:        }
                    783:        if(visible) {
                    784:            xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); 
                    785:        }
                    786:        if(xmlStrlen(ns->prefix) == 0) {
                    787:            has_empty_ns = 1;
                    788:        }
                    789:     }
                    790:     
                    791:         
                    792:     /* add attributes */
                    793:     for(attr = cur->properties; attr != NULL; attr = attr->next) {
                    794:         /* 
                    795:          * we need to check that attribute is visible and has non
                    796:          * default namespace (XML Namespaces: "default namespaces 
                    797:         * do not apply directly to attributes")         
                    798:          */
                    799:        if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) {
                    800:            already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
                    801:            xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur); 
                    802:            if(!already_rendered && visible) {
                    803:                xmlListInsert(list, attr->ns); 
                    804:            }
                    805:            if(xmlStrlen(attr->ns->prefix) == 0) {
                    806:                has_empty_ns = 1;
                    807:            }
                    808:        } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) {
                    809:            has_visibly_utilized_empty_ns = 1;
                    810:        }
                    811:     }
                    812: 
                    813:     /*
                    814:      * Process xmlns=""
                    815:      */
                    816:     if(visible && has_visibly_utilized_empty_ns && 
                    817:            !has_empty_ns && !has_empty_ns_in_inclusive_list) {
                    818:         static xmlNs ns_default;
                    819: 
                    820:         memset(&ns_default, 0, sizeof(ns_default));
                    821:        
                    822:         already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
                    823:        if(!already_rendered) {
                    824:            xmlC14NPrintNamespaces(&ns_default, ctx);
                    825:        }
                    826:     } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
                    827:         static xmlNs ns_default;
                    828: 
                    829:         memset(&ns_default, 0, sizeof(ns_default));
                    830:         if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
                    831:            xmlC14NPrintNamespaces(&ns_default, ctx);
                    832:        }
                    833:     }
                    834: 
                    835:     
                    836: 
                    837:     /* 
                    838:      * print out all elements from list 
                    839:      */
                    840:     xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
                    841: 
                    842:     /* 
                    843:      * Cleanup
                    844:      */
                    845:     xmlListDelete(list);
                    846:     return (0);
                    847: }
                    848: 
                    849: 
                    850: /**
                    851:  * xmlC14NIsXmlAttr:
                    852:  * @attr:              the attr to check
                    853:  *             
                    854:  * Checks whether the given attribute is a default "xml:" namespace
                    855:  * with href="http://www.w3.org/XML/1998/namespace"
                    856:  *
                    857:  * Returns 1 if the node is default or 0 otherwise
                    858:  */
                    859: 
                    860: /* todo: make it a define? */
                    861: static int
                    862: xmlC14NIsXmlAttr(xmlAttrPtr attr)
                    863: {
                    864:     return ((attr->ns != NULL) && 
                    865:            (xmlC14NIsXmlNs(attr->ns) != 0));
                    866: }
                    867: 
                    868: 
                    869: /**
                    870:  * xmlC14NAttrsCompare:
                    871:  * @attr1:             the pointer tls o first attr
                    872:  * @attr2:             the pointer to second attr
                    873:  *
                    874:  * Prints the given attribute to the output buffer from C14N context.
                    875:  *
                    876:  * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
                    877:  */
                    878: static int
                    879: xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
                    880: {
                    881:     int ret = 0;
                    882: 
                    883:     /*
                    884:      * Simple cases
                    885:      */
                    886:     if (attr1 == attr2)
                    887:         return (0);
                    888:     if (attr1 == NULL)
                    889:         return (-1);
                    890:     if (attr2 == NULL)
                    891:         return (1);
                    892:     if (attr1->ns == attr2->ns) {
                    893:         return (xmlStrcmp(attr1->name, attr2->name));
                    894:     }
                    895: 
                    896:     /* 
                    897:      * Attributes in the default namespace are first
                    898:      * because the default namespace is not applied to
                    899:      * unqualified attributes
                    900:      */
                    901:     if (attr1->ns == NULL)
                    902:         return (-1);
                    903:     if (attr2->ns == NULL)
                    904:         return (1);
                    905:     if (attr1->ns->prefix == NULL)
                    906:         return (-1);
                    907:     if (attr2->ns->prefix == NULL)
                    908:         return (1);
                    909: 
                    910:     ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
                    911:     if (ret == 0) {
                    912:         ret = xmlStrcmp(attr1->name, attr2->name);
                    913:     }
                    914:     return (ret);
                    915: }
                    916: 
                    917: 
                    918: /**
                    919:  * xmlC14NPrintAttrs:
                    920:  * @attr:              the pointer to attr
                    921:  * @ctx:               the C14N context
                    922:  *
                    923:  * Prints out canonical attribute urrent node to the
                    924:  * buffer from C14N context as follows 
                    925:  *
                    926:  * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
                    927:  *
                    928:  * Returns 1 on success or 0 on fail.
                    929:  */
                    930: static int
                    931: xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
                    932: {
                    933:     xmlChar *value;
                    934:     xmlChar *buffer;
                    935: 
                    936:     if ((attr == NULL) || (ctx == NULL)) {
                    937:         xmlC14NErrParam("writing attributes");
                    938:         return (0);
                    939:     }
                    940: 
                    941:     xmlOutputBufferWriteString(ctx->buf, " ");
                    942:     if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
                    943:         xmlOutputBufferWriteString(ctx->buf,
                    944:                                    (const char *) attr->ns->prefix);
                    945:         xmlOutputBufferWriteString(ctx->buf, ":");
                    946:     }
                    947:     xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
                    948:     xmlOutputBufferWriteString(ctx->buf, "=\"");
                    949: 
                    950:     value = xmlNodeListGetString(ctx->doc, attr->children, 1);
                    951:     /* todo: should we log an error if value==NULL ? */
                    952:     if (value != NULL) {
                    953:         buffer = xmlC11NNormalizeAttr(value);
                    954:         xmlFree(value);
                    955:         if (buffer != NULL) {
                    956:             xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
                    957:             xmlFree(buffer);
                    958:         } else {
                    959:             xmlC14NErrInternal("normalizing attributes axis");
                    960:             return (0);
                    961:         }
                    962:     }
                    963:     xmlOutputBufferWriteString(ctx->buf, "\"");
                    964:     return (1);
                    965: }
                    966: 
                    967: /**
                    968:  * xmlC14NFindHiddenParentAttr:
                    969:  *
                    970:  * Finds an attribute in a hidden parent node.
                    971:  * 
                    972:  * Returns a pointer to the attribute node (if found) or NULL otherwise.
                    973:  */
                    974: static xmlAttrPtr
                    975: xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns)
                    976: {
                    977:     xmlAttrPtr res;
                    978:     while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
                    979:         res = xmlHasNsProp(cur, name, ns);
                    980:         if(res != NULL) {
                    981:             return res;
                    982:         }
                    983: 
                    984:         cur = cur->parent;
                    985:     }
                    986: 
                    987:     return NULL;
                    988: }
                    989: 
                    990: /**
                    991:  * xmlC14NFixupBaseAttr:
                    992:  *
                    993:  * Fixes up the xml:base attribute
                    994:  *
                    995:  * Returns the newly created attribute or NULL
                    996:  */
                    997: static xmlAttrPtr
                    998: xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr)
                    999: {    
                   1000:     xmlChar * res = NULL;
                   1001:     xmlNodePtr cur;
                   1002:     xmlAttrPtr attr;
                   1003:     xmlChar * tmp_str;
                   1004:     xmlChar * tmp_str2;
                   1005:     int tmp_str_len;
                   1006: 
                   1007:     if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) {
                   1008:         xmlC14NErrParam("processing xml:base attribute");
                   1009:         return (NULL);
                   1010:     }
                   1011: 
                   1012:     /* start from current value */
                   1013:     res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1);
                   1014:     if(res == NULL) {
                   1015:         xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
                   1016:         return (NULL);
                   1017:     }
                   1018: 
                   1019:     /* go up the stack until we find a node that we rendered already */
                   1020:     cur = xml_base_attr->parent->parent;
                   1021:     while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
                   1022:         attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
                   1023:         if(attr != NULL) {
                   1024:             /* get attr value */
                   1025:             tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1);
                   1026:             if(tmp_str == NULL) {
                   1027:                 xmlFree(res);
                   1028: 
                   1029:                 xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
                   1030:                 return (NULL);
                   1031:             } 
                   1032: 
                   1033:             /* we need to add '/' if our current base uri ends with '..' or '.' 
                   1034:             to ensure that we are forced to go "up" all the time */
                   1035:             tmp_str_len = xmlStrlen(tmp_str);
                   1036:             if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') {
                   1037:                 tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/");
                   1038:                 if(tmp_str2 == NULL) {
                   1039:                     xmlFree(tmp_str);
                   1040:                     xmlFree(res);
                   1041: 
                   1042:                     xmlC14NErrInternal("processing xml:base attribute - can't modify uri");
                   1043:                     return (NULL);
                   1044:                 }
                   1045: 
                   1046:                 tmp_str = tmp_str2;
                   1047:             }
                   1048: 
                   1049:             /* build uri */
                   1050:             tmp_str2 = xmlBuildURI(res, tmp_str); 
                   1051:             if(tmp_str2 == NULL) {
                   1052:                 xmlFree(tmp_str);
                   1053:                 xmlFree(res);
                   1054: 
                   1055:                 xmlC14NErrInternal("processing xml:base attribute - can't construct uri");
                   1056:                 return (NULL);
                   1057:             }
                   1058: 
                   1059:             /* cleanup and set the new res */
                   1060:             xmlFree(tmp_str);
                   1061:             xmlFree(res);
                   1062:             res = tmp_str2;
                   1063:         }
                   1064: 
                   1065:         /* next */
                   1066:         cur = cur->parent;
                   1067:     }
                   1068: 
                   1069:     /* check if result uri is empty or not */
                   1070:     if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) {
                   1071:         xmlFree(res);
                   1072:         return (NULL);
                   1073:     }
                   1074: 
                   1075:     /* create and return the new attribute node */
                   1076:     attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res);
                   1077:     if(attr == NULL) {
                   1078:         xmlFree(res);
                   1079: 
                   1080:         xmlC14NErrInternal("processing xml:base attribute - can't construct attribute");
                   1081:         return (NULL);
                   1082:     }
                   1083:  
                   1084:     /* done */
                   1085:     xmlFree(res);
                   1086:     return (attr);
                   1087: }
                   1088: 
                   1089: /**
                   1090:  * xmlC14NProcessAttrsAxis:
                   1091:  * @ctx:               the C14N context
                   1092:  * @cur:               the current node
                   1093:  * @parent_visible:    the visibility of parent node
                   1094:  * @all_parents_visible: the visibility of all parent nodes
                   1095:  *
                   1096:  * Prints out canonical attribute axis of the current node to the
                   1097:  * buffer from C14N context as follows 
                   1098:  *
                   1099:  * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
                   1100:  *
                   1101:  * Attribute Axis 
                   1102:  * In lexicographic order (ascending), process each node that 
                   1103:  * is in the element's attribute axis and in the node-set.
                   1104:  * 
                   1105:  * The processing of an element node E MUST be modified slightly 
                   1106:  * when an XPath node-set is given as input and the element's 
                   1107:  * parent is omitted from the node-set.
                   1108:  *
                   1109:  *
                   1110:  * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
                   1111:  *
                   1112:  * Canonical XML applied to a document subset requires the search of the 
                   1113:  * ancestor nodes of each orphan element node for attributes in the xml 
                   1114:  * namespace, such as xml:lang and xml:space. These are copied into the 
                   1115:  * element node except if a declaration of the same attribute is already 
                   1116:  * in the attribute axis of the element (whether or not it is included in 
                   1117:  * the document subset). This search and copying are omitted from the 
                   1118:  * Exclusive XML Canonicalization method.
                   1119:  *
                   1120:  * Returns 0 on success or -1 on fail.
                   1121:  */
                   1122: static int
                   1123: xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible)
                   1124: {
                   1125:     xmlAttrPtr attr;
                   1126:     xmlListPtr list;    
                   1127:     xmlAttrPtr attrs_to_delete = NULL;
                   1128:     
                   1129:     /* special processing for 1.1 spec */
                   1130:     xmlAttrPtr xml_base_attr = NULL;
                   1131:     xmlAttrPtr xml_lang_attr = NULL;
                   1132:     xmlAttrPtr xml_space_attr = NULL;
                   1133: 
                   1134:     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
                   1135:         xmlC14NErrParam("processing attributes axis");
                   1136:         return (-1);
                   1137:     }
                   1138: 
                   1139:     /*
                   1140:      * Create a sorted list to store element attributes
                   1141:      */
                   1142:     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
                   1143:     if (list == NULL) {
                   1144:         xmlC14NErrInternal("creating attributes list");
                   1145:         return (-1);
                   1146:     }
                   1147: 
                   1148:     switch(ctx->mode) {
                   1149:     case XML_C14N_1_0:
                   1150:         /* The processing of an element node E MUST be modified slightly when an XPath node-set is 
                   1151:          * given as input and the element's parent is omitted from the node-set. The method for processing 
                   1152:          * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's 
                   1153:          * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such 
                   1154:          * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes, 
                   1155:          * remove any that are in E's attribute axis (whether or not they are in the node-set). Then, 
                   1156:          * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 
                   1157:          * the node-set. The result of visiting the attribute axis is computed by processing the attribute 
                   1158:          * nodes in this merged attribute list. 
                   1159:          */
                   1160:     
                   1161:         /* 
                   1162:          * Add all visible attributes from current node. 
                   1163:          */
                   1164:         attr = cur->properties;
                   1165:         while (attr != NULL) {
                   1166:             /* check that attribute is visible */
                   1167:             if (xmlC14NIsVisible(ctx, attr, cur)) {
                   1168:                 xmlListInsert(list, attr);
                   1169:             }
                   1170:             attr = attr->next;
                   1171:         }
                   1172: 
                   1173:         /* 
                   1174:          * Handle xml attributes
                   1175:          */
                   1176:         if (parent_visible && (cur->parent != NULL) && 
                   1177:             (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) 
                   1178:         {
                   1179:             xmlNodePtr tmp;
                   1180: 
                   1181:             /*
                   1182:              * If XPath node-set is not specified then the parent is always 
                   1183:              * visible!
                   1184:              */
                   1185:             tmp = cur->parent;
                   1186:             while (tmp != NULL) {
                   1187:                 attr = tmp->properties;
                   1188:                 while (attr != NULL) {
                   1189:                     if (xmlC14NIsXmlAttr(attr) != 0) {
                   1190:                         if (xmlListSearch(list, attr) == NULL) {
                   1191:                             xmlListInsert(list, attr);
                   1192:                         }
                   1193:                     }
                   1194:                     attr = attr->next;
                   1195:                 }
                   1196:                 tmp = tmp->parent;
                   1197:             }
                   1198:         }
                   1199: 
                   1200:         /* done */
                   1201:         break;
                   1202:     case XML_C14N_EXCLUSIVE_1_0:
                   1203:         /* attributes in the XML namespace, such as xml:lang and xml:space 
                   1204:          * are not imported into orphan nodes of the document subset 
                   1205:          */
                   1206: 
                   1207:         /* 
                   1208:          * Add all visible attributes from current node. 
                   1209:          */
                   1210:         attr = cur->properties;
                   1211:         while (attr != NULL) {
                   1212:             /* check that attribute is visible */
                   1213:             if (xmlC14NIsVisible(ctx, attr, cur)) {
                   1214:                 xmlListInsert(list, attr);
                   1215:             }
                   1216:             attr = attr->next;
                   1217:         }
                   1218: 
                   1219:         /* do nothing special for xml attributes */
                   1220:         break;
                   1221:     case XML_C14N_1_1:
                   1222:         /* The processing of an element node E MUST be modified slightly when an XPath node-set is 
                   1223:          * given as input and some of the element's ancestors are omitted from the node-set. 
                   1224:          *
                   1225:          * Simple inheritable attributes are attributes that have a value that requires at most a simple 
                   1226:          * redeclaration. This redeclaration is done by supplying a new value in the child axis. The 
                   1227:          * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done 
                   1228:          * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes 
                   1229:          * are xml:lang and xml:space.
                   1230:          * 
                   1231:          * The method for processing the attribute axis of an element E in the node-set is hence enhanced. 
                   1232:          * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple 
                   1233:          * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they 
                   1234:          * are in the node-set). From this list of attributes, any simple inheritable attributes that are 
                   1235:          * already in E's attribute axis (whether or not they are in the node-set) are removed. Then, 
                   1236:          * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 
                   1237:          * the node-set. The result of visiting the attribute axis is computed by processing the attribute 
                   1238:          * nodes in this merged attribute list.
                   1239:          * 
                   1240:          * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is 
                   1241:          * performed.
                   1242:          * 
                   1243:          * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond 
                   1244:          * a simple redeclaration.
                   1245:          * 
                   1246:          * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed 
                   1247:          * as ordinary attributes.
                   1248:          */
                   1249: 
                   1250:         /* 
                   1251:          * Add all visible attributes from current node. 
                   1252:          */
                   1253:         attr = cur->properties;
                   1254:         while (attr != NULL) {
                   1255:             /* special processing for XML attribute kiks in only when we have invisible parents */
                   1256:             if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) {
                   1257:                 /* check that attribute is visible */
                   1258:                 if (xmlC14NIsVisible(ctx, attr, cur)) {
                   1259:                     xmlListInsert(list, attr);
                   1260:                 }
                   1261:             } else {
                   1262:                 int matched = 0;
                   1263: 
                   1264:                 /* check for simple inheritance attributes */
                   1265:                 if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) {
                   1266:                     xml_lang_attr = attr;
                   1267:                     matched = 1;
                   1268:                 } 
                   1269:                 if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) {
                   1270:                     xml_space_attr = attr;
                   1271:                     matched = 1;
                   1272:                 }
                   1273: 
                   1274:                 /* check for base attr */
                   1275:                 if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) {
                   1276:                     xml_base_attr = attr;
                   1277:                     matched = 1;
                   1278:                 }
                   1279: 
                   1280:                 /* otherwise, it is a normal attribute, so just check if it is visible */
                   1281:                 if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) {
                   1282:                     xmlListInsert(list, attr);
                   1283:                 }
                   1284:             }
                   1285:          
                   1286:             /* move to the next one */
                   1287:             attr = attr->next;
                   1288:         }
                   1289:             
                   1290:         /* special processing for XML attribute kiks in only when we have invisible parents */
                   1291:         if ((parent_visible)) {
                   1292: 
                   1293:             /* simple inheritance attributes - copy */
                   1294:             if(xml_lang_attr == NULL) {
                   1295:                 xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE);
                   1296:             }
                   1297:             if(xml_lang_attr != NULL) {
                   1298:                 xmlListInsert(list, xml_lang_attr);
                   1299:             }
                   1300:             if(xml_space_attr == NULL) {
                   1301:                 xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE);
                   1302:             }
                   1303:             if(xml_space_attr != NULL) {
                   1304:                 xmlListInsert(list, xml_space_attr);
                   1305:             }
                   1306: 
                   1307:             /* base uri attribute - fix up */
                   1308:             if(xml_base_attr == NULL) {
                   1309:                 /* if we don't have base uri attribute, check if we have a "hidden" one above */
                   1310:                 xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE);
                   1311:             }
                   1312:             if(xml_base_attr != NULL) {
                   1313:                 xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr);
                   1314:                 if(xml_base_attr != NULL) {                    
                   1315:                     xmlListInsert(list, xml_base_attr);
                   1316: 
                   1317:                     /* note that we MUST delete returned attr node ourselves! */
                   1318:                     xml_base_attr->next = attrs_to_delete;
                   1319:                     attrs_to_delete = xml_base_attr;
                   1320:                 }
                   1321:             }
                   1322:         }
                   1323: 
                   1324:         /* done */
                   1325:         break;
                   1326:     }
                   1327: 
                   1328:     /* 
                   1329:      * print out all elements from list 
                   1330:      */
                   1331:     xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
                   1332: 
                   1333:     /* 
                   1334:      * Cleanup
                   1335:      */
                   1336:     xmlFreePropList(attrs_to_delete);
                   1337:     xmlListDelete(list);
                   1338:     return (0);
                   1339: }
                   1340: 
                   1341: /** 
                   1342:  * xmlC14NCheckForRelativeNamespaces:
                   1343:  * @ctx:               the C14N context
                   1344:  * @cur:               the current element node
                   1345:  *
                   1346:  * Checks that current element node has no relative namespaces defined
                   1347:  *
                   1348:  * Returns 0 if the node has no relative namespaces or -1 otherwise.
                   1349:  */
                   1350: static int
                   1351: xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
                   1352: {
                   1353:     xmlNsPtr ns;
                   1354: 
                   1355:     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
                   1356:         xmlC14NErrParam("checking for relative namespaces");
                   1357:         return (-1);
                   1358:     }
                   1359: 
                   1360:     ns = cur->nsDef;
                   1361:     while (ns != NULL) {
                   1362:         if (xmlStrlen(ns->href) > 0) {
                   1363:             xmlURIPtr uri;
                   1364: 
                   1365:             uri = xmlParseURI((const char *) ns->href);
                   1366:             if (uri == NULL) {
                   1367:                 xmlC14NErrInternal("parsing namespace uri");
                   1368:                 return (-1);
                   1369:             }
                   1370:             if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
                   1371:                 xmlC14NErrRelativeNamespace(uri->scheme);
                   1372:                 xmlFreeURI(uri);
                   1373:                 return (-1);
                   1374:             }
                   1375:             if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0)
                   1376:                 && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0)
                   1377:                 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
                   1378:                 xmlC14NErrRelativeNamespace(uri->scheme);
                   1379:                 xmlFreeURI(uri);
                   1380:                 return (-1);
                   1381:             }
                   1382:             xmlFreeURI(uri);
                   1383:         }
                   1384:         ns = ns->next;
                   1385:     }
                   1386:     return (0);
                   1387: }
                   1388: 
                   1389: /**
                   1390:  * xmlC14NProcessElementNode:
                   1391:  * @ctx:               the pointer to C14N context object
                   1392:  * @cur:               the node to process
                   1393:  * @visible:    this node is visible
                   1394:  * @all_parents_visible: whether all the parents of this node are visible
                   1395:  *             
                   1396:  * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
                   1397:  *
                   1398:  * Element Nodes
                   1399:  * If the element is not in the node-set, then the result is obtained 
                   1400:  * by processing the namespace axis, then the attribute axis, then 
                   1401:  * processing the child nodes of the element that are in the node-set 
                   1402:  * (in document order). If the element is in the node-set, then the result 
                   1403:  * is an open angle bracket (<), the element QName, the result of 
                   1404:  * processing the namespace axis, the result of processing the attribute 
                   1405:  * axis, a close angle bracket (>), the result of processing the child 
                   1406:  * nodes of the element that are in the node-set (in document order), an 
                   1407:  * open angle bracket, a forward slash (/), the element QName, and a close 
                   1408:  * angle bracket.
                   1409:  *
                   1410:  * Returns non-negative value on success or negative value on fail
                   1411:  */
                   1412: static int
                   1413: xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
                   1414: {
                   1415:     int ret;
                   1416:     xmlC14NVisibleNsStack state;
                   1417:     int parent_is_doc = 0;
                   1418: 
                   1419:     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
                   1420:         xmlC14NErrParam("processing element node");
                   1421:         return (-1);
                   1422:     }
                   1423: 
                   1424:     /* 
                   1425:      * Check relative relative namespaces:
                   1426:      * implementations of XML canonicalization MUST report an operation
                   1427:      * failure on documents containing relative namespace URIs.
                   1428:      */
                   1429:     if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
                   1430:         xmlC14NErrInternal("checking for relative namespaces");
                   1431:         return (-1);
                   1432:     }
                   1433: 
                   1434: 
                   1435:     /* 
                   1436:      * Save ns_rendered stack position
                   1437:      */
                   1438:     memset(&state, 0, sizeof(state));
                   1439:     xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
                   1440: 
                   1441:     if (visible) {     
                   1442:         if (ctx->parent_is_doc) {
                   1443:            /* save this flag into the stack */
                   1444:            parent_is_doc = ctx->parent_is_doc;
                   1445:            ctx->parent_is_doc = 0;
                   1446:             ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
                   1447:         }
                   1448:         xmlOutputBufferWriteString(ctx->buf, "<");
                   1449: 
                   1450:         if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
                   1451:             xmlOutputBufferWriteString(ctx->buf,
                   1452:                                        (const char *) cur->ns->prefix);
                   1453:             xmlOutputBufferWriteString(ctx->buf, ":");
                   1454:         }
                   1455:         xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
                   1456:     }
                   1457: 
                   1458:     if (!xmlC14NIsExclusive(ctx)) {
                   1459:         ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
                   1460:     } else {
                   1461:         ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
                   1462:     }
                   1463:     if (ret < 0) {
                   1464:         xmlC14NErrInternal("processing namespaces axis");
                   1465:         return (-1);
                   1466:     }
                   1467:     /* todo: shouldn't this go to "visible only"? */
                   1468:     if(visible) {
                   1469:        xmlC14NVisibleNsStackShift(ctx->ns_rendered);
                   1470:     }
                   1471:     
                   1472:     ret = xmlC14NProcessAttrsAxis(ctx, cur, visible);
                   1473:     if (ret < 0) {
                   1474:        xmlC14NErrInternal("processing attributes axis");
                   1475:        return (-1);
                   1476:     }
                   1477: 
                   1478:     if (visible) { 
                   1479:         xmlOutputBufferWriteString(ctx->buf, ">");
                   1480:     }
                   1481:     if (cur->children != NULL) {
                   1482:         ret = xmlC14NProcessNodeList(ctx, cur->children);
                   1483:         if (ret < 0) {
                   1484:             xmlC14NErrInternal("processing childrens list");
                   1485:             return (-1);
                   1486:         }
                   1487:     }
                   1488:     if (visible) {
                   1489:         xmlOutputBufferWriteString(ctx->buf, "</");
                   1490:         if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
                   1491:             xmlOutputBufferWriteString(ctx->buf,
                   1492:                                        (const char *) cur->ns->prefix);
                   1493:             xmlOutputBufferWriteString(ctx->buf, ":");
                   1494:         }
                   1495:         xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
                   1496:         xmlOutputBufferWriteString(ctx->buf, ">");
                   1497:         if (parent_is_doc) {
                   1498:            /* restore this flag from the stack for next node */
                   1499:             ctx->parent_is_doc = parent_is_doc;
                   1500:            ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
                   1501:         }
                   1502:     }
                   1503: 
                   1504:     /* 
                   1505:      * Restore ns_rendered stack position
                   1506:      */
                   1507:     xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
                   1508:     return (0);
                   1509: }
                   1510: 
                   1511: /**
                   1512:  * xmlC14NProcessNode:
                   1513:  * @ctx:               the pointer to C14N context object
                   1514:  * @cur:               the node to process
                   1515:  *             
                   1516:  * Processes the given node
                   1517:  *
                   1518:  * Returns non-negative value on success or negative value on fail
                   1519:  */
                   1520: static int
                   1521: xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
                   1522: {
                   1523:     int ret = 0;
                   1524:     int visible;
                   1525: 
                   1526:     if ((ctx == NULL) || (cur == NULL)) {
                   1527:         xmlC14NErrParam("processing node");
                   1528:         return (-1);
                   1529:     }
                   1530: 
                   1531:     visible = xmlC14NIsVisible(ctx, cur, cur->parent);
                   1532:     switch (cur->type) {
                   1533:         case XML_ELEMENT_NODE:
                   1534:             ret = xmlC14NProcessElementNode(ctx, cur, visible);
                   1535:             break;
                   1536:         case XML_CDATA_SECTION_NODE:
                   1537:         case XML_TEXT_NODE:
                   1538:             /*
                   1539:              * Text Nodes
                   1540:              * the string value, except all ampersands are replaced 
                   1541:              * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing 
                   1542:              * angle brackets (>) are replaced by &gt;, and all #xD characters are 
                   1543:              * replaced by &#xD;.
                   1544:              */
                   1545:             /* cdata sections are processed as text nodes */
                   1546:             /* todo: verify that cdata sections are included in XPath nodes set */
                   1547:             if ((visible) && (cur->content != NULL)) {
                   1548:                 xmlChar *buffer;
                   1549: 
                   1550:                 buffer = xmlC11NNormalizeText(cur->content);
                   1551:                 if (buffer != NULL) {
                   1552:                     xmlOutputBufferWriteString(ctx->buf,
                   1553:                                                (const char *) buffer);
                   1554:                     xmlFree(buffer);
                   1555:                 } else {
                   1556:                     xmlC14NErrInternal("normalizing text node");
                   1557:                     return (-1);
                   1558:                 }
                   1559:             }
                   1560:             break;
                   1561:         case XML_PI_NODE:
                   1562:             /* 
                   1563:              * Processing Instruction (PI) Nodes- 
                   1564:              * The opening PI symbol (<?), the PI target name of the node, 
                   1565:              * a leading space and the string value if it is not empty, and 
                   1566:              * the closing PI symbol (?>). If the string value is empty, 
                   1567:              * then the leading space is not added. Also, a trailing #xA is 
                   1568:              * rendered after the closing PI symbol for PI children of the 
                   1569:              * root node with a lesser document order than the document 
                   1570:              * element, and a leading #xA is rendered before the opening PI 
                   1571:              * symbol of PI children of the root node with a greater document 
                   1572:              * order than the document element.
                   1573:              */
                   1574:             if (visible) {
                   1575:                 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
                   1576:                     xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
                   1577:                 } else {
                   1578:                     xmlOutputBufferWriteString(ctx->buf, "<?");
                   1579:                 }
                   1580: 
                   1581:                 xmlOutputBufferWriteString(ctx->buf,
                   1582:                                            (const char *) cur->name);
                   1583:                 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
                   1584:                     xmlChar *buffer;
                   1585: 
                   1586:                     xmlOutputBufferWriteString(ctx->buf, " ");
                   1587: 
                   1588:                     /* todo: do we need to normalize pi? */
                   1589:                     buffer = xmlC11NNormalizePI(cur->content);
                   1590:                     if (buffer != NULL) {
                   1591:                         xmlOutputBufferWriteString(ctx->buf,
                   1592:                                                    (const char *) buffer);
                   1593:                         xmlFree(buffer);
                   1594:                     } else {
                   1595:                         xmlC14NErrInternal("normalizing pi node");
                   1596:                         return (-1);
                   1597:                     }
                   1598:                 }
                   1599: 
                   1600:                 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
                   1601:                     xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
                   1602:                 } else {
                   1603:                     xmlOutputBufferWriteString(ctx->buf, "?>");
                   1604:                 }
                   1605:             }
                   1606:             break;
                   1607:         case XML_COMMENT_NODE:
                   1608:             /*
                   1609:              * Comment Nodes
                   1610:              * Nothing if generating canonical XML without  comments. For 
                   1611:              * canonical XML with comments, generate the opening comment 
                   1612:              * symbol (<!--), the string value of the node, and the 
                   1613:              * closing comment symbol (-->). Also, a trailing #xA is rendered 
                   1614:              * after the closing comment symbol for comment children of the 
                   1615:              * root node with a lesser document order than the document 
                   1616:              * element, and a leading #xA is rendered before the opening 
                   1617:              * comment symbol of comment children of the root node with a 
                   1618:              * greater document order than the document element. (Comment 
                   1619:              * children of the root node represent comments outside of the 
                   1620:              * top-level document element and outside of the document type 
                   1621:              * declaration).
                   1622:              */
                   1623:             if (visible && ctx->with_comments) {
                   1624:                 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
                   1625:                     xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
                   1626:                 } else {
                   1627:                     xmlOutputBufferWriteString(ctx->buf, "<!--");
                   1628:                 }
                   1629: 
                   1630:                 if (cur->content != NULL) {
                   1631:                     xmlChar *buffer;
                   1632: 
                   1633:                     /* todo: do we need to normalize comment? */
                   1634:                     buffer = xmlC11NNormalizeComment(cur->content);
                   1635:                     if (buffer != NULL) {
                   1636:                         xmlOutputBufferWriteString(ctx->buf,
                   1637:                                                    (const char *) buffer);
                   1638:                         xmlFree(buffer);
                   1639:                     } else {
                   1640:                         xmlC14NErrInternal("normalizing comment node");
                   1641:                         return (-1);
                   1642:                     }
                   1643:                 }
                   1644: 
                   1645:                 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
                   1646:                     xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
                   1647:                 } else {
                   1648:                     xmlOutputBufferWriteString(ctx->buf, "-->");
                   1649:                 }
                   1650:             }
                   1651:             break;
                   1652:         case XML_DOCUMENT_NODE:
                   1653:         case XML_DOCUMENT_FRAG_NODE:   /* should be processed as document? */
                   1654: #ifdef LIBXML_DOCB_ENABLED
                   1655:         case XML_DOCB_DOCUMENT_NODE:   /* should be processed as document? */
                   1656: #endif
                   1657: #ifdef LIBXML_HTML_ENABLED
                   1658:         case XML_HTML_DOCUMENT_NODE:   /* should be processed as document? */
                   1659: #endif
                   1660:             if (cur->children != NULL) {
                   1661:                 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
                   1662:                 ctx->parent_is_doc = 1;
                   1663:                 ret = xmlC14NProcessNodeList(ctx, cur->children);
                   1664:             }
                   1665:             break;
                   1666: 
                   1667:         case XML_ATTRIBUTE_NODE:
                   1668:             xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node");
                   1669:             return (-1);
                   1670:         case XML_NAMESPACE_DECL:
                   1671:             xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node");
                   1672:             return (-1);
                   1673:         case XML_ENTITY_REF_NODE:
                   1674:             xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node");
                   1675:             return (-1);
                   1676:         case XML_ENTITY_NODE:
                   1677:             xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node");
                   1678:             return (-1);
                   1679: 
                   1680:         case XML_DOCUMENT_TYPE_NODE:
                   1681:         case XML_NOTATION_NODE:
                   1682:         case XML_DTD_NODE:
                   1683:         case XML_ELEMENT_DECL:
                   1684:         case XML_ATTRIBUTE_DECL:
                   1685:         case XML_ENTITY_DECL:
                   1686: #ifdef LIBXML_XINCLUDE_ENABLED
                   1687:         case XML_XINCLUDE_START:
                   1688:         case XML_XINCLUDE_END:
                   1689: #endif
                   1690:             /* 
                   1691:              * should be ignored according to "W3C Canonical XML" 
                   1692:              */
                   1693:             break;
                   1694:         default:
                   1695:             xmlC14NErrUnknownNode(cur->type, "processing node");
                   1696:             return (-1);
                   1697:     }
                   1698: 
                   1699:     return (ret);
                   1700: }
                   1701: 
                   1702: /**
                   1703:  * xmlC14NProcessNodeList:
                   1704:  * @ctx:               the pointer to C14N context object
                   1705:  * @cur:               the node to start from
                   1706:  *             
                   1707:  * Processes all nodes in the row starting from cur.
                   1708:  *
                   1709:  * Returns non-negative value on success or negative value on fail
                   1710:  */
                   1711: static int
                   1712: xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
                   1713: {
                   1714:     int ret;
                   1715: 
                   1716:     if (ctx == NULL) {
                   1717:         xmlC14NErrParam("processing node list");
                   1718:         return (-1);
                   1719:     }
                   1720: 
                   1721:     for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
                   1722:         ret = xmlC14NProcessNode(ctx, cur);
                   1723:     }
                   1724:     return (ret);
                   1725: }
                   1726: 
                   1727: 
                   1728: /**
                   1729:  * xmlC14NFreeCtx:
                   1730:  * @ctx: the pointer to C14N context object
                   1731:  *             
                   1732:  * Cleanups the C14N context object.
                   1733:  */
                   1734: 
                   1735: static void
                   1736: xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
                   1737: {
                   1738:     if (ctx == NULL) {
                   1739:         xmlC14NErrParam("freeing context");
                   1740:         return;
                   1741:     }
                   1742: 
                   1743:     if (ctx->ns_rendered != NULL) {
                   1744:         xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
                   1745:     }
                   1746:     xmlFree(ctx);
                   1747: }
                   1748: 
                   1749: /**
                   1750:  * xmlC14NNewCtx:
                   1751:  * @doc:               the XML document for canonization
                   1752:  * @is_visible_callback:the function to use to determine is node visible 
                   1753:  *                     or not
                   1754:  * @user_data:                 the first parameter for @is_visible_callback function
                   1755:  *                     (in most cases, it is nodes set)
                   1756:  * @mode:   the c14n mode (see @xmlC14NMode)
                   1757:  * @inclusive_ns_prefixe the list of inclusive namespace prefixes 
                   1758:  *                     ended with a NULL or NULL if there is no
                   1759:  *                     inclusive namespaces (only for ` 
                   1760:  *                     canonicalization)
                   1761:  * @with_comments:     include comments in the result (!=0) or not (==0)
                   1762:  * @buf:               the output buffer to store canonical XML; this 
                   1763:  *                     buffer MUST have encoder==NULL because C14N requires
                   1764:  *                     UTF-8 output
                   1765:  *             
                   1766:  * Creates new C14N context object to store C14N parameters.
                   1767:  *
                   1768:  * Returns pointer to newly created object (success) or NULL (fail)
                   1769:  */
                   1770: static xmlC14NCtxPtr
                   1771: xmlC14NNewCtx(xmlDocPtr doc,  
                   1772:              xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
                   1773:               xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes,
                   1774:               int with_comments, xmlOutputBufferPtr buf)
                   1775: {
                   1776:     xmlC14NCtxPtr ctx = NULL;
                   1777: 
                   1778:     if ((doc == NULL) || (buf == NULL)) {
                   1779:         xmlC14NErrParam("creating new context");
                   1780:         return (NULL);
                   1781:     }
                   1782: 
                   1783:     /*
                   1784:      *  Validate the encoding output buffer encoding
                   1785:      */
                   1786:     if (buf->encoder != NULL) {
                   1787:         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
                   1788: "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
                   1789:         return (NULL);
                   1790:     }
                   1791: 
                   1792:     /*
                   1793:      *  Validate the XML document encoding value, if provided.
                   1794:      */
                   1795:     if (doc->charset != XML_CHAR_ENCODING_UTF8) {
                   1796:         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
                   1797:                   "xmlC14NNewCtx: source document not in UTF8\n");
                   1798:         return (NULL);
                   1799:     }
                   1800: 
                   1801:     /*
                   1802:      * Allocate a new xmlC14NCtxPtr and fill the fields.
                   1803:      */
                   1804:     ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
                   1805:     if (ctx == NULL) {
                   1806:        xmlC14NErrMemory("creating context");
                   1807:         return (NULL);
                   1808:     }
                   1809:     memset(ctx, 0, sizeof(xmlC14NCtx));
                   1810: 
                   1811:     /*
                   1812:      * initialize C14N context
                   1813:      */
                   1814:     ctx->doc = doc;
                   1815:     ctx->with_comments = with_comments;
                   1816:     ctx->is_visible_callback = is_visible_callback;
                   1817:     ctx->user_data = user_data;
                   1818:     ctx->buf = buf;
                   1819:     ctx->parent_is_doc = 1;
                   1820:     ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
                   1821:     ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
                   1822: 
                   1823:     if(ctx->ns_rendered == NULL) {
                   1824:         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
                   1825:                   "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
                   1826:        xmlC14NFreeCtx(ctx);
                   1827:         return (NULL);
                   1828:     }
                   1829: 
                   1830:     /*
                   1831:      * Set "mode" flag and remember list of incluseve prefixes
                   1832:      * for exclusive c14n
                   1833:      */
                   1834:     ctx->mode = mode;
                   1835:     if(xmlC14NIsExclusive(ctx)) {
                   1836:         ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
                   1837:     }
                   1838:     return (ctx);
                   1839: }
                   1840: 
                   1841: /**
                   1842:  * xmlC14NExecute:
                   1843:  * @doc:               the XML document for canonization
                   1844:  * @is_visible_callback:the function to use to determine is node visible 
                   1845:  *                     or not
                   1846:  * @user_data:                 the first parameter for @is_visible_callback function
                   1847:  *                     (in most cases, it is nodes set)
                   1848:  * @mode:      the c14n mode (see @xmlC14NMode)
                   1849:  * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 
                   1850:  *                     ended with a NULL or NULL if there is no
                   1851:  *                     inclusive namespaces (only for exclusive 
                   1852:  *                     canonicalization, ignored otherwise)
                   1853:  * @with_comments:     include comments in the result (!=0) or not (==0)
                   1854:  * @buf:               the output buffer to store canonical XML; this 
                   1855:  *                     buffer MUST have encoder==NULL because C14N requires
                   1856:  *                     UTF-8 output
                   1857:  *             
                   1858:  * Dumps the canonized image of given XML document into the provided buffer.
                   1859:  * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
                   1860:  * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
                   1861:  *
                   1862:  * Returns non-negative value on success or a negative value on fail  
                   1863:  */
                   1864: int            
                   1865: xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
                   1866:         void* user_data, int mode, xmlChar **inclusive_ns_prefixes,
                   1867:         int with_comments, xmlOutputBufferPtr buf) {
                   1868: 
                   1869:     xmlC14NCtxPtr ctx;
                   1870:     xmlC14NMode c14n_mode = XML_C14N_1_0;
                   1871:     int ret;
                   1872: 
                   1873:     if ((buf == NULL) || (doc == NULL)) {
                   1874:         xmlC14NErrParam("executing c14n");
                   1875:         return (-1);
                   1876:     }
                   1877: 
                   1878:     /* for backward compatibility, we have to have "mode" as "int" 
                   1879:        and here we check that user gives valid value */
                   1880:     switch(mode) {
                   1881:     case XML_C14N_1_0:
                   1882:     case XML_C14N_EXCLUSIVE_1_0:
                   1883:     case XML_C14N_1_1: 
                   1884:          c14n_mode = (xmlC14NMode)mode;
                   1885:          break;
                   1886:     default:       
                   1887:         xmlC14NErrParam("invalid mode for executing c14n");
                   1888:         return (-1);
                   1889:     }
                   1890: 
                   1891:     /*
                   1892:      *  Validate the encoding output buffer encoding
                   1893:      */
                   1894:     if (buf->encoder != NULL) {
                   1895:         xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
                   1896: "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
                   1897:         return (-1);
                   1898:     }
                   1899: 
                   1900:     ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data, 
                   1901:                    c14n_mode, inclusive_ns_prefixes,
                   1902:                     with_comments, buf);
                   1903:     if (ctx == NULL) {
                   1904:         xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
                   1905:                   "xmlC14NExecute: unable to create C14N context\n");
                   1906:         return (-1);
                   1907:     }
                   1908: 
                   1909: 
                   1910: 
                   1911:     /*  
                   1912:      * Root Node
                   1913:      * The root node is the parent of the top-level document element. The 
                   1914:      * result of processing each of its child nodes that is in the node-set 
                   1915:      * in document order. The root node does not generate a byte order mark, 
                   1916:      * XML declaration, nor anything from within the document type 
                   1917:      * declaration.
                   1918:      */
                   1919:     if (doc->children != NULL) {
                   1920:         ret = xmlC14NProcessNodeList(ctx, doc->children);
                   1921:         if (ret < 0) {
                   1922:             xmlC14NErrInternal("processing docs children list");
                   1923:             xmlC14NFreeCtx(ctx);
                   1924:             return (-1);
                   1925:         }
                   1926:     }
                   1927: 
                   1928:     /*
                   1929:      * Flush buffer to get number of bytes written
                   1930:      */
                   1931:     ret = xmlOutputBufferFlush(buf);
                   1932:     if (ret < 0) {
                   1933:         xmlC14NErrInternal("flushing output buffer");
                   1934:         xmlC14NFreeCtx(ctx);
                   1935:         return (-1);
                   1936:     }
                   1937: 
                   1938:     /* 
                   1939:      * Cleanup
                   1940:      */
                   1941:     xmlC14NFreeCtx(ctx);
                   1942:     return (ret);
                   1943: }
                   1944: 
                   1945: /**
                   1946:  * xmlC14NDocSaveTo:
                   1947:  * @doc:               the XML document for canonization
                   1948:  * @nodes:             the nodes set to be included in the canonized image
                   1949:  *                     or NULL if all document nodes should be included
                   1950:  * @mode:              the c14n mode (see @xmlC14NMode)
                   1951:  * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 
                   1952:  *                     ended with a NULL or NULL if there is no
                   1953:  *                     inclusive namespaces (only for exclusive 
                   1954:  *                     canonicalization, ignored otherwise)
                   1955:  * @with_comments:     include comments in the result (!=0) or not (==0)
                   1956:  * @buf:               the output buffer to store canonical XML; this 
                   1957:  *                     buffer MUST have encoder==NULL because C14N requires
                   1958:  *                     UTF-8 output
                   1959:  *             
                   1960:  * Dumps the canonized image of given XML document into the provided buffer.
                   1961:  * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
                   1962:  * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
                   1963:  *
                   1964:  * Returns non-negative value on success or a negative value on fail  
                   1965:  */
                   1966: int
                   1967: xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
                   1968:                  int mode, xmlChar ** inclusive_ns_prefixes,
                   1969:                  int with_comments, xmlOutputBufferPtr buf) {
                   1970:     return(xmlC14NExecute(doc, 
                   1971:                        (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
                   1972:                        nodes,
                   1973:                        mode,
                   1974:                        inclusive_ns_prefixes,
                   1975:                        with_comments,
                   1976:                        buf));
                   1977: }
                   1978: 
                   1979: 
                   1980: /**
                   1981:  * xmlC14NDocDumpMemory:
                   1982:  * @doc:               the XML document for canonization
                   1983:  * @nodes:             the nodes set to be included in the canonized image
                   1984:  *                     or NULL if all document nodes should be included
                   1985:  * @mode:              the c14n mode (see @xmlC14NMode)
                   1986:  * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 
                   1987:  *                     ended with a NULL or NULL if there is no
                   1988:  *                     inclusive namespaces (only for exclusive 
                   1989:  *                     canonicalization, ignored otherwise)
                   1990:  * @with_comments:     include comments in the result (!=0) or not (==0)
                   1991:  * @doc_txt_ptr:       the memory pointer for allocated canonical XML text;
                   1992:  *                     the caller of this functions is responsible for calling
                   1993:  *                     xmlFree() to free allocated memory 
                   1994:  *             
                   1995:  * Dumps the canonized image of given XML document into memory.
                   1996:  * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
                   1997:  * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
                   1998:  *
                   1999:  * Returns the number of bytes written on success or a negative value on fail  
                   2000:  */
                   2001: int
                   2002: xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
                   2003:                      int mode, xmlChar ** inclusive_ns_prefixes,
                   2004:                      int with_comments, xmlChar ** doc_txt_ptr)
                   2005: {
                   2006:     int ret;
                   2007:     xmlOutputBufferPtr buf;
                   2008: 
                   2009:     if (doc_txt_ptr == NULL) {
                   2010:         xmlC14NErrParam("dumping doc to memory");
                   2011:         return (-1);
                   2012:     }
                   2013: 
                   2014:     *doc_txt_ptr = NULL;
                   2015: 
                   2016:     /*
                   2017:      * create memory buffer with UTF8 (default) encoding 
                   2018:      */
                   2019:     buf = xmlAllocOutputBuffer(NULL);
                   2020:     if (buf == NULL) {
                   2021:         xmlC14NErrMemory("creating output buffer");
                   2022:         return (-1);
                   2023:     }
                   2024: 
                   2025:     /*
                   2026:      * canonize document and write to buffer
                   2027:      */
                   2028:     ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
                   2029:                            with_comments, buf);
                   2030:     if (ret < 0) {
                   2031:         xmlC14NErrInternal("saving doc to output buffer");
                   2032:         (void) xmlOutputBufferClose(buf);
                   2033:         return (-1);
                   2034:     }
                   2035: 
                   2036:     ret = buf->buffer->use;
                   2037:     if (ret > 0) {
                   2038:         *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
                   2039:     }
                   2040:     (void) xmlOutputBufferClose(buf);
                   2041: 
                   2042:     if ((*doc_txt_ptr == NULL) && (ret > 0)) {
                   2043:         xmlC14NErrMemory("coping canonicanized document");
                   2044:         return (-1);
                   2045:     }
                   2046:     return (ret);
                   2047: }
                   2048: 
                   2049: /**
                   2050:  * xmlC14NDocSave:
                   2051:  * @doc:               the XML document for canonization
                   2052:  * @nodes:             the nodes set to be included in the canonized image
                   2053:  *                     or NULL if all document nodes should be included
                   2054:  * @mode:              the c14n mode (see @xmlC14NMode)
                   2055:  * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 
                   2056:  *                     ended with a NULL or NULL if there is no
                   2057:  *                     inclusive namespaces (only for exclusive 
                   2058:  *                     canonicalization, ignored otherwise)
                   2059:  * @with_comments:     include comments in the result (!=0) or not (==0)
                   2060:  * @filename:          the filename to store canonical XML image
                   2061:  * @compression:       the compression level (zlib requred): 
                   2062:  *                             -1 - libxml default,
                   2063:  *                              0 - uncompressed, 
                   2064:  *                             >0 - compression level
                   2065:  *             
                   2066:  * Dumps the canonized image of given XML document into the file.
                   2067:  * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
                   2068:  * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
                   2069:  *
                   2070:  * Returns the number of bytes written success or a negative value on fail  
                   2071:  */
                   2072: int
                   2073: xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
                   2074:                int mode, xmlChar ** inclusive_ns_prefixes,
                   2075:                int with_comments, const char *filename, int compression)
                   2076: {
                   2077:     xmlOutputBufferPtr buf;
                   2078:     int ret;
                   2079: 
                   2080:     if (filename == NULL) {
                   2081:         xmlC14NErrParam("saving doc");
                   2082:         return (-1);
                   2083:     }
                   2084: #ifdef HAVE_ZLIB_H
                   2085:     if (compression < 0)
                   2086:         compression = xmlGetCompressMode();
                   2087: #endif
                   2088: 
                   2089:     /* 
                   2090:      * save the content to a temp buffer, use default UTF8 encoding.
                   2091:      */
                   2092:     buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
                   2093:     if (buf == NULL) {
                   2094:         xmlC14NErrInternal("creating temporary filename");
                   2095:         return (-1);
                   2096:     }
                   2097: 
                   2098:     /*
                   2099:      * canonize document and write to buffer
                   2100:      */
                   2101:     ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
                   2102:                            with_comments, buf);
                   2103:     if (ret < 0) {
                   2104:         xmlC14NErrInternal("cannicanize document to buffer");
                   2105:         (void) xmlOutputBufferClose(buf);
                   2106:         return (-1);
                   2107:     }
                   2108: 
                   2109:     /* 
                   2110:      * get the numbers of bytes written 
                   2111:      */
                   2112:     ret = xmlOutputBufferClose(buf);
                   2113:     return (ret);
                   2114: }
                   2115: 
                   2116: 
                   2117: 
                   2118: /*
                   2119:  * Macro used to grow the current buffer.
                   2120:  */
                   2121: #define growBufferReentrant() {                                                \
                   2122:     buffer_size *= 2;                                                  \
                   2123:     buffer = (xmlChar *)                                               \
                   2124:                xmlRealloc(buffer, buffer_size * sizeof(xmlChar));      \
                   2125:     if (buffer == NULL) {                                              \
                   2126:        xmlC14NErrMemory("growing buffer");                             \
                   2127:        return(NULL);                                                   \
                   2128:     }                                                                  \
                   2129: }
                   2130: 
                   2131: /** 
                   2132:  * xmlC11NNormalizeString:
                   2133:  * @input:             the input string
                   2134:  * @mode:              the normalization mode (attribute, comment, PI or text)
                   2135:  *
                   2136:  * Converts a string to a canonical (normalized) format. The code is stolen
                   2137:  * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
                   2138:  * and the @mode parameter
                   2139:  *
                   2140:  * Returns a normalized string (caller is responsible for calling xmlFree())
                   2141:  * or NULL if an error occurs
                   2142:  */
                   2143: static xmlChar *
                   2144: xmlC11NNormalizeString(const xmlChar * input,
                   2145:                        xmlC14NNormalizationMode mode)
                   2146: {
                   2147:     const xmlChar *cur = input;
                   2148:     xmlChar *buffer = NULL;
                   2149:     xmlChar *out = NULL;
                   2150:     int buffer_size = 0;
                   2151: 
                   2152:     if (input == NULL)
                   2153:         return (NULL);
                   2154: 
                   2155:     /*
                   2156:      * allocate an translation buffer.
                   2157:      */
                   2158:     buffer_size = 1000;
                   2159:     buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
                   2160:     if (buffer == NULL) {
                   2161:        xmlC14NErrMemory("allocating buffer");
                   2162:         return (NULL);
                   2163:     }
                   2164:     out = buffer;
                   2165: 
                   2166:     while (*cur != '\0') {
                   2167:         if ((out - buffer) > (buffer_size - 10)) {
                   2168:             int indx = out - buffer;
                   2169: 
                   2170:             growBufferReentrant();
                   2171:             out = &buffer[indx];
                   2172:         }
                   2173: 
                   2174:         if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
                   2175:                               (mode == XMLC14N_NORMALIZE_TEXT))) {
                   2176:             *out++ = '&';
                   2177:             *out++ = 'l';
                   2178:             *out++ = 't';
                   2179:             *out++ = ';';
                   2180:         } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
                   2181:             *out++ = '&';
                   2182:             *out++ = 'g';
                   2183:             *out++ = 't';
                   2184:             *out++ = ';';
                   2185:         } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
                   2186:                                      (mode == XMLC14N_NORMALIZE_TEXT))) {
                   2187:             *out++ = '&';
                   2188:             *out++ = 'a';
                   2189:             *out++ = 'm';
                   2190:             *out++ = 'p';
                   2191:             *out++ = ';';
                   2192:         } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
                   2193:             *out++ = '&';
                   2194:             *out++ = 'q';
                   2195:             *out++ = 'u';
                   2196:             *out++ = 'o';
                   2197:             *out++ = 't';
                   2198:             *out++ = ';';
                   2199:         } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
                   2200:             *out++ = '&';
                   2201:             *out++ = '#';
                   2202:             *out++ = 'x';
                   2203:             *out++ = '9';
                   2204:             *out++ = ';';
                   2205:         } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
                   2206:             *out++ = '&';
                   2207:             *out++ = '#';
                   2208:             *out++ = 'x';
                   2209:             *out++ = 'A';
                   2210:             *out++ = ';';
                   2211:         } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
                   2212:                                         (mode == XMLC14N_NORMALIZE_TEXT) ||
                   2213:                                         (mode == XMLC14N_NORMALIZE_COMMENT) ||
                   2214:                                        (mode == XMLC14N_NORMALIZE_PI))) {
                   2215:             *out++ = '&';
                   2216:             *out++ = '#';
                   2217:             *out++ = 'x';
                   2218:             *out++ = 'D';
                   2219:             *out++ = ';';
                   2220:         } else {
                   2221:             /*
                   2222:              * Works because on UTF-8, all extended sequences cannot
                   2223:              * result in bytes in the ASCII range.
                   2224:              */
                   2225:             *out++ = *cur;
                   2226:         }
                   2227:         cur++;
                   2228:     }
                   2229:     *out = 0;
                   2230:     return (buffer);
                   2231: }
                   2232: #endif /* LIBXML_OUTPUT_ENABLED */
                   2233: #define bottom_c14n
                   2234: #include "elfgcchack.h"
                   2235: #endif /* LIBXML_C14N_ENABLED */

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