libxml-ruby 5.0.6 → 6.0.0

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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY → CHANGELOG.md} +875 -930
  3. data/LICENSE +20 -20
  4. data/README.md +67 -0
  5. data/Rakefile +13 -34
  6. data/ext/libxml/extconf.rb +34 -20
  7. data/ext/libxml/libxml.c +2 -14
  8. data/ext/libxml/ruby_libxml.h +1 -1
  9. data/ext/libxml/ruby_xml_attr.c +27 -22
  10. data/ext/libxml/ruby_xml_attr.h +1 -0
  11. data/ext/libxml/ruby_xml_attr_decl.c +19 -12
  12. data/ext/libxml/ruby_xml_attributes.c +18 -9
  13. data/ext/libxml/ruby_xml_document.c +111 -98
  14. data/ext/libxml/ruby_xml_document.h +1 -0
  15. data/ext/libxml/ruby_xml_dtd.c +49 -19
  16. data/ext/libxml/ruby_xml_dtd.h +1 -0
  17. data/ext/libxml/ruby_xml_html_parser.c +1 -1
  18. data/ext/libxml/ruby_xml_html_parser_context.c +19 -6
  19. data/ext/libxml/ruby_xml_html_parser_context.h +1 -0
  20. data/ext/libxml/ruby_xml_input_cbg.c +45 -17
  21. data/ext/libxml/ruby_xml_io.c +3 -1
  22. data/ext/libxml/ruby_xml_namespace.c +20 -12
  23. data/ext/libxml/ruby_xml_namespace.h +1 -0
  24. data/ext/libxml/ruby_xml_namespaces.c +40 -20
  25. data/ext/libxml/ruby_xml_node.c +71 -32
  26. data/ext/libxml/ruby_xml_node.h +2 -0
  27. data/ext/libxml/ruby_xml_parser.c +1 -1
  28. data/ext/libxml/ruby_xml_parser_context.c +54 -47
  29. data/ext/libxml/ruby_xml_parser_context.h +1 -0
  30. data/ext/libxml/ruby_xml_reader.c +25 -15
  31. data/ext/libxml/ruby_xml_registry.c +31 -0
  32. data/ext/libxml/ruby_xml_registry.h +22 -0
  33. data/ext/libxml/ruby_xml_relaxng.c +21 -5
  34. data/ext/libxml/ruby_xml_relaxng.h +1 -0
  35. data/ext/libxml/ruby_xml_sax_parser.c +1 -1
  36. data/ext/libxml/ruby_xml_schema.c +18 -11
  37. data/ext/libxml/ruby_xml_schema.h +1 -0
  38. data/ext/libxml/ruby_xml_schema_attribute.c +7 -7
  39. data/ext/libxml/ruby_xml_schema_element.c +8 -8
  40. data/ext/libxml/ruby_xml_schema_facet.c +7 -7
  41. data/ext/libxml/ruby_xml_schema_type.c +12 -19
  42. data/ext/libxml/ruby_xml_version.h +4 -4
  43. data/ext/libxml/ruby_xml_writer.c +18 -6
  44. data/ext/libxml/ruby_xml_xpath.c +2 -2
  45. data/ext/libxml/ruby_xml_xpath.h +1 -1
  46. data/ext/libxml/ruby_xml_xpath_context.c +72 -26
  47. data/ext/libxml/ruby_xml_xpath_expression.c +11 -5
  48. data/ext/libxml/ruby_xml_xpath_expression.h +1 -0
  49. data/ext/libxml/ruby_xml_xpath_object.c +69 -54
  50. data/ext/libxml/ruby_xml_xpath_object.h +3 -1
  51. data/ext/vc/libxml_ruby/libxml_ruby.vcxproj +271 -0
  52. data/ext/xcode/libxml-ruby.xcodeproj/project.pbxproj +633 -0
  53. data/ext/xcode/libxml-ruby.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  54. data/ext/xcode/libxml-ruby.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  55. data/ext/xcode/libxml-ruby.xcodeproj/xcshareddata/xcschemes/libxml-ruby.xcscheme +80 -0
  56. data/lib/libxml/document.rb +0 -29
  57. data/lib/libxml/error.rb +30 -3
  58. data/lib/libxml/html_parser.rb +0 -16
  59. data/lib/libxml/node.rb +1 -3
  60. data/lib/libxml/parser.rb +0 -8
  61. data/lib/libxml/schema/attribute.rb +27 -19
  62. data/lib/libxml/schema/element.rb +20 -0
  63. data/lib/libxml/schema/type.rb +44 -21
  64. data/lib/libxml/schema.rb +47 -47
  65. data/lib/libxml-ruby.rb +30 -30
  66. data/libxml-ruby.gemspec +12 -16
  67. data/test/c14n/result/1-1-without-comments/example-1 +3 -3
  68. data/test/c14n/result/1-1-without-comments/example-2 +10 -10
  69. data/test/c14n/result/1-1-without-comments/example-3 +13 -13
  70. data/test/c14n/result/1-1-without-comments/example-4 +8 -8
  71. data/test/c14n/result/1-1-without-comments/example-5 +2 -2
  72. data/test/c14n/result/with-comments/example-1 +5 -5
  73. data/test/c14n/result/with-comments/example-2 +10 -10
  74. data/test/c14n/result/with-comments/example-3 +13 -13
  75. data/test/c14n/result/with-comments/example-4 +8 -8
  76. data/test/c14n/result/with-comments/example-5 +3 -3
  77. data/test/c14n/result/without-comments/example-1 +3 -3
  78. data/test/c14n/result/without-comments/example-2 +10 -10
  79. data/test/c14n/result/without-comments/example-3 +13 -13
  80. data/test/c14n/result/without-comments/example-4 +8 -8
  81. data/test/c14n/result/without-comments/example-5 +2 -2
  82. data/test/test_attr.rb +179 -180
  83. data/test/test_attr_decl.rb +131 -131
  84. data/test/test_attributes.rb +135 -135
  85. data/test/test_canonicalize.rb +122 -120
  86. data/test/test_document.rb +2 -4
  87. data/test/test_dtd.rb +12 -4
  88. data/test/test_encoding_sax.rb +114 -114
  89. data/test/test_error.rb +1 -1
  90. data/test/test_html_parser.rb +6 -2
  91. data/test/test_html_parser_context.rb +22 -22
  92. data/test/test_input_callbacks.rb +36 -0
  93. data/test/test_namespace.rb +1 -1
  94. data/test/test_namespaces.rb +200 -200
  95. data/test/test_node.rb +16 -0
  96. data/test/test_node_cdata.rb +50 -50
  97. data/test/test_node_comment.rb +32 -32
  98. data/test/test_node_copy.rb +40 -40
  99. data/test/test_node_edit.rb +176 -158
  100. data/test/test_node_pi.rb +37 -37
  101. data/test/test_node_text.rb +69 -69
  102. data/test/test_node_xlink.rb +28 -28
  103. data/test/test_parser.rb +5 -41
  104. data/test/test_parser_context.rb +198 -198
  105. data/test/test_properties.rb +38 -38
  106. data/test/test_reader.rb +55 -6
  107. data/test/test_relaxng.rb +59 -53
  108. data/test/test_sax_parser.rb +345 -345
  109. data/test/test_schema.rb +28 -0
  110. data/test/test_traversal.rb +152 -152
  111. data/test/test_writer.rb +0 -31
  112. data/test/test_xinclude.rb +20 -20
  113. data/test/test_xml.rb +3 -7
  114. data/test/test_xpath.rb +244 -244
  115. data/test/test_xpath_context.rb +87 -87
  116. data/test/test_xpath_expression.rb +37 -37
  117. metadata +32 -25
  118. data/README.rdoc +0 -208
  119. data/ext/libxml/extconf.h +0 -4
  120. data/ext/libxml/ruby_xml_cbg.c +0 -85
  121. data/lib/libxml/hpricot.rb +0 -78
  122. data/lib/libxml.rb +0 -5
  123. data/lib/xml/libxml.rb +0 -10
  124. data/lib/xml.rb +0 -14
  125. data/script/benchmark/depixelate +0 -634
  126. data/script/benchmark/hamlet.xml +0 -9055
  127. data/script/benchmark/parsecount +0 -170
  128. data/script/benchmark/sock_entries.xml +0 -507
  129. data/script/benchmark/throughput +0 -41
  130. data/script/test +0 -6
  131. data/test/test_deprecated_require.rb +0 -12
