⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmlnode.c

📁 Simple Jabber Client for Symbian Platform
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *  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 + -