Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of libdom.
  3.  * Licensed under the MIT License,
  4.  *                      http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
  6.  * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
  7.  */
  8.  
  9. #include <string.h>
  10.  
  11.  
  12. typedef unsigned int uint32_t;
  13.  
  14. #include <dom/dom.h>
  15.  
  16.  
  17.  
  18. #include "utils/namespace.h"
  19. #include "utils/validate.h"
  20. #include "utils/utils.h"
  21.  
  22.  
  23. /** XML prefix */
  24. static dom_string *xml;
  25. /** XMLNS prefix */
  26. static dom_string *xmlns;
  27.  
  28. /* The namespace strings */
  29. static const char *namespaces[DOM_NAMESPACE_COUNT] = {
  30.         NULL,
  31.         "http://www.w3.org/1999/xhtml",
  32.         "http://www.w3.org/1998/Math/MathML",
  33.         "http://www.w3.org/2000/svg",
  34.         "http://www.w3.org/1999/xlink",
  35.         "http://www.w3.org/XML/1998/namespace",
  36.         "http://www.w3.org/2000/xmlns/"
  37. };
  38.  
  39. dom_string *dom_namespaces[DOM_NAMESPACE_COUNT] = {
  40.         NULL,
  41. };
  42.  
  43. /**
  44.  * Initialise the namespace component
  45.  *
  46.  * \return DOM_NO_ERR on success.
  47.  */
  48. static dom_exception _dom_namespace_initialise(void)
  49. {
  50.         int i;
  51.         dom_exception err;
  52.  
  53.         err = dom_string_create((const uint8_t *) "xml", SLEN("xml"), &xml);
  54.         if (err != DOM_NO_ERR) {
  55.                 return err;
  56.         }
  57.  
  58.         err = dom_string_create((const uint8_t *) "xmlns", SLEN("xmlns"),
  59.                         &xmlns);
  60.         if (err != DOM_NO_ERR) {
  61.                 dom_string_unref(xml);
  62.                 xml = NULL;
  63.  
  64.                 return err;
  65.         }
  66.  
  67.         for (i = 1; i < DOM_NAMESPACE_COUNT; i++) {
  68.                 err = dom_string_create(
  69.                                 (const uint8_t *) namespaces[i],
  70.                                 strlen(namespaces[i]), &dom_namespaces[i]);
  71.                 if (err != DOM_NO_ERR) {
  72.                         dom_string_unref(xmlns);
  73.                         xmlns = NULL;
  74.  
  75.                         dom_string_unref(xml);
  76.                         xml = NULL;
  77.  
  78.                         return err;
  79.                 }
  80.         }
  81.  
  82.         return DOM_NO_ERR;
  83. }
  84.  
  85. #ifdef FINALISE_NAMESPACE
  86. /**
  87.  * Finalise the namespace component
  88.  *
  89.  * \return DOM_NO_ERR on success.
  90.  */
  91. dom_exception _dom_namespace_finalise(void)
  92. {
  93.         int i;
  94.  
  95.         if (xmlns != NULL) {
  96.                 dom_string_unref(xmlns);
  97.                 xmlns = NULL;
  98.         }
  99.  
  100.         if (xml != NULL) {
  101.                 dom_string_unref(xml);
  102.                 xml = NULL;
  103.         }
  104.  
  105.         for (i = 1; i < DOM_NAMESPACE_COUNT; i++) {
  106.                 if (dom_namespaces[i] != NULL) {
  107.                         dom_string_unref(dom_namespaces[i]);
  108.                         dom_namespaces[i] = NULL;
  109.                 }
  110.         }
  111.  
  112.         return DOM_NO_ERR;
  113. }
  114. #endif
  115.  
  116. /**
  117.  * Ensure a QName is valid
  118.  *
  119.  * \param qname      The qname to validate
  120.  * \param namespace  The namespace URI associated with the QName, or NULL
  121.  * \return DOM_NO_ERR                if valid,
  122.  *         DOM_INVALID_CHARACTER_ERR if ::qname contains an invalid character,
  123.  *         DOM_NAMESPACE_ERR         if ::qname is malformed, or it has a
  124.  *                                   prefix and ::namespace is NULL, or
  125.  *                                   ::qname has a prefix "xml" and
  126.  *                                   ::namespace is not
  127.  *                                   "http://www.w3.org/XML/1998/namespace",
  128.  *                                   or ::qname has a prefix "xmlns" and
  129.  *                                   ::namespace is not
  130.  *                                   "http://www.w3.org/2000/xmlns", or
  131.  *                                   ::namespace is
  132.  *                                   "http://www.w3.org/2000/xmlns" and
  133.  *                                   ::qname is not (or is not prefixed by)
  134.  *                                   "xmlns".
  135.  */
  136. dom_exception _dom_namespace_validate_qname(dom_string *qname,
  137.                 dom_string *namespace)
  138. {
  139.         uint32_t colon, len;
  140.  
  141.         if (xml == NULL) {
  142.                 dom_exception err = _dom_namespace_initialise();
  143.                 if (err != DOM_NO_ERR)
  144.                         return err;
  145.         }
  146.  
  147.         if (qname == NULL) {
  148.                 if (namespace != NULL)
  149.                         return DOM_NAMESPACE_ERR;
  150.                 if (namespace == NULL)
  151.                         return DOM_NO_ERR;
  152.         }
  153.  
  154.         if (_dom_validate_name(qname) == false)
  155.                 return DOM_NAMESPACE_ERR;
  156.  
  157.         len = dom_string_length(qname);
  158.  
  159.         /* Find colon */
  160.         colon = dom_string_index(qname, ':');
  161.  
  162.         if (colon == (uint32_t) -1) {
  163.                 /* No prefix */
  164.                 /* If namespace URI is for xmlns, ensure qname == "xmlns" */
  165.                 if (namespace != NULL &&
  166.                                 dom_string_isequal(namespace,
  167.                                 dom_namespaces[DOM_NAMESPACE_XMLNS]) &&
  168.                                 dom_string_isequal(qname, xmlns) == false) {
  169.                         return DOM_NAMESPACE_ERR;
  170.                 }
  171.  
  172.                 /* If qname == "xmlns", ensure namespace URI is for xmlns */
  173.                 if (namespace != NULL &&
  174.                                 dom_string_isequal(qname, xmlns) &&
  175.                                 dom_string_isequal(namespace,
  176.                                 dom_namespaces[DOM_NAMESPACE_XMLNS]) == false) {
  177.                         return DOM_NAMESPACE_ERR;
  178.                 }
  179.         } else if (colon == 0) {
  180.                 /* Some name like ":name" */
  181.                 if (namespace != NULL)
  182.                         return DOM_NAMESPACE_ERR;
  183.         } else {
  184.                 /* Prefix */
  185.                 dom_string *prefix;
  186.                 dom_string *lname;
  187.                 dom_exception err;
  188.  
  189.                 /* Ensure there is a namespace URI */
  190.                 if (namespace == NULL) {
  191.                         return DOM_NAMESPACE_ERR;
  192.                 }
  193.  
  194.                 err = dom_string_substr(qname, 0, colon, &prefix);
  195.                 if (err != DOM_NO_ERR) {
  196.                         return err;
  197.                 }
  198.  
  199.                 err = dom_string_substr(qname, colon + 1, len, &lname);
  200.                 if (err != DOM_NO_ERR) {
  201.                         return err;
  202.                 }
  203.  
  204.                 if (_dom_validate_ncname(prefix) == false ||
  205.                                 _dom_validate_ncname(lname) == false) {
  206.                         return DOM_NAMESPACE_ERR;
  207.                 }
  208.  
  209.                 /* Test for invalid XML namespace */
  210.                 if (dom_string_isequal(prefix, xml) &&
  211.                                 dom_string_isequal(namespace,
  212.                                 dom_namespaces[DOM_NAMESPACE_XML]) == false) {
  213.                         dom_string_unref(prefix);
  214.                         return DOM_NAMESPACE_ERR;
  215.                 }
  216.  
  217.                 /* Test for invalid xmlns namespace */
  218.                 if (dom_string_isequal(prefix, xmlns) &&
  219.                                 dom_string_isequal(namespace,
  220.                                 dom_namespaces[DOM_NAMESPACE_XMLNS]) == false) {
  221.                         dom_string_unref(prefix);
  222.                         return DOM_NAMESPACE_ERR;
  223.                 }
  224.  
  225.                 /* Test for presence of xmlns namespace with non xmlns prefix */
  226.                 if (dom_string_isequal(namespace,
  227.                                 dom_namespaces[DOM_NAMESPACE_XMLNS]) &&
  228.                                 dom_string_isequal(prefix, xmlns) == false) {
  229.                         dom_string_unref(prefix);
  230.                         return DOM_NAMESPACE_ERR;
  231.                 }
  232.  
  233.                 dom_string_unref(prefix);
  234.         }
  235.  
  236.         return DOM_NO_ERR;
  237. }
  238.  
  239. /**
  240.  * Split a QName into a namespace prefix and localname string
  241.  *
  242.  * \param qname      The qname to split
  243.  * \param prefix     Pointer to location to receive prefix
  244.  * \param localname  Pointer to location to receive localname
  245.  * \return DOM_NO_ERR on success.
  246.  *
  247.  * If there is no prefix present in ::qname, then ::prefix will be NULL.
  248.  *
  249.  * ::prefix and ::localname will be referenced. The caller should unreference
  250.  * them once finished.
  251.  */
  252. dom_exception _dom_namespace_split_qname(dom_string *qname,
  253.                 dom_string **prefix, dom_string **localname)
  254. {
  255.         uint32_t colon;
  256.         dom_exception err;
  257.  
  258.         if (xml == NULL) {
  259.                 err = _dom_namespace_initialise();
  260.                 if (err != DOM_NO_ERR)
  261.                         return err;
  262.         }
  263.  
  264.         /* Find colon, if any */
  265.         colon = dom_string_index(qname, ':');
  266.  
  267.         if (colon == (uint32_t) -1) {
  268.                 /* None found => no prefix */
  269.                 *prefix = NULL;
  270.                 *localname = dom_string_ref(qname);
  271.         } else {
  272.                 /* Found one => prefix */
  273.                 err = dom_string_substr(qname, 0, colon, prefix);
  274.                 if (err != DOM_NO_ERR) {
  275.                         return err;
  276.                 }
  277.  
  278.                 err = dom_string_substr(qname, colon + 1,
  279.                                 dom_string_length(qname), localname);
  280.                 if (err != DOM_NO_ERR) {
  281.                         dom_string_unref(*prefix);
  282.                         *prefix = NULL;
  283.                         return err;
  284.                 }
  285.         }
  286.  
  287.         return DOM_NO_ERR;
  288. }
  289.  
  290. /**
  291.  * Get the XML prefix dom_string
  292.  *
  293.  * \return the xml prefix dom_string.
  294.  *
  295.  * Note: The client of this function may or may not call the dom_string_ref
  296.  * on the returned dom_string, because this string will only be destroyed when
  297.  * the dom_finalise is called. But if the client call dom_string_ref, it must
  298.  * call dom_string_unref to maintain a correct ref count of the dom_string.
  299.  */
  300. dom_string *_dom_namespace_get_xml_prefix(void)
  301. {
  302.         if (xml == NULL) {
  303.                 if (_dom_namespace_initialise() != DOM_NO_ERR)
  304.                         return NULL;
  305.         }
  306.  
  307.         return xml;
  308. }
  309.  
  310. /**
  311.  * Get the XMLNS prefix dom_string.
  312.  *
  313.  * \return the xmlns prefix dom_string
  314.  *
  315.  * Note: The client of this function may or may not call the dom_string_ref
  316.  * on the returned dom_string, because this string will only be destroyed when
  317.  * the dom_finalise is called. But if the client call dom_string_ref, it must
  318.  * call dom_string_unref to maintain a correct ref count of the dom_string.
  319.  */
  320. dom_string *_dom_namespace_get_xmlns_prefix(void)
  321. {
  322.         if (xml == NULL) {
  323.                 if (_dom_namespace_initialise() != DOM_NO_ERR)
  324.                         return NULL;
  325.         }
  326.  
  327.         return xmlns;
  328. }
  329.  
  330.