]> www.fi.muni.cz Git - evince.git/blob - backend/impress/iksemel.c
6d24d43a339b54bdf990efb11f188ad868aee8f3
[evince.git] / backend / impress / iksemel.c
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.
5 */
6
7 /* minimum sax buffer size */
8 #define SAX_BUFFER_MIN_SIZE 128
9
10 /* sax parser structure plus extra data of dom parser */
11 #define DEFAULT_DOM_CHUNK_SIZE 256
12
13 /* sax parser structure plus extra data of stream parser */
14 #define DEFAULT_STREAM_CHUNK_SIZE 256
15
16 /* iks structure, its data, child iks structures, for stream parsing */
17 #define DEFAULT_IKS_CHUNK_SIZE 1024
18
19 /* iks structure, its data, child iks structures, for file parsing */
20 #define DEFAULT_DOM_IKS_CHUNK_SIZE 2048
21
22 /* rule structure and from/to/id/ns strings */
23 #define DEFAULT_RULE_CHUNK_SIZE 128
24
25 /* file is read by blocks with this size */
26 #define FILE_IO_BUF_SIZE 4096
27
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.
34 */
35
36 #include <errno.h>
37
38 #include "common.h"
39 #include "iksemel.h"
40
41 /*****  malloc wrapper  *****/
42
43 static void *(*my_malloc_func)(size_t size);
44 static void (*my_free_func)(void *ptr);
45
46 void *
47 iks_malloc (size_t size)
48 {
49         if (my_malloc_func)
50                 return my_malloc_func (size);
51         else
52                 return malloc (size);
53 }
54
55 void
56 iks_free (void *ptr)
57 {
58         if (my_free_func)
59                 my_free_func (ptr);
60         else
61                 free (ptr);
62 }
63
64 void
65 iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr))
66 {
67         my_malloc_func = malloc_func;
68         my_free_func = free_func;
69 }
70
71 /*****  NULL-safe Functions  *****/
72
73 char *
74 iks_strdup (const char *src)
75 {
76         if (src) return strdup(src);
77         return NULL;
78 }
79
80 char *
81 iks_strcat (char *dest, const char *src)
82 {
83         size_t len;
84
85         if (!src) return dest;
86
87         len = strlen (src);
88         memcpy (dest, src, len);
89         dest[len] = '\0';
90         return dest + len;
91 }
92
93 int
94 iks_strcmp (const char *a, const char *b)
95 {
96         if (!a || !b) return -1;
97         return strcmp (a, b);
98 }
99
100 int
101 iks_strcasecmp (const char *a, const char *b)
102 {
103         if (!a || !b) return -1;
104         return strcasecmp (a, b);
105 }
106
107 int
108 iks_strncmp (const char *a, const char *b, size_t n)
109 {
110         if (!a || !b) return -1;
111         return strncmp (a, b, n);
112 }
113
114 int
115 iks_strncasecmp (const char *a, const char *b, size_t n)
116 {
117         if (!a || !b) return -1;
118         return strncasecmp (a, b, n);
119 }
120
121 size_t
122 iks_strlen (const char *src)
123 {
124         if (!src) return 0;
125         return strlen (src);
126 }
127
128 /*****  XML Escaping  *****/
129
130 char *
131 iks_escape (ikstack *s, char *src, size_t len)
132 {
133         char *ret;
134         int i, j, nlen;
135
136         if (!src || !s) return NULL;
137         if (len == -1) len = strlen (src);
138
139         nlen = len;
140         for (i=0; i<len; i++) {
141                 switch (src[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;
147                 }
148         }
149         if (len == nlen) return src;
150
151         ret = iks_stack_alloc (s, nlen + 1);
152         if (!ret) return NULL;
153
154         for (i=j=0; i<len; i++) {
155                 switch (src[i]) {
156                 case '&': memcpy (&ret[j], "&amp;", 5); j += 5; break;
157                 case '\'': memcpy (&ret[j], "&apos;", 6); j += 6; break;
158                 case '"': memcpy (&ret[j], "&quot;", 6); j += 6; break;
159                 case '<': memcpy (&ret[j], "&lt;", 4); j += 4; break;
160                 case '>': memcpy (&ret[j], "&gt;", 4); j += 4; break;
161                 default: ret[j++] = src[i];
162                 }
163         }
164         ret[j] = '\0';
165
166         return ret;
167 }
168
169 char *
170 iks_unescape (ikstack *s, char *src, size_t len)
171 {
172         int i,j;
173         char *ret;
174
175         if (!s || !src) return NULL;
176         if (!strchr (src, '&')) return src;
177         if (len == -1) len = strlen (src);
178
179         ret = iks_stack_alloc (s, len + 1);
180         if (!ret) return NULL;
181
182         for (i=j=0; i<len; i++) {
183                 if (src[i] == '&') {
184                         i++;
185                         if (strncmp (&src[i], "amp;", 4) == 0) {
186                                 ret[j] = '&';
187                                 i += 3;
188                         } else if (strncmp (&src[i], "quot;", 5) == 0) {
189                                 ret[j] = '"';
190                                 i += 4;
191                         } else if (strncmp (&src[i], "apos;", 5) == 0) {
192                                 ret[j] = '\'';
193                                 i += 4;
194                         } else if (strncmp (&src[i], "lt;", 3) == 0) {
195                                 ret[j] = '<';
196                                 i += 2;
197                         } else if (strncmp (&src[i], "gt;", 3) == 0) {
198                                 ret[j] = '>';
199                                 i += 2;
200                         } else {
201                                 ret[j] = src[--i];
202                         }
203                 } else {
204                         ret[j] = src[i];
205                 }
206                 j++;
207         }
208         ret[j] = '\0';
209
210         return ret;
211 }
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.
216 */
217
218 #include "common.h"
219 #include "iksemel.h"
220
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)) )
227
228 typedef struct ikschunk_struct {
229         struct ikschunk_struct *next;
230         size_t size;
231         size_t used;
232         size_t last;
233         char data[4];
234 } ikschunk;
235
236 struct ikstack_struct {
237         size_t allocated;
238         ikschunk *meta;
239         ikschunk *data;
240 };
241
242 static ikschunk *
243 find_space (ikstack *s, ikschunk *c, size_t size)
244 {
245         /* FIXME: dont use *2 after over allocated chunks */
246         while (1) {
247                 if (c->size - c->used >= size) return c;
248                 if (!c->next) {
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;
253                         c = c->next;
254                         c->next = NULL;
255                         c->size = size;
256                         c->used = 0;
257                         c->last = (size_t) -1;
258                         return c;
259                 }
260                 c = c->next;
261         }
262         return NULL;
263 }
264
265 ikstack *
266 iks_stack_new (size_t meta_chunk, size_t data_chunk)
267 {
268         ikstack *s;
269         size_t len;
270
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);
275
276         len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2);
277         s = iks_malloc (len);
278         if (!s) return NULL;
279         s->allocated = len;
280         s->meta = (ikschunk *) ((char *) s + sizeof (ikstack));
281         s->meta->next = NULL;
282         s->meta->size = meta_chunk;
283         s->meta->used = 0;
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;
288         s->data->used = 0;
289         s->data->last = (size_t) -1;
290         return s;
291 }
292
293 void *
294 iks_stack_alloc (ikstack *s, size_t size)
295 {
296         ikschunk *c;
297         void *mem;
298
299         if (size < MIN_ALLOC_SIZE) size = MIN_ALLOC_SIZE;
300         if (size & ALIGN_MASK) size = ALIGN (size);
301
302         c = find_space (s, s->meta, size);
303         if (!c) return NULL;
304         mem = c->data + c->used;
305         c->used += size;
306         return mem;
307 }
308
309 char *
310 iks_stack_strdup (ikstack *s, const char *src, size_t len)
311 {
312         ikschunk *c;
313         char *dest;
314
315         if (!src) return NULL;
316         if (0 == len) len = strlen (src);
317
318         c = find_space (s, s->data, len + 1);
319         if (!c) return NULL;
320         dest = c->data + c->used;
321         c->last = c->used;
322         c->used += len + 1;
323         memcpy (dest, src, len);
324         dest[len] = '\0';
325         return dest;
326 }
327
328 char *
329 iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len)
330 {
331         char *ret;
332         ikschunk *c;
333
334         if (!old) {
335                 return iks_stack_strdup (s, src, src_len);
336         }
337         if (0 == old_len) old_len = strlen (old);
338         if (0 == src_len) src_len = strlen (src);
339
340         for (c = s->data; c; c = c->next) {
341                 if (c->data + c->last == old) break;
342         }
343         if (!c) {
344                 c = find_space (s, s->data, old_len + src_len + 1);
345                 if (!c) return NULL;
346                 ret = c->data + c->used;
347                 c->last = 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';
352                 return ret;
353         }
354
355         if (c->size - c->used > src_len) {
356                 ret = c->data + c->last;
357                 memcpy (ret + old_len, src, src_len);
358                 c->used += src_len;
359                 ret[old_len + src_len] = '\0';
360         } else {
361                 /* FIXME: decrease c->used before moving string to new place */
362                 c = find_space (s, s->data, old_len + src_len + 1);
363                 if (!c) return NULL;
364                 c->last = c->used;
365                 ret = c->data + c->used;
366                 memcpy (ret, old, old_len);
367                 c->used += old_len;
368                 memcpy (c->data + c->used, src, src_len);
369                 c->used += src_len;
370                 c->data[c->used] = '\0';
371                 c->used++;
372         }
373         return ret;
374 }
375
376 void
377 iks_stack_stat (ikstack *s, size_t *allocated, size_t *used)
378 {
379         ikschunk *c;
380
381         if (allocated) {
382                 *allocated = s->allocated;
383         }
384         if (used) {
385                 *used = 0;
386                 for (c = s->meta; c; c = c->next) {
387                         (*used) += c->used;
388                 }
389                 for (c = s->data; c; c = c->next) {
390                         (*used) += c->used;
391                 }
392         }
393 }
394
395 void
396 iks_stack_delete (ikstack *s)
397 {
398         ikschunk *c, *tmp;
399
400         c = s->meta->next;
401         while (c) {
402                 tmp = c->next;
403                 iks_free (c);
404                 c = tmp;
405         }
406         c = s->data->next;
407         while (c) {
408                 tmp = c->next;
409                 iks_free (c);
410                 c = tmp;
411         }
412         iks_free (s);
413 }
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.
418 */
419
420 #include "common.h"
421 #include "iksemel.h"
422
423 enum cons_e {
424         C_CDATA = 0,
425         C_TAG_START,
426         C_TAG,
427         C_TAG_END,
428         C_ATTRIBUTE,
429         C_ATTRIBUTE_1,
430         C_ATTRIBUTE_2,
431         C_VALUE,
432         C_VALUE_APOS,
433         C_VALUE_QUOT,
434         C_WHITESPACE,
435         C_ENTITY,
436         C_COMMENT,
437         C_COMMENT_1,
438         C_COMMENT_2,
439         C_COMMENT_3,
440         C_MARKUP,
441         C_MARKUP_1,
442         C_SECT,
443         C_SECT_CDATA,
444         C_SECT_CDATA_1,
445         C_SECT_CDATA_2,
446         C_SECT_CDATA_3,
447         C_SECT_CDATA_4,
448         C_SECT_CDATA_C,
449         C_SECT_CDATA_E,
450         C_SECT_CDATA_E2,
451         C_PI
452 };
453
454 /* if you add a variable here, dont forget changing iks_parser_reset */
455 struct iksparser_struct {
456         ikstack *s;
457         void *user_data;
458         iksTagHook *tagHook;
459         iksCDataHook *cdataHook;
460         iksDeleteHook *deleteHook;
461         /* parser context */
462         char *stack;
463         size_t stack_pos;
464         size_t stack_max;
465
466         enum cons_e context;
467         enum cons_e oldcontext;
468
469         char *tag_name;
470         enum ikstagtype tagtype;
471
472         unsigned int attmax;
473         unsigned int attcur;
474         int attflag;
475         char **atts;
476         int valflag;
477
478         unsigned int entpos;
479         char entity[8];
480
481         unsigned long nr_bytes;
482         unsigned long nr_lines;
483
484         int uni_max;
485         int uni_len;
486 };
487
488 iksparser *
489 iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook)
490 {
491         iksparser *prs;
492
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;
499         return prs;
500 }
501
502 iksparser *
503 iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook)
504 {
505         iksparser *prs;
506
507         prs = iks_stack_alloc (s, sizeof (iksparser));
508         if (NULL == prs) return NULL;
509         memset (prs, 0, sizeof (iksparser));
510         prs->s = s;
511         prs->user_data = user_data;
512         prs->tagHook = tagHook;
513         prs->cdataHook = cdataHook;
514         prs->deleteHook = deleteHook;
515         return prs;
516 }
517
518 ikstack *
519 iks_parser_stack (iksparser *prs)
520 {
521         return prs->s;
522 }
523
524 void *
525 iks_user_data (iksparser *prs)
526 {
527         return prs->user_data;
528 }
529
530 unsigned long
531 iks_nr_bytes (iksparser *prs)
532 {
533         return prs->nr_bytes;
534 }
535
536 unsigned long
537 iks_nr_lines (iksparser *prs)
538 {
539         return prs->nr_lines;
540 }
541
542 #define IS_WHITESPACE(x) ' ' == (x) || '\t' == (x) || '\r' == (x) || '\n' == (x)
543 #define NOT_WHITESPACE(x) ' ' != (x) && '\t' != (x) && '\r' != (x) && '\n' != (x)
544
545 static int
546 stack_init (iksparser *prs)
547 {
548         prs->stack = iks_malloc (128);
549         if (!prs->stack) return 0;
550         prs->stack_max = 128;
551         prs->stack_pos = 0;
552         return 1;
553 }
554
555 static int
556 stack_expand (iksparser *prs, int len)
557 {
558         size_t need;
559         off_t diff;
560         char *tmp;
561         need = len - (prs->stack_max - prs->stack_pos);
562         if (need < prs->stack_max) {
563                 need = prs->stack_max * 2;
564         } else {
565                 need = prs->stack_max + (need * 1.2);
566         }
567         tmp = iks_malloc (need);
568         if (!tmp) return 0;
569         diff = tmp - prs->stack;
570         memcpy (tmp, prs->stack, prs->stack_max);
571         iks_free (prs->stack);
572         prs->stack = tmp;
573         prs->stack_max = need;
574         prs->tag_name += diff;
575         if (prs->attflag != 0) {
576                 int i = 0;
577                 while (i < (prs->attmax * 2)) {
578                         if (prs->atts[i]) prs->atts[i] += diff;
579                         i++;
580                 }
581         }
582         return 1;
583 }
584
585 #define STACK_INIT \
586         if (NULL == prs->stack && 0 == stack_init (prs)) return IKS_NOMEM
587
588 #define STACK_PUSH_START (prs->stack + prs->stack_pos)
589
590 #define STACK_PUSH(buf,len) \
591 { \
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; \
596         } \
597         memcpy (prs->stack + prs->stack_pos, sbuf, slen); \
598         prs->stack_pos += slen; \
599 }
600
601 #define STACK_PUSH_END \
602 { \
603         if (prs->stack_pos >= prs->stack_max) { \
604                 if (0 == stack_expand (prs, 1)) return IKS_NOMEM; \
605         } \
606         prs->stack[prs->stack_pos] = '\0'; \
607         prs->stack_pos++; \
608 }
609
610 static enum ikserror
611 sax_core (iksparser *prs, char *buf, int len)
612 {
613         enum ikserror err;
614         int pos = 0, old = 0, re, stack_old = -1;
615         unsigned char c;
616
617         while (pos < len) {
618                 re = 0;
619                 c = buf[pos];
620                 if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML;
621                 if (prs->uni_max) {
622                         if ((c & 0xC0) != 0x80) return IKS_BADXML;
623                         prs->uni_len++;
624                         if (prs->uni_len == prs->uni_max) prs->uni_max = 0;
625                         goto cont;
626                 } else {
627                         if (c & 0x80) {
628                                 unsigned char mask;
629                                 if ((c & 0x60) == 0x40) {
630                                         prs->uni_max = 2;
631                                         mask = 0x1F;
632                                 } else if ((c & 0x70) == 0x60) {
633                                         prs->uni_max = 3;
634                                         mask = 0x0F;
635                                 } else if ((c & 0x78) == 0x70) {
636                                         prs->uni_max = 4;
637                                         mask = 0x07;
638                                 } else if ((c & 0x7C) == 0x78) {
639                                         prs->uni_max = 5;
640                                         mask = 0x03;
641                                 } else if ((c & 0x7E) == 0x7C) {
642                                         prs->uni_max = 6;
643                                         mask = 0x01;
644                                 } else {
645                                         return IKS_BADXML;
646                                 }
647                                 if ((c & mask) == 0) return IKS_BADXML;
648                                 prs->uni_len = 1;
649                                 if (stack_old == -1) stack_old = pos;
650                                 goto cont;
651                         }
652                 }
653
654                 switch (prs->context) {
655                         case C_CDATA:
656                                 if ('&' == c) {
657                                         if (old < pos && prs->cdataHook) {
658                                                 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
659                                                 if (IKS_OK != err) return err;
660                                         }
661                                         prs->context = C_ENTITY;
662                                         prs->entpos = 0;
663                                         break;
664                                 }
665                                 if ('<' == c) {
666                                         if (old < pos && prs->cdataHook) {
667                                                 err = prs->cdataHook (prs->user_data, &buf[old], pos - old);
668                                                 if (IKS_OK != err) return err;
669                                         }
670                                         STACK_INIT;
671                                         prs->tag_name = STACK_PUSH_START;
672                                         if (!prs->tag_name) return IKS_NOMEM;
673                                         prs->context = C_TAG_START;
674                                 }
675                                 break;
676
677                         case C_TAG_START:
678                                 prs->context = C_TAG;
679                                 if ('/' == c) {
680                                         prs->tagtype = IKS_CLOSE;
681                                         break;
682                                 }
683                                 if ('?' == c) {
684                                         prs->context = C_PI;
685                                         break;
686                                 }
687                                 if ('!' == c) {
688                                         prs->context = C_MARKUP;
689                                         break;
690                                 }
691                                 prs->tagtype = IKS_OPEN;
692                                 stack_old = pos;
693                                 break;
694
695                         case C_TAG:
696                                 if (IS_WHITESPACE(c)) {
697                                         if (IKS_CLOSE == prs->tagtype)
698                                                 prs->oldcontext = C_TAG_END;
699                                         else
700                                                 prs->oldcontext = C_ATTRIBUTE;
701                                         prs->context = C_WHITESPACE;
702                                         if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
703                                         stack_old = -1;
704                                         STACK_PUSH_END;
705                                         break;
706                                 }
707                                 if ('/' == c) {
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);
712                                         stack_old = -1;
713                                         STACK_PUSH_END;
714                                         break;
715                                 }
716                                 if ('>' == c) {
717                                         prs->context = C_TAG_END;
718                                         if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
719                                         stack_old = -1;
720                                         STACK_PUSH_END;
721                                         re = 1;
722                                 }
723                                 if (stack_old == -1) stack_old = pos;
724                                 break;
725
726                         case C_TAG_END:
727                                 if (c != '>') return IKS_BADXML;
728                                 if (prs->tagHook) {
729                                         char **tmp;
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;
733                                 }
734                                 prs->stack_pos = 0;
735                                 stack_old = -1;
736                                 prs->attcur = 0;
737                                 prs->attflag = 0;
738                                 prs->context = C_CDATA;
739                                 old = pos + 1;
740                                 break;
741
742                         case C_ATTRIBUTE:
743                                 if ('/' == c) {
744                                         prs->tagtype = IKS_SINGLE;
745                                         prs->context = C_TAG_END;
746                                         break;
747                                 }
748                                 if ('>' == c) {
749                                         prs->context = C_TAG_END;
750                                         re = 1;
751                                         break;
752                                 }
753                                 if (!prs->atts) {
754                                         prs->attmax = 12;
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);
758                                         prs->attcur = 0;
759                                 } else {
760                                         if (prs->attcur >= (prs->attmax * 2)) {
761                                                 void *tmp;
762                                                 prs->attmax += 12;
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);
767                                                 free (prs->atts);
768                                                 prs->atts = tmp;
769                                         }
770                                 }
771                                 prs->attflag = 1;
772                                 prs->atts[prs->attcur] = STACK_PUSH_START;
773                                 stack_old = pos;
774                                 prs->context = C_ATTRIBUTE_1;
775                                 break;
776
777                         case C_ATTRIBUTE_1:
778                                 if ('=' == c) {
779                                         if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
780                                         stack_old = -1;
781                                         STACK_PUSH_END;
782                                         prs->context = C_VALUE;
783                                         break;
784                                 }
785                                 if (stack_old == -1) stack_old = pos;
786                                 break;
787
788                         case C_ATTRIBUTE_2:
789                                 if ('/' == c) {
790                                         prs->tagtype = IKS_SINGLE;
791                                         prs->atts[prs->attcur] = NULL;
792                                         prs->context = C_TAG_END;
793                                         break;
794                                 }
795                                 if ('>' == c) {
796                                         prs->atts[prs->attcur] = NULL;
797                                         prs->context = C_TAG_END;
798                                         re = 1;
799                                         break;
800                                 }
801                                 prs->context = C_ATTRIBUTE;
802                                 re = 1;
803                                 break;
804
805                         case C_VALUE:
806                                 prs->atts[prs->attcur + 1] = STACK_PUSH_START;
807                                 if ('\'' == c) {
808                                         prs->context = C_VALUE_APOS;
809                                         break;
810                                 }
811                                 if ('"' == c) {
812                                         prs->context = C_VALUE_QUOT;
813                                         break;
814                                 }
815                                 return IKS_BADXML;
816
817                         case C_VALUE_APOS:
818                                 if ('\'' == c) {
819                                         if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
820                                         stack_old = -1;
821                                         STACK_PUSH_END;
822                                         prs->oldcontext = C_ATTRIBUTE_2;
823                                         prs->context = C_WHITESPACE;
824                                         prs->attcur += 2;
825                                 }
826                                 if (stack_old == -1) stack_old = pos;
827                                 break;
828
829                         case C_VALUE_QUOT:
830                                 if ('"' == c) {
831                                         if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old);
832                                         stack_old = -1;
833                                         STACK_PUSH_END;
834                                         prs->oldcontext = C_ATTRIBUTE_2;
835                                         prs->context = C_WHITESPACE;
836                                         prs->attcur += 2;
837                                 }
838                                 if (stack_old == -1) stack_old = pos;
839                                 break;
840
841                         case C_WHITESPACE:
842                                 if (NOT_WHITESPACE(c)) {
843                                         prs->context = prs->oldcontext;
844                                         re = 1;
845                                 }
846                                 break;
847
848                         case C_ENTITY:
849                                 if (';' == c) {
850                                         char hede[2];
851                                         char t = '?';
852                                         prs->entity[prs->entpos] = '\0';
853                                         if (strcmp(prs->entity, "amp") == 0)
854                                                 t = '&';
855                                         else if (strcmp(prs->entity, "quot") == 0)
856                                                 t = '"';
857                                         else if (strcmp(prs->entity, "apos") == 0)
858                                                 t = '\'';
859                                         else if (strcmp(prs->entity, "lt") == 0)
860                                                 t = '<';
861                                         else if (strcmp(prs->entity, "gt") == 0)
862                                                 t = '>';
863                                         old = pos + 1;
864                                         hede[0] = t;
865                                         if (prs->cdataHook) {
866                                                 err = prs->cdataHook (prs->user_data, &hede[0], 1);
867                                                 if (IKS_OK != err) return err;
868                                         }
869                                         prs->context = C_CDATA;
870                                 } else {
871                                         prs->entity[prs->entpos++] = buf[pos];
872                                         if (prs->entpos > 7) return IKS_BADXML;
873                                 }
874                                 break;
875
876                         case C_COMMENT:
877                                 if ('-' != c) return IKS_BADXML;
878                                 prs->context = C_COMMENT_1;
879                                 break;
880
881                         case C_COMMENT_1:
882                                 if ('-' == c) prs->context = C_COMMENT_2;
883                                 break;
884
885                         case C_COMMENT_2:
886                                 if ('-' == c)
887                                         prs->context = C_COMMENT_3;
888                                 else
889                                         prs->context = C_COMMENT_1;
890                                 break;
891
892                         case C_COMMENT_3:
893                                 if ('>' != c) return IKS_BADXML;
894                                 prs->context = C_CDATA;
895                                 old = pos + 1;
896                                 break;
897
898                         case C_MARKUP:
899                                 if ('[' == c) {
900                                         prs->context = C_SECT;
901                                         break;
902                                 }
903                                 if ('-' == c) {
904                                         prs->context = C_COMMENT;
905                                         break;
906                                 }
907                                 prs->context = C_MARKUP_1;
908
909                         case C_MARKUP_1:
910                                 if ('>' == c) {
911                                         old = pos + 1;
912                                         prs->context = C_CDATA;
913                                 }
914                                 break;
915
916                         case C_SECT:
917                                 if ('C' == c) {
918                                         prs->context = C_SECT_CDATA;
919                                         break;
920                                 }
921                                 return IKS_BADXML;
922
923                         case C_SECT_CDATA:
924                                 if ('D' != c) return IKS_BADXML;
925                                 prs->context = C_SECT_CDATA_1;
926                                 break;
927
928                         case C_SECT_CDATA_1:
929                                 if ('A' != c) return IKS_BADXML;
930                                 prs->context = C_SECT_CDATA_2;
931                                 break;
932
933                         case C_SECT_CDATA_2:
934                                 if ('T' != c) return IKS_BADXML;
935                                 prs->context = C_SECT_CDATA_3;
936                                 break;
937
938                         case C_SECT_CDATA_3:
939                                 if ('A' != c) return IKS_BADXML;
940                                 prs->context = C_SECT_CDATA_4;
941                                 break;
942
943                         case C_SECT_CDATA_4:
944                                 if ('[' != c) return IKS_BADXML;
945                                 old = pos + 1;
946                                 prs->context = C_SECT_CDATA_C;
947                                 break;
948
949                         case C_SECT_CDATA_C:
950                                 if (']' == 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;
955                                         }
956                                 }
957                                 break;
958
959                         case C_SECT_CDATA_E:
960                                 if (']' == c) {
961                                         prs->context = C_SECT_CDATA_E2;
962                                 } else {
963                                         if (prs->cdataHook) {
964                                                 err = prs->cdataHook (prs->user_data, "]", 1);
965                                                 if (IKS_OK != err) return err;
966                                         }
967                                         old = pos;
968                                         prs->context = C_SECT_CDATA_C;
969                                 }
970                                 break;
971
972                         case C_SECT_CDATA_E2:
973                                 if ('>' == c) {
974                                         old = pos + 1;
975                                         prs->context = C_CDATA;
976                                 } else {
977                                         if (prs->cdataHook) {
978                                                 err = prs->cdataHook (prs->user_data, "]]", 2);
979                                                 if (IKS_OK != err) return err;
980                                         }
981                                         old = pos;
982                                         prs->context = C_SECT_CDATA_C;
983                                 }
984                                 break;
985
986                         case C_PI:
987                                 old = pos + 1;
988                                 if ('>' == c) prs->context = C_CDATA;
989                                 break;
990                 }
991 cont:
992                 if (0 == re) {
993                         pos++;
994                         prs->nr_bytes++;
995                         if ('\n' == c) prs->nr_lines++;
996                 }
997         }
998
999         if (stack_old != -1)
1000                 STACK_PUSH (buf + stack_old, pos - stack_old);
1001
1002         err = IKS_OK;
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);
1005         return err;
1006 }
1007
1008 int
1009 iks_parse (iksparser *prs, const char *data, size_t len, int finish)
1010 {
1011         if (!data) return IKS_OK;
1012         if (len == 0) len = strlen (data);
1013         return sax_core (prs, (char *) data, len);
1014 }
1015
1016 void
1017 iks_parser_reset (iksparser *prs)
1018 {
1019         if (prs->deleteHook) prs->deleteHook (prs->user_data);
1020         prs->stack_pos = 0;
1021         prs->context = 0;
1022         prs->oldcontext = 0;
1023         prs->tagtype = 0;
1024         prs->attcur = 0;
1025         prs->attflag = 0;
1026         prs->valflag = 0;
1027         prs->entpos = 0;
1028         prs->nr_bytes = 0;
1029         prs->nr_lines = 0;
1030         prs->uni_max = 0;
1031         prs->uni_len = 0;
1032 }
1033
1034 void
1035 iks_parser_delete (iksparser *prs)
1036 {
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);
1041 }
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.
1046 */
1047
1048 #include "common.h"
1049 #include "iksemel.h"
1050
1051 #define IKS_COMMON \
1052         struct iks_struct *next, *prev; \
1053         struct iks_struct *parent; \
1054         enum ikstype type; \
1055         ikstack *s
1056
1057 struct iks_struct {
1058         IKS_COMMON;
1059 };
1060
1061 struct iks_tag {
1062         IKS_COMMON;
1063         struct iks_struct *children, *last_child;
1064         struct iks_struct *attribs, *last_attrib;
1065         char *name;
1066 };
1067
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
1073
1074 struct iks_cdata {
1075         IKS_COMMON;
1076         char *cdata;
1077         size_t len;
1078 };
1079
1080 #define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata
1081 #define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len
1082
1083 struct iks_attrib {
1084         IKS_COMMON;
1085         char *name;
1086         char *value;
1087 };
1088
1089 #define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name
1090 #define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value
1091
1092 /*****  Node Creating & Deleting  *****/
1093
1094 iks *
1095 iks_new (const char *name)
1096 {
1097         ikstack *s;
1098         iks *x;
1099
1100         s = iks_stack_new (sizeof (struct iks_tag) * 6, 256);
1101         if (!s) return NULL;
1102         x = iks_new_within (name, s);
1103         if (!x) {
1104                 iks_stack_delete (s);
1105                 return NULL;
1106         }
1107         return x;
1108 }
1109
1110 iks *
1111 iks_new_within (const char *name, ikstack *s)
1112 {
1113         iks *x;
1114         size_t len;
1115
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;
1119         memset (x, 0, len);
1120         x->s = s;
1121         x->type = IKS_TAG;
1122         if (name) {
1123                 IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0);
1124                 if (!IKS_TAG_NAME (x)) return NULL;
1125         }
1126         return x;
1127 }
1128
1129 iks *
1130 iks_insert (iks *x, const char *name)
1131 {
1132         iks *y;
1133
1134         if (!x) return NULL;
1135
1136         y = iks_new_within (name, x->s);
1137         if (!y) return NULL;
1138         y->parent = x;
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);
1143         }
1144         IKS_TAG_LAST_CHILD (x) = y;
1145         return y;
1146 }
1147
1148 iks *
1149 iks_insert_cdata (iks *x, const char *data, size_t len)
1150 {
1151         iks *y;
1152
1153         if(!x || !data) return NULL;
1154         if(len == 0) len = strlen (data);
1155
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;
1160         } else {
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;
1167         }
1168         return y;
1169 }
1170
1171 iks *
1172 iks_insert_attrib (iks *x, const char *name, const char *value)
1173 {
1174         iks *y;
1175         size_t len;
1176
1177         if (!x) return NULL;
1178
1179         y = IKS_TAG_ATTRIBS (x);
1180         while (y) {
1181                 if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break;
1182                 y = y->next;
1183         }
1184         if (NULL == y) {
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);
1191                 y->parent = x;
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);
1196                 }
1197                 IKS_TAG_LAST_ATTRIB (x) = y;
1198         }
1199
1200         if (value) {
1201                 len = strlen (value);
1202                 IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, len);
1203                 if (!IKS_ATTRIB_VALUE (y)) return NULL;
1204         } else {
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;
1209         }
1210
1211         return y;
1212 }
1213
1214 iks *
1215 iks_insert_node (iks *x, iks *y)
1216 {
1217         y->parent = x;
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);
1222         }
1223         IKS_TAG_LAST_CHILD (x) = y;
1224         return y;
1225 }
1226
1227 void
1228 iks_hide (iks *x)
1229 {
1230         iks *y;
1231
1232         if (!x) return;
1233
1234         if (x->prev) x->prev->next = x->next;
1235         if (x->next) x->next->prev = x->prev;
1236         y = x->parent;
1237         if (y) {
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;
1240         }
1241 }
1242
1243 void
1244 iks_delete (iks *x)
1245 {
1246         if (x) iks_stack_delete (x->s);
1247 }
1248
1249 /*****  Node Traversing  *****/
1250
1251 iks *
1252 iks_next (iks *x)
1253 {
1254         if (x) return x->next;
1255         return NULL;
1256 }
1257
1258 iks *
1259 iks_next_tag (iks *x)
1260 {
1261         if (x) {
1262                 while (1) {
1263                         x = x->next;
1264                         if (NULL == x) break;
1265                         if (IKS_TAG == x->type) return x;
1266                 }
1267         }
1268         return NULL;
1269 }
1270
1271 iks *
1272 iks_prev (iks *x)
1273 {
1274         if (x) return x->prev;
1275         return NULL;
1276 }
1277
1278 iks *
1279 iks_prev_tag (iks *x)
1280 {
1281         if (x) {
1282                 while (1) {
1283                         x = x->prev;
1284                         if (NULL == x) break;
1285                         if (IKS_TAG == x->type) return x;
1286                 }
1287         }
1288         return NULL;
1289 }
1290
1291 iks *
1292 iks_parent (iks *x)
1293 {
1294         if (x) return x->parent;
1295         return NULL;
1296 }
1297
1298 iks *
1299 iks_root (iks *x)
1300 {
1301         if (x) {
1302                 while (x->parent)
1303                         x = x->parent;
1304         }
1305         return x;
1306 }
1307
1308 iks *
1309 iks_child (iks *x)
1310 {
1311         if (x) return IKS_TAG_CHILDREN (x);
1312         return NULL;
1313 }
1314
1315 iks *
1316 iks_first_tag (iks *x)
1317 {
1318         if (x) {
1319                 x = IKS_TAG_CHILDREN (x);
1320                 while (x) {
1321                         if (IKS_TAG == x->type) return x;
1322                         x = x->next;
1323                 }
1324         }
1325         return NULL;
1326 }
1327
1328 iks *
1329 iks_attrib (iks *x)
1330 {
1331         if (x) return IKS_TAG_ATTRIBS (x);
1332         return NULL;
1333 }
1334
1335 iks *
1336 iks_find (iks *x, const char *name)
1337 {
1338         iks *y;
1339
1340         if (!x) return NULL;
1341         y = IKS_TAG_CHILDREN (x);
1342         while (y) {
1343                 if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y;
1344                 y = y->next;
1345         }
1346         return NULL;
1347 }
1348
1349 char *
1350 iks_find_cdata (iks *x, const char *name)
1351 {
1352         iks *y;
1353
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);
1359 }
1360
1361 char *
1362 iks_find_attrib (iks *x, const char *name)
1363 {
1364         iks *y;
1365
1366         if (!x) return NULL;
1367
1368         y = IKS_TAG_ATTRIBS (x);
1369         while (y) {
1370                 if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0)
1371                         return IKS_ATTRIB_VALUE (y);
1372                 y = y->next;
1373         }
1374         return NULL;
1375 }
1376
1377 iks *
1378 iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value)
1379 {
1380         iks *y;
1381
1382         if (NULL == x) return NULL;
1383
1384         if (tagname) {
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) {
1389                                         return y;
1390                         }
1391                 }
1392         } else {
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) {
1396                                         return y;
1397                         }
1398                 }
1399         }
1400         return NULL;
1401 }
1402
1403 /*****  Node Information  *****/
1404
1405 ikstack *
1406 iks_stack (iks *x)
1407 {
1408         if (x) return x->s;
1409         return NULL;
1410 }
1411
1412 enum ikstype
1413 iks_type (iks *x)
1414 {
1415         if (x) return x->type;
1416         return IKS_NONE;
1417 }
1418
1419 char *
1420 iks_name (iks *x)
1421 {
1422         if (x) {
1423                 if (IKS_TAG == x->type)
1424                         return IKS_TAG_NAME (x);
1425                 else
1426                         return IKS_ATTRIB_NAME (x);
1427         }
1428         return NULL;
1429 }
1430
1431 char *
1432 iks_cdata (iks *x)
1433 {
1434         if (x) {
1435                 if (IKS_CDATA == x->type)
1436                         return IKS_CDATA_CDATA (x);
1437                 else
1438                         return IKS_ATTRIB_VALUE (x);
1439         }
1440         return NULL;
1441 }
1442
1443 size_t
1444 iks_cdata_size (iks *x)
1445 {
1446         if (x) return IKS_CDATA_LEN (x);
1447         return 0;
1448 }
1449
1450 int
1451 iks_has_children (iks *x)
1452 {
1453         if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1;
1454         return 0;
1455 }
1456
1457 int
1458 iks_has_attribs (iks *x)
1459 {
1460         if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1;
1461         return 0;
1462 }
1463
1464 /*****  Serializing  *****/
1465
1466 static size_t
1467 escape_size (char *src, size_t len)
1468 {
1469         size_t sz;
1470         char c;
1471         int i;
1472
1473         sz = 0;
1474         for (i = 0; i < len; i++) {
1475                 c = src[i];
1476                 switch (c) {
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;
1483                 }
1484         }
1485         return sz;
1486 }
1487
1488 static char *
1489 my_strcat (char *dest, char *src, size_t len)
1490 {
1491         if (0 == len) len = strlen (src);
1492         memcpy (dest, src, len);
1493         return dest + len;
1494 }
1495
1496 static char *
1497 escape (char *dest, char *src, size_t len)
1498 {
1499         char c;
1500         int i;
1501         int j = 0;
1502
1503         for (i = 0; i < len; i++) {
1504                 c = src[i];
1505                 if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) {
1506                         if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1507                         j = i + 1;
1508                         switch (c) {
1509                         case '&': dest = my_strcat (dest, "&amp;", 5); break;
1510                         case '\'': dest = my_strcat (dest, "&apos;", 6); break;
1511                         case '"': dest = my_strcat (dest, "&quot;", 6); break;
1512                         case '<': dest = my_strcat (dest, "&lt;", 4); break;
1513                         case '>': dest = my_strcat (dest, "&gt;", 4); break;
1514                         }
1515                 }
1516         }
1517         if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
1518         return dest;
1519 }
1520
1521 char *
1522 iks_string (ikstack *s, iks *x)
1523 {
1524         size_t size;
1525         int level, dir;
1526         iks *y, *z;
1527         char *ret, *t;
1528
1529         if (!x) return NULL;
1530
1531         if (x->type == IKS_CDATA) {
1532                 if (s) {
1533                         return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1534                 } else {
1535                         ret = iks_malloc (IKS_CDATA_LEN (x));
1536                         memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1537                         return ret;
1538                 }
1539         }
1540
1541         size = 0;
1542         level = 0;
1543         dir = 0;
1544         y = x;
1545         while (1) {
1546                 if (dir==0) {
1547                         if (y->type == IKS_TAG) {
1548                                 size++;
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)));
1553                                 }
1554                                 if (IKS_TAG_CHILDREN (y)) {
1555                                         size++;
1556                                         y = IKS_TAG_CHILDREN (y);
1557                                         level++;
1558                                         continue;
1559                                 } else {
1560                                         size += 2;
1561                                 }
1562                         } else {
1563                                 size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y));
1564                         }
1565                 }
1566                 z = y->next;
1567                 if (z) {
1568                         if (0 == level) {
1569                                 if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y));
1570                                 break;
1571                         }
1572                         y = z;
1573                         dir = 0;
1574                 } else {
1575                         y = y->parent;
1576                         level--;
1577                         if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y));
1578                         if (level < 1) break;
1579                         dir = 1;
1580                 }
1581         }
1582
1583         if (s) ret = iks_stack_alloc (s, size + 1);
1584         else ret = iks_malloc (size + 1);
1585
1586         if (!ret) return NULL;
1587
1588         t = ret;
1589         level = 0;
1590         dir = 0;
1591         while (1) {
1592                 if (dir==0) {
1593                         if (x->type == IKS_TAG) {
1594                                 *t++ = '<';
1595                                 t = my_strcat (t, IKS_TAG_NAME (x), 0);
1596                                 y = IKS_TAG_ATTRIBS (x);
1597                                 while (y) {
1598                                         *t++ = ' ';
1599                                         t = my_strcat (t, IKS_ATTRIB_NAME (y), 0);
1600                                         *t++ = '=';
1601                                         *t++ = '\'';
1602                                         t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y)));
1603                                         *t++ = '\'';
1604                                         y = y->next;
1605                                 }
1606                                 if (IKS_TAG_CHILDREN (x)) {
1607                                         *t++ = '>';
1608                                         x = IKS_TAG_CHILDREN (x);
1609                                         level++;
1610                                         continue;
1611                                 } else {
1612                                         *t++ = '/';
1613                                         *t++ = '>';
1614                                 }
1615                         } else {
1616                                 t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1617                         }
1618                 }
1619                 y = x->next;
1620                 if (y) {
1621                         if (0 == level) {
1622                                 if (IKS_TAG_CHILDREN (x)) {
1623                                         *t++ = '<';
1624                                         *t++ = '/';
1625                                         t = my_strcat (t, IKS_TAG_NAME (x), 0);
1626                                         *t++ = '>';
1627                                 }
1628                                 break;
1629                         }
1630                         x = y;
1631                         dir = 0;
1632                 } else {
1633                         x = x->parent;
1634                         level--;
1635                         if (level >= 0) {
1636                                         *t++ = '<';
1637                                         *t++ = '/';
1638                                         t = my_strcat (t, IKS_TAG_NAME (x), 0);
1639                                         *t++ = '>';
1640                                 }
1641                         if (level < 1) break;
1642                         dir = 1;
1643                 }
1644         }
1645         *t = '\0';
1646
1647         return ret;
1648 }
1649
1650 /*****  Copying  *****/
1651
1652 iks *
1653 iks_copy_within (iks *x, ikstack *s)
1654 {
1655         int level=0, dir=0;
1656         iks *copy = NULL;
1657         iks *cur = NULL;
1658         iks *y;
1659
1660         while (1) {
1661                 if (dir == 0) {
1662                         if (x->type == IKS_TAG) {
1663                                 if (copy == NULL) {
1664                                         copy = iks_new_within (IKS_TAG_NAME (x), s);
1665                                         cur = copy;
1666                                 } else {
1667                                         cur = iks_insert (cur, IKS_TAG_NAME (x));
1668                                 }
1669                                 for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) {
1670                                         iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y));
1671                                 }
1672                                 if (IKS_TAG_CHILDREN (x)) {
1673                                         x = IKS_TAG_CHILDREN (x);
1674                                         level++;
1675                                         continue;
1676                                 } else {
1677                                         cur = cur->parent;
1678                                 }
1679                         } else {
1680                                 iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
1681                         }
1682                 }
1683                 y = x->next;
1684                 if (y) {
1685                         if (0 == level) break;
1686                         x = y;
1687                         dir = 0;
1688                 } else {
1689                         if (level < 2) break;
1690                         level--;
1691                         x = x->parent;
1692                         cur = cur->parent;
1693                         dir = 1;
1694                 }
1695         }
1696         return copy;
1697 }
1698
1699 iks *
1700 iks_copy (iks *x)
1701 {
1702         return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256));
1703 }
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.
1708 */
1709
1710 #include "common.h"
1711 #include "iksemel.h"
1712
1713 struct dom_data {
1714         iks **iksptr;
1715         iks *current;
1716         size_t chunk_size;
1717 };
1718
1719 static int
1720 tagHook (struct dom_data *data, char *name, char **atts, int type)
1721 {
1722         iks *x;
1723
1724         if (IKS_OPEN == type || IKS_SINGLE == type) {
1725                 if (data->current) {
1726                         x = iks_insert (data->current, name);
1727                 } else {
1728                         ikstack *s;
1729                         s = iks_stack_new (data->chunk_size, data->chunk_size);
1730                         x = iks_new_within (name, s);
1731                 }
1732                 if (atts) {
1733                         int i=0;
1734                         while (atts[i]) {
1735                                 iks_insert_attrib (x, atts[i], atts[i+1]);
1736                                 i += 2;
1737                         }
1738                 }
1739                 data->current = x;
1740         }
1741         if (IKS_CLOSE == type || IKS_SINGLE == type) {
1742                 x = iks_parent (data->current);
1743                 if (x)
1744                         data->current = x;
1745                 else {
1746                         *(data->iksptr) = data->current;
1747                         data->current = NULL;
1748                 }
1749         }
1750         return IKS_OK;
1751 }
1752
1753 static int
1754 cdataHook (struct dom_data *data, char *cdata, size_t len)
1755 {
1756         if (data->current) iks_insert_cdata (data->current, cdata, len);
1757         return IKS_OK;
1758 }
1759
1760 static void
1761 deleteHook (struct dom_data *data)
1762 {
1763         if (data->current) iks_delete (data->current);
1764         data->current = NULL;
1765 }
1766
1767 iksparser *
1768 iks_dom_new (iks **iksptr)
1769 {
1770         ikstack *s;
1771         struct dom_data *data;
1772
1773         *iksptr = NULL;
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);
1781 }
1782
1783 void
1784 iks_set_size_hint (iksparser *prs, size_t approx_size)
1785 {
1786         size_t cs;
1787         struct dom_data *data = iks_user_data (prs);
1788
1789         cs = approx_size / 10;
1790         if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE;
1791         data->chunk_size = cs;
1792 }
1793
1794 iks *
1795 iks_tree (const char *xml_str, size_t len, int *err)
1796 {
1797         iksparser *prs;
1798         iks *x;
1799         int e;
1800
1801         if (0 == len) len = strlen (xml_str);
1802         prs = iks_dom_new (&x);
1803         if (!prs) {
1804                 if (err) *err = IKS_NOMEM;
1805                 return NULL;
1806         }
1807         e = iks_parse (prs, xml_str, len, 1);
1808         if (err) *err = e;
1809         iks_parser_delete (prs);
1810         return x;
1811 }
1812
1813 int
1814 iks_load (const char *fname, iks **xptr)
1815 {
1816         iksparser *prs;
1817         char *buf;
1818         FILE *f;
1819         int len, done = 0;
1820         int ret;
1821
1822         *xptr = NULL;
1823
1824         buf = iks_malloc (FILE_IO_BUF_SIZE);
1825         if (!buf) return IKS_NOMEM;
1826         ret = IKS_NOMEM;
1827         prs = iks_dom_new (xptr);
1828         if (prs) {
1829                 f = fopen (fname, "r");
1830                 if (f) {
1831                         while (0 == done) {
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;
1836                                                 len = 0;
1837                                         }
1838                                         done = 1;
1839                                 }
1840                                 if (len > 0) {
1841                                         int e;
1842                                         e = iks_parse (prs, buf, len, done);
1843                                         if (IKS_OK != e) {
1844                                                 ret = e;
1845                                                 break;
1846                                         }
1847                                         if (done) ret = IKS_OK;
1848                                 }
1849                         }
1850                         fclose (f);
1851                 } else {
1852                         if (ENOENT == errno) ret = IKS_FILE_NOFILE;
1853                         else ret = IKS_FILE_NOACCESS;
1854                 }
1855                 iks_parser_delete (prs);
1856         }
1857         iks_free (buf);
1858         return ret;
1859 }
1860
1861 int
1862 iks_save (const char *fname, iks *x)
1863 {
1864         FILE *f;
1865         char *data;
1866         int ret;
1867
1868         ret = IKS_NOMEM;
1869         data = iks_string (NULL, x);
1870         if (data) {
1871                 ret = IKS_FILE_NOACCESS;
1872                 f = fopen (fname, "w");
1873                 if (f) {
1874                         ret = IKS_FILE_RWERR;
1875                         if (fputs (data, f) >= 0) ret = IKS_OK;
1876                         fclose (f);
1877                 }
1878                 iks_free (data);
1879         }
1880         return ret;
1881 }