require "bindata/single"
module BinData
# A BinData::Stringz object is a container for a zero ("\0") terminated
# string.
#
# For convenience, the zero terminator is not necessary when setting the
# value. Likewise, the returned value will not be zero terminated.
#
# require 'bindata'
#
# data = "abcd\x00efgh"
#
# obj = BinData::Stringz.new
# obj.read(data)
# obj.snapshot #=> "abcd"
# obj.value #=> "abcd"
# obj.num_bytes #=> 5
# obj.to_s #=> "abcd\000"
#
# == Parameters
#
# Stringz objects accept all the params that BinData::Single
# does, as well as the following:
#
# :max_length:: The maximum length of the string including the zero
# byte.
class Stringz < BinData::Single
# Register this class
register(self.name, self)
# These are the parameters used by this class.
optional_parameters :max_length
# Overrides value to return the value of this data excluding the trailing
# zero byte.
def value
v = super
val_to_str(v).chomp("\0")
end
#---------------
private
# Returns +val+ ensuring it is zero terminated and no longer
# than :max_length bytes.
def val_to_str(val)
zero_terminate(val, eval_param(:max_length))
end
# Read a number of bytes from +io+ and return the value they represent.
def read_val(io)
max_length = eval_param(:max_length)
str = ""
i = 0
ch = nil
# read until zero byte or we have read in the max number of bytes
while ch != "\0" and i != max_length
ch = io.readbytes(1)
str << ch
i += 1
end
zero_terminate(str, max_length)
end
# Returns an empty string as default.
def sensible_default
""
end
# Returns +str+ after it has been zero terminated. The returned string
# will not be longer than +max_length+.
def zero_terminate(str, max_length = nil)
# str must not be empty
result = (str == "") ? "\0" : str
# remove anything after the first \0
result = result.sub(/([^\0]*\0).*/, '\1')
# trim string to be no longer than max_length including zero byte
if max_length
max_length = 1 if max_length < 1
result = result[0, max_length]
if result.length == max_length and result[-1, 1] != "\0"
result[-1, 1] = "\0"
end
end
# ensure last byte in the string is a zero byte
result << "\0" if result[-1, 1] != "\0"
result
end
end
end