179 lines
3.4 KiB
C
179 lines
3.4 KiB
C
/* 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 (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;
|
|
len = 0;
|
|
}
|
|
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;
|
|
}
|