jabberd2
2.2.16
|
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 " */ 00815 NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen); 00816 memcpy(nad->cdata + nad->ccur, """, 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 ' */ 00831 NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen); 00832 memcpy(nad->cdata + nad->ccur, "'", 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 < */ 00847 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen); 00848 memcpy(nad->cdata + nad->ccur, "<", 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 > */ 00863 NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen); 00864 memcpy(nad->cdata + nad->ccur, ">", 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 & */ 00885 memcpy(nad->cdata + nad->ccur, "&", 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 }