nokogiri 1.14.2 → 1.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +19 -15
  3. data/README.md +4 -1
  4. data/dependencies.yml +9 -8
  5. data/ext/nokogiri/extconf.rb +69 -26
  6. data/ext/nokogiri/html4_document.c +1 -2
  7. data/ext/nokogiri/html4_element_description.c +19 -14
  8. data/ext/nokogiri/html4_sax_parser_context.c +10 -16
  9. data/ext/nokogiri/html4_sax_push_parser.c +3 -3
  10. data/ext/nokogiri/nokogiri.c +46 -24
  11. data/ext/nokogiri/nokogiri.h +23 -5
  12. data/ext/nokogiri/test_global_handlers.c +1 -1
  13. data/ext/nokogiri/xml_attr.c +1 -1
  14. data/ext/nokogiri/xml_cdata.c +30 -17
  15. data/ext/nokogiri/xml_comment.c +1 -1
  16. data/ext/nokogiri/xml_document.c +113 -25
  17. data/ext/nokogiri/xml_document_fragment.c +1 -1
  18. data/ext/nokogiri/xml_dtd.c +1 -1
  19. data/ext/nokogiri/xml_element_content.c +32 -29
  20. data/ext/nokogiri/xml_element_decl.c +5 -5
  21. data/ext/nokogiri/xml_encoding_handler.c +12 -4
  22. data/ext/nokogiri/xml_entity_reference.c +1 -1
  23. data/ext/nokogiri/xml_namespace.c +11 -16
  24. data/ext/nokogiri/xml_node.c +13 -16
  25. data/ext/nokogiri/xml_node_set.c +125 -105
  26. data/ext/nokogiri/xml_processing_instruction.c +1 -1
  27. data/ext/nokogiri/xml_reader.c +61 -74
  28. data/ext/nokogiri/xml_relax_ng.c +66 -79
  29. data/ext/nokogiri/xml_sax_parser.c +24 -5
  30. data/ext/nokogiri/xml_sax_parser_context.c +50 -25
  31. data/ext/nokogiri/xml_sax_push_parser.c +30 -9
  32. data/ext/nokogiri/xml_schema.c +94 -115
  33. data/ext/nokogiri/xml_syntax_error.c +3 -3
  34. data/ext/nokogiri/xml_text.c +26 -13
  35. data/ext/nokogiri/xml_xpath_context.c +153 -83
  36. data/ext/nokogiri/xslt_stylesheet.c +111 -53
  37. data/gumbo-parser/Makefile +18 -0
  38. data/gumbo-parser/src/error.c +8 -4
  39. data/gumbo-parser/src/foreign_attrs.c +13 -14
  40. data/gumbo-parser/src/foreign_attrs.gperf +1 -1
  41. data/gumbo-parser/src/parser.c +21 -5
  42. data/gumbo-parser/src/tokenizer.c +1 -0
  43. data/lib/nokogiri/css/parser_extras.rb +1 -1
  44. data/lib/nokogiri/css/xpath_visitor.rb +3 -23
  45. data/lib/nokogiri/extension.rb +1 -1
  46. data/lib/nokogiri/html4/document.rb +1 -1
  47. data/lib/nokogiri/html4/document_fragment.rb +1 -1
  48. data/lib/nokogiri/html4/element_description_defaults.rb +1821 -353
  49. data/lib/nokogiri/html4/encoding_reader.rb +1 -1
  50. data/lib/nokogiri/html5/document_fragment.rb +1 -1
  51. data/lib/nokogiri/html5/node.rb +5 -0
  52. data/lib/nokogiri/html5.rb +0 -63
  53. data/lib/nokogiri/jruby/nokogiri_jars.rb +9 -9
  54. data/lib/nokogiri/version/constant.rb +1 -1
  55. data/lib/nokogiri/version/info.rb +6 -5
  56. data/lib/nokogiri/xml/attr.rb +2 -2
  57. data/lib/nokogiri/xml/attribute_decl.rb +4 -2
  58. data/lib/nokogiri/xml/document.rb +4 -5
  59. data/lib/nokogiri/xml/document_fragment.rb +3 -3
  60. data/lib/nokogiri/xml/element_content.rb +10 -2
  61. data/lib/nokogiri/xml/element_decl.rb +4 -2
  62. data/lib/nokogiri/xml/entity_decl.rb +4 -2
  63. data/lib/nokogiri/xml/namespace.rb +1 -2
  64. data/lib/nokogiri/xml/node/save_options.rb +8 -0
  65. data/lib/nokogiri/xml/node.rb +53 -37
  66. data/lib/nokogiri/xml/node_set.rb +3 -3
  67. data/lib/nokogiri/xml/pp/node.rb +23 -12
  68. data/lib/nokogiri/xml/reader.rb +10 -9
  69. data/lib/nokogiri/xml/sax/document.rb +1 -1
  70. data/lib/nokogiri/xml/searchable.rb +21 -13
  71. data/lib/nokogiri/xml/syntax_error.rb +1 -1
  72. data/lib/nokogiri/xml.rb +1 -1
  73. data/lib/nokogiri/xslt/stylesheet.rb +29 -7
  74. data/lib/nokogiri/xslt.rb +74 -4
  75. data/lib/nokogiri.rb +13 -5
  76. data/lib/xsd/xmlparser/nokogiri.rb +1 -1
  77. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  78. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  79. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  80. data/ports/archives/libxml2-2.12.7.tar.xz +0 -0
  81. data/ports/archives/libxslt-1.1.39.tar.xz +0 -0
  82. metadata +16 -12
  83. data/patches/libxslt/0001-update-automake-files-for-arm64.patch +0 -3037
  84. data/ports/archives/libxml2-2.10.3.tar.xz +0 -0
  85. data/ports/archives/libxslt-1.1.37.tar.xz +0 -0
