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 " */
865 NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
866 memcpy(nad->cdata + nad->ccur, """, 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 ' */
881 NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
882 memcpy(nad->cdata + nad->ccur, "'", 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 < */
897 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
898 memcpy(nad->cdata + nad->ccur, "<", 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 > */
913 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
914 memcpy(nad->cdata + nad->ccur, ">", 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 & */
935 memcpy(nad->cdata + nad->ccur, "&", 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