2 * jabberd - Jabber Open Source Server
3 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4 * Ryan Eatmon, Robert Norris
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
22 /** ! ! ! Patched version to fix segfault issue for jabberd-2.0s4 ! ! ! */
25 * !!! Things to do (after 2.0)
27 * - make nad_find_scoped_namespace() take an element index, and only search
28 * the scope on that element (currently, it searchs all elements from
29 * end to start, which isn't really correct, though it works in most cases
32 * * insert one nad (or part thereof) into another nad
33 * * clear a part of a nad (like xmlnode_hide)
35 * - audit use of depth array and parent (see j2 bug #792)
41 #include "expat/expat.h"
44 /* define NAD_DEBUG to get pointer tracking - great for weird bugs that you can't reproduce */
47 static xht _nad_alloc_tracked = NULL;
48 static xht _nad_free_tracked = NULL;
50 static void _nad_ptr_check(const char *func, nad_t nad) {
52 snprintf(loc, sizeof(loc), "%x", (int) nad);
54 if(xhash_get(_nad_alloc_tracked, loc) == NULL) {
55 fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad);
59 if(xhash_get(_nad_free_tracked, loc) != NULL) {
60 fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad);
64 fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad);
67 #define _nad_ptr_check(func,nad)
70 #define BLOCKSIZE 1024
72 /** internal: do and return the math and ensure it gets realloc'd */
73 int _nad_realloc(void **oblocks, int len)
78 /* round up to standard block sizes */
79 nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
81 /* keep trying till we get it */
82 while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1);
87 /** this is the safety check used to make sure there's always enough mem */
88 #define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size));
90 /** internal: append some cdata and return the index to it */
91 int _nad_cdata(nad_t nad, const char *cdata, int len)
93 NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
95 memcpy(nad->cdata + nad->ccur, cdata, len);
97 return nad->ccur - len;
100 /** internal: create a new attr on any given elem */
101 int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
105 /* make sure there's mem for us */
106 NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen);
110 nad->attrs[attr].next = nad->elems[elem].attr;
111 nad->elems[elem].attr = attr;
112 nad->attrs[attr].lname = strlen(name);
113 nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname);
115 nad->attrs[attr].lval = vallen;
117 nad->attrs[attr].lval = strlen(val);
118 nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
119 nad->attrs[attr].my_ns = ns;
124 /** create a new cache, simple pointer to a list of nads */
125 nad_cache_t nad_cache_new(void)
128 while((cache = malloc(sizeof(nad_cache_t))) == NULL) sleep(1);
132 if(_nad_alloc_tracked == NULL) _nad_alloc_tracked = xhash_new(501);
133 if(_nad_free_tracked == NULL) _nad_free_tracked = xhash_new(501);
140 /** free the cache and any nads in it */
141 void nad_cache_free(nad_cache_t cache)
144 while((cur = *cache) != NULL)
157 /** get the next nad from the cache, or create some */
158 nad_t nad_new(nad_cache_t cache)
163 /* If cache==NULL, then this NAD is not in a cache */
165 if ((cache!=NULL) && (*cache != NULL))
169 nad->ccur = nad->ecur = nad->acur = nad->ncur = 0;
177 while((nad = malloc(sizeof(struct nad_st))) == NULL) sleep(1);
178 memset(nad,0,sizeof(struct nad_st));
186 snprintf(loc, sizeof(loc), "%x", (int) nad);
187 xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1);
189 _nad_ptr_check(__func__, nad);
195 nad_t nad_copy(nad_t nad)
199 _nad_ptr_check(__func__, nad);
201 if(nad == NULL) return NULL;
203 /* create a new nad not participating in a cache */
204 copy = nad_new(NULL);
206 /* if it's not large enough, make bigger */
207 NAD_SAFE(copy->elems, nad->elen, copy->elen);
208 NAD_SAFE(copy->attrs, nad->alen, copy->alen);
209 NAD_SAFE(copy->nss, nad->nlen, copy->nlen);
210 NAD_SAFE(copy->cdata, nad->clen, copy->clen);
213 memcpy(copy->elems, nad->elems, nad->elen);
214 memcpy(copy->attrs, nad->attrs, nad->alen);
215 memcpy(copy->nss, nad->nss, nad->nlen);
216 memcpy(copy->cdata, nad->cdata, nad->clen);
219 copy->ecur = nad->ecur;
220 copy->acur = nad->acur;
221 copy->ncur = nad->ncur;
222 copy->ccur = nad->ccur;
224 copy->scope = nad->scope;
229 /** free nad, or plug nad back in the cache */
230 void nad_free(nad_t nad)
232 if(nad == NULL) return;
235 _nad_ptr_check(__func__, nad);
238 snprintf(loc, sizeof(loc), "%x", (int) nad);
239 xhash_zap(_nad_alloc_tracked, loc);
240 xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad);
243 /* If nad->cache != NULL, then put back into cache, otherwise this nad is not in a cache */
245 if (nad->cache != NULL) {
246 nad->next = *(nad->cache);
260 /** locate the next elem at a given depth with an optional matching name */
261 int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth)
266 _nad_ptr_check(__func__, nad);
268 /* make sure there are valid args */
269 if(elem >= nad->ecur || name == NULL) return -1;
271 /* set up args for searching */
272 depth = nad->elems[elem].depth + depth;
273 if(name != NULL) lname = strlen(name);
276 for(elem++;elem < nad->ecur;elem++)
278 /* if we hit one with a depth less than ours, then we don't have the
279 * same parent anymore, bail */
280 if(nad->elems[elem].depth < depth)
283 if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) &&
284 (ns < 0 || ((my_ns = nad->elems[elem].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0)))
291 /** get a matching attr on this elem, both name and optional val */
292 int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
297 _nad_ptr_check(__func__, nad);
299 /* make sure there are valid args */
300 if(elem >= nad->ecur || name == NULL) return -1;
302 attr = nad->elems[elem].attr;
303 lname = strlen(name);
304 if(val != NULL) lval = strlen(val);
308 /* hefty, match name and if a val, also match that */
309 if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 &&
310 (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) &&
311 (ns < 0 || ((my_ns = nad->attrs[attr].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0)))
313 attr = nad->attrs[attr].next;
318 /** get a matching ns on this elem, both uri and optional prefix */
319 int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix)
323 _nad_ptr_check(__func__, nad);
328 /* work backwards through our parents, looking for our namespace on each one.
329 * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */
333 ns = nad->elems[check].ns;
336 if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
338 ns = nad->nss[ns].next;
340 check = nad->elems[check].parent;
346 /** find a namespace in scope */
347 int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
351 _nad_ptr_check(__func__, nad);
356 for(ns = 0; ns < nad->ncur; ns++)
358 if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 &&
360 (nad->nss[ns].iprefix >= 0 &&
361 strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
368 /** create, update, or zap any matching attr on this elem */
369 void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
373 _nad_ptr_check(__func__, nad);
375 /* find one to replace first */
376 if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0)
378 /* only create new if there's a value to store */
380 _nad_attr(nad, elem, ns, name, val, vallen);
384 /* got matching, update value or zap */
387 nad->attrs[attr].lval = nad->attrs[attr].lname = 0;
390 nad->attrs[attr].lval = vallen;
392 nad->attrs[attr].lval = strlen(val);
393 nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
398 /** shove in a new child elem after the given one */
399 int nad_insert_elem(nad_t nad, int parent, int ns, const char *name, const char *cdata)
401 int elem = parent + 1;
403 _nad_ptr_check(__func__, nad);
405 NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
407 /* relocate all the rest of the elems (unless we're at the end already) */
408 if(nad->ecur != elem)
409 memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
412 /* set up req'd parts of new elem */
413 nad->elems[elem].parent = parent;
414 nad->elems[elem].lname = strlen(name);
415 nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
416 nad->elems[elem].attr = -1;
417 nad->elems[elem].ns = nad->scope; nad->scope = -1;
418 nad->elems[elem].itail = nad->elems[elem].ltail = 0;
419 nad->elems[elem].my_ns = ns;
421 /* add cdata if given */
424 nad->elems[elem].lcdata = strlen(cdata);
425 nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata);
427 nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
431 nad->elems[elem].depth = nad->elems[parent].depth + 1;
436 /** wrap an element with another element */
437 void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name)
441 _nad_ptr_check(__func__, nad);
443 if(elem >= nad->ecur) return;
445 NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
447 /* relocate all the rest of the elems after us */
448 memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
451 /* set up req'd parts of new elem */
452 nad->elems[elem].lname = strlen(name);
453 nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
454 nad->elems[elem].attr = -1;
455 nad->elems[elem].ns = nad->scope; nad->scope = -1;
456 nad->elems[elem].itail = nad->elems[elem].ltail = 0;
457 nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
458 nad->elems[elem].my_ns = ns;
460 /* raise the bar on all the children */
461 nad->elems[elem+1].depth++;
462 for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++;
464 /* relink the parents */
465 nad->elems[elem].parent = nad->elems[elem + 1].parent;
466 nad->elems[elem + 1].parent = elem;
469 /** create a new elem on the list */
470 int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
474 _nad_ptr_check(__func__, nad);
476 /* make sure there's mem for us */
477 NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
481 nad->elems[elem].lname = strlen(name);
482 nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
483 nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
484 nad->elems[elem].itail = nad->elems[elem].ltail = 0;
485 nad->elems[elem].attr = -1;
486 nad->elems[elem].ns = nad->scope; nad->scope = -1;
487 nad->elems[elem].depth = depth;
488 nad->elems[elem].my_ns = ns;
490 /* make sure there's mem in the depth array, then track us */
491 NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen);
492 nad->depths[depth] = elem;
494 /* our parent is the previous guy in the depth array */
496 nad->elems[elem].parent = -1;
498 nad->elems[elem].parent = nad->depths[depth - 1];
503 /** attach new attr to the last elem */
504 int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
506 _nad_ptr_check(__func__, nad);
508 return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0);
511 /** append new cdata to the last elem */
512 void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
514 int elem = nad->ecur - 1;
516 _nad_ptr_check(__func__, nad);
518 /* make sure this cdata is the child of the last elem to append */
519 if(nad->elems[elem].depth == depth - 1)
521 if(nad->elems[elem].icdata == 0)
522 nad->elems[elem].icdata = nad->ccur;
523 _nad_cdata(nad,cdata,len);
524 nad->elems[elem].lcdata += len;
528 /* otherwise, pin the cdata on the tail of the last element at this depth */
529 elem = nad->depths[depth];
530 if(nad->elems[elem].itail == 0)
531 nad->elems[elem].itail = nad->ccur;
532 _nad_cdata(nad,cdata,len);
533 nad->elems[elem].ltail += len;
536 /** bring a new namespace into scope */
537 int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
541 _nad_ptr_check(__func__, nad);
543 /* only add it if its not already in scope */
544 ns = nad_find_scoped_namespace(nad, uri, NULL);
548 /* make sure there's mem for us */
549 NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
553 nad->nss[ns].next = nad->scope;
556 nad->nss[ns].luri = strlen(uri);
557 nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
560 nad->nss[ns].lprefix = strlen(prefix);
561 nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
564 nad->nss[ns].iprefix = -1;
569 /** declare a namespace on an already-existing element */
570 int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix) {
573 _nad_ptr_check(__func__, nad);
575 /* see if its already scoped on this element */
576 ns = nad_find_namespace(nad, elem, uri, NULL);
581 NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
585 nad->nss[ns].next = nad->elems[elem].ns;
586 nad->elems[elem].ns = ns;
588 nad->nss[ns].luri = strlen(uri);
589 nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
592 nad->nss[ns].lprefix = strlen(prefix);
593 nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
596 nad->nss[ns].iprefix = -1;
601 void _nad_escape(nad_t nad, int data, int len, int flag)
608 /* first, if told, find and escape ' */
609 while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
614 /* cute, eh? handle other data before this normally */
615 _nad_escape(nad, data, ic - data, 2);
617 /* ensure enough space, and add our escaped ' */
618 NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
619 memcpy(nad->cdata + nad->ccur, "'", 6);
622 /* just update and loop for more */
623 len -= (ic+1) - data;
627 /* next look for < */
628 while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
631 _nad_escape(nad, data, ic - data, 1);
633 /* ensure enough space, and add our escaped < */
634 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
635 memcpy(nad->cdata + nad->ccur, "<", 4);
638 /* just update and loop for more */
639 len -= (ic+1) - data;
643 /* check for ]]>, we need to escape the > */
644 /* WE DID THIS (add the '0' as the first test to the while loop
645 because the loops dies 3 lines in... (and we don't reall
648 while( 0 && flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
652 _nad_escape(nad, data, ic - data, 0);
654 /* check for the sequence */
656 if( c >= nad->cdata + 2 && c[-1] == ']' && c[-2] == ']')
658 /* ensure enough space, and add our escaped > */
659 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
660 memcpy(nad->cdata + nad->ccur, ">", 4);
664 /* otherwise, just plug the > in as-is */
667 NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
668 *(nad->cdata + nad->ccur) = '>';
672 /* just update and loop for more */
673 len -= (ic+1) - data;
677 /* if & is found, escape it */
678 while((c = memchr(nad->cdata + data,'&',len)) != NULL)
682 /* ensure enough space */
683 NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);
685 /* handle normal data */
686 memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
687 nad->ccur += (ic - data);
689 /* append escaped < */
690 memcpy(nad->cdata + nad->ccur, "&", 5);
693 /* just update and loop for more */
694 len -= (ic+1) - data;
698 /* nothing exciting, just append normal cdata */
699 NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
700 memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
704 /** internal recursive printing function */
705 int _nad_lp0(nad_t nad, int elem)
711 /* there's a lot of code in here, but don't let that scare you, it's just duplication in order to be a bit more efficient cpu-wise */
713 /* this whole thing is in a big loop for processing siblings */
714 while(elem != nad->ecur)
717 /* make enough space for the opening element */
718 ns = nad->elems[elem].my_ns;
719 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
721 NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen);
723 NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen);
727 *(nad->cdata + nad->ccur++) = '<';
729 /* add the prefix if necessary */
730 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
732 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
733 nad->ccur += nad->nss[ns].lprefix;
734 *(nad->cdata + nad->ccur++) = ':';
737 /* copy in the name */
738 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
739 nad->ccur += nad->elems[elem].lname;
741 /* add the namespaces */
742 for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next)
744 /* never explicitly declare the implicit xml namespace */
745 if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0)
749 if(nad->nss[ns].iprefix >= 0)
751 NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
753 NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
757 memcpy(nad->cdata + nad->ccur, " xmlns", 6);
760 /* prefix if necessary */
761 if(nad->nss[ns].iprefix >= 0)
763 *(nad->cdata + nad->ccur++) = ':';
764 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
765 nad->ccur += nad->nss[ns].lprefix;
768 *(nad->cdata + nad->ccur++) = '=';
769 *(nad->cdata + nad->ccur++) = '\'';
772 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
773 nad->ccur += nad->nss[ns].luri;
775 *(nad->cdata + nad->ccur++) = '\'';
778 for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next)
780 if(nad->attrs[attr].lname <= 0) continue;
782 /* make enough space for the wrapper part */
783 ns = nad->attrs[attr].my_ns;
784 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
786 NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen);
788 NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen);
791 *(nad->cdata + nad->ccur++) = ' ';
793 /* add the prefix if necessary */
794 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
796 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
797 nad->ccur += nad->nss[ns].lprefix;
798 *(nad->cdata + nad->ccur++) = ':';
801 /* copy in the name parts */
802 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname);
803 nad->ccur += nad->attrs[attr].lname;
804 *(nad->cdata + nad->ccur++) = '=';
805 *(nad->cdata + nad->ccur++) = '\'';
807 /* copy in the escaped value */
808 _nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 3);
810 /* make enough space for the closing quote and add it */
811 NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
812 *(nad->cdata + nad->ccur++) = '\'';
815 /* figure out what's next */
816 if(elem+1 == nad->ecur)
819 ndepth = nad->elems[elem+1].depth;
821 /* handle based on if there are children, update nelem after done */
822 if(ndepth <= nad->elems[elem].depth)
824 /* make sure there's enough for what we could need */
825 NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen);
826 if(nad->elems[elem].lcdata == 0)
828 memcpy(nad->cdata + nad->ccur, "/>", 2);
831 *(nad->cdata + nad->ccur++) = '>';
833 /* copy in escaped cdata */
834 _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,2);
837 ns = nad->elems[elem].my_ns;
838 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
840 NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
842 NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
846 memcpy(nad->cdata + nad->ccur, "</", 2);
849 /* add the prefix if necessary */
850 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
852 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
853 nad->ccur += nad->nss[ns].lprefix;
854 *(nad->cdata + nad->ccur++) = ':';
857 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
858 nad->ccur += nad->elems[elem].lname;
859 *(nad->cdata + nad->ccur++) = '>';
862 /* always try to append the tail */
863 _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,2);
865 /* if no siblings either, bail */
866 if(ndepth < nad->elems[elem].depth)
873 /* process any children */
875 /* close ourself and append any cdata first */
876 NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
877 *(nad->cdata + nad->ccur++) = '>';
878 _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,2);
880 /* process children */
881 nelem = _nad_lp0(nad,elem+1);
883 /* close and tail up */
884 ns = nad->elems[elem].my_ns;
885 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
887 NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
889 NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
891 memcpy(nad->cdata + nad->ccur, "</", 2);
893 if(ns >= 0 && nad->nss[ns].iprefix >= 0)
895 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
896 nad->ccur += nad->nss[ns].lprefix;
897 *(nad->cdata + nad->ccur++) = ':';
899 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
900 nad->ccur += nad->elems[elem].lname;
901 *(nad->cdata + nad->ccur++) = '>';
902 _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,2);
904 /* if the next element is not our sibling, we're done */
905 if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth)
908 /* for next sibling in while loop */
912 /* here's the end of that big while loop */
918 void nad_print(nad_t nad, int elem, char **xml, int *len)
920 int ixml = nad->ccur;
922 _nad_ptr_check(__func__, nad);
925 *len = nad->ccur - ixml;
926 *xml = nad->cdata + ixml;
930 * nads serialize to a buffer of this form:
932 * [buflen][ecur][acur][ncur][ccur][elems][attrs][nss][cdata]
934 * nothing is done with endianness or word length, so the nad must be
935 * serialized and deserialized on the same platform
937 * buflen is not actually used by deserialize(), but is provided as a
938 * convenience to the application so it knows how many bytes to read before
939 * passing them in to deserialize()
941 * the depths array is not stored, so after deserialization
942 * nad_append_elem() and nad_append_cdata() will not work. this is rarely
946 void nad_serialize(nad_t nad, char **buf, int *len) {
949 _nad_ptr_check(__func__, nad);
951 *len = sizeof(int) * 5 + /* 4 ints in nad_t, plus one for len */
952 sizeof(struct nad_elem_st) * nad->ecur +
953 sizeof(struct nad_attr_st) * nad->acur +
954 sizeof(struct nad_ns_st) * nad->ncur +
955 sizeof(char) * nad->ccur;
957 *buf = (char *) malloc(*len);
960 * (int *) pos = *len; pos += sizeof(int);
961 * (int *) pos = nad->ecur; pos += sizeof(int);
962 * (int *) pos = nad->acur; pos += sizeof(int);
963 * (int *) pos = nad->ncur; pos += sizeof(int);
964 * (int *) pos = nad->ccur; pos += sizeof(int);
966 memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur;
967 memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur;
968 memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur;
969 memcpy(pos, nad->cdata, sizeof(char) * nad->ccur);
972 nad_t nad_deserialize(nad_cache_t cache, const char *buf) {
973 nad_t nad = nad_new(cache);
974 const char *pos = buf + sizeof(int); /* skip len */
976 _nad_ptr_check(__func__, nad);
978 nad->ecur = * (int *) pos; pos += sizeof(int);
979 nad->acur = * (int *) pos; pos += sizeof(int);
980 nad->ncur = * (int *) pos; pos += sizeof(int);
981 nad->ccur = * (int *) pos; pos += sizeof(int);
982 nad->elen = nad->ecur;
983 nad->alen = nad->acur;
984 nad->nlen = nad->ncur;
985 nad->clen = nad->ccur;
989 nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur);
990 memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur);
991 pos += sizeof(struct nad_elem_st) * nad->ecur;
996 nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur);
997 memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur);
998 pos += sizeof(struct nad_attr_st) * nad->acur;
1003 nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur);
1004 memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur);
1005 pos += sizeof(struct nad_ns_st) * nad->ncur;
1010 nad->cdata = (char *) malloc(sizeof(char) * nad->ccur);
1011 memcpy(nad->cdata, pos, sizeof(char) * nad->ccur);
1019 /** parse a buffer into a nad */
1026 static void _nad_parse_element_start(void *arg, const char *name, const char **atts) {
1027 struct build_data *bd = (struct build_data *) arg;
1029 char *uri, *elem, *prefix;
1034 strncpy(buf, name, 1024);
1038 prefixed namespaced elem: uri|elem|prefix
1039 default namespaced elem: uri|elem
1040 un-namespaced elem: elem
1043 /* extract all the bits */
1045 elem = strchr(uri, '|');
1049 prefix = strchr(elem, '|');
1050 if(prefix != NULL) {
1054 ns = nad_add_namespace(bd->nad, uri, prefix);
1056 /* un-namespaced, just take it as-is */
1064 nad_append_elem(bd->nad, ns, elem, bd->depth);
1066 /* now the attributes, one at a time */
1068 while(attr[0] != NULL) {
1071 strncpy(buf, attr[0], 1024);
1074 /* extract all the bits */
1076 elem = strchr(uri, '|');
1080 prefix = strchr(elem, '|');
1081 if(prefix != NULL) {
1085 ns = nad_add_namespace(bd->nad, uri, prefix);
1087 /* un-namespaced, just take it as-is */
1095 nad_append_attr(bd->nad, ns, elem, (char *) attr[1]);
1103 static void _nad_parse_element_end(void *arg, const char *name) {
1104 struct build_data *bd = (struct build_data *) arg;
1109 static void _nad_parse_cdata(void *arg, const char *str, int len) {
1110 struct build_data *bd = (struct build_data *) arg;
1113 nad_append_cdata(bd->nad, (char *) str, len, bd->depth);
1116 static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri) {
1117 struct build_data *bd = (struct build_data *) arg;
1119 nad_add_namespace(bd->nad, (char *) uri, (char *) prefix);
1122 nad_t nad_parse(nad_cache_t cache, const char *buf, int len) {
1123 struct build_data bd;
1129 p = XML_ParserCreateNS(NULL, '|');
1133 bd.nad = nad_new(cache);
1136 XML_SetUserData(p, (void *) &bd);
1137 XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
1138 XML_SetCharacterDataHandler(p, _nad_parse_cdata);
1139 XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);
1141 if(!XML_Parse(p, buf, len, 1)) {