# :stopdoc:
module Nokogiri
module LibXML
extend FFI::Library
if RUBY_PLATFORM =~ /java/ && java.lang.System.getProperty('os.name') =~ /windows/i
raise(RuntimeError, "Nokogiri requires JRuby 1.4.0 or later on Windows") if JRUBY_VERSION < "1.4.0"
dll_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "ext", "nokogiri"))
libs = ["libxml2.dll", "libxslt.dll", "libexslt.dll"].collect do |lib|
File.join(dll_dir, lib).tr("/","\\") # see http://jira.codehaus.org/browse/JRUBY-2763
end + ["msvcrt"]
ffi_lib(*libs)
else
ffi_lib 'xml2', 'xslt', 'exslt'
end
# globals.c
attach_function :__xmlParserVersion, [], :pointer
attach_function :__xmlIndentTreeOutput, [], :pointer
attach_function :__xmlTreeIndentString, [], :pointer
attach_function :xmlDeregisterNodeDefault, [:pointer], :pointer
end
LIBXML_PARSER_VERSION = LibXML.__xmlParserVersion().read_pointer.read_string
LIBXML_VERSION = LIBXML_PARSER_VERSION.scan(/^(.*)(..)(..)$/).first.collect{|j|j.to_i}.join(".")
LIBXML_ICONV_ENABLED = true # sigh.
end
require 'nokogiri/version'
Nokogiri::VERSION_INFO['libxml'] = {}
Nokogiri::VERSION_INFO['libxml']['loaded'] = Nokogiri::LIBXML_VERSION
Nokogiri::VERSION_INFO['libxml']['binding'] = 'ffi'
if RUBY_PLATFORM =~ /java/
Nokogiri::VERSION_INFO['libxml']['platform'] = 'jruby'
raise(RuntimeError, "Nokogiri requires JRuby 1.3.0 or later") if JRUBY_VERSION < "1.3.0"
else
Nokogiri::VERSION_INFO['libxml']['platform'] = 'ruby'
end
module Nokogiri
module LibXML
XML_CHAR_ENCODING_ERROR = -1
# useful callback signatures
callback :syntax_error_handler, [:pointer, :pointer], :void
callback :generic_error_handler, [:pointer, :string], :void
callback :io_write_callback, [:pointer, :string, :int], :int
callback :io_read_callback, [:pointer, :pointer, :int], :int
callback :io_close_callback, [:pointer], :int
callback :hash_copier_callback, [:pointer, :pointer, :string], :void
callback :xpath_callback, [:pointer, :int], :void
callback :xpath_lookup_callback, [:pointer, :string, :pointer], :xpath_callback
callback :start_document_sax_func, [:pointer], :void
callback :end_document_sax_func, [:pointer], :void
callback :start_element_sax_func, [:pointer, :string, :pointer], :void
callback :end_element_sax_func, [:pointer, :string], :void
callback :characters_sax_func, [:pointer, :string, :int], :void
callback :comment_sax_func, [:pointer, :string], :void
callback :warning_sax_func, [:pointer, :string], :void
callback :error_sax_func, [:pointer, :string], :void
callback :cdata_block_sax_func, [:pointer, :string, :int], :void
callback :start_element_ns_sax2_func, [:pointer, :pointer, :pointer, :pointer, :int, :pointer, :int, :int, :pointer], :void
callback :end_element_ns_sax2_func, [:pointer, :pointer, :pointer, :pointer], :void
# encoding.c
attach_function :xmlFindCharEncodingHandler, [:string], :pointer
attach_function :xmlDelEncodingAlias, [:string], :int
attach_function :xmlAddEncodingAlias, [:string, :string], :int
attach_function :xmlCleanupEncodingAliases, [], :void
# HTMLparser.c
attach_function :htmlReadMemory, [:string, :int, :string, :string, :int], :pointer
attach_function :htmlReadIO, [:io_read_callback, :io_close_callback, :pointer, :string, :string, :int], :pointer
attach_function :htmlNewDoc, [:string, :string], :pointer
attach_function :htmlTagLookup, [:string], :pointer
attach_function :htmlEntityLookup, [:string], :pointer
attach_function :htmlSAXParseFile, [:string, :pointer, :pointer, :pointer], :pointer # second arg 'encoding' should be a string, but we assign it as a pointer elsewhere
attach_function :htmlSAXParseDoc, [:pointer, :pointer, :pointer, :pointer], :pointer # second arg 'encoding' should be a string, but we assign it as a pointer elsewhere
attach_function :htmlCreateMemoryParserCtxt, [:pointer, :int], :pointer
attach_function :htmlCreateFileParserCtxt, [:pointer, :pointer], :pointer
attach_function :htmlParseDocument, [:pointer], :int
# HTMLtree.c
attach_function :htmlDocDumpMemory, [:pointer, :pointer, :pointer], :void
attach_function :htmlNodeDump, [:pointer, :pointer, :pointer], :int
attach_function :htmlGetMetaEncoding, [:pointer], :string # returns const char*
attach_function :htmlSetMetaEncoding, [:pointer, :string], :void
# parser.c
attach_function :xmlReadMemory, [:string, :int, :string, :string, :int], :pointer
attach_function :xmlInitParser, [], :void
attach_function :xmlReadIO, [:io_read_callback, :io_close_callback, :pointer, :string, :string, :int], :pointer
attach_function :xmlCreateIOParserCtxt, [:pointer, :pointer, :io_read_callback, :io_close_callback, :pointer, :int], :pointer
attach_function :xmlCreateMemoryParserCtxt, [:pointer, :int], :pointer
attach_function :xmlCreateFileParserCtxt, [:pointer], :pointer
attach_function :xmlSAXUserParseMemory, [:pointer, :pointer, :string, :int], :int
attach_function :xmlSAXUserParseFile, [:pointer, :pointer, :string], :int
attach_function :xmlParseDocument, [:pointer], :int
attach_function :xmlFreeParserCtxt, [:pointer], :void
attach_function :xmlCreatePushParserCtxt, [:pointer, :pointer, :string, :int, :string], :pointer
attach_function :xmlParseChunk, [:pointer, :string, :int, :int], :int
attach_function :xmlCtxtUseOptions, [:pointer, :int], :int
# tree.c
attach_function :xmlNewDoc, [:string], :pointer
attach_function :xmlNewDocFragment, [:pointer], :pointer
attach_function :xmlDocGetRootElement, [:pointer], :pointer
attach_function :xmlDocSetRootElement, [:pointer, :pointer], :pointer
attach_function :xmlCopyDoc, [:pointer, :int], :pointer
attach_function :xmlFreeDoc, [:pointer], :void
attach_function :xmlSetTreeDoc, [:pointer, :pointer], :void
attach_function :xmlNewReference, [:pointer, :string], :pointer
attach_function :xmlNewNode, [:pointer, :string], :pointer
attach_function :xmlCopyNode, [:pointer, :int], :pointer
attach_function :xmlDocCopyNode, [:pointer, :pointer, :int], :pointer
attach_function :xmlReplaceNode, [:pointer, :pointer], :pointer
attach_function :xmlUnlinkNode, [:pointer], :void
attach_function :xmlAddChild, [:pointer, :pointer], :pointer
attach_function :xmlAddNextSibling, [:pointer, :pointer], :pointer
attach_function :xmlAddPrevSibling, [:pointer, :pointer], :pointer
attach_function :xmlIsBlankNode, [:pointer], :int
attach_function :xmlHasProp, [:pointer, :string], :pointer
attach_function :xmlHasNsProp, [:pointer, :string, :string], :pointer
attach_function :xmlGetProp, [:pointer, :string], :pointer # returns char* that must be freed
attach_function :xmlSetProp, [:pointer, :string, :string], :pointer
attach_function :xmlRemoveProp, [:pointer], :int
attach_function :xmlNodeSetContent, [:pointer, :string], :void
attach_function :xmlNodeGetContent, [:pointer], :pointer # returns char* that must be freed
attach_function :xmlNodeSetName, [:pointer, :string], :void
attach_function :xmlGetNodePath, [:pointer], :pointer
attach_function :xmlNewCDataBlock, [:pointer, :string, :int], :pointer
attach_function :xmlNewDocComment, [:pointer, :string], :pointer
attach_function :xmlNewDocPI, [:pointer, :string, :string], :pointer
attach_function :xmlNewText, [:string], :pointer
attach_function :xmlFreeNode, [:pointer], :void
attach_function :xmlFreeNodeList, [:pointer], :void
attach_function :xmlEncodeEntitiesReentrant, [:pointer, :string], :pointer # returns char* that must be freed
attach_function :xmlStringGetNodeList, [:pointer, :pointer], :pointer # second arg should be a :string, but we only ship the results of xmlEncodeEntitiesReentrant, so let's optimize.
attach_function :xmlNewNs, [:pointer, :string, :string], :pointer
attach_function :xmlNewNsProp, [:pointer, :pointer, :string, :string], :pointer
attach_function :xmlSearchNs, [:pointer, :pointer, :string], :pointer
attach_function :xmlSearchNsByHref, [:pointer, :pointer, :string], :pointer
attach_function :xmlGetIntSubset, [:pointer], :pointer
attach_function :xmlBufferCreate, [], :pointer
attach_function :xmlBufferFree, [:pointer], :void
attach_function :xmlSplitQName2, [:string, :buffer_out], :pointer # returns char* that must be freed
attach_function :xmlNewDocProp, [:pointer, :string, :string], :pointer
attach_function :xmlFreePropList, [:pointer], :void
attach_function :xmlCreateIntSubset, [:pointer] * 4, :pointer
attach_function :xmlNewDtd, [:pointer] * 4, :pointer
# valid.c
attach_function :xmlNewValidCtxt, [], :pointer
attach_function :xmlValidateDtd, [:pointer, :pointer, :pointer], :int
attach_function :xmlFreeValidCtxt, [:pointer], :void
# xmlsave.c
attach_function :xmlDocDumpMemory, [:pointer, :pointer, :pointer], :void
attach_function :xmlNodeDump, [:pointer, :pointer, :pointer, :int, :int], :int
attach_function :xmlSaveToIO, [:io_write_callback, :io_close_callback, :pointer, :string, :int], :pointer
attach_function :xmlSaveTree, [:pointer, :pointer], :int
attach_function :xmlSaveClose, [:pointer], :int
attach_function :xmlSetNs, [:pointer, :pointer], :void
# entities.c
attach_function :xmlEncodeSpecialChars, [:pointer, :string], :pointer # returns char* that must be freed
# xpath.c
attach_function :xmlXPathInit, [], :void
attach_function :xmlXPathNewContext, [:pointer], :pointer
attach_function :xmlXPathFreeContext, [:pointer], :void
attach_function :xmlXPathEvalExpression, [:string, :pointer], :pointer
attach_function :xmlXPathRegisterNs, [:pointer, :string, :string], :int
attach_function :xmlXPathCmpNodes, [:pointer, :pointer], :int
attach_function :xmlXPathNodeSetContains, [:pointer, :pointer], :int
attach_function :xmlXPathNodeSetAdd, [:pointer, :pointer], :void
attach_function :xmlXPathNodeSetRemove, [:pointer, :int], :void
attach_function :xmlXPathNodeSetCreate, [:pointer], :pointer
attach_function :xmlXPathNodeSetDel, [:pointer, :pointer], :void
attach_function :xmlXPathIntersection, [:pointer, :pointer], :pointer
attach_function :xmlXPathFreeNodeSetList, [:pointer], :void
attach_function :xmlXPathRegisterFuncLookup, [:pointer, :xpath_lookup_callback, :pointer], :void
attach_function :valuePop, [:pointer], :pointer
attach_function :valuePush, [:pointer, :pointer], :int
attach_function :xmlXPathCastToString, [:pointer], :pointer # returns char* that must be freed
attach_function :xmlXPathNodeSetMerge, [:pointer, :pointer], :pointer
attach_function :xmlXPathWrapNodeSet, [:pointer], :pointer
attach_function :xmlXPathWrapCString, [:pointer], :pointer # should take a :string, but we optimize
attach_function :xmlXPathWrapString, [:pointer], :pointer # should take a :string, but we optimize
attach_function :xmlXPathNewBoolean, [:int], :pointer
attach_function :xmlXPathNewFloat, [:double], :pointer
class << self
# these functions are implemented as C macros
def xmlXPathReturnNodeSet(ctx, ns)
valuePush(ctx, xmlXPathWrapNodeSet(ns))
end
def xmlXPathReturnTrue(ctx)
valuePush(ctx, xmlXPathNewBoolean(1))
end
def xmlXPathReturnFalse(ctx)
valuePush(ctx, xmlXPathNewBoolean(0))
end
def xmlXPathReturnString(ctx, str)
valuePush(ctx, xmlXPathWrapString(str))
end
def xmlXPathReturnNumber(ctx, val)
valuePush(ctx, xmlXPathNewFloat(val))
end
end
# xmlstring.c
attach_function :xmlStrdup, [:string], :pointer # returns char* that must be freed
def self.xmlFree(pointer)
# xmlFree is a C preprocessor macro, not an actual function
self.free(pointer)
end
# error.c
attach_function :xmlSetStructuredErrorFunc, [:pointer, :syntax_error_handler], :void
attach_function :xmlSetGenericErrorFunc, [:pointer, :generic_error_handler], :void
attach_function :xmlResetLastError, [], :void
attach_function :xmlCopyError, [:pointer, :pointer], :int
attach_function :xmlGetLastError, [], :pointer
attach_function :xmlCtxtGetLastError, [:pointer], :pointer
# hash.c
attach_function :xmlHashScan, [:pointer, :hash_copier_callback, :pointer], :void
# xmlreader.c
attach_function :xmlReaderForMemory, [:pointer, :int, :string, :string, :int], :pointer
attach_function :xmlTextReaderGetAttribute, [:pointer, :string], :pointer # returns char* that must be freed
attach_function :xmlTextReaderGetAttributeNo, [:pointer, :int], :pointer # returns char* that must be freed
attach_function :xmlTextReaderLookupNamespace, [:pointer, :string], :pointer # returns char* that must be freed
attach_function :xmlTextReaderRead, [:pointer], :int
attach_function :xmlTextReaderReadInnerXml, [:pointer], :pointer
attach_function :xmlTextReaderReadOuterXml, [:pointer], :pointer
attach_function :xmlTextReaderAttributeCount, [:pointer], :int
attach_function :xmlTextReaderCurrentNode, [:pointer], :pointer
attach_function :xmlTextReaderExpand, [:pointer], :pointer
attach_function :xmlTextReaderIsDefault, [:pointer], :int
attach_function :xmlTextReaderDepth, [:pointer], :int
attach_function :xmlTextReaderConstXmlLang, [:pointer], :pointer # returns a const char*, but must check for null
attach_function :xmlTextReaderConstLocalName, [:pointer], :pointer # returns a const char* that is deallocated with the reader
attach_function :xmlTextReaderConstName, [:pointer], :pointer # returns a const char* that is deallocated with the reader
attach_function :xmlTextReaderConstNamespaceUri, [:pointer], :pointer # returns a const char* that is deallocated with the reader
attach_function :xmlTextReaderConstPrefix, [:pointer], :pointer # returns a const char* that is deallocated with the reader
attach_function :xmlTextReaderConstValue, [:pointer], :pointer # returns a const char* that is deallocated on the next read()
attach_function :xmlTextReaderConstXmlVersion, [:pointer], :pointer # returns a const char* that is deallocated with the reader
attach_function :xmlTextReaderReadState, [:pointer], :int
attach_function :xmlTextReaderHasValue, [:pointer], :int
attach_function :xmlFreeTextReader, [:pointer], :void
attach_function :xmlReaderForIO, [:io_read_callback, :io_close_callback, :pointer, :string, :string, :int], :pointer
attach_function :xmlTextReaderNodeType, [:pointer], :int
# xslt.c
attach_function :xsltParseStylesheetDoc, [:pointer], :pointer
attach_function :xsltFreeStylesheet, [:pointer], :void
attach_function :xsltApplyStylesheet, [:pointer, :pointer, :pointer], :pointer
attach_function :xsltSaveResultToString, [:buffer_out, :buffer_out, :pointer, :pointer], :int
attach_function :xsltSetGenericErrorFunc, [:pointer, :generic_error_handler], :void
# exslt.c
attach_function :exsltRegisterAll, [], :void
# xmlschemas.c
attach_function :xmlSchemaNewValidCtxt, [:pointer], :pointer
attach_function :xmlSchemaSetValidStructuredErrors, [:pointer, :syntax_error_handler, :pointer], :void unless Nokogiri.is_2_6_16?
attach_function :xmlSchemaValidateDoc, [:pointer, :pointer], :void
attach_function :xmlSchemaFreeValidCtxt, [:pointer], :void
attach_function :xmlSchemaNewMemParserCtxt, [:pointer, :int], :pointer # first arg could be string, but we pass length, so let's optimize
attach_function :xmlSchemaSetParserStructuredErrors, [:pointer, :syntax_error_handler, :pointer], :void unless Nokogiri.is_2_6_16?
attach_function :xmlSchemaParse, [:pointer], :pointer
attach_function :xmlSchemaFreeParserCtxt, [:pointer], :void
attach_function :xmlSchemaNewDocParserCtxt, [:pointer], :pointer
# relaxng.c
attach_function :xmlRelaxNGNewValidCtxt, [:pointer], :pointer
attach_function :xmlRelaxNGSetValidStructuredErrors, [:pointer, :syntax_error_handler, :pointer], :void unless Nokogiri.is_2_6_16?
attach_function :xmlRelaxNGValidateDoc, [:pointer, :pointer], :int
attach_function :xmlRelaxNGFreeValidCtxt, [:pointer], :void
attach_function :xmlRelaxNGNewMemParserCtxt, [:pointer, :int], :pointer # first arg could be string, but we pass length, so let's optimize
attach_function :xmlRelaxNGSetParserStructuredErrors, [:pointer, :syntax_error_handler, :pointer], :void unless Nokogiri.is_2_6_16?
attach_function :xmlRelaxNGParse, [:pointer], :pointer
attach_function :xmlRelaxNGFreeParserCtxt, [:pointer], :void
attach_function :xmlRelaxNGNewDocParserCtxt, [:pointer], :pointer
# libc
attach_function :calloc, [:int, :int], :pointer
attach_function :free, [:pointer], :void
attach_function :xmlParseCharEncoding, [:string], :int
attach_function :xmlSwitchEncoding, [:pointer, :int], :void
# helpers
POINTER_SIZE = FFI.type_size(:pointer)
def self.pointer_offset(n)
n * POINTER_SIZE # byte offset of nth pointer in an array of pointers
end
end
end
# :startdoc:
require 'nokogiri/syntax_error'
require 'nokogiri/xml/syntax_error'
[ "io_callbacks",
"encoding_handler",
"structs/common_node",
"structs/xml_alloc",
"structs/xml_char_encoding_handler",
"structs/xml_document",
"structs/xml_node",
"structs/xml_dtd",
"structs/xml_notation",
"structs/xml_node_set",
"structs/xml_xpath_context",
"structs/xml_xpath_object",
"structs/xml_xpath_parser_context",
"structs/xml_buffer",
"structs/xml_syntax_error",
"structs/xml_attr",
"structs/xml_ns",
"structs/xml_schema",
"structs/xml_relax_ng",
"structs/xml_text_reader",
"structs/xml_sax_handler",
"structs/xml_sax_push_parser_context",
"structs/xml_enumeration",
"structs/html_elem_desc",
"structs/html_entity_desc",
"structs/xslt_stylesheet",
"structs/xml_parser_context",
"structs/xml_attribute",
"structs/xml_element",
"structs/xml_entity",
"structs/xml_element_content",
"xml/node",
"xml/namespace",
"xml/dtd",
"xml/attr",
"xml/attribute_decl",
"xml/element_decl",
"xml/element_content",
"xml/entity_decl",
"xml/document",
"xml/document_fragment",
"xml/schema",
"xml/relax_ng",
"xml/text",
"xml/cdata",
"xml/comment",
"xml/processing_instruction",
"xml/node_set",
"xml/xpath",
"xml/xpath_context",
"xml/syntax_error",
"xml/reader",
"xml/entity_reference",
"xml/sax/parser_context",
"xml/sax/parser",
"xml/sax/push_parser",
"html/document",
"html/element_description",
"html/entity_lookup",
"html/sax/parser_context",
"xslt/stylesheet",
].each do |file|
require "nokogiri/ffi/#{file}"
end