Tue, 07 Jan 2003 20:57:48 +0000
[gaim-migrate @ 4474]
Is it ironic that I use Time Warner cable to help develope an
AIM client?
| 3127 | 1 | /* -------------------------------------------------------------------------- |
| 2 | * | |
| 3 | * License | |
| 4 | * | |
| 5 | * The contents of this file are subject to the Jabber Open Source License | |
| 6 | * Version 1.0 (the "JOSL"). You may not copy or use this file, in either | |
| 7 | * source code or executable form, except in compliance with the JOSL. You | |
| 8 | * may obtain a copy of the JOSL at http://www.jabber.org/ or at | |
| 9 | * http://www.opensource.org/. | |
| 10 | * | |
| 11 | * Software distributed under the JOSL is distributed on an "AS IS" basis, | |
| 12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL | |
| 13 | * for the specific language governing rights and limitations under the | |
| 14 | * JOSL. | |
| 15 | * | |
| 16 | * Copyrights | |
| 17 | * | |
| 18 | * Portions created by or assigned to Jabber.com, Inc. are | |
| 19 | * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact | |
| 20 | * information for Jabber.com, Inc. is available at http://www.jabber.com/. | |
| 2086 | 21 | * |
| 3127 | 22 | * Portions Copyright (c) 1998-1999 Jeremie Miller. |
| 23 | * | |
| 24 | * Acknowledgements | |
| 25 | * | |
| 26 | * Special thanks to the Jabber Open Source Contributors for their | |
| 27 | * suggestions and support of Jabber. | |
| 28 | * | |
| 29 | * Alternatively, the contents of this file may be used under the terms of the | |
| 30 | * GNU General Public License Version 2 or later (the "GPL"), in which case | |
| 31 | * the provisions of the GPL are applicable instead of those above. If you | |
| 32 | * wish to allow use of your version of this file only under the terms of the | |
| 33 | * GPL and not to allow others to use your version of this file under the JOSL, | |
| 34 | * indicate your decision by deleting the provisions above and replace them | |
| 35 | * with the notice and other provisions required by the GPL. If you do not | |
| 36 | * delete the provisions above, a recipient may use your version of this file | |
| 37 | * under either the JOSL or the GPL. | |
| 38 | * | |
| 39 | * | |
| 40 | * --------------------------------------------------------------------------*/ | |
| 2086 | 41 | |
| 3127 | 42 | #include "lib.h" |
| 2086 | 43 | |
| 44 | /* Internal routines */ | |
| 45 | xmlnode _xmlnode_new(pool p, const char* name, unsigned int type) | |
| 46 | { | |
| 47 | xmlnode result = NULL; | |
| 48 | if (type > NTYPE_LAST) | |
| 49 | return NULL; | |
| 50 | ||
| 51 | if (type != NTYPE_CDATA && name == NULL) | |
| 52 | return NULL; | |
| 53 | ||
| 54 | if (p == NULL) | |
| 55 | { | |
| 56 | p = pool_heap(1*1024); | |
| 57 | } | |
| 58 | ||
| 59 | /* Allocate & zero memory */ | |
| 3127 | 60 | result = (xmlnode)pmalloco(p, sizeof(_xmlnode)); |
| 2086 | 61 | |
| 62 | /* Initialize fields */ | |
| 63 | if (type != NTYPE_CDATA) | |
| 64 | result->name = pstrdup(p,name); | |
| 65 | result->type = type; | |
| 66 | result->p = p; | |
| 67 | return result; | |
| 68 | } | |
| 69 | ||
| 70 | static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type) | |
| 71 | { | |
| 72 | xmlnode result; | |
| 73 | ||
| 74 | result = _xmlnode_new(xmlnode_pool(lastsibling), name, type); | |
| 75 | if (result != NULL) | |
| 76 | { | |
| 77 | /* Setup sibling pointers */ | |
| 78 | result->prev = lastsibling; | |
| 79 | lastsibling->next = result; | |
| 80 | } | |
| 81 | return result; | |
| 82 | } | |
| 83 | ||
| 84 | static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type) | |
| 85 | { | |
| 86 | xmlnode result; | |
| 87 | ||
| 3127 | 88 | if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL; |
| 2086 | 89 | |
| 90 | /* If parent->firstchild is NULL, simply create a new node for the first child */ | |
| 91 | if (parent->firstchild == NULL) | |
| 92 | { | |
| 93 | result = _xmlnode_new(parent->p, name, type); | |
| 94 | parent->firstchild = result; | |
| 95 | } | |
| 96 | /* Otherwise, append this to the lastchild */ | |
| 97 | else | |
| 98 | { | |
| 99 | result= _xmlnode_append_sibling(parent->lastchild, name, type); | |
| 100 | } | |
| 101 | result->parent = parent; | |
| 102 | parent->lastchild = result; | |
| 103 | return result; | |
| 104 | ||
| 105 | } | |
| 106 | ||
| 107 | static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type) | |
| 108 | { | |
| 109 | xmlnode current; | |
| 110 | ||
| 111 | /* Walk the sibling list, looking for a NTYPE_TAG xmlnode with | |
| 112 | the specified name */ | |
| 113 | current = firstsibling; | |
| 114 | while (current != NULL) | |
| 115 | { | |
| 116 | if ((current->type == type) && (j_strcmp(current->name, name) == 0)) | |
| 117 | return current; | |
| 118 | else | |
| 119 | current = current->next; | |
| 120 | } | |
| 121 | return NULL; | |
| 122 | } | |
| 123 | ||
| 3127 | 124 | void _xmlnode_merge(xmlnode data) |
| 2086 | 125 | { |
| 3127 | 126 | xmlnode cur; |
| 127 | char *merge, *scur; | |
| 128 | int imerge; | |
| 129 | ||
| 130 | /* get total size of all merged cdata */ | |
| 131 | imerge = 0; | |
| 132 | for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next) | |
| 133 | imerge += cur->data_sz; | |
| 2086 | 134 | |
| 3127 | 135 | /* copy in current data and then spin through all of them and merge */ |
| 136 | scur = merge = pmalloc(data->p,imerge + 1); | |
| 137 | for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next) | |
| 138 | { | |
| 139 | memcpy(scur,cur->data,cur->data_sz); | |
| 140 | scur += cur->data_sz; | |
| 141 | } | |
| 142 | *scur = '\0'; | |
| 2086 | 143 | |
| 3127 | 144 | /* this effectively hides all of the merged-in chunks */ |
| 145 | data->next = cur; | |
| 146 | if(cur == NULL) | |
| 147 | data->parent->lastchild = data; | |
| 148 | else | |
| 149 | cur->prev = data; | |
| 150 | ||
| 151 | /* reset data */ | |
| 152 | data->data = merge; | |
| 153 | data->data_sz = imerge; | |
| 154 | ||
| 2086 | 155 | } |
| 156 | ||
| 157 | static void _xmlnode_hide_sibling(xmlnode child) | |
| 158 | { | |
| 159 | if(child == NULL) | |
| 160 | return; | |
| 161 | ||
| 162 | if(child->prev != NULL) | |
| 163 | child->prev->next = child->next; | |
| 164 | if(child->next != NULL) | |
| 165 | child->next->prev = child->prev; | |
| 166 | } | |
| 167 | ||
| 168 | void _xmlnode_tag2str(spool s, xmlnode node, int flag) | |
| 169 | { | |
| 170 | xmlnode tmp; | |
| 171 | ||
| 172 | if(flag==0 || flag==1) | |
| 173 | { | |
| 174 | spooler(s,"<",xmlnode_get_name(node),s); | |
| 175 | tmp = xmlnode_get_firstattrib(node); | |
| 176 | while(tmp) { | |
| 177 | spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp)),"'",s); | |
| 178 | tmp = xmlnode_get_nextsibling(tmp); | |
| 179 | } | |
| 180 | if(flag==0) | |
| 181 | spool_add(s,"/>"); | |
| 182 | else | |
| 183 | spool_add(s,">"); | |
| 184 | } | |
| 185 | else | |
| 186 | { | |
| 187 | spooler(s,"</",xmlnode_get_name(node),">",s); | |
| 188 | } | |
| 189 | } | |
| 190 | ||
| 191 | spool _xmlnode2spool(xmlnode node) | |
| 192 | { | |
| 193 | spool s; | |
| 194 | int level=0,dir=0; | |
| 195 | xmlnode tmp; | |
| 196 | ||
| 197 | if(!node || xmlnode_get_type(node)!=NTYPE_TAG) | |
| 3127 | 198 | return NULL; |
| 2086 | 199 | |
| 200 | s = spool_new(xmlnode_pool(node)); | |
| 201 | if(!s) return(NULL); | |
| 202 | ||
| 203 | while(1) | |
| 204 | { | |
| 205 | if(dir==0) | |
| 206 | { | |
| 207 | if(xmlnode_get_type(node) == NTYPE_TAG) | |
| 208 | { | |
| 3127 | 209 | if(xmlnode_has_children(node)) |
| 2086 | 210 | { |
| 3127 | 211 | _xmlnode_tag2str(s,node,1); |
| 212 | node = xmlnode_get_firstchild(node); | |
| 213 | level++; | |
| 214 | continue; | |
| 215 | }else{ | |
| 216 | _xmlnode_tag2str(s,node,0); | |
| 217 | } | |
| 218 | }else{ | |
| 219 | spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node))); | |
| 220 | } | |
| 221 | } | |
| 2086 | 222 | |
| 223 | tmp = xmlnode_get_nextsibling(node); | |
| 3127 | 224 | if(!tmp) |
| 2086 | 225 | { |
| 3127 | 226 | node = xmlnode_get_parent(node); |
| 227 | level--; | |
| 228 | if(level>=0) _xmlnode_tag2str(s,node,2); | |
| 229 | if(level<1) break; | |
| 230 | dir = 1; | |
| 231 | }else{ | |
| 232 | node = tmp; | |
| 233 | dir = 0; | |
| 234 | } | |
| 2086 | 235 | } |
| 236 | ||
| 237 | return s; | |
| 238 | } | |
| 239 | ||
| 240 | ||
| 241 | /* External routines */ | |
| 242 | ||
| 243 | ||
| 244 | /* | |
| 245 | * xmlnode_new_tag -- create a tag node | |
| 246 | * Automatically creates a memory pool for the node. | |
| 247 | * | |
| 248 | * parameters | |
| 249 | * name -- name of the tag | |
| 250 | * | |
| 251 | * returns | |
| 252 | * a pointer to the tag node | |
| 253 | * or NULL if it was unsuccessfull | |
| 254 | */ | |
| 255 | xmlnode xmlnode_new_tag(const char* name) | |
| 256 | { | |
| 257 | return _xmlnode_new(NULL, name, NTYPE_TAG); | |
| 258 | } | |
| 259 | ||
| 260 | ||
| 261 | /* | |
| 262 | * xmlnode_new_tag_pool -- create a tag node within given pool | |
| 263 | * | |
| 264 | * parameters | |
| 265 | * p -- previously created memory pool | |
| 266 | * name -- name of the tag | |
| 267 | * | |
| 268 | * returns | |
| 269 | * a pointer to the tag node | |
| 270 | * or NULL if it was unsuccessfull | |
| 271 | */ | |
| 272 | xmlnode xmlnode_new_tag_pool(pool p, const char* name) | |
| 273 | { | |
| 274 | return _xmlnode_new(p, name, NTYPE_TAG); | |
| 275 | } | |
| 276 | ||
| 277 | ||
| 278 | /* | |
| 279 | * xmlnode_insert_tag -- append a child tag to a tag | |
| 280 | * | |
| 281 | * parameters | |
| 282 | * parent -- pointer to the parent tag | |
| 283 | * name -- name of the child tag | |
| 284 | * | |
| 285 | * returns | |
| 286 | * a pointer to the child tag node | |
| 287 | * or NULL if it was unsuccessfull | |
| 288 | */ | |
| 289 | xmlnode xmlnode_insert_tag(xmlnode parent, const char* name) | |
| 290 | { | |
| 291 | return _xmlnode_insert(parent, name, NTYPE_TAG); | |
| 292 | } | |
| 293 | ||
| 294 | ||
| 295 | /* | |
| 296 | * xmlnode_insert_cdata -- append character data to a tag | |
| 297 | * | |
| 298 | * parameters | |
| 299 | * parent -- parent tag | |
| 300 | * CDATA -- character data | |
| 301 | * size -- size of CDATA | |
| 302 | * or -1 for null-terminated CDATA strings | |
| 303 | * | |
| 304 | * returns | |
| 305 | * a pointer to the child CDATA node | |
| 306 | * or NULL if it was unsuccessfull | |
| 307 | */ | |
| 308 | xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size) | |
| 309 | { | |
| 310 | xmlnode result; | |
| 311 | ||
| 312 | if(CDATA == NULL || parent == NULL) | |
| 313 | return NULL; | |
| 314 | ||
| 315 | if(size == -1) | |
| 316 | size = strlen(CDATA); | |
| 317 | ||
| 3127 | 318 | result = _xmlnode_insert(parent, NULL, NTYPE_CDATA); |
| 319 | if (result != NULL) | |
| 2086 | 320 | { |
| 3127 | 321 | result->data = (char*)pmalloc(result->p, size + 1); |
| 322 | memcpy(result->data, CDATA, size); | |
| 323 | result->data[size] = '\0'; | |
| 324 | result->data_sz = size; | |
| 2086 | 325 | } |
| 326 | ||
| 327 | return result; | |
| 328 | } | |
| 329 | ||
| 330 | ||
| 331 | /* | |
| 332 | * xmlnode_get_tag -- find given tag in an xmlnode tree | |
| 333 | * | |
| 334 | * parameters | |
| 335 | * parent -- pointer to the parent tag | |
| 336 | * name -- "name" for the child tag of that name | |
| 337 | * "name/name" for a sub child (recurses) | |
| 338 | * "?attrib" to match the first tag with that attrib defined | |
| 339 | * "?attrib=value" to match the first tag with that attrib and value | |
| 3127 | 340 | * "=cdata" to match the cdata contents of the child |
| 341 | * or any combination: "name/name/?attrib", "name=cdata", etc | |
| 2086 | 342 | * |
| 343 | * results | |
| 344 | * a pointer to the tag matching search criteria | |
| 345 | * or NULL if search was unsuccessfull | |
| 346 | */ | |
| 347 | xmlnode xmlnode_get_tag(xmlnode parent, const char* name) | |
| 348 | { | |
| 349 | char *str, *slash, *qmark, *equals; | |
| 350 | xmlnode step, ret; | |
| 351 | ||
| 3127 | 352 | |
| 2086 | 353 | if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; |
| 354 | ||
| 3127 | 355 | if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL) |
| 2086 | 356 | return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); |
| 357 | ||
| 358 | str = strdup(name); | |
| 359 | slash = strstr(str, "/"); | |
| 360 | qmark = strstr(str, "?"); | |
| 361 | equals = strstr(str, "="); | |
| 362 | ||
| 3127 | 363 | if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark)) |
| 364 | { /* of type =cdata */ | |
| 365 | ||
| 366 | *equals = '\0'; | |
| 367 | equals++; | |
| 368 | ||
| 369 | for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | |
| 370 | { | |
| 371 | if(xmlnode_get_type(step) != NTYPE_TAG) | |
| 372 | continue; | |
| 373 | ||
| 374 | if(*str != '\0') | |
| 375 | if(j_strcmp(xmlnode_get_name(step),str) != 0) | |
| 376 | continue; | |
| 377 | ||
| 378 | if(j_strcmp(xmlnode_get_data(step),equals) != 0) | |
| 379 | continue; | |
| 380 | ||
| 381 | break; | |
| 382 | } | |
| 383 | ||
| 384 | free(str); | |
| 385 | return step; | |
| 386 | } | |
| 387 | ||
| 388 | ||
| 2086 | 389 | if(qmark != NULL && (slash == NULL || qmark < slash)) |
| 390 | { /* of type ?attrib */ | |
| 391 | ||
| 392 | *qmark = '\0'; | |
| 393 | qmark++; | |
| 394 | if(equals != NULL) | |
| 395 | { | |
| 396 | *equals = '\0'; | |
| 397 | equals++; | |
| 398 | } | |
| 399 | ||
| 400 | for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | |
| 401 | { | |
| 402 | if(xmlnode_get_type(step) != NTYPE_TAG) | |
| 403 | continue; | |
| 404 | ||
| 405 | if(*str != '\0') | |
| 406 | if(j_strcmp(xmlnode_get_name(step),str) != 0) | |
| 407 | continue; | |
| 408 | ||
| 409 | if(xmlnode_get_attrib(step,qmark) == NULL) | |
| 410 | continue; | |
| 411 | ||
| 412 | if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0) | |
| 413 | continue; | |
| 414 | ||
| 415 | break; | |
| 416 | } | |
| 417 | ||
| 418 | free(str); | |
| 419 | return step; | |
| 420 | } | |
| 421 | ||
| 422 | ||
| 423 | *slash = '\0'; | |
| 424 | ++slash; | |
| 425 | ||
| 426 | for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | |
| 427 | { | |
| 428 | if(xmlnode_get_type(step) != NTYPE_TAG) continue; | |
| 429 | ||
| 430 | if(j_strcmp(xmlnode_get_name(step),str) != 0) | |
| 431 | continue; | |
| 432 | ||
| 433 | ret = xmlnode_get_tag(step, slash); | |
| 434 | if(ret != NULL) | |
| 435 | { | |
| 436 | free(str); | |
| 437 | return ret; | |
| 438 | } | |
| 439 | } | |
| 440 | ||
| 441 | free(str); | |
| 442 | return NULL; | |
| 443 | } | |
| 444 | ||
| 445 | ||
| 446 | /* return the cdata from any tag */ | |
| 447 | char *xmlnode_get_tag_data(xmlnode parent, const char *name) | |
| 448 | { | |
| 449 | xmlnode tag; | |
| 450 | ||
| 451 | tag = xmlnode_get_tag(parent, name); | |
| 452 | if(tag == NULL) return NULL; | |
| 453 | ||
| 454 | return xmlnode_get_data(tag); | |
| 455 | } | |
| 456 | ||
| 457 | ||
| 458 | void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value) | |
| 459 | { | |
| 460 | xmlnode attrib; | |
| 461 | ||
| 462 | if(owner == NULL || name == NULL || value == NULL) return; | |
| 463 | ||
| 464 | /* If there are no existing attributs, allocate a new one to start | |
| 465 | the list */ | |
| 466 | if (owner->firstattrib == NULL) | |
| 467 | { | |
| 468 | attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB); | |
| 469 | owner->firstattrib = attrib; | |
| 470 | owner->lastattrib = attrib; | |
| 471 | } | |
| 472 | else | |
| 473 | { | |
| 474 | attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
| 475 | if(attrib == NULL) | |
| 476 | { | |
| 477 | attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB); | |
| 478 | owner->lastattrib = attrib; | |
| 479 | } | |
| 480 | } | |
| 481 | /* Update the value of the attribute */ | |
| 482 | attrib->data_sz = strlen(value); | |
| 483 | attrib->data = pstrdup(owner->p, value); | |
| 484 | ||
| 485 | } | |
| 486 | ||
| 487 | char* xmlnode_get_attrib(xmlnode owner, const char* name) | |
| 488 | { | |
| 489 | xmlnode attrib; | |
| 490 | ||
| 491 | if (owner != NULL && owner->firstattrib != NULL) | |
| 492 | { | |
| 493 | attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
| 494 | if (attrib != NULL) | |
| 495 | return (char*)attrib->data; | |
| 496 | } | |
| 497 | return NULL; | |
| 498 | } | |
| 499 | ||
| 500 | void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value) | |
| 501 | { | |
| 502 | xmlnode attrib; | |
| 503 | ||
| 504 | if (owner != NULL) | |
| 505 | { | |
| 506 | attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
| 507 | if (attrib == NULL) | |
| 508 | { | |
| 509 | xmlnode_put_attrib(owner, name, ""); | |
| 510 | attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
| 511 | } | |
| 512 | if (attrib != NULL) | |
| 513 | attrib->firstchild = (xmlnode)value; | |
| 514 | } | |
| 515 | } | |
| 516 | ||
| 517 | void* xmlnode_get_vattrib(xmlnode owner, const char* name) | |
| 518 | { | |
| 519 | xmlnode attrib; | |
| 520 | ||
| 521 | if (owner != NULL && owner->firstattrib != NULL) | |
| 522 | { | |
| 523 | attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | |
| 524 | if (attrib != NULL) | |
| 525 | return (void*)attrib->firstchild; | |
| 526 | } | |
| 527 | return NULL; | |
| 528 | } | |
| 529 | ||
| 530 | xmlnode xmlnode_get_firstattrib(xmlnode parent) | |
| 531 | { | |
| 532 | if (parent != NULL) | |
| 533 | return parent->firstattrib; | |
| 534 | return NULL; | |
| 535 | } | |
| 536 | ||
| 537 | xmlnode xmlnode_get_firstchild(xmlnode parent) | |
| 538 | { | |
| 539 | if (parent != NULL) | |
| 540 | return parent->firstchild; | |
| 541 | return NULL; | |
| 542 | } | |
| 543 | ||
| 544 | xmlnode xmlnode_get_lastchild(xmlnode parent) | |
| 545 | { | |
| 546 | if (parent != NULL) | |
| 547 | return parent->lastchild; | |
| 548 | return NULL; | |
| 549 | } | |
| 550 | ||
| 551 | xmlnode xmlnode_get_nextsibling(xmlnode sibling) | |
| 552 | { | |
| 553 | if (sibling != NULL) | |
| 554 | return sibling->next; | |
| 555 | return NULL; | |
| 556 | } | |
| 557 | ||
| 558 | xmlnode xmlnode_get_prevsibling(xmlnode sibling) | |
| 559 | { | |
| 560 | if (sibling != NULL) | |
| 561 | return sibling->prev; | |
| 562 | return NULL; | |
| 563 | } | |
| 564 | ||
| 565 | xmlnode xmlnode_get_parent(xmlnode node) | |
| 566 | { | |
| 567 | if (node != NULL) | |
| 568 | return node->parent; | |
| 569 | return NULL; | |
| 570 | } | |
| 571 | ||
| 572 | char* xmlnode_get_name(xmlnode node) | |
| 573 | { | |
| 574 | if (node != NULL) | |
| 575 | return node->name; | |
| 576 | return NULL; | |
| 577 | } | |
| 578 | ||
| 579 | char* xmlnode_get_data(xmlnode node) | |
| 580 | { | |
| 3127 | 581 | if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */ |
| 582 | for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node)) | |
| 583 | if(xmlnode_get_type(node) == NTYPE_CDATA) break; | |
| 2086 | 584 | |
| 585 | if(node == NULL) return NULL; | |
| 586 | ||
| 3127 | 587 | /* check for a dirty node w/ unassembled cdata chunks */ |
| 588 | if(xmlnode_get_type(node->next) == NTYPE_CDATA) | |
| 589 | _xmlnode_merge(node); | |
| 590 | ||
| 591 | return node->data; | |
| 2086 | 592 | } |
| 593 | ||
| 594 | int xmlnode_get_datasz(xmlnode node) | |
| 595 | { | |
| 3127 | 596 | if(xmlnode_get_type(node) != NTYPE_CDATA) return 0; |
| 597 | ||
| 598 | /* check for a dirty node w/ unassembled cdata chunks */ | |
| 599 | if(xmlnode_get_type(node->next) == NTYPE_CDATA) | |
| 600 | _xmlnode_merge(node); | |
| 601 | return node->data_sz; | |
| 2086 | 602 | } |
| 603 | ||
| 604 | int xmlnode_get_type(xmlnode node) | |
| 605 | { | |
| 606 | if (node != NULL) | |
| 607 | return node->type; | |
| 3127 | 608 | return NTYPE_UNDEF; |
| 2086 | 609 | } |
| 610 | ||
| 611 | int xmlnode_has_children(xmlnode node) | |
| 612 | { | |
| 613 | if ((node != NULL) && (node->firstchild != NULL)) | |
| 614 | return 1; | |
| 615 | return 0; | |
| 616 | } | |
| 617 | ||
| 618 | int xmlnode_has_attribs(xmlnode node) | |
| 619 | { | |
| 620 | if ((node != NULL) && (node->firstattrib != NULL)) | |
| 621 | return 1; | |
| 622 | return 0; | |
| 623 | } | |
| 624 | ||
| 625 | pool xmlnode_pool(xmlnode node) | |
| 626 | { | |
| 627 | if (node != NULL) | |
| 628 | return node->p; | |
| 629 | return (pool)NULL; | |
| 630 | } | |
| 631 | ||
| 632 | void xmlnode_hide(xmlnode child) | |
| 633 | { | |
| 634 | xmlnode parent; | |
| 635 | ||
| 636 | if(child == NULL || child->parent == NULL) | |
| 637 | return; | |
| 638 | ||
| 639 | parent = child->parent; | |
| 640 | ||
| 641 | /* first fix up at the child level */ | |
| 642 | _xmlnode_hide_sibling(child); | |
| 643 | ||
| 644 | /* next fix up at the parent level */ | |
| 645 | if(parent->firstchild == child) | |
| 646 | parent->firstchild = child->next; | |
| 647 | if(parent->lastchild == child) | |
| 648 | parent->lastchild = child->prev; | |
| 649 | } | |
| 650 | ||
| 651 | void xmlnode_hide_attrib(xmlnode parent, const char *name) | |
| 652 | { | |
| 653 | xmlnode attrib; | |
| 654 | ||
| 655 | if(parent == NULL || parent->firstattrib == NULL || name == NULL) | |
| 656 | return; | |
| 657 | ||
| 658 | attrib = _xmlnode_search(parent->firstattrib, name, NTYPE_ATTRIB); | |
| 659 | if(attrib == NULL) | |
| 660 | return; | |
| 661 | ||
| 662 | /* first fix up at the child level */ | |
| 663 | _xmlnode_hide_sibling(attrib); | |
| 664 | ||
| 665 | /* next fix up at the parent level */ | |
| 666 | if(parent->firstattrib == attrib) | |
| 667 | parent->firstattrib = attrib->next; | |
| 668 | if(parent->lastattrib == attrib) | |
| 669 | parent->lastattrib = attrib->prev; | |
| 670 | } | |
| 671 | ||
| 672 | ||
| 673 | ||
| 674 | /* | |
| 675 | * xmlnode2str -- convert given xmlnode tree into a string | |
| 676 | * | |
| 677 | * parameters | |
| 678 | * node -- pointer to the xmlnode structure | |
| 679 | * | |
| 680 | * results | |
| 681 | * a pointer to the created string | |
| 682 | * or NULL if it was unsuccessfull | |
| 683 | */ | |
| 684 | char *xmlnode2str(xmlnode node) | |
| 685 | { | |
| 686 | return spool_print(_xmlnode2spool(node)); | |
| 687 | } | |
| 688 | ||
| 689 | /* | |
| 690 | * xmlnode2tstr -- convert given xmlnode tree into a newline terminated string | |
| 691 | * | |
| 692 | * parameters | |
| 693 | * node -- pointer to the xmlnode structure | |
| 694 | * | |
| 695 | * results | |
| 696 | * a pointer to the created string | |
| 697 | * or NULL if it was unsuccessfull | |
| 698 | */ | |
| 699 | char* xmlnode2tstr(xmlnode node) | |
| 700 | { | |
| 701 | spool s = _xmlnode2spool(node); | |
| 702 | if (s != NULL) | |
| 703 | spool_add(s, "\n"); | |
| 704 | return spool_print(s); | |
| 705 | } | |
| 706 | ||
| 707 | ||
| 708 | /* loop through both a and b comparing everything, attribs, cdata, children, etc */ | |
| 709 | int xmlnode_cmp(xmlnode a, xmlnode b) | |
| 710 | { | |
| 711 | int ret = 0; | |
| 712 | ||
| 713 | while(1) | |
| 714 | { | |
| 715 | if(a == NULL && b == NULL) | |
| 716 | return 0; | |
| 717 | ||
| 718 | if(a == NULL || b == NULL) | |
| 719 | return -1; | |
| 720 | ||
| 721 | if(xmlnode_get_type(a) != xmlnode_get_type(b)) | |
| 722 | return -1; | |
| 723 | ||
| 724 | switch(xmlnode_get_type(a)) | |
| 725 | { | |
| 726 | case NTYPE_ATTRIB: | |
| 727 | ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); | |
| 728 | if(ret != 0) | |
| 729 | return -1; | |
| 730 | ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); | |
| 731 | if(ret != 0) | |
| 732 | return -1; | |
| 733 | break; | |
| 734 | case NTYPE_TAG: | |
| 735 | ret = j_strcmp(xmlnode_get_name(a), xmlnode_get_name(b)); | |
| 736 | if(ret != 0) | |
| 737 | return -1; | |
| 738 | ret = xmlnode_cmp(xmlnode_get_firstattrib(a), xmlnode_get_firstattrib(b)); | |
| 739 | if(ret != 0) | |
| 740 | return -1; | |
| 741 | ret = xmlnode_cmp(xmlnode_get_firstchild(a), xmlnode_get_firstchild(b)); | |
| 742 | if(ret != 0) | |
| 743 | return -1; | |
| 744 | break; | |
| 745 | case NTYPE_CDATA: | |
| 746 | ret = j_strcmp(xmlnode_get_data(a), xmlnode_get_data(b)); | |
| 747 | if(ret != 0) | |
| 748 | return -1; | |
| 749 | } | |
| 750 | a = xmlnode_get_nextsibling(a); | |
| 751 | b = xmlnode_get_nextsibling(b); | |
| 752 | } | |
| 753 | } | |
| 754 | ||
| 755 | ||
| 756 | xmlnode xmlnode_insert_tag_node(xmlnode parent, xmlnode node) | |
| 757 | { | |
| 758 | xmlnode child; | |
| 759 | ||
| 760 | child = xmlnode_insert_tag(parent, xmlnode_get_name(node)); | |
| 761 | if (xmlnode_has_attribs(node)) | |
| 762 | xmlnode_insert_node(child, xmlnode_get_firstattrib(node)); | |
| 763 | if (xmlnode_has_children(node)) | |
| 764 | xmlnode_insert_node(child, xmlnode_get_firstchild(node)); | |
| 765 | ||
| 766 | return child; | |
| 767 | } | |
| 768 | ||
| 769 | /* places copy of node and node's siblings in parent */ | |
| 770 | void xmlnode_insert_node(xmlnode parent, xmlnode node) | |
| 771 | { | |
| 772 | if(node == NULL || parent == NULL) | |
| 773 | return; | |
| 774 | ||
| 775 | while(node != NULL) | |
| 776 | { | |
| 777 | switch(xmlnode_get_type(node)) | |
| 778 | { | |
| 779 | case NTYPE_ATTRIB: | |
| 780 | xmlnode_put_attrib(parent, xmlnode_get_name(node), xmlnode_get_data(node)); | |
| 781 | break; | |
| 782 | case NTYPE_TAG: | |
| 783 | xmlnode_insert_tag_node(parent, node); | |
| 784 | break; | |
| 785 | case NTYPE_CDATA: | |
| 786 | xmlnode_insert_cdata(parent, xmlnode_get_data(node), xmlnode_get_datasz(node)); | |
| 787 | } | |
| 788 | node = xmlnode_get_nextsibling(node); | |
| 789 | } | |
| 790 | } | |
| 791 | ||
| 792 | ||
| 793 | /* produce full duplicate of x with a new pool, x must be a tag! */ | |
| 794 | xmlnode xmlnode_dup(xmlnode x) | |
| 795 | { | |
| 796 | xmlnode x2; | |
| 797 | ||
| 798 | if(x == NULL) | |
| 799 | return NULL; | |
| 800 | ||
| 801 | x2 = xmlnode_new_tag(xmlnode_get_name(x)); | |
| 802 | ||
| 803 | if (xmlnode_has_attribs(x)) | |
| 804 | xmlnode_insert_node(x2, xmlnode_get_firstattrib(x)); | |
| 805 | if (xmlnode_has_children(x)) | |
| 806 | xmlnode_insert_node(x2, xmlnode_get_firstchild(x)); | |
| 807 | ||
| 808 | return x2; | |
| 809 | } | |
| 810 | ||
| 811 | xmlnode xmlnode_dup_pool(pool p, xmlnode x) | |
| 812 | { | |
| 813 | xmlnode x2; | |
| 814 | ||
| 815 | if(x == NULL) | |
| 816 | return NULL; | |
| 817 | ||
| 818 | x2 = xmlnode_new_tag_pool(p, xmlnode_get_name(x)); | |
| 819 | ||
| 820 | if (xmlnode_has_attribs(x)) | |
| 821 | xmlnode_insert_node(x2, xmlnode_get_firstattrib(x)); | |
| 822 | if (xmlnode_has_children(x)) | |
| 823 | xmlnode_insert_node(x2, xmlnode_get_firstchild(x)); | |
| 824 | ||
| 825 | return x2; | |
| 826 | } | |
| 827 | ||
| 828 | xmlnode xmlnode_wrap(xmlnode x,const char *wrapper) | |
| 829 | { | |
| 830 | xmlnode wrap; | |
| 831 | if(x==NULL||wrapper==NULL) return NULL; | |
| 832 | wrap=xmlnode_new_tag_pool(xmlnode_pool(x),wrapper); | |
| 833 | if(wrap==NULL) return NULL; | |
| 834 | wrap->firstchild=x; | |
| 835 | wrap->lastchild=x; | |
| 836 | x->parent=wrap; | |
| 837 | return wrap; | |
| 838 | } | |
| 839 | ||
| 840 | void xmlnode_free(xmlnode node) | |
| 841 | { | |
| 842 | if(node == NULL) | |
| 843 | return; | |
| 844 | ||
| 845 | pool_free(node->p); | |
| 846 | } |