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