jabberd2  2.6.1
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  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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
848 static void _nad_escape(nad_t nad, int data, int len, int flag)
849 {
850  char *c;
851  int ic;
852 
853  if(len <= 0) return;
854 
855  /* first, if told, find and escape " */
856  while(flag >= 4 && (c = memchr(nad->cdata + data,'"',len)) != NULL)
857  {
858  /* get offset */
859  ic = c - nad->cdata;
860 
861  /* cute, eh? handle other data before this normally */
862  _nad_escape(nad, data, ic - data, 3);
863 
864  /* ensure enough space, and add our escaped &quot; */
865  NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
866  memcpy(nad->cdata + nad->ccur, "&quot;", 6);
867  nad->ccur += 6;
868 
869  /* just update and loop for more */
870  len -= (ic+1) - data;
871  data = ic+1;
872  }
873 
874  /* next, find and escape ' */
875  while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
876  {
877  ic = c - nad->cdata;
878  _nad_escape(nad, data, ic - data, 2);
879 
880  /* ensure enough space, and add our escaped &apos; */
881  NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
882  memcpy(nad->cdata + nad->ccur, "&apos;", 6);
883  nad->ccur += 6;
884 
885  /* just update and loop for more */
886  len -= (ic+1) - data;
887  data = ic+1;
888  }
889 
890  /* next look for < */
891  while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
892  {
893  ic = c - nad->cdata;
894  _nad_escape(nad, data, ic - data, 1);
895 
896  /* ensure enough space, and add our escaped &lt; */
897  NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
898  memcpy(nad->cdata + nad->ccur, "&lt;", 4);
899  nad->ccur += 4;
900 
901  /* just update and loop for more */
902  len -= (ic+1) - data;
903  data = ic+1;
904  }
905 
906  /* next look for > */
907  while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
908  {
909  ic = c - nad->cdata;
910  _nad_escape(nad, data, ic - data, 0);
911 
912  /* ensure enough space, and add our escaped &gt; */
913  NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
914  memcpy(nad->cdata + nad->ccur, "&gt;", 4);
915  nad->ccur += 4;
916 
917  /* just update and loop for more */
918  len -= (ic+1) - data;
919  data = ic+1;
920  }
921 
922  /* if & is found, escape it */
923  while((c = memchr(nad->cdata + data,'&',len)) != NULL)
924  {
925  ic = c - nad->cdata;
926 
927  /* ensure enough space */
928  NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);
929 
930  /* handle normal data */
931  memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
932  nad->ccur += (ic - data);
933 
934  /* append escaped &amp; */
935  memcpy(nad->cdata + nad->ccur, "&amp;", 5);
936  nad->ccur += 5;
937 
938  /* just update and loop for more */
939  len -= (ic+1) - data;
940  data = ic+1;
941  }
942 
943  /* nothing exciting, just append normal cdata */
944  if(len > 0) {
945  NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
946  memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
947  nad->ccur += len;
948  }
949 }
950 
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 
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 
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 
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 
1310 struct build_data {
1311  nad_t nad;
1312  int depth;
1313  XML_Parser p;
1314 };
1315 
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 
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 
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 
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. */
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 
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 }
int attr
Definition: nad.h:74
int iname
Definition: nad.h:81
void nad_wrap_elem(nad_t nad, unsigned int elem, int ns, const char *name)
wrap an element with another element
Definition: nad.c:507
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:745
#define NAD_SAFE(blocks, size, len)
this is the safety check used to make sure there&#39;s always enough mem
Definition: nad.c:89
int ltail
Definition: nad.h:73
int depth
Definition: config.c:39
int nad_find_attr(nad_t nad, unsigned 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:237
Not A DOM.
void nad_set_attr(nad_t nad, unsigned 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:407
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:753
void nad_drop_elem(nad_t nad, unsigned int elem)
remove an element (and its subelements)
Definition: nad.c:484
static void _nad_parse_element_end(void *arg, const char *name)
Definition: nad.c:1393
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:778
void nad_print(nad_t nad, unsigned int elem, const char **xml, int *len)
create a string representation of the given element (and children), point references to it ...
Definition: nad.c:1208
#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_insert_elem(nad_t nad, unsigned int parent, int ns, const char *name, const char *cdata)
shove in a new child elem after the given one
Definition: nad.c:437
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:711
void nad_free(nad_t nad)
free that nad
Definition: nad.c:180
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
nad_t nad_copy(nad_t nad)
copy a nad
Definition: nad.c:147
int lname
Definition: nad.h:71
nad_t nad_deserialize(const char *buf)
Definition: nad.c:1262
#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:1236
int nad_find_namespace(nad_t nad, unsigned int elem, const char *uri, const char *prefix)
get a matching ns on this elem, both uri and optional prefix
Definition: nad.c:264
#define uri_XML
Definition: uri.h:31
unsigned int depth
Definition: nad.h:77
int parent
Definition: nad.h:70
static void _nad_escape(nad_t nad, int data, int len, int flag)
Definition: nad.c:848
nad_t nad_parse(const char *buf, int len)
create a nad from raw xml
Definition: nad.c:1430
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:1316
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:1313
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:1399
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_find_elem(nad_t nad, unsigned 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:206
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:544
int iprefix
Definition: nad.h:89
#define NAD_NPREFIX(N, NS)
Definition: nad.h:193
int * depths
Definition: nad.h:99
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
xht xhash_new(int prime)
Definition: xhash.c:96
int next
Definition: nad.h:90
static int _nad_lp0(nad_t nad, unsigned int elem)
internal recursive printing function
Definition: nad.c:952
static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri)
Definition: nad.c:1406
int itail
Definition: nad.h:73
int ival
Definition: nad.h:82
int nad_append_namespace(nad_t nad, unsigned int elem, const char *uri, const char *prefix)
declare a namespace on an already-existing element
Definition: nad.c:814
int lcdata
Definition: nad.h:72
Definition: nad.h:87
int nad_find_elem_path(nad_t nad, unsigned 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:322
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:292
int iuri
Definition: nad.h:88