nokogiri 1.19.3 → 1.19.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE-DEPENDENCIES.md +29 -0
- data/ext/nokogiri/extconf.rb +1 -0
- data/ext/nokogiri/gumbo.c +83 -6
- data/ext/nokogiri/html4_document.c +10 -3
- data/ext/nokogiri/libxml2_polyfill.c +12 -0
- data/ext/nokogiri/nokogiri.c +90 -5
- data/ext/nokogiri/nokogiri.h +30 -3
- data/ext/nokogiri/xml_attr.c +28 -23
- data/ext/nokogiri/xml_document.c +64 -30
- data/ext/nokogiri/xml_node.c +151 -52
- data/ext/nokogiri/xml_node_set.c +10 -10
- data/ext/nokogiri/xml_reader.c +198 -107
- data/ext/nokogiri/xml_sax_parser.c +3 -3
- data/ext/nokogiri/xml_sax_parser_context.c +38 -7
- data/ext/nokogiri/xml_sax_push_parser.c +12 -0
- data/ext/nokogiri/xml_xpath_context.c +135 -27
- data/ext/nokogiri/xslt_stylesheet.c +123 -27
- data/gumbo-parser/src/Makefile +2 -0
- data/gumbo-parser/src/hashmap.c +1154 -0
- data/gumbo-parser/src/hashmap.h +62 -0
- data/gumbo-parser/src/parser.c +49 -13
- data/gumbo-parser/src/string_set.c +41 -0
- data/gumbo-parser/src/string_set.h +21 -0
- data/gumbo-parser/src/tokenizer.c +49 -19
- data/lib/nokogiri/css/parser.rb +35 -18
- data/lib/nokogiri/css/parser.y +35 -17
- data/lib/nokogiri/css/xpath_visitor.rb +71 -28
- data/lib/nokogiri/html5/document.rb +9 -0
- data/lib/nokogiri/html5/document_fragment.rb +16 -1
- data/lib/nokogiri/html5/node.rb +1 -1
- data/lib/nokogiri/html5.rb +16 -0
- data/lib/nokogiri/version/constant.rb +1 -1
- data/lib/nokogiri/version/info.rb +10 -0
- data/lib/nokogiri/xml/attr.rb +2 -0
- data/lib/nokogiri/xml/attribute_decl.rb +2 -1
- data/lib/nokogiri/xml/builder.rb +24 -32
- data/lib/nokogiri/xml/document.rb +4 -2
- data/lib/nokogiri/xml/dtd.rb +2 -1
- data/lib/nokogiri/xml/element_decl.rb +2 -1
- data/lib/nokogiri/xml/entity_decl.rb +2 -1
- data/lib/nokogiri/xml/node.rb +65 -12
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b6ae8d128fac90392dfbe122d0c1e1e8c056fd6dc1c49cfecdef2ac1d09788f
|
|
4
|
+
data.tar.gz: 315ef5552e29320fe8008f9fceff8316718ce263668bf13d1e2f015715203540
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18e131261027295c823d6e4b4d4d0c739ac8dcfc2a5d570409f3081917f39b4c69f6719f55eb4a9e78c34e390c442abb50267bd9e0cfe8a25bfd3076a4de0bdd
|
|
7
|
+
data.tar.gz: 9ac2042bf9ce20532e61b2b0e29b9582127c034914ddf370bde9a6b0b8abad067c1e4030551451c2f171bb3b48981f83b69aa2c8b45ddb939ffd3fe88d1453ba
|
data/LICENSE-DEPENDENCIES.md
CHANGED
|
@@ -15,6 +15,7 @@ Note that this document is broken into multiple sections, each of which describe
|
|
|
15
15
|
* [Native WindowsⓇ platform releases ("x64-mingw-ucrt")](#native-windows%E2%93%A1-platform-releases-x64-mingw-ucrt)
|
|
16
16
|
* [JavaⓇ (JRuby) platform release ("java")](#java%E2%93%A1-jruby-platform-release-java)
|
|
17
17
|
- [Appendix: Dependencies' License Texts](#appendix-dependencies-license-texts)
|
|
18
|
+
* [hashmap.c](#hashmapc)
|
|
18
19
|
* [libgumbo](#libgumbo)
|
|
19
20
|
* [libxml2](#libxml2)
|
|
20
21
|
* [libxslt](#libxslt)
|
|
@@ -114,6 +115,34 @@ This section contains a subsection for each potentially-distributed dependency,
|
|
|
114
115
|
Please see previous sections to understand which of these potential dependencies is actually distributed in the gem file you're downloading and using.
|
|
115
116
|
|
|
116
117
|
|
|
118
|
+
### hashmap.c
|
|
119
|
+
|
|
120
|
+
MIT
|
|
121
|
+
|
|
122
|
+
https://github.com/tidwall/hashmap.c/blob/master/LICENSE
|
|
123
|
+
|
|
124
|
+
The MIT License (MIT)
|
|
125
|
+
|
|
126
|
+
Copyright (c) 2020 Joshua J Baker
|
|
127
|
+
|
|
128
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
129
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
130
|
+
the Software without restriction, including without limitation the rights to
|
|
131
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
132
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
133
|
+
subject to the following conditions:
|
|
134
|
+
|
|
135
|
+
The above copyright notice and this permission notice shall be included in all
|
|
136
|
+
copies or substantial portions of the Software.
|
|
137
|
+
|
|
138
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
139
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
140
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
141
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
142
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
143
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
144
|
+
|
|
145
|
+
|
|
117
146
|
### libgumbo
|
|
118
147
|
|
|
119
148
|
Apache 2.0
|
data/ext/nokogiri/extconf.rb
CHANGED
|
@@ -1125,6 +1125,7 @@ end
|
|
|
1125
1125
|
have_func("xmlCtxtSetOptions") # introduced in libxml2 2.13.0
|
|
1126
1126
|
have_func("xmlCtxtGetOptions") # introduced in libxml2 2.14.0
|
|
1127
1127
|
have_func("xmlSwitchEncodingName") # introduced in libxml2 2.13.0
|
|
1128
|
+
have_func("xmlAddIDSafe") # introduced in libxml2 2.13.0
|
|
1128
1129
|
have_func("rb_category_warning") # introduced in Ruby 3.0 but had trouble resolving this symbol in truffleruby
|
|
1129
1130
|
|
|
1130
1131
|
other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",")
|
data/ext/nokogiri/gumbo.c
CHANGED
|
@@ -113,6 +113,71 @@ set_line(xmlNodePtr node, size_t line)
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
// This function is essentially xmlNewNsProp, but we skip the full list traversal to append by
|
|
117
|
+
// providing the last property in the linked list as a parameter.
|
|
118
|
+
static xmlAttrPtr
|
|
119
|
+
append_property(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value, xmlAttrPtr last_prop)
|
|
120
|
+
{
|
|
121
|
+
xmlAttrPtr cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
|
|
122
|
+
if (cur == NULL) {
|
|
123
|
+
return NULL;
|
|
124
|
+
}
|
|
125
|
+
memset(cur, 0, sizeof(xmlAttr));
|
|
126
|
+
cur->type = XML_ATTRIBUTE_NODE;
|
|
127
|
+
cur->parent = node;
|
|
128
|
+
xmlDocPtr doc = node->doc;
|
|
129
|
+
cur->doc = doc;
|
|
130
|
+
cur->ns = ns;
|
|
131
|
+
|
|
132
|
+
if ((doc != NULL) && (doc->dict != NULL)) {
|
|
133
|
+
cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
|
|
134
|
+
} else {
|
|
135
|
+
cur->name = xmlStrdup(name);
|
|
136
|
+
}
|
|
137
|
+
if (cur->name == NULL) {
|
|
138
|
+
goto error;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (value != NULL) {
|
|
142
|
+
cur->children = xmlNewDocText(doc, value);
|
|
143
|
+
if (cur->children == NULL) {
|
|
144
|
+
goto error;
|
|
145
|
+
}
|
|
146
|
+
cur->last = NULL;
|
|
147
|
+
xmlNodePtr tmp = cur->children;
|
|
148
|
+
while (tmp != NULL) {
|
|
149
|
+
tmp->parent = (xmlNodePtr) cur;
|
|
150
|
+
if (tmp->next == NULL) {
|
|
151
|
+
cur->last = tmp;
|
|
152
|
+
}
|
|
153
|
+
tmp = tmp->next;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (doc != NULL) {
|
|
157
|
+
int res = xmlIsID(doc, node, cur);
|
|
158
|
+
if (res < 0) {
|
|
159
|
+
goto error;
|
|
160
|
+
}
|
|
161
|
+
if ((res == 1) && (xmlAddIDSafe(cur, value) < 0)) {
|
|
162
|
+
goto error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (node->properties == NULL) {
|
|
168
|
+
node->properties = cur;
|
|
169
|
+
} else {
|
|
170
|
+
last_prop->next = cur;
|
|
171
|
+
cur->prev = last_prop;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return cur;
|
|
175
|
+
|
|
176
|
+
error:
|
|
177
|
+
xmlFreeProp(cur);
|
|
178
|
+
return (NULL);
|
|
179
|
+
}
|
|
180
|
+
|
|
116
181
|
// Construct an XML tree rooted at xml_output_node from the Gumbo tree rooted
|
|
117
182
|
// at gumbo_node.
|
|
118
183
|
static void
|
|
@@ -200,6 +265,7 @@ build_tree(
|
|
|
200
265
|
xmlAddChild(xml_node, xml_child);
|
|
201
266
|
|
|
202
267
|
// Add the attributes.
|
|
268
|
+
xmlAttrPtr last_prop = NULL;
|
|
203
269
|
const GumboVector *attrs = &gumbo_child->v.element.attributes;
|
|
204
270
|
for (size_t i = 0; i < attrs->length; i++) {
|
|
205
271
|
const GumboAttribute *attr = attrs->data[i];
|
|
@@ -220,7 +286,9 @@ build_tree(
|
|
|
220
286
|
default:
|
|
221
287
|
ns = NULL;
|
|
222
288
|
}
|
|
223
|
-
|
|
289
|
+
|
|
290
|
+
// We micromanage the attribute list for performance reasons.
|
|
291
|
+
last_prop = append_property(xml_child, ns, (const xmlChar *)attr->name, (const xmlChar *)attr->value, last_prop);
|
|
224
292
|
}
|
|
225
293
|
|
|
226
294
|
// Add children for this element.
|
|
@@ -373,12 +441,20 @@ parse_continue(VALUE parse_args)
|
|
|
373
441
|
} else {
|
|
374
442
|
doc = new_html_doc(NULL, NULL, NULL);
|
|
375
443
|
}
|
|
376
|
-
|
|
444
|
+
|
|
445
|
+
// We're about to build the libxml2 tree structure from the Gumbo tree
|
|
446
|
+
// structure. If an exception is raised during tree building, control passes
|
|
447
|
+
// to `parse_cleanup()` which needs to free the newly allocated `xmlDoc`,
|
|
448
|
+
// `doc`. If the tree is successfully constructed, then
|
|
449
|
+
// `noko_xml_document_wrap()` will create a new Ruby object which will own
|
|
450
|
+
// `doc`. In that case, `parse_cleanup()` should not free `doc`.
|
|
451
|
+
args->doc = doc;
|
|
377
452
|
build_tree(doc, (xmlNodePtr)doc, output->document);
|
|
453
|
+
args->doc = NULL;
|
|
378
454
|
VALUE rdoc = noko_xml_document_wrap(args->klass, doc);
|
|
455
|
+
|
|
379
456
|
rb_iv_set(rdoc, "@url", args->url_or_frag);
|
|
380
457
|
rb_iv_set(rdoc, "@quirks_mode", INT2NUM(output->document->v.document.doc_type_quirks_mode));
|
|
381
|
-
args->doc = NULL; // The Ruby runtime now owns doc so don't delete it.
|
|
382
458
|
add_errors(output, rdoc, args->input, args->url_or_frag);
|
|
383
459
|
return rdoc;
|
|
384
460
|
}
|
|
@@ -512,6 +588,7 @@ error:
|
|
|
512
588
|
continue;
|
|
513
589
|
}
|
|
514
590
|
VALUE element_name = rb_funcall(node, name, 0);
|
|
591
|
+
Check_Type(element_name, T_STRING);
|
|
515
592
|
if (RSTRING_LEN(element_name) == 4
|
|
516
593
|
&& !st_strcasecmp(RSTRING_PTR(element_name), "form")
|
|
517
594
|
&& lookup_namespace(node, false) == GUMBO_NAMESPACE_HTML) {
|
|
@@ -568,7 +645,7 @@ error:
|
|
|
568
645
|
.output = output,
|
|
569
646
|
.input = tags,
|
|
570
647
|
.url_or_frag = doc_fragment,
|
|
571
|
-
.doc =
|
|
648
|
+
.doc = NULL,
|
|
572
649
|
};
|
|
573
650
|
rb_ensure(fragment_continue, (VALUE)(&args), parse_cleanup, (VALUE)(&args));
|
|
574
651
|
return Qnil;
|
|
@@ -580,9 +657,9 @@ fragment_continue(VALUE parse_args)
|
|
|
580
657
|
ParseArgs *args = (ParseArgs *)parse_args;
|
|
581
658
|
GumboOutput *output = args->output;
|
|
582
659
|
VALUE doc_fragment = args->url_or_frag;
|
|
583
|
-
|
|
660
|
+
VALUE doc = rb_funcall(doc_fragment, rb_intern_const("document"), 0);
|
|
661
|
+
xmlDocPtr xml_doc = (xmlDocPtr)extract_xml_node(doc);
|
|
584
662
|
|
|
585
|
-
args->doc = NULL; // The Ruby runtime owns doc so make sure we don't delete it.
|
|
586
663
|
xmlNodePtr xml_frag = extract_xml_node(doc_fragment);
|
|
587
664
|
build_tree(xml_doc, xml_frag, output->root);
|
|
588
665
|
rb_iv_set(doc_fragment, "@quirks_mode", INT2NUM(output->document->v.document.doc_type_quirks_mode));
|
|
@@ -18,8 +18,8 @@ rb_html_document_s_new(int argc, VALUE *argv, VALUE klass)
|
|
|
18
18
|
htmlDocPtr doc;
|
|
19
19
|
|
|
20
20
|
rb_scan_args(argc, argv, "0*", &rest);
|
|
21
|
-
uri = rb_ary_entry(rest, (
|
|
22
|
-
external_id = rb_ary_entry(rest, (
|
|
21
|
+
uri = rb_ary_entry(rest, (rb_len_t)0);
|
|
22
|
+
external_id = rb_ary_entry(rest, (rb_len_t)1);
|
|
23
23
|
|
|
24
24
|
doc = htmlNewDoc(
|
|
25
25
|
RTEST(uri) ? (const xmlChar *)StringValueCStr(uri) : NULL,
|
|
@@ -48,10 +48,17 @@ rb_html_document_s_read_io(VALUE klass, VALUE rb_io, VALUE rb_url, VALUE rb_enco
|
|
|
48
48
|
|
|
49
49
|
xmlSetStructuredErrorFunc((void *)rb_error_list, noko__error_array_pusher);
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
noko_io_read_reset_exception();
|
|
52
|
+
c_doc = htmlReadIO(noko_io_read_protected, noko_io_close, (void *)rb_io, c_url, c_encoding, options);
|
|
53
|
+
VALUE rb_io_read_exception = noko_io_read_take_exception();
|
|
52
54
|
|
|
53
55
|
xmlSetStructuredErrorFunc(NULL, NULL);
|
|
54
56
|
|
|
57
|
+
if (!NIL_P(rb_io_read_exception)) {
|
|
58
|
+
xmlFreeDoc(c_doc);
|
|
59
|
+
noko_io_read_raise_exception(rb_io_read_exception);
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
/*
|
|
56
63
|
* If EncodingFound has occurred in EncodingReader, make sure to do
|
|
57
64
|
* a cleanup and propagate the error.
|
|
@@ -112,3 +112,15 @@ xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding)
|
|
|
112
112
|
return (xmlSwitchToEncoding(ctxt, handler));
|
|
113
113
|
}
|
|
114
114
|
#endif
|
|
115
|
+
|
|
116
|
+
#ifndef HAVE_XMLADDIDSAFE
|
|
117
|
+
int
|
|
118
|
+
xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value)
|
|
119
|
+
{
|
|
120
|
+
xmlIDPtr id = xmlAddID(NULL, attr->doc, value, attr);
|
|
121
|
+
if (id) {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
#endif
|
data/ext/nokogiri/nokogiri.c
CHANGED
|
@@ -50,7 +50,7 @@ void noko_init_html4_sax_parser(void);
|
|
|
50
50
|
void noko_init_gumbo(void);
|
|
51
51
|
void noko_init_test_global_handlers(void);
|
|
52
52
|
|
|
53
|
-
static ID id_read, id_write, id_external_encoding;
|
|
53
|
+
static ID id_read, id_write, id_external_encoding, id_io_read_exception;
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
static VALUE
|
|
@@ -92,6 +92,87 @@ noko_io_read(void *io, char *c_buffer, int c_buffer_len)
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
typedef struct {
|
|
96
|
+
void *io;
|
|
97
|
+
char *c_buffer;
|
|
98
|
+
int c_buffer_len;
|
|
99
|
+
int n_bytes_read;
|
|
100
|
+
} noko_io_read_args_t;
|
|
101
|
+
|
|
102
|
+
static VALUE
|
|
103
|
+
noko_io_read_call(VALUE data)
|
|
104
|
+
{
|
|
105
|
+
noko_io_read_args_t *args = (noko_io_read_args_t *)data;
|
|
106
|
+
args->n_bytes_read = noko_io_read(args->io, args->c_buffer, args->c_buffer_len);
|
|
107
|
+
return Qnil;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Like noko_io_read, a StandardError raised by IO#read is swallowed, and libxml2 sees a read
|
|
113
|
+
* error. Any other exception (e.g., Interrupt or Timeout::ExitException) must not unwind through
|
|
114
|
+
* libxml2's stack frames, because that skips libxml2's cleanup and leaks memory, and skips the
|
|
115
|
+
* reset of the error handlers. So it is saved in a fiber-local variable, and $! is cleared until
|
|
116
|
+
* it is re-raised.
|
|
117
|
+
*
|
|
118
|
+
* A caller of libxml2 that passes this callback must call noko_io_read_reset_exception before
|
|
119
|
+
* calling libxml2, and noko_io_read_take_exception after libxml2 returns, and must re-raise a
|
|
120
|
+
* non-nil result with noko_io_read_raise_exception.
|
|
121
|
+
*/
|
|
122
|
+
int
|
|
123
|
+
noko_io_read_protected(void *io, char *c_buffer, int c_buffer_len)
|
|
124
|
+
{
|
|
125
|
+
noko_io_read_args_t args = { io, c_buffer, c_buffer_len, -1 };
|
|
126
|
+
int state = 0;
|
|
127
|
+
|
|
128
|
+
rb_protect(noko_io_read_call, (VALUE)&args, &state);
|
|
129
|
+
|
|
130
|
+
if (state) {
|
|
131
|
+
VALUE rb_errinfo_value = rb_errinfo();
|
|
132
|
+
if (RB_TYPE_P(rb_errinfo_value, T_OBJECT) && rb_obj_is_kind_of(rb_errinfo_value, rb_eException)) {
|
|
133
|
+
rb_set_errinfo(Qnil);
|
|
134
|
+
} else {
|
|
135
|
+
rb_errinfo_value = Qnil;
|
|
136
|
+
}
|
|
137
|
+
rb_thread_local_aset(rb_thread_current(), id_io_read_exception,
|
|
138
|
+
rb_assoc_new(INT2FIX(state), rb_errinfo_value));
|
|
139
|
+
return -1;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return args.n_bytes_read;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
void
|
|
147
|
+
noko_io_read_reset_exception(void)
|
|
148
|
+
{
|
|
149
|
+
rb_thread_local_aset(rb_thread_current(), id_io_read_exception, Qnil);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
VALUE
|
|
154
|
+
noko_io_read_take_exception(void)
|
|
155
|
+
{
|
|
156
|
+
VALUE rb_thread = rb_thread_current();
|
|
157
|
+
VALUE rb_exception = rb_thread_local_aref(rb_thread, id_io_read_exception);
|
|
158
|
+
|
|
159
|
+
rb_thread_local_aset(rb_thread, id_io_read_exception, Qnil);
|
|
160
|
+
return rb_exception;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
void
|
|
165
|
+
noko_io_read_raise_exception(VALUE rb_exception)
|
|
166
|
+
{
|
|
167
|
+
VALUE rb_errinfo_value = rb_ary_entry(rb_exception, 1);
|
|
168
|
+
|
|
169
|
+
if (!NIL_P(rb_errinfo_value)) {
|
|
170
|
+
rb_set_errinfo(rb_errinfo_value);
|
|
171
|
+
}
|
|
172
|
+
rb_jump_tag(FIX2INT(rb_ary_entry(rb_exception, 0)));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
95
176
|
static VALUE
|
|
96
177
|
noko_io_write_check(VALUE rb_args)
|
|
97
178
|
{
|
|
@@ -122,7 +203,7 @@ noko_io_write(void *io, char *c_buffer, int c_buffer_len)
|
|
|
122
203
|
io_encoding = RB_NIL_P(rb_enc) ? rb_ascii8bit_encoding() : rb_to_encoding(rb_enc);
|
|
123
204
|
|
|
124
205
|
rb_args[0] = rb_io;
|
|
125
|
-
rb_args[1] = rb_enc_str_new(c_buffer, (
|
|
206
|
+
rb_args[1] = rb_enc_str_new(c_buffer, (rb_len_t)c_buffer_len, io_encoding);
|
|
126
207
|
|
|
127
208
|
rb_n_bytes_written = rb_rescue(noko_io_write_check, (VALUE)rb_args, noko_io_write_failed, 0);
|
|
128
209
|
if (rb_n_bytes_written == Qundef) { return -1; }
|
|
@@ -203,9 +284,6 @@ Init_nokogiri(void)
|
|
|
203
284
|
rb_const_set(mNokogiri, rb_intern("LIBXSLT_COMPILED_VERSION"), NOKOGIRI_STR_NEW2(LIBXSLT_DOTTED_VERSION));
|
|
204
285
|
rb_const_set(mNokogiri, rb_intern("LIBXSLT_LOADED_VERSION"), NOKOGIRI_STR_NEW2(xsltEngineVersion));
|
|
205
286
|
|
|
206
|
-
rb_const_set(mNokogiri, rb_intern("LIBXML_ZLIB_ENABLED"),
|
|
207
|
-
xmlHasFeature(XML_WITH_ZLIB) == 1 ? Qtrue : Qfalse);
|
|
208
|
-
|
|
209
287
|
#ifdef NOKOGIRI_PACKAGED_LIBRARIES
|
|
210
288
|
rb_const_set(mNokogiri, rb_intern("PACKAGED_LIBRARIES"), Qtrue);
|
|
211
289
|
# ifdef NOKOGIRI_PRECOMPILED_LIBRARIES
|
|
@@ -228,6 +306,12 @@ Init_nokogiri(void)
|
|
|
228
306
|
rb_const_set(mNokogiri, rb_intern("LIBXML_ICONV_ENABLED"), Qfalse);
|
|
229
307
|
#endif
|
|
230
308
|
|
|
309
|
+
rb_const_set(mNokogiri, rb_intern("LIBXML_ZLIB_ENABLED"),
|
|
310
|
+
xmlHasFeature(XML_WITH_ZLIB) == 1 ? Qtrue : Qfalse);
|
|
311
|
+
|
|
312
|
+
rb_const_set(mNokogiri, rb_intern("LIBXML_HTTP_ENABLED"),
|
|
313
|
+
xmlHasFeature(XML_WITH_HTTP) == 1 ? Qtrue : Qfalse);
|
|
314
|
+
|
|
231
315
|
#ifdef NOKOGIRI_OTHER_LIBRARY_VERSIONS
|
|
232
316
|
rb_const_set(mNokogiri, rb_intern("OTHER_LIBRARY_VERSIONS"), NOKOGIRI_STR_NEW2(NOKOGIRI_OTHER_LIBRARY_VERSIONS));
|
|
233
317
|
#endif
|
|
@@ -289,6 +373,7 @@ Init_nokogiri(void)
|
|
|
289
373
|
noko_init_test_global_handlers();
|
|
290
374
|
|
|
291
375
|
id_read = rb_intern("read");
|
|
376
|
+
id_io_read_exception = rb_intern("__nokogiri_io_read_exception");
|
|
292
377
|
id_write = rb_intern("write");
|
|
293
378
|
id_external_encoding = rb_intern("external_encoding");
|
|
294
379
|
}
|
data/ext/nokogiri/nokogiri.h
CHANGED
|
@@ -66,6 +66,9 @@ int xmlCtxtGetOptions(xmlParserCtxtPtr ctxt);
|
|
|
66
66
|
#ifndef HAVE_XMLSWITCHENCODINGNAME
|
|
67
67
|
int xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding);
|
|
68
68
|
#endif
|
|
69
|
+
#ifndef HAVE_XMLADDIDSAFE
|
|
70
|
+
int xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value);
|
|
71
|
+
#endif
|
|
69
72
|
|
|
70
73
|
#define XMLNS_PREFIX "xmlns"
|
|
71
74
|
#define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
|
|
@@ -85,7 +88,7 @@ int xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding);
|
|
|
85
88
|
#include <ruby/version.h>
|
|
86
89
|
|
|
87
90
|
#define NOKOGIRI_STR_NEW2(str) NOKOGIRI_STR_NEW(str, strlen((const char *)(str)))
|
|
88
|
-
#define NOKOGIRI_STR_NEW(str, len) rb_external_str_new_with_enc((const char *)(str), (
|
|
91
|
+
#define NOKOGIRI_STR_NEW(str, len) rb_external_str_new_with_enc((const char *)(str), (rb_len_t)(len), rb_utf8_encoding())
|
|
89
92
|
#define RBSTR_OR_QNIL(_str) (_str ? NOKOGIRI_STR_NEW2(_str) : Qnil)
|
|
90
93
|
|
|
91
94
|
#ifndef NORETURN_DECL
|
|
@@ -178,11 +181,24 @@ void noko_xml_document_pin_namespace(xmlNsPtr, xmlDocPtr);
|
|
|
178
181
|
int noko_xml_document_has_wrapped_blank_nodes_p(xmlDocPtr c_document);
|
|
179
182
|
|
|
180
183
|
int noko_io_read(void *ctx, char *buffer, int len);
|
|
184
|
+
int noko_io_read_protected(void *ctx, char *buffer, int len);
|
|
185
|
+
void noko_io_read_reset_exception(void);
|
|
186
|
+
VALUE noko_io_read_take_exception(void);
|
|
187
|
+
NORETURN_DECL void noko_io_read_raise_exception(VALUE rb_exception);
|
|
181
188
|
int noko_io_write(void *ctx, char *buffer, int len);
|
|
182
189
|
int noko_io_close(void *ctx);
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
static inline void *
|
|
192
|
+
_noko_data_ptr(VALUE rb_object)
|
|
193
|
+
{
|
|
194
|
+
void *c_data = DATA_PTR(rb_object);
|
|
195
|
+
if (c_data == NULL) {
|
|
196
|
+
rb_raise(rb_eRuntimeError, "Uninitialized %" PRIsVALUE " struct (null data pointer)", rb_obj_class(rb_object));
|
|
197
|
+
}
|
|
198
|
+
return c_data;
|
|
199
|
+
}
|
|
200
|
+
#define Noko_Node_Get_Struct(obj,type,sval) ((sval) = (type*)_noko_data_ptr(obj))
|
|
201
|
+
#define Noko_Namespace_Get_Struct(obj,type,sval) ((sval) = (type*)_noko_data_ptr(obj))
|
|
186
202
|
|
|
187
203
|
VALUE noko_xml_node_wrap(VALUE klass, xmlNodePtr node) ;
|
|
188
204
|
VALUE noko_xml_node_wrap_node_set_result(xmlNodePtr node, VALUE node_set) ;
|
|
@@ -225,6 +241,17 @@ void noko_xml_sax_parser_context_set_encoding(xmlParserCtxtPtr c_context, VALUE
|
|
|
225
241
|
# define NOKO_WARN_DEPRECATION(message...) rb_warning(message)
|
|
226
242
|
#endif
|
|
227
243
|
|
|
244
|
+
#ifndef HAVE_RB_LEN_T
|
|
245
|
+
typedef long rb_len_t;
|
|
246
|
+
#endif
|
|
247
|
+
#ifndef RB_NUM2LEN
|
|
248
|
+
#define RB_NUM2LEN RB_NUM2LONG
|
|
249
|
+
#endif
|
|
250
|
+
/* Ruby 4.1.0-preview1 defines HAVE_RB_LEN_T but not RB_FIX2LEN, which came later. */
|
|
251
|
+
#ifndef RB_FIX2LEN
|
|
252
|
+
#define RB_FIX2LEN RB_FIX2LONG
|
|
253
|
+
#endif
|
|
254
|
+
|
|
228
255
|
void noko__structured_error_func_save(libxmlStructuredErrorHandlerState *handler_state);
|
|
229
256
|
void noko__structured_error_func_save_and_set(libxmlStructuredErrorHandlerState *handler_state, void *user_data,
|
|
230
257
|
xmlStructuredErrorFunc handler);
|
data/ext/nokogiri/xml_attr.c
CHANGED
|
@@ -10,37 +10,42 @@ VALUE cNokogiriXmlAttr;
|
|
|
10
10
|
* (e.g., a HTML boolean attribute).
|
|
11
11
|
*/
|
|
12
12
|
static VALUE
|
|
13
|
-
|
|
13
|
+
noko_xml_attr_set_value(VALUE self, VALUE content)
|
|
14
14
|
{
|
|
15
15
|
xmlAttrPtr attr;
|
|
16
|
-
xmlChar *value;
|
|
17
|
-
xmlNode *cur;
|
|
18
16
|
|
|
19
17
|
Noko_Node_Get_Struct(self, xmlAttr, attr);
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
{
|
|
20
|
+
/* Unlink and pin any wrapped children */
|
|
21
|
+
xmlNode *cur = attr->children;
|
|
22
|
+
xmlNode *next;
|
|
23
|
+
|
|
24
|
+
while (cur) {
|
|
25
|
+
next = cur->next;
|
|
26
|
+
if (cur->_private) {
|
|
27
|
+
xmlUnlinkNode(cur);
|
|
28
|
+
noko_xml_document_pin_node(cur);
|
|
29
|
+
}
|
|
30
|
+
cur = next;
|
|
31
|
+
}
|
|
23
32
|
}
|
|
24
|
-
attr->children = attr->last = NULL;
|
|
25
33
|
|
|
26
34
|
if (content == Qnil) {
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
value = xmlEncodeEntitiesReentrant(attr->doc, (unsigned char *)StringValueCStr(content));
|
|
31
|
-
if (xmlStrlen(value) == 0) {
|
|
32
|
-
attr->children = xmlNewDocText(attr->doc, value);
|
|
35
|
+
xmlNodeSetContent((xmlNodePtr)attr, NULL); /* Clear any remaining unwrapped children. */
|
|
33
36
|
} else {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
xmlChar *value = xmlEncodeEntitiesReentrant(attr->doc, (unsigned char *)StringValueCStr(content));
|
|
38
|
+
|
|
39
|
+
if (xmlStrlen(value) == 0) {
|
|
40
|
+
xmlNodeSetContent((xmlNodePtr)attr, NULL); /* Clear any remaining unwrapped children. */
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
attr
|
|
42
|
+
/* Preserve empty-string attributes as `foo=""` and not boolean `foo` */
|
|
43
|
+
attr->children = attr->last = xmlNewDocText(attr->doc, value);
|
|
44
|
+
attr->children->parent = (xmlNode *)attr;
|
|
45
|
+
} else {
|
|
46
|
+
xmlNodeSetContent((xmlNodePtr)attr, value);
|
|
43
47
|
}
|
|
48
|
+
xmlFree(value);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
return content;
|
|
@@ -53,7 +58,7 @@ set_value(VALUE self, VALUE content)
|
|
|
53
58
|
* Create a new Attr element on the +document+ with +name+
|
|
54
59
|
*/
|
|
55
60
|
static VALUE
|
|
56
|
-
|
|
61
|
+
noko_xml_attr__new(int argc, VALUE *argv, VALUE klass)
|
|
57
62
|
{
|
|
58
63
|
xmlDocPtr xml_doc;
|
|
59
64
|
VALUE document;
|
|
@@ -97,7 +102,7 @@ noko_init_xml_attr(void)
|
|
|
97
102
|
*/
|
|
98
103
|
cNokogiriXmlAttr = rb_define_class_under(mNokogiriXml, "Attr", cNokogiriXmlNode);
|
|
99
104
|
|
|
100
|
-
rb_define_singleton_method(cNokogiriXmlAttr, "new",
|
|
105
|
+
rb_define_singleton_method(cNokogiriXmlAttr, "new", noko_xml_attr__new, -1);
|
|
101
106
|
|
|
102
|
-
rb_define_method(cNokogiriXmlAttr, "value=",
|
|
107
|
+
rb_define_method(cNokogiriXmlAttr, "value=", noko_xml_attr_set_value, 1);
|
|
103
108
|
}
|