upload source
[external/xmlsec1.git] / src / xmltree.c
1 /** 
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  * Common XML Doc utility functions
5  *
6  * This is free software; see Copyright file in the source
7  * distribution for preciese wording.
8  * 
9  * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
10  */
11 #include "globals.h"
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <errno.h>
17  
18 #include <libxml/tree.h>
19 #include <libxml/valid.h>
20 #include <libxml/xpath.h>
21 #include <libxml/xpathInternals.h>
22
23 #include <xmlsec/xmlsec.h>
24 #include <xmlsec/xmltree.h>
25 #include <xmlsec/parser.h>
26 #include <xmlsec/private.h>
27 #include <xmlsec/base64.h>
28 #include <xmlsec/errors.h>
29
30 /**
31  * xmlSecFindChild:
32  * @parent:             the pointer to XML node.
33  * @name:               the name.
34  * @ns:                 the namespace href (may be NULL).
35  *
36  * Searches a direct child of the @parent node having given name and 
37  * namespace href.
38  * 
39  * Returns: the pointer to the found node or NULL if an error occurs or 
40  * node is not found.
41  */
42 xmlNodePtr
43 xmlSecFindChild(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
44     xmlNodePtr cur;
45         
46     xmlSecAssert2(parent != NULL, NULL);
47     xmlSecAssert2(name != NULL, NULL);
48     
49     cur = parent->children;
50     while(cur != NULL) {
51         if(cur->type == XML_ELEMENT_NODE) {
52             if(xmlSecCheckNodeName(cur, name, ns)) {
53                 return(cur);
54             }
55         }
56         cur = cur->next;
57     }
58     return(NULL);
59 }
60
61 /**
62  * xmlSecFindParent:
63  * @cur:                the pointer to an XML node.
64  * @name:               the name.
65  * @ns:                 the namespace href (may be NULL).
66  *
67  * Searches the ancestors axis of the @cur node for a node having given name 
68  * and namespace href.
69  * 
70  * Returns: the pointer to the found node or NULL if an error occurs or 
71  * node is not found.
72  */
73 xmlNodePtr
74 xmlSecFindParent(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) {
75     xmlSecAssert2(cur != NULL, NULL);
76     xmlSecAssert2(name != NULL, NULL);        
77
78     if(xmlSecCheckNodeName(cur, name, ns)) {
79         return(cur);
80     } else if(cur->parent != NULL) {
81         return(xmlSecFindParent(cur->parent, name, ns));
82     }
83     return(NULL);
84 }
85
86 /**
87  * xmlSecFindNode:
88  * @parent:             the pointer to XML node.
89  * @name:               the name.
90  * @ns:                 the namespace href (may be NULL).
91  *
92  * Searches all children of the @parent node having given name and 
93  * namespace href.
94  * 
95  * Returns: the pointer to the found node or NULL if an error occurs or 
96  * node is not found.
97  */
98 xmlNodePtr              
99 xmlSecFindNode(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
100     xmlNodePtr cur;
101     xmlNodePtr ret;
102         
103     xmlSecAssert2(name != NULL, NULL); 
104     
105     cur = parent;
106     while(cur != NULL) {
107         if((cur->type == XML_ELEMENT_NODE) && xmlSecCheckNodeName(cur, name, ns)) {
108             return(cur);
109         }
110         if(cur->children != NULL) {
111             ret = xmlSecFindNode(cur->children, name, ns);
112             if(ret != NULL) {
113                 return(ret);        
114             }
115         }
116         cur = cur->next;
117     }
118     return(NULL);
119 }
120
121 /**
122  * xmlSecGetNodeNsHref:
123  * @cur:                the pointer to node.
124  *
125  * Get's node's namespace href.
126  *
127  * Returns: node's namespace href.
128  */
129 const xmlChar* 
130 xmlSecGetNodeNsHref(const xmlNodePtr cur) {
131     xmlNsPtr ns;
132     
133     xmlSecAssert2(cur != NULL, NULL);
134     
135     /* do we have a namespace in the node? */
136     if(cur->ns != NULL) {
137         return(cur->ns->href);
138     }
139     
140     /* search for default namespace */
141     ns = xmlSearchNs(cur->doc, cur, NULL);
142     if(ns != NULL) {
143         return(ns->href);
144     }
145         
146     return(NULL);
147 }
148
149 /** 
150  * xmlSecCheckNodeName:
151  * @cur:                the pointer to an XML node.
152  * @name:               the name,
153  * @ns:                 the namespace href.
154  *
155  * Checks that the node has a given name and a given namespace href.
156  *
157  * Returns: 1 if the node matches or 0 otherwise.
158  */
159 int
160 xmlSecCheckNodeName(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) {
161     xmlSecAssert2(cur != NULL, 0);
162     
163     return(xmlStrEqual(cur->name, name) && 
164            xmlStrEqual(xmlSecGetNodeNsHref(cur), ns));
165 }
166
167 /**
168  * xmlSecAddChild:
169  * @parent:             the pointer to an XML node.
170  * @name:               the new node name.
171  * @ns:                 the new node namespace.
172  *
173  * Adds a child to the node @parent with given @name and namespace @ns.
174  *
175  * Returns: pointer to the new node or NULL if an error occurs.
176  */
177 xmlNodePtr              
178 xmlSecAddChild(xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) {
179     xmlNodePtr cur;
180     xmlNodePtr text;
181
182     xmlSecAssert2(parent != NULL, NULL);
183     xmlSecAssert2(name != NULL, NULL);        
184
185     if(parent->children == NULL) {
186         /* TODO: add indents */
187         text = xmlNewText(xmlSecStringCR); 
188         if(text == NULL) {      
189             xmlSecError(XMLSEC_ERRORS_HERE,
190                         NULL,
191                         "xmlNewText",
192                         XMLSEC_ERRORS_R_XML_FAILED,
193                         XMLSEC_ERRORS_NO_MESSAGE);
194             return(NULL);
195         }
196         xmlAddChild(parent, text);
197     }
198
199     cur = xmlNewChild(parent, NULL, name, NULL);
200     if(cur == NULL) {
201         xmlSecError(XMLSEC_ERRORS_HERE,
202                     NULL,
203                     "xmlNewChild",
204                     XMLSEC_ERRORS_R_XML_FAILED,
205                     XMLSEC_ERRORS_NO_MESSAGE);
206         return(NULL);
207     }
208
209     /* namespaces support */
210     if(ns != NULL) {
211         xmlNsPtr nsPtr;
212         
213         /* find namespace by href and check that its prefix is not overwritten */
214         nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
215         if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) {
216             nsPtr = xmlNewNs(cur, ns, NULL);
217         }
218         xmlSetNs(cur, nsPtr);
219     }
220     
221     /* TODO: add indents */
222     text = xmlNewText(xmlSecStringCR); 
223     if(text == NULL) {  
224         xmlSecError(XMLSEC_ERRORS_HERE,
225                     NULL,
226                     "xmlNewText",
227                     XMLSEC_ERRORS_R_XML_FAILED,
228                     XMLSEC_ERRORS_NO_MESSAGE);
229         return(NULL);
230     }
231     xmlAddChild(parent, text);
232
233     return(cur);
234 }
235
236 /**
237  * xmlSecAddChildNode:
238  * @parent:             the pointer to an XML node.
239  * @child:              the new node.
240  *
241  * Adds @child node to the @parent node.
242  *
243  * Returns: pointer to the new node or NULL if an error occurs.
244  */
245 xmlNodePtr              
246 xmlSecAddChildNode(xmlNodePtr parent, xmlNodePtr child) {
247     xmlNodePtr text;
248
249     xmlSecAssert2(parent != NULL, NULL);
250     xmlSecAssert2(child != NULL, NULL);        
251
252     if(parent->children == NULL) {
253         /* TODO: add indents */
254         text = xmlNewText(xmlSecStringCR); 
255         if(text == NULL) {      
256             xmlSecError(XMLSEC_ERRORS_HERE,
257                         NULL,
258                         "xmlNewText",
259                         XMLSEC_ERRORS_R_XML_FAILED,
260                         XMLSEC_ERRORS_NO_MESSAGE);
261             return(NULL);
262         }
263         xmlAddChild(parent, text);
264     }
265
266     xmlAddChild(parent, child);
267
268     /* TODO: add indents */
269     text = xmlNewText(xmlSecStringCR); 
270     if(text == NULL) {  
271         xmlSecError(XMLSEC_ERRORS_HERE,
272                     NULL,
273                     "xmlNewText",
274                     XMLSEC_ERRORS_R_XML_FAILED,
275                     XMLSEC_ERRORS_NO_MESSAGE);
276         return(NULL);
277     }
278     xmlAddChild(parent, text);
279
280     return(child);
281 }
282
283 /**
284  * xmlSecAddNextSibling
285  * @node:               the pointer to an XML node.
286  * @name:               the new node name.
287  * @ns:                 the new node namespace.
288  *
289  * Adds next sibling to the node @node with given @name and namespace @ns.
290  *
291  * Returns: pointer to the new node or NULL if an error occurs.
292  */
293 xmlNodePtr
294 xmlSecAddNextSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) {
295     xmlNodePtr cur;
296     xmlNodePtr text;
297
298     xmlSecAssert2(node != NULL, NULL);
299     xmlSecAssert2(name != NULL, NULL);    
300
301     cur = xmlNewNode(NULL, name);
302     if(cur == NULL) {
303         xmlSecError(XMLSEC_ERRORS_HERE,
304                     NULL,
305                     "xmlNewNode",
306                     XMLSEC_ERRORS_R_XML_FAILED,
307                     XMLSEC_ERRORS_NO_MESSAGE);
308         return(NULL);
309     }
310     xmlAddNextSibling(node, cur);
311
312     /* namespaces support */
313     if(ns != NULL) {
314         xmlNsPtr nsPtr;
315         
316         /* find namespace by href and check that its prefix is not overwritten */
317         nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
318         if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) {
319             nsPtr = xmlNewNs(cur, ns, NULL);
320         }
321         xmlSetNs(cur, nsPtr);
322     }
323
324     /* TODO: add indents */
325     text = xmlNewText(xmlSecStringCR);
326     if(text == NULL) {  
327         xmlSecError(XMLSEC_ERRORS_HERE,
328                     NULL,
329                     "xmlNewText",
330                     XMLSEC_ERRORS_R_XML_FAILED,
331                     XMLSEC_ERRORS_NO_MESSAGE);
332         return(NULL);
333     }
334     xmlAddNextSibling(node, text);
335     
336     return(cur);
337 }
338
339 /**
340  * xmlSecAddPrevSibling
341  * @node:               the pointer to an XML node.
342  * @name:               the new node name.
343  * @ns:                 the new node namespace.
344  *
345  * Adds prev sibling to the node @node with given @name and namespace @ns.
346  *
347  * Returns: pointer to the new node or NULL if an error occurs.
348  */
349 xmlNodePtr
350 xmlSecAddPrevSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) {
351     xmlNodePtr cur;
352     xmlNodePtr text;
353
354     xmlSecAssert2(node != NULL, NULL);
355     xmlSecAssert2(name != NULL, NULL);    
356
357     cur = xmlNewNode(NULL, name);
358     if(cur == NULL) {
359         xmlSecError(XMLSEC_ERRORS_HERE,
360                     NULL,
361                     "xmlNewNode",
362                     XMLSEC_ERRORS_R_XML_FAILED,
363                     XMLSEC_ERRORS_NO_MESSAGE);
364         return(NULL);
365     }
366     xmlAddPrevSibling(node, cur);
367
368     /* namespaces support */
369     if(ns != NULL) {
370         xmlNsPtr nsPtr;
371         
372         /* find namespace by href and check that its prefix is not overwritten */
373         nsPtr = xmlSearchNsByHref(cur->doc, cur, ns);
374         if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) {
375             nsPtr = xmlNewNs(cur, ns, NULL);
376         }
377         xmlSetNs(cur, nsPtr);
378     }
379
380     /* TODO: add indents */
381     text = xmlNewText(xmlSecStringCR);
382     if(text == NULL) {  
383         xmlSecError(XMLSEC_ERRORS_HERE,
384                     NULL,
385                     "xmlNewText",
386                     XMLSEC_ERRORS_R_XML_FAILED,
387                     XMLSEC_ERRORS_NO_MESSAGE);
388         return(NULL);
389     }
390     xmlAddPrevSibling(node, text);
391
392     return(cur);
393 }
394
395 /**
396  * xmlSecGetNextElementNode:
397  * @cur:                the pointer to an XML node.
398  *
399  * Seraches for the next element node.
400  *
401  * Returns: the pointer to next element node or NULL if it is not found.
402  */
403 xmlNodePtr
404 xmlSecGetNextElementNode(xmlNodePtr cur) {
405     
406     while((cur != NULL) && (cur->type != XML_ELEMENT_NODE)) {
407         cur = cur->next;
408     }
409     return(cur);
410 }
411
412 /**
413  * xmlSecReplaceNode:
414  * @node:               the current node.
415  * @newNode:            the new node.
416  * 
417  * Swaps the @node and @newNode in the XML tree.
418  *
419  * Returns: 0 on success or a negative value if an error occurs.
420  */
421 int
422 xmlSecReplaceNode(xmlNodePtr node, xmlNodePtr newNode) {
423     return xmlSecReplaceNodeAndReturn(node, newNode, NULL);
424 }
425
426 /**                 
427  * xmlSecReplaceNodeAndReturn:
428  * @node:               the current node.
429  * @newNode:            the new node.
430  * @replaced:           the replaced node, or release it if NULL is given
431  * 
432  * Swaps the @node and @newNode in the XML tree.
433  *
434  * Returns: 0 on success or a negative value if an error occurs.
435  */
436 int
437 xmlSecReplaceNodeAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr* replaced) {
438     xmlNodePtr oldNode;
439     int restoreRoot = 0;
440     
441     xmlSecAssert2(node != NULL, -1);
442     xmlSecAssert2(newNode != NULL, -1);    
443
444     /* fix documents children if necessary first */
445     if((node->doc != NULL) && (node->doc->children == node)) {
446         node->doc->children = node->next;
447         restoreRoot = 1;
448     }
449     if((newNode->doc != NULL) && (newNode->doc->children == newNode)) {
450         newNode->doc->children = newNode->next;
451     }
452
453     oldNode = xmlReplaceNode(node, newNode);
454     if(oldNode == NULL) {
455         xmlSecError(XMLSEC_ERRORS_HERE,
456                     NULL,
457                     "xmlReplaceNode",
458                     XMLSEC_ERRORS_R_XML_FAILED,
459                     XMLSEC_ERRORS_NO_MESSAGE);
460         return(-1);
461     }
462
463     if(restoreRoot != 0) {
464         xmlDocSetRootElement(oldNode->doc, newNode);
465     }
466
467     /* return the old node if requested */
468     if(replaced != NULL) {
469         (*replaced) = oldNode;                  
470     } else {
471         xmlFreeNode(oldNode); 
472     }
473    
474     return(0);
475 }
476
477 /**
478  * xmlSecReplaceContent
479  * @node:               the current node.
480  * @newNode:            the new node.
481  * 
482  * Swaps the content of @node and @newNode.
483  *
484  * Returns: 0 on success or a negative value if an error occurs.
485  */
486 int
487 xmlSecReplaceContent(xmlNodePtr node, xmlNodePtr newNode) {
488      return xmlSecReplaceContentAndReturn(node, newNode, NULL);
489 }
490
491 /**
492  * xmlSecReplaceContentAndReturn
493  * @node:               the current node.
494  * @newNode:            the new node.
495  * @replaced:           the replaced nodes, or release them if NULL is given
496  * 
497  * Swaps the content of @node and @newNode.
498  *
499  * Returns: 0 on success or a negative value if an error occurs.
500  */
501 int
502 xmlSecReplaceContentAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr *replaced) {
503     xmlSecAssert2(node != NULL, -1);
504     xmlSecAssert2(newNode != NULL, -1);  
505
506     xmlUnlinkNode(newNode);
507     xmlSetTreeDoc(newNode, node->doc);
508
509     /* return the old nodes if requested */
510     if(replaced != NULL) {
511         xmlNodePtr cur, next, tail;
512
513         (*replaced) = tail = NULL;
514         for(cur = node->children; (cur != NULL); cur = next) {
515             next = cur->next;
516             if((*replaced) != NULL) {
517                 /* n is unlinked in this function */            
518                 xmlAddNextSibling(tail, cur); 
519                 tail = cur;
520             } else {
521                 /* this is the first node, (*replaced) is the head */
522                 xmlUnlinkNode(cur);
523                 (*replaced) = tail = cur;           
524           }
525         }
526     } else {
527         /* just delete the content */
528         xmlNodeSetContent(node, NULL);
529     }
530
531     xmlAddChild(node, newNode);
532     xmlSetTreeDoc(newNode, node->doc);
533
534     return(0);
535 }
536
537 /**
538  * xmlSecReplaceNodeBuffer:
539  * @node:               the current node.
540  * @buffer:             the XML data.
541  * @size:               the XML data size.
542  * 
543  * Swaps the @node and the parsed XML data from the @buffer in the XML tree.
544  *
545  * Returns: 0 on success or a negative value if an error occurs.
546  */
547 int
548 xmlSecReplaceNodeBuffer(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size) {
549     return xmlSecReplaceNodeBufferAndReturn(node, buffer, size, NULL);
550 }
551
552 /**
553  * xmlSecReplaceNodeBufferAndReturn:
554  * @node:               the current node.
555  * @buffer:             the XML data.
556  * @size:               the XML data size.
557  * @replaced:           the replaced nodes, or release them if NULL is given
558  * 
559  * Swaps the @node and the parsed XML data from the @buffer in the XML tree.
560  *
561  * Returns: 0 on success or a negative value if an error occurs.
562  */
563 int
564 xmlSecReplaceNodeBufferAndReturn(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size, xmlNodePtr *replaced) {
565     xmlNodePtr results = NULL;
566     xmlNodePtr next = NULL;
567
568     xmlSecAssert2(node != NULL, -1);
569     xmlSecAssert2(node->parent != NULL, -1);
570
571     /* parse buffer in the context of node's parent */
572     if(xmlParseInNodeContext(node->parent, (const char*)buffer, size, XML_PARSE_NODICT, &results) != XML_ERR_OK) {
573         xmlSecError(XMLSEC_ERRORS_HERE,
574                     NULL,
575                     "xmlParseInNodeContext",
576                     XMLSEC_ERRORS_R_XML_FAILED,
577                     "Failed to parse content");
578         return(-1);         
579     }
580
581     /* add new nodes */
582     while (results != NULL) {
583         next = results->next;
584         xmlAddPrevSibling(node, results);
585         results = next;
586     }
587
588     /* remove old node */
589     xmlUnlinkNode(node);
590
591     /* return the old node if requested */
592     if(replaced != NULL) {
593         (*replaced) = node;             
594     } else {
595         xmlFreeNode(node); 
596     }
597
598     return(0);
599 }
600
601 /**
602  * xmlSecNodeEncodeAndSetContent:
603  * @node:                   the pointer to an XML node.
604  * @buffer:             the pointer to the node content.
605  *
606  * Encodes "special" characters in the @buffer and sets the result
607  * as the node content.
608  *
609  * Returns: 0 on success or a negative value if an error occurs.
610  */
611 int
612 xmlSecNodeEncodeAndSetContent(xmlNodePtr node, const xmlChar * buffer) {
613     xmlSecAssert2(node != NULL, -1);
614     xmlSecAssert2(node->doc != NULL, -1);
615     
616     if(buffer != NULL) {
617             xmlChar * tmp;
618
619         tmp = xmlEncodeSpecialChars(node->doc, buffer);        
620         if (tmp == NULL) {
621             xmlSecError(XMLSEC_ERRORS_HERE,
622                         NULL,
623                         "xmlEncodeSpecialChars",
624                         XMLSEC_ERRORS_R_XML_FAILED,
625                         "Failed to encode special characters");
626             return(-1);         
627         }
628
629         xmlNodeSetContent(node, tmp);
630         xmlFree(tmp);
631     } else {
632         xmlNodeSetContent(node, NULL);
633     }
634
635     return(0);
636 }
637
638 /**
639  * xmlSecAddIDs:
640  * @doc:                the pointer to an XML document.
641  * @cur:                the pointer to an XML node.
642  * @ids:                the pointer to a NULL terminated list of ID attributes.
643  *
644  * Walks thru all children of the @cur node and adds all attributes 
645  * from the @ids list to the @doc document IDs attributes hash.
646  */
647 void    
648 xmlSecAddIDs(xmlDocPtr doc, xmlNodePtr cur, const xmlChar** ids) {
649     xmlNodePtr children = NULL;
650
651     xmlSecAssert(doc != NULL);
652     xmlSecAssert(ids != NULL);    
653     
654     if((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) {
655         xmlAttrPtr attr;
656         xmlAttrPtr tmp;
657         int i;
658         xmlChar* name;
659         
660         for(attr = cur->properties; attr != NULL; attr = attr->next) {
661             for(i = 0; ids[i] != NULL; ++i) {
662                 if(xmlStrEqual(attr->name, ids[i])) {
663                     name = xmlNodeListGetString(doc, attr->children, 1);
664                     if(name != NULL) {
665                         tmp = xmlGetID(doc, name);
666                         if(tmp == NULL) {
667                             xmlAddID(NULL, doc, name, attr);
668                         } else if(tmp != attr) {
669                             xmlSecError(XMLSEC_ERRORS_HERE,
670                                         NULL,
671                                         NULL,
672                                         XMLSEC_ERRORS_R_INVALID_DATA,
673                                         "id=%s already defined", 
674                                         xmlSecErrorsSafeString(name));
675                         }
676                         xmlFree(name);
677                     }               
678                 }
679             }
680         }
681         
682         children = cur->children;
683     } else if(cur == NULL) {
684         children = doc->children;
685     }
686     
687     while(children != NULL) {
688         if(children->type == XML_ELEMENT_NODE) {
689             xmlSecAddIDs(doc, children, ids);
690         }
691         children = children->next;
692     }
693 }
694
695 /**
696  * xmlSecGenerateAndAddID:
697  * @node:                       the node to ID attr to.
698  * @attrName:                   the ID attr name.
699  * @prefix:                     the prefix to add to the generated ID (can be NULL).
700  * @len:                        the length of ID.
701  *
702  * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes)
703  * and puts it in the attribute @attrName.
704  *
705  * Returns: 0 on success or a negative value if an error occurs.
706  */
707 int 
708 xmlSecGenerateAndAddID(xmlNodePtr node, const xmlChar* attrName, const xmlChar* prefix, xmlSecSize len) {
709     xmlChar* id;
710     int count;
711     
712     xmlSecAssert2(node != NULL, -1);    
713     xmlSecAssert2(attrName != NULL, -1);    
714
715     /* we will try 5 times before giving up */
716     for(count = 0; count < 5; count++) {
717         id = xmlSecGenerateID(prefix, len);
718         if(id == NULL) {
719             xmlSecError(XMLSEC_ERRORS_HERE,
720                         NULL,
721                         "xmlSecGenerateID",
722                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
723                         XMLSEC_ERRORS_NO_MESSAGE);
724             return(-1);
725         }
726
727         if((node->doc == NULL) || (xmlGetID(node->doc, id) == NULL)) {
728             /* this is a unique ID in the document and we can use it */
729             if(xmlSetProp(node, attrName, id) == NULL) {
730                 xmlSecError(XMLSEC_ERRORS_HERE,
731                             NULL,
732                             "xmlSetProp",
733                             XMLSEC_ERRORS_R_XML_FAILED,
734                             XMLSEC_ERRORS_NO_MESSAGE);
735                 xmlFree(id);
736                 return(-1);     
737             }
738             
739             xmlFree(id);
740             return(0);
741         }
742         xmlFree(id);
743     }
744
745     return(-1);
746 }
747
748 /**
749  * xmlSecGenerateID:
750  * @prefix:                     the prefix to add to the generated ID (can be NULL).
751  * @len:                        the length of ID.
752  *
753  * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes).
754  * The caller is responsible for freeing returned string using @xmlFree function.
755  *
756  * Returns: pointer to generated ID string or NULL if an error occurs.
757  */
758 xmlChar*
759 xmlSecGenerateID(const xmlChar* prefix, xmlSecSize len) {
760     xmlSecBuffer buffer;    
761     xmlSecSize i, binLen;
762     xmlChar* res;
763     xmlChar* p;
764     int ret;
765
766     xmlSecAssert2(len > 0, NULL);    
767     
768     /* we will do base64 decoding later */
769     binLen = (3 * len + 1) / 4;
770     
771     ret = xmlSecBufferInitialize(&buffer, binLen + 1);
772     if(ret < 0) {
773         xmlSecError(XMLSEC_ERRORS_HERE,
774                     NULL,
775                     "xmlSecBufferInitialize",
776                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
777                     XMLSEC_ERRORS_NO_MESSAGE);
778         return(NULL);   
779     }
780     xmlSecAssert2(xmlSecBufferGetData(&buffer) != NULL, NULL);
781     xmlSecAssert2(xmlSecBufferGetMaxSize(&buffer) >= binLen, NULL);
782     
783     ret = xmlSecBufferSetSize(&buffer, binLen);
784     if(ret < 0) {
785         xmlSecError(XMLSEC_ERRORS_HERE,
786                     NULL,
787                     "xmlSecBufferSetSize",
788                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
789                     XMLSEC_ERRORS_NO_MESSAGE);
790         xmlSecBufferFinalize(&buffer);
791         return(NULL);   
792     }
793     xmlSecAssert2(xmlSecBufferGetSize(&buffer) == binLen, NULL);
794     
795     /* create random bytes */
796     for(i = 0; i < binLen; i++) {
797         (xmlSecBufferGetData(&buffer)) [i] = (xmlSecByte) (256.0 * rand() / (RAND_MAX + 1.0));
798     }
799     
800     /* base64 encode random bytes */
801     res = xmlSecBase64Encode(xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), 0);
802     if((res == NULL) || (xmlStrlen(res) == 0)) {
803         xmlSecError(XMLSEC_ERRORS_HERE,
804                     NULL,
805                     "xmlSecBase64Encode",
806                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
807                     XMLSEC_ERRORS_NO_MESSAGE);
808         xmlSecBufferFinalize(&buffer);
809         return(NULL);   
810     }
811     xmlSecBufferFinalize(&buffer);
812
813     /* truncate the generated id attribute if needed */
814     if(xmlStrlen(res) > (int)len) {
815         res[len] = '\0';
816     }
817
818     /* we need to cleanup base64 encoded id because ID attr can't have '+' or '/' characters */ 
819     for(p = res; (*p) != '\0'; p++) {
820         if(((*p) == '+') || ((*p) == '/')) {
821             (*p) = '_';
822         }
823     }
824     
825     /* add prefix if exist */
826     if(prefix) {
827         xmlChar* tmp;
828         xmlSecSize tmpLen;
829         
830         tmpLen = xmlStrlen(prefix) + xmlStrlen(res) + 1;
831         tmp = xmlMalloc(tmpLen + 1);
832         if(tmp == NULL) {
833             xmlSecError(XMLSEC_ERRORS_HERE,
834                         NULL,
835                         "xmlMalloc",
836                         XMLSEC_ERRORS_R_MALLOC_FAILED,
837                         XMLSEC_ERRORS_NO_MESSAGE);
838             xmlFree(res);
839             return(NULL);
840         }
841         
842         xmlSecStrPrintf(tmp, tmpLen, BAD_CAST "%s%s", prefix, res);
843         xmlFree(res);
844         res = tmp;    
845     } else {
846         /* no prefix: check that ID attribute starts from a letter */
847         if(!(((res[0] >= 'A') && (res[0] <= 'Z')) || 
848              ((res[0] >= 'a') && (res[0] <= 'z')))) {
849              res[0] = 'A';
850         }
851     }
852     
853     return(res);
854 }
855
856
857 /**
858  * xmlSecCreateTree:
859  * @rootNodeName:       the root node name.
860  * @rootNodeNs:         the root node namespace (otpional).
861  *
862  * Creates a new XML tree with one root node @rootNodeName.
863  *
864  * Returns: pointer to the newly created tree or NULL if an error occurs.
865  */
866 xmlDocPtr 
867 xmlSecCreateTree(const xmlChar* rootNodeName, const xmlChar* rootNodeNs) {
868     xmlDocPtr doc;
869     xmlNodePtr root;
870     xmlNsPtr ns;
871     
872     xmlSecAssert2(rootNodeName != NULL, NULL);
873
874     /* create doc */
875     doc = xmlNewDoc(BAD_CAST "1.0");
876     if(doc == NULL) {
877         xmlSecError(XMLSEC_ERRORS_HERE,
878                     NULL,
879                     "xmlNewDoc",
880                     XMLSEC_ERRORS_R_XML_FAILED,
881                     XMLSEC_ERRORS_NO_MESSAGE);
882         return(NULL);
883     }
884     
885     /* create root node */
886     root = xmlNewDocNode(doc, NULL, rootNodeName, NULL); 
887     if(root == NULL) {
888         xmlSecError(XMLSEC_ERRORS_HERE, 
889                     NULL,
890                     "xmlNewDocNode",
891                     XMLSEC_ERRORS_R_XML_FAILED,
892                     "node=Keys");
893         xmlFreeDoc(doc);
894         return(NULL);
895     }
896     xmlDocSetRootElement(doc, root);
897
898     /* and set root node namespace */
899     ns = xmlNewNs(root, rootNodeNs, NULL);
900     if(ns == NULL) {
901         xmlSecError(XMLSEC_ERRORS_HERE,
902                     NULL,
903                     "xmlNewNs",
904                     XMLSEC_ERRORS_R_XML_FAILED,
905                     "ns=%s",
906                     xmlSecErrorsSafeString(rootNodeNs));
907         xmlFreeDoc(doc); 
908         return(NULL);
909     }
910     xmlSetNs(root, ns);
911
912     return(doc);
913 }
914
915 /**
916  * xmlSecIsEmptyNode:
917  * @node:               the node to check
918  *
919  * Checks whethere the @node is empty (i.e. has only whitespaces children).
920  *
921  * Returns: 1 if @node is empty, 0 otherwise or a negative value if an error occurs.
922  */
923 int 
924 xmlSecIsEmptyNode(xmlNodePtr node) {
925     xmlChar* content;
926     int res;
927     
928     xmlSecAssert2(node != NULL, -1);
929
930     if(xmlSecGetNextElementNode(node->children) != NULL) {
931         return(0);
932     }
933     
934     content = xmlNodeGetContent(node);
935     if(content == NULL) {
936         return(1);
937     }
938     
939     res = xmlSecIsEmptyString(content);
940     xmlFree(content);
941     return(res);
942 }
943
944 /**
945  * xmlSecIsEmptyString:
946  * @str:                the string to check
947  *
948  * Checks whethere the @str is empty (i.e. has only whitespaces children).
949  *
950  * Returns: 1 if @str is empty, 0 otherwise or a negative value if an error occurs.
951  */
952 int 
953 xmlSecIsEmptyString(const xmlChar* str) {
954     xmlSecAssert2(str != NULL, -1);
955     
956     for( ;*str != '\0'; ++str) {
957         if(!isspace((int)(*str))) {
958             return(0);
959         }
960     }
961     return(1);
962 }
963
964 /**
965  * xmlSecPrintXmlString: 
966  * @fd:                the file descriptor to write the XML string to
967  * @str:               the string
968  *
969  * Encodes the @str (e.g. replaces '&' with '&amp;') and writes it to @fd.
970  *
971  * Returns: he number of bytes transmitted or a negative value if an error occurs.
972  */
973 int 
974 xmlSecPrintXmlString(FILE * fd, const xmlChar * str) {
975     int res;
976     
977     if(str != NULL) {    
978         xmlChar * encoded_str = NULL;
979         encoded_str = xmlEncodeSpecialChars(NULL, str);
980         if(encoded_str == NULL) {
981             xmlSecError(XMLSEC_ERRORS_HERE,     
982                         NULL,
983                         "xmlEncodeSpecialChars",
984                         XMLSEC_ERRORS_R_XML_FAILED,
985                         "string=%s",
986                         xmlSecErrorsSafeString(str));
987             return(-1);
988         }
989     
990         res = fprintf(fd, "%s", (const char*)encoded_str);
991         xmlFree(encoded_str);
992     } else {
993         res = fprintf(fd, "NULL");
994     }
995     
996     if(res < 0) {
997         xmlSecError(XMLSEC_ERRORS_HERE, 
998                     NULL,
999                     "fprintf",
1000                     XMLSEC_ERRORS_R_IO_FAILED,
1001                     "res=%d,errno=%d",
1002                     res, errno);
1003         return(-1);
1004     }
1005     return(res);
1006 }
1007
1008
1009 /** 
1010  * xmlSecGetQName:
1011  * @node:               the context node.
1012  * @href:               the QName href (can be NULL).
1013  * @local:              the QName local part.
1014  *
1015  * Creates QName (prefix:local) from @href and @local in the context of the @node.
1016  * Caller is responsible for freeing returned string with xmlFree.
1017  *
1018  * Returns: qname or NULL if an error occurs.
1019  */
1020 xmlChar* 
1021 xmlSecGetQName(xmlNodePtr node, const xmlChar* href, const xmlChar* local) {
1022     xmlChar* qname;
1023     xmlNsPtr ns;
1024
1025     xmlSecAssert2(node != NULL, NULL);
1026     xmlSecAssert2(local != NULL, NULL);
1027
1028     /* we don't want to create namespace node ourselves because
1029      * it might cause collisions */
1030     ns = xmlSearchNsByHref(node->doc, node, href);
1031     if((ns == NULL) && (href != NULL)) {
1032         xmlSecError(XMLSEC_ERRORS_HERE,
1033                     NULL,
1034                     "xmlSearchNsByHref",
1035                     XMLSEC_ERRORS_R_XML_FAILED,
1036                     "node=%s,href=%s",
1037                     xmlSecErrorsSafeString(node->name),
1038                     xmlSecErrorsSafeString(href));
1039         return(NULL);
1040     }
1041         
1042     if((ns != NULL) && (ns->prefix != NULL)) {
1043         xmlSecSize len;
1044         
1045         len = xmlStrlen(local) + xmlStrlen(ns->prefix) + 4;
1046         qname = xmlMalloc(len);
1047         if(qname == NULL) {
1048             xmlSecError(XMLSEC_ERRORS_HERE,
1049                         NULL,
1050                         "xmlMalloc",
1051                         XMLSEC_ERRORS_R_MALLOC_FAILED,
1052                         "node=%s",
1053                         xmlSecErrorsSafeString(node->name));
1054             return(NULL);
1055         }
1056         xmlSecStrPrintf(qname, len, BAD_CAST "%s:%s", ns->prefix, local);
1057     } else {
1058         qname = xmlStrdup(local);
1059         if(qname == NULL) {
1060             xmlSecError(XMLSEC_ERRORS_HERE,
1061                         NULL,
1062                         "xmlStrdup",
1063                         XMLSEC_ERRORS_R_MALLOC_FAILED,
1064                         "node=%s",
1065                         xmlSecErrorsSafeString(node->name));
1066             return(NULL);
1067         }
1068     }
1069
1070
1071     return(qname);
1072 }
1073
1074
1075 /*************************************************************************
1076  *
1077  * QName <-> Integer mapping
1078  *
1079  ************************************************************************/
1080 /** 
1081  * xmlSecQName2IntegerGetInfo:
1082  * @info:               the qname<->integer mapping information.
1083  * @intValue:           the integer value.
1084  *
1085  * Maps integer @intValue to a QName prefix.
1086  * 
1087  * Returns: the QName info that is mapped to @intValue or NULL if such value
1088  * is not found.
1089  */
1090 xmlSecQName2IntegerInfoConstPtr 
1091 xmlSecQName2IntegerGetInfo(xmlSecQName2IntegerInfoConstPtr info, int intValue) {
1092     unsigned int ii;
1093
1094     xmlSecAssert2(info != NULL, NULL);
1095
1096     for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
1097         if(info[ii].intValue == intValue) {
1098             return(&info[ii]);
1099         }
1100     }
1101
1102     return(NULL);
1103 }
1104
1105 /** 
1106  * xmlSecQName2IntegerGetInteger:
1107  * @info:               the qname<->integer mapping information.
1108  * @qnameHref:          the qname href value.
1109  * @qnameLocalPart:     the qname local part value.
1110  * @intValue:           the pointer to result integer value.
1111  * 
1112  * Maps qname qname to an integer and returns it in @intValue.
1113  * 
1114  * Returns: 0 on success or a negative value if an error occurs,
1115  */
1116 int 
1117 xmlSecQName2IntegerGetInteger(xmlSecQName2IntegerInfoConstPtr info, 
1118                              const xmlChar* qnameHref, const xmlChar* qnameLocalPart, 
1119                              int* intValue) {
1120     unsigned int ii;
1121
1122     xmlSecAssert2(info != NULL, -1);
1123     xmlSecAssert2(qnameLocalPart != NULL, -1);
1124     xmlSecAssert2(intValue != NULL, -1);
1125
1126     for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
1127         if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && 
1128            xmlStrEqual(info[ii].qnameHref, qnameHref)) {
1129             (*intValue) = info[ii].intValue;
1130             return(0);
1131         }
1132     }
1133
1134     return(-1);
1135 }
1136
1137 /** 
1138  * xmlSecQName2IntegerGetIntegerFromString:
1139  * @info:               the qname<->integer mapping information.
1140  * @node:               the pointer to node.
1141  * @qname:              the qname string.
1142  * @intValue:           the pointer to result integer value.
1143  * 
1144  * Converts @qname into integer in context of @node.
1145  * 
1146  * Returns: 0 on success or a negative value if an error occurs,
1147  */
1148 int 
1149 xmlSecQName2IntegerGetIntegerFromString(xmlSecQName2IntegerInfoConstPtr info,
1150                                         xmlNodePtr node, const xmlChar* qname,
1151                                         int* intValue) {
1152     const xmlChar* qnameLocalPart = NULL;
1153     xmlChar* qnamePrefix = NULL;
1154     const xmlChar* qnameHref;
1155     xmlNsPtr ns;
1156     int ret;
1157     
1158     xmlSecAssert2(info != NULL, -1);
1159     xmlSecAssert2(node != NULL, -1);
1160     xmlSecAssert2(qname != NULL, -1);
1161     xmlSecAssert2(intValue != NULL, -1);
1162     
1163     qnameLocalPart = xmlStrchr(qname, ':');
1164     if(qnameLocalPart != NULL) {
1165         qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname);
1166         if(qnamePrefix == NULL) {
1167             xmlSecError(XMLSEC_ERRORS_HERE,
1168                         NULL,
1169                         "xmlStrndup",
1170                         XMLSEC_ERRORS_R_MALLOC_FAILED,
1171                         "node=%s,value=%s",
1172                         xmlSecErrorsSafeString(node->name),
1173                         xmlSecErrorsSafeString(qname));
1174             return(-1); 
1175         }
1176         qnameLocalPart++;
1177     } else {
1178         qnamePrefix = NULL;
1179         qnameLocalPart = qname;
1180     }
1181     
1182     /* search namespace href */
1183     ns = xmlSearchNs(node->doc, node, qnamePrefix);
1184     if((ns == NULL) && (qnamePrefix != NULL)) {
1185         xmlSecError(XMLSEC_ERRORS_HERE,
1186                     NULL,
1187                     "xmlSearchNs",
1188                     XMLSEC_ERRORS_R_XML_FAILED,
1189                     "node=%s,qnamePrefix=%s",
1190                     xmlSecErrorsSafeString(node->name),
1191                     xmlSecErrorsSafeString(qnamePrefix));
1192         if(qnamePrefix != NULL) {
1193             xmlFree(qnamePrefix);
1194         }
1195         return(-1);     
1196     }
1197     qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL;
1198
1199     /* and finally search for integer */
1200     ret = xmlSecQName2IntegerGetInteger(info, qnameHref, qnameLocalPart, intValue);
1201     if(ret < 0) {
1202         xmlSecError(XMLSEC_ERRORS_HERE,
1203                     NULL,
1204                     "xmlSecQName2IntegerGetInteger",
1205                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1206                     "node=%s,qnameLocalPart=%s,qnameHref=%s",
1207                     xmlSecErrorsSafeString(node->name),
1208                     xmlSecErrorsSafeString(qnameLocalPart),
1209                     xmlSecErrorsSafeString(qnameHref));
1210         if(qnamePrefix != NULL) {
1211             xmlFree(qnamePrefix);
1212         }
1213         return(-1);     
1214     }
1215
1216     if(qnamePrefix != NULL) {
1217         xmlFree(qnamePrefix);
1218     }
1219     return(0);
1220 }
1221
1222
1223 /** 
1224  * xmlSecQName2IntegerGetStringFromInteger:
1225  * @info:               the qname<->integer mapping information.
1226  * @node:               the pointer to node.
1227  * @intValue:           the integer value.
1228  * 
1229  * Creates qname string for @intValue in context of given @node. Caller
1230  * is responsible for freeing returned string with @xmlFree.
1231  * 
1232  * Returns: pointer to newly allocated string on success or NULL if an error occurs,
1233  */
1234 xmlChar* 
1235 xmlSecQName2IntegerGetStringFromInteger(xmlSecQName2IntegerInfoConstPtr info,
1236                                         xmlNodePtr node, int intValue) {
1237     xmlSecQName2IntegerInfoConstPtr qnameInfo;
1238
1239     xmlSecAssert2(info != NULL, NULL);
1240     xmlSecAssert2(node != NULL, NULL);
1241
1242     qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
1243     if(qnameInfo == NULL) {
1244         xmlSecError(XMLSEC_ERRORS_HERE,
1245                     NULL,
1246                     "xmlSecQName2IntegerGetInfo",
1247                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1248                     "node=%s,intValue=%d",
1249                     xmlSecErrorsSafeString(node->name),
1250                     intValue);
1251         return(NULL);
1252     }
1253     
1254     return (xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart));
1255 }
1256
1257 /** 
1258  * xmlSecQName2IntegerNodeRead:
1259  * @info:               the qname<->integer mapping information.
1260  * @node:               the pointer to node.
1261  * @intValue:           the pointer to result integer value.
1262  * 
1263  * Reads the content of @node and converts it to an integer using mapping 
1264  * from @info.
1265  * 
1266  * Returns: 0 on success or a negative value if an error occurs,
1267  */
1268 int 
1269 xmlSecQName2IntegerNodeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, int* intValue) {
1270     xmlChar* content = NULL;
1271     int ret;
1272
1273     xmlSecAssert2(info != NULL, -1);
1274     xmlSecAssert2(node != NULL, -1);
1275     xmlSecAssert2(intValue != NULL, -1);
1276
1277     content = xmlNodeGetContent(node);
1278     if(content == NULL) {
1279         xmlSecError(XMLSEC_ERRORS_HERE,
1280                     NULL,
1281                     "xmlNodeGetContent",
1282                     XMLSEC_ERRORS_R_XML_FAILED,
1283                     "node=%s",
1284                     xmlSecErrorsSafeString(node->name));
1285         return(-1);     
1286     }
1287     /* todo: trim content? */
1288
1289     ret = xmlSecQName2IntegerGetIntegerFromString(info, node, content, intValue);
1290     if(ret < 0) {
1291         xmlSecError(XMLSEC_ERRORS_HERE,
1292                     NULL,
1293                     "xmlSecQName2IntegerGetIntegerFromString",
1294                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1295                     "node=%s,value=%s",
1296                     xmlSecErrorsSafeString(node->name),
1297                     xmlSecErrorsSafeString(content));
1298         xmlFree(content);
1299         return(-1);     
1300     }
1301
1302     xmlFree(content);
1303     return(0);
1304 }
1305
1306 /** 
1307  * xmlSecQName2IntegerNodeWrite:
1308  * @info:               the qname<->integer mapping information.
1309  * @node:               the parent node.
1310  * @nodeName:           the child node name.
1311  * @nodeNs:             the child node namespace.
1312  * @intValue:           the integer value.
1313  * 
1314  * Creates new child node in @node and sets its value to @intValue.
1315  * 
1316  * Returns: 0 on success or a negative value if an error occurs,
1317  */
1318 int 
1319 xmlSecQName2IntegerNodeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
1320                             const xmlChar* nodeName, const xmlChar* nodeNs, int intValue) {
1321     xmlNodePtr cur;
1322     xmlChar* qname = NULL;
1323
1324     xmlSecAssert2(info != NULL, -1);
1325     xmlSecAssert2(node != NULL, -1);
1326     xmlSecAssert2(nodeName != NULL, -1);
1327
1328     /* find and build qname */
1329     qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue);
1330     if(qname == NULL) {
1331         xmlSecError(XMLSEC_ERRORS_HERE,
1332                     NULL,
1333                     "xmlSecQName2IntegerGetStringFromInteger",
1334                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1335                     "node=%s,intValue=%d",
1336                     xmlSecErrorsSafeString(node->name),
1337                     intValue);
1338         return(-1);
1339     }
1340     
1341     cur = xmlSecAddChild(node, nodeName, nodeNs);
1342     if(cur == NULL) {
1343         xmlSecError(XMLSEC_ERRORS_HERE,
1344                     NULL,
1345                     "xmlSecAddChild",
1346                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1347                     "node=%s,intValue=%d",
1348                     xmlSecErrorsSafeString(nodeName),
1349                     intValue);
1350         xmlFree(qname);
1351         return(-1);
1352     }
1353
1354     xmlNodeSetContent(cur, qname);
1355     xmlFree(qname);
1356     return(0);
1357 }
1358
1359 /** 
1360  * xmlSecQName2IntegerAttributeRead:
1361  * @info:               the qname<->integer mapping information.
1362  * @node:               the element node. 
1363  * @attrName:           the attribute name.
1364  * @intValue:           the pointer to result integer value.
1365  * 
1366  * Gets the value of @attrName atrtibute from @node and converts it to integer
1367  * according to @info.
1368  * 
1369  * Returns: 0 on success or a negative value if an error occurs,
1370  */
1371 int 
1372 xmlSecQName2IntegerAttributeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
1373                             const xmlChar* attrName, int* intValue) {
1374     xmlChar* attrValue;
1375     int ret;
1376
1377     xmlSecAssert2(info != NULL, -1);
1378     xmlSecAssert2(node != NULL, -1);
1379     xmlSecAssert2(attrName != NULL, -1);
1380     xmlSecAssert2(intValue != NULL, -1);
1381
1382     attrValue = xmlGetProp(node, attrName);
1383     if(attrValue == NULL) {
1384         xmlSecError(XMLSEC_ERRORS_HERE,
1385                     NULL,
1386                     "xmlGetProp",
1387                     XMLSEC_ERRORS_R_XML_FAILED,
1388                     "node=%s,attrValue=%s",
1389                     xmlSecErrorsSafeString(node->name),
1390                     xmlSecErrorsSafeString(attrName));
1391         return(-1);     
1392     }
1393     /* todo: trim value? */
1394
1395     ret = xmlSecQName2IntegerGetIntegerFromString(info, node, attrValue, intValue);
1396     if(ret < 0) {
1397         xmlSecError(XMLSEC_ERRORS_HERE,
1398                     NULL,
1399                     "xmlSecQName2IntegerGetIntegerFromString",
1400                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1401                     "node=%s,attrName=%s,attrValue=%s",
1402                     xmlSecErrorsSafeString(node->name),
1403                     xmlSecErrorsSafeString(attrName),
1404                     xmlSecErrorsSafeString(attrValue));
1405         xmlFree(attrValue);
1406         return(-1);     
1407     }
1408
1409     xmlFree(attrValue);
1410     return(0);
1411 }
1412
1413 /** 
1414  * xmlSecQName2IntegerAttributeWrite:
1415  * @info:               the qname<->integer mapping information.
1416  * @node:               the parent node.
1417  * @attrName:           the name of attribute.
1418  * @intValue:           the integer value.
1419  * 
1420  * Converts @intValue to a qname and sets it to the value of 
1421  * attribute @attrName in @node.
1422  * 
1423  * Returns: 0 on success or a negative value if an error occurs,
1424  */
1425 int
1426 xmlSecQName2IntegerAttributeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node,
1427                             const xmlChar* attrName, int intValue) {
1428     xmlChar* qname;
1429     xmlAttrPtr attr;
1430
1431     xmlSecAssert2(info != NULL, -1);
1432     xmlSecAssert2(node != NULL, -1);
1433     xmlSecAssert2(attrName != NULL, -1);
1434
1435     /* find and build qname */
1436     qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue);
1437     if(qname == NULL) {
1438         xmlSecError(XMLSEC_ERRORS_HERE,
1439                     NULL,
1440                     "xmlSecQName2IntegerGetStringFromInteger",
1441                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1442                     "node=%s,attrName=%s,intValue=%d",
1443                     xmlSecErrorsSafeString(node->name),
1444                     xmlSecErrorsSafeString(attrName),
1445                     intValue);
1446         return(-1);
1447     }
1448
1449     attr = xmlSetProp(node, attrName, qname);
1450     if(attr == NULL) {
1451         xmlSecError(XMLSEC_ERRORS_HERE,
1452                     NULL,
1453                     "xmlSecAddChildNode",
1454                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1455                     "node=%s,attrName=%s,intValue=%d",
1456                     xmlSecErrorsSafeString(node->name),
1457                     xmlSecErrorsSafeString(attrName),
1458                     intValue);
1459         xmlFree(qname);
1460         return(-1);
1461     }
1462
1463     xmlFree(qname);
1464     return(0);
1465 }
1466
1467 /** 
1468  * xmlSecQName2IntegerDebugDump:
1469  * @info:               the qname<->integer mapping information.
1470  * @intValue:           the integer value.
1471  * @name:               the value name to print.
1472  * @output:             the pointer to output FILE.
1473  * 
1474  * Prints @intValue into @output.
1475  */
1476 void 
1477 xmlSecQName2IntegerDebugDump(xmlSecQName2IntegerInfoConstPtr info, int intValue,
1478                             const xmlChar* name, FILE* output) {
1479     xmlSecQName2IntegerInfoConstPtr qnameInfo;
1480
1481     xmlSecAssert(info != NULL);
1482     xmlSecAssert(name != NULL);
1483     xmlSecAssert(output != NULL);
1484
1485     qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
1486     if(qnameInfo != NULL) {
1487         fprintf(output, "== %s: %d (name=\"%s\", href=\"%s\")\n", name, intValue, 
1488             (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL,
1489             (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL);
1490     }    
1491 }
1492
1493 /** 
1494  * xmlSecQName2IntegerDebugXmlDump:
1495  * @info:               the qname<->integer mapping information.
1496  * @intValue:           the integer value.
1497  * @name:               the value name to print.
1498  * @output:             the pointer to output FILE.
1499  * 
1500  * Prints @intValue into @output in XML format. 
1501  */
1502 void 
1503 xmlSecQName2IntegerDebugXmlDump(xmlSecQName2IntegerInfoConstPtr info, int intValue,
1504                             const xmlChar* name, FILE* output) {
1505     xmlSecQName2IntegerInfoConstPtr qnameInfo;
1506
1507     xmlSecAssert(info != NULL);
1508     xmlSecAssert(name != NULL);
1509     xmlSecAssert(output != NULL);
1510
1511     qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue);
1512     if(qnameInfo != NULL) {
1513         fprintf(output, "<%s value=\"%d\" href=\"%s\">%s<%s>\n", name, intValue, 
1514             (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL,
1515             (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL,
1516             name);
1517     }    
1518 }
1519                                                                  
1520
1521 /*************************************************************************
1522  *
1523  * QName <-> Bits mask mapping
1524  *
1525  ************************************************************************/
1526 /** 
1527  * xmlSecQName2BitMaskGetInfo:
1528  * @info:               the qname<->bit mask mapping information.
1529  * @mask:               the bit mask.
1530  * 
1531  * Converts @mask to qname.
1532  *
1533  * Returns: pointer to the qname info for @mask or NULL if mask is unknown.
1534  */
1535 xmlSecQName2BitMaskInfoConstPtr
1536 xmlSecQName2BitMaskGetInfo(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask) {
1537     unsigned int ii;
1538
1539     xmlSecAssert2(info != NULL, NULL);
1540
1541     for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
1542         xmlSecAssert2(info[ii].mask != 0, NULL);
1543         if(info[ii].mask == mask) {
1544             return(&info[ii]);
1545         }
1546     }
1547
1548     return(NULL);
1549 }
1550
1551 /** 
1552  * xmlSecQName2BitMaskGetBitMask:
1553  * @info:               the qname<->bit mask mapping information.
1554  * @qnameHref:          the qname Href value.
1555  * @qnameLocalPart:     the qname LocalPart value.
1556  * @mask:               the pointer to result mask.
1557  * 
1558  * Converts @qnameLocalPart to @mask.
1559  * 
1560  * Returns: 0 on success or a negative value if an error occurs,
1561  */
1562 int 
1563 xmlSecQName2BitMaskGetBitMask(xmlSecQName2BitMaskInfoConstPtr info, 
1564                             const xmlChar* qnameHref, const xmlChar* qnameLocalPart,
1565                             xmlSecBitMask* mask) {
1566     unsigned int ii;
1567
1568     xmlSecAssert2(info != NULL, -1);
1569     xmlSecAssert2(qnameLocalPart != NULL, -1);
1570     xmlSecAssert2(mask != NULL, -1);
1571
1572     for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) {
1573         xmlSecAssert2(info[ii].mask != 0, -1);
1574         if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && 
1575            xmlStrEqual(info[ii].qnameHref, qnameHref)) {
1576
1577             (*mask) = info[ii].mask;
1578             return(0);
1579         }
1580     }
1581
1582     return(-1);
1583 }
1584
1585 /** 
1586  * xmlSecQName2BitMaskGetBitMaskFromString:
1587  * @info:               the qname<->integer mapping information.
1588  * @node:               the pointer to node.
1589  * @qname:              the qname string.
1590  * @mask:               the pointer to result msk value.
1591  * 
1592  * Converts @qname into integer in context of @node.
1593  * 
1594  * Returns: 0 on success or a negative value if an error occurs,
1595  */
1596 int 
1597 xmlSecQName2BitMaskGetBitMaskFromString(xmlSecQName2BitMaskInfoConstPtr info,
1598                                         xmlNodePtr node, const xmlChar* qname,
1599                                         xmlSecBitMask* mask) {
1600     const xmlChar* qnameLocalPart = NULL;
1601     xmlChar* qnamePrefix = NULL;
1602     const xmlChar* qnameHref;
1603     xmlNsPtr ns;
1604     int ret;
1605     
1606     xmlSecAssert2(info != NULL, -1);
1607     xmlSecAssert2(node != NULL, -1);
1608     xmlSecAssert2(qname != NULL, -1);
1609     xmlSecAssert2(mask != NULL, -1);
1610
1611     qnameLocalPart = xmlStrchr(qname, ':');
1612     if(qnameLocalPart != NULL) {
1613         qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname);
1614         if(qnamePrefix == NULL) {
1615             xmlSecError(XMLSEC_ERRORS_HERE,
1616                         NULL,
1617                         "xmlStrndup",
1618                         XMLSEC_ERRORS_R_MALLOC_FAILED,
1619                         "node=%s,value=%s",
1620                         xmlSecErrorsSafeString(node->name),
1621                         xmlSecErrorsSafeString(qname));
1622             return(-1); 
1623         }
1624         qnameLocalPart++;
1625     } else {
1626         qnamePrefix = NULL;
1627         qnameLocalPart = qname;
1628     }
1629     
1630     /* search namespace href */
1631     ns = xmlSearchNs(node->doc, node, qnamePrefix);
1632     if((ns == NULL) && (qnamePrefix != NULL)) {
1633         xmlSecError(XMLSEC_ERRORS_HERE,
1634                     NULL,
1635                     "xmlSearchNs",
1636                     XMLSEC_ERRORS_R_XML_FAILED,
1637                     "node=%s,qnamePrefix=%s",
1638                     xmlSecErrorsSafeString(node->name),
1639                     xmlSecErrorsSafeString(qnamePrefix));
1640         if(qnamePrefix != NULL) {
1641             xmlFree(qnamePrefix);
1642         }
1643         return(-1);     
1644     }
1645     qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL;
1646
1647     /* and finally search for integer */
1648     ret = xmlSecQName2BitMaskGetBitMask(info, qnameHref, qnameLocalPart, mask);
1649     if(ret < 0) {
1650         xmlSecError(XMLSEC_ERRORS_HERE,
1651                     NULL,
1652                     "xmlSecQName2BitMaskGetBitMask",
1653                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1654                     "node=%s,qnameLocalPart=%s,qnameHref=%s",
1655                     xmlSecErrorsSafeString(node->name),
1656                     xmlSecErrorsSafeString(qnameLocalPart),
1657                     xmlSecErrorsSafeString(qnameHref));
1658         if(qnamePrefix != NULL) {
1659             xmlFree(qnamePrefix);
1660         }
1661         return(-1);     
1662     }
1663
1664     if(qnamePrefix != NULL) {
1665         xmlFree(qnamePrefix);
1666     }
1667     return(0);
1668 }
1669
1670
1671 /** 
1672  * xmlSecQName2BitMaskGetStringFromBitMask:
1673  * @info:               the qname<->integer mapping information.
1674  * @node:               the pointer to node.
1675  * @mask:               the mask.
1676  * 
1677  * Creates qname string for @mask in context of given @node. Caller
1678  * is responsible for freeing returned string with @xmlFree.
1679  * 
1680  * Returns: pointer to newly allocated string on success or NULL if an error occurs,
1681  */
1682 xmlChar* 
1683 xmlSecQName2BitMaskGetStringFromBitMask(xmlSecQName2BitMaskInfoConstPtr info,
1684                                         xmlNodePtr node, xmlSecBitMask mask) {
1685     xmlSecQName2BitMaskInfoConstPtr qnameInfo;
1686
1687     xmlSecAssert2(info != NULL, NULL);
1688     xmlSecAssert2(node != NULL, NULL);
1689
1690     qnameInfo = xmlSecQName2BitMaskGetInfo(info, mask);
1691     if(qnameInfo == NULL) {
1692         xmlSecError(XMLSEC_ERRORS_HERE,
1693                     NULL,
1694                     "xmlSecQName2BitMaskGetInfo",
1695                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
1696                     "node=%s,mask=%d",
1697                     xmlSecErrorsSafeString(node->name),
1698                     mask);
1699         return(NULL);
1700     }
1701     
1702     return(xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart));
1703 }
1704
1705 /** 
1706  * xmlSecQName2BitMaskNodesRead:
1707  * @info:               the qname<->bit mask mapping information.
1708  * @node:               the start.
1709  * @nodeName:           the mask nodes name.
1710  * @nodeNs:             the mask nodes namespace.
1711  * @stopOnUnknown:      if this flag is set then function exits if unknown
1712  *                      value was found.
1713  * @mask:               the pointer to result mask.
1714  * 
1715  * Reads <@nodeNs:@nodeName> elements and puts the result bit mask
1716  * into @mask. When function exits, @node points to the first element node
1717  * after all the <@nodeNs:@nodeName> elements.
1718  * 
1719  * Returns: 0 on success or a negative value if an error occurs,
1720  */
1721 int 
1722 xmlSecQName2BitMaskNodesRead(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr* node,
1723                             const xmlChar* nodeName, const xmlChar* nodeNs, 
1724                             int stopOnUnknown, xmlSecBitMask* mask) {
1725     xmlNodePtr cur;
1726     xmlChar* content;
1727     xmlSecBitMask tmp;
1728     int ret;
1729
1730     xmlSecAssert2(info != NULL, -1);
1731     xmlSecAssert2(node != NULL, -1);
1732     xmlSecAssert2(mask != NULL, -1);
1733
1734     (*mask) = 0;
1735     cur = (*node);
1736     while((cur != NULL) && (xmlSecCheckNodeName(cur, nodeName, nodeNs))) {
1737         content = xmlNodeGetContent(cur);
1738         if(content == NULL) {
1739             xmlSecError(XMLSEC_ERRORS_HERE,
1740                         NULL,
1741                         "xmlNodeGetContent",
1742                         XMLSEC_ERRORS_R_XML_FAILED,
1743                         "node=%s",
1744                         xmlSecErrorsSafeString(cur->name));
1745             return(-1); 
1746         }
1747         
1748         ret = xmlSecQName2BitMaskGetBitMaskFromString(info, cur, content, &tmp);
1749         if(ret < 0) {
1750             xmlSecError(XMLSEC_ERRORS_HERE,
1751                         NULL,
1752                         "xmlSecQName2BitMaskGetBitMaskFromString",
1753                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
1754                         "value=%s",
1755                         xmlSecErrorsSafeString(content));
1756             xmlFree(content);
1757             return(-1); 
1758         }
1759         xmlFree(content);
1760
1761         if((stopOnUnknown != 0) && (tmp == 0)) {
1762             /* todo: better error */
1763             xmlSecError(XMLSEC_ERRORS_HERE,
1764                         NULL,
1765                         "xmlSecQName2BitMaskGetBitMaskFromString",
1766                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
1767                         "value=%s",
1768                         xmlSecErrorsSafeString(content));
1769             return(-1); 
1770         }
1771         
1772         (*mask) |= tmp;
1773         cur = xmlSecGetNextElementNode(cur->next);
1774     }
1775
1776     (*node) = cur;    
1777     return(0); 
1778 }
1779
1780 /** 
1781  * xmlSecQName2BitMaskNodesWrite:
1782  * @info:               the qname<->bit mask mapping information.
1783  * @node:               the parent element for mask nodes.
1784  * @nodeName:           the mask nodes name.
1785  * @nodeNs:             the mask nodes namespace.
1786  * @mask:               the bit mask.
1787  * 
1788  * Writes <@nodeNs:@nodeName> elemnts with values from @mask to @node.
1789  * 
1790  * Returns: 0 on success or a negative value if an error occurs,
1791  */
1792 int 
1793 xmlSecQName2BitMaskNodesWrite(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr node,
1794                             const xmlChar* nodeName, const xmlChar* nodeNs, 
1795                             xmlSecBitMask mask) {
1796     unsigned int ii;
1797
1798     xmlSecAssert2(info != NULL, -1);
1799     xmlSecAssert2(node != NULL, -1);
1800     xmlSecAssert2(nodeName != NULL, -1);
1801
1802     for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
1803         xmlSecAssert2(info[ii].mask != 0, -1);
1804
1805         if((mask & info[ii].mask) != 0) {
1806             xmlNodePtr cur;
1807             xmlChar* qname;
1808             
1809             qname = xmlSecGetQName(node, info[ii].qnameHref, info[ii].qnameLocalPart);
1810             if(qname == NULL) {
1811                 xmlSecError(XMLSEC_ERRORS_HERE,
1812                             NULL,
1813                             "xmlSecGetQName",
1814                             XMLSEC_ERRORS_R_XML_FAILED,
1815                             "node=%s",
1816                             xmlSecErrorsSafeString(nodeName));
1817                 return(-1);     
1818             }
1819             
1820             cur = xmlSecAddChild(node, nodeName, nodeNs);
1821             if(cur == NULL) {
1822                 xmlSecError(XMLSEC_ERRORS_HERE,
1823                             NULL,
1824                             "xmlSecAddChild",
1825                             XMLSEC_ERRORS_R_XML_FAILED,
1826                             "node=%s",
1827                             xmlSecErrorsSafeString(nodeName));
1828                 xmlFree(qname);
1829                 return(-1);
1830             }
1831             
1832             xmlNodeSetContent(cur, qname);
1833             xmlFree(qname);
1834         }
1835     }
1836     return(0);
1837 }
1838
1839 /** 
1840  * xmlSecQName2BitMaskDebugDump:
1841  * @info:               the qname<->bit mask mapping information.
1842  * @mask:               the bit mask.
1843  * @name:               the value name to print.
1844  * @output:             the pointer to output FILE.
1845  * 
1846  * Prints debug information about @mask to @output.
1847  */
1848 void 
1849 xmlSecQName2BitMaskDebugDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask,
1850                             const xmlChar* name, FILE* output) {
1851     unsigned int ii;
1852
1853     xmlSecAssert(info != NULL);
1854     xmlSecAssert(name != NULL);
1855     xmlSecAssert(output != NULL);
1856
1857     if(mask == 0) {
1858         return;
1859     }
1860
1861     fprintf(output, "== %s (0x%08x): ", name, mask);
1862     for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
1863         xmlSecAssert(info[ii].mask != 0);
1864
1865         if((mask & info[ii].mask) != 0) {
1866             fprintf(output, "name=\"%s\" (href=\"%s\"),", info[ii].qnameLocalPart, info[ii].qnameHref);
1867         }
1868     }
1869     fprintf(output, "\n");
1870 }
1871
1872 /** 
1873  * xmlSecQName2BitMaskDebugXmlDump:
1874  * @info:               the qname<->bit mask mapping information.
1875  * @mask:               the bit mask.
1876  * @name:               the value name to print.
1877  * @output:             the pointer to output FILE.
1878  * 
1879  * Prints debug information about @mask to @output in XML format.
1880  */
1881 void 
1882 xmlSecQName2BitMaskDebugXmlDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask,
1883                             const xmlChar* name, FILE* output) {
1884     unsigned int ii;
1885
1886     xmlSecAssert(info != NULL);
1887     xmlSecAssert(name != NULL);
1888     xmlSecAssert(output != NULL);
1889
1890     if(mask == 0) {
1891         return;
1892     }
1893
1894     fprintf(output, "<%sList>\n", name);
1895     for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) {
1896         xmlSecAssert(info[ii].mask != 0);
1897
1898         if((mask & info[ii].mask) != 0) {
1899             fprintf(output, "<%s href=\"%s\">%s</%s>\n", name, 
1900                     info[ii].qnameHref, info[ii].qnameLocalPart, name);
1901         }
1902     }
1903     fprintf(output, "</%sList>\n", name);
1904 }
1905                                                                  
1906
1907
1908