Module: Leptris::XML::FFI
- Extended by:
- FFI::Library
- Defined in:
- lib/leptris/xml/ffi.rb
Defined Under Namespace
Classes: ParseOptionsStruct, PullEventStruct, SAXHandler, SaxEventRecord, SerializeOptions
Constant Summary collapse
- SAX_EVENT_START_DOCUMENT =
0- SAX_EVENT_END_DOCUMENT =
1- SAX_EVENT_START_ELEMENT =
2- SAX_EVENT_END_ELEMENT =
3- SAX_EVENT_CHARACTERS =
4- SAX_EVENT_COMMENT =
5- SAX_EVENT_CDATA =
6- SAX_EVENT_PI =
7- SAX_EVENT_START_PREFIX =
8- SAX_EVENT_END_PREFIX =
9- SAX_EVENT_ERROR =
10- ITERPARSE_TOP_LEVEL =
0- ITERPARSE_FULL_DOCUMENT =
1- LEPTRIS_OK =
0- LEPTRIS_ERROR_MEMORY =
-1
- LEPTRIS_ERROR_PARSE =
-2
- LEPTRIS_ERROR_XPATH =
-3
- LEPTRIS_ERROR_NULL_ARG =
-4
- LEPTRIS_ERROR_INVALID_ARG =
-5
- LEPTRIS_ERROR_NOT_FOUND =
-6
- LEPTRIS_ERROR_IO =
-7
- LEPTRIS_ERROR_NOT_IMPLEMENTED =
-8
- XPATH_NODESET =
0- XPATH_BOOLEAN =
1- XPATH_NUMBER =
2- XPATH_STRING =
3- XPATH_NODE_ELEMENT =
0- XPATH_NODE_ATTRIBUTE =
1- XPATH_NODE_TEXT =
2- XPATH_NODE_OTHER =
3- NODE_ELEMENT =
0- NODE_TEXT =
1- NODE_COMMENT =
2- NODE_CDATA =
3- NODE_PI =
4- NODE_DOCTYPE =
5- NODE_ATTRIBUTE =
6- C14N_1_0 =
0- C14N_1_1 =
1- C14N_MODE_CANONICAL =
0- C14N_MODE_EXCLUSIVE =
1- TRAVERSE_PRE_ORDER =
0- TRAVERSE_POST_ORDER =
1- PULL_START_ELEMENT =
0- PULL_END_ELEMENT =
1- PULL_TEXT =
2- PULL_COMMENT =
3- PULL_CDATA =
4- PULL_PI =
5- PULL_END_DOCUMENT =
6- PULL_ERROR =
7- LEPTRIS_PARSE_DEFAULT =
0- LEPTRIS_PARSE_DROP_WS_TEXT =
1- XPATH_KIND_HINT =
XPath result-set batch (leptris_xpath_result_get_nodes_ex): the call fills out_kinds in the 4-value XPATH_NODE space (ELEMENT/ATTRIBUTE/TEXT/OTHER). ELEMENT is the only value that maps unambiguously — XPath's data model reports CDATA as TEXT, so a TEXT hint cannot distinguish Text from CDATA (different content getters) — everything else falls back to get_type in the wrapper. Returns [pointers, element_hints].
{ XPATH_NODE_ELEMENT => NODE_ELEMENT }.freeze
Class Method Summary collapse
-
.check_status(status) ⇒ Object
Single status seam: turns a C status code into a Ruby error, appending the library's last-error detail when present.
-
.fetch_children(c_ptr) ⇒ Object
All-kind child handle batch (libleptris 1.7.0): count-only query sizes the buffer, one fetch copies every child kind, one bulk read materializes the pointers.
- .fetch_result_nodes(result_ptr, count) ⇒ Object
-
.parse_fragment_with_status(xml, document_ptr) ⇒ Object
Fragment parse with the status out-param read: returns [document-or-fragment pointer, status].
-
.read_owned_string(ptr) ⇒ Object
Reads an libleptris-owned char* result and frees it as one unit, so a call site can neither leak nor double-free.
-
.serialize_into_string(ffi_function, c_ptr, options) ⇒ Object
Caller-buffer serialization cycle: size query (buf=NULL), allocate exactly, fill, read.
- .status_message(status) ⇒ Object
-
.with_ns_set(hash) ⇒ Object
Namespace-binding lifecycle, written once: flatten the prefix/URI hash into the alternating CStringArray wire format, build the caller-owned set, yield it, free it under all outcomes.
-
.with_pointer_buffer(count) ⇒ Object
The one buffer-allocation point for handle-array fetches: everything MemoryPointer-related above this line is either an attached C call or another seam helper.
Class Method Details
.check_status(status) ⇒ Object
Single status seam: turns a C status code into a Ruby error, appending the library's last-error detail when present. The detail is a library-global string, so it can only be treated as best-effort context.
768 769 770 771 772 773 |
# File 'lib/leptris/xml/ffi.rb', line 768 def self.check_status(status) unless status == LEPTRIS_OK raise Leptris::XML::Error, (status) end status end |
.fetch_children(c_ptr) ⇒ Object
All-kind child handle batch (libleptris 1.7.0): count-only query sizes the buffer, one fetch copies every child kind, one bulk read materializes the pointers.
823 824 825 826 827 828 829 830 |
# File 'lib/leptris/xml/ffi.rb', line 823 def self.fetch_children(c_ptr) count = leptris_node_children(c_ptr, nil, 0) return [] if count.zero? with_pointer_buffer(count) do |buffer| copied = leptris_node_children(c_ptr, buffer, count) buffer.get_array_of_pointer(0, copied) end end |
.fetch_result_nodes(result_ptr, count) ⇒ Object
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 |
# File 'lib/leptris/xml/ffi.rb', line 841 def self.fetch_result_nodes(result_ptr, count) return [[], nil] if count.zero? with_pointer_buffer(count) do |buffer| kinds = ::FFI::MemoryPointer.new(:int, count) begin copied = leptris_xpath_result_get_nodes_ex( result_ptr, buffer, kinds, count) hints = kinds.get_array_of_int(0, copied) .map { |k| XPATH_KIND_HINT[k] } [buffer.get_array_of_pointer(0, copied), hints] ensure kinds.free end end end |
.parse_fragment_with_status(xml, document_ptr) ⇒ Object
Fragment parse with the status out-param read: returns [document-or-fragment pointer, status].
859 860 861 862 863 864 |
# File 'lib/leptris/xml/ffi.rb', line 859 def self.parse_fragment_with_status(xml, document_ptr) status = ::FFI::MemoryPointer.new(:int) raw = leptris_parse_fragment( xml, xml.bytesize, document_ptr, status) [raw, status.read_int] end |
.read_owned_string(ptr) ⇒ Object
Reads an libleptris-owned char* result and frees it as one unit, so a call site can neither leak nor double-free.
758 759 760 761 762 |
# File 'lib/leptris/xml/ffi.rb', line 758 def self.read_owned_string(ptr) return "" if ptr.nil? || ptr.null? ptr.read_string.tap { leptris_free_string(ptr) } .force_encoding(Encoding::UTF_8) end |
.serialize_into_string(ffi_function, c_ptr, options) ⇒ Object
Caller-buffer serialization cycle: size query (buf=NULL),
allocate exactly, fill, read. Since libleptris 1.9.0 the
pair reuses one serialization through the per-document
cache. ffi_function is leptris_document_serialize_into or
leptris_element_serialize_into. The buffer holds the
serialization + NUL and XML output is NUL-free, so the
bounded read is exact.
808 809 810 811 812 813 814 815 816 817 818 |
# File 'lib/leptris/xml/ffi.rb', line 808 def self.serialize_into_string(ffi_function, c_ptr, ) need = ffi_function.call(c_ptr, nil, 0, nil, ) return "" if need.zero? buffer = ::FFI::MemoryPointer.new(:char, need) begin ffi_function.call(c_ptr, buffer, need, nil, ) buffer.read_string ensure buffer.free end end |
.status_message(status) ⇒ Object
775 776 777 778 779 |
# File 'lib/leptris/xml/ffi.rb', line 775 def self.(status) base = leptris_status_string(status).to_s detail = leptris_last_error.to_s detail.empty? ? base : "#{base} (#{detail})" end |
.with_ns_set(hash) ⇒ Object
Namespace-binding lifecycle, written once: flatten the prefix/URI hash into the alternating CStringArray wire format, build the caller-owned set, yield it, free it under all outcomes. Every eval variant uses this; none of them knows how a set is born or dies.
786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/leptris/xml/ffi.rb', line 786 def self.with_ns_set(hash) flat = hash.flat_map { |prefix, uri| [prefix.to_s, uri.to_s] } buffer, _anchors = Leptris::XML::CStringArray.to_c(flat) set = leptris_xpath_ns_set_new_from_pairs(buffer, flat.length / 2) if set.null? raise Leptris::XML::Error, "leptris_xpath_ns_set_new_from_pairs failed" end begin yield set ensure leptris_xpath_ns_set_free(set) end end |
.with_pointer_buffer(count) ⇒ Object
The one buffer-allocation point for handle-array fetches: everything MemoryPointer-related above this line is either an attached C call or another seam helper.
869 870 871 872 873 874 875 876 |
# File 'lib/leptris/xml/ffi.rb', line 869 def self.with_pointer_buffer(count) buffer = ::FFI::MemoryPointer.new(:pointer, count) begin yield buffer ensure buffer.free end end |