Statistics
| Revision:

root / src / xml.c @ 322

History | View | Annotate | Download (12.7 kB)

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