@@ -129,14 +129,21 @@ static htmlParserCtxtPtr htmlNewParserCtxt(void)
129
129
  }
130
130
  #endif
131
131
 
132
- static void rxml_html_parser_context_free(htmlParserCtxtPtr ctxt)
132
+ static void rxml_html_parser_context_free(void* data)
133
133
  {
134
+ htmlParserCtxtPtr ctxt = (htmlParserCtxtPtr)data;
134
135
  htmlFreeParserCtxt(ctxt);
135
136
  }
136
137
 
138
+ const rb_data_type_t rxml_html_parser_context_type = {
139
+ "LibXML::XML::HTMLParser::Context",
140
+ {NULL, rxml_html_parser_context_free, NULL},
141
+ &rxml_parser_context_type, NULL, 0
142
+ };
143
+
137
144
  static VALUE rxml_html_parser_context_wrap(htmlParserCtxtPtr ctxt)
138
145
  {
139
- return Data_Wrap_Struct(cXMLHtmlParserContext, NULL, rxml_html_parser_context_free, ctxt);
146
+ return TypedData_Wrap_Struct(cXMLHtmlParserContext, &rxml_html_parser_context_type, ctxt);
140
147
  }
141
148
 
142
149
  /* call-seq:
@@ -275,7 +282,7 @@ static VALUE rxml_html_parser_context_close(VALUE self)
275
282
  {
276
283
  htmlParserCtxtPtr ctxt;
277
284
  xmlParserInputPtr xinput;
278
- Data_Get_Struct(self, htmlParserCtxt, ctxt);
285
+ TypedData_Get_Struct(self, htmlParserCtxt, &rxml_html_parser_context_type, ctxt);
279
286
 
280
287
  while ((xinput = inputPop(ctxt)) != NULL)
281
288
  {
@@ -293,7 +300,7 @@ static VALUE rxml_html_parser_context_close(VALUE self)
293
300
  static VALUE rxml_html_parser_context_disable_cdata_set(VALUE self, VALUE value)
294
301
  {
295
302
  htmlParserCtxtPtr ctxt;
296
- Data_Get_Struct(self, htmlParserCtxt, ctxt);
303
+ TypedData_Get_Struct(self, htmlParserCtxt, &rxml_html_parser_context_type, ctxt);
297
304
 
298
305
  if (ctxt->sax == NULL)
299
306
  rb_raise(rb_eRuntimeError, "Sax handler is not yet set");
@@ -320,9 +327,8 @@ static VALUE rxml_html_parser_context_options_set(VALUE self, VALUE options)
320
327
  {
321
328
  int xml_options = NUM2INT(options);
322
329
  htmlParserCtxtPtr ctxt;
323
- Check_Type(options, T_FIXNUM);
324
330
 
325
- Data_Get_Struct(self, htmlParserCtxt, ctxt);
331
+ TypedData_Get_Struct(self, htmlParserCtxt, &rxml_html_parser_context_type, ctxt);
326
332
  htmlCtxtUseOptions(ctxt, xml_options);
327
333
 
328
334
  #if LIBXML_VERSION >= 20707
@@ -337,10 +343,17 @@ static VALUE rxml_html_parser_context_options_set(VALUE self, VALUE options)
337
343
  return self;
338
344
  }
339
345
 
346
+ static VALUE rxml_html_parser_context_alloc(VALUE klass)
347
+ {
348
+ xmlParserCtxtPtr ctxt = htmlNewParserCtxt();
349
+ return TypedData_Wrap_Struct(klass, &rxml_html_parser_context_type, ctxt);
350
+ }
351
+
340
352
  void rxml_init_html_parser_context(void)
341
353
  {
342
354
  IO_ATTR = ID2SYM(rb_intern("@io"));
343
355
  cXMLHtmlParserContext = rb_define_class_under(cXMLHtmlParser, "Context", cXMLParserContext);
356
+ rb_define_alloc_func(cXMLHtmlParserContext, rxml_html_parser_context_alloc);
344
357
 
345
358
  rb_define_singleton_method(cXMLHtmlParserContext, "file", rxml_html_parser_context_file, -1);
346
359
  rb_define_singleton_method(cXMLHtmlParserContext, "io", rxml_html_parser_context_io, -1);
@@ -4,6 +4,7 @@
4
4
  #define __RXML_HTML_PARSER_CONTEXT__
5
5
 
6
6
  extern VALUE cXMLHtmlParserContext;
7
+ extern const rb_data_type_t rxml_html_parser_context_type;
7
8
 
8
9
  void rxml_init_html_parser_context(void);
9
10
 
@@ -8,8 +8,38 @@
8
8
  * Support for adding custom scheme handlers. */
