1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  *                    Ryan Eatmon, Robert Norris
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 /**
22  * !!! Things to do (after 2.0)
23  *
24  * - make nad_find_scoped_namespace() take an element index, and only search
25  *   the scope on that element (currently, it searchs all elements from
26  *   end to start, which isn't really correct, though it works in most cases
27  *
28  * - new functions:
29  *     * insert one nad (or part thereof) into another nad
30  *     * clear a part of a nad (like xmlnode_hide)
31  *
32  * - audit use of depth array and parent (see j2 bug #792)
33  */
34 
35 #include "nad.h"
36 #include "util.h"
37 
38 /* define NAD_DEBUG to get pointer tracking - great for weird bugs that you can't reproduce */
39 #ifdef NAD_DEBUG
40 
41 static xht _nad_alloc_tracked = NULL;
42 static xht _nad_free_tracked = NULL;
43 
_nad_ptr_check(const char * func,nad_t nad)44 static void _nad_ptr_check(const char *func, nad_t nad) {
45     char loc[24];
46     snprintf(loc, sizeof(loc), "%x", (int) nad);
47 
48     if(xhash_get(_nad_alloc_tracked, loc) == NULL) {
49         fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad);
50         abort();
51     }
52 
53     if(xhash_get(_nad_free_tracked, loc) != NULL) {
54         fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad);
55         abort();
56     }
57 
58     fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad);
59 }
60 #else
61 #define _nad_ptr_check(func,nad)
62 #endif
63 
64 #define BLOCKSIZE 128
65 
66 /**
67  * Reallocate the given buffer to make it larger.
68  *
69  * @param oblocks A pointer to a buffer that will be made larger.
70  * @param len     The minimum size in bytes to make the buffer.  The
71  *                actual size of the buffer will be rounded up to the
72  *                nearest block of 1024 bytes.
73  *
74  * @return The new size of the buffer in bytes.
75  */
_nad_realloc(void ** oblocks,int len)76 static int _nad_realloc(void **oblocks, int len)
77 {
78     int nlen;
79 
80     /* round up to standard block sizes */
81     nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
82 
83     /* keep trying till we get it */
84     *oblocks = realloc(*oblocks, nlen);
85     return nlen;
86 }
87 
88 /** this is the safety check used to make sure there's always enough mem */
89 #define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size));
90 
91 /** internal: append some cdata and return the index to it */
_nad_cdata(nad_t nad,const char * cdata,int len)92 static int _nad_cdata(nad_t nad, const char *cdata, int len)
93 {
94     NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
95 
96     memcpy(nad->cdata + nad->ccur, cdata, len);
97     nad->ccur += len;
98     return nad->ccur - len;
99 }
100 
101 /** internal: create a new attr on any given elem */
_nad_attr(nad_t nad,int elem,int ns,const char * name,const char * val,int vallen)102 static int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
103 {
104     int attr;
105 
106     /* make sure there's mem for us */
107     NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen);
108 
109     attr = nad->acur;
110     nad->acur++;
111     nad->attrs[attr].next = nad->elems[elem].attr;
112     nad->elems[elem].attr = attr;
113     nad->attrs[attr].lname = strlen(name);
114     nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname);
115     if(vallen > 0)
116         nad->attrs[attr].lval = vallen;
117     else
118         nad->attrs[attr].lval = strlen(val);
119     nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
120     nad->attrs[attr].my_ns = ns;
121 
122     return attr;
123 }
124 
nad_new(void)125 nad_t nad_new(void)
126 {
127     nad_t nad;
128 
129     nad = calloc(1, sizeof(struct nad_st));
130 
131     nad->scope = -1;
132 
133 #ifdef NAD_DEBUG
134     if(_nad_alloc_tracked == NULL) _nad_alloc_tracked = xhash_new(501);
135     if(_nad_free_tracked == NULL) _nad_free_tracked = xhash_new(501);
136     {
137     char loc[24];
138     snprintf(loc, sizeof(loc), "%x", (int) nad);
139     xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1);
140     }
141     _nad_ptr_check(__func__, nad);
142 #endif
143 
144     return nad;
145 }
146 
nad_copy(nad_t nad)147 nad_t nad_copy(nad_t nad)
148 {
149     nad_t copy;
150 
151     _nad_ptr_check(__func__, nad);
152 
153     if(nad == NULL) return NULL;
154 
155     copy = nad_new();
156 
157     /* if it's not large enough, make bigger */
158     NAD_SAFE(copy->elems, nad->elen, copy->elen);
159     NAD_SAFE(copy->attrs, nad->alen, copy->alen);
160     NAD_SAFE(copy->nss, nad->nlen, copy->nlen);
161     NAD_SAFE(copy->cdata, nad->clen, copy->clen);
162 
163     /* copy all data */
164     memcpy(copy->elems, nad->elems, nad->elen);
165     memcpy(copy->attrs, nad->attrs, nad->alen);
166     memcpy(copy->nss, nad->nss, nad->nlen);
167     memcpy(copy->cdata, nad->cdata, nad->clen);
168 
169     /* sync data */
170     copy->ecur = nad->ecur;
171     copy->acur = nad->acur;
172     copy->ncur = nad->ncur;
173     copy->ccur = nad->ccur;
174 
175     copy->scope = nad->scope;
176 
177     return copy;
178 }
179 
nad_free(nad_t nad)180 void nad_free(nad_t nad)
181 {
182     if(nad == NULL) return;
183 
184 #ifdef NAD_DEBUG
185     _nad_ptr_check(__func__, nad);
186     {
187     char loc[24];
188     snprintf(loc, sizeof(loc), "%x", (int) nad);
189     xhash_zap(_nad_alloc_tracked, loc);
190     xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad);
191     }
192 #endif
193 
194     /* Free nad */
195     free(nad->elems);
196     free(nad->attrs);
197     free(nad->cdata);
198     free(nad->nss);
199     free(nad->depths);
200 #ifndef NAD_DEBUG
201     free(nad);
202 #endif
203 }
204 
205 /** locate the next elem at a given depth with an optional matching name */
nad_find_elem(nad_t nad,unsigned int elem,int ns,const char * name,int depth)206 int nad_find_elem(nad_t nad, unsigned int elem, int ns, const char *name, int depth)
207 {
208     int my_ns;
209     int lname = 0;
210 
211     _nad_ptr_check(__func__, nad);
212 
213     /* make sure there are valid args */
214     if(elem >= nad->ecur) return -1;
215 
216     /* set up args for searching */
217     depth = nad->elems[elem].depth + depth;
218     if(name != NULL) lname = strlen(name);
219 
220     /* search */
221     for(elem++;elem < nad->ecur;elem++)
222     {
223         /* if we hit one with a depth less than ours, then we don't have the
224          * same parent anymore, bail */
225         if(nad->elems[elem].depth < depth)
226             return -1;
227 
228         if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) &&
229           (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)))
230             return elem;
231     }
232 
233     return -1;
234 }
235 
236 /** get a matching attr on this elem, both name and optional val */
nad_find_attr(nad_t nad,unsigned int elem,int ns,const char * name,const char * val)237 int nad_find_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val)
238 {
239     int attr, my_ns;
240     int lname, lval = 0;
241 
242     _nad_ptr_check(__func__, nad);
243 
244     /* make sure there are valid args */
245     if(elem >= nad->ecur || name == NULL) return -1;
246 
247     attr = nad->elems[elem].attr;
248     lname = strlen(name);
249     if(val != NULL) lval = strlen(val);
250 
251     while(attr >= 0)
252     {
253         /* hefty, match name and if a val, also match that */
254         if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 &&
255           (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) &&
256           (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)))
257             return attr;
258         attr = nad->attrs[attr].next;
259     }
260     return -1;
261 }
262 
263 /** get a matching ns on this elem, both uri and optional prefix */
nad_find_namespace(nad_t nad,unsigned int elem,const char * uri,const char * prefix)264 int nad_find_namespace(nad_t nad, unsigned int elem, const char *uri, const char *prefix)
265 {
266     int check, ns;
267 
268     _nad_ptr_check(__func__, nad);
269 
270     /* make sure there are valid args */
271     if(elem >= nad->ecur || uri == NULL) return -1;
272 
273     /* work backwards through our parents, looking for our namespace on each one.
274      * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */
275     check = elem;
276     while(check >= 0)
277     {
278         ns = nad->elems[check].ns;
279         while(ns >= 0)
280         {
281             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)))
282                 return ns;
283             ns = nad->nss[ns].next;
284         }
285         check = nad->elems[check].parent;
286     }
287 
288     return -1;
289 }
290 
291 /** find a namespace in scope */
nad_find_scoped_namespace(nad_t nad,const char * uri,const char * prefix)292 int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
293 {
294     int ns;
295 
296     _nad_ptr_check(__func__, nad);
297 
298     if(uri == NULL)
299         return -1;
300 
301     for(ns = 0; ns < nad->ncur; ns++)
302     {
303         if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 &&
304            (prefix == NULL ||
305              (nad->nss[ns].iprefix >= 0 &&
306               strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
307             return ns;
308     }
309 
310     return -1;
311 }
312 
313 /** find elem using XPath like query
314  *  name -- "name" for the child tag of that name
315  *          "name/name" for a sub child (recurses)
316  *          "?attrib" to match the first tag with that attrib defined
317  *          "?attrib=value" to match the first tag with that attrib and value
318  *          "!attrib" to match the first tag without that attrib defined
319  *          "!attrib=value" to match the first tag without that attrib and value
320  *          or any combination: "name/name/?attrib", etc
321  */
nad_find_elem_path(nad_t nad,unsigned int elem,int ns,const char * name)322 int nad_find_elem_path(nad_t nad, unsigned int elem, int ns, const char *name) {
323     char *str, *slash, *qmark, *excl, *equals;
324     int el;
325 
326     _nad_ptr_check(__func__, nad);
327 
328     /* make sure there are valid args */
329     if(elem >= nad->ecur || name == NULL) return -1;
330 
331     /* if it's plain name just search children */
332     if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name,"!") == NULL)
333         return nad_find_elem(nad, elem, ns, name, 1);
334 
335     el = elem;
336     str = strdup(name);
337     slash = strstr(str, "/");
338     qmark = strstr(str, "?");
339     excl  = strstr(str, "!");
340     equals = strstr(str, "=");
341 
342     /* no / in element name part */
343     if(qmark != NULL && (slash == NULL || qmark < slash))
344     { /* of type ?attrib */
345 
346         *qmark = '\0';
347         qmark++;
348         if(equals != NULL)
349         {
350             *equals = '\0';
351             equals++;
352         }
353 
354         for(el = nad_find_elem(nad, el, ns, str, 1); ; el = nad_find_elem(nad, el, ns, str, 0)) {
355             if(el < 0) break;
356             if(strcmp(qmark, "xmlns") == 0) {
357                 if(nad_find_namespace(nad, el, equals, NULL) >= 0) break;
358             }
359             else {
360                 if(nad_find_attr(nad, el, ns, qmark, equals) >= 0) break;
361             }
362         }
363 
364         free(str);
365         return el;
366     }
367 
368     if(excl != NULL && (slash == NULL || excl < slash))
369     { /* of type !attrib */
370 
371         *excl = '\0';
372         excl++;
373         if(equals != NULL)
374         {
375             *equals = '\0';
376             equals++;
377         }
378 
379         for(el = nad_find_elem(nad, el, ns, str, 1); ; el = nad_find_elem(nad, el, ns, str, 0)) {
380             if(el < 0) break;
381             if(strcmp(excl, "xmlns") == 0) {
382                 if(nad_find_namespace(nad, el, equals, NULL) < 0) break;
383             }
384             else {
385                 if(nad_find_attr(nad, el, ns, excl, equals) < 0) break;
386             }
387         }
388 
389         free(str);
390         return el;
391     }
392 
393     /* there is a / in element name part - need to recurse */
394     *slash = '\0';
395     ++slash;
396 
397     for(el = nad_find_elem(nad, el, ns, str, 1); ; el = nad_find_elem(nad, el, ns, str, 0)) {
398         if(el < 0) break;
399         if((el = nad_find_elem_path(nad, el, ns, slash)) >= 0) break;
400     }
401 
402     free(str);
403     return el;
404 }
405 
406 /** create, update, or zap any matching attr on this elem */
nad_set_attr(nad_t nad,unsigned int elem,int ns,const char * name,const char * val,int vallen)407 void nad_set_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val, int vallen)
408 {
409     int attr;
410 
411     _nad_ptr_check(__func__, nad);
412 
413     /* find one to replace first */
414     if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0)
415     {
416         /* only create new if there's a value to store */
417         if(val != NULL)
418             _nad_attr(nad, elem, ns, name, val, vallen);
419         return;
420     }
421 
422     /* got matching, update value or zap */
423     if(val == NULL)
424     {
425         nad->attrs[attr].lval = nad->attrs[attr].lname = 0;
426     }else{
427         if(vallen > 0)
428             nad->attrs[attr].lval = vallen;
429         else
430             nad->attrs[attr].lval = strlen(val);
431         nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
432     }
433 
434 }
435 
436 /** shove in a new child elem after the given one */
nad_insert_elem(nad_t nad,unsigned int parent,int ns,const char * name,const char * cdata)437 int nad_insert_elem(nad_t nad, unsigned int parent, int ns, const char *name, const char *cdata)
438 {
439     int elem;
440 
441     if (parent >= nad->ecur) {
442         if (nad->ecur > 0)
443             parent = nad->ecur -1;
444         else
445             parent = 0;
446     }
447 
448     elem = parent + 1;
449 
450     _nad_ptr_check(__func__, nad);
451 
452     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
453 
454     /* relocate all the rest of the elems (unless we're at the end already) */
455     if(nad->ecur != elem)
456         memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
457     nad->ecur++;
458 
459     /* set up req'd parts of new elem */
460     nad->elems[elem].parent = parent;
461     nad->elems[elem].lname = strlen(name);
462     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
463     nad->elems[elem].attr = -1;
464     nad->elems[elem].ns = nad->scope; nad->scope = -1;
465     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
466     nad->elems[elem].my_ns = ns;
467 
468     /* add cdata if given */
469     if(cdata != NULL)
470     {
471         nad->elems[elem].lcdata = strlen(cdata);
472         nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata);
473     }else{
474         nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
475     }
476 
477     /* parent/child */
478     nad->elems[elem].depth = nad->elems[parent].depth + 1;
479 
480     return elem;
481 }
482 
483 /** remove an element (and its subelements) */
nad_drop_elem(nad_t nad,unsigned int elem)484 void nad_drop_elem(nad_t nad, unsigned int elem) {
485     int next, cur;
486 
487     _nad_ptr_check(__func__, nad);
488 
489     if(elem >= nad->ecur) return;
490 
491     /* find the next elem at this depth to move into the space */
492     next = elem + 1;
493     while(next < nad->ecur && nad->elems[next].depth > nad->elems[elem].depth) next++;
494 
495     /* relocate */
496     if(next < nad->ecur)
497         memmove(&nad->elems[elem], &nad->elems[next], (nad->ecur - next) * sizeof(struct nad_elem_st));
498     nad->ecur -= next - elem;
499 
500     /* relink parents */
501     for(cur = elem; cur < nad->ecur; cur++)
502         if(nad->elems[cur].parent > next)
503             nad->elems[cur].parent -= (next - elem);
504 }
505 
506 /** wrap an element with another element */
nad_wrap_elem(nad_t nad,unsigned int elem,int ns,const char * name)507 void nad_wrap_elem(nad_t nad, unsigned int elem, int ns, const char *name)
508 {
509     int cur;
510 
511     _nad_ptr_check(__func__, nad);
512 
513     if(elem >= nad->ecur) return;
514 
515     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
516 
517     /* relocate all the rest of the elems after us */
518     memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
519     nad->ecur++;
520 
521     /* set up req'd parts of new elem */
522     nad->elems[elem].lname = strlen(name);
523     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
524     nad->elems[elem].attr = -1;
525     nad->elems[elem].ns = nad->scope; nad->scope = -1;
526     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
527     nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
528     nad->elems[elem].my_ns = ns;
529     /* hook up the parent */
530     nad->elems[elem].parent = nad->elems[elem + 1].parent;
531 
532     /* relink parents on moved elements */
533     for(cur = elem + 1; cur < nad->ecur; cur++)
534         if(nad->elems[cur].parent >= elem)
535             nad->elems[cur].parent++;
536 
537     /* raise the bar on all the children */
538     nad->elems[elem+1].depth++;
539     for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++;
540 
541 }
542 
543 /** insert part of a nad into another nad */
nad_insert_nad(nad_t dest,int delem,nad_t src,int selem)544 int nad_insert_nad(nad_t dest, int delem, nad_t src, int selem) {
545     int nelem, first, i, j, ns, nattr, attr;
546     char buri[256], *uri = buri, bprefix[256], *prefix = bprefix;
547 
548     _nad_ptr_check(__func__, dest);
549     _nad_ptr_check(__func__, src);
550 
551     /* can't do anything if these aren't real elems */
552     if(src->ecur <= selem || dest->ecur <= delem)
553         return -1;
554 
555     /* figure out how many elements to copy */
556     nelem = 1;
557     while(selem + nelem < src->ecur && src->elems[selem + nelem].depth > src->elems[selem].depth) nelem++;
558 
559     /* make room */
560     NAD_SAFE(dest->elems, (dest->ecur + nelem) * sizeof(struct nad_elem_st), dest->elen);
561 
562     /* relocate all the elems after us */
563     memmove(&dest->elems[delem + nelem + 1], &dest->elems[delem + 1], (dest->ecur - delem - 1) * sizeof(struct nad_elem_st));
564     dest->ecur += nelem;
565 
566     /* relink parents on moved elements */
567     for(i = delem + nelem; i < dest->ecur; i++)
568         if(dest->elems[i].parent > delem)
569             dest->elems[i].parent += nelem;
570 
571     first = delem + 1;
572 
573     /* copy them in, one at a time */
574     for(i = 0; i < nelem; i++) {
575         /* link the parent */
576         dest->elems[first + i].parent = delem + (src->elems[selem + i].parent - src->elems[selem].parent);
577 
578         /* depth */
579         dest->elems[first + i].depth = dest->elems[delem].depth + (src->elems[selem + i].depth - src->elems[selem].depth) + 1;
580 
581         /* name */
582         dest->elems[first + i].lname = src->elems[selem + i].lname;
583         dest->elems[first + i].iname = _nad_cdata(dest, src->cdata + src->elems[selem + i].iname, src->elems[selem + i].lname);
584 
585         /* cdata */
586         dest->elems[first + i].lcdata = src->elems[selem + i].lcdata;
587         dest->elems[first + i].icdata = _nad_cdata(dest, src->cdata + src->elems[selem + i].icdata, src->elems[selem + i].lcdata);
588         dest->elems[first + i].ltail = src->elems[selem + i].ltail;
589         dest->elems[first + i].itail = _nad_cdata(dest, src->cdata + src->elems[selem + i].itail, src->elems[selem + i].ltail);
590 
591         /* namespaces */
592         dest->elems[first + i].my_ns = dest->elems[first + i].ns = dest->scope = -1;
593 
594         /* first, the element namespace */
595         ns = src->elems[selem + i].my_ns;
596         if(ns >= 0) {
597             for(j = 0; j < dest->ncur; j++)
598                 if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) {
599                     dest->elems[first + i].my_ns = j;
600                     break;
601                 }
602 
603             /* not found, gotta add it */
604             if(j == dest->ncur) {
605                 /* make room */
606                 /* !!! this can go once we have _ex() functions */
607                 if(NAD_NURI_L(src, ns) > 255)
608                     uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
609                 if(NAD_NPREFIX_L(src, ns) > 255)
610                     prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
611 
612                 sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns));
613 
614                 if(NAD_NPREFIX_L(src, ns) > 0) {
615                     sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns));
616                     dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, prefix);
617                 } else
618                     dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, NULL);
619 
620                 if(uri != buri) {
621                     free(uri);
622                     uri = buri;
623                 }
624                 if(prefix != bprefix) {
625                     free(prefix);
626                     prefix = bprefix;
627                 }
628             }
629         }
630 
631         /* then, any declared namespaces */
632         for(ns = src->elems[selem + i].ns; ns >= 0; ns = src->nss[ns].next) {
633             for(j = 0; j < dest->ncur; j++)
634                 if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0)
635                     break;
636 
637             /* not found, gotta add it */
638             if(j == dest->ncur) {
639                 /* make room */
640                 /* !!! this can go once we have _ex() functions */
641                 if(NAD_NURI_L(src, ns) > 255)
642                     uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
643                 if(NAD_NPREFIX_L(src, ns) > 255)
644                     prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
645 
646                 sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns));
647 
648                 if(NAD_NPREFIX_L(src, ns) > 0) {
649                     sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns));
650                     nad_add_namespace(dest, uri, prefix);
651                 } else
652                     nad_add_namespace(dest, uri, NULL);
653 
654                 if(uri != buri) {
655                     free(uri);
656                     uri = buri;
657                 }
658                 if(prefix != bprefix) {
659                     free(prefix);
660                     prefix = bprefix;
661                 }
662             }
663         }
664 
665         /* scope any new namespaces onto this element */
666         dest->elems[first + i].ns = dest->scope; dest->scope = -1;
667 
668         /* attributes */
669         dest->elems[first + i].attr = -1;
670         if(src->acur > 0) {
671             nattr = 0;
672             for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) nattr++;
673 
674             /* make room */
675             NAD_SAFE(dest->attrs, (dest->acur + nattr) * sizeof(struct nad_attr_st), dest->alen);
676 
677             /* kopy ker-azy! */
678             for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) {
679                 /* name */
680                 dest->attrs[dest->acur].lname = src->attrs[attr].lname;
681                 dest->attrs[dest->acur].iname = _nad_cdata(dest, src->cdata + src->attrs[attr].iname, src->attrs[attr].lname);
682 
683                 /* val */
684                 dest->attrs[dest->acur].lval = src->attrs[attr].lval;
685                 dest->attrs[dest->acur].ival = _nad_cdata(dest, src->cdata + src->attrs[attr].ival, src->attrs[attr].lval);
686 
687                 /* namespace */
688                 dest->attrs[dest->acur].my_ns = -1;
689 
690                 ns = src->attrs[attr].my_ns;
691                 if(ns >= 0)
692                     for(j = 0; j < dest->ncur; j++)
693                         if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) {
694                             dest->attrs[dest->acur].my_ns = j;
695                             break;
696                         }
697 
698                 /* link it up */
699                 dest->attrs[dest->acur].next = dest->elems[first + i].attr;
700                 dest->elems[first + i].attr = dest->acur;
701 
702                 dest->acur++;
703             }
704         }
705     }
706 
707     return first;
708 }
709 
710 /** create a new elem on the list */
nad_append_elem(nad_t nad,int ns,const char * name,int depth)711 int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
712 {
713     int elem;
714 
715     _nad_ptr_check(__func__, nad);
716 
717     /* make sure there's mem for us */
718     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
719 
720     elem = nad->ecur;
721     nad->ecur++;
722     nad->elems[elem].lname = strlen(name);
723     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
724     nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
725     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
726     nad->elems[elem].attr = -1;
727     nad->elems[elem].ns = nad->scope; nad->scope = -1;
728     nad->elems[elem].depth = depth;
729     nad->elems[elem].my_ns = ns;
730 
731     /* make sure there's mem in the depth array, then track us */
732     NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen);
733     nad->depths[depth] = elem;
734 
735     /* our parent is the previous guy in the depth array */
736     if(depth <= 0)
737         nad->elems[elem].parent = -1;
738     else
739         nad->elems[elem].parent = nad->depths[depth - 1];
740 
741     return elem;
742 }
743 
744 /** attach new attr to the last elem */
nad_append_attr(nad_t nad,int ns,const char * name,const char * val)745 int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
746 {
747     _nad_ptr_check(__func__, nad);
748 
749     return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0);
750 }
751 
752 /** append new cdata to the last elem */
nad_append_cdata(nad_t nad,const char * cdata,int len,int depth)753 void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
754 {
755     int elem = nad->ecur - 1;
756 
757     _nad_ptr_check(__func__, nad);
758 
759     /* make sure this cdata is the child of the last elem to append */
760     if(nad->elems[elem].depth == depth - 1)
761     {
762         if(nad->elems[elem].icdata == 0)
763             nad->elems[elem].icdata = nad->ccur;
764         _nad_cdata(nad,cdata,len);
765         nad->elems[elem].lcdata += len;
766         return;
767     }
768 
769     /* otherwise, pin the cdata on the tail of the last element at this depth */
770     elem = nad->depths[depth];
771     if(nad->elems[elem].itail == 0)
772         nad->elems[elem].itail = nad->ccur;
773     _nad_cdata(nad,cdata,len);
774     nad->elems[elem].ltail += len;
775 }
776 
777 /** bring a new namespace into scope */
nad_add_namespace(nad_t nad,const char * uri,const char * prefix)778 int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
779 {
780     int ns;
781 
782     _nad_ptr_check(__func__, nad);
783 
784     /* only add it if its not already in scope */
785     ns = nad_find_scoped_namespace(nad, uri, NULL);
786     if(ns >= 0)
787         return ns;
788 
789     /* make sure there's mem for us */
790     NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
791 
792     ns = nad->ncur;
793     nad->ncur++;
794     nad->nss[ns].next = nad->scope;
795     nad->scope = ns;
796 
797     nad->nss[ns].luri = strlen(uri);
798     nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
799     if(prefix != NULL)
800     {
801         nad->nss[ns].lprefix = strlen(prefix);
802         nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
803     }
804     else
805     {
806         nad->nss[ns].lprefix = 0;
807         nad->nss[ns].iprefix = -1;
808     }
809 
810     return ns;
811 }
812 
813 /** declare a namespace on an already-existing element */
nad_append_namespace(nad_t nad,unsigned int elem,const char * uri,const char * prefix)814 int nad_append_namespace(nad_t nad, unsigned int elem, const char *uri, const char *prefix) {
815     int ns;
816 
817     _nad_ptr_check(__func__, nad);
818 
819     /* see if its already scoped on this element */
820     ns = nad_find_namespace(nad, elem, uri, NULL);
821     if(ns >= 0)
822         return ns;
823 
824     /* make some room */
825     NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
826 
827     ns = nad->ncur;
828     nad->ncur++;
829     nad->nss[ns].next = nad->elems[elem].ns;
830     nad->elems[elem].ns = ns;
831 
832     nad->nss[ns].luri = strlen(uri);
833     nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
834     if(prefix != NULL)
835     {
836         nad->nss[ns].lprefix = strlen(prefix);
837         nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
838     }
839     else
840     {
841         nad->nss[ns].lprefix = 0;
842         nad->nss[ns].iprefix = -1;
843     }
844 
845     return ns;
846 }
847 
_nad_escape(nad_t nad,int data,int len,int flag)848 static void _nad_escape(nad_t nad, int data, int len, int flag)
849 {
850     char *c;
851     int ic;
852 
853     if(len <= 0) return;
854 
855     /* first, if told, find and escape " */
856     while(flag >= 4 && (c = memchr(nad->cdata + data,'"',len)) != NULL)
857     {
858         /* get offset */
859         ic = c - nad->cdata;
860 
861         /* cute, eh?  handle other data before this normally */
862         _nad_escape(nad, data, ic - data, 3);
863 
864         /* ensure enough space, and add our escaped &quot; */
865         NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
866         memcpy(nad->cdata + nad->ccur, "&quot;", 6);
867         nad->ccur += 6;
868 
869         /* just update and loop for more */
870         len -= (ic+1) - data;
871         data = ic+1;
872     }
873 
874     /* next, find and escape ' */
875     while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
876     {
877         ic = c - nad->cdata;
878         _nad_escape(nad, data, ic - data, 2);
879 
880         /* ensure enough space, and add our escaped &apos; */
881         NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
882         memcpy(nad->cdata + nad->ccur, "&apos;", 6);
883         nad->ccur += 6;
884 
885         /* just update and loop for more */
886         len -= (ic+1) - data;
887         data = ic+1;
888     }
889 
890     /* next look for < */
891     while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
892     {
893         ic = c - nad->cdata;
894         _nad_escape(nad, data, ic - data, 1);
895 
896         /* ensure enough space, and add our escaped &lt; */
897         NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
898         memcpy(nad->cdata + nad->ccur, "&lt;", 4);
899         nad->ccur += 4;
900 
901         /* just update and loop for more */
902         len -= (ic+1) - data;
903         data = ic+1;
904     }
905 
906     /* next look for > */
907     while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
908     {
909         ic = c - nad->cdata;
910         _nad_escape(nad, data, ic - data, 0);
911 
912         /* ensure enough space, and add our escaped &gt; */
913         NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
914         memcpy(nad->cdata + nad->ccur, "&gt;", 4);
915         nad->ccur += 4;
916 
917         /* just update and loop for more */
918         len -= (ic+1) - data;
919         data = ic+1;
920     }
921 
922     /* if & is found, escape it */
923     while((c = memchr(nad->cdata + data,'&',len)) != NULL)
924     {
925         ic = c - nad->cdata;
926 
927         /* ensure enough space */
928         NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);
929 
930         /* handle normal data */
931         memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
932         nad->ccur += (ic - data);
933 
934         /* append escaped &amp; */
935         memcpy(nad->cdata + nad->ccur, "&amp;", 5);
936         nad->ccur += 5;
937 
938         /* just update and loop for more */
939         len -= (ic+1) - data;
940         data = ic+1;
941     }
942 
943     /* nothing exciting, just append normal cdata */
944     if(len > 0) {
945         NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
946         memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
947         nad->ccur += len;
948     }
949 }
950 
951 /** internal recursive printing function */
_nad_lp0(nad_t nad,unsigned int elem)952 static int _nad_lp0(nad_t nad, unsigned int elem)
953 {
954     int attr;
955     int ndepth;
956     int ns;
957     int elem_ns;
958 
959     /* 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 */
960 
961     /* this whole thing is in a big loop for processing siblings */
962     while(elem != nad->ecur)
963     {
964 
965     /* make enough space for the opening element */
966     ns = nad->elems[elem].my_ns;
967     if(ns >= 0 && nad->nss[ns].iprefix >= 0)
968     {
969         NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen);
970     } else {
971         NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen);
972     }
973 
974     /* opening tag */
975     *(nad->cdata + nad->ccur++) = '<';
976 
977     /* add the prefix if necessary */
978     if(ns >= 0 && nad->nss[ns].iprefix >= 0)
979     {
980         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
981         nad->ccur += nad->nss[ns].lprefix;
982         *(nad->cdata + nad->ccur++) = ':';
983     }
984 
985     /* copy in the name */
986     memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
987     nad->ccur += nad->elems[elem].lname;
988 
989     /* add element prefix namespace */
990     ns = nad->elems[elem].my_ns;
991     if(ns >= 0 && nad->nss[ns].iprefix >= 0)
992     {
993         /* make space */
994         if(nad->nss[ns].iprefix >= 0)
995         {
996             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
997         } else {
998             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
999         }
1000 
1001         /* start */
1002         memcpy(nad->cdata + nad->ccur, " xmlns", 6);
1003         nad->ccur += 6;
1004 
1005         /* prefix if necessary */
1006         if(nad->nss[ns].iprefix >= 0)
1007         {
1008             *(nad->cdata + nad->ccur++) = ':';
1009             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
1010             nad->ccur += nad->nss[ns].lprefix;
1011         }
1012 
1013         *(nad->cdata + nad->ccur++) = '=';
1014         *(nad->cdata + nad->ccur++) = '\'';
1015 
1016         /* uri */
1017         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
1018         nad->ccur += nad->nss[ns].luri;
1019 
1020         *(nad->cdata + nad->ccur++) = '\'';
1021 
1022         elem_ns = ns;
1023     }else{
1024         elem_ns = -1;
1025     }
1026 
1027     /* add the namespaces */
1028     for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next)
1029     {
1030         /* never explicitly declare the implicit xml namespace */
1031         if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0)
1032             continue;
1033 
1034         /* do not redeclare element namespace */
1035         if(ns == elem_ns)
1036             continue;
1037 
1038         /* make space */
1039         if(nad->nss[ns].iprefix >= 0)
1040         {
1041             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
1042         } else {
1043             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
1044         }
1045 
1046         /* start */
1047         memcpy(nad->cdata + nad->ccur, " xmlns", 6);
1048         nad->ccur += 6;
1049 
1050         /* prefix if necessary */
1051         if(nad->nss[ns].iprefix >= 0)
1052         {
1053             *(nad->cdata + nad->ccur++) = ':';
1054             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
1055             nad->ccur += nad->nss[ns].lprefix;
1056         }
1057 
1058         *(nad->cdata + nad->ccur++) = '=';
1059         *(nad->cdata + nad->ccur++) = '\'';
1060 
1061         /* uri */
1062         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
1063         nad->ccur += nad->nss[ns].luri;
1064 
1065         *(nad->cdata + nad->ccur++) = '\'';
1066     }
1067 
1068     for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next)
1069     {
1070         if(nad->attrs[attr].lname <= 0) continue;
1071 
1072         /* make enough space for the wrapper part */
1073         ns = nad->attrs[attr].my_ns;
1074         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1075         {
1076             NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen);
1077         } else {
1078             NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen);
1079         }
1080 
1081         *(nad->cdata + nad->ccur++) = ' ';
1082 
1083         /* add the prefix if necessary */
1084         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1085         {
1086             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
1087             nad->ccur += nad->nss[ns].lprefix;
1088             *(nad->cdata + nad->ccur++) = ':';
1089         }
1090 
1091         /* copy in the name parts */
1092         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname);
1093         nad->ccur += nad->attrs[attr].lname;
1094         *(nad->cdata + nad->ccur++) = '=';
1095         *(nad->cdata + nad->ccur++) = '\'';
1096 
1097         /* copy in the escaped value */
1098         _nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 4);
1099 
1100         /* make enough space for the closing quote and add it */
1101         NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
1102         *(nad->cdata + nad->ccur++) = '\'';
1103     }
1104 
1105     /* figure out what's next */
1106     if(elem+1 == nad->ecur)
1107         ndepth = -1;
1108     else
1109         ndepth = nad->elems[elem+1].depth;
1110 
1111     /* handle based on if there are children, update nelem after done */
1112     if(ndepth <= nad->elems[elem].depth)
1113     {
1114         /* make sure there's enough for what we could need */
1115         NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen);
1116         if(nad->elems[elem].lcdata == 0)
1117         {
1118             memcpy(nad->cdata + nad->ccur, "/>", 2);
1119             nad->ccur += 2;
1120         }else{
1121             *(nad->cdata + nad->ccur++) = '>';
1122 
1123             /* copy in escaped cdata */
1124             _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,4);
1125 
1126             /* make room */
1127             ns = nad->elems[elem].my_ns;
1128             if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1129             {
1130                 NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
1131             } else {
1132                 NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
1133             }
1134 
1135             /* close tag */
1136             memcpy(nad->cdata + nad->ccur, "</", 2);
1137             nad->ccur += 2;
1138 
1139             /* add the prefix if necessary */
1140             if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1141             {
1142                 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
1143                 nad->ccur += nad->nss[ns].lprefix;
1144                 *(nad->cdata + nad->ccur++) = ':';
1145             }
1146 
1147             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
1148             nad->ccur += nad->elems[elem].lname;
1149             *(nad->cdata + nad->ccur++) = '>';
1150         }
1151 
1152         /* always try to append the tail */
1153         _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);
1154 
1155         /* if no siblings either, bail */
1156         if(ndepth < nad->elems[elem].depth)
1157             return elem+1;
1158 
1159         /* next sibling */
1160         elem++;
1161     }else{
1162         int nelem;
1163         /* process any children */
1164 
1165         /* close ourself and append any cdata first */
1166         NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
1167         *(nad->cdata + nad->ccur++) = '>';
1168         _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata, 4);
1169 
1170         /* process children */
1171         nelem = _nad_lp0(nad, elem+1);
1172 
1173         /* close and tail up */
1174         ns = nad->elems[elem].my_ns;
1175         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1176         {
1177             NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
1178         } else {
1179             NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
1180         }
1181         memcpy(nad->cdata + nad->ccur, "</", 2);
1182         nad->ccur += 2;
1183         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
1184         {
1185             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
1186             nad->ccur += nad->nss[ns].lprefix;
1187             *(nad->cdata + nad->ccur++) = ':';
1188         }
1189         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
1190         nad->ccur += nad->elems[elem].lname;
1191         *(nad->cdata + nad->ccur++) = '>';
1192         _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);
1193 
1194         /* if the next element is not our sibling, we're done */
1195         if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth)
1196             return nelem;
1197 
1198         /* for next sibling in while loop */
1199         elem = nelem;
1200     }
1201 
1202     /* here's the end of that big while loop */
1203     }
1204 
1205     return elem;
1206 }
1207 
nad_print(nad_t nad,unsigned int elem,const char ** xml,int * len)1208 void nad_print(nad_t nad, unsigned int elem, const char **xml, int *len)
1209 {
1210     int ixml = nad->ccur;
1211 
1212     _nad_ptr_check(__func__, nad);
1213 
1214     _nad_lp0(nad, elem);
1215     *len = nad->ccur - ixml;
1216     *xml = nad->cdata + ixml;
1217 }
1218 
1219 /**
1220  * nads serialize to a buffer of this form:
1221  *
1222  * [buflen][ecur][acur][ncur][ccur][elems][attrs][nss][cdata]
1223  *
1224  * nothing is done with endianness or word length, so the nad must be
1225  * serialized and deserialized on the same platform
1226  *
1227  * buflen is not actually used by deserialize(), but is provided as a
1228  * convenience to the application so it knows how many bytes to read before
1229  * passing them in to deserialize()
1230  *
1231  * the depths array is not stored, so after deserialization
1232  * nad_append_elem() and nad_append_cdata() will not work. this is rarely
1233  * a problem
1234  */
1235 
nad_serialize(nad_t nad,char ** buf,int * len)1236 void nad_serialize(nad_t nad, char **buf, int *len) {
1237     char *pos;
1238 
1239     _nad_ptr_check(__func__, nad);
1240 
1241     *len = sizeof(int) * 5 + /* 4 ints in nad_t, plus one for len */
1242            sizeof(struct nad_elem_st) * nad->ecur +
1243            sizeof(struct nad_attr_st) * nad->acur +
1244            sizeof(struct nad_ns_st) * nad->ncur +
1245            sizeof(char) * nad->ccur;
1246 
1247     *buf = (char *) malloc(*len);
1248     pos = *buf;
1249 
1250     * (int *) pos = *len;       pos += sizeof(int);
1251     * (int *) pos = nad->ecur;  pos += sizeof(int);
1252     * (int *) pos = nad->acur;  pos += sizeof(int);
1253     * (int *) pos = nad->ncur;  pos += sizeof(int);
1254     * (int *) pos = nad->ccur;  pos += sizeof(int);
1255 
1256     memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur);    pos += sizeof(struct nad_elem_st) * nad->ecur;
1257     memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur);    pos += sizeof(struct nad_attr_st) * nad->acur;
1258     memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur);        pos += sizeof(struct nad_ns_st) * nad->ncur;
1259     memcpy(pos, nad->cdata, sizeof(char) * nad->ccur);
1260 }
1261 
nad_deserialize(const char * buf)1262 nad_t nad_deserialize(const char *buf) {
1263     nad_t nad = nad_new();
1264     const char *pos = buf + sizeof(int);  /* skip len */
1265 
1266     _nad_ptr_check(__func__, nad);
1267 
1268     nad->ecur = * (int *) pos; pos += sizeof(int);
1269     nad->acur = * (int *) pos; pos += sizeof(int);
1270     nad->ncur = * (int *) pos; pos += sizeof(int);
1271     nad->ccur = * (int *) pos; pos += sizeof(int);
1272     nad->elen = nad->ecur;
1273     nad->alen = nad->acur;
1274     nad->nlen = nad->ncur;
1275     nad->clen = nad->ccur;
1276 
1277     if(nad->ecur > 0)
1278     {
1279         nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur);
1280         memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur);
1281         pos += sizeof(struct nad_elem_st) * nad->ecur;
1282     }
1283 
1284     if(nad->acur > 0)
1285     {
1286         nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur);
1287         memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur);
1288         pos += sizeof(struct nad_attr_st) * nad->acur;
1289     }
1290 
1291     if(nad->ncur > 0)
1292     {
1293         nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur);
1294         memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur);
1295         pos += sizeof(struct nad_ns_st) * nad->ncur;
1296     }
1297 
1298     if(nad->ccur > 0)
1299     {
1300         nad->cdata = (char *) malloc(sizeof(char) * nad->ccur);
1301         memcpy(nad->cdata, pos, sizeof(char) * nad->ccur);
1302     }
1303 
1304     return nad;
1305 }
1306 
1307 
1308 /** parse a buffer into a nad */
1309 
1310 struct build_data {
1311     nad_t               nad;
1312     int                 depth;
1313     XML_Parser          p;
1314 };
1315 
_nad_parse_element_start(void * arg,const char * name,const char ** atts)1316 static void _nad_parse_element_start(void *arg, const char *name, const char **atts) {
1317     struct build_data *bd = (struct build_data *) arg;
1318     char buf[1024];
1319     char *uri, *elem, *prefix;
1320     const char **attr;
1321     int el, ns;
1322 
1323     /* make a copy */
1324     strncpy(buf, name, 1024);
1325     buf[1023] = '\0';
1326 
1327     /* expat gives us:
1328          prefixed namespaced elem: uri|elem|prefix
1329           default namespaced elem: uri|elem
1330                un-namespaced elem: elem
1331      */
1332 
1333     /* extract all the bits */
1334     uri = buf;
1335     elem = strchr(uri, '|');
1336     if(elem != NULL) {
1337         *elem = '\0';
1338         elem++;
1339         prefix = strchr(elem, '|');
1340         if(prefix != NULL) {
1341             *prefix = '\0';
1342             prefix++;
1343         }
1344         ns = nad_add_namespace(bd->nad, uri, prefix);
1345     } else {
1346         /* un-namespaced, just take it as-is */
1347         uri = NULL;
1348         elem = buf;
1349         prefix = NULL;
1350         ns = -1;
1351     }
1352 
1353     /* add it */
1354     el = nad_append_elem(bd->nad, ns, elem, bd->depth);
1355 
1356     /* now the attributes, one at a time */
1357     attr = atts;
1358     while(attr[0] != NULL) {
1359 
1360         /* make a copy */
1361         strncpy(buf, attr[0], 1024);
1362         buf[1023] = '\0';
1363 
1364         /* extract all the bits */
1365         uri = buf;
1366         elem = strchr(uri, '|');
1367         if(elem != NULL) {
1368             *elem = '\0';
1369             elem++;
1370             prefix = strchr(elem, '|');
1371             if(prefix != NULL) {
1372                 *prefix = '\0';
1373                 prefix++;
1374             }
1375             ns = nad_append_namespace(bd->nad, el, uri, prefix);
1376         } else {
1377             /* un-namespaced, just take it as-is */
1378             uri = NULL;
1379             elem = buf;
1380             prefix = NULL;
1381             ns = -1;
1382         }
1383 
1384         /* add it */
1385         nad_append_attr(bd->nad, ns, elem, (char *) attr[1]);
1386 
1387         attr += 2;
1388     }
1389 
1390     bd->depth++;
1391 }
1392 
_nad_parse_element_end(void * arg,const char * name)1393 static void _nad_parse_element_end(void *arg, const char *name) {
1394     struct build_data *bd = (struct build_data *) arg;
1395 
1396     bd->depth--;
1397 }
1398 
_nad_parse_cdata(void * arg,const char * str,int len)1399 static void _nad_parse_cdata(void *arg, const char *str, int len) {
1400     struct build_data *bd = (struct build_data *) arg;
1401 
1402     /* go */
1403     nad_append_cdata(bd->nad, (char *) str, len, bd->depth);
1404 }
1405 
_nad_parse_namespace_start(void * arg,const char * prefix,const char * uri)1406 static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri) {
1407     struct build_data *bd = (struct build_data *) arg;
1408     int ns;
1409 
1410     ns = nad_add_namespace(bd->nad, (char *) uri, (char *) prefix);
1411 
1412     /* Always set the namespace (to catch cases where nad_add_namespace doesn't add it) */
1413     bd->nad->scope = ns;
1414 }
1415 
1416 #ifdef HAVE_XML_STOPPARSER
1417 /* Stop the parser if an entity declaration is hit. */
_nad_parse_entity_declaration(void * arg,const char * entityName,int is_parameter_entity,const char * value,int value_length,const char * base,const char * systemId,const char * publicId,const char * notationName)1418 static void _nad_parse_entity_declaration(void *arg, const char *entityName,
1419                                           int is_parameter_entity, const char *value,
1420                                           int value_length, const char *base,
1421                                           const char *systemId, const char *publicId,
1422                                           const char *notationName)
1423 {
1424     struct build_data *bd = (struct build_data *) arg;
1425 
1426     XML_StopParser(bd->p, XML_FALSE);
1427 }
1428 #endif
1429 
nad_parse(const char * buf,int len)1430 nad_t nad_parse(const char *buf, int len) {
1431     struct build_data bd;
1432     XML_Parser p;
1433 
1434     if(len == 0)
1435         len = strlen(buf);
1436 
1437     p = XML_ParserCreateNS(NULL, '|');
1438     if(p == NULL)
1439         return NULL;
1440     bd.p = p;
1441 
1442     XML_SetReturnNSTriplet(p, 1);
1443     /* Prevent the "billion laughs" attack against expat by disabling
1444      * internal entity expansion.  With 2.x, forcibly stop the parser
1445      * if an entity is declared - this is safer and a more obvious
1446      * failure mode.  With older versions, simply prevent expenansion
1447      * of such entities. */
1448 #ifdef HAVE_XML_STOPPARSER
1449     XML_SetEntityDeclHandler(p, (void *) _nad_parse_entity_declaration);
1450 #else
1451     XML_SetDefaultHandler(p, NULL);
1452 #endif
1453 
1454     bd.nad = nad_new();
1455     bd.depth = 0;
1456 
1457     XML_SetUserData(p, (void *) &bd);
1458     XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
1459     XML_SetCharacterDataHandler(p, _nad_parse_cdata);
1460     XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);
1461 
1462     if(!XML_Parse(p, buf, len, 1)) {
1463         XML_ParserFree(p);
1464         nad_free(bd.nad);
1465         return NULL;
1466     }
1467 
1468     XML_ParserFree(p);
1469 
1470     if(bd.depth != 0)
1471         return NULL;
1472 
1473     return bd.nad;
1474 }
1475