Module: Leptris::XML::FFI
- Extended by:
- FFI::Library
- Defined in:
- lib/leptris/xml/ffi.rb
Defined Under Namespace
Classes: ParseOptionsStruct, PullEventStruct, SAXHandler, SerializeOptions
Constant Summary collapse
- 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.
714 715 716 717 718 719 |
# File 'lib/leptris/xml/ffi.rb', line 714 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.
769 770 771 772 773 774 775 776 |
# File 'lib/leptris/xml/ffi.rb', line 769 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
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 |
# File 'lib/leptris/xml/ffi.rb', line 787 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].
805 806 807 808 809 810 |
# File 'lib/leptris/xml/ffi.rb', line 805 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.
704 705 706 707 708 |
# File 'lib/leptris/xml/ffi.rb', line 704 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.
754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/leptris/xml/ffi.rb', line 754 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
721 722 723 724 725 |
# File 'lib/leptris/xml/ffi.rb', line 721 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.
732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
# File 'lib/leptris/xml/ffi.rb', line 732 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.
815 816 817 818 819 820 821 822 |
# File 'lib/leptris/xml/ffi.rb', line 815 def self.with_pointer_buffer(count) buffer = ::FFI::MemoryPointer.new(:pointer, count) begin yield buffer ensure buffer.free end end |