Mercurial > pidgin
comparison src/protocols/jabber/xmlnode.c @ 7014:67c4e9d39242
[gaim-migrate @ 7577]
Here it is, the bulk of the new Jabber prpl.
Left to do:
- Implement registration
- Implement password changing
- Keep track of conversation threads (since I apparently have to)
- Fix the bugs that always magically appear in code after I commit
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Mon, 29 Sep 2003 15:23:19 +0000 |
| parents | 4e7cefc55971 |
| children | 4e5654931401 |
comparison
equal
deleted
inserted
replaced
| 7013:859cafb6433f | 7014:67c4e9d39242 |
|---|---|
| 1 /* -------------------------------------------------------------------------- | 1 /** |
| 2 * | 2 * @file xmlnode.c XML DOM functions |
| 3 * License | 3 * |
| 4 * | 4 * gaim |
| 5 * The contents of this file are subject to the Jabber Open Source License | 5 * |
| 6 * Version 1.0 (the "JOSL"). You may not copy or use this file, in either | 6 * Copyright (C) 2003 Nathan Walp <faceprint@faceprint.com> |
| 7 * source code or executable form, except in compliance with the JOSL. You | 7 * |
| 8 * may obtain a copy of the JOSL at http://www.jabber.org/ or at | 8 * This program is free software; you can redistribute it and/or modify |
| 9 * http://www.opensource.org/. | 9 * it under the terms of the GNU General Public License as published by |
| 10 * | 10 * the Free Software Foundation; either version 2 of the License, or |
| 11 * Software distributed under the JOSL is distributed on an "AS IS" basis, | 11 * (at your option) any later version. |
| 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL | 12 * |
| 13 * for the specific language governing rights and limitations under the | 13 * This program is distributed in the hope that it will be useful, |
| 14 * JOSL. | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 * Copyrights | 16 * GNU General Public License for more details. |
| 17 * | 17 * |
| 18 * Portions created by or assigned to Jabber.com, Inc. are | 18 * You should have received a copy of the GNU General Public License |
| 19 * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact | 19 * along with this program; if not, write to the Free Software |
| 20 * information for Jabber.com, Inc. is available at http://www.jabber.com/. | 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 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" | |
| 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 */ | |
| 60 result = (xmlnode)pmalloco(p, sizeof(_xmlnode)); | |
| 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 | |
| 88 if(parent == NULL || (type != NTYPE_CDATA && name == NULL)) return NULL; | |
| 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 | |
| 124 void _xmlnode_merge(xmlnode data) | |
| 125 { | |
| 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; | |
| 134 | |
| 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 | |
| 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) | |
| 198 return NULL; | |
| 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 { | |
| 209 if(xmlnode_has_children(node)) | |
| 210 { | |
| 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 } | |
| 222 | |
| 223 tmp = xmlnode_get_nextsibling(node); | |
| 224 if(!tmp) | |
| 225 { | |
| 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 } | |
| 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 */ | 21 */ |
| 255 xmlnode xmlnode_new_tag(const char* name) | 22 |
| 256 { | 23 /* A lot of this code at least resembles the code in libxode, but since |
| 257 return _xmlnode_new(NULL, name, NTYPE_TAG); | 24 * libxode uses memory pools that we simply have no need for, I decided to |
| 258 } | 25 * write my own stuff. Also, re-writing this lets me be as lightweight |
| 259 | 26 * as I want to be. Thank you libxode for giving me a good starting point */ |
| 260 | 27 |
| 261 /* | 28 #include "internal.h" |
| 262 * xmlnode_new_tag_pool -- create a tag node within given pool | 29 |
| 263 * | 30 #include <string.h> |
| 264 * parameters | 31 #include <glib.h> |
| 265 * p -- previously created memory pool | 32 |
| 266 * name -- name of the tag | 33 #include "xmlnode.h" |
| 267 * | 34 |
| 268 * returns | 35 static xmlnode* |
| 269 * a pointer to the tag node | 36 new_node(const char *name, NodeType type) |
| 270 * or NULL if it was unsuccessfull | 37 { |
| 271 */ | 38 xmlnode *node = g_new0(xmlnode, 1); |
| 272 xmlnode xmlnode_new_tag_pool(pool p, const char* name) | 39 if(name) |
| 273 { | 40 node->name = g_strdup(name); |
| 274 return _xmlnode_new(p, name, NTYPE_TAG); | 41 node->type = type; |
| 275 } | 42 |
| 276 | 43 return node; |
| 277 | 44 } |
| 278 /* | 45 |
| 279 * xmlnode_insert_tag -- append a child tag to a tag | 46 xmlnode* |
| 280 * | 47 xmlnode_new(const char *name) |
| 281 * parameters | 48 { |
| 282 * parent -- pointer to the parent tag | 49 g_return_val_if_fail(name != NULL, NULL); |
| 283 * name -- name of the child tag | 50 |
| 284 * | 51 return new_node(name, NODE_TYPE_TAG); |
| 285 * returns | 52 } |
| 286 * a pointer to the child tag node | 53 |
| 287 * or NULL if it was unsuccessfull | 54 xmlnode *xmlnode_new_child(xmlnode *parent, const char *name) |
| 288 */ | 55 { |
| 289 xmlnode xmlnode_insert_tag(xmlnode parent, const char* name) | 56 xmlnode *node; |
| 290 { | 57 |
| 291 return _xmlnode_insert(parent, name, NTYPE_TAG); | 58 g_return_val_if_fail(parent != NULL, NULL); |
| 292 } | 59 g_return_val_if_fail(name != NULL, NULL); |
| 293 | 60 |
| 294 | 61 node = new_node(name, NODE_TYPE_TAG); |
| 295 /* | 62 |
| 296 * xmlnode_insert_cdata -- append character data to a tag | 63 xmlnode_insert_child(parent, node); |
| 297 * | 64 |
| 298 * parameters | 65 return node; |
| 299 * parent -- parent tag | 66 } |
| 300 * CDATA -- character data | 67 |
| 301 * size -- size of CDATA | 68 void |
| 302 * or -1 for null-terminated CDATA strings | 69 xmlnode_insert_child(xmlnode *parent, xmlnode *child) |
| 303 * | 70 { |
| 304 * returns | 71 g_return_if_fail(parent != NULL); |
| 305 * a pointer to the child CDATA node | 72 g_return_if_fail(child != NULL); |
| 306 * or NULL if it was unsuccessfull | 73 |
| 307 */ | 74 child->parent = parent; |
| 308 xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size) | 75 |
| 309 { | 76 if(parent->child) { |
| 310 xmlnode result; | 77 xmlnode *x; |
| 311 | 78 for(x = parent->child; x->next; x = x->next); |
| 312 if(CDATA == NULL || parent == NULL) | 79 x->next = child; |
| 313 return NULL; | 80 } else { |
| 314 | 81 parent->child = child; |
| 315 if(size == -1) | 82 } |
| 316 size = strlen(CDATA); | 83 } |
| 317 | 84 |
| 318 result = _xmlnode_insert(parent, NULL, NTYPE_CDATA); | 85 void |
| 319 if (result != NULL) | 86 xmlnode_insert_data(xmlnode *parent, const char *data, size_t size) |
| 320 { | 87 { |
| 321 result->data = (char*)pmalloc(result->p, size + 1); | 88 xmlnode *node; |
| 322 memcpy(result->data, CDATA, size); | 89 size_t real_size; |
| 323 result->data[size] = '\0'; | 90 |
| 324 result->data_sz = size; | 91 g_return_if_fail(parent != NULL); |
| 325 } | 92 g_return_if_fail(data != NULL); |
| 326 | 93 g_return_if_fail(size != 0); |
| 327 return result; | 94 |
| 328 } | 95 real_size = size == -1 ? strlen(data) : size; |
| 329 | 96 |
| 330 | 97 node = new_node(NULL, NODE_TYPE_DATA); |
| 331 /* | 98 |
| 332 * xmlnode_get_tag -- find given tag in an xmlnode tree | 99 node->data = g_memdup(data, real_size); |
| 333 * | 100 node->data_sz = real_size; |
| 334 * parameters | 101 |
| 335 * parent -- pointer to the parent tag | 102 xmlnode_insert_child(parent, node); |
| 336 * name -- "name" for the child tag of that name | 103 } |
| 337 * "name/name" for a sub child (recurses) | 104 |
| 338 * "?attrib" to match the first tag with that attrib defined | 105 void |
| 339 * "?attrib=value" to match the first tag with that attrib and value | 106 xmlnode_remove_attrib(xmlnode *node, const char *attr) |
| 340 * "=cdata" to match the cdata contents of the child | 107 { |
| 341 * or any combination: "name/name/?attrib", "name=cdata", etc | 108 xmlnode *attr_node, *sibling = NULL; |
| 342 * | 109 |
| 343 * results | 110 g_return_if_fail(node != NULL); |
| 344 * a pointer to the tag matching search criteria | 111 g_return_if_fail(attr != NULL); |
| 345 * or NULL if search was unsuccessfull | 112 |
| 346 */ | 113 for(attr_node = node->child; attr_node; attr_node = attr_node->next) |
| 347 xmlnode xmlnode_get_tag(xmlnode parent, const char* name) | 114 { |
| 348 { | 115 if(attr_node->type == NODE_TYPE_ATTRIB && |
| 349 char *str, *slash, *qmark, *equals; | 116 !strcmp(attr_node->name, attr)) { |
| 350 xmlnode step, ret; | 117 if(node->child == attr_node) { |
| 351 | 118 node->child = attr_node->next; |
| 352 | 119 } else { |
| 353 if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL; | 120 sibling->next = attr_node->next; |
| 354 | 121 } |
| 355 if(strstr(name, "/") == NULL && strstr(name,"?") == NULL && strstr(name, "=") == NULL) | 122 xmlnode_free(attr_node); |
| 356 return _xmlnode_search(parent->firstchild, name, NTYPE_TAG); | 123 return; |
| 357 | 124 } |
| 358 str = strdup(name); | 125 sibling = attr_node; |
| 359 slash = strstr(str, "/"); | 126 } |
| 360 qmark = strstr(str, "?"); | 127 } |
| 361 equals = strstr(str, "="); | 128 |
| 362 | 129 void |
| 363 if(equals != NULL && (slash == NULL || equals < slash) && (qmark == NULL || equals < qmark)) | 130 xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value) |
| 364 { /* of type =cdata */ | 131 { |
| 365 | 132 xmlnode *attrib_node; |
| 366 *equals = '\0'; | 133 |
| 367 equals++; | 134 g_return_if_fail(node != NULL); |
| 368 | 135 g_return_if_fail(attr != NULL); |
| 369 for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | 136 g_return_if_fail(value != NULL); |
| 370 { | 137 |
| 371 if(xmlnode_get_type(step) != NTYPE_TAG) | 138 xmlnode_remove_attrib(node, attr); |
| 372 continue; | 139 |
| 373 | 140 attrib_node = new_node(attr, NODE_TYPE_ATTRIB); |
| 374 if(*str != '\0') | 141 |
| 375 if(j_strcmp(xmlnode_get_name(step),str) != 0) | 142 attrib_node->data = g_strdup(value); |
| 376 continue; | 143 |
| 377 | 144 xmlnode_insert_child(node, attrib_node); |
| 378 if(j_strcmp(xmlnode_get_data(step),equals) != 0) | 145 } |
| 379 continue; | 146 |
| 380 | 147 const char* |
| 381 break; | 148 xmlnode_get_attrib(xmlnode *node, const char *attr) |
| 382 } | 149 { |
| 383 | 150 xmlnode *x; |
| 384 free(str); | 151 |
| 385 return step; | 152 g_return_val_if_fail(node != NULL, NULL); |
| 386 } | 153 |
| 387 | 154 for(x = node->child; x; x = x->next) { |
| 388 | 155 if(x->type == NODE_TYPE_ATTRIB && !strcmp(attr, x->name)) { |
| 389 if(qmark != NULL && (slash == NULL || qmark < slash)) | 156 return x->data; |
| 390 { /* of type ?attrib */ | 157 } |
| 391 | 158 } |
| 392 *qmark = '\0'; | 159 |
| 393 qmark++; | 160 return NULL; |
| 394 if(equals != NULL) | 161 } |
| 395 { | 162 |
| 396 *equals = '\0'; | 163 void xmlnode_free(xmlnode *node) |
| 397 equals++; | 164 { |
| 398 } | 165 xmlnode *x, *y; |
| 399 | 166 |
| 400 for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | 167 g_return_if_fail(node != NULL); |
| 401 { | 168 |
| 402 if(xmlnode_get_type(step) != NTYPE_TAG) | 169 x = node->child; |
| 403 continue; | 170 while(x) { |
| 404 | 171 y = x->next; |
| 405 if(*str != '\0') | 172 xmlnode_free(x); |
| 406 if(j_strcmp(xmlnode_get_name(step),str) != 0) | 173 x = y; |
| 407 continue; | 174 } |
| 408 | 175 |
| 409 if(xmlnode_get_attrib(step,qmark) == NULL) | 176 if(node->name) |
| 410 continue; | 177 g_free(node->name); |
| 411 | 178 if(node->data) |
| 412 if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0) | 179 g_free(node->data); |
| 413 continue; | 180 g_free(node); |
| 414 | 181 } |
| 415 break; | 182 |
| 416 } | 183 xmlnode* |
| 417 | 184 xmlnode_get_child(xmlnode *parent, const char *name) |
| 418 free(str); | 185 { |
| 419 return step; | 186 xmlnode *x, *ret = NULL; |
| 420 } | 187 char **names; |
| 421 | 188 char *parent_name, *child_name; |
| 422 | 189 |
| 423 *slash = '\0'; | 190 g_return_val_if_fail(parent != NULL, NULL); |
| 424 ++slash; | 191 |
| 425 | 192 names = g_strsplit(name, "/", 2); |
| 426 for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step)) | 193 parent_name = names[0]; |
| 427 { | 194 child_name = names[1]; |
| 428 if(xmlnode_get_type(step) != NTYPE_TAG) continue; | 195 |
| 429 | 196 for(x = parent->child; x; x = x->next) { |
| 430 if(j_strcmp(xmlnode_get_name(step),str) != 0) | 197 if(x->type == NODE_TYPE_TAG && name && !strcmp(parent_name, x->name)) { |
| 431 continue; | 198 ret = x; |
| 432 | 199 break; |
| 433 ret = xmlnode_get_tag(step, slash); | 200 } |
| 434 if(ret != NULL) | 201 } |
| 435 { | 202 |
| 436 free(str); | 203 if(child_name && ret) |
| 437 return ret; | 204 ret = xmlnode_get_child(x, child_name); |
| 438 } | 205 |
| 439 } | 206 g_strfreev(names); |
| 440 | 207 return ret; |
| 441 free(str); | 208 } |
| 442 return NULL; | 209 |
| 443 } | 210 char * |
| 444 | 211 xmlnode_get_data(xmlnode *node) |
| 445 | 212 { |
| 446 /* return the cdata from any tag */ | 213 GString *str; |
| 447 char *xmlnode_get_tag_data(xmlnode parent, const char *name) | 214 char *ret; |
| 448 { | 215 xmlnode *c; |
| 449 xmlnode tag; | 216 |
| 450 | 217 g_return_val_if_fail(node != NULL, NULL); |
| 451 tag = xmlnode_get_tag(parent, name); | 218 |
| 452 if(tag == NULL) return NULL; | 219 str = g_string_new(""); |
| 453 | 220 |
| 454 return xmlnode_get_data(tag); | 221 for(c = node->child; c; c = c->next) { |
| 455 } | 222 if(c->type == NODE_TYPE_DATA) |
| 456 | 223 str = g_string_append_len(str, c->data, c->data_sz); |
| 457 | 224 } |
| 458 void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value) | 225 |
| 459 { | 226 ret = str->str; |
| 460 xmlnode attrib; | 227 g_string_free(str, FALSE); |
| 461 | 228 |
| 462 if(owner == NULL || name == NULL || value == NULL) return; | 229 return ret; |
| 463 | 230 } |
| 464 /* If there are no existing attributs, allocate a new one to start | 231 |
| 465 the list */ | 232 char *xmlnode_to_str(xmlnode *node) |
| 466 if (owner->firstattrib == NULL) | 233 { |
| 467 { | 234 char *ret; |
| 468 attrib = _xmlnode_new(owner->p, name, NTYPE_ATTRIB); | 235 GString *text = g_string_new(""); |
| 469 owner->firstattrib = attrib; | 236 xmlnode *c; |
| 470 owner->lastattrib = attrib; | 237 char *node_name, *esc, *esc2; |
| 471 } | 238 gboolean need_end = FALSE; |
| 472 else | 239 |
| 473 { | 240 node_name = g_markup_escape_text(node->name, -1); |
| 474 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | 241 g_string_append_printf(text, "<%s", node_name); |
| 475 if(attrib == NULL) | 242 |
| 476 { | 243 |
| 477 attrib = _xmlnode_append_sibling(owner->lastattrib, name, NTYPE_ATTRIB); | 244 for(c = node->child; c; c = c->next) |
| 478 owner->lastattrib = attrib; | 245 { |
| 479 } | 246 if(c->type == NODE_TYPE_ATTRIB) { |
| 480 } | 247 esc = g_markup_escape_text(c->name, -1); |
| 481 /* Update the value of the attribute */ | 248 esc2 = g_markup_escape_text(c->data, -1); |
| 482 attrib->data_sz = strlen(value); | 249 g_string_append_printf(text, " %s='%s'", esc, esc2); |
| 483 attrib->data = pstrdup(owner->p, value); | 250 g_free(esc); |
| 484 | 251 g_free(esc2); |
| 485 } | 252 } else if(c->type == NODE_TYPE_TAG || c->type == NODE_TYPE_DATA) { |
| 486 | 253 need_end = TRUE; |
| 487 char* xmlnode_get_attrib(xmlnode owner, const char* name) | 254 } |
| 488 { | 255 } |
| 489 xmlnode attrib; | 256 |
| 490 | 257 if(need_end) { |
| 491 if (owner != NULL && owner->firstattrib != NULL) | 258 text = g_string_append_c(text, '>'); |
| 492 { | 259 |
| 493 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | 260 for(c = node->child; c; c = c->next) |
| 494 if (attrib != NULL) | 261 { |
| 495 return (char*)attrib->data; | 262 if(c->type == NODE_TYPE_TAG) { |
| 496 } | 263 esc = xmlnode_to_str(c); |
| 497 return NULL; | 264 g_string_append_printf(text, "%s", esc); |
| 498 } | 265 g_free(esc); |
| 499 | 266 } else if(c->type == NODE_TYPE_DATA) { |
| 500 void xmlnode_put_vattrib(xmlnode owner, const char* name, void *value) | 267 esc = g_markup_escape_text(c->data, c->data_sz); |
| 501 { | 268 g_string_append_printf(text, "%s", esc); |
| 502 xmlnode attrib; | 269 g_free(esc); |
| 503 | 270 } |
| 504 if (owner != NULL) | 271 } |
| 505 { | 272 |
| 506 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | 273 g_string_append_printf(text, "</%s>", node_name); |
| 507 if (attrib == NULL) | 274 } else { |
| 508 { | 275 g_string_append_printf(text, "/>"); |
| 509 xmlnode_put_attrib(owner, name, ""); | 276 } |
| 510 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | 277 |
| 511 } | 278 g_free(node_name); |
| 512 if (attrib != NULL) | 279 |
| 513 attrib->firstchild = (xmlnode)value; | 280 ret = text->str; |
| 514 } | 281 g_string_free(text, FALSE); |
| 515 } | 282 return ret; |
| 516 | 283 } |
| 517 void* xmlnode_get_vattrib(xmlnode owner, const char* name) | 284 |
| 518 { | 285 struct _xmlnode_parser_data { |
| 519 xmlnode attrib; | 286 xmlnode *current; |
| 520 | 287 }; |
| 521 if (owner != NULL && owner->firstattrib != NULL) | 288 |
| 522 { | 289 static void |
| 523 attrib = _xmlnode_search(owner->firstattrib, name, NTYPE_ATTRIB); | 290 xmlnode_parser_element_start(GMarkupParseContext *context, |
| 524 if (attrib != NULL) | 291 const char *element_name, const char **attrib_names, |
| 525 return (void*)attrib->firstchild; | 292 const char **attrib_values, gpointer user_data, GError **error) |
| 526 } | 293 { |
| 527 return NULL; | 294 struct _xmlnode_parser_data *xpd = user_data; |
| 528 } | 295 xmlnode *node; |
| 529 | 296 int i; |
| 530 xmlnode xmlnode_get_firstattrib(xmlnode parent) | 297 |
| 531 { | 298 if(!element_name) { |
| 532 if (parent != NULL) | 299 return; |
| 533 return parent->firstattrib; | 300 } else { |
| 534 return NULL; | 301 if(xpd->current) |
| 535 } | 302 node = xmlnode_new_child(xpd->current, element_name); |
| 536 | 303 else |
| 537 xmlnode xmlnode_get_firstchild(xmlnode parent) | 304 node = xmlnode_new(element_name); |
| 538 { | 305 |
| 539 if (parent != NULL) | 306 for(i=0; attrib_names[i]; i++) |
| 540 return parent->firstchild; | 307 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]); |
| 541 return NULL; | 308 |
| 542 } | 309 xpd->current = node; |
| 543 | 310 } |
| 544 xmlnode xmlnode_get_lastchild(xmlnode parent) | 311 } |
| 545 { | 312 |
| 546 if (parent != NULL) | 313 static void |
| 547 return parent->lastchild; | 314 xmlnode_parser_element_end(GMarkupParseContext *context, |
| 548 return NULL; | 315 const char *element_name, gpointer user_data, GError **error) |
| 549 } | 316 { |
| 550 | 317 struct _xmlnode_parser_data *xpd = user_data; |
| 551 xmlnode xmlnode_get_nextsibling(xmlnode sibling) | 318 |
| 552 { | 319 if(!element_name || !xpd->current) |
| 553 if (sibling != NULL) | 320 return; |
| 554 return sibling->next; | 321 |
| 555 return NULL; | 322 if(xpd->current->parent) { |
| 556 } | 323 if(!strcmp(xpd->current->name, element_name)) |
| 557 | 324 xpd->current = xpd->current->parent; |
| 558 xmlnode xmlnode_get_prevsibling(xmlnode sibling) | 325 } |
| 559 { | 326 } |
| 560 if (sibling != NULL) | 327 |
| 561 return sibling->prev; | 328 static void |
| 562 return NULL; | 329 xmlnode_parser_element_text(GMarkupParseContext *context, const char *text, |
| 563 } | 330 gsize text_len, gpointer user_data, GError **error) |
| 564 | 331 { |
| 565 xmlnode xmlnode_get_parent(xmlnode node) | 332 struct _xmlnode_parser_data *xpd = user_data; |
| 566 { | 333 |
| 567 if (node != NULL) | 334 if(!xpd->current) |
| 568 return node->parent; | 335 return; |
| 569 return NULL; | 336 |
| 570 } | 337 if(!text || !text_len) |
| 571 | 338 return; |
| 572 char* xmlnode_get_name(xmlnode node) | 339 |
| 573 { | 340 xmlnode_insert_data(xpd->current, text, text_len); |
| 574 if (node != NULL) | 341 } |
| 575 return node->name; | 342 |
| 576 return NULL; | 343 static GMarkupParser xmlnode_parser = { |
| 577 } | 344 xmlnode_parser_element_start, |
| 578 | 345 xmlnode_parser_element_end, |
| 579 char* xmlnode_get_data(xmlnode node) | 346 xmlnode_parser_element_text, |
| 580 { | 347 NULL, |
| 581 if(xmlnode_get_type(node) == NTYPE_TAG) /* loop till we find a CDATA in the children */ | 348 NULL |
| 582 for(node = xmlnode_get_firstchild(node); node != NULL; node = xmlnode_get_nextsibling(node)) | 349 }; |
| 583 if(xmlnode_get_type(node) == NTYPE_CDATA) break; | 350 |
| 584 | 351 |
| 585 if(node == NULL) return NULL; | 352 xmlnode *xmlnode_from_str(const char *str, size_t size) |
| 586 | 353 { |
| 587 /* check for a dirty node w/ unassembled cdata chunks */ | 354 struct _xmlnode_parser_data *xpd = g_new0(struct _xmlnode_parser_data, 1); |
| 588 if(xmlnode_get_type(node->next) == NTYPE_CDATA) | 355 xmlnode *ret; |
| 589 _xmlnode_merge(node); | 356 GMarkupParseContext *context; |
| 590 | 357 size_t real_size = size == -1 ? strlen(str) : size; |
| 591 return node->data; | 358 |
| 592 } | 359 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); |
| 593 | 360 |
| 594 int xmlnode_get_datasz(xmlnode node) | 361 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { |
| 595 { | 362 while(xpd->current && xpd->current->parent) |
| 596 if(xmlnode_get_type(node) != NTYPE_CDATA) return 0; | 363 xpd->current = xpd->current->parent; |
| 597 | 364 xmlnode_free(xpd->current); |
| 598 /* check for a dirty node w/ unassembled cdata chunks */ | 365 xpd->current = NULL; |
| 599 if(xmlnode_get_type(node->next) == NTYPE_CDATA) | 366 } |
| 600 _xmlnode_merge(node); | 367 g_markup_parse_context_free(context); |
| 601 return node->data_sz; | 368 |
| 602 } | 369 ret = xpd->current; |
| 603 | 370 g_free(xpd); |
| 604 int xmlnode_get_type(xmlnode node) | 371 return ret; |
| 605 { | 372 } |
| 606 if (node != NULL) | |
| 607 return node->type; | |
| 608 return NTYPE_UNDEF; | |
| 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 } |