9
9
 
10
10
  static ic_scheme *first_scheme = 0;
11
+ static int input_callbacks_registered = 0;
11
12
 
12
- int ic_match(char const *filename)
13
+ static int ic_match(char const *filename);
14
+ static void* ic_open(char const *filename);
15
+ static int ic_read(void *context, char *buffer, int len);
16
+ static int ic_close(void *context);
17
+
18
+ static void input_callbacks_register_once(void)
19
+ {
20
+ if (input_callbacks_registered)
21
+ return;
22
+
23
+ xmlRegisterInputCallbacks(ic_match, ic_open, ic_read, ic_close);
24
+ input_callbacks_registered = 1;
25
+ }
26
+
27
+ static char *ic_strdup(const char *string)
28
+ {
29
+ size_t length = strlen(string) + 1;
30
+ char *copy = ruby_xmalloc(length);
31
+ memcpy(copy, string, length);
32
+ return copy;
33
+ }
34
+
35
+ static void ic_scheme_free(ic_scheme *scheme)
36
+ {
37
+ rb_gc_unregister_address(&scheme->class);
38
+ ruby_xfree(scheme->scheme_name);
39
+ ruby_xfree(scheme);
40
+ }
41
+
42
+ static int ic_match(char const *filename)
13
43
  {
14
44
  ic_scheme *scheme;
15
45
 
@@ -27,7 +57,7 @@ int ic_match(char const *filename)
27
57
  return 0;
28
58
  }
29
59
 
30
- void* ic_open(char const *filename)
60
+ static void* ic_open(char const *filename)
31
61
  {
32
62
  ic_doc_context *ic_doc;
33
63
  ic_scheme *scheme;
@@ -38,12 +68,11 @@ void* ic_open(char const *filename)
38
68
  {
39
69
  if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST scheme->scheme_name, scheme->name_len))
