nokogiri 1.10.7 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +42 -0
- data/LICENSE-DEPENDENCIES.md +1632 -1022
- data/LICENSE.md +1 -1
- data/README.md +188 -96
- data/bin/nokogiri +63 -50
- data/dependencies.yml +34 -66
- data/ext/nokogiri/depend +38 -358
- data/ext/nokogiri/extconf.rb +862 -421
- data/ext/nokogiri/gumbo.c +594 -0
- data/ext/nokogiri/html4_document.c +165 -0
- data/ext/nokogiri/html4_element_description.c +299 -0
- data/ext/nokogiri/html4_entity_lookup.c +37 -0
- data/ext/nokogiri/html4_sax_parser_context.c +108 -0
- data/ext/nokogiri/html4_sax_push_parser.c +95 -0
- data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
- data/ext/nokogiri/nokogiri.c +251 -105
- data/ext/nokogiri/nokogiri.h +222 -90
- data/ext/nokogiri/test_global_handlers.c +40 -0
- data/ext/nokogiri/xml_attr.c +17 -17
- data/ext/nokogiri/xml_attribute_decl.c +22 -22
- data/ext/nokogiri/xml_cdata.c +39 -31
- data/ext/nokogiri/xml_comment.c +20 -27
- data/ext/nokogiri/xml_document.c +408 -243
- data/ext/nokogiri/xml_document_fragment.c +13 -17
- data/ext/nokogiri/xml_dtd.c +64 -58
- data/ext/nokogiri/xml_element_content.c +63 -55
- data/ext/nokogiri/xml_element_decl.c +31 -31
- data/ext/nokogiri/xml_encoding_handler.c +54 -21
- data/ext/nokogiri/xml_entity_decl.c +37 -35
- data/ext/nokogiri/xml_entity_reference.c +17 -19
- data/ext/nokogiri/xml_namespace.c +131 -61
- data/ext/nokogiri/xml_node.c +1343 -674
- data/ext/nokogiri/xml_node_set.c +246 -216
- data/ext/nokogiri/xml_processing_instruction.c +18 -20
- data/ext/nokogiri/xml_reader.c +305 -213
- data/ext/nokogiri/xml_relax_ng.c +87 -78
- data/ext/nokogiri/xml_sax_parser.c +149 -124
- data/ext/nokogiri/xml_sax_parser_context.c +149 -103
- data/ext/nokogiri/xml_sax_push_parser.c +65 -37
- data/ext/nokogiri/xml_schema.c +138 -82
- data/ext/nokogiri/xml_syntax_error.c +42 -21
- data/ext/nokogiri/xml_text.c +35 -26
- data/ext/nokogiri/xml_xpath_context.c +363 -178
- data/ext/nokogiri/xslt_stylesheet.c +335 -189
- data/gumbo-parser/CHANGES.md +63 -0
- data/gumbo-parser/Makefile +126 -0
- data/gumbo-parser/THANKS +27 -0
- data/gumbo-parser/src/Makefile +34 -0
- data/gumbo-parser/src/README.md +41 -0
- data/gumbo-parser/src/ascii.c +75 -0
- data/gumbo-parser/src/ascii.h +115 -0
- data/gumbo-parser/src/attribute.c +42 -0
- data/gumbo-parser/src/attribute.h +17 -0
- data/gumbo-parser/src/char_ref.c +22225 -0
- data/gumbo-parser/src/char_ref.h +29 -0
- data/gumbo-parser/src/char_ref.rl +2154 -0
- data/gumbo-parser/src/error.c +630 -0
- data/gumbo-parser/src/error.h +148 -0
- data/gumbo-parser/src/foreign_attrs.c +103 -0
- data/gumbo-parser/src/foreign_attrs.gperf +27 -0
- data/gumbo-parser/src/insertion_mode.h +33 -0
- data/gumbo-parser/src/macros.h +91 -0
- data/gumbo-parser/src/nokogiri_gumbo.h +944 -0
- data/gumbo-parser/src/parser.c +4891 -0
- data/gumbo-parser/src/parser.h +41 -0
- data/gumbo-parser/src/replacement.h +33 -0
- data/gumbo-parser/src/string_buffer.c +103 -0
- data/gumbo-parser/src/string_buffer.h +68 -0
- data/gumbo-parser/src/string_piece.c +48 -0
- data/gumbo-parser/src/svg_attrs.c +174 -0
- data/gumbo-parser/src/svg_attrs.gperf +77 -0
- data/gumbo-parser/src/svg_tags.c +137 -0
- data/gumbo-parser/src/svg_tags.gperf +55 -0
- data/gumbo-parser/src/tag.c +223 -0
- data/gumbo-parser/src/tag_lookup.c +382 -0
- data/gumbo-parser/src/tag_lookup.gperf +170 -0
- data/gumbo-parser/src/tag_lookup.h +13 -0
- data/gumbo-parser/src/token_buffer.c +79 -0
- data/gumbo-parser/src/token_buffer.h +71 -0
- data/gumbo-parser/src/token_type.h +17 -0
- data/gumbo-parser/src/tokenizer.c +3464 -0
- data/gumbo-parser/src/tokenizer.h +112 -0
- data/gumbo-parser/src/tokenizer_states.h +339 -0
- data/gumbo-parser/src/utf8.c +245 -0
- data/gumbo-parser/src/utf8.h +164 -0
- data/gumbo-parser/src/util.c +66 -0
- data/gumbo-parser/src/util.h +34 -0
- data/gumbo-parser/src/vector.c +111 -0
- data/gumbo-parser/src/vector.h +45 -0
- data/lib/nokogiri/class_resolver.rb +67 -0
- data/lib/nokogiri/css/node.rb +10 -8
- data/lib/nokogiri/css/parser.rb +397 -377
- data/lib/nokogiri/css/parser.y +250 -245
- data/lib/nokogiri/css/parser_extras.rb +54 -49
- data/lib/nokogiri/css/syntax_error.rb +3 -1
- data/lib/nokogiri/css/tokenizer.rb +5 -3
- data/lib/nokogiri/css/tokenizer.rex +3 -2
- data/lib/nokogiri/css/xpath_visitor.rb +205 -96
- data/lib/nokogiri/css.rb +56 -17
- data/lib/nokogiri/decorators/slop.rb +9 -7
- data/lib/nokogiri/encoding_handler.rb +57 -0
- data/lib/nokogiri/extension.rb +32 -0
- data/lib/nokogiri/gumbo.rb +15 -0
- data/lib/nokogiri/html.rb +38 -27
- data/lib/nokogiri/{html → html4}/builder.rb +4 -2
- data/lib/nokogiri/html4/document.rb +214 -0
- data/lib/nokogiri/html4/document_fragment.rb +54 -0
- data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
- data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
- data/lib/nokogiri/html4/encoding_reader.rb +121 -0
- data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
- data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
- data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
- data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
- data/lib/nokogiri/html4.rb +47 -0
- data/lib/nokogiri/html5/document.rb +168 -0
- data/lib/nokogiri/html5/document_fragment.rb +90 -0
- data/lib/nokogiri/html5/node.rb +103 -0
- data/lib/nokogiri/html5.rb +326 -0
- data/lib/nokogiri/jruby/dependencies.rb +3 -0
- data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
- data/lib/nokogiri/syntax_error.rb +2 -0
- data/lib/nokogiri/version/constant.rb +6 -0
- data/lib/nokogiri/version/info.rb +224 -0
- data/lib/nokogiri/version.rb +3 -108
- data/lib/nokogiri/xml/attr.rb +55 -3
- data/lib/nokogiri/xml/attribute_decl.rb +6 -2
- data/lib/nokogiri/xml/builder.rb +75 -34
- data/lib/nokogiri/xml/cdata.rb +3 -1
- data/lib/nokogiri/xml/character_data.rb +2 -0
- data/lib/nokogiri/xml/document.rb +312 -127
- data/lib/nokogiri/xml/document_fragment.rb +93 -48
- data/lib/nokogiri/xml/dtd.rb +4 -2
- data/lib/nokogiri/xml/element_content.rb +12 -2
- data/lib/nokogiri/xml/element_decl.rb +6 -2
- data/lib/nokogiri/xml/entity_decl.rb +7 -3
- data/lib/nokogiri/xml/entity_reference.rb +2 -0
- data/lib/nokogiri/xml/namespace.rb +44 -0
- data/lib/nokogiri/xml/node/save_options.rb +23 -8
- data/lib/nokogiri/xml/node.rb +1096 -419
- data/lib/nokogiri/xml/node_set.rb +137 -61
- data/lib/nokogiri/xml/notation.rb +13 -0
- data/lib/nokogiri/xml/parse_options.rb +145 -52
- data/lib/nokogiri/xml/pp/character_data.rb +9 -6
- data/lib/nokogiri/xml/pp/node.rb +42 -30
- data/lib/nokogiri/xml/pp.rb +4 -2
- data/lib/nokogiri/xml/processing_instruction.rb +4 -1
- data/lib/nokogiri/xml/reader.rb +21 -28
- data/lib/nokogiri/xml/relax_ng.rb +8 -2
- data/lib/nokogiri/xml/sax/document.rb +45 -49
- data/lib/nokogiri/xml/sax/parser.rb +39 -36
- data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
- data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
- data/lib/nokogiri/xml/sax.rb +6 -4
- data/lib/nokogiri/xml/schema.rb +19 -9
- data/lib/nokogiri/xml/searchable.rb +120 -72
- data/lib/nokogiri/xml/syntax_error.rb +7 -5
- data/lib/nokogiri/xml/text.rb +2 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
- data/lib/nokogiri/xml/xpath.rb +15 -4
- data/lib/nokogiri/xml/xpath_context.rb +3 -3
- data/lib/nokogiri/xml.rb +39 -38
- data/lib/nokogiri/xslt/stylesheet.rb +3 -1
- data/lib/nokogiri/xslt.rb +101 -22
- data/lib/nokogiri.rb +59 -75
- data/lib/xsd/xmlparser/nokogiri.rb +29 -25
- data/patches/libxml2/{0004-libxml2.la-is-in-top_builddir.patch → 0003-libxml2.la-is-in-top_builddir.patch} +1 -1
- data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
- data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
- data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
- data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
- data/ports/archives/libxml2-2.12.3.tar.xz +0 -0
- data/ports/archives/libxslt-1.1.39.tar.xz +0 -0
- metadata +121 -291
- data/ext/nokogiri/html_document.c +0 -170
- data/ext/nokogiri/html_document.h +0 -10
- data/ext/nokogiri/html_element_description.c +0 -279
- data/ext/nokogiri/html_element_description.h +0 -10
- data/ext/nokogiri/html_entity_lookup.c +0 -32
- data/ext/nokogiri/html_entity_lookup.h +0 -8
- data/ext/nokogiri/html_sax_parser_context.c +0 -116
- data/ext/nokogiri/html_sax_parser_context.h +0 -11
- data/ext/nokogiri/html_sax_push_parser.c +0 -87
- data/ext/nokogiri/html_sax_push_parser.h +0 -9
- data/ext/nokogiri/xml_attr.h +0 -9
- data/ext/nokogiri/xml_attribute_decl.h +0 -9
- data/ext/nokogiri/xml_cdata.h +0 -9
- data/ext/nokogiri/xml_comment.h +0 -9
- data/ext/nokogiri/xml_document.h +0 -23
- data/ext/nokogiri/xml_document_fragment.h +0 -10
- data/ext/nokogiri/xml_dtd.h +0 -10
- data/ext/nokogiri/xml_element_content.h +0 -10
- data/ext/nokogiri/xml_element_decl.h +0 -9
- data/ext/nokogiri/xml_encoding_handler.h +0 -8
- data/ext/nokogiri/xml_entity_decl.h +0 -10
- data/ext/nokogiri/xml_entity_reference.h +0 -9
- data/ext/nokogiri/xml_io.c +0 -61
- data/ext/nokogiri/xml_io.h +0 -11
- data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
- data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
- data/ext/nokogiri/xml_namespace.h +0 -14
- data/ext/nokogiri/xml_node.h +0 -13
- data/ext/nokogiri/xml_node_set.h +0 -12
- data/ext/nokogiri/xml_processing_instruction.h +0 -9
- data/ext/nokogiri/xml_reader.h +0 -10
- data/ext/nokogiri/xml_relax_ng.h +0 -9
- data/ext/nokogiri/xml_sax_parser.h +0 -39
- data/ext/nokogiri/xml_sax_parser_context.h +0 -10
- data/ext/nokogiri/xml_sax_push_parser.h +0 -9
- data/ext/nokogiri/xml_schema.h +0 -9
- data/ext/nokogiri/xml_syntax_error.h +0 -13
- data/ext/nokogiri/xml_text.h +0 -9
- data/ext/nokogiri/xml_xpath_context.h +0 -10
- data/ext/nokogiri/xslt_stylesheet.h +0 -14
- data/lib/nokogiri/html/document.rb +0 -335
- data/lib/nokogiri/html/document_fragment.rb +0 -49
- data/lib/nokogiri/html/element_description_defaults.rb +0 -671
- data/lib/nokogiri/html/sax/parser_context.rb +0 -16
- data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
- data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
- data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
- /data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
- /data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2018 Craig Barnes.
|
3
|
+
Copyright 2010 Google Inc.
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include "utf8.h"
|
19
|
+
|
20
|
+
#include <assert.h>
|
21
|
+
#include <stdint.h>
|
22
|
+
#include <string.h>
|
23
|
+
|
24
|
+
#include "error.h"
|
25
|
+
#include "nokogiri_gumbo.h"
|
26
|
+
#include "parser.h"
|
27
|
+
#include "ascii.h"
|
28
|
+
#include "vector.h"
|
29
|
+
|
30
|
+
// References:
|
31
|
+
// * https://tools.ietf.org/html/rfc3629
|
32
|
+
// * https://html.spec.whatwg.org/multipage/parsing.html#preprocessing-the-input-stream
|
33
|
+
|
34
|
+
// The following code is a DFA-based UTF-8 decoder by Bjoern Hoehrmann.
|
35
|
+
// We wrap the inner table-based decoder routine in our own handling for
|
36
|
+
// newlines, tabs, invalid continuation bytes, and other conditions that
|
37
|
+
// the HTML5 spec fully specifies but normal UTF-8 decoders do not handle.
|
38
|
+
// See https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
39
|
+
|
40
|
+
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
41
|
+
//
|
42
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
43
|
+
// copy of this software and associated documentation files (the "Software"),
|
44
|
+
// to deal in the Software without restriction, including without limitation
|
45
|
+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
46
|
+
// and/or sell copies of the Software, and to permit persons to whom the
|
47
|
+
// Software is furnished to do so, subject to the following conditions:
|
48
|
+
//
|
49
|
+
// The above copyright notice and this permission notice shall be included in
|
50
|
+
// all copies or substantial portions of the Software.
|
51
|
+
|
52
|
+
#define UTF8_ACCEPT 0
|
53
|
+
#define UTF8_REJECT 12
|
54
|
+
|
55
|
+
static const uint8_t utf8d[] = {
|
56
|
+
// The first part of the table maps bytes to character classes that
|
57
|
+
// to reduce the size of the transition table and create bitmasks.
|
58
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
59
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
60
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
61
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
62
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
63
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
64
|
+
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
65
|
+
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
66
|
+
|
67
|
+
// The second part is a transition table that maps a combination
|
68
|
+
// of a state of the automaton and a character class to a state.
|
69
|
+
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
70
|
+
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
71
|
+
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
72
|
+
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
73
|
+
12,36,12,12,12,12,12,12,12,12,12,12,
|
74
|
+
};
|
75
|
+
|
76
|
+
static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
|
77
|
+
uint32_t type = utf8d[byte];
|
78
|
+
|
79
|
+
*codep =
|
80
|
+
(*state != UTF8_ACCEPT)
|
81
|
+
? (byte & 0x3fu) | (*codep << 6)
|
82
|
+
: (0xff >> type) & (byte);
|
83
|
+
|
84
|
+
*state = utf8d[256 + *state + type];
|
85
|
+
return *state;
|
86
|
+
}
|
87
|
+
|
88
|
+
// END COPIED CODE.
|
89
|
+
|
90
|
+
// Adds a decoding error to the parser's error list, based on the current state
|
91
|
+
// of the Utf8Iterator.
|
92
|
+
static void add_error(Utf8Iterator* iter, GumboErrorType type) {
|
93
|
+
GumboParser* parser = iter->_parser;
|
94
|
+
|
95
|
+
GumboError* error = gumbo_add_error(parser);
|
96
|
+
if (!error) {
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
error->type = type;
|
100
|
+
error->position = iter->_pos;
|
101
|
+
error->original_text.data = iter->_start;
|
102
|
+
error->original_text.length = iter->_width;
|
103
|
+
error->v.tokenizer.codepoint = iter->_current;
|
104
|
+
}
|
105
|
+
|
106
|
+
// Reads the next UTF-8 character in the iter.
|
107
|
+
// This assumes that iter->_start points to the beginning of the character.
|
108
|
+
// When this method returns, iter->_width and iter->_current will be set
|
109
|
+
// appropriately, as well as any error flags.
|
110
|
+
static void read_char(Utf8Iterator* iter) {
|
111
|
+
if (iter->_start >= iter->_end) {
|
112
|
+
// No input left to consume; emit an EOF and set width = 0.
|
113
|
+
iter->_current = -1;
|
114
|
+
iter->_width = 0;
|
115
|
+
return;
|
116
|
+
}
|
117
|
+
|
118
|
+
uint32_t code_point = 0;
|
119
|
+
uint32_t state = UTF8_ACCEPT;
|
120
|
+
for (const char* c = iter->_start; c < iter->_end; ++c) {
|
121
|
+
decode(&state, &code_point, (uint32_t)(unsigned char) (*c));
|
122
|
+
if (state == UTF8_ACCEPT) {
|
123
|
+
iter->_width = c - iter->_start + 1;
|
124
|
+
// This is the special handling for carriage returns that is mandated by
|
125
|
+
// the HTML5 spec. Since we're looking for particular 7-bit literal
|
126
|
+
// characters, we operate in terms of chars and only need a check for iter
|
127
|
+
// overrun, instead of having to read in a full next code point.
|
128
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#preprocessing-the-input-stream
|
129
|
+
if (code_point == '\r') {
|
130
|
+
assert(iter->_width == 1);
|
131
|
+
const char* next = c + 1;
|
132
|
+
if (next < iter->_end && *next == '\n') {
|
133
|
+
// Advance the iter, as if the carriage return didn't exist.
|
134
|
+
++iter->_start;
|
135
|
+
// Preserve the true offset, since other tools that look at it may be
|
136
|
+
// unaware of HTML5's rules for converting \r into \n.
|
137
|
+
++iter->_pos.offset;
|
138
|
+
}
|
139
|
+
code_point = '\n';
|
140
|
+
}
|
141
|
+
iter->_current = code_point;
|
142
|
+
if (utf8_is_surrogate(code_point)) {
|
143
|
+
add_error(iter, GUMBO_ERR_SURROGATE_IN_INPUT_STREAM);
|
144
|
+
} else if (utf8_is_noncharacter(code_point)) {
|
145
|
+
add_error(iter, GUMBO_ERR_NONCHARACTER_IN_INPUT_STREAM);
|
146
|
+
} else if (utf8_is_control(code_point)
|
147
|
+
&& !(gumbo_ascii_isspace(code_point) || code_point == 0)) {
|
148
|
+
add_error(iter, GUMBO_ERR_CONTROL_CHARACTER_IN_INPUT_STREAM);
|
149
|
+
}
|
150
|
+
return;
|
151
|
+
} else if (state == UTF8_REJECT) {
|
152
|
+
// We don't want to consume the invalid continuation byte of a multi-byte
|
153
|
+
// run, but we do want to skip past an invalid first byte.
|
154
|
+
iter->_width = c - iter->_start + (c == iter->_start);
|
155
|
+
iter->_current = kUtf8ReplacementChar;
|
156
|
+
add_error(iter, GUMBO_ERR_UTF8_INVALID);
|
157
|
+
return;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
// If we got here without exiting early, then we've reached the end of the
|
161
|
+
// iterator. Add an error for truncated input, set the width to consume the
|
162
|
+
// rest of the iterator, and emit a replacement character. The next time we
|
163
|
+
// enter this method, it will detect that there's no input to consume and
|
164
|
+
// output an EOF.
|
165
|
+
iter->_width = iter->_end - iter->_start;
|
166
|
+
iter->_current = kUtf8ReplacementChar;
|
167
|
+
add_error(iter, GUMBO_ERR_UTF8_TRUNCATED);
|
168
|
+
}
|
169
|
+
|
170
|
+
static void update_position(Utf8Iterator* iter) {
|
171
|
+
iter->_pos.offset += iter->_width;
|
172
|
+
if (iter->_current == '\n') {
|
173
|
+
++iter->_pos.line;
|
174
|
+
iter->_pos.column = 1;
|
175
|
+
} else if (iter->_current == '\t') {
|
176
|
+
int tab_stop = iter->_parser->_options->tab_stop;
|
177
|
+
iter->_pos.column = ((iter->_pos.column / tab_stop) + 1) * tab_stop;
|
178
|
+
} else if (iter->_current != -1) {
|
179
|
+
++iter->_pos.column;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
void utf8iterator_init (
|
184
|
+
GumboParser* parser,
|
185
|
+
const char* source,
|
186
|
+
size_t source_length,
|
187
|
+
Utf8Iterator* iter
|
188
|
+
) {
|
189
|
+
iter->_start = source;
|
190
|
+
iter->_end = source + source_length;
|
191
|
+
iter->_pos.line = 1;
|
192
|
+
iter->_pos.column = 1;
|
193
|
+
iter->_pos.offset = 0;
|
194
|
+
iter->_parser = parser;
|
195
|
+
read_char(iter);
|
196
|
+
if (iter->_current == kUtf8BomChar) {
|
197
|
+
iter->_start += iter->_width;
|
198
|
+
iter->_pos.offset += iter->_width;
|
199
|
+
read_char(iter);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
void utf8iterator_next(Utf8Iterator* iter) {
|
204
|
+
// We update positions based on the *last* character read, so that the first
|
205
|
+
// character following a newline is at column 1 in the next line.
|
206
|
+
update_position(iter);
|
207
|
+
iter->_start += iter->_width;
|
208
|
+
read_char(iter);
|
209
|
+
}
|
210
|
+
|
211
|
+
bool utf8iterator_maybe_consume_match (
|
212
|
+
Utf8Iterator* iter,
|
213
|
+
const char* prefix,
|
214
|
+
size_t length,
|
215
|
+
bool case_sensitive
|
216
|
+
) {
|
217
|
+
bool matched =
|
218
|
+
(iter->_start + length <= iter->_end)
|
219
|
+
&& (
|
220
|
+
case_sensitive
|
221
|
+
? !strncmp(iter->_start, prefix, length)
|
222
|
+
: !gumbo_ascii_strncasecmp(iter->_start, prefix, length)
|
223
|
+
)
|
224
|
+
;
|
225
|
+
if (matched) {
|
226
|
+
for (size_t i = 0; i < length; ++i) {
|
227
|
+
utf8iterator_next(iter);
|
228
|
+
}
|
229
|
+
return true;
|
230
|
+
} else {
|
231
|
+
return false;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
void utf8iterator_mark(Utf8Iterator* iter) {
|
236
|
+
iter->_mark = iter->_start;
|
237
|
+
iter->_mark_pos = iter->_pos;
|
238
|
+
}
|
239
|
+
|
240
|
+
// Returns the current input stream position to the mark.
|
241
|
+
void utf8iterator_reset(Utf8Iterator* iter) {
|
242
|
+
iter->_start = iter->_mark;
|
243
|
+
iter->_pos = iter->_mark_pos;
|
244
|
+
read_char(iter);
|
245
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
#ifndef GUMBO_UTF8_H_
|
2
|
+
#define GUMBO_UTF8_H_
|
3
|
+
|
4
|
+
// This contains an implementation of a UTF-8 iterator and decoder suitable for
|
5
|
+
// a HTML5 parser. This does a bit more than straight UTF-8 decoding. The
|
6
|
+
// HTML5 spec specifies that:
|
7
|
+
// 1. Decoding errors are parse errors.
|
8
|
+
// 2. Certain other codepoints (e.g. control characters) are parse errors.
|
9
|
+
// 3. Carriage returns and CR/LF groups are converted to line feeds.
|
10
|
+
// https://encoding.spec.whatwg.org/#utf-8-decode
|
11
|
+
//
|
12
|
+
// Also, we want to keep track of source positions for error handling. As a
|
13
|
+
// result, we fold all that functionality into this decoder, and can't use an
|
14
|
+
// off-the-shelf library.
|
15
|
+
//
|
16
|
+
// This header is internal-only, which is why we prefix functions with only
|
17
|
+
// utf8_ or utf8_iterator_ instead of gumbo_utf8_.
|
18
|
+
|
19
|
+
#include <stdbool.h>
|
20
|
+
#include <stddef.h>
|
21
|
+
|
22
|
+
#include "nokogiri_gumbo.h"
|
23
|
+
#include "macros.h"
|
24
|
+
|
25
|
+
#ifdef __cplusplus
|
26
|
+
extern "C" {
|
27
|
+
#endif
|
28
|
+
|
29
|
+
struct GumboInternalError;
|
30
|
+
struct GumboInternalParser;
|
31
|
+
|
32
|
+
// Unicode replacement char.
|
33
|
+
#define kUtf8ReplacementChar 0xFFFD
|
34
|
+
#define kUtf8BomChar 0xFEFF
|
35
|
+
#define kUtf8MaxChar 0x10FFFF
|
36
|
+
|
37
|
+
typedef struct GumboInternalUtf8Iterator {
|
38
|
+
// Points at the start of the code point most recently read into 'current'.
|
39
|
+
const char* _start;
|
40
|
+
|
41
|
+
// Points at the mark. The mark is initially set to the beginning of the
|
42
|
+
// input.
|
43
|
+
const char* _mark;
|
44
|
+
|
45
|
+
// Points past the end of the iter, like a past-the-end iterator in the STL.
|
46
|
+
const char* _end;
|
47
|
+
|
48
|
+
// The code point under the cursor.
|
49
|
+
int _current;
|
50
|
+
|
51
|
+
// The width in bytes of the current code point.
|
52
|
+
size_t _width;
|
53
|
+
|
54
|
+
// The SourcePosition for the current location.
|
55
|
+
GumboSourcePosition _pos;
|
56
|
+
|
57
|
+
// The SourcePosition for the mark.
|
58
|
+
GumboSourcePosition _mark_pos;
|
59
|
+
|
60
|
+
// Pointer back to the GumboParser instance, for configuration options and
|
61
|
+
// error recording.
|
62
|
+
struct GumboInternalParser* _parser;
|
63
|
+
} Utf8Iterator;
|
64
|
+
|
65
|
+
// Returns true if this Unicode code point is a surrogate.
|
66
|
+
CONST_FN static inline bool utf8_is_surrogate(int c) {
|
67
|
+
return c >= 0xD800 && c <= 0xDFFF;
|
68
|
+
}
|
69
|
+
|
70
|
+
// Returns true if this Unicode code point is a noncharacter.
|
71
|
+
CONST_FN static inline bool utf8_is_noncharacter(int c) {
|
72
|
+
return
|
73
|
+
(c >= 0xFDD0 && c <= 0xFDEF)
|
74
|
+
|| ((c & 0xFFFF) == 0xFFFE)
|
75
|
+
|| ((c & 0xFFFF) == 0xFFFF);
|
76
|
+
}
|
77
|
+
|
78
|
+
// Returns true if this Unicode code point is a control.
|
79
|
+
CONST_FN static inline bool utf8_is_control(int c) {
|
80
|
+
return ((unsigned int)c < 0x1Fu) || (c >= 0x7F && c <= 0x9F);
|
81
|
+
}
|
82
|
+
|
83
|
+
// Initializes a new Utf8Iterator from the given byte buffer. The source does
|
84
|
+
// not have to be NUL-terminated, but the length must be passed in explicitly.
|
85
|
+
void utf8iterator_init (
|
86
|
+
struct GumboInternalParser* parser,
|
87
|
+
const char* source,
|
88
|
+
size_t source_length,
|
89
|
+
Utf8Iterator* iter
|
90
|
+
);
|
91
|
+
|
92
|
+
// Advances the current position by one code point.
|
93
|
+
void utf8iterator_next(Utf8Iterator* iter);
|
94
|
+
|
95
|
+
// Returns the current code point as an integer.
|
96
|
+
static inline int utf8iterator_current(const Utf8Iterator* iter) {
|
97
|
+
return iter->_current;
|
98
|
+
}
|
99
|
+
|
100
|
+
// Retrieves and fills the output parameter with the current source position.
|
101
|
+
static inline void utf8iterator_get_position (
|
102
|
+
const Utf8Iterator* iter,
|
103
|
+
GumboSourcePosition* output
|
104
|
+
) {
|
105
|
+
*output = iter->_pos;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Retrieves the marked position.
|
109
|
+
static inline GumboSourcePosition utf8iterator_get_mark_position (
|
110
|
+
const Utf8Iterator* iter
|
111
|
+
) {
|
112
|
+
return iter->_mark_pos;
|
113
|
+
}
|
114
|
+
|
115
|
+
// Retrieves a character pointer to the start of the current character.
|
116
|
+
static inline const char* utf8iterator_get_char_pointer(const Utf8Iterator* iter) {
|
117
|
+
return iter->_start;
|
118
|
+
}
|
119
|
+
|
120
|
+
// Retrieves the width of the current character.
|
121
|
+
static inline size_t utf8iterator_get_width(const Utf8Iterator* iter) {
|
122
|
+
return iter->_width;
|
123
|
+
}
|
124
|
+
|
125
|
+
// Retrieves a character pointer to 1 past the end of the buffer. This is
|
126
|
+
// necessary for certain state machines and string comparisons that would like
|
127
|
+
// to look directly for ASCII text in the buffer without going through the
|
128
|
+
// decoder.
|
129
|
+
static inline const char* utf8iterator_get_end_pointer(const Utf8Iterator* iter) {
|
130
|
+
return iter->_end;
|
131
|
+
}
|
132
|
+
|
133
|
+
// Retrieves a character pointer to the marked position.
|
134
|
+
static inline const char* utf8iterator_get_mark_pointer(const Utf8Iterator* iter) {
|
135
|
+
return iter->_mark;
|
136
|
+
}
|
137
|
+
|
138
|
+
// If the upcoming text in the buffer matches the specified prefix (which has
|
139
|
+
// length 'length'), consume it and return true. Otherwise, return false with
|
140
|
+
// no other effects. If the length of the string would overflow the buffer,
|
141
|
+
// this returns false. Note that prefix should not contain null bytes because
|
142
|
+
// of the use of strncmp/strncasecmp internally. All existing use-cases adhere
|
143
|
+
// to this.
|
144
|
+
bool utf8iterator_maybe_consume_match (
|
145
|
+
Utf8Iterator* iter,
|
146
|
+
const char* prefix,
|
147
|
+
size_t length,
|
148
|
+
bool case_sensitive
|
149
|
+
);
|
150
|
+
|
151
|
+
// "Marks" a particular location of interest in the input stream, so that it can
|
152
|
+
// later be reset() to. There's also the ability to record an error at the
|
153
|
+
// point that was marked, as oftentimes that's more useful than the last
|
154
|
+
// character before the error was detected.
|
155
|
+
void utf8iterator_mark(Utf8Iterator* iter);
|
156
|
+
|
157
|
+
// Returns the current input stream position to the mark.
|
158
|
+
void utf8iterator_reset(Utf8Iterator* iter);
|
159
|
+
|
160
|
+
#ifdef __cplusplus
|
161
|
+
}
|
162
|
+
#endif
|
163
|
+
|
164
|
+
#endif // GUMBO_UTF8_H_
|
@@ -0,0 +1,66 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2017-2018 Craig Barnes.
|
3
|
+
Copyright 2010 Google Inc.
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <stdio.h>
|
19
|
+
#include <stdlib.h>
|
20
|
+
#include <string.h>
|
21
|
+
#include "util.h"
|
22
|
+
#include "nokogiri_gumbo.h"
|
23
|
+
|
24
|
+
void* gumbo_alloc(size_t size) {
|
25
|
+
void* ptr = malloc(size);
|
26
|
+
if (unlikely(ptr == NULL)) {
|
27
|
+
perror(__func__);
|
28
|
+
abort();
|
29
|
+
}
|
30
|
+
return ptr;
|
31
|
+
}
|
32
|
+
|
33
|
+
void* gumbo_realloc(void* ptr, size_t size) {
|
34
|
+
ptr = realloc(ptr, size);
|
35
|
+
if (unlikely(ptr == NULL)) {
|
36
|
+
perror(__func__);
|
37
|
+
abort();
|
38
|
+
}
|
39
|
+
return ptr;
|
40
|
+
}
|
41
|
+
|
42
|
+
void gumbo_free(void* ptr) {
|
43
|
+
free(ptr);
|
44
|
+
}
|
45
|
+
|
46
|
+
char* gumbo_strdup(const char* str) {
|
47
|
+
const size_t size = strlen(str) + 1;
|
48
|
+
// The strdup(3) function isn't available in strict "-std=c99" mode
|
49
|
+
// (it's part of POSIX, not C99), so use malloc(3) and memcpy(3)
|
50
|
+
// instead:
|
51
|
+
char* buffer = gumbo_alloc(size);
|
52
|
+
return memcpy(buffer, str, size);
|
53
|
+
}
|
54
|
+
|
55
|
+
#ifdef GUMBO_DEBUG
|
56
|
+
#include <stdarg.h>
|
57
|
+
// Debug function to trace operation of the parser
|
58
|
+
// (define GUMBO_DEBUG to use).
|
59
|
+
void gumbo_debug(const char* format, ...) {
|
60
|
+
va_list args;
|
61
|
+
va_start(args, format);
|
62
|
+
vprintf(format, args);
|
63
|
+
va_end(args);
|
64
|
+
fflush(stdout);
|
65
|
+
}
|
66
|
+
#endif
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#ifndef GUMBO_UTIL_H_
|
2
|
+
#define GUMBO_UTIL_H_
|
3
|
+
|
4
|
+
#include <stdbool.h>
|
5
|
+
#include <stddef.h>
|
6
|
+
#include "macros.h"
|
7
|
+
|
8
|
+
#ifdef __cplusplus
|
9
|
+
extern "C" {
|
10
|
+
#endif
|
11
|
+
|
12
|
+
// Utility function for allocating & copying a null-terminated string into a
|
13
|
+
// freshly-allocated buffer. This is necessary for proper memory management; we
|
14
|
+
// have the convention that all const char* in parse tree structures are
|
15
|
+
// freshly-allocated, so if we didn't copy, we'd try to delete a literal string
|
16
|
+
// when the parse tree is destroyed.
|
17
|
+
char* gumbo_strdup(const char* str) XMALLOC NONNULL_ARGS;
|
18
|
+
|
19
|
+
void* gumbo_alloc(size_t size) XMALLOC;
|
20
|
+
void* gumbo_realloc(void* ptr, size_t size) RETURNS_NONNULL;
|
21
|
+
void gumbo_free(void* ptr);
|
22
|
+
|
23
|
+
// Debug wrapper for printf
|
24
|
+
#ifdef GUMBO_DEBUG
|
25
|
+
void gumbo_debug(const char* format, ...) PRINTF(1);
|
26
|
+
#else
|
27
|
+
static inline void PRINTF(1) gumbo_debug(const char* UNUSED_ARG(format), ...) {};
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#ifdef __cplusplus
|
31
|
+
}
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#endif // GUMBO_UTIL_H_
|
@@ -0,0 +1,111 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2018 Craig Barnes.
|
3
|
+
Copyright 2010 Google Inc.
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <assert.h>
|
19
|
+
#include <stdlib.h>
|
20
|
+
#include <string.h>
|
21
|
+
#include "vector.h"
|
22
|
+
#include "util.h"
|
23
|
+
|
24
|
+
void gumbo_vector_init(unsigned int initial_capacity, GumboVector* vector) {
|
25
|
+
vector->length = 0;
|
26
|
+
vector->capacity = initial_capacity;
|
27
|
+
if (initial_capacity > 0) {
|
28
|
+
vector->data = gumbo_alloc(sizeof(void*) * initial_capacity);
|
29
|
+
} else {
|
30
|
+
vector->data = NULL;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
void gumbo_vector_destroy(GumboVector* vector) {
|
35
|
+
if (vector->capacity > 0) {
|
36
|
+
gumbo_free(vector->data);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
static void enlarge_vector_if_full(GumboVector* vector) {
|
41
|
+
if (vector->length >= vector->capacity) {
|
42
|
+
if (vector->capacity) {
|
43
|
+
vector->capacity *= 2;
|
44
|
+
size_t num_bytes = sizeof(void*) * vector->capacity;
|
45
|
+
vector->data = gumbo_realloc(vector->data, num_bytes);
|
46
|
+
} else {
|
47
|
+
// 0-capacity vector; no previous array to deallocate.
|
48
|
+
vector->capacity = 2;
|
49
|
+
vector->data = gumbo_alloc(sizeof(void*) * vector->capacity);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
void gumbo_vector_add(void* element, GumboVector* vector) {
|
55
|
+
enlarge_vector_if_full(vector);
|
56
|
+
assert(vector->data);
|
57
|
+
assert(vector->length < vector->capacity);
|
58
|
+
vector->data[vector->length++] = element;
|
59
|
+
}
|
60
|
+
|
61
|
+
void* gumbo_vector_pop(GumboVector* vector) {
|
62
|
+
if (vector->length == 0) {
|
63
|
+
return NULL;
|
64
|
+
}
|
65
|
+
return vector->data[--vector->length];
|
66
|
+
}
|
67
|
+
|
68
|
+
int gumbo_vector_index_of(GumboVector* vector, const void* element) {
|
69
|
+
for (unsigned int i = 0; i < vector->length; ++i) {
|
70
|
+
if (vector->data[i] == element) {
|
71
|
+
return i;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
return -1;
|
75
|
+
}
|
76
|
+
|
77
|
+
void gumbo_vector_insert_at (
|
78
|
+
void* element,
|
79
|
+
unsigned int index,
|
80
|
+
GumboVector* vector
|
81
|
+
) {
|
82
|
+
assert(index <= vector->length);
|
83
|
+
enlarge_vector_if_full(vector);
|
84
|
+
++vector->length;
|
85
|
+
memmove (
|
86
|
+
&vector->data[index + 1],
|
87
|
+
&vector->data[index],
|
88
|
+
sizeof(void*) * (vector->length - index - 1)
|
89
|
+
);
|
90
|
+
vector->data[index] = element;
|
91
|
+
}
|
92
|
+
|
93
|
+
void gumbo_vector_remove(void* node, GumboVector* vector) {
|
94
|
+
int index = gumbo_vector_index_of(vector, node);
|
95
|
+
if (index == -1) {
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
gumbo_vector_remove_at(index, vector);
|
99
|
+
}
|
100
|
+
|
101
|
+
void* gumbo_vector_remove_at(unsigned int index, GumboVector* vector) {
|
102
|
+
assert(index < vector->length);
|
103
|
+
void* result = vector->data[index];
|
104
|
+
memmove (
|
105
|
+
&vector->data[index],
|
106
|
+
&vector->data[index + 1],
|
107
|
+
sizeof(void*) * (vector->length - index - 1)
|
108
|
+
);
|
109
|
+
--vector->length;
|
110
|
+
return result;
|
111
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#ifndef GUMBO_VECTOR_H_
|
2
|
+
#define GUMBO_VECTOR_H_
|
3
|
+
|
4
|
+
#include "nokogiri_gumbo.h"
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
// Initializes a new GumboVector with the specified initial capacity.
|
11
|
+
void gumbo_vector_init(unsigned int initial_capacity, GumboVector* vector);
|
12
|
+
|
13
|
+
// Frees the memory used by a GumboVector. Does not free the contained
|
14
|
+
// pointers.
|
15
|
+
void gumbo_vector_destroy(GumboVector* vector);
|
16
|
+
|
17
|
+
// Adds a new element to a GumboVector.
|
18
|
+
void gumbo_vector_add(void* element, GumboVector* vector);
|
19
|
+
|
20
|
+
// Removes and returns the element most recently added to the GumboVector.
|
21
|
+
// Ownership is transferred to caller. Capacity is unchanged. If the vector is
|
22
|
+
// empty, NULL is returned.
|
23
|
+
void* gumbo_vector_pop(GumboVector* vector);
|
24
|
+
|
25
|
+
// Inserts an element at a specific index. This is potentially O(N) time, but
|
26
|
+
// is necessary for some of the spec's behavior.
|
27
|
+
void gumbo_vector_insert_at (
|
28
|
+
void* element,
|
29
|
+
unsigned int index,
|
30
|
+
GumboVector* vector
|
31
|
+
);
|
32
|
+
|
33
|
+
// Removes an element from the vector, or does nothing if the element is not in
|
34
|
+
// the vector.
|
35
|
+
void gumbo_vector_remove(void* element, GumboVector* vector);
|
36
|
+
|
37
|
+
// Removes and returns an element at a specific index. Note that this is
|
38
|
+
// potentially O(N) time and should be used sparingly.
|
39
|
+
void* gumbo_vector_remove_at(unsigned int index, GumboVector* vector);
|
40
|
+
|
41
|
+
#ifdef __cplusplus
|
42
|
+
}
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#endif // GUMBO_VECTOR_H_
|