hackedteam/vector-rmi

View on GitHub
wps/wbxml2/wbxml_tree_clb_xml.c

Summary

Maintainability
Test Coverage
/*
 * libwbxml, the WBXML Library.
 * Copyright (C) 2002-2005 Aymerick Jehanne <aymerick@jehanne.org>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * LGPL v2.1: http://www.gnu.org/copyleft/lesser.txt
 * 
 * Contact: libwbxml@aymerick.com
 * Home: http://libwbxml.aymerick.com
 */
 
/**
 * @file wbxml_tree_clb_xml.c
 * @ingroup wbxml_tree
 *
 * @author Aymerick Jehanne <libwbxml@aymerick.com>
 * @date 03/03/11
 *
 * @brief WBXML Tree Callbacks for XML Parser (Expat)
 */

#if defined( HAVE_EXPAT )

#include "wbxml.h"


/************************************
 *  Public Functions
 */

void wbxml_tree_clb_xml_decl(void           *ctx,
                             const XML_Char *version,
                             const XML_Char *encoding,
                             int             standalone)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* This handler is called for XML declarations and also for text declarations discovered 
     * in external entities. The way to distinguish is that the version parameter will
     * be NULL for text declarations.
     */
    if (version != NULL) {
        if (encoding != NULL) {
            /* Get encoding */
            if (!wbxml_charset_get_mib((const WB_TINY*)encoding, &(tree_ctx->tree->orig_charset))) {
                WBXML_WARNING((WBXML_CONV, "Charset Encoding not supported: %s", encoding));
            }
        }
    }
}


void wbxml_tree_clb_xml_doctype_decl(void           *ctx, 
                                     const XML_Char *doctypeName, 
                                     const XML_Char *sysid,
                                     const XML_Char *pubid, 
                                     int             has_internal_subset)
{    
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;
    const WBXMLLangEntry *lang_table = NULL;

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* Search for Language Table, given the XML Public ID and System ID */
    lang_table = wbxml_tables_search_table(wbxml_tables_get_main(), 
                                           (const WB_UTINY *) pubid, 
                                           (const WB_UTINY *) sysid, 
                                           NULL);

    if (lang_table != NULL) {
        /* Ho Yeah ! We got it ! */
        tree_ctx->tree->lang = lang_table;
    }
    else {
        /* We will try to find the Language Table, given the Root Element */
        WBXML_WARNING((WBXML_CONV, "Language Table NOT found, given the XML Public ID and System ID"));
    }
}


void wbxml_tree_clb_xml_start_element(void           *ctx,
                                      const XML_Char *localName,
                                      const XML_Char **attrs)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;
    const WBXMLLangEntry *lang_table = NULL;

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0) {
        tree_ctx->skip_lvl++;
        return;
    }

    if (tree_ctx->current == NULL) {
        /* This is the Root Element */
        if (tree_ctx->tree->lang == NULL) {
            /* Language Table not already found: Search again */
            lang_table = wbxml_tables_search_table(wbxml_tables_get_main(), 
                                                   NULL, 
                                                   NULL, 
                                                   (const WB_UTINY *) localName);
        
            if (lang_table == NULL) {
                /* Damn, this is an unknown language for us... */
                tree_ctx->error = WBXML_ERROR_UNKNOWN_XML_LANGUAGE;
                return;
            }
            else {
                /* Well, we hope this was the Language we are searching for.. let's try with it :| */
                tree_ctx->tree->lang = lang_table;
            }
        }
    }

#if defined( WBXML_SUPPORT_SYNCML )

    /* If this is an embedded (not root) "DevInf" document, skip it */
    if ((WBXML_STRCMP(localName, "DevInf") == 0) &&
        (tree_ctx->current != NULL))
    {
        tree_ctx->skip_start = XML_GetCurrentByteIndex(tree_ctx->xml_parser);

        /* Skip this node */
        tree_ctx->skip_lvl++;

        return;
    }

#endif /* WBXML_SUPPORT_SYNCML */

    /* Add Element Node */
    tree_ctx->current = wbxml_tree_add_xml_elt_with_attrs(tree_ctx->tree,
                                                          tree_ctx->current,
                                                          (WB_UTINY *) localName,
                                                          (const WB_UTINY**) attrs);

    if (tree_ctx->current == NULL) {
        tree_ctx->error = WBXML_ERROR_NOT_ENOUGH_MEMORY;
    }
}


void wbxml_tree_clb_xml_end_element(void           *ctx,
                                    const XML_Char *localName)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;
