metasploit-framework/lib/bindata/string.rb

115 lines
3.7 KiB
Ruby

require "bindata/single"
module BinData
# A String is a sequence of bytes. This is the same as strings in Ruby.
# 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_s #=> "abcd\000\000"
#
# obj = BinData::String.new(:length => 6, :pad_char => 'A')
# obj.value = "abcd"
# obj.value #=> "abcdAA"
# obj.to_s #=> "abcdAA"
#
# == Parameters
#
# String objects accept all the params that BinData::Single
# does, as well as the following:
#
# <tt>:read_length</tt>:: The length 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_char</tt>:: 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.
# <tt>:trim_value</tt>:: 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::Single
# Register this class
register(self.name, self)
# These are the parameters used by this class.
optional_parameters :read_length, :length, :trim_value
default_parameters :pad_char => "\0"
mutually_exclusive_parameters :read_length, :length
mutually_exclusive_parameters :length, :value
class << self
# Ensures that +params+ is of the form expected by #initialize.
def sanitize_parameters!(sanitizer, params)
# warn about deprecated param - remove before releasing 1.0
if params[:initial_length]
warn ":initial_length is deprecated. Replacing with :read_length"
params[:read_length] = params.delete(:initial_length)
end
# set :pad_char to be a single length character string
if params.has_key?(:pad_char)
ch = params[:pad_char]
ch = ch.respond_to?(:chr) ? ch.chr : ch.to_s
if ch.length > 1
raise ArgumentError, ":pad_char must not contain more than 1 char"
end
params[:pad_char] = ch
end
super(sanitizer, params)
end
end
# Overrides value to return the value padded to the desired length or
# trimmed as required.
def value
v = val_to_str(_value)
v.sub!(/#{eval_param(:pad_char)}*$/, "") if param(:trim_value) == true
v
end
#---------------
private
# Returns +val+ ensuring that it is padded to the desired length.
def val_to_str(val)
# trim val if necessary
len = eval_param(:length) || val.length
str = val.slice(0, len)
# then pad to length if str is short
str << (eval_param(:pad_char) * (len - str.length))
end
# Read a number of bytes from +io+ and return the value they represent.
def read_val(io)
len = eval_param(:read_length) || eval_param(:length) || 0
io.readbytes(len)
end
# Returns an empty string as default.
def sensible_default
""
end
end
end