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.
42 /***** malloc wrapper *****/
44 static void *(*my_malloc_func)(size_t size);
45 static void (*my_free_func)(void *ptr);
48 iks_malloc (size_t size)
51 return my_malloc_func (size);
66 iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr))
68 my_malloc_func = malloc_func;
69 my_free_func = free_func;
72 /***** NULL-safe Functions *****/
75 iks_strdup (const char *src)
77 if (src) return strdup(src);
82 iks_strcat (char *dest, const char *src)
86 if (!src) return dest;
89 memcpy (dest, src, len);
95 iks_strcmp (const char *a, const char *b)
97 if (!a || !b) return -1;
102 iks_strcasecmp (const char *a, const char *b)
104 if (!a || !b) return -1;
105 return strcasecmp (a, b);
109 iks_strncmp (const char *a, const char *b, size_t n)
111 if (!a || !b) return -1;
112 return strncmp (a, b, n);
116 iks_strncasecmp (const char *a, const char *b, size_t n)
118 if (!a || !b) return -1;
119 return strncasecmp (a, b, n);
123 iks_strlen (const char *src)
129 /***** XML Escaping *****/
132 iks_escape (ikstack *s, char *src, size_t len)
137 if (!src || !s) return NULL;
138 if (len == -1) len = strlen (src);
141 for (i=0; i<len; i++) {
143 case '&': nlen += 4; break;
144 case '<': nlen += 3; break;
145 case '>': nlen += 3; break;
146 case '\'': nlen += 5; break;
147 case '"': nlen += 5; break;
150 if (len == nlen) return src;
152 ret = iks_stack_alloc (s, nlen + 1);
153 if (!ret) return NULL;
155 for (i=j=0; i<len; i++) {
157 case '&': memcpy (&ret[j], "&", 5); j += 5; break;
158 case '\'': memcpy (&ret[j], "'", 6); j += 6; break;
159 case '"': memcpy (&ret[j], """, 6); j += 6; break;
160 case '<': memcpy (&ret[j], "<", 4); j += 4; break;
161 case '>': memcpy (&ret[j], ">", 4); j += 4; break;
162 default: ret[j++] = src[i];
171 iks_unescape (ikstack *s, char *src, size_t len)
176 if (!s || !src) return NULL;
177 if (!strchr (src, '&')) return src;
178 if (len == -1) len = strlen (src);
180 ret = iks_stack_alloc (s, len + 1);
181 if (!ret) return NULL;
183 for (i=j=0; i<len; i++) {
186 if (strncmp (&src[i], "amp;", 4) == 0) {
189 } else if (strncmp (&src[i], "quot;", 5) == 0) {
192 } else if (strncmp (&src[i], "apos;", 5) == 0) {
195 } else if (strncmp (&src[i], "lt;", 3) == 0) {
198 } else if (strncmp (&src[i], "gt;", 3) == 0) {
213 /* iksemel (XML parser for Jabber)
214 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
215 ** This code is free software; you can redistribute it and/or
216 ** modify it under the terms of GNU Lesser General Public License.
222 struct align_test { char a; double b; };
223 #define DEFAULT_ALIGNMENT ((size_t) ((char *) &((struct align_test *) 0)->b - (char *) 0))
224 #define ALIGN_MASK ( DEFAULT_ALIGNMENT - 1 )
225 #define MIN_CHUNK_SIZE ( DEFAULT_ALIGNMENT * 8 )
226 #define MIN_ALLOC_SIZE DEFAULT_ALIGNMENT
227 #define ALIGN(x) ( (x) + (DEFAULT_ALIGNMENT - ( (x) & ALIGN_MASK)) )
229 typedef struct ikschunk_struct {
230 struct ikschunk_struct *next;
237 struct ikstack_struct {
244 find_space (ikstack *s, ikschunk *c, size_t size)
246 /* FIXME: dont use *2 after over allocated chunks */
248 if (c->size - c->used >= size) return c;
250 if ((c->size * 2) > size) size = c->size * 2;
251 c->next = iks_malloc (sizeof (ikschunk) + size);
252 if (!c->next) return NULL;
253 s->allocated += sizeof (ikschunk) + size;
258 c->last = (size_t) -1;
267 iks_stack_new (size_t meta_chunk, size_t data_chunk)
272 if (meta_chunk < MIN_CHUNK_SIZE) meta_chunk = MIN_CHUNK_SIZE;
273 if (meta_chunk & ALIGN_MASK) meta_chunk = ALIGN (meta_chunk);
274 if (data_chunk < MIN_CHUNK_SIZE) data_chunk = MIN_CHUNK_SIZE;
275 if (data_chunk & ALIGN_MASK) data_chunk = ALIGN (data_chunk);
277 len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2);
278 s = iks_malloc (len);
281 s->meta = (ikschunk *) ((char *) s + sizeof (ikstack));
282 s->meta->next = NULL;
283 s->meta->size = meta_chunk;
285 s->meta->last = (size_t) -1;
286 s->data = (ikschunk *) ((char *) s + sizeof (ikstack) + sizeof (ikschunk) + meta_chunk);
287 s->data->next = NULL;
288 s->data->size = data_chunk;
290 s->data->last = (size_t) -1;
295 iks_stack_alloc (ikstack *s, size_t size)
300 if (size < MIN_ALLOC_SIZE) size = MIN_ALLOC_SIZE;
301 if (size & ALIGN_MASK) size = ALIGN (size);
303 c = find_space (s, s->meta, size);
305 mem = c->data + c->used;
311 iks_stack_strdup (ikstack *s, const char *src, size_t len)
316 if (!src) return NULL;
317 if (0 == len) len = strlen (src);
319 c = find_space (s, s->data, len + 1);
321 dest = c->data + c->used;
324 memcpy (dest, src, len);
330 iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len)
336 return iks_stack_strdup (s, src, src_len);
338 if (0 == old_len) old_len = strlen (old);
339 if (0 == src_len) src_len = strlen (src);
341 for (c = s->data; c; c = c->next) {
342 if (c->data + c->last == old) break;
345 c = find_space (s, s->data, old_len + src_len + 1);
347 ret = c->data + c->used;
349 c->used += old_len + src_len + 1;
350 memcpy (ret, old, old_len);
351 memcpy (ret + old_len, src, src_len);
352 ret[old_len + src_len] = '\0';
356 if (c->size - c->used > src_len) {
357 ret = c->data + c->last;
358 memcpy (ret + old_len, src, src_len);
360 ret[old_len + src_len] = '\0';
362 /* FIXME: decrease c->used before moving string to new place */
363 c = find_space (s, s->data, old_len + src_len + 1);
366 ret = c->data + c->used;
367 memcpy (ret, old, old_len);
369 memcpy (c->data + c->used, src, src_len);
371 c->data[c->used] = '\0';
378 iks_stack_stat (ikstack *s, size_t *allocated, size_t *used)
383 *allocated = s->allocated;
387 for (c = s->meta; c; c = c->next) {
390 for (c = s->data; c; c = c->next) {
397 iks_stack_delete (ikstack *s)
415 /* iksemel (XML parser for Jabber)
416 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
417 ** This code is free software; you can redistribute it and/or
418 ** modify it under the terms of GNU Lesser General Public License.
455 /* if you add a variable here, dont forget changing iks_parser_reset */
456 struct iksparser_struct {
460 iksCDataHook *cdataHook;
461 iksDeleteHook *deleteHook;
468 enum cons_e oldcontext;
471 enum ikstagtype tagtype;
482 unsigned long nr_bytes;
483 unsigned long nr_lines;
490 iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook)
494 prs = iks_malloc (sizeof (iksparser));
495 if (NULL == prs) return NULL;
496 memset (prs, 0, sizeof (iksparser));
497 prs->user_data = user_data;
498 prs->tagHook = tagHook;
499 prs->cdataHook = cdataHook;
504 iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook)
508 prs = iks_stack_alloc (s, sizeof (iksparser));
509 if (NULL == prs) return NULL;
510 memset (prs, 0, sizeof (iksparser));
512 prs->user_data = user_data;
513 prs->tagHook = tagHook;
514 prs->cdataHook = cdataHook;
515 prs->deleteHook = deleteHook;
520 iks_parser_stack (iksparser *prs)
526 iks_user_data (iksparser *prs)
528 return prs->user_data;
532 iks_nr_bytes (iksparser *prs)
534 return prs->nr_bytes;
538 iks_nr_lines (iksparser *prs)
540 return prs->nr_lines;
543 #define IS_WHITESPACE(x) ' ' == (x) || '\t' == (x) || '\r' == (x) || '\n' == (x)
544 #define NOT_WHITESPACE(x) ' ' != (x) && '\t' != (x) && '\r' != (x) && '\n' != (x)
547 stack_init (iksparser *prs)
549 prs->stack = iks_malloc (128);
550 if (!prs->stack) return 0;
551 prs->stack_max = 128;
557 stack_expand (iksparser *prs, int len)
562 need = len - (prs->stack_max - prs->stack_pos);
563 if (need < prs->stack_max) {
564 need = prs->stack_max * 2;
566 need = prs->stack_max + (need * 1.2);
568 tmp = iks_malloc (need);
570 diff = tmp - prs->stack;
571 memcpy (tmp, prs->stack, prs->stack_max);
572 iks_free (prs->stack);
574 prs->stack_max = need;
575 prs->tag_name += diff;
576 if (prs->attflag != 0) {
578 while (i < (prs->attmax * 2)) {
579 if (prs->atts[i]) prs->atts[i] += diff;
587 if (NULL == prs->stack && 0 == stack_init (prs)) return IKS_NOMEM
589 #define STACK_PUSH_START (prs->stack + prs->stack_pos)
591 #define STACK_PUSH(buf,len) \
593 char *sbuf = (buf); \
594 size_t slen = (len); \
595 if (prs->stack_max - prs->stack_pos <= slen) { \
596 if (0 == stack_expand (prs, slen)) return IKS_NOMEM; \
598 memcpy (prs->stack + prs->stack_pos, sbuf, slen); \
599 prs->stack_pos += slen; \
602 #define STACK_PUSH_END \
604 if (prs->stack_pos >= prs->stack_max) { \
605 if (0 == stack_expand (prs, 1)) return IKS_NOMEM; \
607 prs->stack[prs->stack_pos] = '\0'; \
612 sax_core (iksparser *prs, char *buf, int len)
615 int pos = 0, old = 0, re, stack_old = -1;
621 if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML;
623 if ((c & 0xC0) != 0x80) return IKS_BADXML;
625 if (prs->uni_len == prs->uni_max) prs->uni_max = 0;
630 if ((c & 0x60) == 0x40) {
633 } else if ((c & 0x70) == 0x60) {
636 } else if ((c & 0x78) == 0x70) {
639 } else if ((c & 0x7C) == 0x78) {
642 } else if ((c & 0x7E) == 0x7C) {
648 if ((c & mask) == 0) return IKS_BADXML;
650 if (stack_old == -1) stack_old = pos;
655 switch (prs->context) {
658 if (old < pos && prs->cdataHook) {
659 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
660 if (IKS_OK != err) return err;
662 prs->context = C_ENTITY;
667 if (old < pos && prs->cdataHook) {
668 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
669 if (IKS_OK != err) return err;
672 prs->tag_name = STACK_PUSH_START;
673 if (!prs->tag_name) return IKS_NOMEM;
674 prs->context = C_TAG_START;
679 prs->context = C_TAG;
681 prs->tagtype = IKS_CLOSE;
689 prs->context = C_MARKUP;
692 prs->tagtype = IKS_OPEN;
697 if (IS_WHITESPACE(c)) {
698 if (IKS_CLOSE == prs->tagtype)
699 prs->oldcontext = C_TAG_END;
701 prs->oldcontext = C_ATTRIBUTE;
702 prs->context = C_WHITESPACE;
703 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
709 if (IKS_CLOSE == prs->tagtype) return IKS_BADXML;
710 prs->tagtype = IKS_SINGLE;
711 prs->context = C_TAG_END;
712 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
718 prs->context = C_TAG_END;
719 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
724 if (stack_old == -1) stack_old = pos;
728 if (c != '>') return IKS_BADXML;
731 if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts;
732 err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype);
733 if (IKS_OK != err) return err;
739 prs->context = C_CDATA;
745 prs->tagtype = IKS_SINGLE;
746 prs->context = C_TAG_END;
750 prs->context = C_TAG_END;
756 prs->atts = iks_malloc (sizeof(char *) * 2 * 12);
757 if (!prs->atts) return IKS_NOMEM;
758 memset (prs->atts, 0, sizeof(char *) * 2 * 12);
761 if (prs->attcur >= (prs->attmax * 2)) {
764 tmp = iks_malloc (sizeof(char *) * 2 * prs->attmax);
765 if (!tmp) return IKS_NOMEM;
766 memset (tmp, 0, sizeof(char *) * 2 * prs->attmax);
767 memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur);
773 prs->atts[prs->attcur] = STACK_PUSH_START;
775 prs->context = C_ATTRIBUTE_1;
780 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
783 prs->context = C_VALUE;
786 if (stack_old == -1) stack_old = pos;
791 prs->tagtype = IKS_SINGLE;
792 prs->atts[prs->attcur] = NULL;
793 prs->context = C_TAG_END;
797 prs->atts[prs->attcur] = NULL;
798 prs->context = C_TAG_END;
802 prs->context = C_ATTRIBUTE;
807 prs->atts[prs->attcur + 1] = STACK_PUSH_START;
809 prs->context = C_VALUE_APOS;
813 prs->context = C_VALUE_QUOT;
820 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
823 prs->oldcontext = C_ATTRIBUTE_2;
824 prs->context = C_WHITESPACE;
827 if (stack_old == -1) stack_old = pos;
832 if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
835 prs->oldcontext = C_ATTRIBUTE_2;
836 prs->context = C_WHITESPACE;
839 if (stack_old == -1) stack_old = pos;
843 if (NOT_WHITESPACE(c)) {
844 prs->context = prs->oldcontext;
853 prs->entity[prs->entpos] = '\0';
854 if (strcmp(prs->entity, "amp") == 0)
856 else if (strcmp(prs->entity, "quot") == 0)
858 else if (strcmp(prs->entity, "apos") == 0)
860 else if (strcmp(prs->entity, "lt") == 0)
862 else if (strcmp(prs->entity, "gt") == 0)
866 if (prs->cdataHook) {
867 err = prs->cdataHook (prs->user_data, &hede[0], 1);
868 if (IKS_OK != err) return err;
870 prs->context = C_CDATA;
872 prs->entity[prs->entpos++] = buf[pos];
873 if (prs->entpos > 7) return IKS_BADXML;
878 if ('-' != c) return IKS_BADXML;
879 prs->context = C_COMMENT_1;
883 if ('-' == c) prs->context = C_COMMENT_2;
888 prs->context = C_COMMENT_3;
890 prs->context = C_COMMENT_1;
894 if ('>' != c) return IKS_BADXML;
895 prs->context = C_CDATA;
901 prs->context = C_SECT;
905 prs->context = C_COMMENT;
908 prs->context = C_MARKUP_1;
913 prs->context = C_CDATA;
919 prs->context = C_SECT_CDATA;
925 if ('D' != c) return IKS_BADXML;
926 prs->context = C_SECT_CDATA_1;
930 if ('A' != c) return IKS_BADXML;
931 prs->context = C_SECT_CDATA_2;
935 if ('T' != c) return IKS_BADXML;
936 prs->context = C_SECT_CDATA_3;
940 if ('A' != c) return IKS_BADXML;
941 prs->context = C_SECT_CDATA_4;
945 if ('[' != c) return IKS_BADXML;
947 prs->context = C_SECT_CDATA_C;
952 prs->context = C_SECT_CDATA_E;
953 if (prs->cdataHook && old < pos) {
954 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
955 if (IKS_OK != err) return err;
962 prs->context = C_SECT_CDATA_E2;
964 if (prs->cdataHook) {
965 err = prs->cdataHook (prs->user_data, "]", 1);
966 if (IKS_OK != err) return err;
969 prs->context = C_SECT_CDATA_C;
973 case C_SECT_CDATA_E2:
976 prs->context = C_CDATA;
978 if (prs->cdataHook) {
979 err = prs->cdataHook (prs->user_data, "]]", 2);
980 if (IKS_OK != err) return err;
983 prs->context = C_SECT_CDATA_C;
989 if ('>' == c) prs->context = C_CDATA;
996 if ('\n' == c) prs->nr_lines++;
1000 if (stack_old != -1)
1001 STACK_PUSH (buf + stack_old, pos - stack_old);
1004 if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos)
1005 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
1010 iks_parse (iksparser *prs, const char *data, size_t len, int finish)
1012 if (!data) return IKS_OK;
1013 if (len == 0) len = strlen (data);
1014 return sax_core (prs, (char *) data, len);
1018 iks_parser_reset (iksparser *prs)
1020 if (prs->deleteHook) prs->deleteHook (prs->user_data);
1023 prs->oldcontext = 0;
1036 iks_parser_delete (iksparser *prs)
1038 if (prs->deleteHook) prs->deleteHook (prs->user_data);
1039 if (prs->stack) iks_free (prs->stack);
1040 if (prs->atts) iks_free (prs->atts);
1041 if (prs->s) iks_stack_delete (prs->s); else iks_free (prs);
1043 /* iksemel (XML parser for Jabber)
1044 ** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net>
1045 ** This code is free software; you can redistribute it and/or
1046 ** modify it under the terms of GNU Lesser General Public License.
1050 #include "iksemel.h"
1052 #define IKS_COMMON \
1053 struct iks_struct *next, *prev; \
1054 struct iks_struct *parent; \
1055 enum ikstype type; \
1064 struct iks_struct *children, *last_child;
1065 struct iks_struct *attribs, *last_attrib;
1069 #define IKS_TAG_NAME(x) ((struct iks_tag *) (x) )->name
1070 #define IKS_TAG_CHILDREN(x) ((struct iks_tag *) (x) )->children
1071 #define IKS_TAG_LAST_CHILD(x) ((struct iks_tag *) (x) )->last_child
1072 #define IKS_TAG_ATTRIBS(x) ((struct iks_tag *) (x) )->attribs
1073 #define IKS_TAG_LAST_ATTRIB(x) ((struct iks_tag *) (x) )->last_attrib
1081 #define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata
1082 #define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len
1090 #define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name
1091 #define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value
1093 /***** Node Creating & Deleting *****/
1096 iks_new (const char *name)
1101 s = iks_stack_new (sizeof (struct iks_tag) * 6, 256);
1102 if (!s) return NULL;
1103 x = iks_new_within (name, s);
1105 iks_stack_delete (s);
1112 iks_new_within (const char *name, ikstack *s)
1117 if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata);
1118 x = iks_stack_alloc (s, len);
1119 if (!x) return NULL;
1124 IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0);
1125 if (!IKS_TAG_NAME (x)) return NULL;
1131 iks_insert (iks *x, const char *name)
1135 if (!x) return NULL;
1137 y = iks_new_within (name, x->s);
1138 if (!y) return NULL;
1140 if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
1141 if (IKS_TAG_LAST_CHILD (x)) {
1142 IKS_TAG_LAST_CHILD (x)->next = y;
1143 y->prev = IKS_TAG_LAST_CHILD (x);
1145 IKS_TAG_LAST_CHILD (x) = y;
1150 iks_insert_cdata (iks *x, const char *data, size_t len)
1154 if(!x || !data) return NULL;
1155 if(len == 0) len = strlen (data);
1157 y = IKS_TAG_LAST_CHILD (x);
1158 if (y && y->type == IKS_CDATA) {
1159 IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len);
1160 IKS_CDATA_LEN (y) += len;
1162 y = iks_insert (x, NULL);
1163 if (!y) return NULL;
1164 y->type = IKS_CDATA;
1165 IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len);
1166 if (!IKS_CDATA_CDATA (y)) return NULL;
1167 IKS_CDATA_LEN (y) = len;
1173 iks_insert_attrib (iks *x, const char *name, const char *value)
1178 if (!x) return NULL;
1180 y = IKS_TAG_ATTRIBS (x);
1182 if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break;
1186 if (!value) return NULL;
1187 y = iks_stack_alloc (x->s, sizeof (struct iks_attrib));
1188 if (!y) return NULL;
1189 memset (y, 0, sizeof (struct iks_attrib));
1190 y->type = IKS_ATTRIBUTE;
1191 IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0);
1193 if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y;
1194 if (IKS_TAG_LAST_ATTRIB (x)) {
1195 IKS_TAG_LAST_ATTRIB (x)->next = y;
1196 y->prev = IKS_TAG_LAST_ATTRIB (x);
1198 IKS_TAG_LAST_ATTRIB (x) = y;
1202 len = strlen (value);
1203 IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, len);
1204 if (!IKS_ATTRIB_VALUE (y)) return NULL;
1206 if (y->next) y->next->prev = y->prev;
1207 if (y->prev) y->prev->next = y->next;
1208 if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next;
1209 if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev;
1216 iks_insert_node (iks *x, iks *y)
1219 if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
1220 if (IKS_TAG_LAST_CHILD (x)) {
1221 IKS_TAG_LAST_CHILD (x)->next = y;
1222 y->prev = IKS_TAG_LAST_CHILD (x);
1224 IKS_TAG_LAST_CHILD (x) = y;
1235 if (x->prev) x->prev->next = x->next;
1236 if (x->next) x->next->prev = x->prev;
1239 if (IKS_TAG_CHILDREN (y) == x) IKS_TAG_CHILDREN (y) = x->next;
1240 if (IKS_TAG_LAST_CHILD (y) == x) IKS_TAG_LAST_CHILD (y) = x->prev;
1247 if (x) iks_stack_delete (x->s);
1250 /***** Node Traversing *****/
1255 if (x) return x->next;
1260 iks_next_tag (iks *x)
1265 if (NULL == x) break;
1266 if (IKS_TAG == x->type) return x;
1275 if (x) return x->prev;
1280 iks_prev_tag (iks *x)
1285 if (NULL == x) break;
1286 if (IKS_TAG == x->type) return x;
1295 if (x) return x->parent;
1312 if (x) return IKS_TAG_CHILDREN (x);
1317 iks_first_tag (iks *x)
1320 x = IKS_TAG_CHILDREN (x);
1322 if (IKS_TAG == x->type) return x;
1332 if (x) return IKS_TAG_ATTRIBS (x);
1337 iks_find (iks *x, const char *name)
1341 if (!x) return NULL;
1342 y = IKS_TAG_CHILDREN (x);
1344 if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y;
1351 iks_find_cdata (iks *x, const char *name)
1355 y = iks_find (x, name);
1356 if (!y) return NULL;
1357 y = IKS_TAG_CHILDREN (y);
1358 if (!y || IKS_CDATA != y->type) return NULL;
1359 return IKS_CDATA_CDATA (y);
1363 iks_find_attrib (iks *x, const char *name)
1367 if (!x) return NULL;
1369 y = IKS_TAG_ATTRIBS (x);
1371 if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0)
1372 return IKS_ATTRIB_VALUE (y);
1379 iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value)
1383 if (NULL == x) return NULL;
1386 for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
1387 if (IKS_TAG == y->type
1388 && strcmp (IKS_TAG_NAME (y), tagname) == 0
1389 && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
1394 for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
1395 if (IKS_TAG == y->type
1396 && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
1404 /***** Node Information *****/
1416 if (x) return x->type;
1424 if (IKS_TAG == x->type)
1425 return IKS_TAG_NAME (x);
1427 return IKS_ATTRIB_NAME (x);
1436 if (IKS_CDATA == x->type)
1437 return IKS_CDATA_CDATA (x);
1439 return IKS_ATTRIB_VALUE (x);
1445 iks_cdata_size (iks *x)
1447 if (x) return IKS_CDATA_LEN (x);
1452 iks_has_children (iks *x)
1454 if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1;
1459 iks_has_attribs (iks *x)
1461 if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1;
1465 /***** Serializing *****/
1468 escape_size (char *src, size_t len)
1475 for (i = 0; i < len; i++) {
1478 case '&': sz += 5; break;
1479 case '\'': sz += 6; break;
1480 case '"': sz += 6; break;
1481 case '<': sz += 4; break;
1482 case '>': sz += 4; break;
1483 default: sz++; break;
1490 my_strcat (char *dest, char *src, size_t len)
1492 if (0 == len) len = strlen (src);
1493 memcpy (dest, src, len);
1498 escape (char *dest, char *src, size_t len)
1504 for (i = 0; i < len; i++) {
1506 if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) {
1507 if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1510 case '&': dest = my_strcat (dest, "&", 5); break;
1511 case '\'': dest = my_strcat (dest, "'", 6); break;
1512 case '"': dest = my_strcat (dest, """, 6); break;
1513 case '<': dest = my_strcat (dest, "<", 4); break;
1514 case '>': dest = my_strcat (dest, ">", 4); break;
1518 if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1523 iks_string (ikstack *s, iks *x)
1530 if (!x) return NULL;
1532 if (x->type == IKS_CDATA) {
1534 return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1536 ret = iks_malloc (IKS_CDATA_LEN (x));
1537 memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1548 if (y->type == IKS_TAG) {
1550 size += strlen (IKS_TAG_NAME (y));
1551 for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) {
1552 size += 4 + strlen (IKS_ATTRIB_NAME (z))
1553 + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z)));
1555 if (IKS_TAG_CHILDREN (y)) {
1557 y = IKS_TAG_CHILDREN (y);
1564 size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y));
1570 if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y));
1578 if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y));
1579 if (level < 1) break;
1584 if (s) ret = iks_stack_alloc (s, size + 1);
1585 else ret = iks_malloc (size + 1);
1587 if (!ret) return NULL;
1594 if (x->type == IKS_TAG) {
1596 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1597 y = IKS_TAG_ATTRIBS (x);
1600 t = my_strcat (t, IKS_ATTRIB_NAME (y), 0);
1603 t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y)));
1607 if (IKS_TAG_CHILDREN (x)) {
1609 x = IKS_TAG_CHILDREN (x);
1617 t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1623 if (IKS_TAG_CHILDREN (x)) {
1626 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1639 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1642 if (level < 1) break;
1651 /***** Copying *****/
1654 iks_copy_within (iks *x, ikstack *s)
1663 if (x->type == IKS_TAG) {
1665 copy = iks_new_within (IKS_TAG_NAME (x), s);
1668 cur = iks_insert (cur, IKS_TAG_NAME (x));
1670 for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) {
1671 iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y));
1673 if (IKS_TAG_CHILDREN (x)) {
1674 x = IKS_TAG_CHILDREN (x);
1681 iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1686 if (0 == level) break;
1690 if (level < 2) break;
1703 return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256));
1705 /* iksemel (XML parser for Jabber)
1706 ** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
1707 ** This code is free software; you can redistribute it and/or
1708 ** modify it under the terms of GNU Lesser General Public License.
1712 #include "iksemel.h"
1721 tagHook (struct dom_data *data, char *name, char **atts, int type)
1725 if (IKS_OPEN == type || IKS_SINGLE == type) {
1726 if (data->current) {
1727 x = iks_insert (data->current, name);
1730 s = iks_stack_new (data->chunk_size, data->chunk_size);
1731 x = iks_new_within (name, s);
1736 iks_insert_attrib (x, atts[i], atts[i+1]);
1742 if (IKS_CLOSE == type || IKS_SINGLE == type) {
1743 x = iks_parent (data->current);
1747 *(data->iksptr) = data->current;
1748 data->current = NULL;
1755 cdataHook (struct dom_data *data, char *cdata, size_t len)
1757 if (data->current) iks_insert_cdata (data->current, cdata, len);
1762 deleteHook (struct dom_data *data)
1764 if (data->current) iks_delete (data->current);
1765 data->current = NULL;
1769 iks_dom_new (iks **iksptr)
1772 struct dom_data *data;
1775 s = iks_stack_new (DEFAULT_DOM_CHUNK_SIZE, 0);
1776 if (!s) return NULL;
1777 data = iks_stack_alloc (s, sizeof (struct dom_data));
1778 data->iksptr = iksptr;
1779 data->current = NULL;
1780 data->chunk_size = DEFAULT_DOM_IKS_CHUNK_SIZE;
1781 return iks_sax_extend (s, data, (iksTagHook *) tagHook, (iksCDataHook *) cdataHook, (iksDeleteHook *) deleteHook);
1785 iks_set_size_hint (iksparser *prs, size_t approx_size)
1788 struct dom_data *data = iks_user_data (prs);
1790 cs = approx_size / 10;
1791 if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE;
1792 data->chunk_size = cs;
1796 iks_tree (const char *xml_str, size_t len, int *err)
1802 if (0 == len) len = strlen (xml_str);
1803 prs = iks_dom_new (&x);
1805 if (err) *err = IKS_NOMEM;
1808 e = iks_parse (prs, xml_str, len, 1);
1810 iks_parser_delete (prs);
1815 iks_load (const char *fname, iks **xptr)
1825 buf = iks_malloc (FILE_IO_BUF_SIZE);
1826 if (!buf) return IKS_NOMEM;
1828 prs = iks_dom_new (xptr);
1830 f = fopen (fname, "r");
1833 len = fread (buf, 1, FILE_IO_BUF_SIZE, f);
1834 if (len < FILE_IO_BUF_SIZE) {
1835 if (0 == feof (f)) {
1836 ret = IKS_FILE_RWERR;
1843 e = iks_parse (prs, buf, len, done);
1848 if (done) ret = IKS_OK;
1853 if (ENOENT == errno) ret = IKS_FILE_NOFILE;
1854 else ret = IKS_FILE_NOACCESS;
1856 iks_parser_delete (prs);
1863 iks_save (const char *fname, iks *x)
1870 data = iks_string (NULL, x);
1872 ret = IKS_FILE_NOACCESS;
1873 f = fopen (fname, "w");
1875 ret = IKS_FILE_RWERR;
1876 if (fputs (data, f) >= 0) ret = IKS_OK;