summaryrefslogtreecommitdiffstats
path: root/src/dom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dom.c')
-rw-r--r--src/dom.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/dom.c b/src/dom.c
new file mode 100644
index 0000000..849bf20
--- /dev/null
+++ b/src/dom.c
@@ -0,0 +1,181 @@
+/* iksemel (XML parser for Jabber)
+** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net>
+** This code is free software; you can redistribute it and/or
+** modify it under the terms of GNU Lesser General Public License.
+*/
+
+#include "common.h"
+#include "iksemel.h"
+
+struct dom_data {
+ iks **iksptr;
+ iks *current;
+ size_t chunk_size;
+};
+
+static int
+tagHook (struct dom_data *data, char *name, char **atts, int type)
+{
+ iks *x;
+
+ if (IKS_OPEN == type || IKS_SINGLE == type) {
+ if (data->current) {
+ x = iks_insert (data->current, name);
+ } else {
+ ikstack *s;
+ s = iks_stack_new (data->chunk_size, data->chunk_size);
+ x = iks_new_within (name, s);
+ }
+ if (atts) {
+ int i=0;
+ while (atts[i]) {
+ iks_insert_attrib (x, atts[i], atts[i+1]);
+ i += 2;
+ }
+ }
+ data->current = x;
+ }
+ if (IKS_CLOSE == type || IKS_SINGLE == type) {
+ x = iks_parent (data->current);
+ if (iks_strcmp(iks_name(data->current), name) != 0)
+ return IKS_BADXML;
+ if (x)
+ data->current = x;
+ else {
+ *(data->iksptr) = data->current;
+ data->current = NULL;
+ }
+ }
+ return IKS_OK;
+}
+
+static int
+cdataHook (struct dom_data *data, char *cdata, size_t len)
+{
+ if (data->current) iks_insert_cdata (data->current, cdata, len);
+ return IKS_OK;
+}
+
+static void
+deleteHook (struct dom_data *data)
+{
+ if (data->current) iks_delete (data->current);
+ data->current = NULL;
+}
+
+iksparser *
+iks_dom_new (iks **iksptr)
+{
+ ikstack *s;
+ struct dom_data *data;
+
+ *iksptr = NULL;
+ s = iks_stack_new (DEFAULT_DOM_CHUNK_SIZE, 0);
+ if (!s) return NULL;
+ data = iks_stack_alloc (s, sizeof (struct dom_data));
+ data->iksptr = iksptr;
+ data->current = NULL;
+ data->chunk_size = DEFAULT_DOM_IKS_CHUNK_SIZE;
+ return iks_sax_extend (s, data, (iksTagHook *) tagHook, (iksCDataHook *) cdataHook, (iksDeleteHook *) deleteHook);
+}
+
+void
+iks_set_size_hint (iksparser *prs, size_t approx_size)
+{
+ size_t cs;
+ struct dom_data *data = iks_user_data (prs);
+
+ cs = approx_size / 10;
+ if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE;
+ data->chunk_size = cs;
+}
+
+iks *
+iks_tree (const char *xml_str, size_t len, int *err)
+{
+ iksparser *prs;
+ iks *x;
+ int e;
+
+ if (0 == len) len = strlen (xml_str);
+ prs = iks_dom_new (&x);
+ if (!prs) {
+ if (err) *err = IKS_NOMEM;
+ return NULL;
+ }
+ e = iks_parse (prs, xml_str, len, 1);
+ if (err) *err = e;
+ iks_parser_delete (prs);
+ return x;
+}
+
+int
+iks_load (const char *fname, iks **xptr)
+{
+ iksparser *prs;
+ char *buf;
+ FILE *f;
+ int len, done = 0;
+ int ret;
+
+ *xptr = NULL;
+
+ buf = iks_malloc (FILE_IO_BUF_SIZE);
+ if (!buf) return IKS_NOMEM;
+ ret = IKS_NOMEM;
+ prs = iks_dom_new (xptr);
+ if (prs) {
+ f = fopen (fname, "r");
+ if (f) {
+ while (0 == done) {
+ len = fread (buf, 1, FILE_IO_BUF_SIZE, f);
+ if (len < FILE_IO_BUF_SIZE) {
+ if (0 == feof (f)) {
+ ret = IKS_FILE_RWERR;
+ break;
+ }
+ if (0 == len) ret = IKS_OK;
+ done = 1;
+ }
+ if (len > 0) {
+ int e;
+ e = iks_parse (prs, buf, len, done);
+ if (IKS_OK != e) {
+ ret = e;
+ break;
+ }
+ if (done) ret = IKS_OK;
+ }
+ }
+ fclose (f);
+ } else {
+ if (ENOENT == errno) ret = IKS_FILE_NOFILE;
+ else ret = IKS_FILE_NOACCESS;
+ }
+ iks_parser_delete (prs);
+ }
+ iks_free (buf);
+ return ret;
+}
+
+int
+iks_save (const char *fname, iks *x)
+{
+ FILE *f;
+ char *data;
+ int ret;
+
+ ret = IKS_NOMEM;
+ data = iks_string (NULL, x);
+ if (data) {
+ ret = IKS_FILE_NOACCESS;
+ f = fopen (fname, "w");
+ if (f) {
+ ret = IKS_FILE_RWERR;
+ if (fputs (data, f) >= 0) ret = IKS_OK;
+ fclose (f);
+ }
+ iks_free (data);
+ }
+ return ret;
+}