Files
gb28181/GB28181Device/bm/xml_node.cpp
2024-12-15 20:42:32 +08:00

587 lines
10 KiB
C++

/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "hxml.h"
#include "xml_node.h"
/***************************************************************************************
*
* XML operational functions
*
***************************************************************************************/
HT_API XMLN * xml_node_add(XMLN * parent, const char * name)
{
XMLN * p_node = (XMLN *)malloc(sizeof(XMLN));
if (p_node == NULL)
{
log_print(HT_LOG_ERR, "%s, memory alloc fail!!!\r\n", __FUNCTION__);
return NULL;
}
memset(p_node, 0, sizeof(XMLN));
p_node->type = NTYPE_TAG;
p_node->name = name;
if (parent != NULL)
{
p_node->parent = parent;
if (parent->f_child == NULL)
{
parent->f_child = p_node;
parent->l_child = p_node;
}
else
{
parent->l_child->next = p_node;
p_node->prev = parent->l_child;
parent->l_child = p_node;
}
}
return p_node;
}
HT_API void xml_node_del(XMLN * p_node)
{
XMLN * p_attr;
XMLN * p_child;
if (p_node == NULL)
{
return;
}
p_attr = p_node->f_attrib;
while (p_attr)
{
XMLN * p_next = p_attr->next;
free(p_attr);
p_attr = p_next;
}
p_child = p_node->f_child;
while (p_child)
{
XMLN * p_next = p_child->next;
xml_node_del(p_child);
p_child = p_next;
}
if (p_node->prev)
{
p_node->prev->next = p_node->next;
}
if (p_node->next)
{
p_node->next->prev = p_node->prev;
}
if (p_node->parent)
{
if (p_node->parent->f_child == p_node)
{
p_node->parent->f_child = p_node->next;
}
if (p_node->parent->l_child == p_node)
{
p_node->parent->l_child = p_node->prev;
}
}
free(p_node);
}
HT_API XMLN * xml_node_get(XMLN * parent, const char * name)
{
XMLN * p_node;
if (parent == NULL || name == NULL)
{
return NULL;
}
p_node = parent->f_child;
while (p_node != NULL)
{
if (strcasecmp(p_node->name, name) == 0)
{
return p_node;
}
p_node = p_node->next;
}
return NULL;
}
HT_API int soap_strcmp(const char * str1, const char * str2)
{
const char * ptr1;
const char * ptr2;
if (strcasecmp(str1, str2) == 0)
{
return 0;
}
ptr1 = strchr(str1, ':');
ptr2 = strchr(str2, ':');
if (ptr1 && ptr2)
{
return strcasecmp(ptr1+1, ptr2+1);
}
else if (ptr1)
{
return strcasecmp(ptr1+1, str2);
}
else if (ptr2)
{
return strcasecmp(str1, ptr2+1);
}
else
{
return strcasecmp(str1, str2);
}
}
HT_API void soap_strncpy(char * dest, const char * src, int size)
{
const char * ptr;
ptr = strchr(src, ':');
if (ptr)
{
strncpy(dest, ptr+1, size);
}
else
{
strncpy(dest, src, size);
}
}
HT_API XMLN * xml_node_soap_get(XMLN * parent, const char * name)
{
XMLN * p_node;
if (parent == NULL || name == NULL)
{
return NULL;
}
p_node = parent->f_child;
while (p_node != NULL)
{
if (soap_strcmp(p_node->name, name) == 0)
{
return p_node;
}
p_node = p_node->next;
}
return NULL;
}
/***************************************************************************************/
HT_API XMLN * xml_attr_add(XMLN * p_node, const char * name, const char * value)
{
XMLN * p_attr;
if (p_node == NULL || name == NULL || value == NULL)
{
return NULL;
}
p_attr = (XMLN *)malloc(sizeof(XMLN));
if (p_attr == NULL)
{
log_print(HT_LOG_ERR, "%s, memory alloc fail!!!\r\n", __FUNCTION__);
return NULL;
}
memset(p_attr, 0, sizeof(XMLN));
p_attr->type = NTYPE_ATTRIB;
p_attr->name = name;
p_attr->data = value;
p_attr->dlen = (int)strlen(value);
if (p_node->f_attrib == NULL)
{
p_node->f_attrib = p_attr;
p_node->l_attrib = p_attr;
}
else
{
p_attr->prev = p_node->l_attrib;
p_node->l_attrib->next = p_attr;
p_node->l_attrib = p_attr;
}
return p_attr;
}
HT_API void xml_attr_del(XMLN * p_node, const char * name)
{
XMLN * p_attr;
if (p_node == NULL || name == NULL)
{
return;
}
p_attr = p_node->f_attrib;
while (p_attr != NULL)
{
if (strcasecmp(p_attr->name, name) == 0)
{
xml_node_del(p_attr);
return;
}
p_attr = p_attr->next;
}
}
HT_API const char * xml_attr_get(XMLN * p_node, const char * name)
{
XMLN * p_attr;
if (p_node == NULL || name == NULL)
{
return NULL;
}
p_attr = p_node->f_attrib;
while (p_attr != NULL)
{
if ((NTYPE_ATTRIB == p_attr->type) && (0 == soap_strcmp(p_attr->name, name)))
{
return p_attr->data;
}
p_attr = p_attr->next;
}
return NULL;
}
HT_API XMLN * xml_attr_node_get(XMLN * p_node, const char * name)
{
XMLN * p_attr;
if (p_node == NULL || name == NULL)
{
return NULL;
}
p_attr = p_node->f_attrib;
while (p_attr != NULL)
{
if ((NTYPE_ATTRIB == p_attr->type) && (0 == soap_strcmp(p_attr->name, name)))
{
return p_attr;
}
p_attr = p_attr->next;
}
return NULL;
}
/***************************************************************************************/
HT_API void xml_cdata_set(XMLN * p_node, const char * value, int len)
{
if (p_node == NULL || value == NULL || len <= 0)
{
return;
}
p_node->data = value;
p_node->dlen = len;
}
/***************************************************************************************/
HT_API int xml_calc_buf_len(XMLN * p_node)
{
int xml_len = 0;
XMLN * p_attr;
xml_len += 1 + (int)strlen(p_node->name);
p_attr = p_node->f_attrib;
while (p_attr)
{
if (p_attr->type == NTYPE_ATTRIB)
{
xml_len += (int)strlen(p_attr->name) + 4 + (int)strlen(p_attr->data);
}
else if (p_attr->type == NTYPE_CDATA)
{
if (0x0a == (*p_attr->data))
{
p_attr = p_attr->next;
continue;
}
xml_len += 5 + (int)strlen(p_attr->data) + 2 + (int)strlen(p_node->name) + 1;
return xml_len;
}
p_attr = p_attr->next;
}
if (p_node->f_child)
{
XMLN * p_child;
xml_len += 5;
p_child = p_node->f_child;
while (p_child)
{
xml_len += xml_calc_buf_len(p_child);
p_child = p_child->next;
}
xml_len += 6 + (int)strlen(p_node->name) + 1;
}
else if (p_node->data)
{
xml_len += 8 + (int)strlen(p_node->data) + (int)strlen(p_node->name);
}
else
{
xml_len += 6;
}
return xml_len+1;
}
/***************************************************************************************/
HT_API int xml_write_buf(XMLN * p_node, char * xml_buf, int buf_len)
{
int ret = 0;
int xml_len = 0;
XMLN * p_attr;
if ((NULL == p_node) || (NULL == p_node->name))
{
return -1;
}
if (strlen(p_node->name) >= (size_t)buf_len)
{
return -1;
}
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, "<%s", p_node->name);
p_attr = p_node->f_attrib;
while (p_attr)
{
if (p_attr->type == NTYPE_ATTRIB)
{
if ((strlen(p_attr->name) + strlen(p_attr->data) + xml_len) > (size_t)buf_len)
{
return -1;
}
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, " %s=\"%s\"", p_attr->name, p_attr->data);
}
else if (p_attr->type == NTYPE_CDATA)
{
if (0x0a == (*p_attr->data))
{
p_attr = p_attr->next;
continue;
}
if ((strlen(p_attr->data) + strlen(p_node->name) + xml_len) >= (size_t)buf_len)
{
return -1;
}
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, ">%s</%s>\r\n", p_attr->data, p_node->name);
return xml_len;
}
p_attr = p_attr->next;
}
if (p_node->f_child)
{
XMLN * p_child;
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, ">\r\n");
p_child = p_node->f_child;
while (p_child)
{
ret = xml_write_buf(p_child, xml_buf+xml_len, buf_len-xml_len);
if (ret < 0)
{
return ret;
}
xml_len += ret;
p_child = p_child->next;
}
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, "</%s>\r\n", p_node->name);
}
else if (p_node->data)
{
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, ">%s</%s>\r\n", p_node->data, p_node->name);
}
else
{
xml_len += snprintf(xml_buf+xml_len, buf_len-xml_len, "/>\r\n");
}
return xml_len;
}
void stream_startElement(void * userdata, const char * name, const char ** atts)
{
XMLN * parent;
XMLN * p_node;
XMLN ** pp_node = (XMLN **)userdata;
if (pp_node == NULL)
{
return;
}
parent = *pp_node;
p_node = xml_node_add(parent, name);
if (atts)
{
int i=0;
while (atts[i] != NULL)
{
if (atts[i+1] == NULL)
{
break;
}
xml_attr_add(p_node, atts[i], atts[i+1]);
i += 2;
}
}
*pp_node = p_node;
}
void stream_endElement(void * userdata, const char * name)
{
XMLN * p_node;
XMLN ** pp_node = (XMLN **)userdata;
if (pp_node == NULL)
{
return;
}
p_node = *pp_node;
if (p_node == NULL)
{
return;
}
p_node->finish = 1;
if (p_node->type == NTYPE_TAG && p_node->parent == NULL)
{
// parse finish
}
else
{
*pp_node = p_node->parent; // back up a level
}
}
void stream_charData(void* userdata, const char* s, int len)
{
XMLN * p_node;
XMLN ** pp_node = (XMLN **)userdata;
if (pp_node == NULL)
{
return;
}
p_node = *pp_node;
if (p_node == NULL)
{
return;
}
p_node->data = s;
p_node->dlen = len;
}
HT_API XMLN * xxx_hxml_parse(char * p_xml, int len)
{
int status;
XMLN * p_root = NULL;
XMLPRS parse;
memset(&parse, 0, sizeof(parse));
parse.userdata = &p_root;
parse.startElement = stream_startElement;
parse.endElement = stream_endElement;
parse.charData = stream_charData;
parse.xmlstart = p_xml;
parse.xmlend = p_xml + len;
parse.ptr = parse.xmlstart;
status = hxml_parse(&parse);
if (status < 0)
{
log_print(HT_LOG_ERR, "%s, err[%d]\r\n", __FUNCTION__, status);
xml_node_del(p_root);
p_root = NULL;
}
return p_root;
}