gwenhywfar/src/parser/xml.c @ 0200e1e7
d8f33628 | aquamaniac | /***************************************************************************
|
|
$RCSfile$
|
|||
-------------------
|
|||
cvs : $Id$
|
|||
begin : Sat Jun 28 2003
|
|||
copyright : (C) 2003 by Martin Preuss
|
|||
email : martin@libchipcard.de
|
|||
***************************************************************************
|
|||
* *
|
|||
* This library is free software; you can redistribute it and/or *
|
|||
* modify it under the terms of the GNU Lesser General Public *
|
|||
* License as published by the Free Software Foundation; either *
|
|||
* version 2.1 of the License, or (at your option) any later version. *
|
|||
* *
|
|||
* This library is distributed in the hope that it will be useful, *
|
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|||
* Lesser General Public License for more details. *
|
|||
* *
|
|||
* You should have received a copy of the GNU Lesser General Public *
|
|||
* License along with this library; if not, write to the Free Software *
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|||
* MA 02111-1307 USA *
|
|||
* *
|
|||
***************************************************************************/
|
|||
#ifdef HAVE_CONFIG_H
|
|||
# include <config.h>
|
|||
#endif
|
|||
3ca7a382 | aquamaniac | #define DISABLE_DEBUGLOG
|
|
9b7237ac | aquamaniac | #include "xml_p.h"
|
|
#include "gwenhyfwar/debug.h"
|
|||
#include "gwenhyfwar/misc.h"
|
|||
d8f33628 | aquamaniac | #include <stdlib.h>
|
|
#include <assert.h>
|
|||
#include <string.h>
|
|||
#include <ctype.h>
|
|||
#include <sys/types.h>
|
|||
#include <sys/stat.h>
|
|||
#include <fcntl.h>
|
|||
#include <errno.h>
|
|||
9b7237ac | aquamaniac | GWEN_XMLPROPERTY *GWEN_XMLProperty_new(const char *name, const char *value){
|
|
GWEN_XMLPROPERTY *p;
|
|||
GWEN_NEW_OBJECT(GWEN_XMLPROPERTY, p);
|
|||
d8f33628 | aquamaniac | if (name)
|
|
p->name=strdup(name);
|
|||
if (value)
|
|||
p->value=strdup(value);
|
|||
return p;
|
|||
}
|
|||
9b7237ac | aquamaniac | ||
void GWEN_XMLProperty_free(GWEN_XMLPROPERTY *p){
|
|||
d8f33628 | aquamaniac | if (p) {
|
|
free(p->name);
|
|||
free(p->value);
|
|||
free(p);
|
|||
}
|
|||
}
|
|||
9b7237ac | aquamaniac | ||
GWEN_XMLPROPERTY *GWEN_XMLProperty_dup(GWEN_XMLPROPERTY *p){
|
|||
return GWEN_XMLProperty_new(p->name, p->value);
|
|||
d8f33628 | aquamaniac | }
|
|
9b7237ac | aquamaniac | ||
void GWEN_XMLProperty_add(GWEN_XMLPROPERTY *p, GWEN_XMLPROPERTY **head){
|
|||
GWEN_LIST_ADD(GWEN_XMLPROPERTY, p, head);
|
|||
d8f33628 | aquamaniac | }
|
|
9b7237ac | aquamaniac | void GWEN_XMLProperty_del(GWEN_XMLPROPERTY *p, GWEN_XMLPROPERTY **head){
|
|
GWEN_LIST_DEL(GWEN_XMLPROPERTY, p, head);
|
|||
d8f33628 | aquamaniac | }
|
|
9b7237ac | aquamaniac | void GWEN_XMLProperty_freeAll(GWEN_XMLPROPERTY *p) {
|
|
d8f33628 | aquamaniac | while(p) {
|
|
9b7237ac | aquamaniac | GWEN_XMLPROPERTY *next;
|
|
d8f33628 | aquamaniac | ||
next=p->next;
|
|||
9b7237ac | aquamaniac | GWEN_XMLProperty_free(p);
|
|
d8f33628 | aquamaniac | p=next;
|
|
} /* while */
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_new(GWEN_XMLNODE_TYPE t, const char *data){
|
|
GWEN_XMLNODE *n;
|
|||
d8f33628 | aquamaniac | ||
9b7237ac | aquamaniac | n=(GWEN_XMLNODE *)malloc(sizeof(GWEN_XMLNODE));
|
|
d8f33628 | aquamaniac | assert(n);
|
|
9b7237ac | aquamaniac | memset(n,0,sizeof(GWEN_XMLNODE));
|
|
d8f33628 | aquamaniac | n->type=t;
|
|
if (data)
|
|||
n->data=strdup(data);
|
|||
return n;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_free(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | if (n) {
|
|
9b7237ac | aquamaniac | GWEN_XMLProperty_freeAll(n->properties);
|
|
d8f33628 | aquamaniac | free(n->data);
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_freeAll(n->child);
|
|
d8f33628 | aquamaniac | free(n);
|
|
}
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_freeAll(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | while(n) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNODE *next;
|
|
d8f33628 | aquamaniac | ||
next=n->next;
|
|||
9b7237ac | aquamaniac | GWEN_XMLNode_free(n);
|
|
d8f33628 | aquamaniac | n=next;
|
|
} /* while */
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_dup(GWEN_XMLNODE *n){
|
|
GWEN_XMLNODE *nn, *cn, *ncn;
|
|||
GWEN_XMLPROPERTY *p;
|
|||
d8f33628 | aquamaniac | ||
/* duplicate node itself */
|
|||
9b7237ac | aquamaniac | nn=GWEN_XMLNode_new(n->type, n->data);
|
|
d8f33628 | aquamaniac | ||
/* duplicate properties */
|
|||
p=n->properties;
|
|||
while(p) {
|
|||
9b7237ac | aquamaniac | GWEN_XMLPROPERTY *np;
|
|
d8f33628 | aquamaniac | ||
9b7237ac | aquamaniac | np=GWEN_XMLProperty_dup(p);
|
|
GWEN_XMLProperty_add(np, &(nn->properties));
|
|||
d8f33628 | aquamaniac | p=p->next;
|
|
} /* while */
|
|||
/* duplicate children */
|
|||
cn=n->child;
|
|||
while(cn) {
|
|||
9b7237ac | aquamaniac | ncn=GWEN_XMLNode_dup(cn);
|
|
GWEN_XMLNode_add(ncn, &(nn->child));
|
|||
d8f33628 | aquamaniac | ncn->parent=nn;
|
|
cn=cn->next;
|
|||
} /* while */
|
|||
return nn;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_add(GWEN_XMLNODE *n, GWEN_XMLNODE **head){
|
|
GWEN_LIST_ADD(GWEN_XMLNODE, n, head);
|
|||
d8f33628 | aquamaniac | }
|
|
9b7237ac | aquamaniac | void GWEN_XMLNode_del(GWEN_XMLNODE *n, GWEN_XMLNODE **head){
|
|
GWEN_LIST_DEL(GWEN_XMLNODE, n, head);
|
|||
d8f33628 | aquamaniac | n->parent=0;
|
|
}
|
|||
9b7237ac | aquamaniac | const char *GWEN_XMLNode_GetProperty(GWEN_XMLNODE *n, const char *name,
|
|
const char *defaultValue){
|
|||
GWEN_XMLPROPERTY *p;
|
|||
d8f33628 | aquamaniac | ||
assert(n);
|
|||
assert(name);
|
|||
p=n->properties;
|
|||
while(p) {
|
|||
assert(p->name);
|
|||
if (strcasecmp(p->name, name)==0)
|
|||
break;
|
|||
p=p->next;
|
|||
} /* while */
|
|||
if (p) {
|
|||
if (p->value)
|
|||
return p->value;
|
|||
}
|
|||
return defaultValue;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_SetProperty(GWEN_XMLNODE *n,
|
|
const char *name, const char *value){
|
|||
GWEN_XMLPROPERTY *p;
|
|||
d8f33628 | aquamaniac | ||
p=n->properties;
|
|||
while(p) {
|
|||
assert(p->name);
|
|||
if (strcasecmp(p->name, name)==0)
|
|||
break;
|
|||
p=p->next;
|
|||
} /* while */
|
|||
if (p) {
|
|||
free(p->value);
|
|||
if (value)
|
|||
p->value=strdup(value);
|
|||
else
|
|||
p->value=0;
|
|||
}
|
|||
else {
|
|||
9b7237ac | aquamaniac | p=GWEN_XMLProperty_new(name, value);
|
|
GWEN_XMLProperty_add(p, &(n->properties));
|
|||
d8f33628 | aquamaniac | }
|
|
}
|
|||
9b7237ac | aquamaniac | const char *GWEN_XMLNode_GetData(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
return n->data;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_SetData(GWEN_XMLNODE *n, const char *data){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
free(n->data);
|
|||
if (data)
|
|||
n->data=strdup(data);
|
|||
else
|
|||
n->data=0;
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_GetChild(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
return n->child;
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_GetParent(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
return n->parent;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_AddChild(GWEN_XMLNODE *n, GWEN_XMLNODE *child){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_add(child, &(n->child));
|
|
d8f33628 | aquamaniac | child->parent=n;
|
|
}
|
|||
9b7237ac | aquamaniac | int GWEN_XML__ReadWord(GWEN_BUFFEREDIO *bio,
|
|
char chr,
|
|||
const char *delims,
|
|||
char *buffer,
|
|||
unsigned int size) {
|
|||
d8f33628 | aquamaniac | int inQuote;
|
|
assert(size);
|
|||
inQuote=0;
|
|||
size--;
|
|||
buffer[0]=0;
|
|||
while(1) {
|
|||
/* get character, if needed */
|
|||
if (chr==0) {
|
|||
9b7237ac | aquamaniac | if (GWEN_BufferedIO_CheckEOF(bio))
|
|
d8f33628 | aquamaniac | break;
|
|
9b7237ac | aquamaniac | chr=GWEN_BufferedIO_ReadChar(bio);
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | DBG_ERROR(0, "Error on ReadChar");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
}
|
|||
if (iscntrl(chr))
|
|||
chr=' ';
|
|||
if (inQuote) {
|
|||
if (chr=='"') {
|
|||
inQuote=0;
|
|||
break;
|
|||
}
|
|||
else {
|
|||
if (size<1) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "Word too long");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
*buffer=chr;
|
|||
buffer++;
|
|||
size--;
|
|||
}
|
|||
}
|
|||
else {
|
|||
if (chr=='"') {
|
|||
inQuote=1;
|
|||
}
|
|||
else if (strchr(delims, chr)) {
|
|||
break;
|
|||
}
|
|||
else if (chr=='<') {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "No tags inside a tag definition allowed");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
else {
|
|||
if (size<1) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "Word too long");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
*buffer=chr;
|
|||
buffer++;
|
|||
size--;
|
|||
}
|
|||
}
|
|||
chr=0;
|
|||
} /* while */
|
|||
*buffer=0;
|
|||
return chr;
|
|||
}
|
|||
0200e1e7 | aquamaniac | int GWEN_XML_Parse(GWEN_XMLNODE *n, GWEN_BUFFEREDIO *bio,
|
|
unsigned int flags) {
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *path[GWEN_XML_MAX_DEPTH];
|
|
d8f33628 | aquamaniac | int currDepth;
|
|
int chr;
|
|||
int isEndTag;
|
|||
int eofMet;
|
|||
int isComment;
|
|||
currDepth=0;
|
|||
chr=0;
|
|||
9b7237ac | aquamaniac | while (!GWEN_BufferedIO_CheckEOF(bio)) {
|
|
d8f33628 | aquamaniac | /* read char (if none set) but skip blanks */
|
|
if (chr==0) {
|
|||
9b7237ac | aquamaniac | chr=GWEN_BufferedIO_ReadChar(bio);
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | DBG_ERROR(0, "Error on BufferedIO_ReadChar");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
}
|
|||
eofMet=0;
|
|||
while(isspace(chr)) {
|
|||
9b7237ac | aquamaniac | if (GWEN_BufferedIO_CheckEOF(bio)) {
|
|
d8f33628 | aquamaniac | eofMet=1;
|
|
break;
|
|||
}
|
|||
9b7237ac | aquamaniac | chr=GWEN_BufferedIO_ReadChar(bio);
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | DBG_ERROR(0, "Error on BufferedIO_ReadChar");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
}
|
|||
if (eofMet)
|
|||
break;
|
|||
if (chr=='<') {
|
|||
9b7237ac | aquamaniac | char tagname[GWEN_XML_MAX_TAGNAMELEN];
|
|
d8f33628 | aquamaniac | char *p;
|
|
isEndTag=0;
|
|||
/* we have a tag */
|
|||
9b7237ac | aquamaniac | chr=GWEN_XML__ReadWord(bio, 0, " ><", tagname, sizeof(tagname));
|
|
d8f33628 | aquamaniac | if (chr<0)
|
|
return -1;
|
|||
p=tagname;
|
|||
if (*p=='/') {
|
|||
isEndTag=1;
|
|||
p++;
|
|||
}
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "Found tag \"%s\"", tagname);
|
|
d8f33628 | aquamaniac | ||
isComment=0;
|
|||
if (strlen(p)>=3)
|
|||
if (strncmp(p,"!--",3)==0)
|
|||
isComment=1;
|
|||
if (isComment) {
|
|||
9b7237ac | aquamaniac | char comment[GWEN_XML_MAX_REMARKLEN];
|
|
d8f33628 | aquamaniac | int comlen;
|
|
9b7237ac | aquamaniac | GWEN_XMLNODE *newNode;
|
|
d8f33628 | aquamaniac | ||
comlen=0;
|
|||
comment[0]=0;
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "Found comment");
|
|
d8f33628 | aquamaniac | /* we have a remark tag, so read it over */
|
|
while(1) {
|
|||
if (chr==0) {
|
|||
9b7237ac | aquamaniac | if (GWEN_BufferedIO_CheckEOF(bio)) {
|
|
DBG_ERROR(0, "Unexpected EOF within comment");
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | chr=GWEN_BufferedIO_ReadChar(bio);
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
return -1;
|
|||
}
|
|||
0200e1e7 | aquamaniac | }
|
|
if (comlen>=sizeof(comment)) {
|
|||
DBG_ERROR(0, "Comment too long !");
|
|||
return -1;
|
|||
}
|
|||
d8f33628 | aquamaniac | comment[comlen++]=chr;
|
|
if (comlen>=3) {
|
|||
if (strncmp(comment+comlen-3,"-->",3)==0) {
|
|||
comlen-=3;
|
|||
comment[comlen]=0;
|
|||
0200e1e7 | aquamaniac | break;
|
|
}
|
|||
else {
|
|||
if (!(flags & GWEN_XML_FLAGS_READ_COMMENTS)) {
|
|||
DBG_VERBOUS(0, "Clipping comment to 2 bytes");
|
|||
memmove(comment, comment+comlen-2, 2);
|
|||
comlen=2;
|
|||
}
|
|||
}
|
|||
}
|
|||
chr=0;
|
|||
d8f33628 | aquamaniac | } /* while */
|
|
0200e1e7 | aquamaniac | /* create new node */
|
|
DBG_VERBOUS(0, "Comment finished");
|
|||
if (flags & GWEN_XML_FLAGS_READ_COMMENTS) {
|
|||
newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeComment,
|
|||
comment);
|
|||
GWEN_XMLNode_add(newNode, &(n->child));
|
|||
newNode->parent=n;
|
|||
DBG_DEBUG(0, "Added comment: \"%s\"", comment);
|
|||
}
|
|||
else {
|
|||
DBG_DEBUG(0, "Skip comment");
|
|||
}
|
|||
d8f33628 | aquamaniac | } /* if remark */
|
|
else {
|
|||
/* handle tagname */
|
|||
if (isEndTag) {
|
|||
/* handle endtag */
|
|||
if (currDepth<1) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "More endtags than start tags !");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (strcasecmp(n->data, p)!=0) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "endtag \"%s\" does not match last start tag (\"%s\")",
|
|
d8f33628 | aquamaniac | tagname, n->data);
|
|
return -1;
|
|||
}
|
|||
/* surface */
|
|||
n=path[currDepth-1];
|
|||
currDepth--;
|
|||
if (currDepth==0) {
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "One node done");
|
|
d8f33628 | aquamaniac | return 0;
|
|
}
|
|||
}
|
|||
else {
|
|||
/* this is a start tag */
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *newNode;
|
|
char varname[GWEN_XML_MAX_VARNAMELEN];
|
|||
char value[GWEN_XML_MAX_VALUELEN];
|
|||
d8f33628 | aquamaniac | ||
if (*p) {
|
|||
int j;
|
|||
j=strlen(p)-1;
|
|||
if (p[j]=='/') {
|
|||
if (chr!='>') {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "\"/\" only allowed just before \">\"");
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
p[j]=0;
|
|||
isEndTag=1;
|
|||
}
|
|||
}
|
|||
9b7237ac | aquamaniac | newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, p);
|
|
d8f33628 | aquamaniac | while (chr!='>' && chr!='/') {
|
|
varname[0]=0;
|
|||
value[0]=0;
|
|||
/* skip blanks */
|
|||
chr=0;
|
|||
9b7237ac | aquamaniac | while(!GWEN_BufferedIO_CheckEOF(bio)) {
|
|
chr=GWEN_BufferedIO_ReadChar(bio);
|
|||
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (!isspace(chr) && !iscntrl(chr))
|
|||
break;
|
|||
}
|
|||
if (chr==0) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "unexpected EOF");
|
|
GWEN_XMLNode_free(newNode);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (chr=='>' || chr=='/')
|
|||
break;
|
|||
/* read possibly following var */
|
|||
9b7237ac | aquamaniac | chr=GWEN_XML__ReadWord(bio, chr, " =/>", varname, sizeof(varname));
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "Found property \"%s\"", varname);
|
|
d8f33628 | aquamaniac | ||
/* skip blanks */
|
|||
if (isspace(chr)) {
|
|||
9b7237ac | aquamaniac | while(!GWEN_BufferedIO_CheckEOF(bio)) {
|
|
chr=GWEN_BufferedIO_ReadChar(bio);
|
|||
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (!isspace(chr) && !iscntrl(chr))
|
|||
break;
|
|||
}
|
|||
}
|
|||
if (chr=='=') {
|
|||
chr=0;
|
|||
/* skip blanks */
|
|||
9b7237ac | aquamaniac | while(!GWEN_BufferedIO_CheckEOF(bio)) {
|
|
chr=GWEN_BufferedIO_ReadChar(bio);
|
|||
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (!isspace(chr))
|
|||
break;
|
|||
}
|
|||
if (chr==0) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "Value expected for property \"%s\"",
|
|
d8f33628 | aquamaniac | varname);
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
if (chr=='>' || chr=='/') {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "Value expected for property \"%s\"",
|
|
d8f33628 | aquamaniac | varname);
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
/* read value */
|
|||
9b7237ac | aquamaniac | chr=GWEN_XML__ReadWord(bio, chr, " />", value, sizeof(value));
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "Found value \"%s\"", value);
|
|
d8f33628 | aquamaniac | } /* if value follows */
|
|
if (varname[0]) {
|
|||
/* add property */
|
|||
9b7237ac | aquamaniac | GWEN_XMLPROPERTY *newProp;
|
|
d8f33628 | aquamaniac | ||
9b7237ac | aquamaniac | newProp=GWEN_XMLProperty_new(varname,
|
|
value[0]?value:0);
|
|||
GWEN_XMLProperty_add(newProp, &(newNode->properties));
|
|||
d8f33628 | aquamaniac | } /* if varname */
|
|
} /* while vars follow */
|
|||
if (chr=='/') {
|
|||
isEndTag=1;
|
|||
9b7237ac | aquamaniac | if (GWEN_BufferedIO_CheckEOF(bio)) {
|
|
DBG_ERROR(0, "\">\" expected");
|
|||
GWEN_XMLNode_free(newNode);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | chr=GWEN_BufferedIO_ReadChar(bio);
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | DBG_ERROR(0, "Error on ReadChar");
|
|
GWEN_XMLNode_free(newNode);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
}
|
|||
if (chr!='>') {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "\">\" expected");
|
|
GWEN_XMLNode_free(newNode);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
/* ok, now the tag is complete, add it */
|
|||
9b7237ac | aquamaniac | if (currDepth>=GWEN_XML_MAX_DEPTH) {
|
|
DBG_ERROR(0, "Maximum depth exceeded");
|
|||
GWEN_XMLNode_free(newNode);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNode_add(newNode, &(n->child));
|
|
d8f33628 | aquamaniac | newNode->parent=n;
|
|
9b7237ac | aquamaniac | DBG_DEBUG(0, "Added node \"%s\"", newNode->data);
|
|
d8f33628 | aquamaniac | if (!isEndTag) {
|
|
/* only dive if this tag is not immediately ended */
|
|||
path[currDepth++]=n;
|
|||
n=newNode;
|
|||
}
|
|||
else {
|
|||
/* immediate endTag, if depth is 0: done */
|
|||
if (currDepth==0) {
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "One node done");
|
|
d8f33628 | aquamaniac | return 0;
|
|
}
|
|||
}
|
|||
} /* if start tag */
|
|||
} /* if no remark */
|
|||
chr=0; /* make begin of loop read new char */
|
|||
} /* if "<" */
|
|||
else {
|
|||
/* add data to current tag */
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *newNode;
|
|
char data[GWEN_XML_MAX_DATALEN];
|
|||
d8f33628 | aquamaniac | ||
9b7237ac | aquamaniac | chr=GWEN_XML__ReadWord(bio, chr, "<", data, sizeof(data));
|
|
d8f33628 | aquamaniac | if (chr<0) {
|
|
9b7237ac | aquamaniac | GWEN_XMLNode_free(newNode);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
9b7237ac | aquamaniac | newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeData, data);
|
|
DBG_DEBUG(0, "Added data \"%s\"", data);
|
|||
GWEN_XMLNode_add(newNode, &(n->child));
|
|||
d8f33628 | aquamaniac | newNode->parent=n;
|
|
}
|
|||
/* do not set chr=0, because we may already have the next char ('<') */
|
|||
} /* while !eof */
|
|||
if (currDepth!=0) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "%d tags are still open", currDepth);
|
|
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
return 0;
|
|||
}
|
|||
0200e1e7 | aquamaniac | int GWEN_XML_ReadFile(GWEN_XMLNODE *n, const char *filepath,
|
|
unsigned int flags){
|
|||
9b7237ac | aquamaniac | GWEN_BUFFEREDIO *dm;
|
|
d8f33628 | aquamaniac | int fd;
|
|
fd=open(filepath, O_RDONLY);
|
|||
if (fd==-1) {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "open(%s): %s",
|
|
d8f33628 | aquamaniac | filepath,
|
|
strerror(errno));
|
|||
return -1;
|
|||
}
|
|||
9b7237ac | aquamaniac | dm=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SetReadBuffer(dm,0,1024);
|
|||
d8f33628 | aquamaniac | ||
9b7237ac | aquamaniac | while(!GWEN_BufferedIO_CheckEOF(dm)) {
|
|
0200e1e7 | aquamaniac | if (GWEN_XML_Parse(n, dm, flags)) {
|
|
9b7237ac | aquamaniac | DBG_ERROR(0, "Error parsing");
|
|
GWEN_BufferedIO_Close(dm);
|
|||
GWEN_BufferedIO_free(dm);
|
|||
d8f33628 | aquamaniac | return -1;
|
|
}
|
|||
} /* while */
|
|||
9b7237ac | aquamaniac | GWEN_BufferedIO_Close(dm);
|
|
GWEN_BufferedIO_free(dm);
|
|||
d8f33628 | aquamaniac | ||
return 0;
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE_TYPE GWEN_XMLNode_GetType(GWEN_XMLNODE *n){
|
|
d8f33628 | aquamaniac | assert(n);
|
|
return n->type;
|
|||
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_Next(GWEN_XMLNODE *n) {
|
|
d8f33628 | aquamaniac | assert(n);
|
|
return n->next;
|
|||
}
|
|||
9b7237ac | aquamaniac | void GWEN_XMLNode_Dump(GWEN_XMLNODE *n, FILE *f, int ind) {
|
|
GWEN_XMLPROPERTY *p;
|
|||
GWEN_XMLNODE *c;
|
|||
d8f33628 | aquamaniac | int i;
|
|
assert(n);
|
|||
for(i=0; i<ind; i++)
|
|||
fprintf(f, " ");
|
|||
9b7237ac | aquamaniac | if (n->type==GWEN_XMLNodeTypeTag) {
|
|
d8f33628 | aquamaniac | if (n->data)
|
|
fprintf(f, "<%s", n->data);
|
|||
else
|
|||
fprintf(f, "<UNKNOWN");
|
|||
p=n->properties;
|
|||
while (p) {
|
|||
4e94dfc9 | aquamaniac | fprintf(f, " %s=\"%s\"", p->name, p->value);
|
|
d8f33628 | aquamaniac | p=p->next;
|
|
}
|
|||
fprintf(f, ">\n");
|
|||
c=n->child;
|
|||
while(c) {
|
|||
9b7237ac | aquamaniac | GWEN_XMLNode_Dump(c, f, ind+2);
|
|
d8f33628 | aquamaniac | c=c->next;
|
|
}
|
|||
for(i=0; i<ind; i++)
|
|||
fprintf(f, " ");
|
|||
if (n->data)
|
|||
fprintf(f, "</%s>\n", n->data);
|
|||
else
|
|||
fprintf(f, "</UNKNOWN>\n");
|
|||
}
|
|||
9b7237ac | aquamaniac | else if (n->type==GWEN_XMLNodeTypeData) {
|
|
d8f33628 | aquamaniac | if (n->data) {
|
|
fprintf(f, "%s\n", n->data);
|
|||
}
|
|||
}
|
|||
9b7237ac | aquamaniac | else if (n->type==GWEN_XMLNodeTypeComment) {
|
|
d8f33628 | aquamaniac | fprintf(f, "<!--");
|
|
if (n->data) {
|
|||
fprintf(f, "%s", n->data);
|
|||
}
|
|||
fprintf(f, "-->\n");
|
|||
}
|
|||
else {
|
|||
9b7237ac | aquamaniac | DBG_ERROR(0, "Unknown tag type (%d)", n->type);
|
|
d8f33628 | aquamaniac | }
|
|
}
|
|||
9b7237ac | aquamaniac | GWEN_XMLNODE *GWEN_XMLNode_FindNode(GWEN_XMLNODE *node,
|
|
GWEN_XMLNODE_TYPE t, const char *data) {
|
|||
GWEN_XMLNODE *n;
|
|||
d8f33628 | aquamaniac | ||
assert(node);
|
|||
assert(data);
|
|||
n=node->child;
|
|||
while(n) {
|
|||
if (n->type==t)
|
|||
if (n->data)
|
|||
if (strcasecmp(n->data, data)==0)
|
|||
break;
|
|||
n=n->next;
|
|||
} /* while */
|
|||
if (!n) {
|
|||
9b7237ac | aquamaniac | DBG_DEBUG(0, "Node %d:\"%s\" not found", t, data);
|
|
d8f33628 | aquamaniac | return 0;
|
|
}
|
|||
return n;
|
|||
}
|
|||
9b7237ac | aquamaniac | ||
void GWEN_XMLNode_UnlinkChild(GWEN_XMLNODE *n, GWEN_XMLNODE *child){
|
|||
d8f33628 | aquamaniac | assert(n);
|
|
assert(child);
|
|||
9b7237ac | aquamaniac | GWEN_XMLNode_del(child, &(n->child));
|
|
d8f33628 | aquamaniac | child->next=0;
|
|
child->parent=0;
|
|||
}
|
|||
0200e1e7 | aquamaniac | void GWEN_XMLNode_RemoveChildren(GWEN_XMLNODE *n){
|
|
GWEN_XMLNODE *cn;
|
|||
assert(n);
|
|||
cn=n->child;
|
|||
while(cn) {
|
|||
GWEN_XMLNODE *ncn;
|
|||
ncn=cn->next;
|
|||
GWEN_XMLNode_free(cn);
|
|||
cn=ncn;
|
|||
} /* while */
|
|||
n->child=0;
|
|||
}
|
|||