diff --git a/ext/nokogiri/nokogiri.h b/ext/nokogiri/nokogiri.h index 51ddbf8d1e..399967ebd0 100644 --- a/ext/nokogiri/nokogiri.h +++ b/ext/nokogiri/nokogiri.h @@ -171,6 +171,7 @@ int noko_io_write(void *ctx, char *buffer, int len); int noko_io_close(void *ctx); #define Noko_Node_Get_Struct(obj,type,sval) ((sval) = (type*)DATA_PTR(obj)) +#define Noko_Namespace_Get_Struct(obj,type,sval) ((sval) = (type*)DATA_PTR(obj)) VALUE noko_xml_node_wrap(VALUE klass, xmlNodePtr node) ; VALUE noko_xml_node_wrap_node_set_result(xmlNodePtr node, VALUE node_set) ; diff --git a/ext/nokogiri/xml_namespace.c b/ext/nokogiri/xml_namespace.c index 0b41acf1af..52b49c5207 100644 --- a/ext/nokogiri/xml_namespace.c +++ b/ext/nokogiri/xml_namespace.c @@ -25,13 +25,15 @@ VALUE cNokogiriXmlNamespace ; static void -dealloc_namespace(xmlNsPtr ns) +_xml_namespace_dealloc(void *ptr) { /* * this deallocator is only used for namespace nodes that are part of an xpath * node set. see noko_xml_namespace_wrap(). */ + xmlNsPtr ns = ptr; NOKOGIRI_DEBUG_START(ns) ; + if (ns->href) { xmlFree(DISCARD_CONST_QUAL_XMLCHAR(ns->href)); } @@ -42,6 +44,36 @@ dealloc_namespace(xmlNsPtr ns) NOKOGIRI_DEBUG_END(ns) ; } +#ifdef HAVE_RB_GC_LOCATION +static void +_xml_namespace_update_references(void *ptr) +{ + xmlNsPtr ns = ptr; + if (ns->_private) { + ns->_private = (void *)rb_gc_location((VALUE)ns->_private); + } +} +#else +# define _xml_namespace_update_references 0 +#endif + +static const rb_data_type_t nokogiri_xml_namespace_type_with_dealloc = { + "Nokogiri/XMLNamespace/WithDealloc", + {0, _xml_namespace_dealloc, 0, _xml_namespace_update_references}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; + +static const rb_data_type_t nokogiri_xml_namespace_type_without_dealloc = { + "Nokogiri/XMLNamespace/WithoutDealloc", + {0, 0, 0, _xml_namespace_update_references}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; /* * call-seq: @@ -54,7 +86,7 @@ prefix(VALUE self) { xmlNsPtr ns; - Data_Get_Struct(self, xmlNs, ns); + Noko_Namespace_Get_Struct(self, xmlNs, ns); if (!ns->prefix) { return Qnil; } return NOKOGIRI_STR_NEW2(ns->prefix); @@ -71,7 +103,7 @@ href(VALUE self) { xmlNsPtr ns; - Data_Get_Struct(self, xmlNs, ns); + Noko_Namespace_Get_Struct(self, xmlNs, ns); if (!ns->href) { return Qnil; } return NOKOGIRI_STR_NEW2(ns->href); @@ -87,14 +119,18 @@ noko_xml_namespace_wrap(xmlNsPtr c_namespace, xmlDocPtr c_document) } if (c_document) { - rb_namespace = Data_Wrap_Struct(cNokogiriXmlNamespace, 0, 0, c_namespace); + rb_namespace = TypedData_Wrap_Struct(cNokogiriXmlNamespace, + &nokogiri_xml_namespace_type_without_dealloc, + c_namespace); if (DOC_RUBY_OBJECT_TEST(c_document)) { rb_iv_set(rb_namespace, "@document", DOC_RUBY_OBJECT(c_document)); rb_ary_push(DOC_NODE_CACHE(c_document), rb_namespace); } } else { - rb_namespace = Data_Wrap_Struct(cNokogiriXmlNamespace, 0, dealloc_namespace, c_namespace); + rb_namespace = TypedData_Wrap_Struct(cNokogiriXmlNamespace, + &nokogiri_xml_namespace_type_with_dealloc, + c_namespace); } c_namespace->_private = (void *)rb_namespace; diff --git a/ext/nokogiri/xml_node.c b/ext/nokogiri/xml_node.c index c80d2d4247..01b5602b65 100644 --- a/ext/nokogiri/xml_node.c +++ b/ext/nokogiri/xml_node.c @@ -1353,7 +1353,7 @@ set_namespace(VALUE self, VALUE namespace) Noko_Node_Get_Struct(self, xmlNode, node); if (!NIL_P(namespace)) { - Data_Get_Struct(namespace, xmlNs, ns); + Noko_Namespace_Get_Struct(namespace, xmlNs, ns); } xmlSetNs(node, ns);