@@ -5,12 +5,40 @@ VALUE cNokogiriXmlSaxParserContext ;
5
5
  static ID id_read;
6
6
 
7
7
  static void
8
- deallocate(xmlParserCtxtPtr ctxt)
8
+ xml_sax_parser_context_free(void *data)
9
9
  {
10
+ xmlParserCtxtPtr ctxt = data;
10
11
  ctxt->sax = NULL;
11
12
  xmlFreeParserCtxt(ctxt);
12
13
  }
13
14
 
15
+ /*
16
+ * note that htmlParserCtxtPtr == xmlParserCtxtPtr and xmlFreeParserCtxt() == htmlFreeParserCtxt()
17
+ * so we use this type for both XML::SAX::ParserContext and HTML::SAX::ParserContext
18
+ */
19
+ static const rb_data_type_t xml_sax_parser_context_type = {
20
+ .wrap_struct_name = "Nokogiri::XML::SAX::ParserContext",
21
+ .function = {
22
+ .dfree = xml_sax_parser_context_free,
23
+ },
24
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
25
+ };
26
+
27
+ xmlParserCtxtPtr
28
+ noko_xml_sax_parser_context_unwrap(VALUE rb_context)
29
+ {
30
+ xmlParserCtxtPtr c_context;
31
+ TypedData_Get_Struct(rb_context, xmlParserCtxt, &xml_sax_parser_context_type, c_context);
32
+ return c_context;
33
+ }
34
+
35
+ VALUE
36
+ noko_xml_sax_parser_context_wrap(VALUE klass, xmlParserCtxtPtr c_context)
37
+ {
38
+ return TypedData_Wrap_Struct(klass, &xml_sax_parser_context_type, c_context);
39
+ }
40
+
41
+
14
42
  /*
15
43
  * call-seq:
16
44
  * parse_io(io, encoding)
@@ -31,12 +59,16 @@ parse_io(VALUE klass, VALUE io, VALUE encoding)
31
59
  (xmlInputReadCallback)noko_io_read,
32
60
  (xmlInputCloseCallback)noko_io_close,
33
61
  (void *)io, enc);
62
+ if (!ctxt) {
63
+ rb_raise(rb_eRuntimeError, "failed to create xml sax parser context");
64
+ }
65
+
34
66
  if (ctxt->sax) {
35
67
  xmlFree(ctxt->sax);
36
68
  ctxt->sax = NULL;
37
69
  }
38
70
 
39
- return Data_Wrap_Struct(klass, NULL, deallocate, ctxt);
71
+ return noko_xml_sax_parser_context_wrap(klass, ctxt);
40
72
  }
41
73
 
42
74
  /*
@@ -49,7 +81,13 @@ static VALUE
49
81
  parse_file(VALUE klass, VALUE filename)
50
82
  {
51
83
  xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(StringValueCStr(filename));
52
- return Data_Wrap_Struct(klass, NULL, deallocate, ctxt);
84
+
85
+ if (ctxt->sax) {
86
+ xmlFree(ctxt->sax);
87
+ ctxt->sax = NULL;
88
+ }
89
+
90
+ return noko_xml_sax_parser_context_wrap(klass, ctxt);
53
91
  }
54
92
 
55
93
  /*
@@ -76,7 +114,7 @@ parse_memory(VALUE klass, VALUE data)
76
114
  ctxt->sax = NULL;
77
115
  }
78
116
 
79
- return Data_Wrap_Struct(klass, NULL, deallocate, ctxt);
117
+ return noko_xml_sax_parser_context_wrap(klass, ctxt);
80
118
  }
81
119
 
82
120
  static VALUE
@@ -116,13 +154,8 @@ parse_with(VALUE self, VALUE sax_handler)
116
154
  rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::SAX::Parser");
117
155
  }
118
156
 
119
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
120
- Data_Get_Struct(sax_handler, xmlSAXHandler, sax);
121
-
122
- /* Free the sax handler since we'll assign our own */
123
- if (ctxt->sax && ctxt->sax != (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) {
124
- xmlFree(ctxt->sax);
125
- }
157
+ ctxt = noko_xml_sax_parser_context_unwrap(self);
158
+ sax = noko_sax_handler_unwrap(sax_handler);
126
159
 
127
160
  ctxt->sax = sax;
128
161
  ctxt->userData = (void *)NOKOGIRI_SAX_TUPLE_NEW(ctxt, sax_handler);
@@ -144,8 +177,7 @@ parse_with(VALUE self, VALUE sax_handler)
144
177
  static VALUE
145
178
  set_replace_entities(VALUE self, VALUE value)
146
179
  {
147
- xmlParserCtxtPtr ctxt;
148
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
180
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
149
181
 
150
182
  if (Qfalse == value) {
151
183
  ctxt->replaceEntities = 0;
@@ -166,8 +198,7 @@ set_replace_entities(VALUE self, VALUE value)
166
198
  static VALUE
167
199
  get_replace_entities(VALUE self)
168
200
  {
169
- xmlParserCtxtPtr ctxt;
170
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
201
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
171
202
 
172
203
  if (0 == ctxt->replaceEntities) {
173
204
  return Qfalse;
@@ -184,10 +215,8 @@ get_replace_entities(VALUE self)
184
215
  static VALUE
185
216
  line(VALUE self)
186
217
  {
187
- xmlParserCtxtPtr ctxt;
188
218
  xmlParserInputPtr io;
189
-
190
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
219
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
191
220
 
192
221
  io = ctxt->input;
193
222
  if (io) {
@@ -205,11 +234,9 @@ line(VALUE self)
205
234
  static VALUE
206
235
  column(VALUE self)
207
236
  {
208
- xmlParserCtxtPtr ctxt;
237
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
209
238
  xmlParserInputPtr io;
210
239
 
211
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
212
-
213
240
  io = ctxt->input;
214
241
  if (io) {
215
242
  return INT2NUM(io->col);
@@ -228,8 +255,7 @@ column(VALUE self)
228
255
  static VALUE
229
256
  set_recovery(VALUE self, VALUE value)
230
257
  {
231
- xmlParserCtxtPtr ctxt;
232
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
258
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
233
259
 
234
260
  if (value == Qfalse) {
235
261
  ctxt->recovery = 0;
@@ -250,8 +276,7 @@ set_recovery(VALUE self, VALUE value)
250
276
  static VALUE
251
277
  get_recovery(VALUE self)
252
278
  {
253
- xmlParserCtxtPtr ctxt;
254
- Data_Get_Struct(self, xmlParserCtxt, ctxt);
279
+ xmlParserCtxtPtr ctxt = noko_xml_sax_parser_context_unwrap(self);
255
280
 
256
281
  if (ctxt->recovery == 0) {
257
282
  return Qfalse;
@@ -3,18 +3,35 @@
3
3
  VALUE cNokogiriXmlSaxPushParser ;
4
4
 
5
5
  static void
6
- deallocate(xmlParserCtxtPtr ctx)
6
+ xml_sax_push_parser_free(void *data)
7
7
  {
8
+ xmlParserCtxtPtr ctx = data;
8
9
  if (ctx != NULL) {
9
10
  NOKOGIRI_SAX_TUPLE_DESTROY(ctx->userData);
10
11
  xmlFreeParserCtxt(ctx);
11
12
  }
12
13
  }
13
14
 
15
+ static const rb_data_type_t xml_sax_push_parser_type = {
16
+ .wrap_struct_name = "Nokogiri::XML::SAX::PushParser",
17
+ .function = {
18
+ .dfree = xml_sax_push_parser_free,
19
+ },
20
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
21
+ };
22
+
14
23
  static VALUE
15
24
  allocate(VALUE klass)
16
25
  {
17
- return Data_Wrap_Struct(klass, NULL, deallocate, NULL);
26
+ return TypedData_Wrap_Struct(klass, &xml_sax_push_parser_type, NULL);
27
+ }
28
+
29
+ xmlParserCtxtPtr
30
+ noko_xml_sax_push_parser_unwrap(VALUE rb_parser)
31
+ {
32
+ xmlParserCtxtPtr c_parser;
33
+ TypedData_Get_Struct(rb_parser, xmlParserCtxt, &xml_sax_push_parser_type, c_parser);
34
+ return c_parser;
18
35
  }
19
36
 
20
37
  /*
@@ -31,7 +48,7 @@ native_write(VALUE self, VALUE _chunk, VALUE _last_chunk)
31
48
  int size = 0;
32
49
 
33
50
 
34
- Data_Get_Struct(self, xmlParserCtxt, ctx);
51
+ ctx = noko_xml_sax_push_parser_unwrap(self);
35
52
 
36
53
  if (Qnil != _chunk) {
37
54
  chunk = StringValuePtr(_chunk);
@@ -42,7 +59,7 @@ native_write(VALUE self, VALUE _chunk, VALUE _last_chunk)
42
59
 
43
60
  if (xmlParseChunk(ctx, chunk, size, Qtrue == _last_chunk ? 1 : 0)) {
44
61
  if (!(ctx->options & XML_PARSE_RECOVER)) {
45
- xmlErrorPtr e = xmlCtxtGetLastError(ctx);
62
+ xmlErrorConstPtr e = xmlCtxtGetLastError(ctx);
46
63
  Nokogiri_error_raise(NULL, e);
47
64
  }
48
65
  }
@@ -63,7 +80,7 @@ initialize_native(VALUE self, VALUE _xml_sax, VALUE _filename)
63
80
  const char *filename = NULL;
64
81
  xmlParserCtxtPtr ctx;
65
82
 
66
- Data_Get_Struct(_xml_sax, xmlSAXHandler, sax);
83
+ sax = noko_sax_handler_unwrap(_xml_sax);
67
84
 
68
85
  if (_filename != Qnil) { filename = StringValueCStr(_filename); }
69
86
 
@@ -89,7 +106,8 @@ static VALUE
89
106
  get_options(VALUE self)
90
107
  {
91
108
  xmlParserCtxtPtr ctx;
92
- Data_Get_Struct(self, xmlParserCtxt, ctx);
109
+
110
+ ctx = noko_xml_sax_push_parser_unwrap(self);
93
111
 
94
112
  return INT2NUM(ctx->options);
95
113
  }
@@ -98,7 +116,8 @@ static VALUE
98
116
  set_options(VALUE self, VALUE options)
99
117
  {
100
118
  xmlParserCtxtPtr ctx;
101
- Data_Get_Struct(self, xmlParserCtxt, ctx);
119
+
120
+ ctx = noko_xml_sax_push_parser_unwrap(self);
102
121
 
103
122
  if (xmlCtxtUseOptions(ctx, (int)NUM2INT(options)) != 0) {
104
123
  rb_raise(rb_eRuntimeError, "Cannot set XML parser context options");
@@ -118,7 +137,8 @@ static VALUE
118
137
  get_replace_entities(VALUE self)
119
138
  {
120
139
  xmlParserCtxtPtr ctx;
121
- Data_Get_Struct(self, xmlParserCtxt, ctx);
140
+
141
+ ctx = noko_xml_sax_push_parser_unwrap(self);
122
142
 
123
143
  if (0 == ctx->replaceEntities) {
124
144
  return Qfalse;
@@ -138,7 +158,8 @@ static VALUE
138
158
  set_replace_entities(VALUE self, VALUE value)
139
159
  {
140
160
  xmlParserCtxtPtr ctx;
141
- Data_Get_Struct(self, xmlParserCtxt, ctx);
161
+
162
+ ctx = noko_xml_sax_push_parser_unwrap(self);
142
163
 
143
164
  if (Qfalse == value) {
144
165
  ctx->replaceEntities = 0;
@@ -3,11 +3,20 @@
3
3
  VALUE cNokogiriXmlSchema;
4
4
 
5
5
  static void
6
- dealloc(xmlSchemaPtr schema)
6
+ xml_schema_deallocate(void *data)
7
7
  {
8
+ xmlSchemaPtr schema = data;
8
9
  xmlSchemaFree(schema);
9
10
  }
10
11
 
12
+ static const rb_data_type_t xml_schema_type = {
13
+ .wrap_struct_name = "Nokogiri::XML::Schema",
14
+ .function = {
15
+ .dfree = xml_schema_deallocate,
16
+ },
17
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
18
+ };
19
+
11
20
  /*
12
21
  * call-seq:
13
22
  * validate_document(document)
@@ -22,8 +31,8 @@ validate_document(VALUE self, VALUE document)
22
31
  xmlSchemaValidCtxtPtr valid_ctxt;
23
32
  VALUE errors;
24
33
 
25
- Data_Get_Struct(self, xmlSchema, schema);
26
- Noko_Node_Get_Struct(document, xmlDoc, doc);
34
+ TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema);
35
+ doc = noko_xml_document_unwrap(document);
27
36
 
28
37
  errors = rb_ary_new();
29
38
 
@@ -63,7 +72,7 @@ validate_file(VALUE self, VALUE rb_filename)
63
72
  const char *filename ;
64
73
  VALUE errors;
65
74
 
66
- Data_Get_Struct(self, xmlSchema, schema);
75
+ TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema);
67
76
  filename = (const char *)StringValueCStr(rb_filename) ;
68
77
 
69
78
  errors = rb_ary_new();
@@ -90,60 +99,54 @@ validate_file(VALUE self, VALUE rb_filename)
90
99
  return errors;
91
100
  }
92
101
 
93
- /*
94
- * call-seq:
95
- * read_memory(string)
96
- *
97
- * Create a new Schema from the contents of +string+
98
- */
99
102
  static VALUE
100
- read_memory(int argc, VALUE *argv, VALUE klass)
103
+ xml_schema_parse_schema(
104
+ VALUE klass,
105
+ xmlSchemaParserCtxtPtr c_parser_context,
106
+ VALUE rb_parse_options
107
+ )
101
108
  {
102
- VALUE content;
103
- VALUE parse_options;
109
+ VALUE rb_errors;
104
110
  int parse_options_int;
105
- xmlSchemaParserCtxtPtr ctx;
106
- xmlSchemaPtr schema;
107
- VALUE errors;
108
- VALUE rb_schema;
109
- int scanned_args = 0;
111
+ xmlSchemaPtr c_schema;
110
112
  xmlExternalEntityLoader old_loader = 0;
113
+ VALUE rb_schema;
111
114
 
112
- scanned_args = rb_scan_args(argc, argv, "11", &content, &parse_options);
113
- if (scanned_args == 1) {
114
- parse_options = rb_const_get_at(rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), rb_intern("DEFAULT_SCHEMA"));
115
+ if (NIL_P(rb_parse_options)) {
116
+ rb_parse_options = rb_const_get_at(
117
+ rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")),
118
+ rb_intern("DEFAULT_SCHEMA")
119
+ );
115
120
  }
116
- parse_options_int = (int)NUM2INT(rb_funcall(parse_options, rb_intern("to_i"), 0));
117
121
 
118
- ctx = xmlSchemaNewMemParserCtxt((const char *)StringValuePtr(content), (int)RSTRING_LEN(content));
119
-
120
- errors = rb_ary_new();
121
- xmlSetStructuredErrorFunc((void *)errors, Nokogiri_error_array_pusher);
122
+ rb_errors = rb_ary_new();
123
+ xmlSetStructuredErrorFunc((void *)rb_errors, Nokogiri_error_array_pusher);
122
124
 
123
125
  #ifdef HAVE_XMLSCHEMASETPARSERSTRUCTUREDERRORS
124
126
  xmlSchemaSetParserStructuredErrors(
125
- ctx,
127
+ c_parser_context,
126
128
  Nokogiri_error_array_pusher,
127
- (void *)errors
129
+ (void *)rb_errors
128
130
  );
129
131
  #endif
130
132
 
133
+ parse_options_int = (int)NUM2INT(rb_funcall(rb_parse_options, rb_intern("to_i"), 0));
131
134
  if (parse_options_int & XML_PARSE_NONET) {
132
135
  old_loader = xmlGetExternalEntityLoader();
133
136
  xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
134
137
  }
135
138
 
136
- schema = xmlSchemaParse(ctx);
139
+ c_schema = xmlSchemaParse(c_parser_context);
137
140
 
138
141
  if (old_loader) {
139
142
  xmlSetExternalEntityLoader(old_loader);
140
143
  }
141
144
 
142
145
  xmlSetStructuredErrorFunc(NULL, NULL);
143
- xmlSchemaFreeParserCtxt(ctx);
146
+ xmlSchemaFreeParserCtxt(c_parser_context);
144
147
 
145
- if (NULL == schema) {
146
- xmlErrorPtr error = xmlGetLastError();
148
+ if (NULL == c_schema) {
149
+ xmlErrorConstPtr error = xmlGetLastError();
147
150
  if (error) {
148
151
  Nokogiri_error_raise(NULL, error);
149
152
  } else {
@@ -153,118 +156,94 @@ read_memory(int argc, VALUE *argv, VALUE klass)
153
156
  return Qnil;
154
157
  }
155
158
 
156
- rb_schema = Data_Wrap_Struct(klass, 0, dealloc, schema);
157
- rb_iv_set(rb_schema, "@errors", errors);
158
- rb_iv_set(rb_schema, "@parse_options", parse_options);
159
+ rb_schema = TypedData_Wrap_Struct(klass, &xml_schema_type, c_schema);
160
+ rb_iv_set(rb_schema, "@errors", rb_errors);
161
+ rb_iv_set(rb_schema, "@parse_options", rb_parse_options);
159
162
 
160
163
  return rb_schema;
161
164
  }
162
165
 
163
- /* Schema creation will remove and deallocate "blank" nodes.
164
- * If those blank nodes have been exposed to Ruby, they could get freed
165
- * out from under the VALUE pointer. This function checks to see if any of
166
- * those nodes have been exposed to Ruby, and if so we should raise an exception.
166
+ /*
167
+ * call-seq:
168
+ * read_memory(string) Nokogiri::XML::Schema
169
+ *
170
+ * Create a new schema parsed from the contents of +string+
171
+ *
172
+ * [Parameters]
173
+ * - +string+: String containing XML to be parsed as a schema
174
+ *
175
+ * [Returns] Nokogiri::XML::Schema
167
176
  */
168
- static int
169
- has_blank_nodes_p(VALUE cache)
177
+ static VALUE
178
+ read_memory(int argc, VALUE *argv, VALUE klass)
170
179
  {
171
- long i;
180
+ VALUE rb_content;
181
+ VALUE rb_parse_options;
182
+ xmlSchemaParserCtxtPtr c_parser_context;
172
183
 
173
- if (NIL_P(cache)) {
174
- return 0;
175
- }
184
+ rb_scan_args(argc, argv, "11", &rb_content, &rb_parse_options);
176
185
 
177
- for (i = 0; i < RARRAY_LEN(cache); i++) {
178
- xmlNodePtr node;
179
- VALUE element = rb_ary_entry(cache, i);
180
- Noko_Node_Get_Struct(element, xmlNode, node);
181
- if (xmlIsBlankNode(node)) {
182
- return 1;
183
- }
184
- }
186
+ c_parser_context = xmlSchemaNewMemParserCtxt(
187
+ (const char *)StringValuePtr(rb_content),
188
+ (int)RSTRING_LEN(rb_content)
189
+ );
185
190
 
186
- return 0;
191
+ return xml_schema_parse_schema(klass, c_parser_context, rb_parse_options);
187
192
  }
188
193
 
189
194
  /*
190
195
  * call-seq:
191
- * from_document(doc)
196
+ * from_document(document) → Nokogiri::XML::Schema
192
197
  *
193
- * Create a new Schema from the Nokogiri::XML::Document +doc+
198
+ * Create a new schema parsed from the +document+.
199
+ *
200
+ * [Parameters]
201
+ * - +document+: Nokogiri::XML::Document to be parsed
202
+ *
203
+ * [Returns] Nokogiri::XML::Schema
194
204
  */
195
205
  static VALUE
196
- from_document(int argc, VALUE *argv, VALUE klass)
206
+ rb_xml_schema_s_from_document(int argc, VALUE *argv, VALUE klass)
197
207
  {
198
- VALUE document;
199
- VALUE parse_options;
200
- int parse_options_int;
201
- xmlDocPtr doc;
202
- xmlSchemaParserCtxtPtr ctx;
203
- xmlSchemaPtr schema;
204
- VALUE errors;
208
+ VALUE rb_document;
209
+ VALUE rb_parse_options;
205
210
  VALUE rb_schema;
206
- int scanned_args = 0;
207
- xmlExternalEntityLoader old_loader = 0;
211
+ xmlDocPtr c_document;
212
+ xmlSchemaParserCtxtPtr c_parser_context;
213
+ int defensive_copy_p = 0;
208
214
 
209
- scanned_args = rb_scan_args(argc, argv, "11", &document, &parse_options);
215
+ rb_scan_args(argc, argv, "11", &rb_document, &rb_parse_options);
210
216
 
211
- Noko_Node_Get_Struct(document, xmlDoc, doc);
212
- doc = doc->doc; /* In case someone passes us a node. ugh. */
213
-
214
- if (scanned_args == 1) {
215
- parse_options = rb_const_get_at(rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), rb_intern("DEFAULT_SCHEMA"));
217
+ if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) {
218
+ rb_raise(rb_eTypeError,
219
+ "expected parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE,
220
+ rb_obj_class(rb_document));
216
221
  }
217
- parse_options_int = (int)NUM2INT(rb_funcall(parse_options, rb_intern("to_i"), 0));
218
222
 
219
- if (has_blank_nodes_p(DOC_NODE_CACHE(doc))) {
220
- rb_raise(rb_eArgError, "Creating a schema from a document that has blank nodes exposed to Ruby is dangerous");
223
+ if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) {
224
+ xmlNodePtr deprecated_node_type_arg;
225
+ NOKO_WARN_DEPRECATION("Passing a Node as the first parameter to Schema.from_document is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0
226
+ Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg);
227
+ c_document = deprecated_node_type_arg->doc;
228
+ } else {
229
+ c_document = noko_xml_document_unwrap(rb_document);
221
230
  }
222
231
 
223
- ctx = xmlSchemaNewDocParserCtxt(doc);
224
-
225
- errors = rb_ary_new();
226
- xmlSetStructuredErrorFunc((void *)errors, Nokogiri_error_array_pusher);
227
-
228
- #ifdef HAVE_XMLSCHEMASETPARSERSTRUCTUREDERRORS
229
- xmlSchemaSetParserStructuredErrors(
230
- ctx,
231
- Nokogiri_error_array_pusher,
232
- (void *)errors
233
- );
234
- #endif
235
-
236
- if (parse_options_int & XML_PARSE_NONET) {
237
- old_loader = xmlGetExternalEntityLoader();
238
- xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
232
+ if (noko_xml_document_has_wrapped_blank_nodes_p(c_document)) {
233
+ // see https://github.com/sparklemotion/nokogiri/pull/2001
234
+ c_document = xmlCopyDoc(c_document, 1);
235
+ defensive_copy_p = 1;
239
236
  }
240
237
 
241
- schema = xmlSchemaParse(ctx);
238
+ c_parser_context = xmlSchemaNewDocParserCtxt(c_document);
239
+ rb_schema = xml_schema_parse_schema(klass, c_parser_context, rb_parse_options);
242
240
 
243
- if (old_loader) {
244
- xmlSetExternalEntityLoader(old_loader);
245
- }
246
-
247
- xmlSetStructuredErrorFunc(NULL, NULL);
248
- xmlSchemaFreeParserCtxt(ctx);
249
-
250
- if (NULL == schema) {
251
- xmlErrorPtr error = xmlGetLastError();
252
- if (error) {
253
- Nokogiri_error_raise(NULL, error);
254
- } else {
255
- rb_raise(rb_eRuntimeError, "Could not parse document");
256
- }
257
-
258
- return Qnil;
241
+ if (defensive_copy_p) {
242
+ xmlFreeDoc(c_document);
243
+ c_document = NULL;
259
244
  }
260
245
 
261
- rb_schema = Data_Wrap_Struct(klass, 0, dealloc, schema);
262
- rb_iv_set(rb_schema, "@errors", errors);
263
- rb_iv_set(rb_schema, "@parse_options", parse_options);
264
-
265
246
  return rb_schema;
266
-
267
- return Qnil;
268
247
  }
269
248
 
270
249
  void
@@ -275,7 +254,7 @@ noko_init_xml_schema(void)
275
254
  rb_undef_alloc_func(cNokogiriXmlSchema);
276
255
 
277
256
  rb_define_singleton_method(cNokogiriXmlSchema, "read_memory", read_memory, -1);
278
- rb_define_singleton_method(cNokogiriXmlSchema, "from_document", from_document, -1);
257
+ rb_define_singleton_method(cNokogiriXmlSchema, "from_document", rb_xml_schema_s_from_document, -1);
279
258
 
280
259
  rb_define_private_method(cNokogiriXmlSchema, "validate_document", validate_document, 1);
281
260
  rb_define_private_method(cNokogiriXmlSchema, "validate_file", validate_file, 1);
@@ -26,7 +26,7 @@ Nokogiri_structured_error_func_restore(libxmlStructuredErrorHandlerState *handle
26
26
  }
27
27
 
28
28
  void
29
- Nokogiri_error_array_pusher(void *ctx, xmlErrorPtr error)
29
+ Nokogiri_error_array_pusher(void *ctx, xmlErrorConstPtr error)
30
30
  {
31
31
  VALUE list = (VALUE)ctx;
32
32
  Check_Type(list, T_ARRAY);
@@ -34,13 +34,13 @@ Nokogiri_error_array_pusher(void *ctx, xmlErrorPtr error)
34
34
  }
35
35
 
36
36
  void
37
- Nokogiri_error_raise(void *ctx, xmlErrorPtr error)
37
+ Nokogiri_error_raise(void *ctx, xmlErrorConstPtr error)
38
38
  {
39
39
  rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
40
40
  }
41
41
 
42
42
  VALUE
43
- Nokogiri_wrap_xml_syntax_error(xmlErrorPtr error)
43
+ Nokogiri_wrap_xml_syntax_error(xmlErrorConstPtr error)
44
44
  {
45
45
  VALUE msg, e, klass;
46
46
 
@@ -9,25 +9,38 @@ VALUE cNokogiriXmlText ;
9
9
  * Create a new Text element on the +document+ with +content+
10
10
  */
11
11
  static VALUE
12
- new (int argc, VALUE *argv, VALUE klass)
12
+ rb_xml_text_s_new(int argc, VALUE *argv, VALUE klass)
13
13
  {
14
- xmlDocPtr doc;
15
- xmlNodePtr node;
16
- VALUE string;
17
- VALUE document;
18
- VALUE rest;
14
+ xmlDocPtr c_document;
15
+ xmlNodePtr c_node;
16
+ VALUE rb_string;
17
+ VALUE rb_document;
18
+ VALUE rb_rest;
19
19
  VALUE rb_node;
20
20
 
21
- rb_scan_args(argc, argv, "2*", &string, &document, &rest);
21
+ rb_scan_args(argc, argv, "2*", &rb_string, &rb_document, &rb_rest);
22
22
 
23
- Noko_Node_Get_Struct(document, xmlDoc, doc);
23
+ if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) {
24
+ rb_raise(rb_eTypeError,
25
+ "expected second parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE,
26
+ rb_obj_class(rb_document));
27
+ }
24
28
 
25
- node = xmlNewText((xmlChar *)StringValueCStr(string));
26
- node->doc = doc->doc;
29
+ if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) {
30
+ xmlNodePtr deprecated_node_type_arg;
31
+ NOKO_WARN_DEPRECATION("Passing a Node as the second parameter to Text.new is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0
32
+ Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg);
33
+ c_document = deprecated_node_type_arg->doc;
34
+ } else {
35
+ c_document = noko_xml_document_unwrap(rb_document);
36
+ }
27
37
 
28
- noko_xml_document_pin_node(node);
38
+ c_node = xmlNewText((xmlChar *)StringValueCStr(rb_string));
39
+ c_node->doc = c_document;
29
40
 
30
- rb_node = noko_xml_node_wrap(klass, node) ;
41
+ noko_xml_document_pin_node(c_node);
42
+
43
+ rb_node = noko_xml_node_wrap(klass, c_node) ;
31
44
  rb_obj_call_init(rb_node, argc, argv);
32
45
 
33
46
  if (rb_block_given_p()) { rb_yield(rb_node); }
@@ -44,5 +57,5 @@ noko_init_xml_text(void)
44
57
  */
45
58
  cNokogiriXmlText = rb_define_class_under(mNokogiriXml, "Text", cNokogiriXmlCharacterData);
46
59
 
47
- rb_define_singleton_method(cNokogiriXmlText, "new", new, -1);
60
+ rb_define_singleton_method(cNokogiriXmlText, "new", rb_xml_text_s_new, -1);
48
61
  }