Class: CTypes::String

Inherits:
Object
  • Object
show all
Includes:
Type
Defined in:
lib/ctypes/string.rb

Overview

Type used to unpack binary strings into Ruby String instances

Examples:

greedy string

t = CTypes::String.new
t.unpack("hello world\0bye")      # => "hello world"

# greedy string will consume all bytes, but only return string up to the
# first null-terminator
t.unpack_one("hello world\0bye")  # => ["hello world", ""]

t.pack("test")                    # => "test"
t.pack("test\0")                  # => "test\0"

null-terminated string

t = CTypes::String.terminated
t.unpack("hello world\0bye")      # => "hello world"

# terminated string will consume bytes up to and including the
# terminator
t.unpack_one("hello world\0bye")  # => ["hello world", "bye"]

t.pack("test")                    # => "test\0"

fixed-size string

t = CTypes::String.new(size: 5)
t.unpack("hello world\0bye")      # => "hello"
t.unpack_one("hello world\0bye")  # => ["hello", " world\0bye"]
t.pack("hi")                      # => "hi\0\0\0"

fixed-size string, preserving null bytes

t = CTypes::String.new(size: 8, trim: false)
t.unpack("abc\0\0xyzXXXX")        # => "abc\0\0xyz"
t.pack("hello")                   # => "hello\0\0\0"

Instance Attribute Summary collapse

Attributes included from Type

#dry_type, #endian

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Type

#default_endian, #default_value, #fixed_size?, #pread, #read, #unpack, #unpack_all, #with_endian, #without_endian

Constructor Details

#initialize(size: nil, trim: true) ⇒ String



63
64
65
66
67
68
69
70
71
72
# File 'lib/ctypes/string.rb', line 63

def initialize(size: nil, trim: true)
  @size = size
  @trim = trim
  @dry_type = Dry::Types["coercible.string"].default("")
  @dry_type = @dry_type.constrained(max_size: size) if size.is_a?(Integer)
  size ||= "*"

  @fmt_pack = "a%s" % size
  @fmt_unpack = (trim ? "Z%s" : "a%s") % size
end

Instance Attribute Details

#trimObject (readonly)

Returns the value of attribute trim.



73
74
75
# File 'lib/ctypes/string.rb', line 73

def trim
  @trim
end

Class Method Details

.terminated(terminator = "\0") ⇒ Object

Return a CTypes::String type that is terminated by the supplied sequence

Examples:

null-terminated string

t = CTypes::String.terminated
t.unpack("hello world\0bye")    # => "hello world"

string terminated string

t = CTypes::String.terminated("STOP")
t.unpack("test 1STOPtest 2STOP")  # => "test 1"


54
55
56
57
58
59
# File 'lib/ctypes/string.rb', line 54

def self.terminated(terminator = "\0")
  size = terminator.size
  Terminated.new(type: new,
    locate: proc { |b, _| [b.index(terminator), size] },
    terminate: terminator)
end

Instance Method Details

#==(other) ⇒ Object



150
151
152
# File 'lib/ctypes/string.rb', line 150

def ==(other)
  other.is_a?(self.class) && other.size == size && other.trim == trim
end

#export_type(q) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ctypes/string.rb', line 125

def export_type(q)
  q << if size && size > 0
    if trim
      "string(%d)" % [@size]
    else
      "string(%d, trim: false)" % [@size]
    end
  else
    "string"
  end
end

#greedy?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



98
99
100
# File 'lib/ctypes/string.rb', line 98

def greedy?
  @size.nil?
end

#pack(value, endian: default_endian, validate: true) ⇒ ::String

pack a ruby String into a binary string, applying any required padding



81
82
83
84
# File 'lib/ctypes/string.rb', line 81

def pack(value, endian: default_endian, validate: true)
  value = @dry_type[value] if validate
  [value].pack(@fmt_pack)
end

#pretty_print(q) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ctypes/string.rb', line 111

def pretty_print(q)
  if size && size > 0
    if trim
      q.text("string(%d)" % @size)
    else
      q.text("string(%d, trim: false)" % @size)
    end
  else
    q.text "string"
  end
end

#sizeObject

get the size in bytes of the string; returns 0 for greedy strings



103
104
105
# File 'lib/ctypes/string.rb', line 103

def size
  @size || 0
end

#terminated(terminator = "\0") ⇒ Object

This function is provided as a helper to Helpers#string to enable string.terminated as a type.

See Also:



146
147
148
# File 'lib/ctypes/string.rb', line 146

def terminated(terminator = "\0")
  String.terminated(terminator)
end

#to_sObject



107
108
109
# File 'lib/ctypes/string.rb', line 107

def to_s
  "string[#{size}]"
end

#type_nameObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



138
139
140
# File 'lib/ctypes/string.rb', line 138

def type_name
  @size ? "char[#{@size}]" : "char[]"
end

#unpack_one(buf, endian: default_endian) ⇒ ::Array(::String, ::String)

unpack a ruby String from binary string data



90
91
92
93
94
95
# File 'lib/ctypes/string.rb', line 90

def unpack_one(buf, endian: default_endian)
  raise missing_bytes_error(input: buf, need: @size) if
    @size && buf.size < @size
  value = buf.unpack1(@fmt_unpack)
  [value, @size ? buf.byteslice(@size..) : ""]
end