Module: PdfOxide::FFI::StringMarshaller

Defined in:
lib/pdf_oxide/ffi/string_marshaller.rb

Overview

UTF-8 string round-tripping between Ruby and the C ABI.

The cdylib’s ‘*char` returns are heap-allocated by Rust and must be released via `free_string`; passing them to `pdf_free` (the handle deallocator) corrupts the heap. StringMarshaller hides the distinction from callers.

Class Method Summary collapse

Class Method Details

.free_c_string(ptr) ⇒ Object

Free a ‘*char` returned by the cdylib. Safe on null.



37
38
39
40
41
42
# File 'lib/pdf_oxide/ffi/string_marshaller.rb', line 37

def self.free_c_string(ptr)
  return if ptr.nil? || ptr.null?
  return unless Bindings.respond_to?(:free_string)

  Bindings.free_string(ptr)
end

.from_c_string(ptr, free_after: true) ⇒ String?

Read a C string pointer and free the underlying buffer.

Parameters:

  • ptr (FFI::Pointer)
  • free_after (Boolean) (defaults to: true)

    free with ‘free_string` after reading.

Returns:

  • (String, nil)

    UTF-8 Ruby string, or nil if the pointer was null.



26
27
28
29
30
31
32
33
34
# File 'lib/pdf_oxide/ffi/string_marshaller.rb', line 26

def self.from_c_string(ptr, free_after: true)
  return nil if ptr.nil? || ptr.null?

  begin
    ptr.read_string.force_encoding('UTF-8')
  ensure
    free_c_string(ptr) if free_after && !ptr.null?
  end
end

.to_utf8(ruby_string) ⇒ String?

Encode a Ruby string as UTF-8 for the C ABI. Returns nil on nil input so callers can pass ‘nil` through unchanged.

Parameters:

  • ruby_string (String, nil)

Returns:

  • (String, nil)


16
17
18
19
20
# File 'lib/pdf_oxide/ffi/string_marshaller.rb', line 16

def self.to_utf8(ruby_string)
  return nil if ruby_string.nil?

  ruby_string.to_s.encode('UTF-8', invalid: :replace, undef: :replace)
end