Subversion Repositories Kolibri OS

Rev

Rev 3584 | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * libdom utilities (implementation).
  21.  */
  22.  
  23. #include <assert.h>
  24. #include <dom/dom.h>
  25.  
  26. #include "utils/config.h"
  27. #include "utils/log.h"
  28.  
  29. #include "utils/libdom.h"
  30.  
  31. /* exported interface documented in libdom.h */
  32. bool libdom_treewalk(dom_node *root,
  33.                 bool (*callback)(dom_node *node, dom_string *name, void *ctx),
  34.                 void *ctx)
  35. {
  36.         dom_node *node;
  37.         bool result = true;
  38.  
  39.         node = dom_node_ref(root); /* tree root */
  40.  
  41.         while (node != NULL) {
  42.                 dom_node *next = NULL;
  43.                 dom_node_type type;
  44.                 dom_string *name;
  45.                 dom_exception exc;
  46.  
  47.                 exc = dom_node_get_first_child(node, &next);
  48.                 if (exc != DOM_NO_ERR) {
  49.                         dom_node_unref(node);
  50.                         break;
  51.                 }
  52.  
  53.                 if (next != NULL) {  /* 1. children */
  54.                         dom_node_unref(node);
  55.                         node = next;
  56.                 } else {
  57.                         exc = dom_node_get_next_sibling(node, &next);
  58.                         if (exc != DOM_NO_ERR) {
  59.                                 dom_node_unref(node);
  60.                                 break;
  61.                         }
  62.  
  63.                         if (next != NULL) {  /* 2. siblings */
  64.                                 dom_node_unref(node);
  65.                                 node = next;
  66.                         } else {  /* 3. ancestor siblings */
  67.                                 while (node != NULL) {
  68.                                         exc = dom_node_get_next_sibling(node,
  69.                                                         &next);
  70.                                         if (exc != DOM_NO_ERR) {
  71.                                                 dom_node_unref(node);
  72.                                                 node = NULL;
  73.                                                 break;
  74.                                         }
  75.  
  76.                                         if (next != NULL) {
  77.                                                 dom_node_unref(next);
  78.                                                 break;
  79.                                         }
  80.  
  81.                                         exc = dom_node_get_parent_node(node,
  82.                                                         &next);
  83.                                         if (exc != DOM_NO_ERR) {
  84.                                                 dom_node_unref(node);
  85.                                                 node = NULL;
  86.                                                 break;
  87.                                         }
  88.  
  89.                                         dom_node_unref(node);
  90.                                         node = next;
  91.                                 }
  92.  
  93.                                 if (node == NULL)
  94.                                         break;
  95.  
  96.                                 exc = dom_node_get_next_sibling(node, &next);
  97.                                 if (exc != DOM_NO_ERR) {
  98.                                         dom_node_unref(node);
  99.                                         break;
  100.                                 }
  101.  
  102.                                 dom_node_unref(node);
  103.                                 node = next;
  104.                         }
  105.                 }
  106.  
  107.                 assert(node != NULL);
  108.  
  109.                 exc = dom_node_get_node_type(node, &type);
  110.                 if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE))
  111.                         continue;
  112.  
  113.                 exc = dom_node_get_node_name(node, &name);
  114.                 if (exc != DOM_NO_ERR)
  115.                         continue;
  116.  
  117.                 result = callback(node, name, ctx);
  118.  
  119.                 dom_string_unref(name);
  120.  
  121.                 if (result == false) {
  122.                         break; /* callback caused early termination */
  123.                 }
  124.  
  125.         }
  126.         return result;
  127. }
  128.  
  129.  
  130. /* libdom_treewalk context for libdom_find_element */
  131. struct find_element_ctx {
  132.         lwc_string *search;
  133.         dom_node *found;
  134. };
  135.  
  136. /* libdom_treewalk callback for libdom_find_element */
  137. static bool libdom_find_element_callback(dom_node *node, dom_string *name,
  138.                 void *ctx)
  139. {
  140.         struct find_element_ctx *data = ctx;
  141.  
  142.         if (dom_string_caseless_lwc_isequal(name, data->search)) {
  143.                 /* Found element */
  144.                 data->found = node;
  145.                 return false; /* Discontinue search */
  146.         }
  147.  
  148.         return true; /* Continue search */
  149. }
  150.  
  151.  
  152. /* exported interface documented in libdom.h */
  153. dom_node *libdom_find_element(dom_node *node, lwc_string *element_name)
  154. {
  155.         struct find_element_ctx data;
  156.  
  157.         assert(element_name != NULL);
  158.  
  159.         if (node == NULL)
  160.                 return NULL;
  161.  
  162.         data.search = element_name;
  163.         data.found = NULL;
  164.  
  165.         libdom_treewalk(node, libdom_find_element_callback, &data);
  166.  
  167.         return data.found;
  168. }
  169.  
  170.  
  171. /* exported interface documented in libdom.h */
  172. dom_node *libdom_find_first_element(dom_node *parent, lwc_string *element_name)
  173. {
  174.         dom_node *element;
  175.         dom_exception exc;
  176.         dom_string *node_name = NULL;
  177.         dom_node_type node_type;
  178.         dom_node *next_node;
  179.  
  180.         exc = dom_node_get_first_child(parent, &element);
  181.         if ((exc != DOM_NO_ERR) || (element == NULL)) {
  182.                 return NULL;
  183.         }
  184.  
  185.         /* find first node thats a element */
  186.         do {
  187.                 exc = dom_node_get_node_type(element, &node_type);
  188.  
  189.                 if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
  190.                         exc = dom_node_get_node_name(element, &node_name);
  191.                         if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
  192.                                 if (dom_string_caseless_lwc_isequal(node_name,
  193.                                                      element_name)) {
  194.                                         dom_string_unref(node_name);
  195.                                         break;
  196.                                 }
  197.                                 dom_string_unref(node_name);
  198.                         }
  199.                 }
  200.  
  201.                 exc = dom_node_get_next_sibling(element, &next_node);
  202.                 dom_node_unref(element);
  203.                 if (exc == DOM_NO_ERR) {
  204.                         element = next_node;
  205.                 } else {
  206.                         element = NULL;
  207.                 }
  208.         } while (element != NULL);
  209.  
  210.         return element;
  211. }
  212.  
  213. /* exported interface documented in libdom.h */
  214. void libdom_iterate_child_elements(dom_node *parent,
  215.                 libdom_iterate_cb cb, void *ctx)
  216. {
  217.         dom_nodelist *children;
  218.         uint32_t index, num_children;
  219.         dom_exception error;
  220.  
  221.         error = dom_node_get_child_nodes(parent, &children);
  222.         if (error != DOM_NO_ERR || children == NULL)
  223.                 return;
  224.  
  225.         error = dom_nodelist_get_length(children, &num_children);
  226.         if (error != DOM_NO_ERR) {
  227.                 dom_nodelist_unref(children);
  228.                 return;
  229.         }
  230.  
  231.         for (index = 0; index < num_children; index++) {
  232.                 dom_node *child;
  233.                 dom_node_type type;
  234.  
  235.                 error = dom_nodelist_item(children, index, &child);
  236.                 if (error != DOM_NO_ERR) {
  237.                         dom_nodelist_unref(children);
  238.                         return;
  239.                 }
  240.  
  241.                 error = dom_node_get_node_type(child, &type);
  242.                 if (error == DOM_NO_ERR && type == DOM_ELEMENT_NODE) {
  243.                         if (cb(child, ctx) == false) {
  244.                                 dom_node_unref(child);
  245.                                 dom_nodelist_unref(children);
  246.                                 return;
  247.                         }
  248.                 }
  249.  
  250.                 dom_node_unref(child);
  251.         }
  252.  
  253.         dom_nodelist_unref(children);
  254. }
  255.  
  256. /* exported interface documented in libdom.h */
  257. nserror libdom_hubbub_error_to_nserror(dom_hubbub_error error)
  258. {
  259.         switch (error) {
  260.  
  261.         /* HUBBUB_REPROCESS is not handled here because it can
  262.          * never occur outside the hubbub treebuilder
  263.          */
  264.  
  265.         case DOM_HUBBUB_OK:
  266.                 /* parsed ok */
  267.                 return NSERROR_OK;
  268.  
  269.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED):
  270.                 /* hubbub input paused */
  271.                 return NSERROR_OK;
  272.  
  273.         case DOM_HUBBUB_NOMEM:
  274.                 /* out of memory error from DOM */
  275.                 return NSERROR_NOMEM;
  276.  
  277.         case DOM_HUBBUB_BADPARM:
  278.                 /* Bad parameter passed to creation */
  279.                 return NSERROR_BAD_PARAMETER;
  280.  
  281.         case DOM_HUBBUB_DOM:
  282.                 /* DOM call returned error */
  283.                 return NSERROR_DOM;
  284.  
  285.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE):
  286.                 /* encoding changed */
  287.                 return NSERROR_ENCODING_CHANGE;
  288.  
  289.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NOMEM):
  290.                 /* out of memory error from parser */
  291.                 return NSERROR_NOMEM;
  292.  
  293.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADPARM):
  294.                 return NSERROR_BAD_PARAMETER;
  295.  
  296.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_INVALID):
  297.                 return NSERROR_INVALID;
  298.  
  299.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_FILENOTFOUND):
  300.                 return NSERROR_NOT_FOUND;
  301.  
  302.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NEEDDATA):
  303.                 return NSERROR_NEED_DATA;
  304.  
  305.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADENCODING):
  306.                 return NSERROR_BAD_ENCODING;
  307.  
  308.         case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_UNKNOWN):
  309.                 /* currently only generated by the libdom hubbub binding */
  310.                 return NSERROR_DOM;
  311.         default:
  312.                 /* unknown error */
  313.                 /** @todo better error handling and reporting */
  314.                 return NSERROR_UNKNOWN;
  315.         }
  316.         return NSERROR_UNKNOWN;
  317. }
  318.  
  319.  
  320. static void ignore_dom_msg(uint32_t severity, void *ctx, const char *msg, ...)
  321. {
  322. }
  323.  
  324. /* exported interface documented in libdom.h */
  325. nserror libdom_parse_file(const char *filename, const char *encoding, dom_document **doc)
  326. {
  327.         dom_hubbub_parser_params parse_params;
  328.         dom_hubbub_error error;
  329.         dom_hubbub_parser *parser;
  330.         dom_document *document;
  331.         FILE *fp = NULL;
  332. #define BUF_SIZE 512
  333.         uint8_t buf[BUF_SIZE];
  334.  
  335.         fp = fopen(filename, "r");
  336.         if (fp == NULL) {
  337.                 return NSERROR_NOT_FOUND;
  338.         }
  339.  
  340.         parse_params.enc = encoding;
  341.         parse_params.fix_enc = false;
  342.         parse_params.enable_script = false;
  343.         parse_params.msg = ignore_dom_msg;
  344.         parse_params.script = NULL;
  345.         parse_params.ctx = NULL;
  346.         parse_params.daf = NULL;
  347.  
  348.         error = dom_hubbub_parser_create(&parse_params, &parser, &document);
  349.         if (error != DOM_HUBBUB_OK) {
  350.                 fclose(fp);
  351.                 return libdom_hubbub_error_to_nserror(error);
  352.         }
  353.  
  354.         while (feof(fp) == 0) {
  355.                 size_t read = fread(buf, sizeof(buf[0]), BUF_SIZE, fp);
  356.  
  357.                 error = dom_hubbub_parser_parse_chunk(parser, buf, read);
  358.                 if (error != DOM_HUBBUB_OK) {
  359.                         dom_node_unref(document);
  360.                         dom_hubbub_parser_destroy(parser);
  361.                         fclose(fp);
  362.                         return NSERROR_DOM;
  363.                 }
  364.         }
  365.  
  366.         error = dom_hubbub_parser_completed(parser);
  367.         if (error != DOM_HUBBUB_OK) {
  368.                 dom_node_unref(document);
  369.                 dom_hubbub_parser_destroy(parser);
  370.                 fclose(fp);
  371.                 return libdom_hubbub_error_to_nserror(error);
  372.         }
  373.  
  374.         dom_hubbub_parser_destroy(parser);
  375.         fclose(fp);
  376.  
  377.         *doc = document;
  378.         return NSERROR_OK;
  379. }
  380.