#if defined( WBXML_SUPPORT_SYNCML )
    WBXMLBuffer *devinf_doc = NULL;
    WBXMLTree *tree = NULL;
    WBXMLError ret = WBXML_OK;
#endif /* WBXML_SUPPORT_SYNCML */

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0) {
        if (tree_ctx->skip_lvl == 1)
        {
            /* End of skipped node */

#if defined( WBXML_SUPPORT_SYNCML )
            if (WBXML_STRCMP(localName, "DevInf") == 0) {
                /* Get embedded DevInf Document */
                devinf_doc = wbxml_buffer_create(tree_ctx->input_buff + tree_ctx->skip_start, 
                                                 XML_GetCurrentByteIndex(tree_ctx->xml_parser) - tree_ctx->skip_start,
                                                 XML_GetCurrentByteIndex(tree_ctx->xml_parser) - tree_ctx->skip_start + 10);

                if (tree_ctx->expat_utf16) {
                    /** @todo Convert from UTF-16 to UTF-8 */
                }

                /* Check Buffer Creation and addd </DevInf> ending tag */
                if ((devinf_doc == NULL) || (!wbxml_buffer_append_cstr(devinf_doc, "</DevInf>")))
                {
                    tree_ctx->error = WBXML_ERROR_NOT_ENOUGH_MEMORY;
                    wbxml_buffer_destroy(devinf_doc);
                    return;
                }

                WBXML_DEBUG((WBXML_PARSER, "\t DevInf Doc : '%s'", wbxml_buffer_get_cstr(devinf_doc)));

                /* Parse 'DevInf' Document */
                if ((ret = wbxml_tree_from_xml(wbxml_buffer_get_cstr(devinf_doc),
                                               wbxml_buffer_len(devinf_doc),
                                               &tree)) != WBXML_OK)
                {
                    tree_ctx->error = ret;
                    wbxml_buffer_destroy(devinf_doc);
                    return;
                }

                /* Add Tree Node */
                tree_ctx->current = wbxml_tree_add_tree(tree_ctx->tree,
                                                        tree_ctx->current,
                                                        tree);
                if (tree_ctx->current == NULL)
                {
                    tree_ctx->error = WBXML_ERROR_INTERNAL;
                    wbxml_tree_destroy(tree);
                    wbxml_buffer_destroy(devinf_doc);
                    return;
                }

                /* Clean-up */
                wbxml_buffer_destroy(devinf_doc);
                tree_ctx->skip_lvl = 0;
            }
#endif /* WBXML_SUPPORT_SYNCML */
        }
        else {
            tree_ctx->skip_lvl--;
            return;
        }
    }

    if (tree_ctx->current == NULL) {
        tree_ctx->error = WBXML_ERROR_INTERNAL;
        return;
    }

    if (tree_ctx->current->parent == NULL) {
        /* This must be the Root Element */
        if (tree_ctx->current != tree_ctx->tree->root) {
            tree_ctx->error = WBXML_ERROR_INTERNAL;
        }
    }
    else {
#if defined ( WBXML_SUPPORT_SYNCML )
        /* Have we added a missing CDATA section ? 
         * If so, we assume that now that we have reached an end of Element, 
         * the CDATA section ended, and so we go back to parent.
         */
        if ((tree_ctx->current != NULL) && (tree_ctx->current->type == WBXML_TREE_CDATA_NODE))
            tree_ctx->current = tree_ctx->current->parent;
#endif /* WBXML_SUPPORT_SYNCML */

        /* Go back one step upper in the tree */
        tree_ctx->current = tree_ctx->current->parent;
    }
}


void wbxml_tree_clb_xml_start_cdata(void *ctx)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0)
        return;

    /* Add CDATA Node */
    tree_ctx->current = wbxml_tree_add_cdata(tree_ctx->tree, tree_ctx->current);
    if (tree_ctx->current == NULL) {
        tree_ctx->error = WBXML_ERROR_INTERNAL;
    }
}


void wbxml_tree_clb_xml_end_cdata(void *ctx)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0)
        return;
        
    if (tree_ctx->current == NULL) {
        tree_ctx->error = WBXML_ERROR_INTERNAL;
        return;
    }

    if (tree_ctx->current->parent == NULL) {
        /* This must be the Root Element */
        if (tree_ctx->current != tree_ctx->tree->root) {
            tree_ctx->error = WBXML_ERROR_INTERNAL;
        }
    }
    else {
        /* Go back one step upper in the tree */
        tree_ctx->current = tree_ctx->current->parent;
    }
}


void wbxml_tree_clb_xml_characters(void           *ctx,
                                   const XML_Char *ch,
                                   int             len)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0)
        return;

