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

608 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 "xml_node.h"
#include "hxml.h"
/***************************************************************************************/
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
#define IS_XMLH_START(ptr) (*ptr == '<' && *(ptr+1) == '?')
#define IS_XMLH_END(ptr) (*ptr == '?' && *(ptr+1) == '>')
/***************************************************************************************/
#define IS_ELEMS_END(ptr) (*ptr == '>' || (*ptr == '/' && *(ptr+1) == '>'))
#define IS_ELEME_START(ptr) (*ptr == '<' && *(ptr+1) == '/')
#define CHECK_XML_STACK_RET(parse) \
do{ if(parse->e_stack_index >= XML_MAX_STACK_DEPTH || parse->e_stack_index < 0) return -1;}while(0)
#define RF_NO_END 0
#define RF_ELES_END 2
#define RF_ELEE_END 3
#define CUR_PARSE_START 1
#define CUR_PARSE_END 2
/***************************************************************************************/
HT_API int hxml_parse_header(XMLPRS * parse)
{
char * ptr = parse->ptr;
char * xmlend = parse->xmlend;
while (IS_WHITE_SPACE(*ptr) && (ptr != xmlend))
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
if (!IS_XMLH_START(ptr))
{
return -1;
}
ptr+=2;
while ((!IS_XMLH_END(ptr)) && (ptr != xmlend))
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
ptr+=2;
parse->ptr = ptr;
return 0;
}
/***************************************************************************************/
HT_API int hxml_parse_attr(XMLPRS * parse)
{
char * ptr = parse->ptr;
char * xmlend = parse->xmlend;
int ret = RF_NO_END;
int cnt = 0;
int len;
while (1)
{
int index;
char * attr_name;
char * attr_value;
ret = RF_NO_END;
while (IS_WHITE_SPACE(*ptr) && (ptr != xmlend))
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
if (*ptr == '>')
{
*ptr = '\0';
ptr++;
ret = RF_ELES_END; // node start finish
break;
}
else if (*ptr == '/' && *(ptr+1) == '>')
{
*ptr = '\0';
ptr += 2;
ret = RF_ELEE_END; // node end finish
break;
}
attr_name = ptr;
while (*ptr != '=' && (!IS_ELEMS_END(ptr)) && ptr != xmlend)
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
if (IS_ELEMS_END(ptr))
{
if (*ptr == '>')
{
ret = RF_ELES_END;
*ptr = '\0';
ptr++;
}
else if (*ptr == '/' && *(ptr+1) == '>')
{
ret = RF_ELEE_END;
*ptr = '\0';
ptr+=2;
}
break;
}
len = ptr - attr_name;
while (len > 0 && attr_name[len-1] == ' ')
{
attr_name[len-1] = '\0';
len--;
}
*ptr = '\0'; // '=' --> '\0'
ptr++;
while (IS_WHITE_SPACE(*ptr) && (ptr != xmlend))
{
ptr++;
}
attr_value = ptr;
if (*ptr == '"')
{
attr_value++;
ptr++;
while (*ptr != '"' && ptr != xmlend)
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
*ptr = '\0'; // '"' --> '\0'
ptr++;
}
else
{
while ((!IS_WHITE_SPACE(*ptr)) && (!IS_ELEMS_END(ptr)) && ptr != xmlend)
{
ptr++;
}
if (ptr == xmlend)
{
return -1;
}
if (IS_WHITE_SPACE(*ptr))
{
*ptr = '\0';
ptr++;
}
else
{
if (*ptr == '>')
{
ret = RF_ELES_END;
*ptr = '\0';
ptr++;
}
else if (*ptr == '/' && *(ptr+1) == '>')
{
ret = RF_ELEE_END;
*ptr = '\0';
ptr+=2;
}
}
}
index = cnt << 1;
if (index < XML_MAX_ATTR_NUM - 2)
{
parse->attr[index] = attr_name;
parse->attr[index+1] = attr_value;
}
cnt++;
if (ret > RF_NO_END)
{
break;
}
}
parse->ptr = ptr;
return ret;
}
HT_API int hxml_parse_element_end(XMLPRS * parse)
{
char * xmlend;
char * stack_name;
char * end_name;
stack_name = parse->e_stack[parse->e_stack_index];
if (stack_name == NULL)
{
return -1;
}
xmlend = parse->xmlend;
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
end_name = (parse->ptr);
while ((!IS_WHITE_SPACE(*(parse->ptr))) && ((parse->ptr) != xmlend) && (*(parse->ptr) != '>'))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
if (IS_WHITE_SPACE(*(parse->ptr)))
{
*(parse->ptr) = '\0';
(parse->ptr)++;
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
}
if (*(parse->ptr) != '>')
{
return -1;
}
*(parse->ptr) = '\0';
(parse->ptr)++;
if (strcasecmp(end_name, stack_name) != 0)
{
log_print(HT_LOG_ERR, "%s, cur name[%s] != stack name[%s]!!!\r\n", __FUNCTION__, end_name, stack_name);
return -1;
}
if (parse->endElement)
{
parse->endElement(parse->userdata, end_name);
}
parse->e_stack[parse->e_stack_index] = NULL;
parse->e_stack_index--;
CHECK_XML_STACK_RET(parse);
return 0;
}
HT_API int hxml_parse_element_start(XMLPRS * parse)
{
char * xmlend;
char * element_name;
xmlend = parse->xmlend;
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
element_name = (parse->ptr);
while ((!IS_WHITE_SPACE(*(parse->ptr))) && ((parse->ptr) != xmlend) && (!IS_ELEMS_END((parse->ptr))))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
parse->e_stack_index++;
parse->e_stack[parse->e_stack_index] = element_name;
CHECK_XML_STACK_RET(parse);
if (*(parse->ptr) == '>')
{
*(parse->ptr) = '\0';
(parse->ptr)++;
if (parse->startElement)
{
parse->startElement(parse->userdata, element_name, (const char **)parse->attr);
}
return RF_ELES_END;
}
else if (*(parse->ptr) == '/' && *((parse->ptr)+1) == '>')
{
*(parse->ptr) = '\0';
(parse->ptr)+=2;
if (parse->startElement)
{
parse->startElement(parse->userdata, element_name, (const char **)parse->attr);
}
if (parse->endElement)
{
parse->endElement(parse->userdata, element_name);
}
parse->e_stack[parse->e_stack_index] = NULL;
parse->e_stack_index--;
CHECK_XML_STACK_RET(parse);
return RF_ELEE_END;
}
else
{
int ret;
*(parse->ptr) = '\0';
(parse->ptr)++;
ret = hxml_parse_attr(parse);
if (ret < 0)
{
return -1;
}
if (parse->startElement)
{
parse->startElement(parse->userdata, element_name, (const char **)parse->attr);
}
memset(parse->attr, 0, sizeof(parse->attr));
if (ret == RF_ELEE_END)
{
if (parse->endElement)
{
parse->endElement(parse->userdata, element_name);
}
parse->e_stack[parse->e_stack_index] = NULL;
parse->e_stack_index--;
CHECK_XML_STACK_RET(parse);
}
return ret;
}
}
HT_API int hxml_parse_element(XMLPRS * parse)
{
char * xmlend = parse->xmlend;
int parse_type = CUR_PARSE_START;
while (1)
{
int ret = RF_NO_END;
xml_parse_type:
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
if (parse->e_stack_index == 0)
{
return 0;
}
return -1;
}
if (*(parse->ptr) == '<' && *((parse->ptr)+1) == '/')
{
(parse->ptr)+=2;
parse_type = CUR_PARSE_END;
}
else if (*(parse->ptr) == '<' && *((parse->ptr)+1) == '!' && *((parse->ptr)+2) == '-' && *((parse->ptr)+3) == '-')
{
(parse->ptr)+=4;
while (((parse->ptr) != xmlend) && ((parse->ptr)+1) != xmlend && ((parse->ptr)+2) != xmlend)
{
if (*(parse->ptr) == '-' && *((parse->ptr)+1) == '-' && *((parse->ptr)+2) == '>')
{
(parse->ptr)+=3;
goto xml_parse_type;
}
(parse->ptr)++;
}
}
else if (*(parse->ptr) == '<')
{
(parse->ptr)++;
parse_type = CUR_PARSE_START;
}
else
{
return -1;
}
//xml_parse_point:
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
if (parse->e_stack_index == 0)
{
return 0;
}
return -1;
}
if (parse_type == CUR_PARSE_END)
{
ret = hxml_parse_element_end(parse);
if (ret < 0)
{
return -1;
}
if (parse->e_stack_index == 0)
{
return 0;
}
parse_type = CUR_PARSE_START;
}
else // CUR_PARSE_START
{
int len;
char * cdata_ptr;
ret = hxml_parse_element_start(parse);
if (ret < 0)
{
return -1;
}
if (ret == RF_ELEE_END)
{
if (parse->e_stack_index == 0)
{
return 0;
}
parse_type = CUR_PARSE_START;
goto xml_parse_type;
}
while (IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend))
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
if (*(parse->ptr) == '<')
{
goto xml_parse_type;
}
cdata_ptr = (parse->ptr);
while (*(parse->ptr) != '<' && (parse->ptr) != xmlend)
{
(parse->ptr)++;
}
if ((parse->ptr) == xmlend)
{
return -1;
}
len = (int)(parse->ptr - cdata_ptr);
if (len > 0)
{
*(parse->ptr) = '\0';
(parse->ptr)++;
if (parse->charData)
{
parse->charData(parse->userdata, cdata_ptr, len);
}
if (*(parse->ptr) != '/')
{
return -1;
}
(parse->ptr)++;
if (hxml_parse_element_end(parse) < 0)
{
return -1;
}
}
goto xml_parse_type;
}
}
return 0;
}
HT_API int hxml_parse(XMLPRS * parse)
{
hxml_parse_header(parse);
return hxml_parse_element(parse);
}