Statistics
| Revision:

root / libsylph / xml.c @ 3052

History | View | Annotate | Download (13.2 kB)

1 528 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 528 hiro
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 528 hiro
 *
5 578 hiro
 * This library is free software; you can redistribute it and/or
6 578 hiro
 * modify it under the terms of the GNU Lesser General Public
7 578 hiro
 * License as published by the Free Software Foundation; either
8 578 hiro
 * version 2.1 of the License, or (at your option) any later version.
9 528 hiro
 *
10 578 hiro
 * This library is distributed in the hope that it will be useful,
11 528 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 578 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 578 hiro
 * Lesser General Public License for more details.
14 528 hiro
 *
15 578 hiro
 * You should have received a copy of the GNU Lesser General Public
16 578 hiro
 * License along with this library; if not, write to the Free Software
17 578 hiro
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 528 hiro
 */
19 528 hiro
20 528 hiro
#include <glib.h>
21 528 hiro
#include <stdio.h>
22 528 hiro
#include <string.h>
23 528 hiro
#include <ctype.h>
24 528 hiro
25 528 hiro
#include "xml.h"
26 528 hiro
#include "utils.h"
27 528 hiro
#include "codeconv.h"
28 528 hiro
29 528 hiro
#define SPARSE_MEMORY
30 528 hiro
/* if this is defined all attr.names and tag.names are stored
31 528 hiro
 * in a hash table */
32 528 hiro
#if defined(SPARSE_MEMORY)
33 528 hiro
#include "stringtable.h"
34 528 hiro
35 528 hiro
static StringTable *xml_string_table;
36 528 hiro
37 528 hiro
static void xml_string_table_create(void)
38 528 hiro
{
39 528 hiro
        if (xml_string_table == NULL)
40 528 hiro
                xml_string_table = string_table_new();
41 528 hiro
}
42 528 hiro
#define XML_STRING_ADD(str) \
43 528 hiro
        string_table_insert_string(xml_string_table, (str))
44 528 hiro
#define XML_STRING_FREE(str) \
45 528 hiro
        string_table_free_string(xml_string_table, (str))
46 528 hiro
47 528 hiro
#define XML_STRING_TABLE_CREATE() \
48 528 hiro
        xml_string_table_create()
49 528 hiro
50 528 hiro
#else /* !SPARSE_MEMORY */
51 528 hiro
52 528 hiro
#define XML_STRING_ADD(str) \
53 528 hiro
        g_strdup(str)
54 528 hiro
#define XML_STRING_FREE(str) \
55 528 hiro
        g_free(str)
56 528 hiro
57 528 hiro
#define XML_STRING_TABLE_CREATE()
58 528 hiro
59 528 hiro
#endif /* SPARSE_MEMORY */
60 528 hiro
61 528 hiro
static void xml_free_tag        (XMLTag                *tag);
62 528 hiro
static gint xml_get_parenthesis        (XMLFile        *file,
63 528 hiro
                                 gchar                *buf,
64 528 hiro
                                 gint                 len);
