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

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

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