Class: Ruckus::Number
Overview
A Ruckus::Number is a type of Parsel that wraps an Integer.
Direct Known Subclasses
Be16, Be32, Be64, Bit, Byte, Decimal, Enum, Le16, Le32, Le64, Len, Nibble, TimeT
Constant Summary collapse
- BASERX =
{ 2 => /([01]+)/, 8 => /([0-7]+)/, 10 => /([0-9]+)/, 16 => /([0-9a-fA-F]+)/ }
Constants inherited from Parsel
Instance Attribute Summary collapse
-
#ascii ⇒ Object
Returns the value of attribute ascii.
-
#endian ⇒ Object
Returns the value of attribute endian.
-
#pad ⇒ Object
Returns the value of attribute pad.
-
#radix ⇒ Object
Returns the value of attribute radix.
-
#value ⇒ Object
Returns the value of attribute value.
-
#width ⇒ Object
Returns the value of attribute width.
Attributes inherited from Parsel
#name, #parent, #rendered_offset, #rendering, #tag
Instance Method Summary collapse
- #ascii_capture(str) ⇒ Object
- #ascii_to_s ⇒ Object
-
#capture(str) ⇒ Object
Given: a string, return: the remainder of the string after parsing the number, side-effect: populate @value.
-
#initialize(opts = {}) ⇒ Number
constructor
- Options: width
- (Default: 32) Width in bits — can be odd! endian
- (Default: :little) Endianness — not honored for odd widths value
-
Usually a fixnum, but can be a method to call on sibling Parsel, e.g.
-
#odd_width? ⇒ Boolean
Is this an odd-width (single bit, nibble, etc) number?.
-
#odd_width_capture(str) ⇒ Object
Capture a whole span of odd-width numbers, see capture.
-
#odd_width_first? ⇒ Boolean
Are we the first odd-width number in the span?.
-
#odd_width_to_s ⇒ Object
Render a span of odd-width numbers as a byte string.
-
#resolve(x) ⇒ Object
Quick hack: true is 1, false is 0, nil is 0.
-
#size ⇒ Object
How big is the encoded number?.
-
#span_bits ⇒ Object
For odd-width fields — find how big the span of neighboring odd-width fields is, in bits.
-
#span_offset ⇒ Object
Where are we in the span of neighboring odd-width fields?.
-
#to_s(off = nil) ⇒ Object
Render this number (or, if odd-width, this span of odd-width values, if we’re the first element of the span) as a bit string.
Methods inherited from Parsel
bytes_for_bits, coerce, #each_matching_selector, endian?, factory?, #find_containing, #find_tag, #find_tag_struct, #fixup, #in, #incomplete!, #index_for_selectors, #inspect, #matches_selector?, #method_missing, #native?, native?, #next, #out, #parent_structure, #permute, #prev, #respond_to?, #root, #visit, #where_am_i?
Constructor Details
#initialize(opts = {}) ⇒ Number
Options:
- width
-
(Default: 32) Width in bits — can be odd!
- endian
-
(Default: :little) Endianness — not honored for odd widths
- value
-
Usually a fixnum, but can be a method to call on sibling Parsel, e.g. :size for “Length” fields.
Note: odd-width fields must be parented (see Blob or Structure) to render or capture their values
20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/ruckus/number.rb', line 20 def initialize(opts={}) opts[:width] ||= 32 opts[:endian] ||= :little # opts[:value] ||= 0xABADCAFE opts[:value] ||= 0 opts[:radix] ||= 0 if opts[:endian] == :native opts[:endian] = Parsel.endian? end super(opts) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Ruckus::Parsel
Instance Attribute Details
#ascii ⇒ Object
Returns the value of attribute ascii.
6 7 8 |
# File 'lib/ruckus/number.rb', line 6 def ascii @ascii end |
#endian ⇒ Object
Returns the value of attribute endian.
6 7 8 |
# File 'lib/ruckus/number.rb', line 6 def endian @endian end |
#pad ⇒ Object
Returns the value of attribute pad.
6 7 8 |
# File 'lib/ruckus/number.rb', line 6 def pad @pad end |
#radix ⇒ Object
Returns the value of attribute radix.
6 7 8 |
# File 'lib/ruckus/number.rb', line 6 def radix @radix end |
#value ⇒ Object
Returns the value of attribute value.
7 8 9 |
# File 'lib/ruckus/number.rb', line 7 def value @value end |
#width ⇒ Object
Returns the value of attribute width.
6 7 8 |
# File 'lib/ruckus/number.rb', line 6 def width @width end |
Instance Method Details
#ascii_capture(str) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/ruckus/number.rb', line 117 def ascii_capture(str) incomplete! if str.empty? # weak if (rad = resolve(@radix)) == 0 if str.starts_with? "0x" rad = 16 str.shift 2 else rad = 10 end end if(str =~ BASERX[rad]) @value = $1.to_i(rad) str.shift($1.size) else @value = 0 end return str end |
#ascii_to_s ⇒ Object
177 178 179 180 181 182 183 184 |
# File 'lib/ruckus/number.rb', line 177 def ascii_to_s if((rad = resolve(@radix)) == 0) rad = 10 end pad = resolve(@pad) || 0 @value.to_s(rad).rjust(pad, "0") end |
#capture(str) ⇒ Object
Given: a string, return: the remainder of the string after parsing the number, side-effect: populate @value
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/ruckus/number.rb', line 99 def capture(str) return ascii_capture(str) if @ascii return odd_width_capture(str) if not (code = widthcode) incomplete! if str.size < size cap = str.shift(size) cap = cap.reverse if not Parsel.native?(@endian) @value = cap.unpack(code).first return str end |
#odd_width? ⇒ Boolean
Is this an odd-width (single bit, nibble, etc) number?
52 |
# File 'lib/ruckus/number.rb', line 52 def odd_width? ; not widthcode ; end |
#odd_width_capture(str) ⇒ Object
Capture a whole span of odd-width numbers, see capture
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/ruckus/number.rb', line 233 def odd_width_capture(str) return str if not odd_width_first? incomplete! if str.size < (bytes_for_bits = Parsel.bytes_for_bits(span_bits)) cap = str.shift(bytes_for_bits) acc = 0 cap.each_byte do |b| acc <<= 8 acc |= b end tbits = cap.size * 8 tot = 0 where_am_i?.upto(parent.count - 1) do |i| break if not parent[i].respond_to? :odd_width? break if not parent[i].odd_width? tot += parent[i].width parent[i].value = (acc >> (tbits - tot)) & Numeric.mask_for(parent[i].width) end return str end |
#odd_width_first? ⇒ Boolean
Are we the first odd-width number in the span?
222 223 224 225 226 227 228 229 |
# File 'lib/ruckus/number.rb', line 222 def odd_width_first? return true if odd_width? and where_am_i? == 0 begin not parent[where_am_i? - 1].odd_width? rescue true end end |
#odd_width_to_s ⇒ Object
Render a span of odd-width numbers as a byte string
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/ruckus/number.rb', line 188 def odd_width_to_s return "" if not odd_width_first? acc = 0 tot = 0 bits = span_bits # Cheat horribly: Ruby has bignums, so just treat the whole # span as one giant bignum and math it into place. where_am_i?.upto(parent.count - 1) do |i| break if not parent[i].respond_to? :odd_width? break if not parent[i].odd_width? acc <<= parent[i].width tot += parent[i].width acc |= parent[i].resolve(parent[i].value) & Numeric.mask_for(parent[i].width) end acc <<= 8 - (tot % 8) if (tot % 8) != 0 # Dump the bignum to a binary string ret = "" while bits > 0 ret << (acc & 0xff).chr acc >>= 8 bits -= 8 end ret.reverse! if @endian == :big return ret end |
#resolve(x) ⇒ Object
Quick hack: true is 1, false is 0, nil is 0.
142 143 144 145 146 147 148 |
# File 'lib/ruckus/number.rb', line 142 def resolve(x) r = super r = 1 if r == true r = 0 if r == false r = 0 if r == nil return r end |
#size ⇒ Object
How big is the encoded number?
259 260 261 262 263 264 265 266 267 268 |
# File 'lib/ruckus/number.rb', line 259 def size if not odd_width? s = Parsel.bytes_for_bits(@width); elsif odd_width_first? s = span_bits * 8 else s = 0 end s end |
#span_bits ⇒ Object
For odd-width fields — find how big the span of neighboring odd-width fields is, in bits.
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/ruckus/number.rb', line 75 def span_bits last = where_am_i? span_start.upto(parent.count - 1) do |i| break if not parent[i].respond_to? :odd_width? break if not parent[i].odd_width? last = i end tot = 0 span_start.upto(last) { |i| tot += parent[i].width } tot end |
#span_offset ⇒ Object
Where are we in the span of neighboring odd-width fields?
90 91 92 93 94 |
# File 'lib/ruckus/number.rb', line 90 def span_offset tot = 0 span_start.upto(where_am_i? - 1) {|i| tot += parent[i].width} tot end |
#to_s(off = nil) ⇒ Object
Render this number (or, if odd-width, this span of odd-width values, if we’re the first element of the span) as a bit string.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/ruckus/number.rb', line 153 def to_s(off=nil) @rendered_offset = off || 0 begin if @ascii r = ascii_to_s elsif not (code = widthcode) r = odd_width_to_s else val = resolve(@value).to_i r = [val].pack(code) r = r.reverse if @endian != Parsel.endian? end if off return r, off+r.size else return r end rescue raise end end |