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.  * Copyright 2012 Daniel Silverstone <dsilvers@netsurf-browser.org>
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12.  
  13. #include "/home/sourcerer/kos_src/newenginek/kolibri/include/hubbub/errors.h"
  14. #include "/home/sourcerer/kos_src/newenginek/kolibri/include/hubbub/hubbub.h"
  15. #include "/home/sourcerer/kos_src/newenginek/kolibri/include/hubbub/parser.h"
  16.  
  17. #include <dom/dom.h>
  18.  
  19. #include "errors.h"
  20. #include "parser.h"
  21. #include "utils.h"
  22.  
  23. #include "core/document.h"
  24. #include "core/string.h"
  25. #include "core/node.h"
  26.  
  27. #include "html/html_document.h"
  28. #include "html/html_button_element.h"
  29. #include "html/html_input_element.h"
  30. #include "html/html_select_element.h"
  31. #include "html/html_text_area_element.h"
  32.  
  33. #include <libwapcaplet/libwapcaplet.h>
  34.  
  35. /**
  36.  * libdom Hubbub parser context
  37.  */
  38. struct dom_hubbub_parser {
  39.         hubbub_parser *parser;          /**< Hubbub parser instance */
  40.         hubbub_tree_handler tree_handler;
  41.                                         /**< Hubbub parser tree handler */
  42.  
  43.         struct dom_document *doc;       /**< DOM Document we're building */
  44.  
  45.         dom_hubbub_encoding_source encoding_source;
  46.                                         /**< The document's encoding source */
  47.         const char *encoding;           /**< The document's encoding */
  48.  
  49.         bool complete;                  /**< Indicate stream completion */
  50.  
  51.         dom_msg msg;            /**< Informational messaging function */
  52.  
  53.         dom_script script;      /**< Script callback function */
  54.  
  55.         void *mctx;             /**< Pointer to client data */
  56. };
  57.  
  58. /* Forward declaration to break reference loop */
  59. static hubbub_error add_attributes(void *parser, void *node, const hubbub_attribute *attributes, uint32_t n_attributes);
  60.  
  61.  
  62.  
  63.  
  64.  
  65. /*--------------------- The callbacks definitions --------------------*/
  66. static hubbub_error create_comment(void *parser, const hubbub_string *data,
  67.                 void **result)
  68. {
  69.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  70.         dom_exception err;
  71.         dom_string *str;
  72.         struct dom_comment *comment;
  73.  
  74.         *result = NULL;
  75.  
  76.         err = dom_string_create(data->ptr, data->len, &str);
  77.         if (err != DOM_NO_ERR) {
  78.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  79.                                 "Can't create comment node text");
  80.                 return HUBBUB_UNKNOWN;
  81.         }
  82.  
  83.         err = dom_document_create_comment(dom_parser->doc, str, &comment);
  84.         if (err != DOM_NO_ERR) {
  85.                 dom_string_unref(str);
  86.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  87.                                 "Can't create comment node with text '%.*s'",
  88.                                 data->len, data->ptr);
  89.                 return HUBBUB_UNKNOWN;
  90.         }
  91.  
  92.         *result = comment;
  93.  
  94.         dom_string_unref(str);
  95.  
  96.         return HUBBUB_OK;
  97. }
  98.  
  99. static char *parser_strndup(const char *s, size_t n)
  100. {
  101.         size_t len;
  102.         char *s2;
  103.  
  104.         for (len = 0; len != n && s[len] != '\0'; len++)
  105.                 continue;
  106.  
  107.         s2 = malloc(len + 1);
  108.         if (s2 == NULL)
  109.                 return NULL;
  110.  
  111.         memcpy(s2, s, len);
  112.         s2[len] = '\0';
  113.         return s2;
  114. }
  115.  
  116. static hubbub_error create_doctype(void *parser, const hubbub_doctype *doctype,
  117.                 void **result)
  118. {
  119.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  120.         dom_exception err;
  121.         char *qname, *public_id = NULL, *system_id = NULL;
  122.         struct dom_document_type *dtype;
  123.  
  124.         *result = NULL;
  125.  
  126.         qname = parser_strndup((const char *) doctype->name.ptr,
  127.                         (size_t) doctype->name.len);
  128.         if (qname == NULL) {
  129.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  130.                                 "Can't create doctype name");
  131.                 goto fail;
  132.         }
  133.  
  134.         if (doctype->public_missing == false) {
  135.                 public_id = parser_strndup(
  136.                                 (const char *) doctype->public_id.ptr,
  137.                                 (size_t) doctype->public_id.len);
  138.         } else {
  139.                 public_id = strdup("");
  140.         }
  141.         if (public_id == NULL) {
  142.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  143.                                 "Can't create doctype public id");
  144.                 goto clean1;
  145.         }
  146.  
  147.         if (doctype->system_missing == false) {
  148.                 system_id = parser_strndup(
  149.                                 (const char *) doctype->system_id.ptr,
  150.                                 (size_t) doctype->system_id.len);
  151.         } else {
  152.                 system_id = strdup("");
  153.         }
  154.         if (system_id == NULL) {
  155.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  156.                                 "Can't create doctype system id");
  157.                 goto clean2;
  158.         }
  159.  
  160.         err = dom_implementation_create_document_type(qname,
  161.                         public_id, system_id, &dtype);
  162.         if (err != DOM_NO_ERR) {
  163.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  164.                                 "Can't create the document type");
  165.                 goto clean3;
  166.         }
  167.  
  168.         *result = dtype;
  169.  
  170. clean3:
  171.         free(system_id);
  172.  
  173. clean2:
  174.         free(public_id);
  175.  
  176. clean1:
  177.         free(qname);
  178.  
  179. fail:
  180.         if (*result == NULL)
  181.                 return HUBBUB_UNKNOWN;
  182.         else
  183.                 return HUBBUB_OK;
  184. }
  185.  
  186. static hubbub_error create_element(void *parser, const hubbub_tag *tag,
  187.                 void **result)
  188. {
  189.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  190.         dom_exception err;
  191.         dom_string *name;
  192.         struct dom_element *element = NULL;
  193.         hubbub_error herr;
  194.  
  195.         *result = NULL;
  196.  
  197.         err = dom_string_create_interned(tag->name.ptr, tag->name.len, &name);
  198.         if (err != DOM_NO_ERR) {
  199.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  200.                                 "Can't create element name");
  201.                 goto fail;
  202.         }
  203.  
  204.         if (tag->ns == HUBBUB_NS_NULL) {
  205.                 err = dom_document_create_element(dom_parser->doc, name,
  206.                                 &element);
  207.                 if (err != DOM_NO_ERR) {
  208.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  209.                                         "Can't create the DOM element");
  210.                         goto clean1;
  211.                 }
  212.         } else {
  213.                 err = dom_document_create_element_ns(dom_parser->doc,
  214.                                 dom_namespaces[tag->ns], name, &element);
  215.                 if (err != DOM_NO_ERR) {
  216.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  217.                                         "Can't create the DOM element");
  218.                         goto clean1;
  219.                 }
  220.         }
  221.  
  222.         if (element != NULL && tag->n_attributes > 0) {
  223.                 herr = add_attributes(parser, element, tag->attributes,
  224.                                 tag->n_attributes);
  225.                 if (herr != HUBBUB_OK)
  226.                         goto clean1;
  227.         }
  228.  
  229.         *result = element;
  230.  
  231. clean1:
  232.         dom_string_unref(name);
  233.  
  234. fail:
  235.         if (*result == NULL)
  236.                 return HUBBUB_UNKNOWN;
  237.         else
  238.                 return HUBBUB_OK;
  239. }
  240.  
  241. static hubbub_error create_text(void *parser, const hubbub_string *data,
  242.                 void **result)
  243. {
  244.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  245.         dom_exception err;
  246.         dom_string *str;
  247.         struct dom_text *text = NULL;
  248.  
  249.         *result = NULL;
  250.  
  251.         err = dom_string_create(data->ptr, data->len, &str);
  252.         if (err != DOM_NO_ERR) {
  253.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  254.                                 "Can't create text '%.*s'", data->len,
  255.                                 data->ptr);
  256.                 goto fail;
  257.         }
  258.  
  259.         err = dom_document_create_text_node(dom_parser->doc, str, &text);
  260.         if (err != DOM_NO_ERR) {
  261.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  262.                                 "Can't create the DOM text node");
  263.                 goto clean1;
  264.         }
  265.  
  266.         *result = text;
  267. clean1:
  268.         dom_string_unref(str);
  269.  
  270. fail:
  271.         if (*result == NULL)
  272.                 return HUBBUB_UNKNOWN;
  273.         else
  274.                 return HUBBUB_OK;
  275.  
  276. }
  277.  
  278. static hubbub_error ref_node(void *parser, void *node)
  279. {
  280.         struct dom_node *dnode = (struct dom_node *) node;
  281.  
  282.         UNUSED(parser);
  283.  
  284.         dom_node_ref(dnode);
  285.  
  286.         return HUBBUB_OK;
  287. }
  288.  
  289. static hubbub_error unref_node(void *parser, void *node)
  290. {
  291.         struct dom_node *dnode = (struct dom_node *) node;
  292.  
  293.         UNUSED(parser);
  294.  
  295.         dom_node_unref(dnode);
  296.  
  297.         return HUBBUB_OK;
  298. }
  299.  
  300. static hubbub_error append_child(void *parser, void *parent, void *child,
  301.                 void **result)
  302. {
  303.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  304.         dom_exception err;
  305.  
  306.         err = dom_node_append_child((struct dom_node *) parent,
  307.                                     (struct dom_node *) child,
  308.                                     (struct dom_node **) result);
  309.         if (err != DOM_NO_ERR) {
  310.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  311.                                 "Can't append child '%p' for parent '%p'",
  312.                                 child, parent);
  313.                 return HUBBUB_UNKNOWN;
  314.         }
  315.  
  316.         return HUBBUB_OK;
  317. }
  318.  
  319. static hubbub_error insert_before(void *parser, void *parent, void *child,
  320.                 void *ref_child, void **result)
  321. {
  322.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  323.         dom_exception err;
  324.  
  325.         err = dom_node_insert_before((struct dom_node *) parent,
  326.                         (struct dom_node *) child,
  327.                         (struct dom_node *) ref_child,
  328.                         (struct dom_node **) result);
  329.         if (err != DOM_NO_ERR) {
  330.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  331.                                 "Can't insert node '%p' before node '%p'",
  332.                                 child, ref_child);
  333.                 return HUBBUB_UNKNOWN;
  334.         }
  335.  
  336.         return HUBBUB_OK;
  337. }
  338.  
  339. static hubbub_error remove_child(void *parser, void *parent, void *child,
  340.                 void **result)
  341. {
  342.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  343.         dom_exception err;
  344.  
  345.         err = dom_node_remove_child((struct dom_node *) parent,
  346.                         (struct dom_node *) child,
  347.                         (struct dom_node **) result);
  348.         if (err != DOM_NO_ERR) {
  349.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  350.                                 "Can't remove child '%p'", child);
  351.                 return HUBBUB_UNKNOWN;
  352.         }
  353.  
  354.         return HUBBUB_OK;
  355. }
  356.  
  357. static hubbub_error clone_node(void *parser, void *node, bool deep,
  358.                 void **result)
  359. {
  360.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  361.         dom_exception err;
  362.  
  363.         err = dom_node_clone_node((struct dom_node *) node, deep,
  364.                         (struct dom_node **) result);
  365.         if (err != DOM_NO_ERR) {
  366.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  367.                                 "Can't clone node '%p'", node);
  368.                 return HUBBUB_UNKNOWN;
  369.         }
  370.  
  371.         return HUBBUB_OK;
  372. }
  373.  
  374. static hubbub_error reparent_children(void *parser, void *node,
  375.                 void *new_parent)
  376. {
  377.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  378.         dom_exception err;
  379.         struct dom_node *child, *result;
  380.  
  381.         while(true) {
  382.                 err = dom_node_get_first_child((struct dom_node *) node,
  383.                                 &child);
  384.                 if (err != DOM_NO_ERR) {
  385.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  386.                                         "Error in dom_note_get_first_child");
  387.                         return HUBBUB_UNKNOWN;
  388.                 }
  389.                 if (child == NULL)
  390.                         break;
  391.  
  392.                 err = dom_node_remove_child(node, (struct dom_node *) child,
  393.                                 &result);
  394.                 if (err != DOM_NO_ERR) {
  395.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  396.                                         "Error in dom_node_remove_child");
  397.                         goto fail;
  398.                 }
  399.                 dom_node_unref(result);
  400.  
  401.                 err = dom_node_append_child((struct dom_node *) new_parent,
  402.                                 (struct dom_node *) child, &result);
  403.                 if (err != DOM_NO_ERR) {
  404.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  405.                                         "Error in dom_node_append_child");
  406.                         goto fail;
  407.                 }
  408.                 dom_node_unref(result);
  409.                 dom_node_unref(child);
  410.         }
  411.         return HUBBUB_OK;
  412.  
  413. fail:
  414.         dom_node_unref(child);
  415.         return HUBBUB_UNKNOWN;
  416. }
  417.  
  418. static hubbub_error get_parent(void *parser, void *node, bool element_only,
  419.                 void **result)
  420. {
  421.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  422.         dom_exception err;
  423.         struct dom_node *parent;
  424.         dom_node_type type = DOM_NODE_TYPE_COUNT;
  425.  
  426.         err = dom_node_get_parent_node((struct dom_node *) node,
  427.                         &parent);
  428.         if (err != DOM_NO_ERR) {
  429.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  430.                                 "Error in dom_node_get_parent");
  431.                 return HUBBUB_UNKNOWN;
  432.         }
  433.         if (element_only == false) {
  434.                 *result = parent;
  435.                 return HUBBUB_OK;
  436.         }
  437.  
  438.         err = dom_node_get_node_type(parent, &type);
  439.         if (err != DOM_NO_ERR) {
  440.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  441.                                 "Error in dom_node_get_type");
  442.                 goto fail;
  443.         }
  444.         if (type == DOM_ELEMENT_NODE) {
  445.                 *result = parent;
  446.                 return HUBBUB_OK;
  447.         } else {
  448.                 *result = NULL;
  449.                 dom_node_unref(parent);
  450.                 return HUBBUB_OK;
  451.         }
  452.  
  453.         return HUBBUB_OK;
  454. fail:
  455.         dom_node_unref(parent);
  456.         return HUBBUB_UNKNOWN;
  457. }
  458.  
  459. static hubbub_error has_children(void *parser, void *node, bool *result)
  460. {
  461.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  462.         dom_exception err;
  463.  
  464.         err = dom_node_has_child_nodes((struct dom_node *) node, result);
  465.         if (err != DOM_NO_ERR) {
  466.                 dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  467.                                 "Error in dom_node_has_child_nodes");
  468.                 return HUBBUB_UNKNOWN;
  469.         }
  470.         return HUBBUB_OK;
  471. }
  472.  
  473. static hubbub_error form_associate(void *parser, void *form, void *node)
  474. {
  475.         /*
  476.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  477.         dom_html_form_element *form_ele = form;
  478.         dom_node_internal *ele = node;
  479.         dom_html_document *doc = (dom_html_document *)ele->owner;
  480.         dom_exception err = DOM_NO_ERR;*/
  481.        
  482.         /* Determine the kind of the node we have here. */
  483.         /*if (dom_string_caseless_isequal(ele->name,
  484.                                         doc->memoised[hds_BUTTON])) {
  485.                 err = _dom_html_button_element_set_form(
  486.                         (dom_html_button_element *)node, form_ele);
  487.                 if (err != DOM_NO_ERR) {
  488.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  489.                                         "Error in form_associate");
  490.                         return HUBBUB_UNKNOWN;
  491.                 }
  492.         } else if (dom_string_caseless_isequal(ele->name,
  493.                                                doc->memoised[hds_INPUT])) {
  494.                 err = _dom_html_input_element_set_form(
  495.                         (dom_html_input_element *)node, form_ele);
  496.                 if (err != DOM_NO_ERR) {
  497.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  498.                                         "Error in form_associate");
  499.                         return HUBBUB_UNKNOWN;
  500.                 }
  501.         } else if (dom_string_caseless_isequal(ele->name,
  502.                                                doc->memoised[hds_SELECT])) {
  503.                 err = _dom_html_select_element_set_form(
  504.                         (dom_html_select_element *)node, form_ele);
  505.                 if (err != DOM_NO_ERR) {
  506.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  507.                                         "Error in form_associate");
  508.                         return HUBBUB_UNKNOWN;
  509.                 }
  510.         } else if (dom_string_caseless_isequal(ele->name,
  511.                                                doc->memoised[hds_TEXTAREA])) {
  512.                 err = _dom_html_text_area_element_set_form(
  513.                         (dom_html_text_area_element *)node, form_ele);
  514.                 if (err != DOM_NO_ERR) {
  515.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  516.                                         "Error in form_associate");
  517.                         return HUBBUB_UNKNOWN;
  518.                 }
  519.         }*/
  520.        
  521.         return HUBBUB_OK;
  522. }
  523.  
  524. static hubbub_error add_attributes(void *parser, void *node,
  525.                 const hubbub_attribute *attributes, uint32_t n_attributes)
  526. {
  527.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  528.         dom_exception err;
  529.         uint32_t i;
  530.  
  531.         for (i = 0; i < n_attributes; i++) {
  532.                 dom_string *name, *value;
  533.  
  534.                 err = dom_string_create_interned(attributes[i].name.ptr,
  535.                                 attributes[i].name.len, &name);
  536.                 if (err != DOM_NO_ERR) {
  537.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  538.                                         "Can't create attribute name");
  539.                         goto fail;
  540.                 }
  541.  
  542.                 err = dom_string_create(attributes[i].value.ptr,
  543.                                 attributes[i].value.len, &value);
  544.                 if (err != DOM_NO_ERR) {
  545.                         dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
  546.                                         "Can't create attribute value");
  547.                         dom_string_unref(name);
  548.                         goto fail;
  549.                 }
  550.  
  551.                 if (attributes[i].ns == HUBBUB_NS_NULL) {
  552.                         err = dom_element_set_attribute(
  553.                                         (struct dom_element *) node, name,
  554.                                         value);
  555.                         dom_string_unref(name);
  556.                         dom_string_unref(value);
  557.                         if (err != DOM_NO_ERR) {
  558.                                 dom_parser->msg(DOM_MSG_CRITICAL,
  559.                                                 dom_parser->mctx,
  560.                                                 "Can't add attribute");
  561.                         }
  562.                 } else {
  563.                         err = dom_element_set_attribute_ns(
  564.                                         (struct dom_element *) node,
  565.                                         dom_namespaces[attributes[i].ns], name,
  566.                                         value);
  567.                         dom_string_unref(name);
  568.                         dom_string_unref(value);
  569.                         if (err != DOM_NO_ERR) {
  570.                                 dom_parser->msg(DOM_MSG_CRITICAL,
  571.                                                 dom_parser->mctx,
  572.                                                 "Can't add attribute ns");
  573.                         }
  574.                 }
  575.         }
  576.  
  577.         return HUBBUB_OK;
  578.  
  579. fail:
  580.         return HUBBUB_UNKNOWN;
  581. }
  582.  
  583. static hubbub_error set_quirks_mode(void *parser, hubbub_quirks_mode mode)
  584. {
  585.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  586.  
  587.         switch (mode) {
  588.         case HUBBUB_QUIRKS_MODE_NONE:
  589.                 dom_document_set_quirks_mode(dom_parser->doc,
  590.                                              DOM_DOCUMENT_QUIRKS_MODE_NONE);
  591.                 break;
  592.         case HUBBUB_QUIRKS_MODE_LIMITED:
  593.                 dom_document_set_quirks_mode(dom_parser->doc,
  594.                                              DOM_DOCUMENT_QUIRKS_MODE_LIMITED);
  595.                 break;
  596.         case HUBBUB_QUIRKS_MODE_FULL:
  597.                 dom_document_set_quirks_mode(dom_parser->doc,
  598.                                              DOM_DOCUMENT_QUIRKS_MODE_FULL);
  599.                 break;
  600.         }
  601.  
  602.         return HUBBUB_OK;
  603. }
  604.  
  605. static hubbub_error change_encoding(void *parser, const char *charset)
  606. {
  607.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  608.         uint32_t source;
  609.         const char *name;
  610.  
  611.         /* If we have an encoding here, it means we are *certain* */
  612.         if (dom_parser->encoding != NULL) {
  613.                 return HUBBUB_OK;
  614.         }
  615.  
  616.         /* Find the confidence otherwise (can only be from a BOM) */
  617.         name = hubbub_parser_read_charset(dom_parser->parser, &source);
  618.  
  619.         if (source == HUBBUB_CHARSET_CONFIDENT) {
  620.                 dom_parser->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_DETECTED;
  621.                 dom_parser->encoding = charset;
  622.                 return HUBBUB_OK;
  623.         }
  624.  
  625.         /* So here we have something of confidence tentative... */
  626.         /* http://www.whatwg.org/specs/web-apps/current-work/#change */
  627.  
  628.         /* 2. "If the new encoding is identical or equivalent to the encoding
  629.          * that is already being used to interpret the input stream, then set
  630.          * the confidence to confident and abort these steps." */
  631.  
  632.         /* Whatever happens, the encoding should be set here; either for
  633.          * reprocessing with a different charset, or for confirming that the
  634.          * charset is in fact correct */
  635.         dom_parser->encoding = charset;
  636.         dom_parser->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_META;
  637.  
  638.         /* Equal encodings will have the same string pointers */
  639.         return (charset == name) ? HUBBUB_OK : HUBBUB_ENCODINGCHANGE;
  640. }
  641.  
  642. static hubbub_error complete_script(void *parser, void *script)
  643. {
  644.         dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
  645.         dom_hubbub_error err;
  646.  
  647.         err = dom_parser->script(dom_parser->mctx, (struct dom_node *)script);
  648.  
  649.         if (err == DOM_HUBBUB_OK) {
  650.                 return HUBBUB_OK;
  651.         }
  652.  
  653.         if ((err & DOM_HUBBUB_HUBBUB_ERR) != 0) {
  654.                 return err & (~DOM_HUBBUB_HUBBUB_ERR);
  655.         }
  656.  
  657.         return HUBBUB_UNKNOWN;
  658. }
  659.  
  660. static hubbub_tree_handler tree_handler = {
  661.         create_comment,
  662.         create_doctype,
  663.         create_element,
  664.         create_text,
  665.         ref_node,
  666.         unref_node,
  667.         append_child,
  668.         insert_before,
  669.         remove_child,
  670.         clone_node,
  671.         reparent_children,
  672.         get_parent,
  673.         has_children,
  674.         form_associate,
  675.         add_attributes,
  676.         set_quirks_mode,
  677.         change_encoding,
  678.         complete_script,
  679.         NULL
  680. };
  681.  
  682. /**
  683.  * Memory allocator
  684.  */
  685. static void *dom_hubbub_alloc(void *ptr, size_t len, void *pw)
  686. {
  687.         UNUSED(pw);
  688.  
  689.         if (ptr == NULL)
  690.                 return len > 0 ? malloc(len) : NULL;
  691.  
  692.         if (len == 0) {
  693.                 free(ptr);
  694.                 return NULL;
  695.         }
  696.  
  697.         return realloc(ptr, len);
  698. }
  699.  
  700. /**
  701.  * Default message callback
  702.  */
  703. static void dom_hubbub_parser_default_msg(uint32_t severity, void *ctx,
  704.                 const char *msg, ...)
  705. {
  706.         UNUSED(severity);
  707.         UNUSED(ctx);
  708.         UNUSED(msg);
  709. }
  710.  
  711. /**
  712.  * Default script callback.
  713.  */
  714. static dom_hubbub_error
  715. dom_hubbub_parser_default_script(void *ctx, struct dom_node *node)
  716. {
  717.         UNUSED(ctx);
  718.         UNUSED(node);
  719.         return DOM_HUBBUB_OK;
  720. }
  721.  
  722. /**
  723.  * Create a Hubbub parser instance
  724.  *
  725.  * \param params The binding creation parameters
  726.  * \param parser Pointer to location to recive instance.
  727.  * \param document Pointer to location to receive document.
  728.  * \return Error code
  729.  */
  730. dom_hubbub_error
  731. dom_hubbub_parser_create(dom_hubbub_parser_params *params,
  732.                          dom_hubbub_parser **parser,
  733.                          dom_document **document)
  734. {
  735.         dom_hubbub_parser *binding;
  736.         hubbub_parser_optparams optparams;
  737.         hubbub_error error;
  738.         dom_exception err;
  739.         dom_string *idname = NULL;
  740.  
  741.         /* check result parameters */
  742.         if (document == NULL) {
  743.                 return DOM_HUBBUB_BADPARM;
  744.         }
  745.  
  746.         if (parser == NULL) {
  747.                 return DOM_HUBBUB_BADPARM;
  748.         }
  749.  
  750.         /* setup binding parser context */
  751.         binding = malloc(sizeof(dom_hubbub_parser));
  752.         if (binding == NULL) {
  753.                 return DOM_HUBBUB_NOMEM;
  754.         }
  755.  
  756.         binding->parser = NULL;
  757.         binding->doc = NULL;
  758.         binding->encoding = params->enc;
  759.  
  760.         if (params->enc != NULL) {
  761.                 binding->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER;
  762.         } else {
  763.                 binding->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_DETECTED;
  764.         }
  765.  
  766.         binding->complete = false;
  767.  
  768.         if (params->msg == NULL) {
  769.                 binding->msg = dom_hubbub_parser_default_msg;
  770.         } else {
  771.                 binding->msg = params->msg;
  772.         }
  773.         binding->mctx = params->ctx;
  774.  
  775.         /* ensure script function is valid or use the default */
  776.         if (params->script == NULL) {
  777.                 binding->script = dom_hubbub_parser_default_script;
  778.         } else {
  779.                 binding->script = params->script;
  780.         }
  781.  
  782.         /* create hubbub parser */
  783.         error = hubbub_parser_create(binding->encoding,
  784.                                      params->fix_enc,
  785.                                      dom_hubbub_alloc,
  786.                                      NULL,
  787.                                      &binding->parser);
  788.         if (error != HUBBUB_OK)  {
  789.                 free(binding);
  790.                 return (DOM_HUBBUB_HUBBUB_ERR | error);
  791.         }
  792.  
  793.         /* create DOM document */
  794.         err = dom_implementation_create_document(DOM_IMPLEMENTATION_HTML,
  795.                                                  NULL,
  796.                                                  NULL,
  797.                                                  NULL,
  798.                                                  params->daf,
  799.                                                  params->ctx,
  800.                                                  &binding->doc);
  801.         if (err != DOM_NO_ERR) {
  802.                 hubbub_parser_destroy(binding->parser);
  803.                 free(binding);
  804.                 return DOM_HUBBUB_DOM;
  805.         }
  806.  
  807.         binding->tree_handler = tree_handler;
  808.         binding->tree_handler.ctx = (void *)binding;
  809.  
  810.         /* set tree handler on parser */
  811.         optparams.tree_handler = &binding->tree_handler;
  812.         hubbub_parser_setopt(binding->parser,
  813.                              HUBBUB_PARSER_TREE_HANDLER,
  814.                              &optparams);
  815.  
  816.         /* set document node*/
  817.         optparams.document_node = dom_node_ref((struct dom_node *)binding->doc);
  818.         hubbub_parser_setopt(binding->parser,
  819.                              HUBBUB_PARSER_DOCUMENT_NODE,
  820.                              &optparams);
  821.  
  822.         /* set scripting state */
  823.         optparams.enable_scripting = params->enable_script;
  824.         hubbub_parser_setopt(binding->parser,
  825.                              HUBBUB_PARSER_ENABLE_SCRIPTING,
  826.                              &optparams);
  827.  
  828.         /* set the document id parameter before the parse so searches
  829.          * based on id succeed.
  830.          */
  831.         err = dom_string_create_interned((const uint8_t *) "id",
  832.                                          SLEN("id"),
  833.                                          &idname);
  834.         if (err != DOM_NO_ERR) {
  835.                 binding->msg(DOM_MSG_ERROR, binding->mctx, "Can't set DOM document id name");
  836.                 hubbub_parser_destroy(binding->parser);
  837.                 free(binding);
  838.                 return DOM_HUBBUB_DOM;
  839.         }
  840.         _dom_document_set_id_name(binding->doc, idname);
  841.         dom_string_unref(idname);
  842.  
  843.         /* set return parameters */
  844.         *document = (dom_document *)dom_node_ref(binding->doc);
  845.         *parser = binding;
  846.  
  847.         return DOM_HUBBUB_OK;
  848. }
  849.  
  850.  
  851. dom_hubbub_error
  852. dom_hubbub_parser_insert_chunk(dom_hubbub_parser *parser,
  853.                                const uint8_t *data,
  854.                                size_t length)
  855. {
  856.         hubbub_parser_insert_chunk(parser->parser, data, length);
  857.  
  858.         return DOM_HUBBUB_OK;
  859. }
  860.  
  861.  
  862. /**
  863.  * Destroy a Hubbub parser instance
  864.  *
  865.  * \param parser  The Hubbub parser object
  866.  */
  867. void dom_hubbub_parser_destroy(dom_hubbub_parser *parser)
  868. {
  869.         hubbub_parser_destroy(parser->parser);
  870.         parser->parser = NULL;
  871.  
  872.         if (parser->doc != NULL) {
  873.                 dom_node_unref((struct dom_node *) parser->doc);
  874.                 parser->doc = NULL;
  875.         }
  876.  
  877.         free(parser);
  878. }
  879.  
  880. /**
  881.  * Parse data with Hubbub parser
  882.  *
  883.  * \param parser  The parser object
  884.  * \param data    The data to be parsed
  885.  * \param len     The length of the data to be parsed
  886.  * \return DOM_HUBBUB_OK on success,
  887.  *         DOM_HUBBUB_HUBBUB_ERR | <hubbub_error> on failure
  888.  */
  889. dom_hubbub_error dom_hubbub_parser_parse_chunk(dom_hubbub_parser *parser,
  890.                 const uint8_t *data, size_t len)
  891. {
  892.         hubbub_error err;
  893.  
  894.         err = hubbub_parser_parse_chunk(parser->parser, data, len);
  895.         if (err != HUBBUB_OK)
  896.                 return DOM_HUBBUB_HUBBUB_ERR | err;
  897.  
  898.         return DOM_HUBBUB_OK;
  899. }
  900.  
  901. /**
  902.  * Notify the parser to complete parsing
  903.  *
  904.  * \param parser  The parser object
  905.  * \return DOM_HUBBUB_OK                          on success,
  906.  *         DOM_HUBBUB_HUBBUB_ERR | <hubbub_error> on underlaying parser failure
  907.  *         DOMHUBBUB_UNKNOWN | <lwc_error>        on libwapcaplet failure
  908.  */
  909. dom_hubbub_error dom_hubbub_parser_completed(dom_hubbub_parser *parser)
  910. {
  911.         hubbub_error err;
  912.  
  913.         err = hubbub_parser_completed(parser->parser);
  914.         if (err != HUBBUB_OK) {
  915.                 parser->msg(DOM_MSG_ERROR, parser->mctx,
  916.                                 "hubbub_parser_completed failed: %d", err);
  917.                 return DOM_HUBBUB_HUBBUB_ERR | err;
  918.         }
  919.  
  920.         parser->complete = true;
  921.  
  922.         return DOM_HUBBUB_OK;
  923. }
  924.  
  925. /**
  926.  * Retrieve the encoding
  927.  *
  928.  * \param parser  The parser object
  929.  * \param source  The encoding_source
  930.  * \return the encoding name
  931.  */
  932. const char *dom_hubbub_parser_get_encoding(dom_hubbub_parser *parser,
  933.                 dom_hubbub_encoding_source *source)
  934. {
  935.         *source = parser->encoding_source;
  936.  
  937.         return parser->encoding != NULL ? parser->encoding
  938.                                         : "Windows-1252";
  939. }
  940.  
  941. /**
  942.  * Set the Parse pause state.
  943.  *
  944.  * \param parser  The parser object
  945.  * \param pause   The pause state to set.
  946.  * \return DOM_HUBBUB_OK on success,
  947.  *         DOM_HUBBUB_HUBBUB_ERR | <hubbub_error> on failure
  948.  */
  949. dom_hubbub_error dom_hubbub_parser_pause(dom_hubbub_parser *parser, bool pause)
  950. {
  951.         hubbub_error err;
  952.         hubbub_parser_optparams params;
  953.  
  954.         params.pause_parse = pause;
  955.         err = hubbub_parser_setopt(parser->parser, HUBBUB_PARSER_PAUSE, &params);
  956.         if (err != HUBBUB_OK)
  957.                 return DOM_HUBBUB_HUBBUB_ERR | err;
  958.  
  959.         return DOM_HUBBUB_OK;
  960. }
  961.