40
70
  {
41
- ic_doc = (ic_doc_context*) malloc(sizeof(ic_doc_context));
42
-
43
71
  res = rb_funcall(scheme->class, rb_intern("document_query"), 1,
44
72
  rb_str_new2(filename));
45
73
 
46
- ic_doc->buffer = strdup(StringValuePtr(res));
74
+ ic_doc = ALLOC(ic_doc_context);
75
+ ic_doc->buffer = ic_strdup(StringValueCStr(res));
47
76
 
48
77
  ic_doc->bpos = ic_doc->buffer;
49
78
  ic_doc->remaining = (int)strlen(ic_doc->buffer);
@@ -54,7 +83,7 @@ void* ic_open(char const *filename)
54
83
  return 0;
55
84
  }
56
85
 
57
- int ic_read(void *context, char *buffer, int len)
86
+ static int ic_read(void *context, char *buffer, int len)
58
87
  {
59
88
  ic_doc_context *ic_doc;
60
89
  int ret_len;
@@ -75,7 +104,7 @@ int ic_read(void *context, char *buffer, int len)
75
104
  return ret_len;
76
105
  }
77
106
 
78
- int ic_close(void *context)
107
+ static int ic_close(void *context)
79
108
  {
80
109
  ruby_xfree(((ic_doc_context*) context)->buffer);
81
110
  ruby_xfree(context);
@@ -90,7 +119,7 @@ int ic_close(void *context)
90
119
  */
91
120
  static VALUE input_callbacks_register_input_callbacks(VALUE self)
92
121
  {
93
- xmlRegisterInputCallbacks(ic_match, ic_open, ic_read, ic_close);
122
+ input_callbacks_register_once();
94
123
  return (Qtrue);
95
124
  }
96
125
 
@@ -107,11 +136,14 @@ static VALUE input_callbacks_add_scheme(VALUE self, VALUE scheme_name,
107
136
 
108
137
  Check_Type(scheme_name, T_STRING);
109
138
 
110
- scheme = (ic_scheme*) malloc(sizeof(ic_scheme));
139
+ input_callbacks_register_once();
140
+
141
+ scheme = ALLOC(ic_scheme);
111
142
  scheme->next_scheme = 0;
112
- scheme->scheme_name = strdup(StringValuePtr(scheme_name)); /* TODO alloc, dealloc */
143
+ scheme->scheme_name = ic_strdup(StringValueCStr(scheme_name));
113
144
  scheme->name_len = (int)strlen(scheme->scheme_name);
114
- scheme->class = class; /* TODO alloc, dealloc */
145
+ scheme->class = class;
146
+ rb_gc_register_address(&scheme->class);
115
147
 
116
148
  //fprintf( stderr, "registered: %s, %d, %s\n", scheme->scheme_name, scheme->name_len, scheme->class );
117
149
 
@@ -150,9 +182,7 @@ static VALUE input_callbacks_remove_scheme(VALUE self, VALUE scheme_name)
150
182
  {
151
183
  save_scheme = first_scheme->next_scheme;
152
184
 
153
- ruby_xfree(first_scheme->scheme_name);
154
- ruby_xfree(first_scheme);
155
-
185
+ ic_scheme_free(first_scheme);
156
186
  first_scheme = save_scheme;
157
187
  return Qtrue;
158
188
  }
@@ -165,9 +195,7 @@ static VALUE input_callbacks_remove_scheme(VALUE self, VALUE scheme_name)
165
195
  {
166
196
  save_scheme = scheme->next_scheme->next_scheme;
167
197
 
168
- ruby_xfree(scheme->next_scheme->scheme_name);
169
- ruby_xfree(scheme->next_scheme);
170
-
198
+ ic_scheme_free(scheme->next_scheme);
171
199
  scheme->next_scheme = save_scheme;
172
200
  return Qtrue;
173
201
  }
@@ -19,6 +19,8 @@ int rxml_read_callback(void *context, char *buffer, int len)
19
19
  return 0;
20
20
 
21
21
  size = RSTRING_LEN(string);
22
+ if (size > (size_t)len)
23
+ size = (size_t)len;
22
24
  memcpy(buffer, StringValuePtr(string), size);
23
25
 
24
26
  return (int)size;
@@ -30,7 +32,7 @@ int rxml_write_callback(VALUE io, const char *buffer, int len)
30
32
  {
31
33
  // Could be StringIO
32
34
  VALUE written, string;
33
- string = rb_external_str_new_with_enc(buffer, (long)strlen(buffer), rb_enc_get(io));
35
+ string = rb_external_str_new_with_enc(buffer, (long)len, rb_enc_get(io));
34
36
  written = rb_funcall(io, WRITE_METHOD, 1, string);
35
37
  return NUM2INT(written);
36
38
  }
@@ -5,6 +5,11 @@
5
5
 
6
6
  VALUE cXMLNamespace;
7
7
 
8
+ const rb_data_type_t rxml_namespace_type = {
9
+ "libxml/namespace",
10
+ {NULL, NULL, NULL},
11
+ };
12
+
8
13
  /* Document-class: LibXML::XML::Namespace
9
14
  *
10
15
  * The Namespace class represents an XML namespace.
@@ -26,12 +31,12 @@ VALUE cXMLNamespace;
26
31
 
27
32
  static VALUE rxml_namespace_alloc(VALUE klass)
28
33
  {
29
- return Data_Wrap_Struct(klass, NULL, NULL, NULL);
34
+ return TypedData_Wrap_Struct(klass, &rxml_namespace_type, NULL);
30
35
  }
31
36
 
32
37
  VALUE rxml_namespace_wrap(xmlNsPtr xns)
33
38
  {
34
- return Data_Wrap_Struct(cXMLNamespace, NULL, NULL, xns);
39
+ return TypedData_Wrap_Struct(cXMLNamespace, &rxml_namespace_type, xns);
35
40
  }
36
41
 
37
42
 
@@ -50,15 +55,14 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
50
55
  xmlChar *xmlPrefix;
51
56
  xmlNsPtr xns;
52
57
 
53
- Check_Type(node, T_DATA);
54
- Data_Get_Struct(node, xmlNode, xnode);
58
+ TypedData_Get_Struct(node, xmlNode, &rxml_node_data_type, xnode);
55
59
  xmlResetLastError();
56
60
 
57
61
  /* Prefix can be null - that means its the default namespace */
58
62
  xmlPrefix = NIL_P(prefix) ? NULL : (xmlChar *)StringValuePtr(prefix);
59
63
  xns = xmlNewNs(xnode, (xmlChar*) StringValuePtr(href), xmlPrefix);
60
64
 
61
- DATA_PTR(self) = xns;
65
+ RTYPEDDATA_DATA(self) = xns;
62
66
  return self;
63
67
  }
64
68
 
@@ -75,7 +79,7 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
75
79
  static VALUE rxml_namespace_href_get(VALUE self)
76
80
  {
77
81
  xmlNsPtr xns;
78
- Data_Get_Struct(self, xmlNs, xns);
82
+ TypedData_Get_Struct(self, xmlNs, &rxml_namespace_type, xns);
79
83
  if (xns->href == NULL)
80
84
  return Qnil;
81
85
  else
@@ -91,7 +95,7 @@ static VALUE rxml_namespace_href_get(VALUE self)
91
95
  static VALUE rxml_namespace_node_type(VALUE self)
92
96
  {
93
97
  xmlNsPtr xns;
94
- Data_Get_Struct(self, xmlNs, xns);
98
+ TypedData_Get_Struct(self, xmlNs, &rxml_namespace_type, xns);
95
99
  return INT2NUM(xns->type);
96
100
  }
97
101
 
@@ -110,7 +114,7 @@ static VALUE rxml_namespace_node_type(VALUE self)
110
114
  static VALUE rxml_namespace_prefix_get(VALUE self)
111
115
  {
112
116
  xmlNsPtr xns;
113
- Data_Get_Struct(self, xmlNs, xns);
117
+ TypedData_Get_Struct(self, xmlNs, &rxml_namespace_type, xns);
114
118
  if (xns->prefix == NULL)
115
119
  return Qnil;
116
120
  else
@@ -132,11 +136,15 @@ static VALUE rxml_namespace_prefix_get(VALUE self)
132
136
  static VALUE rxml_namespace_next(VALUE self)
133
137
  {
134
138
  xmlNsPtr xns;
135
- Data_Get_Struct(self, xmlNs, xns);
136
- if (xns == NULL || xns->next == NULL)
139
+ TypedData_Get_Struct(self, xmlNs, &rxml_namespace_type, xns);
140
+ /* Guard against libxml2's XPath hack where xns->next stores a parent
141
+ element pointer instead of the next namespace (see xmlXPathNodeSetAddNs
142
+ in xpath.c). xmlNs.type and xmlNode.type share the same struct offset,
143
+ so checking the type is safe even when next points to an xmlNode. */
144
+ if (xns == NULL || xns->next == NULL || xns->next->type != XML_LOCAL_NAMESPACE)
137
145
  return (Qnil);
138
- else
139
- return rxml_namespace_wrap(xns->next);
146
+
147
+ return rxml_namespace_wrap(xns->next);
140
148
  }
141
149
 
142
150
  void rxml_init_namespace(void)
@@ -4,6 +4,7 @@
4
4
  #define __RXML_NAMESPACE__
5
5
 
6
6
  extern VALUE cXMLNamespace;
7
+ extern const rb_data_type_t rxml_namespace_type;
7
8
 
8
9
  void rxml_init_namespace(void);
9
10
  VALUE rxml_namespace_wrap(xmlNsPtr xns);
@@ -5,6 +5,11 @@
5
5
 
6
6
  VALUE cXMLNamespaces;
7
7
 
8
+ static const rb_data_type_t rxml_namespaces_type = {
9
+ "libxml/namespaces",
10
+ {NULL, NULL, NULL},
11
+ };
12
+
8
13
  /* Document-class: LibXML::XML::Namespaces
9
14
  *
10
15
  * The XML::Namespaces class is used to access information about
@@ -38,7 +43,7 @@ VALUE cXMLNamespaces;
38
43
 
39
44
  static VALUE rxml_namespaces_alloc(VALUE klass)
40
45
  {
41
- return Data_Wrap_Struct(klass, NULL, NULL, NULL);
46
+ return TypedData_Wrap_Struct(klass, &rxml_namespaces_type, NULL);
42
47
  }
43
48
 
44
49
  /*
@@ -58,10 +63,9 @@ static VALUE rxml_namespaces_initialize(VALUE self, VALUE node)
58
63
  {
59
64
  xmlNodePtr xnode;
60
65
 
61
- Check_Type(node, T_DATA);
62
- Data_Get_Struct(node, xmlNode, xnode);
66
+ TypedData_Get_Struct(node, xmlNode, &rxml_node_data_type, xnode);
63
67
 
64
- DATA_PTR(self) = xnode;
68
+ RTYPEDDATA_DATA(self) = xnode;
65
69
  return self;
66
70
  }
67
71
 
@@ -83,7 +87,7 @@ static VALUE rxml_namespaces_definitions(VALUE self)
83
87
  xmlNsPtr xns;
84
88
  VALUE arr;
85
89
 
86
- Data_Get_Struct(self, xmlNode, xnode);
90
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
87
91
 
88
92
  arr = rb_ary_new();
89
93
  xns = xnode->nsDef;
@@ -112,24 +116,41 @@ static VALUE rxml_namespaces_definitions(VALUE self)
112
116
  * ..
113
117
  * end
114
118
  */
119
+ static VALUE rxml_namespaces_each_yield(VALUE data)
120
+ {
121
+ xmlNsPtr*nsList = (xmlNsPtr*)data;
122
+ xmlNsPtr*xns;
123
+
124
+ for (xns = nsList; *xns != NULL; xns++)
125
+ {
126
+ VALUE ns = rxml_namespace_wrap(*xns);
127
+ rb_yield(ns);
128
+ }
129
+
130
+ return Qnil;
131
+ }
132
+
133
+ static VALUE rxml_namespaces_free_list(VALUE data)
134
+ {
135
+ xmlNsPtr*nsList = (xmlNsPtr*)data;
136
+ xmlFree(nsList);
137
+ return Qnil;
138
+ }
139
+
115
140
  static VALUE rxml_namespaces_each(VALUE self)
116
141
  {
117
142
  xmlNodePtr xnode;
118
- xmlNsPtr *nsList, *xns;
143
+ xmlNsPtr*nsList;
119
144
 
120
- Data_Get_Struct(self, xmlNode, xnode);
145
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
121
146
 
122
147
  nsList = xmlGetNsList(xnode->doc, xnode);
123
148
 
124
149
  if (nsList == NULL)
125
150
  return (Qnil);
126
151
 
127
- for (xns = nsList; *xns != NULL; xns++)
128
- {
129
- VALUE ns = rxml_namespace_wrap(*xns);
130
- rb_yield(ns);
131
- }
132
- xmlFree(nsList);
152
+ rb_ensure(rxml_namespaces_each_yield, (VALUE)nsList,
153
+ rxml_namespaces_free_list, (VALUE)nsList);
133
154
 
134
155
  return Qnil;
135
156
  }
@@ -157,7 +178,7 @@ static VALUE rxml_namespaces_find_by_href(VALUE self, VALUE href)
157
178
  xmlNsPtr xns;
158
179
 
159
180
  Check_Type(href, T_STRING);
160
- Data_Get_Struct(self, xmlNode, xnode);
181
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
161
182
 
162
183
  xns = xmlSearchNsByHref(xnode->doc, xnode, (xmlChar*) StringValuePtr(href));
163
184
  if (xns)
@@ -196,7 +217,7 @@ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix)
196
217
  xprefix = (xmlChar*) StringValuePtr(prefix);
197
218
  }
198
219
 
199
- Data_Get_Struct(self, xmlNode, xnode);
220
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
200
221
 
201
222
  xns = xmlSearchNs(xnode->doc, xnode, xprefix);
202
223
  if (xns)
@@ -221,7 +242,7 @@ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix)
221
242
  static VALUE rxml_namespaces_namespace_get(VALUE self)
