Class: Fields::Field
Overview
Subclasses of Fields::Field should probably at least overload input_to_bitstring
and get_value
and set @length_type
. Check the source code for the base subclasses for ideas. Remember that for the purposes of fuzzing you can probably get away with inheriting from one of the base classes a lot of the time - an EmailField can probably just inherit StringField unless you want stringent checking in your parser.
Direct Known Subclasses
BitstringField, HexstringField, OctetstringField, SignedField, StringField, UnsignedField
Instance Attribute Summary collapse
-
#bitstring ⇒ Object
readonly
Returns the value of attribute bitstring.
-
#default_value ⇒ Object
readonly
Returns the value of attribute default_value.
-
#desc ⇒ Object
readonly
Returns the value of attribute desc.
-
#endianness ⇒ Object
readonly
Returns the value of attribute endianness.
-
#length ⇒ Object
readonly
Returns the value of attribute length.
-
#length_type ⇒ Object
readonly
Returns the value of attribute length_type.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
Instance Method Summary collapse
-
#get_value ⇒ Object
Subclasses should override this.
-
#initialize(bitstring, name, length, desc, default, endian) ⇒ Field
constructor
A new instance of Field.
-
#input_to_bitstring(value) ⇒ Object
Placeholder, classes should override as neccessary.
-
#parse_buffer(bitstring) ⇒ Object
Placeholder, subclasses should probably redefine for clarity.
-
#parse_buffer_lazy(bitstring) ⇒ Object
Provided for classes that don’t care about length matching when assigning the contents.
-
#parse_buffer_strict(bitstring) ⇒ Object
Provided for classes that require strict lengths.
-
#randomize! ⇒ Object
Randomize the bitstring for this field, bit by bit.
-
#set_raw(bitstring) ⇒ Object
Sets the raw field contents.
-
#set_value(new_val) ⇒ Object
Set the field value.
-
#to_s ⇒ Object
This really only makes sense for fields that are byte aligned, but what the hey.
Constructor Details
#initialize(bitstring, name, length, desc, default, endian) ⇒ Field
Returns a new instance of Field.
26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/fields.rb', line 26 def initialize(bitstring, name, length, desc, default, endian) @name=name @length=length @desc=desc default&&=self.input_to_bitstring(default) @default_value=default # can still be nil @bitstring=self.parse_buffer(bitstring) @type=self.class.to_s[/\w+(?=Field)/].downcase #fricking ugly @endianness=endian unless @endianness.downcase==:big or @endianness.downcase==:little raise ArgumentError, "#{self.class.to_s[/\w+$/]} (#{@name}): Unknown endianness #{endianness}, use :little or :big (default)." end end |
Instance Attribute Details
#bitstring ⇒ Object (readonly)
Returns the value of attribute bitstring.
24 25 26 |
# File 'lib/fields.rb', line 24 def bitstring @bitstring end |
#default_value ⇒ Object (readonly)
Returns the value of attribute default_value.
24 25 26 |
# File 'lib/fields.rb', line 24 def default_value @default_value end |
#desc ⇒ Object (readonly)
Returns the value of attribute desc.
24 25 26 |
# File 'lib/fields.rb', line 24 def desc @desc end |
#endianness ⇒ Object (readonly)
Returns the value of attribute endianness.
24 25 26 |
# File 'lib/fields.rb', line 24 def endianness @endianness end |
#length ⇒ Object (readonly)
Returns the value of attribute length.
24 25 26 |
# File 'lib/fields.rb', line 24 def length @length end |
#length_type ⇒ Object (readonly)
Returns the value of attribute length_type.
24 25 26 |
# File 'lib/fields.rb', line 24 def length_type @length_type end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
24 25 26 |
# File 'lib/fields.rb', line 24 def name @name end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
24 25 26 |
# File 'lib/fields.rb', line 24 def type @type end |
Instance Method Details
#get_value ⇒ Object
Subclasses should override this. This default returns the raw bitstring.
106 107 108 |
# File 'lib/fields.rb', line 106 def get_value @bitstring end |
#input_to_bitstring(value) ⇒ Object
Placeholder, classes should override as neccessary. Parse a value in whatever format is determined by the class and return a bitstring. This default does zero checking, so expects a bitstring as input
85 86 87 |
# File 'lib/fields.rb', line 85 def input_to_bitstring( value ) value end |
#parse_buffer(bitstring) ⇒ Object
Placeholder, subclasses should probably redefine for clarity. Defaults to calling parse_buffer_strict, but uses parse_buffer_lazy for variable length fields.
70 71 72 73 |
# File 'lib/fields.rb', line 70 def parse_buffer( bitstring ) return self.parse_buffer_lazy( bitstring ) if self.length_type=="variable" self.parse_buffer_strict( bitstring ) # default to this for subclasses that forget to define @length_type end |
#parse_buffer_lazy(bitstring) ⇒ Object
Provided for classes that don’t care about length matching when assigning the contents. Called by parse_buffer
internally.
59 60 61 62 63 64 65 66 |
# File 'lib/fields.rb', line 59 def parse_buffer_lazy( bitstring ) return "" unless bitstring bitstring||="" unless bitstring.is_a? String and bitstring=~/^[10]*$/ raise ArgumentError, "#{self.class.to_s[/\w+$/]} (#{@name}): <Internal> bitstring buffer borked??" end bitstring end |
#parse_buffer_strict(bitstring) ⇒ Object
Provided for classes that require strict lengths. Left pads with 0 to @length if the input buffer is incomplete. Truncates at @length if too long. Called by parse_buffer
internally.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/fields.rb', line 42 def parse_buffer_strict( bitstring ) return "" unless bitstring bitstring||="" unless bitstring.is_a? String and bitstring=~/^[10]*$/ raise ArgumentError, "Field: <Internal> bitstring buffer borked?? #{bitstring.inspect}" end if bitstring.length <= @length "0"*(@length-bitstring.length)+bitstring elsif bitstring.length > @length bitstring.slice(0,@length) else raise RuntimeError, "Universe Broken Error: value neither less/equal nor greater" end end |
#randomize! ⇒ Object
Randomize the bitstring for this field, bit by bit
90 91 92 93 94 95 96 97 98 |
# File 'lib/fields.rb', line 90 def randomize! random_bitstring=Array.new(self.length).map {|e| e=rand(2).to_s}.join if self.length_type=="variable" slice=random_bitstring[0,(rand((self.length/8)+1)*8)] set_raw(slice) else set_raw(random_bitstring) end end |
#set_raw(bitstring) ⇒ Object
Sets the raw field contents. Can be useful if the set_value method does inconvenient checking when you want to set crazy values.
77 78 79 |
# File 'lib/fields.rb', line 77 def set_raw( bitstring ) @bitstring=self.parse_buffer( bitstring ) end |
#set_value(new_val) ⇒ Object
Set the field value. Calls self.input_to_bitstring which is expected to return a binary string.
101 102 103 |
# File 'lib/fields.rb', line 101 def set_value(new_val) @bitstring=self.input_to_bitstring(new_val) end |
#to_s ⇒ Object
This really only makes sense for fields that are byte aligned, but what the hey. For the rest it effectively packs them as left padded with zeroes to a byte boundary (so a 3 bit field “110” will pack as 006)
112 113 114 |
# File 'lib/fields.rb', line 112 def to_s @bitstring.reverse.scan(/.{1,8}/).map {|s| s.reverse}.reverse.map {|bin| "" << bin.to_i(2)}.join end |