#include "lib.h"
void _xstream_startElement(xstream xs, const char* name, const char** atts)
{
pool p;
if(xs->status > XSTREAM_NODE) return;
if(xs->node == NULL)
{
p = pool_heap(5*1024);
xs->node = xmlnode_new_tag_pool(p,name);
xmlnode_put_expat_attribs(xs->node, atts);
if(xs->status == XSTREAM_ROOT)
{
xs->status = XSTREAM_NODE;
(xs->f)(XSTREAM_ROOT, xs->node, xs->arg);
xs->node = NULL;
}
}else{
xs->node = xmlnode_insert_tag(xs->node, name);
xmlnode_put_expat_attribs(xs->node, atts);
}
xs->depth++;
if(xs->depth > XSTREAM_MAXDEPTH)
xs->status = XSTREAM_ERR;
}
void _xstream_endElement(xstream xs, const char* name)
{
xmlnode parent;
if(xs->status > XSTREAM_NODE) return;
if(xs->node == NULL)
{
xs->status = XSTREAM_CLOSE;
(xs->f)(XSTREAM_CLOSE, NULL, xs->arg);
}else{
parent = xmlnode_get_parent(xs->node);
if(parent == NULL)
(xs->f)(XSTREAM_NODE, xs->node, xs->arg);
xs->node = parent;
}
xs->depth--;
}
void _xstream_charData(xstream xs, const char *str, int len)
{
if(xs->status > XSTREAM_NODE) return;
if(xs->node == NULL)
{
return;
}
xmlnode_insert_cdata(xs->node, str, len);
}
void _xstream_cleanup(void *arg)
{
xstream xs = (xstream)arg;
xmlnode_free(xs->node);
XML_ParserFree(xs->parser);
}
xstream xstream_new(pool p, xstream_onNode f, void *arg)
{
xstream newx;
if(p == NULL || f == NULL)
{
fprintf(stderr,"Fatal Programming Error: xstream_new() was improperly called with NULL.\n");
return NULL;
}
newx = pmalloco(p, sizeof(_xstream));
newx->p = p;
newx->f = f;
newx->arg = arg;
newx->parser = XML_ParserCreate(NULL);
XML_SetUserData(newx->parser, (void *)newx);
XML_SetElementHandler(newx->parser, (void *)_xstream_startElement, (void *)_xstream_endElement);
XML_SetCharacterDataHandler(newx->parser, (void *)_xstream_charData);
pool_cleanup(p, _xstream_cleanup, (void *)newx);
return newx;
}
int xstream_eat(xstream xs, char *buff, int len)
{
char *err;
xmlnode xerr;
static char maxerr[] = "maximum node size reached";
static char deeperr[] = "maximum node depth reached";
if(xs == NULL)
{
fprintf(stderr,"Fatal Programming Error: xstream_eat() was improperly called with NULL.\n");
return XSTREAM_ERR;
}
if(len == 0 || buff == NULL)
return xs->status;
if(len == -1)
len = strlen(buff);
if(!XML_Parse(xs->parser, buff, len, 0))
{
err = (char *)XML_ErrorString(XML_GetErrorCode(xs->parser));
xs->status = XSTREAM_ERR;
}else if(pool_size(xmlnode_pool(xs->node)) > XSTREAM_MAXNODE || xs->cdata_len > XSTREAM_MAXNODE){
err = maxerr;
xs->status = XSTREAM_ERR;
}else if(xs->status == XSTREAM_ERR){
err = deeperr;
}
if(xs->status == XSTREAM_ERR)
{
xerr = xmlnode_new_tag("error");
xmlnode_insert_cdata(xerr,err,-1);
(xs->f)(XSTREAM_ERR, xerr, xs->arg);
}
return xs->status;
}
xmlnode xstream_header(char *namespace, char *to, char *from)
{
xmlnode x;
char id[10];
sprintf(id,"%X",(int)time(NULL));
x = xmlnode_new_tag("stream:stream");
xmlnode_put_attrib(x, "xmlns:stream", "http://etherx.jabber.org/streams");
xmlnode_put_attrib(x, "id", id);
if(namespace != NULL)
xmlnode_put_attrib(x, "xmlns", namespace);
if(to != NULL)
xmlnode_put_attrib(x, "to", to);
if(from != NULL)
xmlnode_put_attrib(x, "from", from);
return x;
}
char *xstream_header_char(xmlnode x)
{
spool s;
char *fixr, *head;
if(xmlnode_has_children(x))
{
fprintf(stderr,"Fatal Programming Error: xstream_header_char() was sent a header with children!\n");
return NULL;
}
s = spool_new(xmlnode_pool(x));
spooler(s,"<?xml version='1.0'?>",xmlnode2str(x),s);
head = spool_print(s);
fixr = strstr(head,"/>");
*fixr = '>';
++fixr;
*fixr = '\0';
return head;
}