c14n.c 69 KB

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