mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-25 05:11:35 +00:00
27a59a0cbc
vulkan, wasapi, quake injector features added. irc, avplug, cef plugins/drivers reworked/updated/added openal reverb, doppler effects added. 'dir' console command now attempts to view clicked files. lots of warning fixes, should now only be deprecation warnings for most targets (depending on compiler version anyway...). SendEntity finally reworked to use flags properly. effectinfo improved, other smc-targetted fixes. mapcluster stuff now has support for linux. .basebone+.baseframe now exist in ssqc. qcc: -Fqccx supports qccx syntax, including qccx hacks. don't expect these to work in fteqw nor dp though. qcc: rewrote function call handling to use refs rather than defs. this makes struct passing more efficient and makes the __out keyword usable with fields etc. qccgui: can cope a little better with non-unicode files. can now represent most quake chars. qcc: suppressed warnings from *extensions.qc git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5000 fc73d0e0-1445-4013-8a0c-d673dee63da5
760 lines
14 KiB
C
760 lines
14 KiB
C
#include "../plugin.h"
|
|
|
|
#include "xml.h"
|
|
|
|
//fixme
|
|
void (*Con_TrySubPrint)(const char *conname, const char *message);
|
|
|
|
void XML_Destroy(xmltree_t *t);
|
|
|
|
char *XML_GetParameter(xmltree_t *t, char *paramname, char *def)
|
|
{
|
|
xmlparams_t *p;
|
|
if (t)
|
|
{
|
|
for (p = t->params; p; p = p->next)
|
|
if (!strcmp(p->name, paramname))
|
|
return p->val;
|
|
}
|
|
return def;
|
|
}
|
|
void XML_AddParameter(xmltree_t *t, char *paramname, char *value)
|
|
{
|
|
xmlparams_t *p = malloc(sizeof(xmlparams_t));
|
|
Q_strlcpy(p->name, paramname, sizeof(p->name));
|
|
Q_strlcpy(p->val, value, sizeof(p->val));
|
|
|
|
if (t->params) //reverse insert
|
|
{
|
|
xmlparams_t *prev;
|
|
for(prev = t->params; prev->next; prev = prev->next)
|
|
;
|
|
prev->next = p;
|
|
p->next = NULL;
|
|
}
|
|
else
|
|
{
|
|
p->next = t->params;
|
|
t->params = p;
|
|
}
|
|
}
|
|
void XML_AddParameteri(xmltree_t *t, char *paramname, int value)
|
|
{
|
|
char svalue[64];
|
|
Q_snprintf(svalue, sizeof(svalue), "%i", value);
|
|
XML_AddParameter(t, paramname, svalue);
|
|
}
|
|
xmltree_t *XML_CreateNode(xmltree_t *parent, char *name, char *xmlns, char *body)
|
|
{
|
|
int bodylen = strlen(body);
|
|
struct subtree_s *node = malloc(sizeof(*node));
|
|
|
|
//clear out links
|
|
node->params = NULL;
|
|
node->child = NULL;
|
|
node->sibling = NULL;
|
|
//link into parent if we actually have a parent.
|
|
if (parent)
|
|
{
|
|
if (parent->child)
|
|
{ //add at tail
|
|
xmltree_t *prev;
|
|
for(prev = parent->child; prev->sibling; prev = prev->sibling)
|
|
;
|
|
prev->sibling = node;
|
|
node->sibling = NULL;
|
|
}
|
|
else
|
|
{
|
|
node->sibling = parent->child;
|
|
parent->child = node;
|
|
}
|
|
}
|
|
|
|
Q_strlcpy(node->name, name, sizeof(node->name));
|
|
Q_strlcpy(node->xmlns, xmlns, sizeof(node->xmlns));
|
|
Q_strlcpy(node->xmlns_dflt, xmlns, sizeof(node->xmlns_dflt));
|
|
node->body = malloc(bodylen+1);
|
|
memcpy(node->body, body, bodylen+1);
|
|
|
|
if (*xmlns)
|
|
XML_AddParameter(node, "xmlns", xmlns);
|
|
|
|
return node;
|
|
}
|
|
|
|
const struct
|
|
{
|
|
int codelen;
|
|
char *code;
|
|
int namelen;
|
|
char *name;
|
|
} xmlchars[] =
|
|
{
|
|
{1, "<", 2, "lt"},
|
|
{1, ">", 2, "gt"},
|
|
{1, "&", 3, "amp"},
|
|
{1, "\'", 4, "apos"},
|
|
{1, "\"", 4, "quot"},
|
|
{2, "\xC3\x96", 4, "ouml"},
|
|
{0, NULL, 0, NULL}
|
|
};
|
|
//converts < to < etc.
|
|
//returns the end of d.
|
|
char *XML_Markup(char *s, char *d, int dlen)
|
|
{
|
|
int i;
|
|
dlen--;
|
|
while(*s)
|
|
{
|
|
for(i = 0; xmlchars[i].code; i++)
|
|
{
|
|
if (!strncmp(s, xmlchars[i].code, xmlchars[i].codelen))
|
|
break;
|
|
}
|
|
if (xmlchars[i].code)
|
|
{
|
|
if (dlen < xmlchars[i].namelen+2)
|
|
break;
|
|
*d++ = '&';
|
|
memcpy(d, xmlchars[i].name, xmlchars[i].namelen);
|
|
d+=xmlchars[i].namelen;
|
|
*d++ = ';';
|
|
s+=xmlchars[i].codelen;
|
|
dlen -= xmlchars[i].namelen+2;
|
|
}
|
|
else
|
|
{
|
|
if (!dlen)
|
|
break;
|
|
dlen--;
|
|
*d++ = *s++;
|
|
}
|
|
}
|
|
*d = 0;
|
|
return d;
|
|
}
|
|
//inplace. result will always be same length or shorter.
|
|
//converts < etc to their original chars
|
|
void XML_Unmark(char *s)
|
|
{
|
|
char *d;
|
|
int i;
|
|
|
|
for (d = s; *s; )
|
|
{
|
|
if (*s == '&')
|
|
{
|
|
s++;
|
|
for (i = 0; xmlchars[i].name; i++)
|
|
{
|
|
if (!strncmp(s, xmlchars[i].name, xmlchars[i].namelen) && s[xmlchars[i].namelen] == ';')
|
|
break;
|
|
}
|
|
if (xmlchars[i].name)
|
|
{
|
|
s += xmlchars[i].namelen+1;
|
|
|
|
memcpy(d, xmlchars[i].code, xmlchars[i].codelen);
|
|
d+=xmlchars[i].codelen;
|
|
}
|
|
else
|
|
{
|
|
*d++ = '&';
|
|
}
|
|
}
|
|
else
|
|
*d++ = *s++;
|
|
}
|
|
*d = 0;
|
|
}
|
|
|
|
struct buf_ctx
|
|
{
|
|
char *buf;
|
|
int len;
|
|
int maxlen;
|
|
};
|
|
static void buf_cat(struct buf_ctx *buf, char *data, int datalen)
|
|
{
|
|
int newlen = buf->len + datalen+1;
|
|
if (newlen > buf->maxlen)
|
|
{
|
|
char *newd;
|
|
newlen *= 2;
|
|
newd = malloc(newlen);
|
|
memcpy(newd, buf->buf, buf->len);
|
|
free(buf->buf);
|
|
buf->buf = newd;
|
|
buf->maxlen = newlen;
|
|
}
|
|
|
|
memcpy(buf->buf + buf->len, data, datalen);
|
|
buf->len += datalen;
|
|
}
|
|
static void XML_DumpToBuf(struct buf_ctx *buf, xmltree_t *t, int indent)
|
|
{
|
|
xmltree_t *c;
|
|
xmlparams_t *p;
|
|
int i;
|
|
for (i = 0; i < indent; i++)
|
|
buf_cat(buf, " ", 1);
|
|
|
|
buf_cat(buf, "<", 1);
|
|
buf_cat(buf, t->name, strlen(t->name));
|
|
|
|
for (p = t->params; p; p = p->next)
|
|
{
|
|
buf_cat(buf, " ", 1);
|
|
buf_cat(buf, p->name, strlen(p->name));
|
|
buf_cat(buf, "=\'", 2);
|
|
buf_cat(buf, p->val, strlen(p->val));
|
|
buf_cat(buf, "\'", 1);
|
|
}
|
|
|
|
if (t->child)
|
|
{
|
|
buf_cat(buf, ">", 1);
|
|
if (indent>=0)
|
|
buf_cat(buf, "\n", 1);
|
|
for (c = t->child; c; c = c->sibling)
|
|
XML_DumpToBuf(buf, c, ((indent<0)?indent:(indent+2)));
|
|
for (i = 0; i < indent; i++)
|
|
buf_cat(buf, " ", 1);
|
|
buf_cat(buf, "</", 2);
|
|
buf_cat(buf, t->name, strlen(t->name));
|
|
buf_cat(buf, ">", 1);
|
|
}
|
|
else if (*t->body)
|
|
{
|
|
buf_cat(buf, ">", 1);
|
|
buf_cat(buf, t->body, strlen(t->body));
|
|
buf_cat(buf, "</", 2);
|
|
buf_cat(buf, t->name, strlen(t->name));
|
|
buf_cat(buf, ">", 1);
|
|
}
|
|
else
|
|
{
|
|
buf_cat(buf, "/>", 2);
|
|
}
|
|
if (indent>=0)
|
|
buf_cat(buf, "\n", 1);
|
|
}
|
|
|
|
char *XML_GenerateString(xmltree_t *root, qboolean readable)
|
|
{
|
|
struct buf_ctx buf = {NULL, 0, 0};
|
|
XML_DumpToBuf(&buf, root, readable?0:-1);
|
|
buf_cat(&buf, "", 1);
|
|
return buf.buf;
|
|
}
|
|
xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronly, char *defaultnamespace)
|
|
{
|
|
xmlparams_t *p;
|
|
xmltree_t *child;
|
|
xmltree_t **childlink; //to add at end, retaining order
|
|
xmltree_t *ret;
|
|
int bodypos;
|
|
int bodymax = 0;
|
|
int pos, i;
|
|
char *tagend;
|
|
char *tagstart;
|
|
char *ns;
|
|
char token[1024];
|
|
pos = *startpos;
|
|
while (buffer[pos] >= '\0' && buffer[pos] <= ' ')
|
|
{
|
|
if (pos >= maxpos)
|
|
break;
|
|
pos++;
|
|
}
|
|
|
|
if (pos == maxpos)
|
|
{
|
|
*startpos = pos;
|
|
return NULL; //nothing anyway.
|
|
}
|
|
|
|
skippedcomment:
|
|
|
|
//expect a <
|
|
|
|
if (buffer[pos] != '<')
|
|
{
|
|
Con_Printf("Missing open bracket\n");
|
|
return NULL; //should never happen
|
|
}
|
|
|
|
if (buffer[pos+1] == '/')
|
|
{
|
|
Con_Printf("Unexpected close tag.\n");
|
|
return NULL; //err, terminating a parent tag
|
|
}
|
|
|
|
if (pos+4 < maxpos && buffer[pos+1] == '!' && buffer[pos+2] == '-' && buffer[pos+3] == '-')
|
|
{
|
|
//this looks like a comment. scan forwards until we find the -->
|
|
pos += 4;
|
|
while (pos+3 < maxpos)
|
|
{
|
|
if (buffer[pos+0] == '-' && buffer[pos+1] == '-' && buffer[pos+2] == '>')
|
|
{
|
|
pos+=3;
|
|
goto skippedcomment;
|
|
}
|
|
pos++;
|
|
}
|
|
Con_Printf("Missing comment end\n");
|
|
return NULL; //should never happen
|
|
}
|
|
|
|
tagend = strchr(buffer+pos, '>');
|
|
if (!tagend)
|
|
{
|
|
Con_Printf("Missing close bracket\n");
|
|
return NULL; //should never happen
|
|
}
|
|
*tagend = '\0';
|
|
tagend++;
|
|
|
|
//assume no nulls in the tag header.
|
|
tagstart = buffer+pos+1;
|
|
while (*tagstart == ' ' || *tagstart == '\n' || *tagstart == '\r' || *tagstart == '\t')
|
|
tagstart++;
|
|
for (i = 0; i < sizeof(token)-1 && *tagstart; )
|
|
{
|
|
if (*tagstart == ' ' || (i&&*tagstart == '/') || (i&&*tagstart == '?') || *tagstart == '\n' || *tagstart == '\r' || *tagstart == '\t')
|
|
break;
|
|
token[i++] = *tagstart++;
|
|
}
|
|
token[i] = 0;
|
|
|
|
pos = tagend - buffer;
|
|
|
|
ret = malloc(sizeof(xmltree_t));
|
|
memset(ret, 0, sizeof(*ret));
|
|
|
|
ns = strchr(token, ':');
|
|
if (ns)
|
|
{
|
|
*ns = 0;
|
|
ns++;
|
|
|
|
memcpy(ret->xmlns, "xmlns:", 6);
|
|
Q_strlcpy(ret->xmlns+6, token, sizeof(ret->xmlns)-6);
|
|
Q_strlcpy(ret->name, ns, sizeof(ret->name));
|
|
}
|
|
else
|
|
{
|
|
Q_strlcpy(ret->xmlns, "xmlns", sizeof(ret->xmlns));
|
|
Q_strlcpy(ret->name, token, sizeof(ret->name));
|
|
}
|
|
|
|
while(*tagstart)
|
|
{
|
|
int nlen;
|
|
|
|
|
|
while(*(unsigned char*)tagstart <= ' ' && *tagstart)
|
|
tagstart++; //skip whitespace (note that we know there is a null terminator before the end of the buffer)
|
|
|
|
if (!*tagstart)
|
|
break;
|
|
|
|
p = malloc(sizeof(xmlparams_t));
|
|
nlen = 0;
|
|
while (nlen < sizeof(p->name)-2)
|
|
{
|
|
if (*(unsigned char*)tagstart <= ' ' || *tagstart == '/' || *tagstart == '?')
|
|
break;
|
|
|
|
if (*tagstart == '=')
|
|
break;
|
|
p->name[nlen++] = *tagstart++;
|
|
}
|
|
p->name[nlen++] = '\0';
|
|
|
|
while(*(unsigned char*)tagstart <= ' ' && *tagstart)
|
|
tagstart++; //skip whitespace (note that we know there is a null terminator before the end of the buffer)
|
|
|
|
if (*tagstart != '=')
|
|
break;
|
|
tagstart++;
|
|
|
|
while(*(unsigned char*)tagstart <= ' ' && *tagstart)
|
|
tagstart++; //skip whitespace (note that we know there is a null terminator before the end of the buffer)
|
|
|
|
nlen = 0;
|
|
if (*tagstart == '\'')
|
|
{
|
|
tagstart++;
|
|
while (*tagstart && nlen < sizeof(p->name)-2)
|
|
{
|
|
if(*tagstart == '\'')
|
|
break;
|
|
|
|
p->val[nlen++] = *tagstart++;
|
|
}
|
|
tagstart++;
|
|
p->val[nlen++] = '\0';
|
|
}
|
|
else if (*tagstart == '\"')
|
|
{
|
|
tagstart++;
|
|
while (*tagstart && nlen < sizeof(p->name)-2)
|
|
{
|
|
if(*tagstart == '\"')
|
|
break;
|
|
|
|
p->val[nlen++] = *tagstart++;
|
|
}
|
|
tagstart++;
|
|
p->val[nlen++] = '\0';
|
|
}
|
|
else
|
|
{
|
|
while (*tagstart && nlen < sizeof(p->name)-2)
|
|
{
|
|
if(*tagstart <= ' ')
|
|
break;
|
|
|
|
p->val[nlen++] = *tagstart++;
|
|
}
|
|
p->val[nlen++] = '\0';
|
|
}
|
|
XML_Unmark(p->val);
|
|
p->next = ret->params;
|
|
ret->params = p;
|
|
}
|
|
|
|
ns = XML_GetParameter(ret, ret->xmlns, "");
|
|
Q_strlcpy(ret->xmlns, ns, sizeof(ret->xmlns));
|
|
|
|
ns = XML_GetParameter(ret, "xmlns", NULL);
|
|
Q_strlcpy(ret->xmlns_dflt, ns?ns:defaultnamespace, sizeof(ret->xmlns_dflt));
|
|
|
|
tagend[-1] = '>';
|
|
|
|
if (tagend[-2] == '/')
|
|
{ //no body
|
|
ret->body = malloc(1);
|
|
*ret->body = 0;
|
|
*startpos = pos;
|
|
return ret;
|
|
}
|
|
if (ret->name[0] == '?')
|
|
{
|
|
//no body either
|
|
if (tagend[-2] == '?')
|
|
{
|
|
ret->body = malloc(1);
|
|
*ret->body = 0;
|
|
*startpos = pos;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (headeronly)
|
|
{
|
|
*startpos = pos;
|
|
return ret;
|
|
}
|
|
|
|
//does it have a body, or is it child tags?
|
|
|
|
childlink = &ret->child;
|
|
bodypos = 0;
|
|
while(1)
|
|
{
|
|
if (pos == maxpos)
|
|
{ //malformed
|
|
Con_Printf("tree is malfored\n");
|
|
XML_Destroy(ret);
|
|
return NULL;
|
|
}
|
|
|
|
if (buffer[pos] == '<')
|
|
{
|
|
if (buffer[pos+1] == '/')
|
|
{ //the end of this block
|
|
//FIXME: check name
|
|
|
|
tagend = strchr(buffer+pos, '>');
|
|
if (!tagend)
|
|
{
|
|
Con_Printf("No close tag\n");
|
|
XML_Destroy(ret);
|
|
return NULL; //should never happen
|
|
}
|
|
tagend++;
|
|
pos = tagend - buffer;
|
|
break;
|
|
}
|
|
|
|
if (!strncmp(&buffer[pos], "<![CDATA[", 9))
|
|
{
|
|
pos += 9;
|
|
while(1)
|
|
{
|
|
char c;
|
|
if (pos == maxpos)
|
|
{ //malformed
|
|
Con_Printf("CDATA is malfored (inside %s)\n", ret->name);
|
|
XML_Destroy(ret);
|
|
return NULL;
|
|
}
|
|
|
|
if (buffer[pos+0] == ']' && buffer[pos+1] == ']' && buffer[pos+2] == '>')
|
|
{
|
|
pos += 3;
|
|
break;
|
|
}
|
|
|
|
c = buffer[pos++];
|
|
if (bodypos == bodymax)
|
|
{
|
|
int nlen = bodypos*2 + 64;
|
|
char *nb = malloc(nlen);
|
|
memcpy(nb, ret->body, bodypos);
|
|
free(ret->body);
|
|
ret->body = nb;
|
|
bodymax = nlen;
|
|
}
|
|
ret->body[bodypos++] = c;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
child = XML_Parse(buffer, &pos, maxpos, false, ret->xmlns_dflt);
|
|
if (!child)
|
|
{
|
|
Con_Printf("Child block is unparsable (within %s)\n", ret->name);
|
|
XML_Destroy(ret);
|
|
return NULL;
|
|
}
|
|
|
|
child->sibling = *childlink;
|
|
*childlink = child;
|
|
childlink = &child->sibling;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char c = buffer[pos++];
|
|
if (bodypos == bodymax)
|
|
{
|
|
int nlen = bodypos*2 + 64;
|
|
char *nb = malloc(nlen);
|
|
memcpy(nb, ret->body, bodypos);
|
|
free(ret->body);
|
|
ret->body = nb;
|
|
bodymax = nlen;
|
|
}
|
|
ret->body[bodypos++] = c;
|
|
}
|
|
}
|
|
if (bodypos == bodymax)
|
|
{
|
|
int nlen = bodypos+1;
|
|
char *nb = malloc(nlen);
|
|
memcpy(nb, ret->body, bodypos);
|
|
free(ret->body);
|
|
ret->body = nb;
|
|
bodymax = nlen;
|
|
}
|
|
ret->body[bodypos++] = '\0';
|
|
|
|
XML_Unmark(ret->body);
|
|
|
|
*startpos = pos;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void XML_Destroy(xmltree_t *t)
|
|
{
|
|
xmlparams_t *p, *np;
|
|
|
|
if (t->child)
|
|
XML_Destroy(t->child);
|
|
if (t->sibling)
|
|
XML_Destroy(t->sibling);
|
|
|
|
for (p = t->params; p; p = np)
|
|
{
|
|
np = p->next;
|
|
free(p);
|
|
}
|
|
free(t->body);
|
|
free(t);
|
|
}
|
|
|
|
xmltree_t *XML_ChildOfTree(xmltree_t *t, char *name, int childnum)
|
|
{
|
|
if (t)
|
|
{
|
|
for (t = t->child; t; t = t->sibling)
|
|
{
|
|
if (!strcmp(t->name, name))
|
|
{
|
|
if (childnum-- == 0)
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
xmltree_t *XML_ChildOfTreeNS(xmltree_t *t, char *xmlns, char *name, int childnum)
|
|
{
|
|
if (t)
|
|
{
|
|
for (t = t->child; t; t = t->sibling)
|
|
{
|
|
if (!strcmp(t->xmlns, xmlns) && !strcmp(t->name, name))
|
|
{
|
|
if (childnum-- == 0)
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
char *XML_GetChildBody(xmltree_t *t, char *paramname, char *def)
|
|
{
|
|
xmltree_t *c = XML_ChildOfTree(t, paramname, 0);
|
|
if (c)
|
|
return c->body;
|
|
return def;
|
|
}
|
|
|
|
void XML_ConPrintTree(xmltree_t *t, char *subconsole, int indent)
|
|
{
|
|
int start, c, chunk;
|
|
struct buf_ctx buf = {NULL, 0, 0};
|
|
XML_DumpToBuf(&buf, t, indent);
|
|
buf_cat(&buf, "", 1);
|
|
|
|
for (start = 0; start < buf.len; )
|
|
{
|
|
chunk = buf.len - start;
|
|
if (chunk > 128)
|
|
chunk = 128;
|
|
c = buf.buf[start+chunk];
|
|
buf.buf[start+chunk] = 0;
|
|
Con_TrySubPrint(subconsole, buf.buf+start);
|
|
buf.buf[start+chunk] = c;
|
|
|
|
start += chunk;
|
|
}
|
|
|
|
free(buf.buf);
|
|
}
|
|
|
|
|
|
static void XML_SkipWhite(char *msg, int *pos, int max)
|
|
{
|
|
while (*pos < max && (
|
|
msg[*pos] == ' ' ||
|
|
msg[*pos] == '\t' ||
|
|
msg[*pos] == '\r' ||
|
|
msg[*pos] == '\n'
|
|
))
|
|
*pos+=1;
|
|
}
|
|
static qboolean XML_ParseString(char *msg, int *pos, int max, char *out, int outlen)
|
|
{
|
|
*out = 0;
|
|
if (*pos < max && msg[*pos] == '\"')
|
|
{
|
|
*pos+=1;
|
|
|
|
outlen--;
|
|
while (*pos < max && msg[*pos] != '\"')
|
|
{
|
|
if (!outlen)
|
|
return false;
|
|
*out = msg[*pos];
|
|
out++;
|
|
outlen--;
|
|
*pos+=1;
|
|
}
|
|
if (*pos < max && msg[*pos] == '\"')
|
|
{
|
|
*out = 0;
|
|
*pos+=1;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outlen--;
|
|
while (*pos < max
|
|
&& msg[*pos] != ' '
|
|
&& msg[*pos] != '\t'
|
|
&& msg[*pos] != '\r'
|
|
&& msg[*pos] != '\n'
|
|
&& msg[*pos] != ':'
|
|
&& msg[*pos] != ','
|
|
&& msg[*pos] != '}'
|
|
&& msg[*pos] != '{')
|
|
{
|
|
if (!outlen)
|
|
return false;
|
|
*out = msg[*pos];
|
|
out++;
|
|
outlen--;
|
|
*pos+=1;
|
|
}
|
|
*out = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
xmltree_t *XML_FromJSON(xmltree_t *t, char *name, char *json, int *jsonpos, int jsonlen)
|
|
{
|
|
char child[4096];
|
|
XML_SkipWhite(json, jsonpos, jsonlen);
|
|
|
|
if (*jsonpos < jsonlen && json[*jsonpos] == '{')
|
|
{
|
|
*jsonpos+=1;
|
|
XML_SkipWhite(json, jsonpos, jsonlen);
|
|
|
|
t = XML_CreateNode(t, name, "", "");
|
|
|
|
while (*jsonpos < jsonlen && json[*jsonpos] == '\"')
|
|
{
|
|
if (!XML_ParseString(json, jsonpos, jsonlen, child, sizeof(child)))
|
|
break;
|
|
XML_SkipWhite(json, jsonpos, jsonlen);
|
|
if (*jsonpos < jsonlen && json[*jsonpos] == ':')
|
|
{
|
|
*jsonpos+=1;
|
|
if (!XML_FromJSON(t, child, json, jsonpos, jsonlen))
|
|
break;
|
|
}
|
|
XML_SkipWhite(json, jsonpos, jsonlen);
|
|
|
|
if (*jsonpos < jsonlen && json[*jsonpos] == ',')
|
|
{
|
|
*jsonpos+=1;
|
|
XML_SkipWhite(json, jsonpos, jsonlen);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (*jsonpos < jsonlen && json[*jsonpos] == '}')
|
|
{
|
|
*jsonpos+=1;
|
|
return t;
|
|
}
|
|
XML_Destroy(t);
|
|
}
|
|
else if (*jsonpos < jsonlen)
|
|
{
|
|
if (XML_ParseString(json, jsonpos, jsonlen, child, sizeof(child)))
|
|
return XML_CreateNode(t, name, "", child);
|
|
}
|
|
return NULL;
|
|
}
|