📄 apr_xml.c
字号:
default:
msg = "There was an unknown error within the XML body.";
break;
}
(void) apr_cpystrn(errbuf, msg, errbufsize);
return errbuf;
}
APU_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p,
apr_xml_parser **parser,
apr_xml_doc **ppdoc,
apr_file_t *xmlfd,
apr_size_t buffer_length)
{
apr_status_t rv;
char *buffer;
apr_size_t length;
*parser = apr_xml_parser_create(p);
if (*parser == NULL) {
/* FIXME: returning an error code would be nice,
* but we dont get one ;( */
return APR_EGENERAL;
}
buffer = apr_palloc(p, buffer_length);
length = buffer_length;
rv = apr_file_read(xmlfd, buffer, &length);
while (rv == APR_SUCCESS) {
rv = apr_xml_parser_feed(*parser, buffer, length);
if (rv != APR_SUCCESS) {
return rv;
}
length = buffer_length;
rv = apr_file_read(xmlfd, buffer, &length);
}
if (rv != APR_EOF) {
return rv;
}
rv = apr_xml_parser_done(*parser, ppdoc);
*parser = NULL;
return rv;
}
APU_DECLARE(void) apr_text_append(apr_pool_t * p, apr_text_header *hdr,
const char *text)
{
apr_text *t = apr_palloc(p, sizeof(*t));
t->text = text;
t->next = NULL;
if (hdr->first == NULL) {
/* no text elements yet */
hdr->first = hdr->last = t;
}
else {
/* append to the last text element */
hdr->last->next = t;
hdr->last = t;
}
}
/* ---------------------------------------------------------------
**
** XML UTILITY FUNCTIONS
*/
/*
** apr_xml_quote_string: quote an XML string
**
** Replace '<', '>', and '&' with '<', '>', and '&'.
** If quotes is true, then replace '"' with '"'.
**
** quotes is typically set to true for XML strings that will occur within
** double quotes -- attribute values.
*/
APU_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s,
int quotes)
{
const char *scan;
apr_size_t len = 0;
apr_size_t extra = 0;
char *qstr;
char *qscan;
char c;
for (scan = s; (c = *scan) != '\0'; ++scan, ++len) {
if (c == '<' || c == '>')
extra += 3; /* < or > */
else if (c == '&')
extra += 4; /* & */
else if (quotes && c == '"')
extra += 5; /* " */
}
/* nothing to do? */
if (extra == 0)
return s;
qstr = apr_palloc(p, len + extra + 1);
for (scan = s, qscan = qstr; (c = *scan) != '\0'; ++scan) {
if (c == '<') {
*qscan++ = '&';
*qscan++ = 'l';
*qscan++ = 't';
*qscan++ = ';';
}
else if (c == '>') {
*qscan++ = '&';
*qscan++ = 'g';
*qscan++ = 't';
*qscan++ = ';';
}
else if (c == '&') {
*qscan++ = '&';
*qscan++ = 'a';
*qscan++ = 'm';
*qscan++ = 'p';
*qscan++ = ';';
}
else if (quotes && c == '"') {
*qscan++ = '&';
*qscan++ = 'q';
*qscan++ = 'u';
*qscan++ = 'o';
*qscan++ = 't';
*qscan++ = ';';
}
else {
*qscan++ = c;
}
}
*qscan = '\0';
return qstr;
}
/* how many characters for the given integer? */
#define APR_XML_NS_LEN(ns) ((ns) < 10 ? 1 : (ns) < 100 ? 2 : (ns) < 1000 ? 3 : \
(ns) < 10000 ? 4 : (ns) < 100000 ? 5 : \
(ns) < 1000000 ? 6 : (ns) < 10000000 ? 7 : \
(ns) < 100000000 ? 8 : (ns) < 1000000000 ? 9 : 10)
static apr_size_t text_size(const apr_text *t)
{
apr_size_t size = 0;
for (; t; t = t->next)
size += strlen(t->text);
return size;
}
static apr_size_t elem_size(const apr_xml_elem *elem, int style,
apr_array_header_t *namespaces, int *ns_map)
{
apr_size_t size;
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
const apr_xml_attr *attr;
size = 0;
if (style == APR_XML_X2T_FULL_NS_LANG) {
int i;
/*
** The outer element will contain xmlns:ns%d="%s" attributes
** and an xml:lang attribute, if applicable.
*/
for (i = namespaces->nelts; i--;) {
/* compute size of: ' xmlns:ns%d="%s"' */
size += (9 + APR_XML_NS_LEN(i) + 2 +
strlen(APR_XML_GET_URI_ITEM(namespaces, i)) + 1);
}
if (elem->lang != NULL) {
/* compute size of: ' xml:lang="%s"' */
size += 11 + strlen(elem->lang) + 1;
}
}
if (elem->ns == APR_XML_NS_NONE) {
/* compute size of: <%s> */
size += 1 + strlen(elem->name) + 1;
}
else {
int ns = ns_map ? ns_map[elem->ns] : elem->ns;
/* compute size of: <ns%d:%s> */
size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(elem->name) + 1;
}
if (APR_XML_ELEM_IS_EMPTY(elem)) {
/* insert a closing "/" */
size += 1;
}
else {
/*
* two of above plus "/":
* <ns%d:%s> ... </ns%d:%s>
* OR <%s> ... </%s>
*/
size = 2 * size + 1;
}
for (attr = elem->attr; attr; attr = attr->next) {
if (attr->ns == APR_XML_NS_NONE) {
/* compute size of: ' %s="%s"' */
size += 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1;
}
else {
/* compute size of: ' ns%d:%s="%s"' */
int ns = ns_map ? ns_map[attr->ns] : attr->ns;
size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1;
}
}
/*
** If the element has an xml:lang value that is *different* from
** its parent, then add the thing in: ' xml:lang="%s"'.
**
** NOTE: we take advantage of the pointer equality established by
** the parsing for "inheriting" the xml:lang values from parents.
*/
if (elem->lang != NULL &&
(elem->parent == NULL || elem->lang != elem->parent->lang)) {
size += 11 + strlen(elem->lang) + 1;
}
}
else if (style == APR_XML_X2T_LANG_INNER) {
/*
* This style prepends the xml:lang value plus a null terminator.
* If a lang value is not present, then we insert a null term.
*/
size = elem->lang ? strlen(elem->lang) + 1 : 1;
}
else
size = 0;
size += text_size(elem->first_cdata.first);
for (elem = elem->first_child; elem; elem = elem->next) {
/* the size of the child element plus the CDATA that follows it */
size += (elem_size(elem, APR_XML_X2T_FULL, NULL, ns_map) +
text_size(elem->following_cdata.first));
}
return size;
}
static char *write_text(char *s, const apr_text *t)
{
for (; t; t = t->next) {
apr_size_t len = strlen(t->text);
memcpy(s, t->text, len);
s += len;
}
return s;
}
static char *write_elem(char *s, const apr_xml_elem *elem, int style,
apr_array_header_t *namespaces, int *ns_map)
{
const apr_xml_elem *child;
apr_size_t len;
int ns;
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
int empty = APR_XML_ELEM_IS_EMPTY(elem);
const apr_xml_attr *attr;
if (elem->ns == APR_XML_NS_NONE) {
len = sprintf(s, "<%s", elem->name);
}
else {
ns = ns_map ? ns_map[elem->ns] : elem->ns;
len = sprintf(s, "<ns%d:%s", ns, elem->name);
}
s += len;
for (attr = elem->attr; attr; attr = attr->next) {
if (attr->ns == APR_XML_NS_NONE)
len = sprintf(s, " %s=\"%s\"", attr->name, attr->value);
else {
ns = ns_map ? ns_map[attr->ns] : attr->ns;
len = sprintf(s, " ns%d:%s=\"%s\"", ns, attr->name, attr->value);
}
s += len;
}
/* add the xml:lang value if necessary */
if (elem->lang != NULL &&
(style == APR_XML_X2T_FULL_NS_LANG ||
elem->parent == NULL ||
elem->lang != elem->parent->lang)) {
len = sprintf(s, " xml:lang=\"%s\"", elem->lang);
s += len;
}
/* add namespace definitions, if required */
if (style == APR_XML_X2T_FULL_NS_LANG) {
int i;
for (i = namespaces->nelts; i--;) {
len = sprintf(s, " xmlns:ns%d=\"%s\"", i,
APR_XML_GET_URI_ITEM(namespaces, i));
s += len;
}
}
/* no more to do. close it up and go. */
if (empty) {
*s++ = '/';
*s++ = '>';
return s;
}
/* just close it */
*s++ = '>';
}
else if (style == APR_XML_X2T_LANG_INNER) {
/* prepend the xml:lang value */
if (elem->lang != NULL) {
len = strlen(elem->lang);
memcpy(s, elem->lang, len);
s += len;
}
*s++ = '\0';
}
s = write_text(s, elem->first_cdata.first);
for (child = elem->first_child; child; child = child->next) {
s = write_elem(s, child, APR_XML_X2T_FULL, NULL, ns_map);
s = write_text(s, child->following_cdata.first);
}
if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) {
if (elem->ns == APR_XML_NS_NONE) {
len = sprintf(s, "</%s>", elem->name);
}
else {
ns = ns_map ? ns_map[elem->ns] : elem->ns;
len = sprintf(s, "</ns%d:%s>", ns, elem->name);
}
s += len;
}
return s;
}
APU_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem)
{
apr_text *scan_txt;
apr_xml_attr *scan_attr;
apr_xml_elem *scan_elem;
/* convert the element's text */
for (scan_txt = elem->first_cdata.first;
scan_txt != NULL;
scan_txt = scan_txt->next) {
scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0);
}
for (scan_txt = elem->following_cdata.first;
scan_txt != NULL;
scan_txt = scan_txt->next) {
scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0);
}
/* convert the attribute values */
for (scan_attr = elem->attr;
scan_attr != NULL;
scan_attr = scan_attr->next) {
scan_attr->value = apr_xml_quote_string(p, scan_attr->value, 1);
}
/* convert the child elements */
for (scan_elem = elem->first_child;
scan_elem != NULL;
scan_elem = scan_elem->next) {
apr_xml_quote_elem(p, scan_elem);
}
}
/* convert an element to a text string */
APU_DECLARE(void) apr_xml_to_text(apr_pool_t * p, const apr_xml_elem *elem,
int style, apr_array_header_t *namespaces,
int *ns_map, const char **pbuf,
apr_size_t *psize)
{
/* get the exact size, plus a null terminator */
apr_size_t size = elem_size(elem, style, namespaces, ns_map) + 1;
char *s = apr_palloc(p, size);
(void) write_elem(s, elem, style, namespaces, ns_map);
s[size - 1] = '\0';
*pbuf = s;
if (psize)
*psize = size;
}
APU_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t * p,
const apr_xml_elem *elem)
{
if (elem->ns == APR_XML_NS_NONE) {
/*
* The prefix (xml...) is already within the prop name, or
* the element simply has no prefix.
*/
return apr_psprintf(p, "<%s/>" DEBUG_CR, elem->name);
}
return apr_psprintf(p, "<ns%d:%s/>" DEBUG_CR, elem->ns, elem->name);
}
/* return the URI's (existing) index, or insert it and return a new index */
APU_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array,
const char *uri)
{
int i;
const char **pelt;
/* never insert an empty URI; this index is always APR_XML_NS_NONE */
if (*uri == '\0')
return APR_XML_NS_NONE;
for (i = uri_array->nelts; i--;) {
if (strcmp(uri, APR_XML_GET_URI_ITEM(uri_array, i)) == 0)
return i;
}
pelt = apr_array_push(uri_array);
*pelt = uri; /* assume uri is const or in a pool */
return uri_array->nelts - 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -