📄 xmlnode.c
字号:
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Jabber
* Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
*/
#include "libxode.h"
/* Internal routines */
xmlnode _xmlnode_new(pool p, const char* name, unsigned int type)
{
xmlnode result = NULL;
if (type > NTYPE_LAST)
return NULL;
if (type != NTYPE_CDATA && name == NULL)
return NULL;
if (p == NULL)
{
p = pool_heap(1*1024);
}
/* Allocate & zero memory */
result = (xmlnode)pmalloc(p, sizeof(_xmlnode));
memset(result, '\0', sizeof(_xmlnode));
/* Initialize fields */
if (type != NTYPE_CDATA)
result->name = pstrdup(p,name);
result->type = type;
result->p = p;
return result;
}
static xmlnode _xmlnode_append_sibling(xmlnode lastsibling, const char* name, unsigned int type)
{
xmlnode result;
result = _xmlnode_new(xmlnode_pool(lastsibling), name, type);
if (result != NULL)
{
/* Setup sibling pointers */
result->prev = lastsibling;
lastsibling->next = result;
}
return result;
}
static xmlnode _xmlnode_insert(xmlnode parent, const char* name, unsigned int type)
{
xmlnode result;
if(parent == NULL || name == NULL) return NULL;
/* If parent->firstchild is NULL, simply create a new node for the first child */
if (parent->firstchild == NULL)
{
result = _xmlnode_new(parent->p, name, type);
parent->firstchild = result;
}
/* Otherwise, append this to the lastchild */
else
{
result= _xmlnode_append_sibling(parent->lastchild, name, type);
}
result->parent = parent;
parent->lastchild = result;
return result;
}
static xmlnode _xmlnode_search(xmlnode firstsibling, const char* name, unsigned int type)
{
xmlnode current;
/* Walk the sibling list, looking for a NTYPE_TAG xmlnode with
the specified name */
current = firstsibling;
while (current != NULL)
{
if ((current->type == type) && (j_strcmp(current->name, name) == 0))
return current;
else
current = current->next;
}
return NULL;
}
static char* _xmlnode_merge(pool p, char* dest, unsigned int destsize, const char* src, unsigned int srcsize)
{
char* result;
result = (char*)pmalloc(p, destsize + srcsize + 1);
memcpy(result, dest, destsize);
memcpy(result+destsize, src, srcsize);
result[destsize + srcsize] = '\0';
/* WARNING: major ugly hack: since we're throwing the old data away, let's jump in the pool and subtract it from the size, this is for xmlstream's big-node checking */
p->size -= destsize;
return result;
}
static void _xmlnode_hide_sibling(xmlnode child)
{
if(child == NULL)
return;
if(child->prev != NULL)
child->prev->next = child->next;
if(child->next != NULL)
child->next->prev = child->prev;
}
void _xmlnode_tag2str(spool s, xmlnode node, int flag)
{
xmlnode tmp;
if(flag==0 || flag==1)
{
spooler(s,"<",xmlnode_get_name(node),s);
tmp = xmlnode_get_firstattrib(node);
while(tmp) {
spooler(s," ",xmlnode_get_name(tmp),"='",strescape(xmlnode_pool(node),xmlnode_get_data(tmp)),"'",s);
tmp = xmlnode_get_nextsibling(tmp);
}
if(flag==0)
spool_add(s,"/>");
else
spool_add(s,">");
}
else
{
spooler(s,"</",xmlnode_get_name(node),">",s);
}
}
spool _xmlnode2spool(xmlnode node)
{
spool s;
int level=0,dir=0;
xmlnode tmp;
if(!node || xmlnode_get_type(node)!=NTYPE_TAG)
return NULL;
s = spool_new(xmlnode_pool(node));
if(!s) return(NULL);
while(1)
{
if(dir==0)
{
if(xmlnode_get_type(node) == NTYPE_TAG)
{
if(xmlnode_has_children(node))
{
_xmlnode_tag2str(s,node,1);
node = xmlnode_get_firstchild(node);
level++;
continue;
}
else
{
_xmlnode_tag2str(s,node,0);
}
}
else
{
spool_add(s,strescape(xmlnode_pool(node),xmlnode_get_data(node)));
}
}
tmp = xmlnode_get_nextsibling(node);
if(!tmp)
{
node = xmlnode_get_parent(node);
level--;
if(level>=0) _xmlnode_tag2str(s,node,2);
if(level<1) break;
dir = 1;
}
else
{
node = tmp;
dir = 0;
}
}
return s;
}
/* External routines */
/*
* xmlnode_new_tag -- create a tag node
* Automatically creates a memory pool for the node.
*
* parameters
* name -- name of the tag
*
* returns
* a pointer to the tag node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_new_tag(const char* name)
{
return _xmlnode_new(NULL, name, NTYPE_TAG);
}
/*
* xmlnode_new_tag_pool -- create a tag node within given pool
*
* parameters
* p -- previously created memory pool
* name -- name of the tag
*
* returns
* a pointer to the tag node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_new_tag_pool(pool p, const char* name)
{
return _xmlnode_new(p, name, NTYPE_TAG);
}
/*
* xmlnode_insert_tag -- append a child tag to a tag
*
* parameters
* parent -- pointer to the parent tag
* name -- name of the child tag
*
* returns
* a pointer to the child tag node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_insert_tag(xmlnode parent, const char* name)
{
return _xmlnode_insert(parent, name, NTYPE_TAG);
}
/*
* xmlnode_insert_cdata -- append character data to a tag
* If last child of the parent is CDATA, merges CDATA nodes. Otherwise
* creates a CDATA node, and appends it to the parent's child list.
*
* parameters
* parent -- parent tag
* CDATA -- character data
* size -- size of CDATA
* or -1 for null-terminated CDATA strings
*
* returns
* a pointer to the child CDATA node
* or NULL if it was unsuccessfull
*/
xmlnode xmlnode_insert_cdata(xmlnode parent, const char* CDATA, unsigned int size)
{
xmlnode result;
if(CDATA == NULL || parent == NULL)
return NULL;
if(size == -1)
size = strlen(CDATA);
/* If last child is already a CDATA segment, merge this new CDATA segment */
if ((parent->lastchild != NULL) && (parent->lastchild->type == NTYPE_CDATA))
{
result = parent->lastchild;
result->data = _xmlnode_merge(result->p, result->data, result->data_sz, CDATA, size);
result->data_sz = result->data_sz + size;
}
/* Otherwise, insert a new CDATA node */
else
{
result = _xmlnode_insert(parent, "", NTYPE_CDATA);
if (result != NULL)
{
result->data = (char*)pmalloc(result->p, size + 1);
memcpy(result->data, CDATA, size);
result->data[size] = '\0';
result->data_sz = size;
}
}
return result;
}
/*
* xmlnode_get_tag -- find given tag in an xmlnode tree
*
* parameters
* parent -- pointer to the parent tag
* name -- "name" for the child tag of that name
* "name/name" for a sub child (recurses)
* "?attrib" to match the first tag with that attrib defined
* "?attrib=value" to match the first tag with that attrib and value
* or any combination: "name/name/?attrib", etc
*
* results
* a pointer to the tag matching search criteria
* or NULL if search was unsuccessfull
*/
xmlnode xmlnode_get_tag(xmlnode parent, const char* name)
{
char *str, *slash, *qmark, *equals;
xmlnode step, ret;
if(parent == NULL || parent->firstchild == NULL || name == NULL || name == '\0') return NULL;
if(strstr(name, "/") == NULL && strstr(name,"?") == NULL)
return _xmlnode_search(parent->firstchild, name, NTYPE_TAG);
/* jer's note: why can't I modify the name directly, why do I have to strdup it? damn c grrr! */
str = strdup(name);
slash = strstr(str, "/");
qmark = strstr(str, "?");
equals = strstr(str, "=");
if(qmark != NULL && (slash == NULL || qmark < slash))
{ /* of type ?attrib */
*qmark = '\0';
qmark++;
if(equals != NULL)
{
*equals = '\0';
equals++;
}
for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
{
if(xmlnode_get_type(step) != NTYPE_TAG)
continue;
if(*str != '\0')
if(j_strcmp(xmlnode_get_name(step),str) != 0)
continue;
if(xmlnode_get_attrib(step,qmark) == NULL)
continue;
if(equals != NULL && j_strcmp(xmlnode_get_attrib(step,qmark),equals) != 0)
continue;
break;
}
free(str);
return step;
}
*slash = '\0';
++slash;
for(step = parent->firstchild; step != NULL; step = xmlnode_get_nextsibling(step))
{
if(xmlnode_get_type(step) != NTYPE_TAG) continue;
if(j_strcmp(xmlnode_get_name(step),str) != 0)
continue;
ret = xmlnode_get_tag(step, slash);
if(ret != NULL)
{
free(str);
return ret;
}
}
free(str);
return NULL;
}
/* return the cdata from any tag */
char *xmlnode_get_tag_data(xmlnode parent, const char *name)
{
xmlnode tag;
tag = xmlnode_get_tag(parent, name);
if(tag == NULL) return NULL;
return xmlnode_get_data(tag);
}
void xmlnode_put_attrib(xmlnode owner, const char* name, const char* value)
{
xmlnode attrib;
if(owner == NULL || name == NULL || value == NULL) return;
/* If there are no existing attributs, allocate a new one to start
the list */
if (owner->firstattrib == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -