1 /* iksemel (XML parser for Jabber)
2 ** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
3 ** This code is free software; you can redistribute it and/or
4 ** modify it under the terms of GNU Lesser General Public License.
7 /* minimum sax buffer size */
8 #define SAX_BUFFER_MIN_SIZE 128
10 /* sax parser structure plus extra data of dom parser */
11 #define DEFAULT_DOM_CHUNK_SIZE 256
13 /* sax parser structure plus extra data of stream parser */
14 #define DEFAULT_STREAM_CHUNK_SIZE 256
16 /* iks structure, its data, child iks structures, for stream parsing */
17 #define DEFAULT_IKS_CHUNK_SIZE 1024
19 /* iks structure, its data, child iks structures, for file parsing */
20 #define DEFAULT_DOM_IKS_CHUNK_SIZE 2048
22 /* rule structure and from/to/id/ns strings */
23 #define DEFAULT_RULE_CHUNK_SIZE 128
25 /* file is read by blocks with this size */
26 #define FILE_IO_BUF_SIZE 4096
28 /* network receive buffer */
29 #define NET_IO_BUF_SIZE 4096
30 /* iksemel (XML parser for Jabber)
31 ** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
32 ** This code is free software; you can redistribute it and/or
33 ** modify it under the terms of GNU Lesser General Public License.
41 /***** malloc wrapper *****/
43 static void *(*my_malloc_func)(size_t size);
44 static void (*my_free_func)(void *ptr);
47 iks_malloc (size_t size)
50 return my_malloc_func (size);
65 iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr))
67 my_malloc_func = malloc_func;
68 my_free_func = free_func;
71 /***** NULL-safe Functions *****/
74 iks_strdup (const char *src)
76 if (src) return strdup(src);
81 iks_strcat (char *dest, const char *src)
85 if (!src) return dest;
88 memcpy (dest, src, len);
94 iks_strcmp (const char *a, const char *b)
96 if (!a || !b) return -1;
101 iks_strcasecmp (const char *a, const char *b)
103 if (!a || !b) return -1;
104 return strcasecmp (a, b);
108 iks_strncmp (const char *a, const char *b, size_t n)
110 if (!a || !b) return -1;
111 return strncmp (a, b, n);
115 iks_strncasecmp (const char *a, const char *b, size_t n)
117 if (!a || !b) return -1;
118 return strncasecmp (a, b, n);
122 iks_strlen (const char *src)
128 /***** XML Escaping *****/
131 iks_escape (ikstack *s, char *src, size_t len)
136 if (!src || !s) return NULL;
137 if (len == -1) len = strlen (src);
140 for (i=0; i<len; i++) {
142 case '&': nlen += 4; break;
143 case '<': nlen += 3; break;
144 case '>': nlen += 3; break;
145 case '\'': nlen += 5; break;
146 case '"': nlen += 5; break;
149 if (len == nlen) return src;
151 ret = iks_stack_alloc (s, nlen + 1);
152 if (!ret) return NULL;
154 for (i=j=0; i<len; i++) {
156 case '&': memcpy (&ret[j], "&", 5); j += 5; break;
157 case '\'': memcpy (&ret[j], "'", 6); j += 6; break;
158 case '"': memcpy (&ret[j], """, 6); j += 6; break;
159 case '<': memcpy (&ret[j], "<", 4); j += 4; break;
160 case '>': memcpy (&ret[j], ">", 4); j += 4; break;
161 default: ret[j++] = src[i];
170 iks_unescape (ikstack *s, char *src, size_t len)
175 if (!s || !src) return NULL;
176 if (!strchr (src, '&')) return src;
177 if (len == -1) len = strlen (src);
179 ret = iks_stack_alloc (s, len + 1);
180 if (!ret) return NULL;
182 for (i=j=0; i<len; i++) {
185 if (strncmp (&src[i], "amp;", 4) == 0) {
188 } else if (strncmp (&src[i], "quot;", 5) == 0) {
191 } else if (strncmp (&src[i], "apos;", 5) == 0) {
194 } else if (strncmp (&src[i], "lt;", 3) == 0) {
197 } else if (strncmp (&src[i], "gt;", 3) == 0) {
212 /* iksemel (XML parser for Jabber)
213 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
214 ** This code is free software; you can redistribute it and/or
215 ** modify it under the terms of GNU Lesser General Public License.
221 struct align_test { char a; double b; };
222 #define DEFAULT_ALIGNMENT ((size_t) ((char *) &((struct align_test *) 0)->b - (char *) 0))
223 #define ALIGN_MASK ( DEFAULT_ALIGNMENT - 1 )
224 #define MIN_CHUNK_SIZE ( DEFAULT_ALIGNMENT * 8 )
225 #define MIN_ALLOC_SIZE DEFAULT_ALIGNMENT
226 #define ALIGN(x) ( (x) + (DEFAULT_ALIGNMENT - ( (x) & ALIGN_MASK)) )
228 typedef struct ikschunk_struct {
229 struct ikschunk_struct *next;
236 struct ikstack_struct {
243 find_space (ikstack *s, ikschunk *c, size_t size)
245 /* FIXME: dont use *2 after over allocated chunks */
247 if (c->size - c->used >= size) return c;
249 if ((c->size * 2) > size) size = c->size * 2;
250 c->next = iks_malloc (sizeof (ikschunk) + size);
251 if (!c->next) return NULL;
252 s->allocated += sizeof (ikschunk) + size;
257 c->last = (size_t) -1;
266 iks_stack_new (size_t meta_chunk, size_t data_chunk)
271 if (meta_chunk < MIN_CHUNK_SIZE) meta_chunk = MIN_CHUNK_SIZE;
272 if (meta_chunk & ALIGN_MASK) meta_chunk = ALIGN (meta_chunk);
273 if (data_chunk < MIN_CHUNK_SIZE) data_chunk = MIN_CHUNK_SIZE;
274 if (data_chunk & ALIGN_MASK) data_chunk = ALIGN (data_chunk);
276 len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2);
277 s = iks_malloc (len);
280 s->meta = (ikschunk *) ((char *) s + sizeof (ikstack));
281 s->meta->next = NULL;
282 s->meta->size = meta_chunk;
284 s->meta->last = (size_t) -1;
285 s->data = (ikschunk *) ((char *) s + sizeof (ikstack) + sizeof (ikschunk) + meta_chunk);
286 s->data->next = NULL;
287 s->data->size = data_chunk;
289 s->data->last = (size_t) -1;
294 iks_stack_alloc (ikstack *s, size_t size)
299 if (size < MIN_ALLOC_SIZE) size = MIN_ALLOC_SIZE;
300 if (size & ALIGN_MASK) size = ALIGN (size);
302 c = find_space (s, s->meta, size);
304 mem = c->data + c->used;
310 iks_stack_strdup (ikstack *s, const char *src, size_t len)
315 if (!src) return NULL;
316 if (0 == len) len = strlen (src);
318 c = find_space (s, s->data, len + 1);
320 dest = c->data + c->used;
323 memcpy (dest, src, len);
329 iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len)
335 return iks_stack_strdup (s, src, src_len);
337 if (0 == old_len) old_len = strlen (old);
338 if (0 == src_len) src_len = strlen (src);
340 for (c = s->data; c; c = c->next) {
341 if (c->data + c->last == old) break;
344 c = find_space (s, s->data, old_len + src_len + 1);
346 ret = c->data + c->used;
348 c->used += old_len + src_len + 1;
349 memcpy (ret, old, old_len);
350 memcpy (ret + old_len, src, src_len);
351 ret[old_len + src_len] = '\0';
355 if (c->size - c->used > src_len) {
356 ret = c->data + c->last;
357 memcpy (ret + old_len, src, src_len);
359 ret[old_len + src_len] = '\0';
361 /* FIXME: decrease c->used before moving string to new place */
362 c = find_space (s, s->data, old_len + src_len + 1);
365 ret = c->data + c->used;
366 memcpy (ret, old, old_len);
368 memcpy (c->data + c->used, src, src_len);
370 c->data[c->used] = '\0';
377 iks_stack_stat (ikstack *s, size_t *allocated, size_t *used)
382 *allocated = s->allocated;
386 for (c = s->meta; c; c = c->next) {
389 for (c = s->data; c; c = c->next) {
396 iks_stack_delete (ikstack *s)
414 /* iksemel (XML parser for Jabber)
415 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
416 ** This code is free software; you can redistribute it and/or
417 ** modify it under the terms of GNU Lesser General Public License.
454 /* if you add a variable here, dont forget changing iks_parser_reset */
455 struct iksparser_struct {
459 iksCDataHook *cdataHook;
460 iksDeleteHook *deleteHook;
467 enum cons_e oldcontext;
470 enum ikstagtype tagtype;
481 unsigned long nr_bytes;
482 unsigned long nr_lines;
489 iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook)
493 prs = iks_malloc (sizeof (iksparser));
494 if (NULL == prs) return NULL;
495 memset (prs, 0, sizeof (iksparser));
496 prs->user_data = user_data;
497 prs->tagHook = tagHook;
498 prs->cdataHook = cdataHook;
503 iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook)
507 prs = iks_stack_alloc (s, sizeof (iksparser));
508 if (NULL == prs) return NULL;
509 memset (prs, 0, sizeof (iksparser));
511 prs->user_data = user_data;
512 prs->tagHook = tagHook;
513 prs->cdataHook = cdataHook;
514 prs->deleteHook = deleteHook;
519 iks_parser_stack (iksparser *prs)
525 iks_user_data (iksparser *prs)
527 return prs->user_data;
531 iks_nr_bytes (iksparser *prs)
533 return prs->nr_bytes;
537 iks_nr_lines (iksparser *prs)
539 return prs->nr_lines;
542 #define IS_WHITESPACE(x) ' ' == (x) || '\t' == (x) || '\r' == (x) || '\n' == (x)
543 #define NOT_WHITESPACE(x) ' ' != (x) && '\t' != (x) && '\r' != (x) && '\n' != (x)
546 stack_init (iksparser *prs)
548 prs->stack = iks_malloc (128);
549 if (!prs->stack) return 0;
550 prs->stack_max = 128;
556 stack_expand (iksparser *prs, int len)
561 need = len - (prs->stack_max - prs->stack_pos);
562 if (need < prs->stack_max) {
563 need = prs->stack_max * 2;
565 need = prs->stack_max + (need * 1.2);
567 tmp = iks_malloc (need);
569 diff = tmp - prs->stack;
570 memcpy (tmp, prs->stack, prs->stack_max);
571 iks_free (prs->stack);
573 prs->stack_max = need;
574 prs->tag_name += diff;
575 if (prs->attflag != 0) {
577 while (i < (prs->attmax * 2)) {
578 if (prs->atts[i]) prs->atts[i] += diff;
586 if (NULL == prs->stack && 0 == stack_init (prs)) return IKS_NOMEM
588 #define STACK_PUSH_START (prs->stack + prs->stack_pos)
590 #define STACK_PUSH(buf,len) \
592 char *sbuf = (buf); \
593 size_t slen = (len); \
594 if (prs->stack_max - prs->stack_pos <= slen) { \
595 if (0 == stack_expand (prs, slen)) return IKS_NOMEM; \
597 memcpy (prs->stack + prs->stack_pos, sbuf, slen); \
598 prs->stack_pos += slen; \
601 #define STACK_PUSH_END \
603 if (prs->stack_pos >= prs->stack_max) { \
604 if (0 == stack_expand (prs, 1)) return IKS_NOMEM; \
606 prs->stack[prs->stack_pos] = '\0'; \
611 sax_core (iksparser *prs, char *buf, int len)
614 int pos = 0, old = 0, re, stack_old = -1;
620 if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML;
622 if ((c & 0xC0) != 0x80) return IKS_BADXML;
624 if (prs->uni_len == prs->uni_max) prs->uni_max = 0;
629 if ((c & 0x60) == 0x40) {
632 } else if ((c & 0x70) == 0x60) {
635 } else if ((c & 0x78) == 0x70) {
638 } else if ((c & 0x7C) == 0x78) {
641 } else if ((c & 0x7E) == 0x7C) {
647 if ((c & mask) == 0) return IKS_BADXML;
649 if (stack_old == -1) stack_old = pos;
654 switch (prs->context) {
657 if (old < pos && prs->cdataHook) {
658 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
659 if (IKS_OK != err) return err;
661 prs->context = C_ENTITY;
666 if (old < pos && prs->cdataHook) {
667 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
668 if (IKS_OK != err) return err;
671 prs->tag_name = STACK_PUSH_START;
672 if (!prs->tag_name) return IKS_NOMEM;
673 prs->context = C_TAG_START;
678 prs->context = C_TAG;
680 prs->tagtype = IKS_CLOSE;
688 prs->context = C_MARKUP;
691 prs->tagtype = IKS_OPEN;
696 if (IS_WHITESPACE(c)) {
697 if (IKS_CLOSE == prs->tagtype)
698 prs->oldcontext = C_TAG_END;
700 prs->oldcontext = C_ATTRIBUTE;
701 prs->context = C_WHITESPACE;
702 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
708 if (IKS_CLOSE == prs->tagtype) return IKS_BADXML;
709 prs->tagtype = IKS_SINGLE;
710 prs->context = C_TAG_END;
711 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
717 prs->context = C_TAG_END;
718 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
723 if (stack_old == -1) stack_old = pos;
727 if (c != '>') return IKS_BADXML;
730 if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts;
731 err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype);
732 if (IKS_OK != err) return err;
738 prs->context = C_CDATA;
744 prs->tagtype = IKS_SINGLE;
745 prs->context = C_TAG_END;
749 prs->context = C_TAG_END;
755 prs->atts = iks_malloc (sizeof(char *) * 2 * 12);
756 if (!prs->atts) return IKS_NOMEM;
757 memset (prs->atts, 0, sizeof(char *) * 2 * 12);
760 if (prs->attcur >= (prs->attmax * 2)) {
763 tmp = iks_malloc (sizeof(char *) * 2 * prs->attmax);
764 if (!tmp) return IKS_NOMEM;
765 memset (tmp, 0, sizeof(char *) * 2 * prs->attmax);
766 memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur);
772 prs->atts[prs->attcur] = STACK_PUSH_START;
774 prs->context = C_ATTRIBUTE_1;
779 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
782 prs->context = C_VALUE;
785 if (stack_old == -1) stack_old = pos;
790 prs->tagtype = IKS_SINGLE;
791 prs->atts[prs->attcur] = NULL;
792 prs->context = C_TAG_END;
796 prs->atts[prs->attcur] = NULL;
797 prs->context = C_TAG_END;
801 prs->context = C_ATTRIBUTE;
806 prs->atts[prs->attcur + 1] = STACK_PUSH_START;
808 prs->context = C_VALUE_APOS;
812 prs->context = C_VALUE_QUOT;
819 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
822 prs->oldcontext = C_ATTRIBUTE_2;
823 prs->context = C_WHITESPACE;
826 if (stack_old == -1) stack_old = pos;
831 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
834 prs->oldcontext = C_ATTRIBUTE_2;
835 prs->context = C_WHITESPACE;
838 if (stack_old == -1) stack_old = pos;
842 if (NOT_WHITESPACE(c)) {
843 prs->context = prs->oldcontext;
852 prs->entity[prs->entpos] = '\0';
853 if (strcmp(prs->entity, "amp") == 0)
855 else if (strcmp(prs->entity, "quot") == 0)
857 else if (strcmp(prs->entity, "apos") == 0)
859 else if (strcmp(prs->entity, "lt") == 0)
861 else if (strcmp(prs->entity, "gt") == 0)
865 if (prs->cdataHook) {
866 err = prs->cdataHook (prs->user_data, &hede[0], 1);
867 if (IKS_OK != err) return err;
869 prs->context = C_CDATA;
871 prs->entity[prs->entpos++] = buf[pos];
872 if (prs->entpos > 7) return IKS_BADXML;
877 if ('-' != c) return IKS_BADXML;
878 prs->context = C_COMMENT_1;
882 if ('-' == c) prs->context = C_COMMENT_2;
887 prs->context = C_COMMENT_3;
889 prs->context = C_COMMENT_1;
893 if ('>' != c) return IKS_BADXML;
894 prs->context = C_CDATA;
900 prs->context = C_SECT;
904 prs->context = C_COMMENT;
907 prs->context = C_MARKUP_1;
912 prs->context = C_CDATA;
918 prs->context = C_SECT_CDATA;
924 if ('D' != c) return IKS_BADXML;
925 prs->context = C_SECT_CDATA_1;
929 if ('A' != c) return IKS_BADXML;
930 prs->context = C_SECT_CDATA_2;
934 if ('T' != c) return IKS_BADXML;
935 prs->context = C_SECT_CDATA_3;
939 if ('A' != c) return IKS_BADXML;
940 prs->context = C_SECT_CDATA_4;
944 if ('[' != c) return IKS_BADXML;
946 prs->context = C_SECT_CDATA_C;
951 prs->context = C_SECT_CDATA_E;
952 if (prs->cdataHook && old < pos) {
953 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
954 if (IKS_OK != err) return err;
961 prs->context = C_SECT_CDATA_E2;
963 if (prs->cdataHook) {
964 err = prs->cdataHook (prs->user_data, "]", 1);
965 if (IKS_OK != err) return err;
968 prs->context = C_SECT_CDATA_C;
972 case C_SECT_CDATA_E2:
975 prs->context = C_CDATA;
977 if (prs->cdataHook) {
978 err = prs->cdataHook (prs->user_data, "]]", 2);
979 if (IKS_OK != err) return err;
982 prs->context = C_SECT_CDATA_C;
988 if ('>' == c) prs->context = C_CDATA;
995 if ('\n' == c) prs->nr_lines++;
1000 STACK_PUSH (buf + stack_old, pos - stack_old);
1003 if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos)
1004 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
1009 iks_parse (iksparser *prs, const char *data, size_t len, int finish)
1011 if (!data) return IKS_OK;
1012 if (len == 0) len = strlen (data);
1013 return sax_core (prs, (char *) data, len);
1017 iks_parser_reset (iksparser *prs)
1019 if (prs->deleteHook) prs->deleteHook (prs->user_data);
1022 prs->oldcontext = 0;
1035 iks_parser_delete (iksparser *prs)
1037 if (prs->deleteHook) prs->deleteHook (prs->user_data);
1038 if (prs->stack) iks_free (prs->stack);
1039 if (prs->atts) iks_free (prs->atts);
1040 if (prs->s) iks_stack_delete (prs->s); else iks_free (prs);
1042 /* iksemel (XML parser for Jabber)
1043 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
1044 ** This code is free software; you can redistribute it and/or
1045 ** modify it under the terms of GNU Lesser General Public License.
1049 #include "iksemel.h"
1051 #define IKS_COMMON \
1052 struct iks_struct *next, *prev; \
1053 struct iks_struct *parent; \
1054 enum ikstype type; \
1063 struct iks_struct *children, *last_child;
1064 struct iks_struct *attribs, *last_attrib;
1068 #define IKS_TAG_NAME(x) ((struct iks_tag *) (x) )->name
1069 #define IKS_TAG_CHILDREN(x) ((struct iks_tag *) (x) )->children
1070 #define IKS_TAG_LAST_CHILD(x) ((struct iks_tag *) (x) )->last_child
1071 #define IKS_TAG_ATTRIBS(x) ((struct iks_tag *) (x) )->attribs
1072 #define IKS_TAG_LAST_ATTRIB(x) ((struct iks_tag *) (x) )->last_attrib
1080 #define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata
1081 #define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len
1089 #define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name
1090 #define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value
1092 /***** Node Creating & Deleting *****/
1095 iks_new (const char *name)
1100 s = iks_stack_new (sizeof (struct iks_tag) * 6, 256);
1101 if (!s) return NULL;
1102 x = iks_new_within (name, s);
1104 iks_stack_delete (s);
1111 iks_new_within (const char *name, ikstack *s)
1116 if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata);
1117 x = iks_stack_alloc (s, len);
1118 if (!x) return NULL;
1123 IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0);
1124 if (!IKS_TAG_NAME (x)) return NULL;
1130 iks_insert (iks *x, const char *name)
1134 if (!x) return NULL;
1136 y = iks_new_within (name, x->s);
1137 if (!y) return NULL;
1139 if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
1140 if (IKS_TAG_LAST_CHILD (x)) {
1141 IKS_TAG_LAST_CHILD (x)->next = y;
1142 y->prev = IKS_TAG_LAST_CHILD (x);
1144 IKS_TAG_LAST_CHILD (x) = y;
1149 iks_insert_cdata (iks *x, const char *data, size_t len)
1153 if(!x || !data) return NULL;
1154 if(len == 0) len = strlen (data);
1156 y = IKS_TAG_LAST_CHILD (x);
1157 if (y && y->type == IKS_CDATA) {
1158 IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len);
1159 IKS_CDATA_LEN (y) += len;
1161 y = iks_insert (x, NULL);
1162 if (!y) return NULL;
1163 y->type = IKS_CDATA;
1164 IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len);
1165 if (!IKS_CDATA_CDATA (y)) return NULL;
1166 IKS_CDATA_LEN (y) = len;
1172 iks_insert_attrib (iks *x, const char *name, const char *value)
1177 if (!x) return NULL;
1179 y = IKS_TAG_ATTRIBS (x);
1181 if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break;
1185 if (!value) return NULL;
1186 y = iks_stack_alloc (x->s, sizeof (struct iks_attrib));
1187 if (!y) return NULL;
1188 memset (y, 0, sizeof (struct iks_attrib));
1189 y->type = IKS_ATTRIBUTE;
1190 IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0);
1192 if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y;
1193 if (IKS_TAG_LAST_ATTRIB (x)) {
1194 IKS_TAG_LAST_ATTRIB (x)->next = y;
1195 y->prev = IKS_TAG_LAST_ATTRIB (x);
1197 IKS_TAG_LAST_ATTRIB (x) = y;
1201 len = strlen (value);
1202 IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, len);
1203 if (!IKS_ATTRIB_VALUE (y)) return NULL;
1205 if (y->next) y->next->prev = y->prev;
1206 if (y->prev) y->prev->next = y->next;
1207 if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next;
1208 if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev;
1215 iks_insert_node (iks *x, iks *y)
1218 if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
1219 if (IKS_TAG_LAST_CHILD (x)) {
1220 IKS_TAG_LAST_CHILD (x)->next = y;
1221 y->prev = IKS_TAG_LAST_CHILD (x);
1223 IKS_TAG_LAST_CHILD (x) = y;
1234 if (x->prev) x->prev->next = x->next;
1235 if (x->next) x->next->prev = x->prev;
1238 if (IKS_TAG_CHILDREN (y) == x) IKS_TAG_CHILDREN (y) = x->next;
1239 if (IKS_TAG_LAST_CHILD (y) == x) IKS_TAG_LAST_CHILD (y) = x->prev;
1246 if (x) iks_stack_delete (x->s);
1249 /***** Node Traversing *****/
1254 if (x) return x->next;
1259 iks_next_tag (iks *x)
1264 if (NULL == x) break;
1265 if (IKS_TAG == x->type) return x;
1274 if (x) return x->prev;
1279 iks_prev_tag (iks *x)
1284 if (NULL == x) break;
1285 if (IKS_TAG == x->type) return x;
1294 if (x) return x->parent;
1311 if (x) return IKS_TAG_CHILDREN (x);
1316 iks_first_tag (iks *x)
1319 x = IKS_TAG_CHILDREN (x);
1321 if (IKS_TAG == x->type) return x;
1331 if (x) return IKS_TAG_ATTRIBS (x);
1336 iks_find (iks *x, const char *name)
1340 if (!x) return NULL;
1341 y = IKS_TAG_CHILDREN (x);
1343 if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y;
1350 iks_find_cdata (iks *x, const char *name)
1354 y = iks_find (x, name);
1355 if (!y) return NULL;
1356 y = IKS_TAG_CHILDREN (y);
1357 if (!y || IKS_CDATA != y->type) return NULL;
1358 return IKS_CDATA_CDATA (y);
1362 iks_find_attrib (iks *x, const char *name)
1366 if (!x) return NULL;
1368 y = IKS_TAG_ATTRIBS (x);
1370 if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0)
1371 return IKS_ATTRIB_VALUE (y);
1378 iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value)
1382 if (NULL == x) return NULL;
1385 for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
1386 if (IKS_TAG == y->type
1387 && strcmp (IKS_TAG_NAME (y), tagname) == 0
1388 && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
1393 for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
1394 if (IKS_TAG == y->type
1395 && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
1403 /***** Node Information *****/
1415 if (x) return x->type;
1423 if (IKS_TAG == x->type)
1424 return IKS_TAG_NAME (x);
1426 return IKS_ATTRIB_NAME (x);
1435 if (IKS_CDATA == x->type)
1436 return IKS_CDATA_CDATA (x);
1438 return IKS_ATTRIB_VALUE (x);
1444 iks_cdata_size (iks *x)
1446 if (x) return IKS_CDATA_LEN (x);
1451 iks_has_children (iks *x)
1453 if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1;
1458 iks_has_attribs (iks *x)
1460 if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1;
1464 /***** Serializing *****/
1467 escape_size (char *src, size_t len)
1474 for (i = 0; i < len; i++) {
1477 case '&': sz += 5; break;
1478 case '\'': sz += 6; break;
1479 case '"': sz += 6; break;
1480 case '<': sz += 4; break;
1481 case '>': sz += 4; break;
1482 default: sz++; break;
1489 my_strcat (char *dest, char *src, size_t len)
1491 if (0 == len) len = strlen (src);
1492 memcpy (dest, src, len);
1497 escape (char *dest, char *src, size_t len)
1503 for (i = 0; i < len; i++) {
1505 if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) {
1506 if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1509 case '&': dest = my_strcat (dest, "&", 5); break;
1510 case '\'': dest = my_strcat (dest, "'", 6); break;
1511 case '"': dest = my_strcat (dest, """, 6); break;
1512 case '<': dest = my_strcat (dest, "<", 4); break;
1513 case '>': dest = my_strcat (dest, ">", 4); break;
1517 if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1522 iks_string (ikstack *s, iks *x)
1529 if (!x) return NULL;
1531 if (x->type == IKS_CDATA) {
1533 return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1535 ret = iks_malloc (IKS_CDATA_LEN (x));
1536 memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1547 if (y->type == IKS_TAG) {
1549 size += strlen (IKS_TAG_NAME (y));
1550 for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) {
1551 size += 4 + strlen (IKS_ATTRIB_NAME (z))
1552 + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z)));
1554 if (IKS_TAG_CHILDREN (y)) {
1556 y = IKS_TAG_CHILDREN (y);
1563 size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y));
1569 if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y));
1577 if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y));
1578 if (level < 1) break;
1583 if (s) ret = iks_stack_alloc (s, size + 1);
1584 else ret = iks_malloc (size + 1);
1586 if (!ret) return NULL;
1593 if (x->type == IKS_TAG) {
1595 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1596 y = IKS_TAG_ATTRIBS (x);
1599 t = my_strcat (t, IKS_ATTRIB_NAME (y), 0);
1602 t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y)));
1606 if (IKS_TAG_CHILDREN (x)) {
1608 x = IKS_TAG_CHILDREN (x);
1616 t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1622 if (IKS_TAG_CHILDREN (x)) {
1625 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1638 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1641 if (level < 1) break;
1650 /***** Copying *****/
1653 iks_copy_within (iks *x, ikstack *s)
1662 if (x->type == IKS_TAG) {
1664 copy = iks_new_within (IKS_TAG_NAME (x), s);
1667 cur = iks_insert (cur, IKS_TAG_NAME (x));
1669 for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) {
1670 iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y));
1672 if (IKS_TAG_CHILDREN (x)) {
1673 x = IKS_TAG_CHILDREN (x);
1680 iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1685 if (0 == level) break;
1689 if (level < 2) break;
1702 return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256));
1704 /* iksemel (XML parser for Jabber)
1705 ** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
1706 ** This code is free software; you can redistribute it and/or
1707 ** modify it under the terms of GNU Lesser General Public License.
1711 #include "iksemel.h"
1720 tagHook (struct dom_data *data, char *name, char **atts, int type)
1724 if (IKS_OPEN == type || IKS_SINGLE == type) {
1725 if (data->current) {
1726 x = iks_insert (data->current, name);
1729 s = iks_stack_new (data->chunk_size, data->chunk_size);
1730 x = iks_new_within (name, s);
1735 iks_insert_attrib (x, atts[i], atts[i+1]);
1741 if (IKS_CLOSE == type || IKS_SINGLE == type) {
1742 x = iks_parent (data->current);
1746 *(data->iksptr) = data->current;
1747 data->current = NULL;
1754 cdataHook (struct dom_data *data, char *cdata, size_t len)
1756 if (data->current) iks_insert_cdata (data->current, cdata, len);
1761 deleteHook (struct dom_data *data)
1763 if (data->current) iks_delete (data->current);
1764 data->current = NULL;
1768 iks_dom_new (iks **iksptr)
1771 struct dom_data *data;
1774 s = iks_stack_new (DEFAULT_DOM_CHUNK_SIZE, 0);
1775 if (!s) return NULL;
1776 data = iks_stack_alloc (s, sizeof (struct dom_data));
1777 data->iksptr = iksptr;
1778 data->current = NULL;
1779 data->chunk_size = DEFAULT_DOM_IKS_CHUNK_SIZE;
1780 return iks_sax_extend (s, data, (iksTagHook *) tagHook, (iksCDataHook *) cdataHook, (iksDeleteHook *) deleteHook);
1784 iks_set_size_hint (iksparser *prs, size_t approx_size)
1787 struct dom_data *data = iks_user_data (prs);
1789 cs = approx_size / 10;
1790 if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE;
1791 data->chunk_size = cs;
1795 iks_tree (const char *xml_str, size_t len, int *err)
1801 if (0 == len) len = strlen (xml_str);
1802 prs = iks_dom_new (&x);
1804 if (err) *err = IKS_NOMEM;
1807 e = iks_parse (prs, xml_str, len, 1);
1809 iks_parser_delete (prs);
1814 iks_load (const char *fname, iks **xptr)
1824 buf = iks_malloc (FILE_IO_BUF_SIZE);
1825 if (!buf) return IKS_NOMEM;
1827 prs = iks_dom_new (xptr);
1829 f = fopen (fname, "r");
1832 len = fread (buf, 1, FILE_IO_BUF_SIZE, f);
1833 if (len < FILE_IO_BUF_SIZE) {
1834 if (0 == feof (f)) {
1835 ret = IKS_FILE_RWERR;
1842 e = iks_parse (prs, buf, len, done);
1847 if (done) ret = IKS_OK;
1852 if (ENOENT == errno) ret = IKS_FILE_NOFILE;
1853 else ret = IKS_FILE_NOACCESS;
1855 iks_parser_delete (prs);
1862 iks_save (const char *fname, iks *x)
1869 data = iks_string (NULL, x);
1871 ret = IKS_FILE_NOACCESS;
1872 f = fopen (fname, "w");
1874 ret = IKS_FILE_RWERR;
1875 if (fputs (data, f) >= 0) ret = IKS_OK;