222
243
  {
223
244
  xmlNodePtr xnode;
224
- Data_Get_Struct(self, xmlNode, xnode);
245
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
225
246
 
226
247
  if (xnode->ns)
227
248
  return rxml_namespace_wrap(xnode->ns);
@@ -253,10 +274,9 @@ static VALUE rxml_namespaces_namespace_set(VALUE self, VALUE ns)
253
274
  xmlNodePtr xnode;
254
275
  xmlNsPtr xns;
255
276
 
256
- Data_Get_Struct(self, xmlNode, xnode);
277
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
257
278
 
258
- Check_Type(ns, T_DATA);
259
- Data_Get_Struct(ns, xmlNs, xns);
279
+ TypedData_Get_Struct(ns, xmlNs, &rxml_namespace_type, xns);
260
280
 
261
281
  xmlSetNs(xnode, xns);
262
282
  return self;
@@ -271,7 +291,7 @@ static VALUE rxml_namespaces_namespace_set(VALUE self, VALUE ns)
271
291
  static VALUE rxml_namespaces_node_get(VALUE self)
272
292
  {
273
293
  xmlNodePtr xnode;
274
- Data_Get_Struct(self, xmlNode, xnode);
294
+ TypedData_Get_Struct(self, xmlNode, &rxml_namespaces_type, xnode);
275
295
  return rxml_node_wrap(xnode);
276
296
  }
277
297
 
@@ -8,6 +8,10 @@
8
8
 
9
9
  VALUE cXMLNode;
10
10
 
11
+ #ifndef TYPED_DATA_EMBEDDED
12
+ #define TYPED_DATA_EMBEDDED ((VALUE)1)
13
+ #endif
14
+
11
15
  /* Document-class: LibXML::XML::Node
12
16
  *
13
17
  * Nodes are the primary objects that make up an XML document.
@@ -26,9 +30,9 @@ VALUE cXMLNode;
26
30
  * have a parent and do not belong to a document). In these cases,
27
31
  * the bindings manage the memory. They do this by installing a free
28
32
  * function and storing a back pointer to the Ruby object from the xmlnode
29
- * using the _private member on libxml structures. When the Ruby object
30
- * goes out of scope, the underlying libxml structure is freed. Libxml
31
- * itself then frees all child node (recursively).
33
+ * using a pointer-keyed registry (see ruby_xml_registry.c). When the
34
+ * Ruby object goes out of scope, the underlying libxml structure is freed.
35
+ * Libxml itself then frees all child node (recursively).
32
36
  *
33
37
  * For all other nodes (the vast majority), the bindings create temporary
34
38
  * Ruby objects that get freed once they go out of scope. Thus there can be
@@ -46,29 +50,71 @@ VALUE cXMLNode;
46
50
  * and are no longer in scope (since if they were the document would not be freed).
47
51
  */
48
52
 
49
- static void rxml_node_free(xmlNodePtr xnode)
53
+ static void rxml_node_free(void *data)
50
54
  {
55
+ xmlNodePtr xnode = (xmlNodePtr)data;
56
+ if (!xnode) return;
57
+
51
58
  /* The ruby object wrapping the xml object no longer exists and this
52
- is a standalone node without a document or parent so ruby is
59
+ is a standalone node without a document or parent so ruby is
53
60
  responsible for freeing the underlying node.*/
54
61
  if (xnode->doc == NULL && xnode->parent == NULL)
55
62
  {
56
- // Remove the back linkage from libxml to Ruby
57
- xnode->_private = NULL;
63
+ rxml_registry_unregister(xnode);
58
64
  xmlFreeNode(xnode);
59
65
  }
60
66
  }
61
67
 
68
+ /* Three TypedData types are used for nodes, all sharing rxml_node_data_type
69
+ * as the parent type so that TypedData_Get_Struct type checks pass for any
70
+ * variant:
71
+ *
72
+ * rxml_node_data_type - Default. Marks the owning document to prevent
73
+ * GC from collecting it. No free function since
74
+ * libxml owns the node memory.
75
+ *
76
+ * rxml_node_unmanaged_data_type - No mark, no free. Used for transient nodes
77
+ * whose lifetime is not controlled by Ruby (e.g.
78
+ * nodes returned by xmlTextReaderExpand that are
79
+ * freed on the next reader read call).
80
+ *
81
+ * rxml_node_managed_data_type - Marks the document and frees standalone nodes
82
+ * (no doc, no parent) when the Ruby wrapper is
83
+ * collected. Used for nodes created from Ruby
84
+ * that have not yet been inserted into a document.
85
+ */
86
+ const rb_data_type_t rxml_node_data_type = {
87
+ .wrap_struct_name = "LibXML::XML::Node",
88
+ .function = { .dmark = (RUBY_DATA_FUNC)rxml_node_mark, .dfree = NULL },
89
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
90
+ };
91
+
92
+ const rb_data_type_t rxml_node_unmanaged_data_type = {
93
+ .wrap_struct_name = "LibXML::XML::Node (unmanaged)",
94
+ .function = { .dmark = NULL, .dfree = NULL },
95
+ .parent = &rxml_node_data_type,
96
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
97
+ };
98
+
99
+ static const rb_data_type_t rxml_node_managed_data_type = {
100
+ .wrap_struct_name = "LibXML::XML::Node (managed)",
101
+ .function = { .dmark = (RUBY_DATA_FUNC)rxml_node_mark, .dfree = rxml_node_free },
102
+ .parent = &rxml_node_data_type,
103
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
104
+ };
105
+
62
106
  void rxml_node_manage(xmlNodePtr xnode, VALUE node)
63
107
  {
64
- RDATA(node)->dfree = (RUBY_DATA_FUNC)rxml_node_free;
65
- xnode->_private = (void*)node;
108
+ VALUE *type_ptr = (VALUE *)&RTYPEDDATA(node)->type;
109
+ *type_ptr = (*type_ptr & TYPED_DATA_EMBEDDED) | (VALUE)&rxml_node_managed_data_type;
110
+ rxml_registry_register(xnode, node);
66
111
  }
67
112
 
68
113
  void rxml_node_unmanage(xmlNodePtr xnode, VALUE node)
69
114
  {
70
- RDATA(node)->dfree = NULL;
71
- xnode->_private = NULL;
115
+ VALUE *type_ptr = (VALUE *)&RTYPEDDATA(node)->type;
116
+ *type_ptr = (*type_ptr & TYPED_DATA_EMBEDDED) | (VALUE)&rxml_node_data_type;
117
+ rxml_registry_unregister(xnode);
72
118
  }
73
119
 
74
120
  xmlNodePtr rxml_node_root(xmlNodePtr xnode)
@@ -87,20 +133,16 @@ void rxml_node_mark(xmlNodePtr xnode)
87
133
  {
88
134
  if (xnode->doc)
89
135
  {
90
- if (xnode->doc->_private)
91
- {
92
- VALUE doc = (VALUE)xnode->doc->_private;
93
- rb_gc_mark(doc);
94
- }
136
+ VALUE doc = rxml_registry_lookup(xnode->doc);
137
+ if (!NIL_P(doc))
138
+ rb_gc_mark(doc);
95
139
  }
96
140
  else if (xnode->parent)
97
141
  {
98
142
  xmlNodePtr root = rxml_node_root(xnode);
99
- if (root->_private)
100
- {
101
- VALUE node = (VALUE)root->_private;
143
+ VALUE node = rxml_registry_lookup(root);
144
+ if (!NIL_P(node))
102
145
  rb_gc_mark(node);
103
- }
104
146
  }
105
147
  }
106
148
 
@@ -109,13 +151,10 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
109
151
  VALUE result = Qnil;
110
152
 
111
153
  // Is this node already wrapped?
112
- if (xnode->_private)
113
- {
114
- result = (VALUE)xnode->_private;
115
- }
116
- else
154
+ result = rxml_registry_lookup(xnode);
155
+ if (NIL_P(result))
117
156
  {
118
- result = Data_Wrap_Struct(cXMLNode, rxml_node_mark, NULL, xnode);
157
+ result = TypedData_Wrap_Struct(cXMLNode, &rxml_node_data_type, xnode);
119
158
  }
120
159
 
121
160
  if (!xnode->doc && !xnode->parent)
@@ -128,13 +167,13 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
128
167
  static VALUE rxml_node_alloc(VALUE klass)
129
168
  {
130
169
  // This node was created from Ruby so we are responsible for freeing it not libxml
131
- return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
170
+ return TypedData_Wrap_Struct(klass, &rxml_node_data_type, NULL);
132
171
  }
133
172
 
134
173
  static xmlNodePtr rxml_get_xnode(VALUE node)
135
174
  {
136
175
  xmlNodePtr result;
137
- Data_Get_Struct(node, xmlNode, result);
176
+ TypedData_Get_Struct(node, xmlNode, &rxml_node_data_type, result);
138
177
 
139
178
  if (!result)
140
179
  rb_raise(rb_eRuntimeError, "This node has already been freed.");
@@ -283,7 +322,7 @@ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
283
322
  name = rb_obj_as_string(name);
284
323
 
285
324
  if (!NIL_P(ns))
286
- Data_Get_Struct(ns, xmlNs, xns);
325
+ TypedData_Get_Struct(ns, xmlNs, &rxml_namespace_type, xns);
287
326
 
288
327
  xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name));
