require "bindata/base_primitive" module BinData # A String is a sequence of bytes. This is the same as strings in Ruby 1.8. # The issue of character encoding is ignored by this class. # # require 'bindata' # # data = "abcdefghij" # # obj = BinData::String.new(:read_length => 5) # obj.read(data) # obj.value #=> "abcde" # # obj = BinData::String.new(:length => 6) # obj.read(data) # obj.value #=> "abcdef" # obj.value = "abcdefghij" # obj.value #=> "abcdef" # obj.value = "abcd" # obj.value #=> "abcd\000\000" # # obj = BinData::String.new(:length => 6, :trim_value => true) # obj.value = "abcd" # obj.value #=> "abcd" # obj.to_binary_s #=> "abcd\000\000" # # obj = BinData::String.new(:length => 6, :pad_char => 'A') # obj.value = "abcd" # obj.value #=> "abcdAA" # obj.to_binary_s #=> "abcdAA" # # == Parameters # # String objects accept all the params that BinData::BasePrimitive # does, as well as the following: # # :read_length:: The length to use when reading a value. # :length:: The fixed length of the string. If a shorter # string is set, it will be padded to this length. # :pad_char:: The character to use when padding a string to a # set length. Valid values are Integers and # Strings of length 1. "\0" is the default. # :trim_padding:: Boolean, default false. If set, #value will # return the value with all pad_chars trimmed # from the end of the string. The value will # not be trimmed when writing. class String < BinData::BasePrimitive register(self.name, self) optional_parameters :read_length, :length, :trim_padding default_parameters :pad_char => "\0" mutually_exclusive_parameters :read_length, :length mutually_exclusive_parameters :length, :value class << self def sanitize_parameters!(params, sanitizer) #:nodoc: warn_replacement_parameter(params, :initial_length, :read_length) if params.has_parameter?(:pad_char) ch = params[:pad_char] params[:pad_char] = sanitized_pad_char(ch) end end #------------- private def sanitized_pad_char(ch) result = ch.is_a?(Integer) ? ch.chr : ch.to_s if result.length > 1 raise ArgumentError, ":pad_char must not contain more than 1 char" end result end end #--------------- private def _assign(val) val = val.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9" super(val) end def _snapshot # override to ensure length and optionally trim padding result = super if has_parameter?(:length) result = truncate_or_pad_to_length(result) end if get_parameter(:trim_padding) == true result = trim_padding(result) end result end def truncate_or_pad_to_length(str) len = eval_parameter(:length) || str.length if str.length == len str elsif str.length > len str.slice(0, len) else str + (eval_parameter(:pad_char) * (len - str.length)) end end def trim_padding(str) str.sub(/#{eval_parameter(:pad_char)}*$/, "") end def value_to_binary_string(val) truncate_or_pad_to_length(val) end def read_and_return_value(io) len = eval_parameter(:read_length) || eval_parameter(:length) || 0 io.readbytes(len) end def sensible_default "" end end end