blob: b7cb7b0e8b43c56aecd5bd08c5d864bac8e18e0f [file] [log] [blame]
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001/*
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002 * "Canonical XML" implementation
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003 * http://www.w3.org/TR/xml-c14n
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005 * "Exclusive XML Canonicalization" implementation
6 * http://www.w3.org/TR/xml-exc-c14n
7 *
8 * See Copyright for the status of this software.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08009 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010 * Author: Aleksey Sanin <aleksey@aleksey.com>
11 */
Daniel Veillard34ce8be2002-03-18 19:37:11 +000012#define IN_LIBXML
Daniel Veillard044fc6b2002-03-04 17:09:44 +000013#include "libxml.h"
14#ifdef LIBXML_C14N_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +000015#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard044fc6b2002-03-04 17:09:44 +000016
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>
Daniel Veillard9ff88172002-03-11 09:15:32 +000024#include <libxml/uri.h>
Daniel Veillard044fc6b2002-03-04 17:09:44 +000025#include <libxml/xmlerror.h>
26#include <libxml/globals.h>
27#include <libxml/xpathInternals.h>
28#include <libxml/c14n.h>
29
Daniel Veillard53aa2932012-07-16 14:37:00 +080030#include "buf.h"
31
Daniel Veillard044fc6b2002-03-04 17:09:44 +000032/************************************************************************
33 * *
34 * Some declaration better left private ATM *
35 * *
36 ************************************************************************/
37
Daniel Veillard9ff88172002-03-11 09:15:32 +000038typedef enum {
39 XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
40 XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
41 XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
Daniel Veillard044fc6b2002-03-04 17:09:44 +000042} xmlC14NPosition;
43
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000044typedef struct _xmlC14NVisibleNsStack {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +000045 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 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +080049 xmlNsPtr *nsTab; /* array of ns in no particular order */
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +000050 xmlNodePtr *nodeTab; /* array of nodes in no particular order */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000051} xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
Aleksey Sanindffd5c82002-05-31 04:24:13 +000052
Daniel Veillard044fc6b2002-03-04 17:09:44 +000053typedef struct _xmlC14NCtx {
54 /* input parameters */
Daniel Veillard9ff88172002-03-11 09:15:32 +000055 xmlDocPtr doc;
Aleksey Sanin2c135a12002-08-01 06:31:50 +000056 xmlC14NIsVisibleCallback is_visible_callback;
Daniel Veillardf8e3db02012-09-11 13:26:36 +080057 void* user_data;
Daniel Veillard9ff88172002-03-11 09:15:32 +000058 int with_comments;
59 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000060
61 /* position in the XML document */
Daniel Veillard9ff88172002-03-11 09:15:32 +000062 xmlC14NPosition pos;
63 int parent_is_doc;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000064 xmlC14NVisibleNsStackPtr ns_rendered;
Daniel Veillardf8e3db02012-09-11 13:26:36 +080065
Aleksey Sanin83868242009-07-09 10:26:22 +020066 /* C14N mode */
67 xmlC14NMode mode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000068
69 /* exclusive canonicalization */
Daniel Veillard9ff88172002-03-11 09:15:32 +000070 xmlChar **inclusive_ns_prefixes;
Daniel Veillardd96cce12003-10-10 12:30:37 +000071
72 /* error number */
73 int error;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000074} xmlC14NCtx, *xmlC14NCtxPtr;
75
Aleksey Sanin2c135a12002-08-01 06:31:50 +000076static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +000077static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
Daniel Veillardf8e3db02012-09-11 13:26:36 +080078static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +000079 xmlNsPtr ns,
80 xmlNodePtr node);
Daniel Veillardf8e3db02012-09-11 13:26:36 +080081static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
Aleksey Sanin2c135a12002-08-01 06:31:50 +000082 xmlC14NVisibleNsStackPtr state);
Daniel Veillardf8e3db02012-09-11 13:26:36 +080083static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
Aleksey Sanin2c135a12002-08-01 06:31:50 +000084 xmlC14NVisibleNsStackPtr state);
Daniel Veillardf8e3db02012-09-11 13:26:36 +080085static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
86static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
Aleksey Sanin2c135a12002-08-01 06:31:50 +000087 xmlNsPtr ns);
Daniel Veillardf8e3db02012-09-11 13:26:36 +080088static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
Aleksey Sanin2c135a12002-08-01 06:31:50 +000089 xmlNsPtr ns,
90 xmlC14NCtxPtr ctx);
91
92static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes,
93 xmlNodePtr node,
94 xmlNodePtr parent);
95
96
Daniel Veillard044fc6b2002-03-04 17:09:44 +000097
Daniel Veillard9ff88172002-03-11 09:15:32 +000098static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
99static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000100typedef enum {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000101 XMLC14N_NORMALIZE_ATTR = 0,
102 XMLC14N_NORMALIZE_COMMENT = 1,
103 XMLC14N_NORMALIZE_PI = 2,
104 XMLC14N_NORMALIZE_TEXT = 3
105} xmlC14NNormalizationMode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000106
Daniel Veillard9ff88172002-03-11 09:15:32 +0000107static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
108 xmlC14NNormalizationMode mode);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000109
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800110#define xmlC11NNormalizeAttr( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000111 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800112#define xmlC11NNormalizeComment( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000113 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800114#define xmlC11NNormalizePI( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000115 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800116#define xmlC11NNormalizeText( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000117 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000118
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800119#define xmlC14NIsVisible( ctx, node, parent ) \
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000120 (((ctx)->is_visible_callback != NULL) ? \
121 (ctx)->is_visible_callback((ctx)->user_data, \
122 (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
Daniel Veillardd96cce12003-10-10 12:30:37 +0000123
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800124#define xmlC14NIsExclusive( ctx ) \
Aleksey Sanin83868242009-07-09 10:26:22 +0200125 ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 )
126
Daniel Veillardd96cce12003-10-10 12:30:37 +0000127/************************************************************************
128 * *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800129 * Some factorized error routines *
Daniel Veillardd96cce12003-10-10 12:30:37 +0000130 * *
131 ************************************************************************/
132
133/**
134 * xmlC14NErrMemory:
135 * @extra: extra informations
136 *
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000137 * Handle a redefinition of memory error
Daniel Veillardd96cce12003-10-10 12:30:37 +0000138 */
139static void
140xmlC14NErrMemory(const char *extra)
141{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000142 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
Daniel Veillardd96cce12003-10-10 12:30:37 +0000143 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/**
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000149 * xmlC14NErrParam:
150 * @extra: extra informations
151 *
152 * Handle a redefinition of param error
153 */
154static void
155xmlC14NErrParam(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 */
169static void
170xmlC14NErrInternal(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 */
184static void
185xmlC14NErrInvalidNode(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 */
199static void
200xmlC14NErrUnknownNode(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 */
214static void
215xmlC14NErrRelativeNamespace(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/**
Daniel Veillardd96cce12003-10-10 12:30:37 +0000226 * 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 */
235static void
236xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error,
237 const char * msg)
238{
239 if (ctxt != NULL)
240 ctxt->error = error;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000241 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96cce12003-10-10 12:30:37 +0000242 ctxt, node, XML_FROM_C14N, error,
243 XML_ERR_ERROR, NULL, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200244 NULL, NULL, NULL, 0, 0, "%s", msg);
Daniel Veillardd96cce12003-10-10 12:30:37 +0000245}
246
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000247/************************************************************************
248 * *
249 * The implementation internals *
250 * *
251 ************************************************************************/
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000252#define XML_NAMESPACES_DEFAULT 16
253
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800254static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000255xmlC14NIsNodeInNodeset(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;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800261
262 memcpy(&ns, node, sizeof(ns));
263
Aleksey Sanin6de6f972004-04-20 02:05:30 +0000264 /* 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 {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800268 ns.next = (xmlNsPtr)parent;
Aleksey Sanin6de6f972004-04-20 02:05:30 +0000269 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000270
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800271 /*
272 * If the input is an XPath node-set, then the node-set must explicitly
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000273 * contain every node to be rendered to the canonical form.
274 */
275 return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
276 }
277 }
278 return(1);
279}
280
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000281static xmlC14NVisibleNsStackPtr
282xmlC14NVisibleNsStackCreate(void) {
283 xmlC14NVisibleNsStackPtr ret;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000284
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000285 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000286 if (ret == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000287 xmlC14NErrMemory("creating namespaces stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000288 return(NULL);
289 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000290 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000291 return(ret);
292}
293
294static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000295xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000296 if(cur == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000297 xmlC14NErrParam("destroying namespaces stack");
298 return;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000299 }
300 if(cur->nsTab != NULL) {
301 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
302 xmlFree(cur->nsTab);
303 }
Aleksey Saninea4272a2002-08-02 23:50:03 +0000304 if(cur->nodeTab != NULL) {
305 memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
306 xmlFree(cur->nodeTab);
307 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000308 memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000309 xmlFree(cur);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800310
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000311}
312
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800313static void
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000314xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800315 if((cur == NULL) ||
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000316 ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
317 ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000318 xmlC14NErrParam("adding namespace to stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000319 return;
320 }
321
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000322 if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000323 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000324 cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
325 if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000326 xmlC14NErrMemory("adding node to stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000327 return;
328 }
329 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000330 memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000331 cur->nsMax = XML_NAMESPACES_DEFAULT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000332 } else if(cur->nsMax == cur->nsCurEnd) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800333 void *tmp;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000334 int tmpSize;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800335
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000336 tmpSize = 2 * cur->nsMax;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000337 tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000338 if (tmp == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000339 xmlC14NErrMemory("adding node to stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000340 return;
341 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000342 cur->nsTab = (xmlNsPtr*)tmp;
343
344 tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
345 if (tmp == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000346 xmlC14NErrMemory("adding node to stack");
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000347 return;
348 }
349 cur->nodeTab = (xmlNodePtr*)tmp;
350
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000351 cur->nsMax = tmpSize;
352 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000353 cur->nsTab[cur->nsCurEnd] = ns;
354 cur->nodeTab[cur->nsCurEnd] = node;
355
356 ++cur->nsCurEnd;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000357}
358
359static void
360xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
361 if((cur == NULL) || (state == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000362 xmlC14NErrParam("saving namespaces stack");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000363 return;
364 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800365
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000366 state->nsCurEnd = cur->nsCurEnd;
367 state->nsPrevStart = cur->nsPrevStart;
368 state->nsPrevEnd = cur->nsPrevEnd;
369}
370
371static void
372xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
373 if((cur == NULL) || (state == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000374 xmlC14NErrParam("restoring namespaces stack");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000375 return;
376 }
377 cur->nsCurEnd = state->nsCurEnd;
378 cur->nsPrevStart = state->nsPrevStart;
379 cur->nsPrevEnd = state->nsPrevEnd;
380}
381
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800382static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000383xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
384 if(cur == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000385 xmlC14NErrParam("shifting namespaces stack");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000386 return;
387 }
388 cur->nsPrevStart = cur->nsPrevEnd;
389 cur->nsPrevEnd = cur->nsCurEnd;
390}
391
392static int
393xmlC14NStrEqual(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:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800405 * @ctx: the C14N context
Daniel Veillard01c13b52002-12-10 15:19:08 +0000406 * @ns: the namespace to check
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000407 *
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 */
412static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000413xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000414{
415 int i;
416 const xmlChar *prefix;
417 const xmlChar *href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000418 int has_empty_ns;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800419
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000420 if(cur == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000421 xmlC14NErrParam("searching namespaces stack (c14n)");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000422 return (0);
423 }
424
425 /*
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800426 * if the default namespace xmlns="" is not defined yet then
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000427 * 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;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000431 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
432
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000433 if (cur->nsTab != NULL) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000434 int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000435 for (i = cur->nsCurEnd - 1; i >= start; --i) {
436 xmlNsPtr ns1 = cur->nsTab[i];
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800437
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000438 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
439 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
440 }
441 }
442 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000443 return(has_empty_ns);
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000444}
445
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800446static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000447xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
448 int i;
449 const xmlChar *prefix;
450 const xmlChar *href;
451 int has_empty_ns;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800452
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000453 if(cur == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000454 xmlC14NErrParam("searching namespaces stack (exc c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000455 return (0);
456 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000457
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000458 /*
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800459 * if the default namespace xmlns="" is not defined yet then
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000460 * we do not want to print it out
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000461 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000462 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));
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000465
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000466 if (cur->nsTab != NULL) {
467 int start = 0;
468 for (i = cur->nsCurEnd - 1; i >= start; --i) {
469 xmlNsPtr ns1 = cur->nsTab[i];
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800470
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000471 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
472 if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800473 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000474 } else {
475 return(0);
476 }
477 }
478 }
479 }
480 return(has_empty_ns);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000481}
482
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000483
484
485
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000486/**
487 * xmlC14NIsXmlNs:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800488 * @ns: the namespace to check
489 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000490 * 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 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000495
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000496/* todo: make it a define? */
497static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000498xmlC14NIsXmlNs(xmlNsPtr ns)
499{
500 return ((ns != NULL) &&
501 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
Aleksey Sanin83868242009-07-09 10:26:22 +0200502 (xmlStrEqual(ns->href, XML_XML_NAMESPACE)));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000503}
504
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000505
506/**
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000507 * xmlC14NNsCompare:
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000508 * @ns1: the pointer to first namespace
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800509 * @ns2: the pointer to second namespace
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000510 *
511 * Compares the namespaces by names (prefixes).
512 *
513 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
514 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000515static int
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100516xmlC14NNsCompare(const void *data1, const void *data2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000517{
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100518 const xmlNsPtr ns1 = (const xmlNsPtr) data1;
519 const xmlNsPtr ns2 = (const xmlNsPtr) data2;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000520 if (ns1 == ns2)
521 return (0);
522 if (ns1 == NULL)
523 return (-1);
524 if (ns2 == NULL)
525 return (1);
526
527 return (xmlStrcmp(ns1->prefix, ns2->prefix));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000528}
529
530
531/**
532 * xmlC14NPrintNamespaces:
533 * @ns: the pointer to namespace
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800534 * @ctx: the C14N context
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000535 *
536 * Prints the given namespace to the output buffer from C14N context.
537 *
538 * Returns 1 on success or 0 on fail.
539 */
540static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000541xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
542{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000543
Daniel Veillard9ff88172002-03-11 09:15:32 +0000544 if ((ns == NULL) || (ctx == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000545 xmlC14NErrParam("writing namespaces");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000546 return 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000547 }
548
Daniel Veillard9ff88172002-03-11 09:15:32 +0000549 if (ns->prefix != NULL) {
550 xmlOutputBufferWriteString(ctx->buf, " xmlns:");
551 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
Aleksey Sanin1ba80b72013-05-09 16:02:16 +0000552 xmlOutputBufferWriteString(ctx->buf, "=");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000553 } else {
Aleksey Sanin1ba80b72013-05-09 16:02:16 +0000554 xmlOutputBufferWriteString(ctx->buf, " xmlns=");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000555 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000556 if(ns->href != NULL) {
Aleksey Sanin1ba80b72013-05-09 16:02:16 +0000557 xmlBufWriteQuotedString(ctx->buf->buffer, ns->href);
558 } else {
559 xmlOutputBufferWriteString(ctx->buf, "\"\"");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000560 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000561 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000562}
563
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100564static int
565xmlC14NPrintNamespacesWalker(const void *ns, void *ctx) {
566 return xmlC14NPrintNamespaces((const xmlNsPtr) ns, (xmlC14NCtxPtr) ctx);
567}
568
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000569/**
570 * xmlC14NProcessNamespacesAxis:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800571 * @ctx: the C14N context
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000572 * @node: the current node
573 *
574 * Prints out canonical namespace axis of the current node to the
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800575 * buffer from C14N context as follows
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000576 *
577 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
578 *
579 * Namespace Axis
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800580 * Consider a list L containing only namespace nodes in the
581 * axis and in the node-set in lexicographic order (ascending). To begin
582 * processing L, if the first node is not the default namespace node (a node
583 * with no namespace URI and no local name), then generate a space followed
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000584 * by xmlns="" if and only if the following conditions are met:
585 * - the element E that owns the axis is in the node-set
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800586 * - The nearest ancestor element of E in the node-set has a default
587 * namespace node in the node-set (default namespace nodes always
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000588 * have non-empty values in XPath)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800589 * The latter condition eliminates unnecessary occurrences of xmlns="" in
590 * the canonical form since an element only receives an xmlns="" if its
591 * default namespace is empty and if it has an immediate parent in the
592 * canonical form that has a non-empty default namespace. To finish
593 * processing L, simply process every namespace node in L, except omit
594 * namespace node with local name xml, which defines the xml prefix,
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000595 * if its string value is http://www.w3.org/XML/1998/namespace.
596 *
597 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800598 * Canonical XML applied to a document subset requires the search of the
599 * ancestor nodes of each orphan element node for attributes in the xml
600 * namespace, such as xml:lang and xml:space. These are copied into the
601 * element node except if a declaration of the same attribute is already
602 * in the attribute axis of the element (whether or not it is included in
603 * the document subset). This search and copying are omitted from the
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000604 * Exclusive XML Canonicalization method.
605 *
606 * Returns 0 on success or -1 on fail.
607 */
608static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000609xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000610{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000611 xmlNodePtr n;
612 xmlNsPtr ns, tmp;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000613 xmlListPtr list;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000614 int already_rendered;
615 int has_empty_ns = 0;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800616
Daniel Veillard9ff88172002-03-11 09:15:32 +0000617 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000618 xmlC14NErrParam("processing namespaces axis (c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000619 return (-1);
620 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000621
622 /*
623 * Create a sorted list to store element namespaces
624 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100625 list = xmlListCreate(NULL, xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000626 if (list == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000627 xmlC14NErrInternal("creating namespaces list (c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000628 return (-1);
629 }
630
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000631 /* check all namespaces */
632 for(n = cur; n != NULL; n = n->parent) {
633 for(ns = n->nsDef; ns != NULL; ns = ns->next) {
634 tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800635
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000636 if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
637 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
638 if(visible) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800639 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000640 }
641 if(!already_rendered) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800642 xmlListInsert(list, ns);
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000643 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800644 if(xmlStrlen(ns->prefix) == 0) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000645 has_empty_ns = 1;
646 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000647 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000648 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000649 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800650
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000651 /**
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800652 * if the first node is not the default namespace node (a node with no
653 * namespace URI and no local name), then generate a space followed by
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000654 * xmlns="" if and only if the following conditions are met:
655 * - the element E that owns the axis is in the node-set
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800656 * - the nearest ancestor element of E in the node-set has a default
657 * namespace node in the node-set (default namespace nodes always
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000658 * have non-empty values in XPath)
659 */
660 if(visible && !has_empty_ns) {
661 static xmlNs ns_default;
662
663 memset(&ns_default, 0, sizeof(ns_default));
664 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800665 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000666 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000667 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800668
669
670 /*
671 * print out all elements from list
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000672 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100673 xmlListWalk(list, xmlC14NPrintNamespacesWalker, (void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000674
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800675 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000676 * Cleanup
677 */
678 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000679 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000680}
681
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000682
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000683/**
684 * xmlExcC14NProcessNamespacesAxis:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800685 * @ctx: the C14N context
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000686 * @node: the current node
687 *
688 * Prints out exclusive canonical namespace axis of the current node to the
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800689 * buffer from C14N context as follows
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000690 *
691 * Exclusive XML Canonicalization
692 * http://www.w3.org/TR/xml-exc-c14n
693 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800694 * If the element node is in the XPath subset then output the node in
695 * accordance with Canonical XML except for namespace nodes which are
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000696 * rendered as follows:
697 *
698 * 1. Render each namespace node iff:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800699 * * it is visibly utilized by the immediate parent element or one of
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000700 * its attributes, or is present in InclusiveNamespaces PrefixList, and
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800701 * * its prefix and value do not appear in ns_rendered. ns_rendered is
702 * obtained by popping the state stack in order to obtain a list of
703 * prefixes and their values which have already been rendered by
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000704 * an output ancestor of the namespace node's parent element.
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800705 * 2. Append the rendered namespace node to the list ns_rendered of namespace
706 * nodes rendered by output ancestors. Push ns_rendered on state stack and
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000707 * recurse.
708 * 3. After the recursion returns, pop thestate stack.
709 *
710 *
711 * Returns 0 on success or -1 on fail.
712 */
713static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000714xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000715{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000716 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000717 xmlListPtr list;
718 xmlAttrPtr attr;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000719 int already_rendered;
720 int has_empty_ns = 0;
721 int has_visibly_utilized_empty_ns = 0;
722 int has_empty_ns_in_inclusive_list = 0;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800723
Daniel Veillard9ff88172002-03-11 09:15:32 +0000724 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000725 xmlC14NErrParam("processing namespaces axis (exc c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000726 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000727 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000728
Aleksey Sanin83868242009-07-09 10:26:22 +0200729 if(!xmlC14NIsExclusive(ctx)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000730 xmlC14NErrParam("processing namespaces axis (exc c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000731 return (-1);
732
733 }
734
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000735 /*
736 * Create a sorted list to store element namespaces
737 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100738 list = xmlListCreate(NULL, xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000739 if (list == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000740 xmlC14NErrInternal("creating namespaces list (exc c14n)");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000741 return (-1);
742 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000743
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800744 /*
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000745 * process inclusive namespaces:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800746 * All namespace nodes appearing on inclusive ns list are
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000747 * handled as provided in Canonical XML
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000748 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000749 if(ctx->inclusive_ns_prefixes != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800750 xmlChar *prefix;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000751 int i;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800752
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000753 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
754 prefix = ctx->inclusive_ns_prefixes[i];
755 /*
756 * Special values for namespace with empty prefix
757 */
758 if (xmlStrEqual(prefix, BAD_CAST "#default")
759 || xmlStrEqual(prefix, BAD_CAST "")) {
760 prefix = NULL;
761 has_empty_ns_in_inclusive_list = 1;
762 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800763
764 ns = xmlSearchNs(cur->doc, cur, prefix);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000765 if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
766 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
767 if(visible) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800768 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000769 }
770 if(!already_rendered) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800771 xmlListInsert(list, ns);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000772 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800773 if(xmlStrlen(ns->prefix) == 0) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000774 has_empty_ns = 1;
775 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000776 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000777 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000778 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800779
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000780 /* add node namespace */
781 if(cur->ns != NULL) {
782 ns = cur->ns;
783 } else {
784 ns = xmlSearchNs(cur->doc, cur, NULL);
785 has_visibly_utilized_empty_ns = 1;
786 }
787 if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800788 if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000789 if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
790 xmlListInsert(list, ns);
791 }
792 }
793 if(visible) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800794 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000795 }
796 if(xmlStrlen(ns->prefix) == 0) {
797 has_empty_ns = 1;
798 }
799 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800800
801
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000802 /* add attributes */
803 for(attr = cur->properties; attr != NULL; attr = attr->next) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800804 /*
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000805 * we need to check that attribute is visible and has non
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800806 * default namespace (XML Namespaces: "default namespaces
807 * do not apply directly to attributes")
Daniel Veillard9ff88172002-03-11 09:15:32 +0000808 */
Aleksey Sanin2650df12005-06-06 17:16:50 +0000809 if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000810 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800811 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000812 if(!already_rendered && visible) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800813 xmlListInsert(list, attr->ns);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000814 }
815 if(xmlStrlen(attr->ns->prefix) == 0) {
816 has_empty_ns = 1;
817 }
Aleksey Saninb2eabc02005-10-28 03:15:18 +0000818 } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000819 has_visibly_utilized_empty_ns = 1;
820 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000821 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000822
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000823 /*
824 * Process xmlns=""
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000825 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800826 if(visible && has_visibly_utilized_empty_ns &&
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000827 !has_empty_ns && !has_empty_ns_in_inclusive_list) {
828 static xmlNs ns_default;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000829
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000830 memset(&ns_default, 0, sizeof(ns_default));
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800831
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000832 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
833 if(!already_rendered) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800834 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000835 }
836 } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
837 static xmlNs ns_default;
838
839 memset(&ns_default, 0, sizeof(ns_default));
840 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800841 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000842 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000843 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000844
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000845
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800846
847 /*
848 * print out all elements from list
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000849 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100850 xmlListWalk(list, xmlC14NPrintNamespacesWalker, (void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000851
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800852 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000853 * Cleanup
854 */
855 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000856 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000857}
858
859
860/**
Aleksey Sanin83868242009-07-09 10:26:22 +0200861 * xmlC14NIsXmlAttr:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800862 * @attr: the attr to check
863 *
Aleksey Sanin83868242009-07-09 10:26:22 +0200864 * Checks whether the given attribute is a default "xml:" namespace
865 * with href="http://www.w3.org/XML/1998/namespace"
866 *
867 * Returns 1 if the node is default or 0 otherwise
868 */
869
870/* todo: make it a define? */
871static int
872xmlC14NIsXmlAttr(xmlAttrPtr attr)
873{
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800874 return ((attr->ns != NULL) &&
Aleksey Sanin83868242009-07-09 10:26:22 +0200875 (xmlC14NIsXmlNs(attr->ns) != 0));
876}
877
878
879/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000880 * xmlC14NAttrsCompare:
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000881 * @attr1: the pointer tls o first attr
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800882 * @attr2: the pointer to second attr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000883 *
884 * Prints the given attribute to the output buffer from C14N context.
885 *
886 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
887 */
888static int
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100889xmlC14NAttrsCompare(const void *data1, const void *data2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000890{
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100891 const xmlAttrPtr attr1 = (const xmlAttrPtr) data1;
892 const xmlAttrPtr attr2 = (const xmlAttrPtr) data2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000893 int ret = 0;
894
895 /*
896 * Simple cases
897 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000898 if (attr1 == attr2)
899 return (0);
900 if (attr1 == NULL)
901 return (-1);
902 if (attr2 == NULL)
903 return (1);
904 if (attr1->ns == attr2->ns) {
905 return (xmlStrcmp(attr1->name, attr2->name));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000906 }
907
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800908 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000909 * Attributes in the default namespace are first
910 * because the default namespace is not applied to
911 * unqualified attributes
912 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000913 if (attr1->ns == NULL)
914 return (-1);
915 if (attr2->ns == NULL)
916 return (1);
917 if (attr1->ns->prefix == NULL)
918 return (-1);
919 if (attr2->ns->prefix == NULL)
920 return (1);
921
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000922 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000923 if (ret == 0) {
924 ret = xmlStrcmp(attr1->name, attr2->name);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000925 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000926 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000927}
928
929
930/**
931 * xmlC14NPrintAttrs:
932 * @attr: the pointer to attr
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800933 * @ctx: the C14N context
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000934 *
935 * Prints out canonical attribute urrent node to the
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800936 * buffer from C14N context as follows
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000937 *
938 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
939 *
940 * Returns 1 on success or 0 on fail.
941 */
942static int
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100943xmlC14NPrintAttrs(const void *data, void *user)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000944{
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +0100945 const xmlAttrPtr attr = (const xmlAttrPtr) data;
946 xmlC14NCtxPtr ctx = (xmlC14NCtxPtr) user;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000947 xmlChar *value;
948 xmlChar *buffer;
949
Daniel Veillard9ff88172002-03-11 09:15:32 +0000950 if ((attr == NULL) || (ctx == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000951 xmlC14NErrParam("writing attributes");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000952 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000953 }
954
955 xmlOutputBufferWriteString(ctx->buf, " ");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000956 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
957 xmlOutputBufferWriteString(ctx->buf,
958 (const char *) attr->ns->prefix);
959 xmlOutputBufferWriteString(ctx->buf, ":");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000960 }
961 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
962 xmlOutputBufferWriteString(ctx->buf, "=\"");
963
Aleksey Sanin83868242009-07-09 10:26:22 +0200964 value = xmlNodeListGetString(ctx->doc, attr->children, 1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000965 /* todo: should we log an error if value==NULL ? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000966 if (value != NULL) {
967 buffer = xmlC11NNormalizeAttr(value);
968 xmlFree(value);
969 if (buffer != NULL) {
970 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
971 xmlFree(buffer);
972 } else {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +0000973 xmlC14NErrInternal("normalizing attributes axis");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000974 return (0);
975 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000976 }
977 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000978 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000979}
980
981/**
Aleksey Sanin83868242009-07-09 10:26:22 +0200982 * xmlC14NFindHiddenParentAttr:
983 *
984 * Finds an attribute in a hidden parent node.
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800985 *
Aleksey Sanin83868242009-07-09 10:26:22 +0200986 * Returns a pointer to the attribute node (if found) or NULL otherwise.
987 */
988static xmlAttrPtr
989xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns)
990{
991 xmlAttrPtr res;
992 while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
993 res = xmlHasNsProp(cur, name, ns);
994 if(res != NULL) {
995 return res;
996 }
997
998 cur = cur->parent;
999 }
1000
1001 return NULL;
1002}
1003
1004/**
1005 * xmlC14NFixupBaseAttr:
1006 *
1007 * Fixes up the xml:base attribute
1008 *
1009 * Returns the newly created attribute or NULL
1010 */
1011static xmlAttrPtr
1012xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001013{
Aleksey Sanin83868242009-07-09 10:26:22 +02001014 xmlChar * res = NULL;
1015 xmlNodePtr cur;
1016 xmlAttrPtr attr;
1017 xmlChar * tmp_str;
1018 xmlChar * tmp_str2;
1019 int tmp_str_len;
1020
1021 if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) {
1022 xmlC14NErrParam("processing xml:base attribute");
1023 return (NULL);
1024 }
1025
1026 /* start from current value */
1027 res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1);
1028 if(res == NULL) {
1029 xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1030 return (NULL);
1031 }
1032
1033 /* go up the stack until we find a node that we rendered already */
1034 cur = xml_base_attr->parent->parent;
1035 while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
1036 attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1037 if(attr != NULL) {
1038 /* get attr value */
1039 tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1);
1040 if(tmp_str == NULL) {
1041 xmlFree(res);
1042
1043 xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1044 return (NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001045 }
Aleksey Sanin83868242009-07-09 10:26:22 +02001046
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001047 /* we need to add '/' if our current base uri ends with '..' or '.'
Aleksey Sanin83868242009-07-09 10:26:22 +02001048 to ensure that we are forced to go "up" all the time */
1049 tmp_str_len = xmlStrlen(tmp_str);
1050 if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') {
1051 tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/");
1052 if(tmp_str2 == NULL) {
1053 xmlFree(tmp_str);
1054 xmlFree(res);
1055
1056 xmlC14NErrInternal("processing xml:base attribute - can't modify uri");
1057 return (NULL);
1058 }
1059
1060 tmp_str = tmp_str2;
1061 }
1062
1063 /* build uri */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001064 tmp_str2 = xmlBuildURI(res, tmp_str);
Aleksey Sanin83868242009-07-09 10:26:22 +02001065 if(tmp_str2 == NULL) {
1066 xmlFree(tmp_str);
1067 xmlFree(res);
1068
1069 xmlC14NErrInternal("processing xml:base attribute - can't construct uri");
1070 return (NULL);
1071 }
1072
1073 /* cleanup and set the new res */
1074 xmlFree(tmp_str);
1075 xmlFree(res);
1076 res = tmp_str2;
1077 }
1078
1079 /* next */
1080 cur = cur->parent;
1081 }
1082
1083 /* check if result uri is empty or not */
1084 if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) {
1085 xmlFree(res);
1086 return (NULL);
1087 }
1088
1089 /* create and return the new attribute node */
1090 attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res);
1091 if(attr == NULL) {
1092 xmlFree(res);
1093
1094 xmlC14NErrInternal("processing xml:base attribute - can't construct attribute");
1095 return (NULL);
1096 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001097
Aleksey Sanin83868242009-07-09 10:26:22 +02001098 /* done */
1099 xmlFree(res);
1100 return (attr);
1101}
1102
1103/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001104 * xmlC14NProcessAttrsAxis:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001105 * @ctx: the C14N context
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001106 * @cur: the current node
Aleksey Sanin3ea201c2005-06-07 16:53:57 +00001107 * @parent_visible: the visibility of parent node
Aleksey Sanin83868242009-07-09 10:26:22 +02001108 * @all_parents_visible: the visibility of all parent nodes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001109 *
1110 * Prints out canonical attribute axis of the current node to the
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001111 * buffer from C14N context as follows
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001112 *
1113 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1114 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001115 * Attribute Axis
1116 * In lexicographic order (ascending), process each node that
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001117 * is in the element's attribute axis and in the node-set.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001118 *
1119 * The processing of an element node E MUST be modified slightly
1120 * when an XPath node-set is given as input and the element's
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001121 * parent is omitted from the node-set.
1122 *
1123 *
1124 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
1125 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001126 * Canonical XML applied to a document subset requires the search of the
1127 * ancestor nodes of each orphan element node for attributes in the xml
1128 * namespace, such as xml:lang and xml:space. These are copied into the
1129 * element node except if a declaration of the same attribute is already
1130 * in the attribute axis of the element (whether or not it is included in
1131 * the document subset). This search and copying are omitted from the
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001132 * Exclusive XML Canonicalization method.
1133 *
1134 * Returns 0 on success or -1 on fail.
1135 */
1136static int
Aleksey Sanin3ea201c2005-06-07 16:53:57 +00001137xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +00001138{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001139 xmlAttrPtr attr;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001140 xmlListPtr list;
Aleksey Sanin83868242009-07-09 10:26:22 +02001141 xmlAttrPtr attrs_to_delete = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001142
Aleksey Sanin83868242009-07-09 10:26:22 +02001143 /* special processing for 1.1 spec */
1144 xmlAttrPtr xml_base_attr = NULL;
1145 xmlAttrPtr xml_lang_attr = NULL;
1146 xmlAttrPtr xml_space_attr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001147
1148 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001149 xmlC14NErrParam("processing attributes axis");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001150 return (-1);
1151 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001152
1153 /*
1154 * Create a sorted list to store element attributes
1155 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +01001156 list = xmlListCreate(NULL, xmlC14NAttrsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001157 if (list == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001158 xmlC14NErrInternal("creating attributes list");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001159 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001160 }
1161
Aleksey Sanin83868242009-07-09 10:26:22 +02001162 switch(ctx->mode) {
1163 case XML_C14N_1_0:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001164 /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1165 * given as input and the element's parent is omitted from the node-set. The method for processing
1166 * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's
1167 * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such
1168 * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes,
1169 * remove any that are in E's attribute axis (whether or not they are in the node-set). Then,
1170 * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1171 * the node-set. The result of visiting the attribute axis is computed by processing the attribute
1172 * nodes in this merged attribute list.
Daniel Veillard9ff88172002-03-11 09:15:32 +00001173 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001174
1175 /*
1176 * Add all visible attributes from current node.
Aleksey Sanin83868242009-07-09 10:26:22 +02001177 */
1178 attr = cur->properties;
1179 while (attr != NULL) {
1180 /* check that attribute is visible */
1181 if (xmlC14NIsVisible(ctx, attr, cur)) {
1182 xmlListInsert(list, attr);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001183 }
Aleksey Sanin83868242009-07-09 10:26:22 +02001184 attr = attr->next;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001185 }
Aleksey Sanin83868242009-07-09 10:26:22 +02001186
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001187 /*
Aleksey Sanin83868242009-07-09 10:26:22 +02001188 * Handle xml attributes
1189 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001190 if (parent_visible && (cur->parent != NULL) &&
1191 (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent)))
Aleksey Sanin83868242009-07-09 10:26:22 +02001192 {
1193 xmlNodePtr tmp;
1194
1195 /*
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001196 * If XPath node-set is not specified then the parent is always
Aleksey Sanin83868242009-07-09 10:26:22 +02001197 * visible!
1198 */
1199 tmp = cur->parent;
1200 while (tmp != NULL) {
1201 attr = tmp->properties;
1202 while (attr != NULL) {
1203 if (xmlC14NIsXmlAttr(attr) != 0) {
1204 if (xmlListSearch(list, attr) == NULL) {
1205 xmlListInsert(list, attr);
1206 }
1207 }
1208 attr = attr->next;
1209 }
1210 tmp = tmp->parent;
1211 }
1212 }
1213
1214 /* done */
1215 break;
1216 case XML_C14N_EXCLUSIVE_1_0:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001217 /* attributes in the XML namespace, such as xml:lang and xml:space
1218 * are not imported into orphan nodes of the document subset
Aleksey Sanin83868242009-07-09 10:26:22 +02001219 */
1220
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001221 /*
1222 * Add all visible attributes from current node.
Aleksey Sanin83868242009-07-09 10:26:22 +02001223 */
1224 attr = cur->properties;
1225 while (attr != NULL) {
1226 /* check that attribute is visible */
1227 if (xmlC14NIsVisible(ctx, attr, cur)) {
1228 xmlListInsert(list, attr);
1229 }
1230 attr = attr->next;
1231 }
1232
1233 /* do nothing special for xml attributes */
1234 break;
1235 case XML_C14N_1_1:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001236 /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1237 * given as input and some of the element's ancestors are omitted from the node-set.
Aleksey Sanin83868242009-07-09 10:26:22 +02001238 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001239 * Simple inheritable attributes are attributes that have a value that requires at most a simple
1240 * redeclaration. This redeclaration is done by supplying a new value in the child axis. The
1241 * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done
1242 * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes
Aleksey Sanin83868242009-07-09 10:26:22 +02001243 * are xml:lang and xml:space.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001244 *
1245 * The method for processing the attribute axis of an element E in the node-set is hence enhanced.
1246 * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple
1247 * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they
1248 * are in the node-set). From this list of attributes, any simple inheritable attributes that are
1249 * already in E's attribute axis (whether or not they are in the node-set) are removed. Then,
1250 * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1251 * the node-set. The result of visiting the attribute axis is computed by processing the attribute
Aleksey Sanin83868242009-07-09 10:26:22 +02001252 * nodes in this merged attribute list.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001253 *
1254 * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is
Aleksey Sanin83868242009-07-09 10:26:22 +02001255 * performed.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001256 *
1257 * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond
Aleksey Sanin83868242009-07-09 10:26:22 +02001258 * a simple redeclaration.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001259 *
1260 * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed
Aleksey Sanin83868242009-07-09 10:26:22 +02001261 * as ordinary attributes.
1262 */
1263
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001264 /*
1265 * Add all visible attributes from current node.
Aleksey Sanin83868242009-07-09 10:26:22 +02001266 */
1267 attr = cur->properties;
1268 while (attr != NULL) {
1269 /* special processing for XML attribute kiks in only when we have invisible parents */
1270 if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) {
1271 /* check that attribute is visible */
1272 if (xmlC14NIsVisible(ctx, attr, cur)) {
1273 xmlListInsert(list, attr);
1274 }
1275 } else {
1276 int matched = 0;
1277
1278 /* check for simple inheritance attributes */
1279 if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) {
1280 xml_lang_attr = attr;
1281 matched = 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001282 }
Aleksey Sanin83868242009-07-09 10:26:22 +02001283 if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) {
1284 xml_space_attr = attr;
1285 matched = 1;
1286 }
1287
1288 /* check for base attr */
1289 if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) {
1290 xml_base_attr = attr;
1291 matched = 1;
1292 }
1293
1294 /* otherwise, it is a normal attribute, so just check if it is visible */
1295 if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) {
1296 xmlListInsert(list, attr);
1297 }
1298 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001299
Aleksey Sanin83868242009-07-09 10:26:22 +02001300 /* move to the next one */
1301 attr = attr->next;
1302 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001303
Aleksey Sanin83868242009-07-09 10:26:22 +02001304 /* special processing for XML attribute kiks in only when we have invisible parents */
1305 if ((parent_visible)) {
1306
1307 /* simple inheritance attributes - copy */
1308 if(xml_lang_attr == NULL) {
1309 xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE);
1310 }
1311 if(xml_lang_attr != NULL) {
1312 xmlListInsert(list, xml_lang_attr);
1313 }
1314 if(xml_space_attr == NULL) {
1315 xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE);
1316 }
1317 if(xml_space_attr != NULL) {
1318 xmlListInsert(list, xml_space_attr);
1319 }
1320
1321 /* base uri attribute - fix up */
1322 if(xml_base_attr == NULL) {
1323 /* if we don't have base uri attribute, check if we have a "hidden" one above */
1324 xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE);
1325 }
1326 if(xml_base_attr != NULL) {
1327 xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001328 if(xml_base_attr != NULL) {
Aleksey Sanin83868242009-07-09 10:26:22 +02001329 xmlListInsert(list, xml_base_attr);
1330
1331 /* note that we MUST delete returned attr node ourselves! */
1332 xml_base_attr->next = attrs_to_delete;
1333 attrs_to_delete = xml_base_attr;
1334 }
1335 }
1336 }
1337
1338 /* done */
1339 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001340 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001341
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001342 /*
1343 * print out all elements from list
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001344 */
Nick Wellnhofer4dd6d7a2017-11-09 17:28:00 +01001345 xmlListWalk(list, xmlC14NPrintAttrs, (void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001346
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001347 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001348 * Cleanup
1349 */
Aleksey Sanin83868242009-07-09 10:26:22 +02001350 xmlFreePropList(attrs_to_delete);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001351 xmlListDelete(list);
1352 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001353}
1354
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001355/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001356 * xmlC14NCheckForRelativeNamespaces:
1357 * @ctx: the C14N context
1358 * @cur: the current element node
1359 *
1360 * Checks that current element node has no relative namespaces defined
1361 *
1362 * Returns 0 if the node has no relative namespaces or -1 otherwise.
1363 */
1364static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001365xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1366{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001367 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001368
Daniel Veillard9ff88172002-03-11 09:15:32 +00001369 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001370 xmlC14NErrParam("checking for relative namespaces");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001371 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001372 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001373
1374 ns = cur->nsDef;
1375 while (ns != NULL) {
1376 if (xmlStrlen(ns->href) > 0) {
1377 xmlURIPtr uri;
1378
1379 uri = xmlParseURI((const char *) ns->href);
1380 if (uri == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001381 xmlC14NErrInternal("parsing namespace uri");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001382 return (-1);
1383 }
1384 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001385 xmlC14NErrRelativeNamespace(uri->scheme);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001386 xmlFreeURI(uri);
1387 return (-1);
1388 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001389 xmlFreeURI(uri);
1390 }
1391 ns = ns->next;
1392 }
1393 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001394}
1395
1396/**
1397 * xmlC14NProcessElementNode:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001398 * @ctx: the pointer to C14N context object
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001399 * @cur: the node to process
Aleksey Sanin83868242009-07-09 10:26:22 +02001400 * @visible: this node is visible
1401 * @all_parents_visible: whether all the parents of this node are visible
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001402 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001403 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1404 *
1405 * Element Nodes
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001406 * If the element is not in the node-set, then the result is obtained
1407 * by processing the namespace axis, then the attribute axis, then
1408 * processing the child nodes of the element that are in the node-set
1409 * (in document order). If the element is in the node-set, then the result
1410 * is an open angle bracket (<), the element QName, the result of
1411 * processing the namespace axis, the result of processing the attribute
1412 * axis, a close angle bracket (>), the result of processing the child
1413 * nodes of the element that are in the node-set (in document order), an
1414 * open angle bracket, a forward slash (/), the element QName, and a close
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001415 * angle bracket.
1416 *
1417 * Returns non-negative value on success or negative value on fail
1418 */
1419static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001420xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1421{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001422 int ret;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001423 xmlC14NVisibleNsStack state;
Daniel Veillard6f293b12002-03-15 09:42:33 +00001424 int parent_is_doc = 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001425
Daniel Veillard9ff88172002-03-11 09:15:32 +00001426 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001427 xmlC14NErrParam("processing element node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001428 return (-1);
1429 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001430
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001431 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001432 * Check relative relative namespaces:
1433 * implementations of XML canonicalization MUST report an operation
1434 * failure on documents containing relative namespace URIs.
1435 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001436 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001437 xmlC14NErrInternal("checking for relative namespaces");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001438 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001439 }
1440
1441
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001442 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001443 * Save ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001444 */
Daniel Veillardaac7c682006-03-10 13:40:16 +00001445 memset(&state, 0, sizeof(state));
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001446 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001447
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001448 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001449 if (ctx->parent_is_doc) {
Daniel Veillard6f293b12002-03-15 09:42:33 +00001450 /* save this flag into the stack */
1451 parent_is_doc = ctx->parent_is_doc;
1452 ctx->parent_is_doc = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001453 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1454 }
1455 xmlOutputBufferWriteString(ctx->buf, "<");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001456
Daniel Veillard9ff88172002-03-11 09:15:32 +00001457 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1458 xmlOutputBufferWriteString(ctx->buf,
1459 (const char *) cur->ns->prefix);
1460 xmlOutputBufferWriteString(ctx->buf, ":");
1461 }
1462 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001463 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001464
Aleksey Sanin83868242009-07-09 10:26:22 +02001465 if (!xmlC14NIsExclusive(ctx)) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001466 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1467 } else {
1468 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1469 }
1470 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001471 xmlC14NErrInternal("processing namespaces axis");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001472 return (-1);
1473 }
1474 /* todo: shouldn't this go to "visible only"? */
1475 if(visible) {
1476 xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1477 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001478
Aleksey Sanin3ea201c2005-06-07 16:53:57 +00001479 ret = xmlC14NProcessAttrsAxis(ctx, cur, visible);
1480 if (ret < 0) {
1481 xmlC14NErrInternal("processing attributes axis");
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001482 return (-1);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001483 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001484
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001485 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001486 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001487 }
1488 if (cur->children != NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001489 ret = xmlC14NProcessNodeList(ctx, cur->children);
1490 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001491 xmlC14NErrInternal("processing childrens list");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001492 return (-1);
1493 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001494 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001495 if (visible) {
1496 xmlOutputBufferWriteString(ctx->buf, "</");
1497 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1498 xmlOutputBufferWriteString(ctx->buf,
1499 (const char *) cur->ns->prefix);
1500 xmlOutputBufferWriteString(ctx->buf, ":");
1501 }
1502 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1503 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard6f293b12002-03-15 09:42:33 +00001504 if (parent_is_doc) {
1505 /* restore this flag from the stack for next node */
1506 ctx->parent_is_doc = parent_is_doc;
1507 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001508 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001509 }
1510
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001511 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001512 * Restore ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001513 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001514 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001515 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001516}
1517
1518/**
1519 * xmlC14NProcessNode:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001520 * @ctx: the pointer to C14N context object
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001521 * @cur: the node to process
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001522 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001523 * Processes the given node
1524 *
1525 * Returns non-negative value on success or negative value on fail
1526 */
1527static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001528xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1529{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001530 int ret = 0;
1531 int visible;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001532
1533 if ((ctx == NULL) || (cur == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001534 xmlC14NErrParam("processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001535 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001536 }
1537
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001538 visible = xmlC14NIsVisible(ctx, cur, cur->parent);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001539 switch (cur->type) {
1540 case XML_ELEMENT_NODE:
1541 ret = xmlC14NProcessElementNode(ctx, cur, visible);
1542 break;
1543 case XML_CDATA_SECTION_NODE:
1544 case XML_TEXT_NODE:
1545 /*
1546 * Text Nodes
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001547 * the string value, except all ampersands are replaced
1548 * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1549 * angle brackets (>) are replaced by &gt;, and all #xD characters are
Daniel Veillard9ff88172002-03-11 09:15:32 +00001550 * replaced by &#xD;.
1551 */
1552 /* cdata sections are processed as text nodes */
1553 /* todo: verify that cdata sections are included in XPath nodes set */
1554 if ((visible) && (cur->content != NULL)) {
1555 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001556
Daniel Veillard9ff88172002-03-11 09:15:32 +00001557 buffer = xmlC11NNormalizeText(cur->content);
1558 if (buffer != NULL) {
1559 xmlOutputBufferWriteString(ctx->buf,
1560 (const char *) buffer);
1561 xmlFree(buffer);
1562 } else {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001563 xmlC14NErrInternal("normalizing text node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001564 return (-1);
1565 }
1566 }
1567 break;
1568 case XML_PI_NODE:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001569 /*
1570 * Processing Instruction (PI) Nodes-
1571 * The opening PI symbol (<?), the PI target name of the node,
1572 * a leading space and the string value if it is not empty, and
1573 * the closing PI symbol (?>). If the string value is empty,
1574 * then the leading space is not added. Also, a trailing #xA is
1575 * rendered after the closing PI symbol for PI children of the
1576 * root node with a lesser document order than the document
1577 * element, and a leading #xA is rendered before the opening PI
1578 * symbol of PI children of the root node with a greater document
Daniel Veillard9ff88172002-03-11 09:15:32 +00001579 * order than the document element.
1580 */
1581 if (visible) {
1582 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1583 xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1584 } else {
1585 xmlOutputBufferWriteString(ctx->buf, "<?");
1586 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001587
Daniel Veillard9ff88172002-03-11 09:15:32 +00001588 xmlOutputBufferWriteString(ctx->buf,
1589 (const char *) cur->name);
1590 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1591 xmlChar *buffer;
1592
1593 xmlOutputBufferWriteString(ctx->buf, " ");
1594
1595 /* todo: do we need to normalize pi? */
1596 buffer = xmlC11NNormalizePI(cur->content);
1597 if (buffer != NULL) {
1598 xmlOutputBufferWriteString(ctx->buf,
1599 (const char *) buffer);
1600 xmlFree(buffer);
1601 } else {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001602 xmlC14NErrInternal("normalizing pi node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001603 return (-1);
1604 }
1605 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001606
Daniel Veillard9ff88172002-03-11 09:15:32 +00001607 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1608 xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1609 } else {
1610 xmlOutputBufferWriteString(ctx->buf, "?>");
1611 }
1612 }
1613 break;
1614 case XML_COMMENT_NODE:
1615 /*
1616 * Comment Nodes
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001617 * Nothing if generating canonical XML without comments. For
1618 * canonical XML with comments, generate the opening comment
1619 * symbol (<!--), the string value of the node, and the
1620 * closing comment symbol (-->). Also, a trailing #xA is rendered
1621 * after the closing comment symbol for comment children of the
1622 * root node with a lesser document order than the document
1623 * element, and a leading #xA is rendered before the opening
1624 * comment symbol of comment children of the root node with a
1625 * greater document order than the document element. (Comment
1626 * children of the root node represent comments outside of the
1627 * top-level document element and outside of the document type
Daniel Veillard9ff88172002-03-11 09:15:32 +00001628 * declaration).
1629 */
1630 if (visible && ctx->with_comments) {
1631 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1632 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1633 } else {
1634 xmlOutputBufferWriteString(ctx->buf, "<!--");
1635 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001636
Daniel Veillard9ff88172002-03-11 09:15:32 +00001637 if (cur->content != NULL) {
1638 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001639
Daniel Veillard9ff88172002-03-11 09:15:32 +00001640 /* todo: do we need to normalize comment? */
1641 buffer = xmlC11NNormalizeComment(cur->content);
1642 if (buffer != NULL) {
1643 xmlOutputBufferWriteString(ctx->buf,
1644 (const char *) buffer);
1645 xmlFree(buffer);
1646 } else {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001647 xmlC14NErrInternal("normalizing comment node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001648 return (-1);
1649 }
1650 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001651
Daniel Veillard9ff88172002-03-11 09:15:32 +00001652 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1653 xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1654 } else {
1655 xmlOutputBufferWriteString(ctx->buf, "-->");
1656 }
1657 }
1658 break;
1659 case XML_DOCUMENT_NODE:
1660 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001661#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001662 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001663#endif
1664#ifdef LIBXML_HTML_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001665 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001666#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001667 if (cur->children != NULL) {
1668 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1669 ctx->parent_is_doc = 1;
1670 ret = xmlC14NProcessNodeList(ctx, cur->children);
1671 }
1672 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001673
Daniel Veillard9ff88172002-03-11 09:15:32 +00001674 case XML_ATTRIBUTE_NODE:
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001675 xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001676 return (-1);
1677 case XML_NAMESPACE_DECL:
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001678 xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001679 return (-1);
1680 case XML_ENTITY_REF_NODE:
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001681 xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001682 return (-1);
1683 case XML_ENTITY_NODE:
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001684 xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001685 return (-1);
1686
1687 case XML_DOCUMENT_TYPE_NODE:
1688 case XML_NOTATION_NODE:
1689 case XML_DTD_NODE:
1690 case XML_ELEMENT_DECL:
1691 case XML_ATTRIBUTE_DECL:
1692 case XML_ENTITY_DECL:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001693#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001694 case XML_XINCLUDE_START:
1695 case XML_XINCLUDE_END:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001696#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001697 /*
1698 * should be ignored according to "W3C Canonical XML"
Daniel Veillard9ff88172002-03-11 09:15:32 +00001699 */
1700 break;
1701 default:
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001702 xmlC14NErrUnknownNode(cur->type, "processing node");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001703 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001704 }
1705
Daniel Veillard9ff88172002-03-11 09:15:32 +00001706 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001707}
1708
1709/**
1710 * xmlC14NProcessNodeList:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001711 * @ctx: the pointer to C14N context object
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001712 * @cur: the node to start from
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001713 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001714 * Processes all nodes in the row starting from cur.
1715 *
1716 * Returns non-negative value on success or negative value on fail
1717 */
1718static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001719xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1720{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001721 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001722
1723 if (ctx == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001724 xmlC14NErrParam("processing node list");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001725 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001726 }
1727
Daniel Veillard9ff88172002-03-11 09:15:32 +00001728 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1729 ret = xmlC14NProcessNode(ctx, cur);
1730 }
1731 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001732}
1733
1734
1735/**
1736 * xmlC14NFreeCtx:
1737 * @ctx: the pointer to C14N context object
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001738 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001739 * Cleanups the C14N context object.
1740 */
1741
1742static void
Daniel Veillard9ff88172002-03-11 09:15:32 +00001743xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1744{
1745 if (ctx == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001746 xmlC14NErrParam("freeing context");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001747 return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001748 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001749
1750 if (ctx->ns_rendered != NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001751 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001752 }
1753 xmlFree(ctx);
1754}
1755
1756/**
1757 * xmlC14NNewCtx:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001758 * @doc: the XML document for canonization
1759 * @is_visible_callback:the function to use to determine is node visible
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001760 * or not
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001761 * @user_data: the first parameter for @is_visible_callback function
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001762 * (in most cases, it is nodes set)
Aleksey Sanin83868242009-07-09 10:26:22 +02001763 * @mode: the c14n mode (see @xmlC14NMode)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001764 * @inclusive_ns_prefixe the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001765 * ended with a NULL or NULL if there is no
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001766 * inclusive namespaces (only for `
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001767 * canonicalization)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001768 * @with_comments: include comments in the result (!=0) or not (==0)
1769 * @buf: the output buffer to store canonical XML; this
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001770 * buffer MUST have encoder==NULL because C14N requires
1771 * UTF-8 output
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001772 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773 * Creates new C14N context object to store C14N parameters.
1774 *
1775 * Returns pointer to newly created object (success) or NULL (fail)
1776 */
1777static xmlC14NCtxPtr
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001778xmlC14NNewCtx(xmlDocPtr doc,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001779 xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
Aleksey Sanin83868242009-07-09 10:26:22 +02001780 xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001781 int with_comments, xmlOutputBufferPtr buf)
1782{
Daniel Veillard659e71e2003-10-10 14:10:40 +00001783 xmlC14NCtxPtr ctx = NULL;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001784
Daniel Veillard9ff88172002-03-11 09:15:32 +00001785 if ((doc == NULL) || (buf == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001786 xmlC14NErrParam("creating new context");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001787 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 }
1789
1790 /*
1791 * Validate the encoding output buffer encoding
1792 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001793 if (buf->encoder != NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001794 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1795"xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001796 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001797 }
1798
1799 /*
1800 * Validate the XML document encoding value, if provided.
1801 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001802 if (doc->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001803 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1804 "xmlC14NNewCtx: source document not in UTF8\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001805 return (NULL);
1806 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001807
1808 /*
1809 * Allocate a new xmlC14NCtxPtr and fill the fields.
1810 */
1811 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1812 if (ctx == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001813 xmlC14NErrMemory("creating context");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001814 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001815 }
1816 memset(ctx, 0, sizeof(xmlC14NCtx));
1817
1818 /*
1819 * initialize C14N context
Daniel Veillard9ff88172002-03-11 09:15:32 +00001820 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001821 ctx->doc = doc;
1822 ctx->with_comments = with_comments;
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001823 ctx->is_visible_callback = is_visible_callback;
1824 ctx->user_data = user_data;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001825 ctx->buf = buf;
1826 ctx->parent_is_doc = 1;
1827 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001828 ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1829
1830 if(ctx->ns_rendered == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001831 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
1832 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001833 xmlC14NFreeCtx(ctx);
1834 return (NULL);
1835 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001836
1837 /*
Aleksey Sanin83868242009-07-09 10:26:22 +02001838 * Set "mode" flag and remember list of incluseve prefixes
1839 * for exclusive c14n
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001840 */
Aleksey Sanin83868242009-07-09 10:26:22 +02001841 ctx->mode = mode;
1842 if(xmlC14NIsExclusive(ctx)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001843 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1844 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001845 return (ctx);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846}
1847
1848/**
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001849 * xmlC14NExecute:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001850 * @doc: the XML document for canonization
1851 * @is_visible_callback:the function to use to determine is node visible
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001852 * or not
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001853 * @user_data: the first parameter for @is_visible_callback function
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001854 * (in most cases, it is nodes set)
Aleksey Sanin83868242009-07-09 10:26:22 +02001855 * @mode: the c14n mode (see @xmlC14NMode)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001856 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001857 * ended with a NULL or NULL if there is no
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001858 * inclusive namespaces (only for exclusive
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001859 * canonicalization, ignored otherwise)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001860 * @with_comments: include comments in the result (!=0) or not (==0)
1861 * @buf: the output buffer to store canonical XML; this
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001862 * buffer MUST have encoder==NULL because C14N requires
1863 * UTF-8 output
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001864 *
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001865 * Dumps the canonized image of given XML document into the provided buffer.
1866 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1867 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1868 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001869 * Returns non-negative value on success or a negative value on fail
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001870 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001871int
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001872xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
Aleksey Sanin175beba2009-07-09 22:54:00 +02001873 void* user_data, int mode, xmlChar **inclusive_ns_prefixes,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001874 int with_comments, xmlOutputBufferPtr buf) {
1875
1876 xmlC14NCtxPtr ctx;
Aleksey Sanin175beba2009-07-09 22:54:00 +02001877 xmlC14NMode c14n_mode = XML_C14N_1_0;
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001878 int ret;
1879
1880 if ((buf == NULL) || (doc == NULL)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001881 xmlC14NErrParam("executing c14n");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001882 return (-1);
1883 }
1884
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001885 /* for backward compatibility, we have to have "mode" as "int"
Aleksey Sanin175beba2009-07-09 22:54:00 +02001886 and here we check that user gives valid value */
1887 switch(mode) {
1888 case XML_C14N_1_0:
1889 case XML_C14N_EXCLUSIVE_1_0:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001890 case XML_C14N_1_1:
Aleksey Sanin175beba2009-07-09 22:54:00 +02001891 c14n_mode = (xmlC14NMode)mode;
1892 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001893 default:
Aleksey Sanin175beba2009-07-09 22:54:00 +02001894 xmlC14NErrParam("invalid mode for executing c14n");
1895 return (-1);
1896 }
1897
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001898 /*
1899 * Validate the encoding output buffer encoding
1900 */
1901 if (buf->encoder != NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001902 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1903"xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001904 return (-1);
1905 }
1906
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001907 ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
Aleksey Sanin175beba2009-07-09 22:54:00 +02001908 c14n_mode, inclusive_ns_prefixes,
1909 with_comments, buf);
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001910 if (ctx == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001911 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
1912 "xmlC14NExecute: unable to create C14N context\n");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001913 return (-1);
1914 }
1915
1916
1917
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001918 /*
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001919 * Root Node
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001920 * The root node is the parent of the top-level document element. The
1921 * result of processing each of its child nodes that is in the node-set
1922 * in document order. The root node does not generate a byte order mark,
1923 * XML declaration, nor anything from within the document type
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001924 * declaration.
1925 */
1926 if (doc->children != NULL) {
1927 ret = xmlC14NProcessNodeList(ctx, doc->children);
1928 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001929 xmlC14NErrInternal("processing docs children list");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001930 xmlC14NFreeCtx(ctx);
1931 return (-1);
1932 }
1933 }
1934
1935 /*
1936 * Flush buffer to get number of bytes written
1937 */
1938 ret = xmlOutputBufferFlush(buf);
1939 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00001940 xmlC14NErrInternal("flushing output buffer");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001941 xmlC14NFreeCtx(ctx);
1942 return (-1);
1943 }
1944
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001945 /*
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001946 * Cleanup
1947 */
1948 xmlC14NFreeCtx(ctx);
1949 return (ret);
1950}
1951
1952/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001953 * xmlC14NDocSaveTo:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001954 * @doc: the XML document for canonization
1955 * @nodes: the nodes set to be included in the canonized image
1956 * or NULL if all document nodes should be included
Aleksey Sanin83868242009-07-09 10:26:22 +02001957 * @mode: the c14n mode (see @xmlC14NMode)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001958 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001959 * ended with a NULL or NULL if there is no
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001960 * inclusive namespaces (only for exclusive
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001961 * canonicalization, ignored otherwise)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001962 * @with_comments: include comments in the result (!=0) or not (==0)
1963 * @buf: the output buffer to store canonical XML; this
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001964 * buffer MUST have encoder==NULL because C14N requires
1965 * UTF-8 output
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001966 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001967 * Dumps the canonized image of given XML document into the provided buffer.
1968 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1969 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1970 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001971 * Returns non-negative value on success or a negative value on fail
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001972 */
1973int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001974xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
Aleksey Sanin83868242009-07-09 10:26:22 +02001975 int mode, xmlChar ** inclusive_ns_prefixes,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001976 int with_comments, xmlOutputBufferPtr buf) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001977 return(xmlC14NExecute(doc,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001978 (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1979 nodes,
Aleksey Sanin83868242009-07-09 10:26:22 +02001980 mode,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001981 inclusive_ns_prefixes,
1982 with_comments,
1983 buf));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001984}
1985
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001986
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001987/**
1988 * xmlC14NDocDumpMemory:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001989 * @doc: the XML document for canonization
1990 * @nodes: the nodes set to be included in the canonized image
1991 * or NULL if all document nodes should be included
Aleksey Sanin83868242009-07-09 10:26:22 +02001992 * @mode: the c14n mode (see @xmlC14NMode)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001993 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001994 * ended with a NULL or NULL if there is no
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001995 * inclusive namespaces (only for exclusive
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001996 * canonicalization, ignored otherwise)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001997 * @with_comments: include comments in the result (!=0) or not (==0)
1998 * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001999 * the caller of this functions is responsible for calling
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002000 * xmlFree() to free allocated memory
2001 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002002 * Dumps the canonized image of given XML document into memory.
2003 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
2004 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
2005 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002006 * Returns the number of bytes written on success or a negative value on fail
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002007 */
2008int
Daniel Veillard9ff88172002-03-11 09:15:32 +00002009xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
Aleksey Sanin175beba2009-07-09 22:54:00 +02002010 int mode, xmlChar ** inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00002011 int with_comments, xmlChar ** doc_txt_ptr)
2012{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002013 int ret;
2014 xmlOutputBufferPtr buf;
2015
2016 if (doc_txt_ptr == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002017 xmlC14NErrParam("dumping doc to memory");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002018 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002019 }
2020
2021 *doc_txt_ptr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00002022
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 /*
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002024 * create memory buffer with UTF8 (default) encoding
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002025 */
2026 buf = xmlAllocOutputBuffer(NULL);
Daniel Veillard9ff88172002-03-11 09:15:32 +00002027 if (buf == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002028 xmlC14NErrMemory("creating output buffer");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002029 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002030 }
2031
2032 /*
2033 * canonize document and write to buffer
2034 */
Aleksey Sanin83868242009-07-09 10:26:22 +02002035 ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00002036 with_comments, buf);
2037 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002038 xmlC14NErrInternal("saving doc to output buffer");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002039 (void) xmlOutputBufferClose(buf);
2040 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002041 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002042
Daniel Veillard53aa2932012-07-16 14:37:00 +08002043 ret = xmlBufUse(buf->buffer);
Daniel Veillard9ff88172002-03-11 09:15:32 +00002044 if (ret > 0) {
Daniel Veillard53aa2932012-07-16 14:37:00 +08002045 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), ret);
Daniel Veillard9ff88172002-03-11 09:15:32 +00002046 }
2047 (void) xmlOutputBufferClose(buf);
2048
2049 if ((*doc_txt_ptr == NULL) && (ret > 0)) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002050 xmlC14NErrMemory("coping canonicanized document");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002051 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002052 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00002053 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002054}
2055
2056/**
2057 * xmlC14NDocSave:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002058 * @doc: the XML document for canonization
2059 * @nodes: the nodes set to be included in the canonized image
2060 * or NULL if all document nodes should be included
Aleksey Sanin83868242009-07-09 10:26:22 +02002061 * @mode: the c14n mode (see @xmlC14NMode)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002062 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002063 * ended with a NULL or NULL if there is no
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002064 * inclusive namespaces (only for exclusive
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002065 * canonicalization, ignored otherwise)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002066 * @with_comments: include comments in the result (!=0) or not (==0)
2067 * @filename: the filename to store canonical XML image
2068 * @compression: the compression level (zlib requred):
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002069 * -1 - libxml default,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002070 * 0 - uncompressed,
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002071 * >0 - compression level
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002072 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002073 * Dumps the canonized image of given XML document into the file.
2074 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
2075 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
2076 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002077 * Returns the number of bytes written success or a negative value on fail
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002078 */
2079int
Daniel Veillard9ff88172002-03-11 09:15:32 +00002080xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
Aleksey Sanin175beba2009-07-09 22:54:00 +02002081 int mode, xmlChar ** inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00002082 int with_comments, const char *filename, int compression)
2083{
2084 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002085 int ret;
2086
Daniel Veillard9ff88172002-03-11 09:15:32 +00002087 if (filename == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002088 xmlC14NErrParam("saving doc");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002089 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002090 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002091#ifdef HAVE_ZLIB_H
Daniel Veillard9ff88172002-03-11 09:15:32 +00002092 if (compression < 0)
2093 compression = xmlGetCompressMode();
2094#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002095
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002096 /*
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002097 * save the content to a temp buffer, use default UTF8 encoding.
2098 */
2099 buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
2100 if (buf == NULL) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002101 xmlC14NErrInternal("creating temporary filename");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002102 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002103 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00002104
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105 /*
2106 * canonize document and write to buffer
2107 */
Aleksey Sanin83868242009-07-09 10:26:22 +02002108 ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00002109 with_comments, buf);
2110 if (ret < 0) {
Aleksey Sanin9e75e9f2005-03-20 19:16:47 +00002111 xmlC14NErrInternal("cannicanize document to buffer");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002112 (void) xmlOutputBufferClose(buf);
2113 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002114 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00002115
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002116 /*
2117 * get the numbers of bytes written
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002118 */
2119 ret = xmlOutputBufferClose(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00002120 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002121}
2122
2123
2124
2125/*
2126 * Macro used to grow the current buffer.
2127 */
2128#define growBufferReentrant() { \
2129 buffer_size *= 2; \
2130 buffer = (xmlChar *) \
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002131 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002132 if (buffer == NULL) { \
Daniel Veillardd96cce12003-10-10 12:30:37 +00002133 xmlC14NErrMemory("growing buffer"); \
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002134 return(NULL); \
2135 } \
2136}
2137
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002138/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002139 * xmlC11NNormalizeString:
2140 * @input: the input string
2141 * @mode: the normalization mode (attribute, comment, PI or text)
2142 *
2143 * Converts a string to a canonical (normalized) format. The code is stolen
2144 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
2145 * and the @mode parameter
2146 *
2147 * Returns a normalized string (caller is responsible for calling xmlFree())
2148 * or NULL if an error occurs
2149 */
2150static xmlChar *
Daniel Veillard9ff88172002-03-11 09:15:32 +00002151xmlC11NNormalizeString(const xmlChar * input,
2152 xmlC14NNormalizationMode mode)
2153{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002154 const xmlChar *cur = input;
2155 xmlChar *buffer = NULL;
2156 xmlChar *out = NULL;
2157 int buffer_size = 0;
2158
Daniel Veillard9ff88172002-03-11 09:15:32 +00002159 if (input == NULL)
2160 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002161
2162 /*
2163 * allocate an translation buffer.
2164 */
2165 buffer_size = 1000;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002166 buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002167 if (buffer == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00002168 xmlC14NErrMemory("allocating buffer");
Daniel Veillard9ff88172002-03-11 09:15:32 +00002169 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002170 }
2171 out = buffer;
2172
2173 while (*cur != '\0') {
Daniel Veillard9ff88172002-03-11 09:15:32 +00002174 if ((out - buffer) > (buffer_size - 10)) {
2175 int indx = out - buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002176
Daniel Veillard9ff88172002-03-11 09:15:32 +00002177 growBufferReentrant();
2178 out = &buffer[indx];
2179 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002180
Daniel Veillard9ff88172002-03-11 09:15:32 +00002181 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2182 (mode == XMLC14N_NORMALIZE_TEXT))) {
2183 *out++ = '&';
2184 *out++ = 'l';
2185 *out++ = 't';
2186 *out++ = ';';
2187 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
2188 *out++ = '&';
2189 *out++ = 'g';
2190 *out++ = 't';
2191 *out++ = ';';
2192 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2193 (mode == XMLC14N_NORMALIZE_TEXT))) {
2194 *out++ = '&';
2195 *out++ = 'a';
2196 *out++ = 'm';
2197 *out++ = 'p';
2198 *out++ = ';';
2199 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2200 *out++ = '&';
2201 *out++ = 'q';
2202 *out++ = 'u';
2203 *out++ = 'o';
2204 *out++ = 't';
2205 *out++ = ';';
2206 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2207 *out++ = '&';
2208 *out++ = '#';
2209 *out++ = 'x';
2210 *out++ = '9';
2211 *out++ = ';';
2212 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2213 *out++ = '&';
2214 *out++ = '#';
2215 *out++ = 'x';
2216 *out++ = 'A';
2217 *out++ = ';';
2218 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2219 (mode == XMLC14N_NORMALIZE_TEXT) ||
2220 (mode == XMLC14N_NORMALIZE_COMMENT) ||
2221 (mode == XMLC14N_NORMALIZE_PI))) {
2222 *out++ = '&';
2223 *out++ = '#';
2224 *out++ = 'x';
2225 *out++ = 'D';
2226 *out++ = ';';
2227 } else {
2228 /*
2229 * Works because on UTF-8, all extended sequences cannot
2230 * result in bytes in the ASCII range.
2231 */
2232 *out++ = *cur;
2233 }
2234 cur++;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002235 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002236 *out = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00002237 return (buffer);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002238}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002239#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +00002240#define bottom_c14n
2241#include "elfgcchack.h"
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002242#endif /* LIBXML_C14N_ENABLED */