#include "util.h"
#ifdef HAVE_EXPAT
#include "expat/expat.h"
#endif
#ifdef NAD_DEBUG
static xht _nad_alloc_tracked = NULL;
static xht _nad_free_tracked = NULL;
static void _nad_ptr_check(const char *func, nad_t nad) {
char loc[24];
snprintf(loc, sizeof(loc), "%x", (int) nad);
if(xhash_get(_nad_alloc_tracked, loc) == NULL) {
fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad);
abort();
}
if(xhash_get(_nad_free_tracked, loc) != NULL) {
fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad);
abort();
}
fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad);
}
#else
#define _nad_ptr_check(func,nad)
#endif
#define BLOCKSIZE 1024
int _nad_realloc(void **oblocks, int len)
{
void *nblocks;
int nlen;
nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1);
*oblocks = nblocks;
return nlen;
}
#define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size));
int _nad_cdata(nad_t nad, const char *cdata, int len)
{
NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
memcpy(nad->cdata + nad->ccur, cdata, len);
nad->ccur += len;
return nad->ccur - len;
}
int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
{
int attr;
NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen);
attr = nad->acur;
nad->acur++;
nad->attrs[attr].next = nad->elems[elem].attr;
nad->elems[elem].attr = attr;
nad->attrs[attr].lname = strlen(name);
nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname);
if(vallen > 0)
nad->attrs[attr].lval = vallen;
else
nad->attrs[attr].lval = strlen(val);
nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
nad->attrs[attr].my_ns = ns;
return attr;
}
nad_cache_t nad_cache_new(void)
{
nad_cache_t cache;
while((cache = malloc(sizeof(nad_cache_t))) == NULL) sleep(1);
*cache = NULL;
#ifdef NAD_DEBUG
if(_nad_alloc_tracked == NULL) _nad_alloc_tracked = xhash_new(501);
if(_nad_free_tracked == NULL) _nad_free_tracked = xhash_new(501);
#endif
return cache;
}
void nad_cache_free(nad_cache_t cache)
{
nad_t cur;
while((cur = *cache) != NULL)
{
*cache = cur->next;
free(cur->elems);
free(cur->attrs);
free(cur->nss);
free(cur->cdata);
free(cur->depths);
free(cur);
}
free(cache);
}
nad_t nad_new(nad_cache_t cache)
{
nad_t nad;
#ifndef NAD_DEBUG
if ((cache!=NULL) && (*cache != NULL))
{
nad = *cache;
*cache = nad->next;
nad->ccur = nad->ecur = nad->acur = nad->ncur = 0;
nad->scope = -1;
nad->cache = cache;
nad->next = NULL;
return nad;
}
#endif
while((nad = malloc(sizeof(struct nad_st))) == NULL) sleep(1);
memset(nad,0,sizeof(struct nad_st));
nad->scope = -1;
nad->cache = cache;
#ifdef NAD_DEBUG
{
char loc[24];
snprintf(loc, sizeof(loc), "%x", (int) nad);
xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1);
}
_nad_ptr_check(__func__, nad);
#endif
return nad;
}
nad_t nad_copy(nad_t nad)
{
nad_t copy;
_nad_ptr_check(__func__, nad);
if(nad == NULL) return NULL;
copy = nad_new(NULL);
NAD_SAFE(copy->elems, nad->elen, copy->elen);
NAD_SAFE(copy->attrs, nad->alen, copy->alen);
NAD_SAFE(copy->nss, nad->nlen, copy->nlen);
NAD_SAFE(copy->cdata, nad->clen, copy->clen);
memcpy(copy->elems, nad->elems, nad->elen);
memcpy(copy->attrs, nad->attrs, nad->alen);
memcpy(copy->nss, nad->nss, nad->nlen);
memcpy(copy->cdata, nad->cdata, nad->clen);
copy->ecur = nad->ecur;
copy->acur = nad->acur;
copy->ncur = nad->ncur;
copy->ccur = nad->ccur;
copy->scope = nad->scope;
return copy;
}
void nad_free(nad_t nad)
{
if(nad == NULL) return;
#ifdef NAD_DEBUG
_nad_ptr_check(__func__, nad);
{
char loc[24];
snprintf(loc, sizeof(loc), "%x", (int) nad);
xhash_zap(_nad_alloc_tracked, loc);
xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad);
}
#else
if (nad->cache != NULL) {
nad->next = *(nad->cache);
*(nad->cache) = nad;
return;
}
#endif
free(nad->elems);
free(nad->attrs);
free(nad->cdata);
free(nad->nss);
free(nad->depths);
#ifndef NAD_DEBUG
free(nad);
#endif
}
int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth)
{
int my_ns;
int lname = 0;
_nad_ptr_check(__func__, nad);
if(elem >= nad->ecur || name == NULL) return -1;
depth = nad->elems[elem].depth + depth;
if(name != NULL) lname = strlen(name);
for(elem++;elem < nad->ecur;elem++)
{
if(nad->elems[elem].depth < depth)
return -1;
if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) &&
(ns < 0 || ((my_ns = nad->elems[elem].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0)))
return elem;
}
return -1;
}
int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
{
int attr, my_ns;
int lname, lval = 0;
_nad_ptr_check(__func__, nad);
if(elem >= nad->ecur || name == NULL) return -1;
attr = nad->elems[elem].attr;
lname = strlen(name);
if(val != NULL) lval = strlen(val);
while(attr >= 0)
{
if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 &&
(lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) &&
(ns < 0 || ((my_ns = nad->attrs[attr].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0)))
return attr;
attr = nad->attrs[attr].next;
}
return -1;
}
int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix)
{
int check, ns;
_nad_ptr_check(__func__, nad);
if(uri == NULL)
return -1;
check = elem;
while(check >= 0)
{
ns = nad->elems[check].ns;
while(ns >= 0)
{
if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
return ns;
ns = nad->nss[ns].next;
}
check = nad->elems[check].parent;
}
return -1;
}
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
{
int ns;
_nad_ptr_check(__func__, nad);
if(uri == NULL)
return -1;
for(ns = 0; ns < nad->ncur; ns++)
{
if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 &&
(prefix == NULL ||
(nad->nss[ns].iprefix >= 0 &&
strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0)))
return ns;
}
return -1;
}
void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
{
int attr;
_nad_ptr_check(__func__, nad);
if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0)
{
if(val != NULL)
_nad_attr(nad, elem, ns, name, val, vallen);
return;
}
if(val == NULL)
{
nad->attrs[attr].lval = nad->attrs[attr].lname = 0;
}else{
if(vallen > 0)
nad->attrs[attr].lval = vallen;
else
nad->attrs[attr].lval = strlen(val);
nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval);
}
}
int nad_insert_elem(nad_t nad, int parent, int ns, const char *name, const char *cdata)
{
int elem = parent + 1;
_nad_ptr_check(__func__, nad);
NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
if(nad->ecur != elem)
memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
nad->ecur++;
nad->elems[elem].parent = parent;
nad->elems[elem].lname = strlen(name);
nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
nad->elems[elem].attr = -1;
nad->elems[elem].ns = nad->scope; nad->scope = -1;
nad->elems[elem].itail = nad->elems[elem].ltail = 0;
nad->elems[elem].my_ns = ns;
if(cdata != NULL)
{
nad->elems[elem].lcdata = strlen(cdata);
nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata);
}else{
nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
}
nad->elems[elem].depth = nad->elems[parent].depth + 1;
return elem;
}
void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name)
{
int cur;
_nad_ptr_check(__func__, nad);
if(elem >= nad->ecur) return;
NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st));
nad->ecur++;
nad->elems[elem].lname = strlen(name);
nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
nad->elems[elem].attr = -1;
nad->elems[elem].ns = nad->scope; nad->scope = -1;
nad->elems[elem].itail = nad->elems[elem].ltail = 0;
nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
nad->elems[elem].my_ns = ns;
nad->elems[elem+1].depth++;
for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++;
nad->elems[elem].parent = nad->elems[elem + 1].parent;
nad->elems[elem + 1].parent = elem;
}
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
{
int elem;
_nad_ptr_check(__func__, nad);
NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen);
elem = nad->ecur;
nad->ecur++;
nad->elems[elem].lname = strlen(name);
nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname);
nad->elems[elem].icdata = nad->elems[elem].lcdata = 0;
nad->elems[elem].itail = nad->elems[elem].ltail = 0;
nad->elems[elem].attr = -1;
nad->elems[elem].ns = nad->scope; nad->scope = -1;
nad->elems[elem].depth = depth;
nad->elems[elem].my_ns = ns;
NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen);
nad->depths[depth] = elem;
if(depth <= 0)
nad->elems[elem].parent = -1;
else
nad->elems[elem].parent = nad->depths[depth - 1];
return elem;
}
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
{
_nad_ptr_check(__func__, nad);
return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0);
}
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
{
int elem = nad->ecur - 1;
_nad_ptr_check(__func__, nad);
if(nad->elems[elem].depth == depth - 1)
{
if(nad->elems[elem].icdata == 0)
nad->elems[elem].icdata = nad->ccur;
_nad_cdata(nad,cdata,len);
nad->elems[elem].lcdata += len;
return;
}
elem = nad->depths[depth];
if(nad->elems[elem].itail == 0)
nad->elems[elem].itail = nad->ccur;
_nad_cdata(nad,cdata,len);
nad->elems[elem].ltail += len;
}
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
{
int ns;
_nad_ptr_check(__func__, nad);
ns = nad_find_scoped_namespace(nad, uri, NULL);
if(ns >= 0)
return ns;
NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
ns = nad->ncur;
nad->ncur++;
nad->nss[ns].next = nad->scope;
nad->scope = ns;
nad->nss[ns].luri = strlen(uri);
nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
if(prefix != NULL)
{
nad->nss[ns].lprefix = strlen(prefix);
nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
}
else
nad->nss[ns].iprefix = -1;
return ns;
}
int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix) {
int ns;
_nad_ptr_check(__func__, nad);
ns = nad_find_namespace(nad, elem, uri, NULL);
if(ns >= 0)
return ns;
NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen);
ns = nad->ncur;
nad->ncur++;
nad->nss[ns].next = nad->elems[elem].ns;
nad->elems[elem].ns = ns;
nad->nss[ns].luri = strlen(uri);
nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri);
if(prefix != NULL)
{
nad->nss[ns].lprefix = strlen(prefix);
nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix);
}
else
nad->nss[ns].iprefix = -1;
return ns;
}
void _nad_escape(nad_t nad, int data, int len, int flag)
{
char *c;
int ic;
if(len <= 0) return;
while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
{
ic = c - nad->cdata;
_nad_escape(nad, data, ic - data, 2);
NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
memcpy(nad->cdata + nad->ccur, "'", 6);
nad->ccur += 6;
len -= (ic+1) - data;
data = ic+1;
}
while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
{
ic = c - nad->cdata;
_nad_escape(nad, data, ic - data, 1);
NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
memcpy(nad->cdata + nad->ccur, "<", 4);
nad->ccur += 4;
len -= (ic+1) - data;
data = ic+1;
}
while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
{
ic = c - nad->cdata;
_nad_escape(nad, data, ic - data, 0);
NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
memcpy(nad->cdata + nad->ccur, ">", 4);
nad->ccur += 4;
len -= (ic+1) - data;
data = ic+1;
}
while((c = memchr(nad->cdata + data,'&',len)) != NULL)
{
ic = c - nad->cdata;
NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);
memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
nad->ccur += (ic - data);
memcpy(nad->cdata + nad->ccur, "&", 5);
nad->ccur += 5;
len -= (ic+1) - data;
data = ic+1;
}
if(len > 0) {
NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
nad->ccur += len;
}
}
int _nad_lp0(nad_t nad, int elem)
{
int attr;
int ndepth;
int ns;
while(elem != nad->ecur)
{
ns = nad->elems[elem].my_ns;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen);
} else {
NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen);
}
*(nad->cdata + nad->ccur++) = '<';
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
nad->ccur += nad->nss[ns].lprefix;
*(nad->cdata + nad->ccur++) = ':';
}
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
nad->ccur += nad->elems[elem].lname;
for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next)
{
if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0)
continue;
if(nad->nss[ns].iprefix >= 0)
{
NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
} else {
NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
}
memcpy(nad->cdata + nad->ccur, " xmlns", 6);
nad->ccur += 6;
if(nad->nss[ns].iprefix >= 0)
{
*(nad->cdata + nad->ccur++) = ':';
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
nad->ccur += nad->nss[ns].lprefix;
}
*(nad->cdata + nad->ccur++) = '=';
*(nad->cdata + nad->ccur++) = '\'';
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
nad->ccur += nad->nss[ns].luri;
*(nad->cdata + nad->ccur++) = '\'';
}
for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next)
{
if(nad->attrs[attr].lname <= 0) continue;
ns = nad->attrs[attr].my_ns;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen);
} else {
NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen);
}
*(nad->cdata + nad->ccur++) = ' ';
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
nad->ccur += nad->nss[ns].lprefix;
*(nad->cdata + nad->ccur++) = ':';
}
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname);
nad->ccur += nad->attrs[attr].lname;
*(nad->cdata + nad->ccur++) = '=';
*(nad->cdata + nad->ccur++) = '\'';
_nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 3);
NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
*(nad->cdata + nad->ccur++) = '\'';
}
if(elem+1 == nad->ecur)
ndepth = -1;
else
ndepth = nad->elems[elem+1].depth;
if(ndepth <= nad->elems[elem].depth)
{
NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen);
if(nad->elems[elem].lcdata == 0)
{
memcpy(nad->cdata + nad->ccur, "/>", 2);
nad->ccur += 2;
}else{
*(nad->cdata + nad->ccur++) = '>';
_nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,2);
ns = nad->elems[elem].my_ns;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
} else {
NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
}
memcpy(nad->cdata + nad->ccur, "</", 2);
nad->ccur += 2;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
nad->ccur += nad->nss[ns].lprefix;
*(nad->cdata + nad->ccur++) = ':';
}
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
nad->ccur += nad->elems[elem].lname;
*(nad->cdata + nad->ccur++) = '>';
}
_nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,2);
if(ndepth < nad->elems[elem].depth)
return elem+1;
elem++;
}else{
int nelem;
NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
*(nad->cdata + nad->ccur++) = '>';
_nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,2);
nelem = _nad_lp0(nad,elem+1);
ns = nad->elems[elem].my_ns;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
} else {
NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
}
memcpy(nad->cdata + nad->ccur, "</", 2);
nad->ccur += 2;
if(ns >= 0 && nad->nss[ns].iprefix >= 0)
{
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
nad->ccur += nad->nss[ns].lprefix;
*(nad->cdata + nad->ccur++) = ':';
}
memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
nad->ccur += nad->elems[elem].lname;
*(nad->cdata + nad->ccur++) = '>';
_nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,2);
if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth)
return nelem;
elem = nelem;
}
}
return elem;
}
void nad_print(nad_t nad, int elem, char **xml, int *len)
{
int ixml = nad->ccur;
_nad_ptr_check(__func__, nad);
_nad_lp0(nad,elem);
*len = nad->ccur - ixml;
*xml = nad->cdata + ixml;
}
void nad_serialize(nad_t nad, char **buf, int *len) {
char *pos;
_nad_ptr_check(__func__, nad);
*len = sizeof(int) * 5 +
sizeof(struct nad_elem_st) * nad->ecur +
sizeof(struct nad_attr_st) * nad->acur +
sizeof(struct nad_ns_st) * nad->ncur +
sizeof(char) * nad->ccur;
*buf = (char *) malloc(*len);
pos = *buf;
* (int *) pos = *len; pos += sizeof(int);
* (int *) pos = nad->ecur; pos += sizeof(int);
* (int *) pos = nad->acur; pos += sizeof(int);
* (int *) pos = nad->ncur; pos += sizeof(int);
* (int *) pos = nad->ccur; pos += sizeof(int);
memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur;
memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur;
memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur;
memcpy(pos, nad->cdata, sizeof(char) * nad->ccur);
}
nad_t nad_deserialize(nad_cache_t cache, const char *buf) {
nad_t nad = nad_new(cache);
const char *pos = buf + sizeof(int);
_nad_ptr_check(__func__, nad);
nad->ecur = * (int *) pos; pos += sizeof(int);
nad->acur = * (int *) pos; pos += sizeof(int);
nad->ncur = * (int *) pos; pos += sizeof(int);
nad->ccur = * (int *) pos; pos += sizeof(int);
nad->elen = nad->ecur;
nad->alen = nad->acur;
nad->nlen = nad->ncur;
nad->clen = nad->ccur;
if(nad->ecur > 0)
{
nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur);
memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur);
pos += sizeof(struct nad_elem_st) * nad->ecur;
}
if(nad->acur > 0)
{
nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur);
memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur);
pos += sizeof(struct nad_attr_st) * nad->acur;
}
if(nad->ncur > 0)
{
nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur);
memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur);
pos += sizeof(struct nad_ns_st) * nad->ncur;
}
if(nad->ccur > 0)
{
nad->cdata = (char *) malloc(sizeof(char) * nad->ccur);
memcpy(nad->cdata, pos, sizeof(char) * nad->ccur);
}
return nad;
}
#ifdef HAVE_EXPAT
struct build_data {
nad_t nad;
int depth;
};
static void _nad_parse_element_start(void *arg, const char *name, const char **atts) {
struct build_data *bd = (struct build_data *) arg;
char buf[1024];
char *uri, *elem, *prefix;
const char **attr;
int ns;
strncpy(buf, name, 1024);
buf[1023] = '\0';
uri = buf;
elem = strchr(uri, '|');
if(elem != NULL) {
*elem = '\0';
elem++;
prefix = strchr(elem, '|');
if(prefix != NULL) {
*prefix = '\0';
prefix++;
}
ns = nad_add_namespace(bd->nad, uri, prefix);
} else {
uri = NULL;
elem = buf;
prefix = NULL;
ns = -1;
}
nad_append_elem(bd->nad, ns, elem, bd->depth);
attr = atts;
while(attr[0] != NULL) {
strncpy(buf, attr[0], 1024);
buf[1023] = '\0';
uri = buf;
elem = strchr(uri, '|');
if(elem != NULL) {
*elem = '\0';
elem++;
prefix = strchr(elem, '|');
if(prefix != NULL) {
*prefix = '\0';
prefix++;
}
ns = nad_add_namespace(bd->nad, uri, prefix);
} else {
uri = NULL;
elem = buf;
prefix = NULL;
ns = -1;
}
nad_append_attr(bd->nad, ns, elem, (char *) attr[1]);
attr += 2;
}
bd->depth++;
}
static void _nad_parse_element_end(void *arg, const char *name) {
struct build_data *bd = (struct build_data *) arg;
bd->depth--;
}
static void _nad_parse_cdata(void *arg, const char *str, int len) {
struct build_data *bd = (struct build_data *) arg;
nad_append_cdata(bd->nad, (char *) str, len, bd->depth);
}
static void _nad_parse_namespace_start(void *arg, const char *prefix, const char *uri) {
struct build_data *bd = (struct build_data *) arg;
int ns;
ns = nad_add_namespace(bd->nad, (char *) uri, (char *) prefix);
bd->nad->scope = ns;
}
nad_t nad_parse(nad_cache_t cache, const char *buf, int len) {
struct build_data bd;
XML_Parser p;
if(len == 0)
len = strlen(buf);
p = XML_ParserCreateNS(NULL, '|');
if(p == NULL)
return NULL;
XML_SetReturnNSTriplet(p, 1);
bd.nad = nad_new(cache);
bd.depth = 0;
XML_SetUserData(p, (void *) &bd);
XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
XML_SetCharacterDataHandler(p, _nad_parse_cdata);
XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);
if(!XML_Parse(p, buf, len, 1)) {
XML_ParserFree(p);
nad_free(bd.nad);
return NULL;
}
XML_ParserFree(p);
if(bd.depth != 0)
return NULL;
return bd.nad;
}
#endif