1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
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 #=> "abcde"
#
# obj = BinData::String.new(length: 6)
# obj.read(data)
# obj #=> "abcdef"
# obj.assign("abcdefghij")
# obj #=> "abcdef"
# obj.assign("abcd")
# obj #=> "abcd\000\000"
#
# obj = BinData::String.new(length: 6, trim_padding: true)
# obj.assign("abcd")
# obj #=> "abcd"
# obj.to_binary_s #=> "abcd\000\000"
#
# obj = BinData::String.new(length: 6, pad_byte: 'A')
# obj.assign("abcd")
# obj #=> "abcdAA"
# obj.to_binary_s #=> "abcdAA"
#
# == Parameters
#
# String objects accept all the params that BinData::BasePrimitive
# does, as well as the following:
#
# <tt>:read_length</tt>:: The length in bytes to use when reading a value.
# <tt>:length</tt>:: The fixed length of the string. If a shorter
# string is set, it will be padded to this length.
# <tt>:pad_byte</tt>:: The byte to use when padding a string to a
# set length. Valid values are Integers and
# Strings of length 1. "\0" is the default.
# <tt>:pad_front</tt>:: Signifies that the padding occurs at the front
# of the string rather than the end. Default
# is false.
# <tt>:trim_padding</tt>:: Boolean, default false. If set, #value will
# return the value with all pad_bytes trimmed
# from the end of the string. The value will
# not be trimmed when writing.
class String < BinData::BasePrimitive
arg_processor :string
optional_parameters :read_length, :length, :trim_padding, :pad_front, :pad_left
default_parameters pad_byte: "\0"
mutually_exclusive_parameters :read_length, :length
mutually_exclusive_parameters :length, :value
def initialize_shared_instance
if (has_parameter?(:value) || has_parameter?(:asserted_value)) &&
!has_parameter?(:read_length)
extend WarnNoReadLengthPlugin
end
super
end
def assign(val)
super(binary_string(val))
end
def snapshot
# override to trim padding
snap = super
snap = clamp_to_length(snap)
if get_parameter(:trim_padding)
trim_padding(snap)
else
snap
end
end
#---------------
private
def clamp_to_length(str)
str = binary_string(str)
len = eval_parameter(:length) || str.length
if str.length == len
str
elsif str.length > len
str.slice(0, len)
else
padding = (eval_parameter(:pad_byte) * (len - str.length))
if get_parameter(:pad_front)
padding + str
else
str + padding
end
end
end
def trim_padding(str)
if get_parameter(:pad_front)
str.sub(/\A#{eval_parameter(:pad_byte)}*/, "")
else
str.sub(/#{eval_parameter(:pad_byte)}*\z/, "")
end
end
def value_to_binary_string(val)
clamp_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
class StringArgProcessor < BaseArgProcessor
def sanitize_parameters!(obj_class, params)
params.warn_replacement_parameter(:initial_length, :read_length)
params.must_be_integer(:read_length, :length)
params.rename_parameter(:pad_left, :pad_front)
params.sanitize(:pad_byte) { |byte| sanitized_pad_byte(byte) }
end
#-------------
private
def sanitized_pad_byte(byte)
pad_byte = byte.is_a?(Integer) ? byte.chr : byte.to_s
if pad_byte.bytesize > 1
raise ArgumentError, ":pad_byte must not contain more than 1 byte"
end
pad_byte
end
end
# Warns when reading if :value && no :read_length
module WarnNoReadLengthPlugin
def read_and_return_value(io)
warn "#{debug_name} does not have a :read_length parameter - returning empty string"
""
end
end
end
|