289
328
 
@@ -291,7 +330,7 @@ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
291
330
  rxml_raise(xmlGetLastError());
292
331
 
293
332
  // Link the ruby wrapper to the underlying libxml node
294
- RDATA(self)->data = xnode;
333
+ RTYPEDDATA_DATA(self) = xnode;
295
334
 
296
335
  // Ruby is in charge of managing this node's memory
297
336
  rxml_node_manage(xnode, self);
@@ -329,7 +368,7 @@ static VALUE rxml_node_modify_dom(VALUE self, VALUE target,
329
368
 
330
369
  /* Assume the target was freed, we need to fix up the ruby object to point to the
331
370
  newly returned node. */
332
- RDATA(target)->data = xresult;
371
+ RTYPEDDATA_DATA(target) = xresult;
333
372
 
334
373
  return target;
335
374
  }
@@ -533,7 +572,7 @@ static VALUE rxml_node_doc(VALUE self)
533
572
  if (xdoc == NULL)
534
573
  return (Qnil);
535
574
 
536
- return (VALUE)xdoc->_private;
575
+ return rxml_registry_lookup(xdoc);
537
576
  }
538
577
 
539
578
  /*
@@ -4,6 +4,8 @@
4
4
  #define __RXML_NODE__
5
5
 
6
6
  extern VALUE cXMLNode;
7
+ extern const rb_data_type_t rxml_node_data_type;
8
+ extern const rb_data_type_t rxml_node_unmanaged_data_type;
7
9
 
8
10
  void rxml_init_node(void);
9
11
  void rxml_node_mark(xmlNodePtr xnode);
@@ -64,7 +64,7 @@ static VALUE rxml_parser_parse(VALUE self)
64
64
  xmlParserCtxtPtr ctxt;
65
65
  VALUE context = rb_ivar_get(self, CONTEXT_ATTR);
66
66
 
67
- Data_Get_Struct(context, xmlParserCtxt, ctxt);
67
+ TypedData_Get_Struct(context, xmlParserCtxt, &rxml_parser_context_type, ctxt);
68
68
 
69
69
  if ((xmlParseDocument(ctxt) == -1 || !ctxt->wellFormed) && ! ctxt->recovery)
70
70
  {