| 1 /* |
1 /* -------------------------------------------------------------------------- |
| 2 * This program is free software; you can redistribute it and/or modify |
2 * |
| 3 * it under the terms of the GNU General Public License as published by |
3 * License |
| 4 * the Free Software Foundation; either version 2 of the License, or |
4 * |
| 5 * (at your option) any later version. |
5 * The contents of this file are subject to the Jabber Open Source License |
| 6 * |
6 * Version 1.0 (the "JOSL"). You may not copy or use this file, in either |
| 7 * This program is distributed in the hope that it will be useful, |
7 * source code or executable form, except in compliance with the JOSL. You |
| 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
8 * may obtain a copy of the JOSL at http://www.jabber.org/ or at |
| 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
9 * http://www.opensource.org/. |
| 10 * GNU General Public License for more details. |
10 * |
| 11 * |
11 * Software distributed under the JOSL is distributed on an "AS IS" basis, |
| 12 * You should have received a copy of the GNU General Public License |
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL |
| 13 * along with this program; if not, write to the Free Software |
13 * for the specific language governing rights and limitations under the |
| 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
14 * JOSL. |
| 15 * |
15 * |
| 16 * Jabber |
16 * Copyrights |
| 17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ |
17 * |
| 18 */ |
18 * Portions created by or assigned to Jabber.com, Inc. are |
| 19 |
19 * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact |
| 20 #include "libxode.h" |
20 * information for Jabber.com, Inc. is available at http://www.jabber.com/. |
| |
21 * |
| |
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 * --------------------------------------------------------------------------*/ |
| |
41 |
| |
42 #include "lib.h" |
| 21 |
43 |
| 22 /* Internal routines */ |
44 /* Internal routines */ |
| 23 xmlnode _xmlnode_new(pool p, const char* name, unsigned int type) |
45 xmlnode _xmlnode_new(pool p, const char* name, unsigned int type) |
| 24 { |
46 { |
| 25 xmlnode result = NULL; |
47 xmlnode result = NULL; |
| 33 { |
55 { |
| 34 p = pool_heap(1*1024); |
56 p = pool_heap(1*1024); |
| 35 } |
57 } |
| 36 |
58 |
| 37 /* Allocate & zero memory */ |
59 /* Allocate & zero memory */ |
| 38 result = (xmlnode)pmalloc(p, sizeof(_xmlnode)); |
60 result = (xmlnode)pmalloco(p, sizeof(_xmlnode)); |
| 39 memset(result, '\0', sizeof(_xmlnode)); |
|
| 40 |
61 |
| 41 /* Initialize fields */ |
62 /* Initialize fields */ |
| 42 if (type != NTYPE_CDATA) |
63 if (type != NTYPE_CDATA) |
| 43 result->name = pstrdup(p,name); |
64 result->name = pstrdup(p,name); |
| 44 result->type = type; |
65 result->type = type; |
| 62 |
83 |
| 63 static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type) |
84 static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type) |
| 64 { |
85 { |
| 65 xmlnode result; |
86 xmlnode result; |
| 66 |
87 |
| 67 if(parent == NULL || name == NULL) return NULL; |
88 if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL; |
| 68 |
89 |
| 69 /* If parent->firstchild is NULL, simply create a new node for the first child */ |
90 /* If parent->firstchild is NULL, simply create a new node for the first child */ |
| 70 if (parent->firstchild == NULL) |
91 if (parent->firstchild == NULL) |
| 71 { |
92 { |
| 72 result = _xmlnode_new(parent->p, name, type); |
93 result = _xmlnode_new(parent->p, name, type); |
| 98 current = current->next; |
119 current = current->next; |
| 99 } |
120 } |
| 100 return NULL; |
121 return NULL; |
| 101 } |
122 } |
| 102 |
123 |
| 103 static char* _xmlnode_merge(pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize) |
124 void _xmlnode_merge(xmlnode data) |
| 104 { |
125 { |
| 105 char* result; |
126 xmlnode cur; |
| 106 result = (char*)pmalloc(p, destsize + srcsize + 1); |
127 char *merge, *scur; |
| 107 memcpy(result, dest, destsize); |
128 int imerge; |
| 108 memcpy(result+destsize, src, srcsize); |
129 |
| 109 result[destsize + srcsize] = '\0'; |
130 /* get total size of all merged cdata */ |
| 110 |
131 imerge = 0; |
| 111 /* WARNING: major ugly hack: since we're throwing the old data away, let's jump in the pool and subtract it from the size, this is for xmlstream's big-node checking */ |
132 for(cur = data; cur != NULL && cur->type == NTYPE_CDATA; cur = cur->next) |
| 112 p->size -= destsize; |
133 imerge += cur->data_sz; |
| 113 |
134 |
| 114 return result; |
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'; |
| |
143 |
| |
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 |
| 115 } |
155 } |
| 116 |
156 |
| 117 static void _xmlnode_hide_sibling(xmlnode child) |
157 static void _xmlnode_hide_sibling(xmlnode child) |
| 118 { |
158 { |
| 119 if(child == NULL) |
159 if(child == NULL) |
| 153 spool s; |
193 spool s; |
| 154 int level=0,dir=0; |
194 int level=0,dir=0; |
| 155 xmlnode tmp; |
195 xmlnode tmp; |
| 156 |
196 |
| 157 if(!node || xmlnode_get_type(node)!=NTYPE_TAG) |
197 if(!node || xmlnode_get_type(node)!=NTYPE_TAG) |
| 158 return NULL; |
198 return NULL; |
| 159 |
199 |
| 160 s = spool_new(xmlnode_pool(node)); |
200 s = spool_new(xmlnode_pool(node)); |
| 161 if(!s) return(NULL); |
201 if(!s) return(NULL); |
| 162 |
202 |
| 163 while(1) |
203 while(1) |
| 164 { |
204 { |
| 165 if(dir==0) |
205 if(dir==0) |
| 166 { |
206 { |
| 167 if(xmlnode_get_type(node) == NTYPE_TAG) |
207 if(xmlnode_get_type(node) == NTYPE_TAG) |
| 168 { |
208 { |
| 169 if(xmlnode_has_children(node)) |
209 if(xmlnode_has_children(node)) |
| 170 { |
210 { |
| 171 _xmlnode_tag2str(s,node,1); |
211 _xmlnode_tag2str(s,node,1); |
| 172 node = xmlnode_get_firstchild(node); |
212 node = xmlnode_get_firstchild(node); |
| 173 level++; |
213 level++; |
| 174 continue; |
214 continue; |
| 175 } |
215 }else{ |
| 176 else |
216 _xmlnode_tag2str(s,node,0); |
| 177 { |
217 } |
| 178 _xmlnode_tag2str(s,node,0); |
218 }else{ |
| 179 } |
219 spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node))); |
| 180 } |
220 } |
| 181 else |
221 } |
| 182 { |
|
| 183 spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node))); |
|
| 184 } |
|
| 185 } |
|
| 186 |
222 |
| 187 tmp = xmlnode_get_nextsibling(node); |
223 tmp = xmlnode_get_nextsibling(node); |
| 188 if(!tmp) |
224 if(!tmp) |
| 189 { |
225 { |
| 190 node = xmlnode_get_parent(node); |
226 node = xmlnode_get_parent(node); |
| 191 level--; |
227 level--; |
| 192 if(level>=0) _xmlnode_tag2str(s,node,2); |
228 if(level>=0) _xmlnode_tag2str(s,node,2); |
| 193 if(level<1) break; |
229 if(level<1) break; |
| 194 dir = 1; |
230 dir = 1; |
| 195 } |
231 }else{ |
| 196 else |
232 node = tmp; |
| 197 { |
233 dir = 0; |
| 198 node = tmp; |
234 } |
| 199 dir = 0; |
|
| 200 } |
|
| 201 } |
235 } |
| 202 |
236 |
| 203 return s; |
237 return s; |
| 204 } |
238 } |
| 205 |
239 |
| 281 return NULL; |
313 return NULL; |
| 282 |
314 |
| 283 if(size == -1) |
315 if(size == -1) |
| 284 size = strlen(CDATA); |
316 size = strlen(CDATA); |
| 285 |
317 |
| 286 if ((parent->lastchild != NULL) && (parent->lastchild->type == NTYPE_CDATA)) |
318 result = _xmlnode_insert(parent, NULL, NTYPE_CDATA); |
| 287 { |
319 if (result != NULL) |
| 288 result = parent->lastchild; |
320 { |
| 289 result->data = _xmlnode_merge(result->p, result->data, result->data_sz, CDATA, size); |
321 result->data = (char*)pmalloc(result->p, size + 1); |
| 290 result->data_sz = result->data_sz + size; |
322 memcpy(result->data, CDATA, size); |
| 291 } |
323 result->data[size] = '\0'; |
| 292 else |
324 result->data_sz = size; |
| 293 { |
|
| 294 result = _xmlnode_insert(parent, "", NTYPE_CDATA); |
|
| 295 if (result != NULL) |
|
| 296 { |
|
| 297 result->data = (char*)pmalloc(result->p, size + 1); |
|
| 298 memcpy(result->data, CDATA, size); |
|
| 299 result->data[size] = '\0'; |
|
| 300 result->data_sz = size; |
|
| 301 } |
|
| 302 } |
325 } |
| 303 |
326 |
| 304 return result; |
327 return result; |
| 305 } |
328 } |
| 306 |
329 |
| 312 * parent -- pointer to the parent tag |
335 * parent -- pointer to the parent tag |
| 313 * name -- "name" for the child tag of that name |
336 * name -- "name" for the child tag of that name |
| 314 * "name/name" for a sub child (recurses) |
337 * "name/name" for a sub child (recurses) |
| 315 * "?attrib" to match the first tag with that attrib defined |
338 * "?attrib" to match the first tag with that attrib defined |
| 316 * "?attrib=value" to match the first tag with that attrib and value |
339 * "?attrib=value" to match the first tag with that attrib and value |
| 317 * or any combination: "name/name/?attrib", etc |
340 * "=cdata" to match the cdata contents of the child |
| |
341 * or any combination: "name/name/?attrib", "name=cdata", etc |
| 318 * |
342 * |
| 319 * results |
343 * results |
| 320 * a pointer to the tag matching search criteria |
344 * a pointer to the tag matching search criteria |
| 321 * or NULL if search was unsuccessfull |
345 * or NULL if search was unsuccessfull |
| 322 */ |
346 */ |
| 323 xmlnode xmlnode_get_tag(xmlnode parent, const char* name) |
347 xmlnode xmlnode_get_tag(xmlnode parent, const char* name) |
| 324 { |
348 { |
| 325 char *str, *slash, *qmark, *equals; |
349 char *str, *slash, *qmark, *equals; |
| 326 xmlnode step, ret; |
350 xmlnode step, ret; |
| 327 |
351 |
| |
352 |
| 328 if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; |
353 if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; |
| 329 |
354 |
| 330 if(strstr(name, "/") == NULL && strstr(name,"?") == NULL) |
355 if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL) |
| 331 return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); |
356 return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); |
| 332 |
357 |
| 333 /* jer's note: why can't I modify the name directly, why do I have to strdup it? damn c grrr! */ |
|
| 334 str = strdup(name); |
358 str = strdup(name); |
| 335 slash = strstr(str, "/"); |
359 slash = strstr(str, "/"); |
| 336 qmark = strstr(str, "?"); |
360 qmark = strstr(str, "?"); |
| 337 equals = strstr(str, "="); |
361 equals = strstr(str, "="); |
| 338 |
362 |
| |
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 |
| 339 if(qmark != NULL && (slash == NULL || qmark < slash)) |
389 if(qmark != NULL && (slash == NULL || qmark < slash)) |
| 340 { /* of type ?attrib */ |
390 { /* of type ?attrib */ |
| 341 |
391 |
| 342 *qmark = '\0'; |
392 *qmark = '\0'; |
| 343 qmark++; |
393 qmark++; |
| 526 return NULL; |
576 return NULL; |
| 527 } |
577 } |
| 528 |
578 |
| 529 char* xmlnode_get_data(xmlnode node) |
579 char* xmlnode_get_data(xmlnode node) |
| 530 { |
580 { |
| 531 xmlnode cur; |
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; |
| 532 |
584 |
| 533 if(node == NULL) return NULL; |
585 if(node == NULL) return NULL; |
| 534 |
586 |
| 535 if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA */ |
587 /* check for a dirty node w/ unassembled cdata chunks */ |
| 536 { |
588 if(xmlnode_get_type(node->next) == NTYPE_CDATA) |
| 537 for(cur = xmlnode_get_firstchild(node); cur != NULL; cur = xmlnode_get_nextsibling(cur)) |
589 _xmlnode_merge(node); |
| 538 if(xmlnode_get_type(cur) == NTYPE_CDATA) |
590 |
| 539 return cur->data; |
591 return node->data; |
| 540 }else{ |
|
| 541 return node->data; |
|
| 542 } |
|
| 543 return NULL; |
|
| 544 } |
592 } |
| 545 |
593 |
| 546 int xmlnode_get_datasz(xmlnode node) |
594 int xmlnode_get_datasz(xmlnode node) |
| 547 { |
595 { |
| 548 if (node != NULL) |
596 if(xmlnode_get_type(node) != NTYPE_CDATA) return 0; |
| 549 return node->data_sz; |
597 |
| 550 return (int)NULL; |
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; |
| 551 } |
602 } |
| 552 |
603 |
| 553 int xmlnode_get_type(xmlnode node) |
604 int xmlnode_get_type(xmlnode node) |
| 554 { |
605 { |
| 555 if (node != NULL) |
606 if (node != NULL) |
| 556 return node->type; |
607 return node->type; |
| 557 return (int)NULL; |
608 return NTYPE_UNDEF; |
| 558 } |
609 } |
| 559 |
610 |
| 560 int xmlnode_has_children(xmlnode node) |
611 int xmlnode_has_children(xmlnode node) |
| 561 { |
612 { |
| 562 if ((node != NULL) && (node->firstchild != NULL)) |
613 if ((node != NULL) && (node->firstchild != NULL)) |