static apr_size_t elem_size()

in xml/apr_xml.c [555:675]


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 ||
        style == APR_XML_X2T_PARSED) {
        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;
            }
        }
        else if (style == APR_XML_X2T_PARSED) {
            apr_xml_ns_scope *ns_scope = elem->ns_scope;

            /* compute size of: ' xmlns:%s="%s"' */
            for (; ns_scope; ns_scope = ns_scope->next) {
                size += 10 + strlen(find_prefix_name(elem, ns_scope->ns, 0)) +
                             strlen(APR_XML_GET_URI_ITEM(namespaces, ns_scope->ns));
            }

            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 if (style == APR_XML_X2T_PARSED) {
            /* compute size of: <%s:%s> */
            size += 3 + strlen(find_prefix_name(elem, elem->ns, 1)) + strlen(elem->name);
        }
        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 if (style == APR_XML_X2T_PARSED) {
                /* compute size of: ' %s:%s="%s"' */
                size += 5 + strlen(find_prefix_name(elem, attr->ns, 1)) + strlen(attr->name) + strlen(attr->value);
            }
            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, style == APR_XML_X2T_PARSED ? APR_XML_X2T_PARSED : APR_XML_X2T_FULL, NULL, ns_map) +
                 text_size(elem->following_cdata.first));
    }

    return size;
}