jabberd2  2.2.16
util/nad.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00035 #include "nad.h"
00036 #include "util.h"
00037 
00038 /* define NAD_DEBUG to get pointer tracking - great for weird bugs that you can't reproduce */
00039 #ifdef NAD_DEBUG
00040 
00041 static xht _nad_alloc_tracked = NULL;
00042 static xht _nad_free_tracked = NULL;
00043 
00044 static void _nad_ptr_check(const char *func, nad_t nad) {
00045     char loc[24];
00046     snprintf(loc, sizeof(loc), "%x", (int) nad);
00047 
00048     if(xhash_get(_nad_alloc_tracked, loc) == NULL) {
00049         fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad);
00050         abort();
00051     }
00052 
00053     if(xhash_get(_nad_free_tracked, loc) != NULL) {
00054         fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad);
00055         abort();
00056     }
00057 
00058     fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad);
00059 }
00060 #else
00061 #define _nad_ptr_check(func,nad)
00062 #endif
00063 
00064 #define BLOCKSIZE 128
00065 
00076 static int _nad_realloc(void **oblocks, int len)
00077 {
00078     int nlen;
00079 
00080     /* round up to standard block sizes */
00081     nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
00082 
00083     /* keep trying till we get it */
00084     *oblocks = realloc(*oblocks, nlen);
00085     return nlen;
00086 }
00087 
00089 #define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size));
00090 
00092 static int _nad_cdata(nad_t nad, const char *cdata, int len)
00093 {
00094     NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
00095 
00096     memcpy(nad->cdata + nad->ccur, cdata, len);
00097     nad->ccur += len;
00098     return nad->ccur - len;
00099 }
00100 
00102 static int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
00103 {
00104     int attr;
00105 
00106     /* make sure there's mem for us */
00107     NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen);
00108 
00109     attr = nad->acur;
00110     nad->acur++;
00111     nad->attrs[attr].next = nad->elems[elem].attr;
00112     nad->elems[elem].attr = attr;
00113     nad->attrs[attr].lname = strlen(name);
00114     nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname);
00115     if(vallen > 0)
00116         nad->attrs[attr].lval = vallen;
00117     else
00118         nad->attrs[attr].lval = strlen(val);
00119     nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);    
00120     nad->attrs[attr].my_ns = ns;
00121 
00122     return attr;
00123 }
00124 
00125 nad_t nad_new(void)
00126 {
00127     nad_t nad;
00128 
00129     nad = calloc(1, sizeof(struct nad_st));
00130 
00131     nad->scope = -1;
00132 
00133 #ifdef NAD_DEBUG
00134     {
00135     char loc[24];
00136     snprintf(loc, sizeof(loc), "%x", (int) nad);
00137     xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1);
00138     }
00139     _nad_ptr_check(__func__, nad);
00140 #endif
00141 
00142     return nad;
00143 }
00144 
00145 nad_t nad_copy(nad_t nad)
00146 {
00147     nad_t copy;
00148 
00149     _nad_ptr_check(__func__, nad);
00150 
00151     if(nad == NULL) return NULL;
00152 
00153     copy = nad_new();
00154 
00155     /* if it's not large enough, make bigger */
00156     NAD_SAFE(copy->elems, nad->elen, copy->elen);
00157     NAD_SAFE(copy->attrs, nad->alen, copy->alen);
00158     NAD_SAFE(copy->nss, nad->nlen, copy->nlen);
00159     NAD_SAFE(copy->cdata, nad->clen, copy->clen);
00160 
00161     /* copy all data */
00162     memcpy(copy->elems, nad->elems, nad->elen);
00163     memcpy(copy->attrs, nad->attrs, nad->alen);
00164     memcpy(copy->nss, nad->nss, nad->nlen);
00165     memcpy(copy->cdata, nad->cdata, nad->clen);
00166 
00167     /* sync data */
00168     copy->ecur = nad->ecur;
00169     copy->acur = nad->acur;
00170     copy->ncur = nad->ncur;
00171     copy->ccur = nad->ccur;
00172 
00173     copy->scope = nad->scope;
00174 
00175     return copy;
00176 }
00177 
00178 void nad_free(nad_t nad)
00179 {
00180     if(nad == NULL) return;
00181 
00182 #ifdef NAD_DEBUG
00183     _nad_ptr_check(__func__, nad);
00184     {
00185     char loc[24];
00186     snprintf(loc, sizeof(loc), "%x", (int) nad);
00187     xhash_zap(_nad_alloc_tracked, loc);
00188     xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad);
00189     }
00190 #endif
00191 
00192     /* Free nad */
00193     free(nad->elems);
00194     free(nad->attrs);
00195     free(nad->cdata);
00196     free(nad->nss);
00197     free(nad->depths);
00198 #ifndef NAD_DEBUG
00199     free(nad);
00200 #endif
00201 }
00202 
00204 int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth)
00205 {
00206     int my_ns;
00207     int lname = 0;
00208 
00209     _nad_ptr_check(__func__, nad);
00210 
00211     /* make sure there are valid args */
00212     if(elem >= nad->ecur) return -1;
00213 
00214     /* set up args for searching */
00215     depth = nad->elems[elem].depth + depth;
00216     if(name != NULL) lname = strlen(name);
00217 
00218     /* search */
00219     for(elem++;elem < nad->ecur;elem++)
00220     {
00221         /* if we hit one with a depth less than ours, then we don't have the
00222          * same parent anymore, bail */
00223         if(nad->elems[elem].depth < depth)
00224             return -1;
00225 
00226         if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) &&
00227           (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)))
00228             return elem;
00229     }
00230 
00231     return -1;
00232 }
00233 
00235 int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
00236 {
00237     int attr, my_ns;
00238     int lname, lval = 0;
00239 
00240     _nad_ptr_check(__func__, nad);
00241 
00242     /* make sure there are valid args */
00243     if(elem >= nad->ecur || name == NULL) return -1;
00244  
00245     attr = nad->elems[elem].attr;
00246     lname = strlen(name);
00247     if(val != NULL) lval = strlen(val);
00248 
00249     while(attr >= 0)
00250     {
00251         /* hefty, match name and if a val, also match that */
00252         if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 && 
00253           (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) &&
00254           (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)))
00255             return attr;
00256         attr = nad->attrs[attr].next;
00257     }
00258     return -1;
00259 }
00260 
00262 int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix)
00263 {
00264     int check, ns;
00265 
00266     _nad_ptr_check(__func__, nad);
00267 
00268     /* make sure there are valid args */
00269     if(elem >= nad->ecur || uri == NULL) return -1;
00270 
00271     /* work backwards through our parents, looking for our namespace on each one.
00272      * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */
00273     check = elem;
00274     while(check >= 0)
00275     {
00276         ns = nad->elems[check].ns;
00277         while(ns >= 0)
00278         {
00279             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)))
00280                 return ns;
00281             ns = nad->nss[ns].next;
00282         }
00283         check = nad->elems[check].parent;
00284     }
00285 
00286     return -1;
00287 }
00288 
00290 int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
00291 {
00292     int ns;
00293 
00294     _nad_ptr_check(__func__, nad);
00295 
00296     if(uri == NULL)
00297         return -1;
00298 
00299     for(ns = 0; ns < nad->ncur; ns++)
00300     {
00301         if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 &&
00302            (prefix == NULL ||
00303              (nad->nss[ns].iprefix >= 0 &&
00304               strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
00305             return ns;
00306     }
00307 
00308     return -1;
00309 }
00310 
00318 int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name) {
00319     char *str, *slash, *qmark, *equals;
00320 
00321     _nad_ptr_check(__func__, nad);
00322 
00323     /* make sure there are valid args */
00324     if(elem >= nad->ecur || name == NULL) return -1;
00325 
00326     /* if it's plain name just search children */
00327     if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
00328         return nad_find_elem(nad, elem, ns, name, 1);
00329 
00330     str = strdup(name);
00331     slash = strstr(str, "/");
00332     qmark = strstr(str, "?");
00333     equals = strstr(str, "=");
00334 
00335     /* no / in element name part */
00336     if(qmark != NULL && (slash == NULL || qmark < slash))
00337     { /* of type ?attrib */
00338 
00339         *qmark = '\0';
00340         qmark++;
00341         if(equals != NULL)
00342         {
00343             *equals = '\0';
00344             equals++;
00345         }
00346 
00347         for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) {
00348             if(elem < 0) break;
00349         if(strcmp(qmark, "xmlns") == 0) {
00350             if(nad_find_namespace(nad, elem, equals, NULL) >= 0) break;
00351             }
00352         else {
00353             if(nad_find_attr(nad, elem, ns, qmark, equals) >= 0) break;
00354         }
00355         }
00356 
00357         free(str);
00358         return elem;
00359     }
00360 
00361     /* there is a / in element name part - need to recurse */
00362     *slash = '\0';
00363     ++slash;
00364 
00365     for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) {
00366         if(elem < 0) break;
00367     if(nad_find_elem_path(nad, elem, ns, slash) >= 0) break;
00368     }
00369 
00370     free(str);
00371     return elem;
00372 }
00373 
00375 void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
00376 {
00377     int attr;
00378 
00379     _nad_ptr_check(__func__, nad);
00380 
00381     /* find one to replace first */
00382     if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0)
00383     {
00384         /* only create new if there's a value to store */
00385         if(val != NULL)
00386             _nad_attr(nad, elem, ns, name, val, vallen);
00387         return;
00388     }
00389 
00390     /* got matching, update value or zap */
00391     if(val == NULL)
00392     {
00393         nad->attrs[attr].lval = nad->attrs[attr].lname = 0;
00394     }else{
00395         if(vallen > 0)
00396             nad->attrs[attr].lval = vallen;
00397         else
00398             nad->attrs[attr].lval = strlen(val);
00399         nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
00400     }
00401 
00402 }
00403 
00405 int nad_insert_elem(nad_t nad, int parent, int ns, const char *name, const char *cdata)
00406 {
00407     int elem;
00408 
00409     if (parent >= nad->ecur) {
00410         if (nad->ecur > 0)
00411             parent = nad->ecur -1;
00412         else
00413             parent = 0;
00414     }
00415 
00416     elem = parent + 1;
00417 
00418     _nad_ptr_check(__func__, nad);
00419 
00420     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
00421 
00422     /* relocate all the rest of the elems (unless we're at the end already) */
00423     if(nad->ecur != elem)
00424         memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
00425     nad->ecur++;
00426 
00427     /* set up req'd parts of new elem */
00428     nad->elems[elem].parent = parent;
00429     nad->elems[elem].lname = strlen(name);
00430     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
00431     nad->elems[elem].attr = -1;
00432     nad->elems[elem].ns = nad->scope; nad->scope = -1;
00433     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
00434     nad->elems[elem].my_ns = ns;
00435 
00436     /* add cdata if given */
00437     if(cdata != NULL)
00438     {
00439         nad->elems[elem].lcdata = strlen(cdata);
00440         nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata);
00441     }else{
00442         nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
00443     }
00444 
00445     /* parent/child */
00446     nad->elems[elem].depth = nad->elems[parent].depth + 1;
00447 
00448     return elem;
00449 }
00450 
00452 void nad_drop_elem(nad_t nad, int elem) {
00453     int next, cur;
00454 
00455     _nad_ptr_check(__func__, nad);
00456 
00457     if(elem >= nad->ecur) return;
00458 
00459     /* find the next elem at this depth to move into the space */
00460     next = elem + 1;
00461     while(next < nad->ecur && nad->elems[next].depth > nad->elems[elem].depth) next++;
00462 
00463     /* relocate */
00464     if(next < nad->ecur)
00465         memmove(&nad->elems[elem], &nad->elems[next], (nad->ecur - next) * sizeof(struct nad_elem_st));
00466     nad->ecur -= next - elem;
00467 
00468     /* relink parents */
00469     for(cur = elem; cur < nad->ecur; cur++)
00470         if(nad->elems[cur].parent > next)
00471             nad->elems[cur].parent -= (next - elem);
00472 }
00473 
00475 void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name)
00476 {
00477     int cur;
00478 
00479     _nad_ptr_check(__func__, nad);
00480 
00481     if(elem >= nad->ecur) return;
00482 
00483     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
00484 
00485     /* relocate all the rest of the elems after us */
00486     memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
00487     nad->ecur++;
00488 
00489     /* relink parents on moved elements */
00490     for(cur = elem + 1; cur < nad->ecur; cur++)
00491         if(nad->elems[cur].parent > elem + 1)
00492             nad->elems[cur].parent++;
00493 
00494     /* set up req'd parts of new elem */
00495     nad->elems[elem].lname = strlen(name);
00496     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
00497     nad->elems[elem].attr = -1;
00498     nad->elems[elem].ns = nad->scope; nad->scope = -1;
00499     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
00500     nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
00501     nad->elems[elem].my_ns = ns;
00502 
00503     /* raise the bar on all the children */
00504     nad->elems[elem+1].depth++;
00505     for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++;
00506 
00507     /* hook up the parent */
00508     nad->elems[elem].parent = nad->elems[elem + 1].parent;
00509 }
00510 
00512 int nad_insert_nad(nad_t dest, int delem, nad_t src, int selem) {
00513     int nelem, first, i, j, ns, nattr, attr;
00514     char buri[256], *uri = buri, bprefix[256], *prefix = bprefix;
00515 
00516     _nad_ptr_check(__func__, dest);
00517     _nad_ptr_check(__func__, src);
00518 
00519     /* can't do anything if these aren't real elems */
00520     if(src->ecur <= selem || dest->ecur <= delem)
00521         return -1;
00522 
00523     /* figure out how many elements to copy */
00524     nelem = 1;
00525     while(selem + nelem < src->ecur && src->elems[selem + nelem].depth > src->elems[selem].depth) nelem++;
00526 
00527     /* make room */
00528     NAD_SAFE(dest->elems, (dest->ecur + nelem) * sizeof(struct nad_elem_st), dest->elen);
00529 
00530     /* relocate all the elems after us */
00531     memmove(&dest->elems[delem + nelem + 1], &dest->elems[delem + 1], (dest->ecur - delem - 1) * sizeof(struct nad_elem_st));
00532     dest->ecur += nelem;
00533 
00534     /* relink parents on moved elements */
00535     for(i = delem + nelem; i < dest->ecur; i++)
00536         if(dest->elems[i].parent > delem)
00537             dest->elems[i].parent += nelem;
00538 
00539     first = delem + 1;
00540 
00541     /* copy them in, one at a time */
00542     for(i = 0; i < nelem; i++) {
00543         /* link the parent */
00544         dest->elems[first + i].parent = delem + (src->elems[selem + i].parent - src->elems[selem].parent);
00545 
00546         /* depth */
00547         dest->elems[first + i].depth = dest->elems[delem].depth + (src->elems[selem + i].depth - src->elems[selem].depth) + 1;
00548 
00549         /* name */
00550         dest->elems[first + i].lname = src->elems[selem + i].lname;
00551         dest->elems[first + i].iname = _nad_cdata(dest, src->cdata + src->elems[selem + i].iname, src->elems[selem + i].lname);
00552 
00553         /* cdata */
00554         dest->elems[first + i].lcdata = src->elems[selem + i].lcdata;
00555         dest->elems[first + i].icdata = _nad_cdata(dest, src->cdata + src->elems[selem + i].icdata, src->elems[selem + i].lcdata);
00556         dest->elems[first + i].ltail = src->elems[selem + i].ltail;
00557         dest->elems[first + i].itail = _nad_cdata(dest, src->cdata + src->elems[selem + i].itail, src->elems[selem + i].ltail);
00558 
00559         /* namespaces */
00560         dest->elems[first + i].my_ns = dest->elems[first + i].ns = dest->scope = -1;
00561         
00562         /* first, the element namespace */
00563         ns = src->elems[selem + i].my_ns;
00564         if(ns >= 0) {
00565             for(j = 0; j < dest->ncur; j++)
00566                 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) {
00567                     dest->elems[first + i].my_ns = j;
00568                     break;
00569                 }
00570 
00571             /* not found, gotta add it */
00572             if(j == dest->ncur) {
00573                 /* make room */
00574                 /* !!! this can go once we have _ex() functions */
00575                 if(NAD_NURI_L(src, ns) > 255)
00576                     uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
00577                 if(NAD_NPREFIX_L(src, ns) > 255)
00578                     prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
00579 
00580                 sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns));
00581 
00582                 if(NAD_NPREFIX_L(src, ns) > 0) {
00583                     sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns));
00584                     dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, prefix);
00585                 } else
00586                     dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, NULL);
00587 
00588                 if(uri != buri) free(uri);
00589                 if(prefix != bprefix) free(prefix);
00590             }
00591         }
00592 
00593         /* then, any declared namespaces */
00594         for(ns = src->elems[selem + i].ns; ns >= 0; ns = src->nss[ns].next) {
00595             for(j = 0; j < dest->ncur; j++)
00596                 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)
00597                     break;
00598 
00599             /* not found, gotta add it */
00600             if(j == dest->ncur) {
00601                 /* make room */
00602                 /* !!! this can go once we have _ex() functions */
00603                 if(NAD_NURI_L(src, ns) > 255)
00604                     uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
00605                 if(NAD_NPREFIX_L(src, ns) > 255)
00606                     prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1));
00607 
00608                 sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns));
00609 
00610                 if(NAD_NPREFIX_L(src, ns) > 0) {
00611                     sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns));
00612                     nad_add_namespace(dest, uri, prefix);
00613                 } else
00614                     nad_add_namespace(dest, uri, NULL);
00615 
00616                 if(uri != buri) free(uri);
00617                 if(prefix != bprefix) free(prefix);
00618             }
00619         }
00620 
00621         /* scope any new namespaces onto this element */
00622         dest->elems[first + i].ns = dest->scope; dest->scope = -1;
00623 
00624         /* attributes */
00625         dest->elems[first + i].attr = -1;
00626         if(src->acur > 0) {
00627             nattr = 0;
00628             for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) nattr++;
00629 
00630             /* make room */
00631             NAD_SAFE(dest->attrs, (dest->acur + nattr) * sizeof(struct nad_attr_st), dest->alen);
00632 
00633             /* kopy ker-azy! */
00634             for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) {
00635                 /* name */
00636                 dest->attrs[dest->acur].lname = src->attrs[attr].lname;
00637                 dest->attrs[dest->acur].iname = _nad_cdata(dest, src->cdata + src->attrs[attr].iname, src->attrs[attr].lname);
00638 
00639                 /* val */
00640                 dest->attrs[dest->acur].lval = src->attrs[attr].lval;
00641                 dest->attrs[dest->acur].ival = _nad_cdata(dest, src->cdata + src->attrs[attr].ival, src->attrs[attr].lval);
00642         
00643                 /* namespace */
00644                 dest->attrs[dest->acur].my_ns = -1;
00645 
00646                 ns = src->attrs[attr].my_ns;
00647                 if(ns >= 0)
00648                     for(j = 0; j < dest->ncur; j++)
00649                         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) {
00650                             dest->attrs[dest->acur].my_ns = j;
00651                             break;
00652                         }
00653                         
00654                 /* link it up */
00655                 dest->attrs[dest->acur].next = dest->elems[first + i].attr;
00656                 dest->elems[first + i].attr = dest->acur;
00657 
00658                 dest->acur++;
00659             }
00660         }
00661     }
00662 
00663     return first;
00664 }
00665 
00667 int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
00668 {
00669     int elem;
00670 
00671     _nad_ptr_check(__func__, nad);
00672 
00673     /* make sure there's mem for us */
00674     NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
00675 
00676     elem = nad->ecur;
00677     nad->ecur++;
00678     nad->elems[elem].lname = strlen(name);
00679     nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
00680     nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
00681     nad->elems[elem].itail = nad->elems[elem].ltail = 0;
00682     nad->elems[elem].attr = -1;
00683     nad->elems[elem].ns = nad->scope; nad->scope = -1;
00684     nad->elems[elem].depth = depth;
00685     nad->elems[elem].my_ns = ns;
00686 
00687     /* make sure there's mem in the depth array, then track us */
00688     NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen);
00689     nad->depths[depth] = elem;
00690 
00691     /* our parent is the previous guy in the depth array */
00692     if(depth <= 0)
00693         nad->elems[elem].parent = -1;
00694     else
00695         nad->elems[elem].parent = nad->depths[depth - 1];
00696 
00697     return elem;
00698 }
00699 
00701 int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
00702 {
00703     _nad_ptr_check(__func__, nad);
00704 
00705     return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0);
00706 }
00707 
00709 void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
00710 {
00711     int elem = nad->ecur - 1;
00712 
00713     _nad_ptr_check(__func__, nad);
00714 
00715     /* make sure this cdata is the child of the last elem to append */
00716     if(nad->elems[elem].depth == depth - 1)
00717     {
00718         if(nad->elems[elem].icdata == 0)
00719             nad->elems[elem].icdata = nad->ccur;
00720         _nad_cdata(nad,cdata,len);
00721         nad->elems[elem].lcdata += len;
00722         return;
00723     }
00724 
00725     /* otherwise, pin the cdata on the tail of the last element at this depth */
00726     elem = nad->depths[depth];
00727     if(nad->elems[elem].itail == 0)
00728         nad->elems[elem].itail = nad->ccur;
00729     _nad_cdata(nad,cdata,len);
00730     nad->elems[elem].ltail += len;
00731 }
00732 
00734 int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
00735 {
00736     int ns;
00737 
00738     _nad_ptr_check(__func__, nad);
00739 
00740     /* only add it if its not already in scope */
00741     ns = nad_find_scoped_namespace(nad, uri, NULL);
00742     if(ns >= 0)
00743         return ns;
00744 
00745     /* make sure there's mem for us */
00746     NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
00747 
00748     ns = nad->ncur;
00749     nad->ncur++;
00750     nad->nss[ns].next = nad->scope;
00751     nad->scope = ns;
00752 
00753     nad->nss[ns].luri = strlen(uri);
00754     nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
00755     if(prefix != NULL)
00756     {
00757         nad->nss[ns].lprefix = strlen(prefix);
00758         nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);    
00759     }
00760     else
00761         nad->nss[ns].iprefix = -1;
00762 
00763     return ns;
00764 }
00765 
00767 int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix) {
00768     int ns;
00769 
00770     _nad_ptr_check(__func__, nad);
00771 
00772     /* see if its already scoped on this element */
00773     ns = nad_find_namespace(nad, elem, uri, NULL);
00774     if(ns >= 0)
00775         return ns;
00776 
00777     /* make some room */
00778     NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
00779 
00780     ns = nad->ncur;
00781     nad->ncur++;
00782     nad->nss[ns].next = nad->elems[elem].ns;
00783     nad->elems[elem].ns = ns;
00784 
00785     nad->nss[ns].luri = strlen(uri);
00786     nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
00787     if(prefix != NULL)
00788     {
00789         nad->nss[ns].lprefix = strlen(prefix);
00790         nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);    
00791     }
00792     else
00793         nad->nss[ns].iprefix = -1;
00794 
00795     return ns;
00796 }
00797 
00798 static void _nad_escape(nad_t nad, int data, int len, int flag)
00799 {
00800     char *c;
00801     int ic;
00802 
00803     if(len <= 0) return;
00804 
00805     /* first, if told, find and escape " */
00806     while(flag >= 4 && (c = memchr(nad->cdata + data,'"',len)) != NULL)
00807     {
00808         /* get offset */
00809         ic = c - nad->cdata;
00810 
00811         /* cute, eh?  handle other data before this normally */
00812         _nad_escape(nad, data, ic - data, 3);
00813 
00814         /* ensure enough space, and add our escaped &quot; */
00815         NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
00816         memcpy(nad->cdata + nad->ccur, "&quot;", 6);
00817         nad->ccur += 6;
00818 
00819         /* just update and loop for more */
00820         len -= (ic+1) - data;
00821         data = ic+1;
00822     }
00823 
00824     /* next, find and escape ' */
00825     while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
00826     {
00827         ic = c - nad->cdata;
00828         _nad_escape(nad, data, ic - data, 2);
00829 
00830         /* ensure enough space, and add our escaped &apos; */
00831         NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
00832         memcpy(nad->cdata + nad->ccur, "&apos;", 6);
00833         nad->ccur += 6;
00834 
00835         /* just update and loop for more */
00836         len -= (ic+1) - data;
00837         data = ic+1;
00838     }
00839 
00840     /* next look for < */
00841     while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
00842     {
00843         ic = c - nad->cdata;
00844         _nad_escape(nad, data, ic - data, 1);
00845 
00846         /* ensure enough space, and add our escaped &lt; */
00847         NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
00848         memcpy(nad->cdata + nad->ccur, "&lt;", 4);
00849         nad->ccur += 4;
00850 
00851         /* just update and loop for more */
00852         len -= (ic+1) - data;
00853         data = ic+1;
00854     }
00855 
00856     /* next look for > */
00857     while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
00858     {
00859         ic = c - nad->cdata;
00860         _nad_escape(nad, data, ic - data, 0);
00861 
00862         /* ensure enough space, and add our escaped &gt; */
00863         NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
00864         memcpy(nad->cdata + nad->ccur, "&gt;", 4);
00865         nad->ccur += 4;
00866 
00867         /* just update and loop for more */
00868         len -= (ic+1) - data;
00869         data = ic+1;
00870     }
00871 
00872     /* if & is found, escape it */
00873     while((c = memchr(nad->cdata + data,'&',len)) != NULL)
00874     {
00875         ic = c - nad->cdata;
00876 
00877         /* ensure enough space */
00878         NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);
00879 
00880         /* handle normal data */
00881         memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
00882         nad->ccur += (ic - data);
00883 
00884         /* append escaped &amp; */
00885         memcpy(nad->cdata + nad->ccur, "&amp;", 5);
00886         nad->ccur += 5;
00887 
00888         /* just update and loop for more */
00889         len -= (ic+1) - data;
00890         data = ic+1;
00891     }
00892 
00893     /* nothing exciting, just append normal cdata */
00894     if(len > 0) {
00895         NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
00896         memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
00897         nad->ccur += len;
00898     }
00899 }
00900 
00902 static int _nad_lp0(nad_t nad, int elem)
00903 {
00904     int attr;
00905     int ndepth;
00906     int ns;
00907 
00908     /* 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 */
00909 
00910     /* this whole thing is in a big loop for processing siblings */
00911     while(elem != nad->ecur)
00912     {
00913 
00914     /* make enough space for the opening element */
00915     ns = nad->elems[elem].my_ns;
00916     if(ns >= 0 && nad->nss[ns].iprefix >= 0)
00917     {
00918         NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen);
00919     } else {
00920         NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen);
00921     }
00922 
00923     /* opening tag */
00924     *(nad->cdata + nad->ccur++) = '<';
00925 
00926     /* add the prefix if necessary */
00927     if(ns >= 0 && nad->nss[ns].iprefix >= 0)
00928     {
00929         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
00930         nad->ccur += nad->nss[ns].lprefix;
00931         *(nad->cdata + nad->ccur++) = ':';
00932     }
00933     
00934     /* copy in the name */
00935     memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
00936     nad->ccur += nad->elems[elem].lname;
00937 
00938     /* add the namespaces */
00939     for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next)
00940     {
00941         /* never explicitly declare the implicit xml namespace */
00942         if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0)
00943             continue;
00944 
00945         /* make space */
00946         if(nad->nss[ns].iprefix >= 0)
00947         {
00948             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
00949         } else {
00950             NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
00951         }
00952 
00953         /* start */
00954         memcpy(nad->cdata + nad->ccur, " xmlns", 6);
00955         nad->ccur += 6;
00956 
00957         /* prefix if necessary */
00958         if(nad->nss[ns].iprefix >= 0)
00959         {
00960             *(nad->cdata + nad->ccur++) = ':';
00961             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
00962             nad->ccur += nad->nss[ns].lprefix;
00963         }
00964 
00965         *(nad->cdata + nad->ccur++) = '=';
00966         *(nad->cdata + nad->ccur++) = '\'';
00967 
00968         /* uri */
00969         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
00970         nad->ccur += nad->nss[ns].luri;
00971 
00972         *(nad->cdata + nad->ccur++) = '\'';
00973     }
00974 
00975     for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next)
00976     {
00977         if(nad->attrs[attr].lname <= 0) continue;
00978 
00979         /* make enough space for the wrapper part */
00980         ns = nad->attrs[attr].my_ns;
00981         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
00982         {
00983             NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen);
00984         } else {
00985             NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen);
00986         }
00987 
00988         *(nad->cdata + nad->ccur++) = ' ';
00989 
00990         /* add the prefix if necessary */
00991         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
00992         {
00993             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
00994             nad->ccur += nad->nss[ns].lprefix;
00995             *(nad->cdata + nad->ccur++) = ':';
00996         }
00997     
00998         /* copy in the name parts */
00999         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname);
01000         nad->ccur += nad->attrs[attr].lname;
01001         *(nad->cdata + nad->ccur++) = '=';
01002         *(nad->cdata + nad->ccur++) = '\'';
01003 
01004         /* copy in the escaped value */
01005         _nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 4);
01006 
01007         /* make enough space for the closing quote and add it */
01008         NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
01009         *(nad->cdata + nad->ccur++) = '\'';
01010     }
01011 
01012     /* figure out what's next */
01013     if(elem+1 == nad->ecur)
01014         ndepth = -1;
01015     else
01016         ndepth = nad->elems[elem+1].depth;
01017 
01018     /* handle based on if there are children, update nelem after done */
01019     if(ndepth <= nad->elems[elem].depth)
01020     {
01021         /* make sure there's enough for what we could need */
01022         NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen);
01023         if(nad->elems[elem].lcdata == 0)
01024         {
01025             memcpy(nad->cdata + nad->ccur, "/>", 2);
01026             nad->ccur += 2;
01027         }else{
01028             *(nad->cdata + nad->ccur++) = '>';
01029 
01030             /* copy in escaped cdata */
01031             _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,4);
01032 
01033             /* make room */
01034             ns = nad->elems[elem].my_ns;
01035             if(ns >= 0 && nad->nss[ns].iprefix >= 0)
01036             {
01037                 NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
01038             } else {
01039                 NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
01040             }
01041 
01042             /* close tag */
01043             memcpy(nad->cdata + nad->ccur, "</", 2);
01044             nad->ccur += 2;
01045     
01046             /* add the prefix if necessary */
01047             if(ns >= 0 && nad->nss[ns].iprefix >= 0)
01048             {
01049                 memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
01050                 nad->ccur += nad->nss[ns].lprefix;
01051                 *(nad->cdata + nad->ccur++) = ':';
01052             }
01053     
01054             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
01055             nad->ccur += nad->elems[elem].lname;
01056             *(nad->cdata + nad->ccur++) = '>';
01057         }
01058 
01059         /* always try to append the tail */
01060         _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);
01061 
01062         /* if no siblings either, bail */
01063         if(ndepth < nad->elems[elem].depth)
01064             return elem+1;
01065 
01066         /* next sibling */
01067         elem++;
01068     }else{
01069         int nelem;
01070         /* process any children */
01071 
01072         /* close ourself and append any cdata first */
01073         NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
01074         *(nad->cdata + nad->ccur++) = '>';
01075         _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,4);
01076 
01077         /* process children */
01078         nelem = _nad_lp0(nad,elem+1);
01079 
01080         /* close and tail up */
01081         ns = nad->elems[elem].my_ns;
01082         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
01083         {
01084             NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
01085         } else {
01086             NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
01087         }
01088         memcpy(nad->cdata + nad->ccur, "</", 2);
01089         nad->ccur += 2;
01090         if(ns >= 0 && nad->nss[ns].iprefix >= 0)
01091         {
01092             memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
01093             nad->ccur += nad->nss[ns].lprefix;
01094             *(nad->cdata + nad->ccur++) = ':';
01095         }
01096         memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
01097         nad->ccur += nad->elems[elem].lname;
01098         *(nad->cdata + nad->ccur++) = '>';
01099         _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);
01100 
01101         /* if the next element is not our sibling, we're done */
01102         if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth)
01103             return nelem;
01104 
01105         /* for next sibling in while loop */
01106         elem = nelem;
01107     }
01108 
01109     /* here's the end of that big while loop */
01110     }
01111 
01112     return elem;
01113 }
01114 
01115 void nad_print(nad_t nad, int elem, char **xml, int *len)
01116 {
01117     int ixml = nad->ccur;
01118 
01119     _nad_ptr_check(__func__, nad);
01120 
01121     _nad_lp0(nad,elem);
01122     *len = nad->ccur - ixml;
01123     *xml = nad->cdata + ixml;
01124 }
01125 
01143 void nad_serialize(nad_t nad, char **buf, int *len) {
01144     char *pos;
01145 
01146     _nad_ptr_check(__func__, nad);
01147 
01148     *len = sizeof(int) * 5 + /* 4 ints in nad_t, plus one for len */
01149            sizeof(struct nad_elem_st) * nad->ecur +
01150            sizeof(struct nad_attr_st) * nad->acur +
01151            sizeof(struct nad_ns_st) * nad->ncur +
01152            sizeof(char) * nad->ccur;
01153 
01154     *buf = (char *) malloc(*len);
01155     pos = *buf;
01156 
01157     * (int *) pos = *len;       pos += sizeof(int);
01158     * (int *) pos = nad->ecur;  pos += sizeof(int);
01159     * (int *) pos = nad->acur;  pos += sizeof(int);
01160     * (int *) pos = nad->ncur;  pos += sizeof(int);
01161     * (int *) pos = nad->ccur;  pos += sizeof(int);
01162 
01163     memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur);    pos += sizeof(struct nad_elem_st) * nad->ecur;
01164     memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur);    pos += sizeof(struct nad_attr_st) * nad->acur;
01165     memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur);        pos += sizeof(struct nad_ns_st) * nad->ncur;
01166     memcpy(pos, nad->cdata, sizeof(char) * nad->ccur);
01167 }
01168 
01169 nad_t nad_deserialize(const char *buf) {
01170     nad_t nad = nad_new();
01171     const char *pos = buf + sizeof(int);  /* skip len */
01172 
01173     _nad_ptr_check(__func__, nad);
01174 
01175     nad->ecur = * (int *) pos; pos += sizeof(int);
01176     nad->acur = * (int *) pos; pos += sizeof(int);
01177     nad->ncur = * (int *) pos; pos += sizeof(int);
01178     nad->ccur = * (int *) pos; pos += sizeof(int);
01179     nad->elen = nad->ecur;
01180     nad->alen = nad->acur;
01181     nad->nlen = nad->ncur;
01182     nad->clen = nad->ccur;
01183 
01184     if(nad->ecur > 0)
01185     {
01186         nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur);
01187         memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur);
01188         pos += sizeof(struct nad_elem_st) * nad->ecur;
01189     }
01190 
01191     if(nad->acur > 0)
01192     {
01193         nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur);
01194         memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur);
01195         pos += sizeof(struct nad_attr_st) * nad->acur;
01196     }
01197 
01198     if(nad->ncur > 0)
01199     {
01200         nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur);
01201         memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur);
01202         pos += sizeof(struct nad_ns_st) * nad->ncur;
01203     }
01204 
01205     if(nad->ccur > 0)
01206     {
01207         nad->cdata = (char *) malloc(sizeof(char) * nad->ccur);
01208         memcpy(nad->cdata, pos, sizeof(char) * nad->ccur);
01209     }
01210 
01211     return nad;
01212 }
01213 
01214 
01217 struct build_data {
01218     nad_t               nad;
01219     int                 depth;
01220     XML_Parser          p;
01221 };
01222 
01223 static void _nad_parse_element_start(void *arg, const char *name, const char **atts) {
01224     struct build_data *bd = (struct build_data *) arg;
01225     char buf[1024];
01226     char *uri, *elem, *prefix;
01227     const char **attr;
01228     int el, ns;
01229 
01230     /* make a copy */
01231     strncpy(buf, name, 1024);
01232     buf[1023] = '\0';
01233 
01234     /* expat gives us:
01235          prefixed namespaced elem: uri|elem|prefix
01236           default namespaced elem: uri|elem
01237                un-namespaced elem: elem
01238      */
01239 
01240     /* extract all the bits */
01241     uri = buf;
01242     elem = strchr(uri, '|');
01243     if(elem != NULL) {
01244         *elem = '\0';
01245         elem++;
01246         prefix = strchr(elem, '|');
01247         if(prefix != NULL) {
01248             *prefix = '\0';
01249             prefix++;
01250         }
01251         ns = nad_add_namespace(bd->nad, uri, prefix);
01252     } else {
01253         /* un-namespaced, just take it as-is */
01254         uri = NULL;
01255         elem = buf;
01256         prefix = NULL;
01257         ns = -1;
01258     }
01259 
01260     /* add it */
01261     el = nad_append_elem(bd->nad, ns, elem, bd->depth);
01262 
01263     /* now the attributes, one at a time */
01264     attr = atts;
01265     while(attr[0] != NULL) {
01266 
01267         /* make a copy */
01268         strncpy(buf, attr[0], 1024);
01269         buf[1023] = '\0';
01270 
01271         /* extract all the bits */
01272         uri = buf;
01273         elem = strchr(uri, '|');
01274         if(elem != NULL) {
01275             *elem = '\0';
01276             elem++;
01277             prefix = strchr(elem, '|');
01278             if(prefix != NULL) {
01279                 *prefix = '\0';
01280                 prefix++;
01281             }
01282             ns = nad_append_namespace(bd->nad, el, uri, prefix);
01283         } else {
01284             /* un-namespaced, just take it as-is */
01285             uri = NULL;
01286             elem = buf;
01287             prefix = NULL;
01288             ns = -1;
01289         }
01290 
01291         /* add it */
01292         nad_append_attr(bd->nad, ns, elem, (char *) attr[1]);
01293 
01294         attr += 2;
01295     }
01296 
01297     bd->depth++;
01298 }
01299 
01300 static void _nad_parse_element_end(void *arg, const char *name) {
01301     struct build_data *bd = (struct build_data *) arg;
01302 
01303     bd->depth--;
01304 }
01305 
01306 static void _nad_parse_cdata(void *arg, const char *str, int len) {
01307     struct build_data *bd = (struct build_data *) arg;
01308 
01309     /* go */
01310     nad_append_cdata(bd->nad, (char *) str, len, bd->depth);
01311 }
01312 
01313 static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri) {
01314     struct build_data *bd = (struct build_data *) arg;
01315     int ns;
01316 
01317     ns = nad_add_namespace(bd->nad, (char *) uri, (char *) prefix);
01318 
01319     /* Always set the namespace (to catch cases where nad_add_namespace doesn't add it) */
01320     bd->nad->scope = ns; 
01321 }
01322 
01323 #ifdef HAVE_XML_STOPPARSER
01324 /* Stop the parser if an entity declaration is hit. */
01325 static void _nad_parse_entity_declaration(void *arg, const char *entityName,
01326                                           int is_parameter_entity, const char *value,
01327                                           int value_length, const char *base,
01328                                           const char *systemId, const char *publicId,
01329                                           const char *notationName)
01330 {
01331     struct build_data *bd = (struct build_data *) arg;
01332 
01333     XML_StopParser(bd->p, XML_FALSE);
01334 }
01335 #endif
01336 
01337 nad_t nad_parse(const char *buf, int len) {
01338     struct build_data bd;
01339     XML_Parser p;
01340 
01341     if(len == 0)
01342         len = strlen(buf);
01343 
01344     p = XML_ParserCreateNS(NULL, '|');
01345     if(p == NULL)
01346         return NULL;
01347     bd.p = p;
01348 
01349     XML_SetReturnNSTriplet(p, 1);
01350     /* Prevent the "billion laughs" attack against expat by disabling
01351      * internal entity expansion.  With 2.x, forcibly stop the parser
01352      * if an entity is declared - this is safer and a more obvious
01353      * failure mode.  With older versions, simply prevent expenansion
01354      * of such entities. */
01355 #ifdef HAVE_XML_STOPPARSER
01356     XML_SetEntityDeclHandler(p, (void *) _nad_parse_entity_declaration);
01357 #else
01358     XML_SetDefaultHandler(p, NULL);
01359 #endif
01360 
01361     bd.nad = nad_new();
01362     bd.depth = 0;
01363 
01364     XML_SetUserData(p, (void *) &bd);
01365     XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
01366     XML_SetCharacterDataHandler(p, _nad_parse_cdata);
01367     XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);
01368 
01369     if(!XML_Parse(p, buf, len, 1)) {
01370         XML_ParserFree(p);
01371         nad_free(bd.nad);
01372         return NULL;
01373     }
01374 
01375     XML_ParserFree(p);
01376 
01377     if(bd.depth != 0)
01378         return NULL;
01379 
01380     return bd.nad;
01381 }