65 528 hiro
66 528 hiro
XMLFile *xml_open_file(const gchar *path)
67 528 hiro
{
68 528 hiro
        XMLFile *newfile;
69 528 hiro
70 528 hiro
        g_return_val_if_fail(path != NULL, NULL);
71 528 hiro
72 528 hiro
        XML_STRING_TABLE_CREATE();
73 528 hiro
74 528 hiro
        newfile = g_new(XMLFile, 1);
75 528 hiro
76 528 hiro
        newfile->fp = g_fopen(path, "rb");
77 528 hiro
        if (!newfile->fp) {
78 528 hiro
                g_free(newfile);
79 528 hiro
                return NULL;
80 528 hiro
        }
81 528 hiro
82 528 hiro
        newfile->buf = g_string_new(NULL);
83 528 hiro
        newfile->bufp = newfile->buf->str;
84 528 hiro
85 528 hiro
        newfile->dtd = NULL;
86 528 hiro
        newfile->encoding = NULL;
87 528 hiro
        newfile->tag_stack = NULL;
88 528 hiro
        newfile->level = 0;
89 528 hiro
        newfile->is_empty_element = FALSE;
90 528 hiro
91 528 hiro
        return newfile;
92 528 hiro
}
93 528 hiro
94 528 hiro
void xml_close_file(XMLFile *file)
95 528 hiro
{
96 528 hiro
        g_return_if_fail(file != NULL);
97 528 hiro
98 528 hiro
        if (file->fp) fclose(file->fp);
99 528 hiro
100 528 hiro
        g_string_free(file->buf, TRUE);
101 528 hiro
102 528 hiro
        g_free(file->dtd);
103 528 hiro
        g_free(file->encoding);
104 528 hiro
105 528 hiro
        while (file->tag_stack != NULL)
106 528 hiro
                xml_pop_tag(file);
107 528 hiro
108 528 hiro
        g_free(file);
109 528 hiro
}
110 528 hiro
111 528 hiro
static GNode *xml_build_tree(XMLFile *file, GNode *parent, guint level)
112 528 hiro
{
113 528 hiro
        GNode *node = NULL;
114 528 hiro
        XMLNode *xmlnode;
115 528 hiro
        XMLTag *tag;
116 528 hiro
117 528 hiro
        while (xml_parse_next_tag(file) == 0) {
118 528 hiro
                if (file->level < level) break;
119 528 hiro
                if (file->level == level) {
120 528 hiro
                        g_warning("xml_build_tree(): Parse error\n");
121 528 hiro
                        break;
122 528 hiro
                }
123 528 hiro
124 528 hiro
                tag = xml_get_current_tag(file);
125 528 hiro
                if (!tag) break;
126 528 hiro
                xmlnode = xml_node_new(xml_copy_tag(tag), NULL);
127 528 hiro
                xmlnode->element = xml_get_element(file);
128 528 hiro
                if (!parent)
129 528 hiro
                        node = g_node_new(xmlnode);
130 528 hiro
                else
131 528 hiro
                        node = g_node_append_data(parent, xmlnode);
132 528 hiro
133 528 hiro
                xml_build_tree(file, node, file->level);
134 528 hiro
                if (file->level == 0) break;
135 528 hiro
        }
136 528 hiro
137 528 hiro
        return node;
138 528 hiro
}
139 528 hiro
140 528 hiro
GNode *xml_parse_file(const gchar *path)
141 528 hiro
{
142 528 hiro
        XMLFile *file;
143 528 hiro
        GNode *node;
144 528 hiro
145 528 hiro
        file = xml_open_file(path);
146 528 hiro
        g_return_val_if_fail(file != NULL, NULL);
147 528 hiro
148 528 hiro
        xml_get_dtd(file);
149 528 hiro
150 528 hiro
        node = xml_build_tree(file, NULL, file->level);
151 528 hiro
152 528 hiro
        xml_close_file(file);
153 528 hiro
154 528 hiro
#if defined(SPARSE_MEMORY)
155 528 hiro
        if (get_debug_mode())
156 528 hiro
                string_table_get_stats(xml_string_table);
157 528 hiro
#endif
158 528 hiro
159 528 hiro
        return node;
160 528 hiro
}
161 528 hiro
162 528 hiro
gint xml_get_dtd(XMLFile *file)
163 528 hiro
{
164 528 hiro
        gchar buf[XMLBUFSIZE];
165 528 hiro
        gchar *bufp = buf;
166 528 hiro
167 528 hiro
        if (xml_get_parenthesis(file, buf, sizeof(buf)) < 0) return -1;
168 528 hiro
169 528 hiro
        if ((*bufp++ == '?') &&
170 528 hiro
            (bufp = strcasestr(bufp, "xml")) &&
171 528 hiro
            (bufp = strcasestr(bufp + 3, "version")) &&
172 528 hiro
            (bufp = strchr(bufp + 7, '?'))) {
173 528 hiro
                file->dtd = g_strdup(buf);
174 528 hiro
                if ((bufp = strcasestr(buf, "encoding=\""))) {
175 528 hiro
                        bufp += 9;
176 528 hiro
                        extract_quote(bufp, '"');
177 528 hiro
                        file->encoding = g_strdup(bufp);
178 528 hiro
                } else
179 528 hiro
                        file->encoding = g_strdup(CS_INTERNAL);
180 528 hiro
        } else {
181 528 hiro
                g_warning("Can't get xml dtd\n");
182 528 hiro
                return -1;
183 528 hiro
        }
184 528 hiro
185 528 hiro
        return 0;
186 528 hiro
}
187 528 hiro
188 528 hiro
gint xml_parse_next_tag(XMLFile *file)
189 528 hiro
{
190 528 hiro
        gchar buf[XMLBUFSIZE];
191 528 hiro
        gchar *bufp = buf;
192 528 hiro
        gchar *tag_str;
193 528 hiro
        XMLTag *tag;
194 528 hiro
        gint len;
195 528 hiro
196 528 hiro
        if (file->is_empty_element == TRUE) {
197 528 hiro
                file->is_empty_element = FALSE;
198 528 hiro
                xml_pop_tag(file);
199 528 hiro
                return 0;
200 528 hiro
        }
201 528 hiro
202 528 hiro
        if (xml_get_parenthesis(file, buf, sizeof(buf)) < 0) {
203 528 hiro
                g_warning("xml_parse_next_tag(): Can't parse next tag\n");
204 528 hiro
                return -1;
205 528 hiro
        }
206 528 hiro
207 528 hiro
        /* end-tag */
208 528 hiro
        if (buf[0] == '/') {
209 528 hiro
                if (strcmp(xml_get_current_tag(file)->tag, buf + 1) != 0) {
210 528 hiro
                        g_warning("xml_parse_next_tag(): Tag name mismatch: %s\n", buf);
211 528 hiro
                        return -1;
212 528 hiro
                }
213 528 hiro
                xml_pop_tag(file);
214 528 hiro
                return 0;
215 528 hiro
        }
216 528 hiro
217 528 hiro
        tag = xml_tag_new(NULL);
218 528 hiro
        xml_push_tag(file, tag);
219 528 hiro
220 528 hiro
        len = strlen(buf);
221 528 hiro
        if (len > 0 && buf[len - 1] == '/') {
222 528 hiro
                file->is_empty_element = TRUE;
223 528 hiro
                buf[len - 1] = '\0';
224 528 hiro
                g_strchomp(buf);
225 528 hiro
        }
226 528 hiro
        if (strlen(buf) == 0) {
227 528 hiro
                g_warning("xml_parse_next_tag(): Tag name is empty\n");
228 528 hiro
                return -1;
229 528 hiro
        }
230 528 hiro
231 528 hiro
        while (*bufp != '\0' && !g_ascii_isspace(*bufp)) bufp++;
232 528 hiro
        if (*bufp == '\0') {
233 528 hiro
                tag_str = conv_codeset_strdup(buf, file->encoding, CS_INTERNAL);
234 528 hiro
                if (tag_str) {
235 528 hiro
                        tag->tag = XML_STRING_ADD(tag_str);
236 528 hiro
                        g_free(tag_str);
237 528 hiro
                } else
238 528 hiro
                        tag->tag = XML_STRING_ADD(buf);
239 528 hiro
                return 0;
240 528 hiro
        } else {
241 528 hiro
                *bufp++ = '\0';
242 528 hiro
                tag_str = conv_codeset_strdup(buf, file->encoding, CS_INTERNAL);
243 528 hiro
                if (tag_str) {
244 528 hiro
                        tag->tag = XML_STRING_ADD(tag_str);
245 528 hiro
                        g_free(tag_str);
246 528 hiro
                } else
247 528 hiro
                        tag->tag = XML_STRING_ADD(buf);
248 528 hiro
        }
249 528 hiro
250 528 hiro
        /* parse attributes ( name=value ) */
251 528 hiro
        while (*bufp) {
252 528 hiro
                XMLAttr *attr;
253 528 hiro
                gchar *attr_name;
254 528 hiro
                gchar *attr_value;
255 528 hiro
                gchar *utf8_attr_name;
256 528 hiro
                gchar *utf8_attr_value;
257 528 hiro
                gchar *p;
258 528 hiro
                gchar quote;
259 528 hiro
260 528 hiro
                while (g_ascii_isspace(*bufp)) bufp++;
261 528 hiro
                attr_name = bufp;
262 528 hiro
                if ((p = strchr(attr_name, '=')) == NULL) {
263 528 hiro
                        g_warning("xml_parse_next_tag(): Syntax error in tag\n");
264 528 hiro
                        return -1;
265 528 hiro
                }
266 528 hiro
                bufp = p;
267 528 hiro
                *bufp++ = '\0';
268 528 hiro
                while (g_ascii_isspace(*bufp)) bufp++;
269 528 hiro
270 528 hiro
                if (*bufp != '"' && *bufp != '\'') {
271 528 hiro
                        g_warning("xml_parse_next_tag(): Syntax error in tag\n");
272 528 hiro
                        return -1;
273 528 hiro
                }
274 528 hiro
                quote = *bufp;
275 528 hiro
                bufp++;
276 528 hiro
                attr_value = bufp;
277 528 hiro
                if ((p = strchr(attr_value, quote)) == NULL) {
278 528 hiro
                        g_warning("xml_parse_next_tag(): Syntax error in tag\n");
279 528 hiro
                        return -1;
280 528 hiro
                }
281 528 hiro
                bufp = p;
282 528 hiro
                *bufp++ = '\0';
283 528 hiro
284 528 hiro
                g_strchomp(attr_name);
285 528 hiro
                xml_unescape_str(attr_value);
286 528 hiro
                utf8_attr_name = conv_codeset_strdup
287 528 hiro
                        (attr_name, file->encoding, CS_INTERNAL);
288 528 hiro
                utf8_attr_value = conv_codeset_strdup
289 528 hiro
                        (attr_value, file->encoding, CS_INTERNAL);
290 528 hiro
                if (!utf8_attr_name)
291 528 hiro
                        utf8_attr_name = g_strdup(attr_name);
292 528 hiro
                if (!utf8_attr_value)
293 528 hiro
                        utf8_attr_value = g_strdup(attr_value);
294 528 hiro
295 528 hiro
                attr = xml_attr_new(utf8_attr_name, utf8_attr_value);
296 528 hiro
                xml_tag_add_attr(tag, attr);
297 528 hiro
298 528 hiro
                g_free(utf8_attr_value);
299 528 hiro
                g_free(utf8_attr_name);
300 528 hiro
        }
301 528 hiro
302 528 hiro
        return 0;
303 528 hiro
}
304 528 hiro
305 528 hiro
void xml_push_tag(XMLFile *file, XMLTag *tag)
306 528 hiro
{
307 528 hiro
        g_return_if_fail(tag != NULL);
308 528 hiro
309 528 hiro
        file->tag_stack = g_list_prepend(file->tag_stack, tag);
310 528 hiro
        file->level++;
311 528 hiro
}
312 528 hiro
313 528 hiro
void xml_pop_tag(XMLFile *file)
314 528 hiro
{
315 528 hiro
        XMLTag *tag;
316 528 hiro
317 528 hiro
        if (!file->tag_stack) return;
318 528 hiro
319 528 hiro
        tag = (XMLTag *)file->tag_stack->data;
320 528 hiro
321 528 hiro
        xml_free_tag(tag);
322 528 hiro
        file->tag_stack = g_list_remove(file->tag_stack, tag);
323 528 hiro
        file->level--;
324 528 hiro
}
325 528 hiro
326 528 hiro
XMLTag *xml_get_current_tag(XMLFile *file)
327 528 hiro
{
328 528 hiro
        if (file->tag_stack)
329 528 hiro
                return (XMLTag *)file->tag_stack->data;
330 528 hiro
        else
331 528 hiro
                return NULL;
332 528 hiro
}
333 528 hiro
334 528 hiro
GList *xml_get_current_tag_attr(XMLFile *file)
335 528 hiro
{
336 528 hiro
        XMLTag *tag;
337 528 hiro
338 528 hiro
        tag = xml_get_current_tag(file);
339 528 hiro
        if (!tag) return NULL;
340 528 hiro
341 528 hiro
        return tag->attr;
342 528 hiro
}
343 528 hiro
344 528 hiro
gchar *xml_get_element(XMLFile *file)
345 528 hiro
{
346 528 hiro
        gchar *str;
347 528 hiro
        gchar *new_str;
348 528 hiro
        gchar *end;
349 528 hiro
350 528 hiro
        while ((end = strchr(file->bufp, '<')) == NULL)
351 528 hiro
                if (xml_read_line(file) < 0) return NULL;
352 528 hiro
353 528 hiro
        if (end == file->bufp)
354 528 hiro
                return NULL;
355 528 hiro
356 528 hiro
        str = g_strndup(file->bufp, end - file->bufp);
357 528 hiro
        /* this is not XML1.0 strict */
358 528 hiro
        g_strstrip(str);
359 528 hiro
        xml_unescape_str(str);
360 528 hiro
361 528 hiro
        file->bufp = end;
362 528 hiro
        xml_truncate_buf(file);
363 528 hiro
364 528 hiro
        if (str[0] == '\0') {
365 528 hiro
                g_free(str);
366 528 hiro
                return NULL;
367 528 hiro
        }
368 528 hiro
369 528 hiro
        new_str = conv_codeset_strdup(str, file->encoding, CS_INTERNAL);
370 528 hiro
        if (!new_str)
371 528 hiro
                new_str = g_strdup(str);
372 528 hiro
        g_free(str);
373 528 hiro
374 528 hiro
        return new_str;
375 528 hiro
}
376 528 hiro
377 528 hiro
gint xml_read_line(XMLFile *file)
378 528 hiro
{
379 528 hiro
        gchar buf[XMLBUFSIZE];
380 528 hiro
        gint index;
381 528 hiro
382 528 hiro
        if (fgets(buf, sizeof(buf), file->fp) == NULL)
383 528 hiro
                return -1;
384 528 hiro
385 528 hiro
        index = file->bufp - file->buf->str;
386 528 hiro
387 528 hiro
        g_string_append(file->buf, buf);
388 528 hiro
389 528 hiro
        file->bufp = file->buf->str + index;
390 528 hiro
391 528 hiro
        return 0;
392 528 hiro
}
393 528 hiro
394 528 hiro
void xml_truncate_buf(XMLFile *file)
395 528 hiro
{
396 528 hiro
        gint len;
397 528 hiro
398 528 hiro
        len = file->bufp - file->buf->str;
399 528 hiro
        if (len > 0) {
400 528 hiro
                g_string_erase(file->buf, 0, len);
401 528 hiro
                file->bufp = file->buf->str;
402 528 hiro
        }
403 528 hiro
}
404 528 hiro
405 528 hiro
gboolean xml_compare_tag(XMLFile *file, const gchar *name)
406 528 hiro
{
407 528 hiro
        XMLTag *tag;
408 528 hiro
409 528 hiro
        tag = xml_get_current_tag(file);
410 528 hiro
411 528 hiro
        if (tag && strcmp(tag->tag, name) == 0)
412 528 hiro
                return TRUE;
413 528 hiro
        else
414 528 hiro
                return FALSE;
415 528 hiro
}
416 528 hiro
417 528 hiro
XMLNode *xml_node_new(XMLTag *tag, const gchar *text)
418 528 hiro
{
419 528 hiro
        XMLNode *node;
420 528 hiro
421 528 hiro
        node = g_new(XMLNode, 1);
422 528 hiro
        node->tag = tag;
423 528 hiro
        node->element = g_strdup(text);
424 528 hiro
425 528 hiro
        return node;
426 528 hiro
}
427 528 hiro
428 528 hiro
XMLTag *xml_tag_new(const gchar *tag)
429 528 hiro
{
430 528 hiro
        XMLTag *new_tag;
431 528 hiro
432 528 hiro
        new_tag = g_new(XMLTag, 1);
433 528 hiro
        if (tag)
434 528 hiro
                new_tag->tag = XML_STRING_ADD(tag);
435 528 hiro
        else
436 528 hiro
                new_tag->tag = NULL;
437 528 hiro
        new_tag->attr = NULL;
438 528 hiro
439 528 hiro
        return new_tag;
440 528 hiro
}
441 528 hiro
442 528 hiro
XMLAttr *xml_attr_new(const gchar *name, const gchar *value)
443 528 hiro
{
444 528 hiro
        XMLAttr *new_attr;
445 528 hiro
446 528 hiro
        new_attr = g_new(XMLAttr, 1);
447 528 hiro
        new_attr->name = XML_STRING_ADD(name);
448 528 hiro
        new_attr->value = g_strdup(value);
449 528 hiro
450 528 hiro
        return new_attr;
451 528 hiro
}
452 528 hiro
453 528 hiro
void xml_tag_add_attr(XMLTag *tag, XMLAttr *attr)
454 528 hiro
{
455 528 hiro
        tag->attr = g_list_append(tag->attr, attr);
456 528 hiro
}
457 528 hiro
458 528 hiro
XMLTag *xml_copy_tag(XMLTag *tag)
459 528 hiro
{
460 528 hiro
        XMLTag *new_tag;
461 528 hiro
        XMLAttr *attr;
462 528 hiro
        GList *list;
463 528 hiro
464 528 hiro
        new_tag = xml_tag_new(tag->tag);
465 528 hiro
        for (list = tag->attr; list != NULL; list = list->next) {
466 528 hiro
                attr = xml_copy_attr((XMLAttr *)list->data);
467 528 hiro
                xml_tag_add_attr(new_tag, attr);
468 528 hiro
        }
469 528 hiro
470 528 hiro
        return new_tag;
471 528 hiro
}
472 528 hiro
473 528 hiro
XMLAttr *xml_copy_attr(XMLAttr *attr)
474 528 hiro
{
475 528 hiro
        return xml_attr_new(attr->name, attr->value);
476 528 hiro
}
477 528 hiro
478 528 hiro
gint xml_unescape_str(gchar *str)
479 528 hiro
{
480 528 hiro
        gchar *start;
481 528 hiro
        gchar *end;
482 528 hiro
        gchar *p = str;
483 528 hiro
        gchar ch;
484 528 hiro
        gint len;
485 528 hiro
486 528 hiro
        while ((start = strchr(p, '&')) != NULL) {
487 528 hiro
                if ((end = strchr(start + 1, ';')) == NULL) {
488 528 hiro
                        g_warning("Unescaped `&' appeared\n");
489 528 hiro
                        p = start + 1;
490 528 hiro
                        continue;
491 528 hiro
                }
492 528 hiro
                len = end - start + 1;
493 528 hiro
                if (len < 3) {
494 528 hiro
                        p = end + 1;
495 528 hiro
                        continue;
496 528 hiro
                }
497 528 hiro
498 2918 hiro
                if (!strncmp(start, "&lt;", 4))
499 528 hiro
                        ch = '<';
500 2918 hiro
                else if (!strncmp(start, "&gt;", 4))
501 528 hiro
                        ch = '>';
502 2918 hiro
                else if (!strncmp(start, "&amp;", 5))
503 528 hiro
                        ch = '&';
504 2918 hiro
                else if (!strncmp(start, "&apos;", 6))
505 528 hiro
                        ch = '\'';
506 2918 hiro
                else if (!strncmp(start, "&quot;", 6))
507 528 hiro
                        ch = '\"';
508 528 hiro
                else {
509 528 hiro
                        p = end + 1;
510 528 hiro
                        continue;
511 528 hiro
                }
512 528 hiro
513 528 hiro
                *start = ch;
514 528 hiro
                memmove(start + 1, end + 1, strlen(end + 1) + 1);
515 528 hiro
                p = start + 1;
516 528 hiro
        }
517 528 hiro
518 528 hiro
        return 0;
519 528 hiro
}
520 528 hiro
521 2721 hiro
gchar *xml_escape_str(const gchar *str)
522 2721 hiro
{
523 2721 hiro
        GString *estr;
524 2721 hiro
        const gchar *p;
525 2721 hiro
526 2721 hiro
        if (!str)
527 2721 hiro
                return NULL;
528 2721 hiro
529 2721 hiro
        estr = g_string_sized_new(strlen(str));
530 2721 hiro
        for (p = str; *p != '\0'; p++) {
531 2721 hiro
                switch (*p) {
532 2721 hiro
                case '<':
533 2721 hiro
                        g_string_append(estr, "&lt;");
534 2721 hiro
                        break;
535 2721 hiro
                case '>':
536 2721 hiro
                        g_string_append(estr, "&gt;");
537 2721 hiro
                        break;
538 2721 hiro
                case '&':
539 2721 hiro
                        g_string_append(estr, "&amp;");
540 2721 hiro
                        break;
541 2721 hiro
                case '\'':
542 2721 hiro
                        g_string_append(estr, "&apos;");
543 2721 hiro
                        break;
544 2721 hiro
                case '\"':
545 2721 hiro
                        g_string_append(estr, "&quot;");
546 2721 hiro
                        break;
547 2721 hiro
                default:
548 2721 hiro
                        g_string_append_c(estr, *p);
549 2721 hiro
                        break;
550 2721 hiro
                }
551 2721 hiro
        }
552 2721 hiro
553 2721 hiro
        return g_string_free(estr, FALSE);
554 2721 hiro
}
555 2721 hiro
556 528 hiro
gint xml_file_put_escape_str(FILE *fp, const gchar *str)
557 528 hiro
{
558 528 hiro
        const gchar *p;
559 528 hiro
560 528 hiro
        g_return_val_if_fail(fp != NULL, -1);
561 528 hiro
562 528 hiro
        if (!str) return 0;
563 528 hiro
564 528 hiro
        for (p = str; *p != '\0'; p++) {
565 528 hiro
                switch (*p) {
566 528 hiro
                case '<':
567 528 hiro
                        fputs("&lt;", fp);
568 528 hiro
                        break;
569 528 hiro
                case '>':
570 528 hiro
                        fputs("&gt;", fp);
571 528 hiro
                        break;
572 528 hiro
                case '&':
573 528 hiro
                        fputs("&amp;", fp);
574 528 hiro
                        break;
575 528 hiro
                case '\'':
576 528 hiro
                        fputs("&apos;", fp);
577 528 hiro
                        break;
578 528 hiro
                case '\"':
579 528 hiro
                        fputs("&quot;", fp);
580 528 hiro
                        break;
581 528 hiro
                default:
582 528 hiro
                        fputc(*p, fp);
583 528 hiro
                }
584 528 hiro
        }
585 528 hiro
586 528 hiro
        return 0;
587 528 hiro
}
588 528 hiro
589 528 hiro
gint xml_file_put_xml_decl(FILE *fp)
590 528 hiro
{
591 528 hiro
        g_return_val_if_fail(fp != NULL, -1);
592 528 hiro
593 528 hiro
        fprintf(fp, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", CS_INTERNAL);
594 528 hiro
        return 0;
595 528 hiro
}
596 528 hiro
597 528 hiro
gint xml_file_put_node(FILE *fp, XMLNode *node)
598 528 hiro
{
599 528 hiro
        GList *cur;
600 528 hiro
601 528 hiro
        g_return_val_if_fail(fp != NULL, -1);
602 528 hiro
        g_return_val_if_fail(node != NULL, -1);
603 528 hiro
604 528 hiro
        fprintf(fp, "<%s", node->tag->tag);
605 528 hiro
606 528 hiro
        for (cur = node->tag->attr; cur != NULL; cur = cur->next) {
607 528 hiro
                XMLAttr *attr = (XMLAttr *)cur->data;
608 528 hiro
                fprintf(fp, " %s=\"", attr->name);
609 528 hiro
                xml_file_put_escape_str(fp, attr->value);
610 528 hiro
                fputs("\"", fp);
611 528 hiro
        }
612 528 hiro
613 528 hiro
        if (node->element) {
614 528 hiro
                fputs(">", fp);
615 528 hiro
                xml_file_put_escape_str(fp, node->element);
616 528 hiro
                fprintf(fp, "</%s>\n", node->tag->tag);
617 528 hiro
        } else {
618 528 hiro
                fputs(" />\n", fp);
619 528 hiro
        }
620 528 hiro
621 528 hiro
        return 0;
622 528 hiro
}
623 528 hiro
624 528 hiro
void xml_free_node(XMLNode *node)
625 528 hiro
{
626 528 hiro
        if (!node) return;
627 528 hiro
628 528 hiro
        xml_free_tag(node->tag);
629 528 hiro
        g_free(node->element);
630 528 hiro
        g_free(node);
631 528 hiro
}
632 528 hiro
633 528 hiro
static gboolean xml_free_func(GNode *node, gpointer data)
634 528 hiro
{
635 528 hiro
        XMLNode *xmlnode = node->data;
636 528 hiro
637 528 hiro
        xml_free_node(xmlnode);
638 528 hiro
        return FALSE;
639 528 hiro
}
640 528 hiro
641 528 hiro
void xml_free_tree(GNode *node)
642 528 hiro
{
643 528 hiro
        g_return_if_fail(node != NULL);
644 528 hiro
645 528 hiro
        g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, xml_free_func,
646 528 hiro
                        NULL);
647 528 hiro
648 528 hiro
        g_node_destroy(node);
649 528 hiro
}
650 528 hiro
651 528 hiro
static void xml_free_tag(XMLTag *tag)
652 528 hiro
{
653 528 hiro
        if (!tag) return;
654 528 hiro
655 528 hiro
        XML_STRING_FREE(tag->tag);
656 528 hiro
        while (tag->attr != NULL) {
657 528 hiro
                XMLAttr *attr = (XMLAttr *)tag->attr->data;
658 528 hiro
                XML_STRING_FREE(attr->name);
659 528 hiro
                g_free(attr->value);
660 528 hiro
                g_free(attr);
661 528 hiro
                tag->attr = g_list_remove(tag->attr, tag->attr->data);
662 528 hiro
        }
663 528 hiro
        g_free(tag);
664 528 hiro
}
665 528 hiro
666 528 hiro
static gint xml_get_parenthesis(XMLFile *file, gchar *buf, gint len)
667 528 hiro
{
668 528 hiro
        gchar *start;
669 528 hiro
        gchar *end;
670 528 hiro
671 528 hiro
        buf[0] = '\0';
672 528 hiro
673 528 hiro
        while ((start = strchr(file->bufp, '<')) == NULL)
674 528 hiro
                if (xml_read_line(file) < 0) return -1;
675 528 hiro
676 528 hiro
        start++;
677 528 hiro
        file->bufp = start;
678 528 hiro
679 528 hiro
        while ((end = strchr(file->bufp, '>')) == NULL)
680 528 hiro
                if (xml_read_line(file) < 0) return -1;
681 528 hiro
682 528 hiro
        strncpy2(buf, file->bufp, MIN(end - file->bufp + 1, len));
683 528 hiro
        g_strstrip(buf);
684 528 hiro
        file->bufp = end + 1;
685 528 hiro
        xml_truncate_buf(file);
686 528 hiro
687 528 hiro
        return 0;
688 528 hiro
}