#if defined ( WBXML_SUPPORT_SYNCML )
    /* Specific treatment for SyncML */
    switch (wbxml_tree_node_get_syncml_data_type(tree_ctx->current)) {
    case WBXML_SYNCML_DATA_TYPE_CLEAR:
    case WBXML_SYNCML_DATA_TYPE_DIRECTORY_VCARD:
    case WBXML_SYNCML_DATA_TYPE_VCALENDAR:
    case WBXML_SYNCML_DATA_TYPE_VCARD:
    case WBXML_SYNCML_DATA_TYPE_VOBJECT:
        /*
         * Add a missing CDATA section node
         *
         * Example:
         * <Add>
         *   <CmdID>6</CmdID>
         *   <Meta><Type xmlns='syncml:metinf'>text/x-vcard</Type></Meta>
         *   <Item>
         *     <Source>
         *         <LocURI>pas-id-3F4B790300000000</LocURI>
         *     </Source>         
         *     <Data>BEGIN:VCARD
         *  VERSION:2.1
         *  X-EVOLUTION-FILE-AS:Ximian, Inc.
         *  N:
         *  LABEL;WORK;ENCODING=QUOTED-PRINTABLE:401 Park Drive  3 West=0ABoston, MA
         *  02215=0AUSA
         *  TEL;WORK;VOICE:(617) 236-0442
         *  TEL;WORK;FAX:(617) 236-8630
         *  EMAIL;INTERNET:[EMAIL PROTECTED]
         *  URL:www.ximian.com/
         *  ORG:Ximian, Inc.
         *  NOTE:Welcome to the Ximian Addressbook.
         *  UID:pas-id-3F4B790300000000
         *  END:VCARD</Data>
         *   </Item>
         * </Add>
         *
         * The end of CDATA section is assumed to be reached when parsing the end 
         * of </Data> element.
         *
         * This kind of document is erroneous, but we must handle it.
         * Normally, this should be:
         *
         *  ...
         *     <Data><!CDATA[[BEGIN:VCARD
         *  VERSION:2.1
         *  X-EVOLUTION-FILE-AS:Ximian, Inc.
         *  ...
         *  UID:pas-id-3F4B790300000000
         *  END:VCARD
         *  ]]></Data>
         *  ...
         */

        /* 
         * We add a missing CDATA section if we are not already in a CDATA section.
         *
         * We don't add a CDATA section if we have already added a CDATA section. This
         * permits to correctly handle good XML documents like this:
         *
         *  ...
         *     <Data><!CDATA[[BEGIN:VCARD
         *  VERSION:2.1
         *  X-EVOLUTION-FILE-AS:Ximian, Inc.
         *  ...
         *  UID:pas-id-3F4B790300000000
         *  END:VCARD
         *  ]]>
         *     </Data>
         *  ...
         *
         * In this example, the spaces beetwen "]]>" and "</Data>" mustn't be added
         * to a CDATA section. 
         */
        if ((tree_ctx->current != NULL) && 
            (tree_ctx->current->type != WBXML_TREE_CDATA_NODE) &&
            !((tree_ctx->current->children != NULL) && 
              (tree_ctx->current->children->type == WBXML_TREE_CDATA_NODE)))
        {
            /* Add CDATA Node */
            tree_ctx->current = wbxml_tree_add_cdata(tree_ctx->tree, tree_ctx->current);
            if (tree_ctx->current == NULL) {
                tree_ctx->error = WBXML_ERROR_INTERNAL;
                return;
            }
        }

        /* Now we can add the Text Node */
        break;

    default:
        /* NOP */
        break;
    } /* switch */
#endif /* WBXML_SUPPORT_SYNCML */

    /* Add Text Node */
    if (wbxml_tree_add_text(tree_ctx->tree,
                            tree_ctx->current,
                            (const WB_UTINY*) ch,
                            len) == NULL)
    {
        tree_ctx->error = WBXML_ERROR_INTERNAL;
    }
}


void wbxml_tree_clb_xml_pi(void           *ctx,
                           const XML_Char *target,
                           const XML_Char *data)
{
    WBXMLTreeClbCtx *tree_ctx = (WBXMLTreeClbCtx *) ctx;

    if (tree_ctx->expat_utf16) {
        /** @todo Convert from UTF-16 to UTF-8 */
    }

    /* Check for Error */
    if (tree_ctx->error != WBXML_OK)
        return;

    /* Are we skipping a whole node ? */
    if (tree_ctx->skip_lvl > 0)
        return;

    /** @todo wbxml2xml_clb_pi() */
}

#endif /* HAVE_EXPAT */