Class: Binstream::Streams::Base
- Inherits:
-
Object
- Object
- Binstream::Streams::Base
- Extended by:
- Forwardable
- Includes:
- Tracking
- Defined in:
- lib/binstream/streams/base.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#stopper ⇒ Object
readonly
Returns the value of attribute stopper.
Instance Method Summary collapse
-
#dump(filename) ⇒ Object
Dump entire stream to a file (for debugging).
- #eof? ⇒ Boolean
-
#initialize(stream, startpos: nil, whence: IO::SEEK_SET, read_length: nil, **kwargs) ⇒ Base
constructor
A new instance of Base.
-
#method_missing(meth_name, *args, &block) ⇒ Object
MISC.
-
#peek(length = nil) ⇒ Object
Returns data without advancing the offset pointer.
-
#peek_slice(new_length, offset_adjustment = nil) ⇒ Object
Get a new stream at the current position, but don’t advance our internal pointer.
- #read(length = nil) ⇒ Object
- #read_binary(len) ⇒ Object
-
#read_bool ⇒ Object
(also: #read_bool8)
8 bit boolean.
- #read_byte ⇒ Object
-
#read_double ⇒ Object
(also: #read_doublele)
8 byte double.
- #read_doublebe ⇒ Object
-
#read_float ⇒ Object
(also: #read_floatle)
4 byte floats.
- #read_floatbe ⇒ Object
- #read_hash(len) ⇒ Object
- #read_int16 ⇒ Object (also: #read_int16le)
- #read_int16be ⇒ Object
-
#read_int32 ⇒ Object
(also: #read_int32le)
32 bits.
- #read_int32be ⇒ Object
-
#read_int64 ⇒ Object
(also: #read_int64le)
64 bits.
- #read_int64be ⇒ Object
-
#read_int8 ⇒ Object
8 Bits.
- #read_single(fmt, bytes = 4) ⇒ Object
-
#read_string(length, encoding: "UTF-8", packfmt: "Z*") ⇒ Object
Reads a null terminated string off the stream.
-
#read_uint16 ⇒ Object
(also: #read_uint16le)
16 Bits.
- #read_uint16be ⇒ Object
- #read_uint32 ⇒ Object (also: #read_uint32le)
- #read_uint32be ⇒ Object
- #read_uint64 ⇒ Object (also: #read_uint64le)
- #read_uint64be ⇒ Object
- #read_uint8 ⇒ Object
- #read_unpack(bytes, fmt) ⇒ Object
-
#remaining ⇒ Object
How many remaining bytes are there.
-
#remaining?(len_to_check = 1) ⇒ Boolean
Do we have any remaining bytes?.
- #reset ⇒ Object
-
#rewind ⇒ Object
Reset the position pointer back to the start.
-
#seek(seek_len, whence = IO::SEEK_CUR) ⇒ Object
Seek to a specific position, or relative.
- #setup_stopper(startpos, whence, max_length) ⇒ Object
-
#slice(new_length, new_offset = nil) ⇒ Object
Create a new stream based off this one using an offset and length.
-
#slice!(new_length, new_offset) ⇒ Object
slice!(length, offset) Get new stream using absolute position.
- #starting_offset ⇒ Object
-
#stell ⇒ Object
Position on the underlying stream.
-
#tell ⇒ Object
(also: #pos)
Position in our current high level stream.
- #total_size ⇒ Object (also: #size)
-
#valid_position?(proposal) ⇒ Boolean
Is this actually a valid position?.
Methods included from Tracking
included, #track, #track_pos, #without_tracking
Constructor Details
#initialize(stream, startpos: nil, whence: IO::SEEK_SET, read_length: nil, **kwargs) ⇒ Base
Returns a new instance of Base.
11 12 13 14 15 |
# File 'lib/binstream/streams/base.rb', line 11 def initialize(stream, startpos: nil, whence: IO::SEEK_SET, read_length: nil, **kwargs) @stream = stream reset setup_stopper(startpos, whence, read_length) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth_name, *args, &block) ⇒ Object
MISC
323 324 325 326 327 328 329 330 |
# File 'lib/binstream/streams/base.rb', line 323 def method_missing(meth_name, *args, &block) meth = "read_#{meth_name}".to_sym if respond_to?(meth) public_send(meth, *args, &block) else super end end |
Instance Attribute Details
#stopper ⇒ Object (readonly)
Returns the value of attribute stopper.
9 10 11 |
# File 'lib/binstream/streams/base.rb', line 9 def stopper @stopper end |
Instance Method Details
#dump(filename) ⇒ Object
Dump entire stream to a file (for debugging)
313 314 315 316 317 318 319 |
# File 'lib/binstream/streams/base.rb', line 313 def dump(filename) # return nil unless $TESTING @stream.seek(@startpos, IO::SEEK_SET) File.open(filename, "wb") do |f| f.write(@stream.read(@stopper - @startpos)) end end |
#eof? ⇒ Boolean
154 155 156 |
# File 'lib/binstream/streams/base.rb', line 154 def eof? remaining <= 0 end |
#peek(length = nil) ⇒ Object
Returns data without advancing the offset pointer
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/binstream/streams/base.rb', line 108 def peek(length=nil) original_pos = stell read_size = (length || size) if remaining - read_size < 0 raise StreamOverrunError.new(read_size, remaining, original_pos) end @stream.seek(@startpos + @cur_offset, IO::SEEK_SET) resp = @stream.read(length) return resp rescue => e raise ensure @stream.seek(original_pos, IO::SEEK_SET) end |
#peek_slice(new_length, offset_adjustment = nil) ⇒ Object
Get a new stream at the current position, but don’t advance our internal pointer
61 62 63 64 65 66 67 68 |
# File 'lib/binstream/streams/base.rb', line 61 def peek_slice(new_length, offset_adjustment=nil) offset_adjustment ||= 0 self.class.new(@stream, startpos: (@startpos + @cur_offset + offset_adjustment), read_length: new_length ) end |
#read(length = nil) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/binstream/streams/base.rb', line 85 def read(length=nil) original_pos = stell read_size = (length || size) if remaining - read_size < 0 raise StreamOverrunError.new(read_size, remaining, original_pos) end @stream.seek(@startpos + @cur_offset, IO::SEEK_SET) resp = @stream.read(length) @cur_offset += read_size return resp rescue => e raise ensure # put the stream back # TODO: possibly remove this, it just makes it slower @stream.seek(original_pos, IO::SEEK_SET) end |
#read_binary(len) ⇒ Object
295 296 297 298 |
# File 'lib/binstream/streams/base.rb', line 295 def read_binary(len) track { sprintf("READ_BINARY(%d+%d = %d)", tell, len, (tell+len)) } read(len) end |
#read_bool ⇒ Object Also known as: read_bool8
8 bit boolean
185 186 187 188 189 190 191 192 193 |
# File 'lib/binstream/streams/base.rb', line 185 def read_bool res = read_single("C", 1) if res != 0 && res != 1 raise InvalidBooleanValueError.new(res, (tell - 1)) end track(res != 0) end |
#read_byte ⇒ Object
203 204 205 |
# File 'lib/binstream/streams/base.rb', line 203 def read_byte track read_single("c", 1) end |
#read_double ⇒ Object Also known as: read_doublele
8 byte double
278 279 280 281 282 283 284 |
# File 'lib/binstream/streams/base.rb', line 278 def read_double res = read_single("E", 8) if res.nan? raise InvalidFloatValueError.new(tell - 8) end track res end |
#read_doublebe ⇒ Object
285 286 287 288 289 290 291 |
# File 'lib/binstream/streams/base.rb', line 285 def read_doublebe res = read_single("G", 8) if res.nan? raise InvalidFloatValueError.new(tell - 8) end track res end |
#read_float ⇒ Object Also known as: read_floatle
4 byte floats
260 261 262 263 264 265 266 |
# File 'lib/binstream/streams/base.rb', line 260 def read_float res = read_single("e", 4) if res.nan? raise InvalidFloatValueError.new(tell - 4) end track res end |
#read_floatbe ⇒ Object
267 268 269 270 271 272 273 |
# File 'lib/binstream/streams/base.rb', line 267 def read_floatbe res = read_single("g", 4) if res.nan? raise InvalidFloatValueError.new(tell - 4) end track res end |
#read_hash(len) ⇒ Object
300 301 302 |
# File 'lib/binstream/streams/base.rb', line 300 def read_hash(len) track read_single("H*", len) end |
#read_int16 ⇒ Object Also known as: read_int16le
216 217 218 |
# File 'lib/binstream/streams/base.rb', line 216 def read_int16 track read_single("s<", 2) end |
#read_int16be ⇒ Object
219 220 221 |
# File 'lib/binstream/streams/base.rb', line 219 def read_int16be track read_single("s>", 2) end |
#read_int32 ⇒ Object Also known as: read_int32le
32 bits
225 226 227 |
# File 'lib/binstream/streams/base.rb', line 225 def read_int32 track read_single("l<", 4) end |
#read_int32be ⇒ Object
228 229 230 |
# File 'lib/binstream/streams/base.rb', line 228 def read_int32be track read_single("l>", 4) end |
#read_int64 ⇒ Object Also known as: read_int64le
64 bits
243 244 245 |
# File 'lib/binstream/streams/base.rb', line 243 def read_int64 track read_single("q<", 8) end |
#read_int64be ⇒ Object
246 247 248 |
# File 'lib/binstream/streams/base.rb', line 246 def read_int64be track read_single("q>", 8) end |
#read_int8 ⇒ Object
8 Bits
197 198 199 |
# File 'lib/binstream/streams/base.rb', line 197 def read_int8 track read_single("c", 1) end |
#read_single(fmt, bytes = 4) ⇒ Object
304 305 306 |
# File 'lib/binstream/streams/base.rb', line 304 def read_single(fmt, bytes = 4) read(bytes).unpack1(fmt) end |
#read_string(length, encoding: "UTF-8", packfmt: "Z*") ⇒ Object
Reads a null terminated string off the stream
175 176 177 178 179 180 181 182 |
# File 'lib/binstream/streams/base.rb', line 175 def read_string(length, encoding: "UTF-8", packfmt: "Z*") if length > 0 res = read_single(packfmt, length).force_encoding(encoding).encode(encoding) track res else raise InvalidLengthError.new(length) end end |
#read_uint16 ⇒ Object Also known as: read_uint16le
16 Bits
208 209 210 |
# File 'lib/binstream/streams/base.rb', line 208 def read_uint16 track read_single("S<", 2) end |
#read_uint16be ⇒ Object
211 212 213 |
# File 'lib/binstream/streams/base.rb', line 211 def read_uint16be track read_single("S>", 2) end |
#read_uint32 ⇒ Object Also known as: read_uint32le
233 234 235 |
# File 'lib/binstream/streams/base.rb', line 233 def read_uint32 track read_single("L<", 4) end |
#read_uint32be ⇒ Object
236 237 238 |
# File 'lib/binstream/streams/base.rb', line 236 def read_uint32be track read_single("L>", 4) end |
#read_uint64 ⇒ Object Also known as: read_uint64le
251 252 253 |
# File 'lib/binstream/streams/base.rb', line 251 def read_uint64 track read_single("Q<", 8) end |
#read_uint64be ⇒ Object
254 255 256 |
# File 'lib/binstream/streams/base.rb', line 254 def read_uint64be track read_single("Q>", 8) end |
#read_uint8 ⇒ Object
200 201 202 |
# File 'lib/binstream/streams/base.rb', line 200 def read_uint8 track read_single("C", 1) end |
#read_unpack(bytes, fmt) ⇒ Object
308 309 310 |
# File 'lib/binstream/streams/base.rb', line 308 def read_unpack(bytes, fmt) read(bytes).unpack(fmt) end |
#remaining ⇒ Object
How many remaining bytes are there
71 72 73 |
# File 'lib/binstream/streams/base.rb', line 71 def remaining size - tell end |
#remaining?(len_to_check = 1) ⇒ Boolean
Do we have any remaining bytes?
76 77 78 |
# File 'lib/binstream/streams/base.rb', line 76 def remaining?(len_to_check=1) remaining >= len_to_check end |
#reset ⇒ Object
35 36 37 38 39 |
# File 'lib/binstream/streams/base.rb', line 35 def reset @cur_offset = 0 @stopper = nil @startpos = 0 end |
#rewind ⇒ Object
Reset the position pointer back to the start
81 82 83 |
# File 'lib/binstream/streams/base.rb', line 81 def rewind @cur_offset = 0 end |
#seek(seek_len, whence = IO::SEEK_CUR) ⇒ Object
Seek to a specific position, or relative
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/binstream/streams/base.rb', line 127 def seek(seek_len, whence=IO::SEEK_CUR) raise ArgumentError.new("Position must be an integer") if seek_len.nil? case whence when IO::SEEK_SET, :SET proposal = seek_len when IO::SEEK_CUR, :CUR proposal = @cur_offset + seek_len when IO::SEEK_END, :END proposal = @stopper + seek_len # This will actually be a +(-999) else raise ArgumentError.new("whence must be :SET, :CUR, :END") end if valid_position?(proposal) @cur_offset = proposal else raise InvalidPositionError.new(proposal) end return true end |
#setup_stopper(startpos, whence, max_length) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/binstream/streams/base.rb', line 17 def setup_stopper(startpos, whence, max_length) if whence == IO::SEEK_CUR startpos += @stream.tell end @startpos = startpos || @stream.tell if max_length @stopper = startpos + max_length else @stopper = @stream.size end end |
#slice(new_length, new_offset = nil) ⇒ Object
Create a new stream based off this one using an offset and length
42 43 44 45 46 47 48 49 |
# File 'lib/binstream/streams/base.rb', line 42 def slice(new_length, new_offset=nil) new_stream = peek_slice(new_length, new_offset) # advance our pointer @cur_offset += new_length return new_stream end |
#slice!(new_length, new_offset) ⇒ Object
slice!(length, offset) Get new stream using absolute position
53 54 55 56 57 58 |
# File 'lib/binstream/streams/base.rb', line 53 def slice!(new_length, new_offset) self.class.new(@stream, startpos: (@startpos + new_offset), read_length: new_length ) end |
#starting_offset ⇒ Object
31 32 33 |
# File 'lib/binstream/streams/base.rb', line 31 def starting_offset @startpos end |
#stell ⇒ Object
Position on the underlying stream
165 166 167 |
# File 'lib/binstream/streams/base.rb', line 165 def stell @stream.tell end |
#tell ⇒ Object Also known as: pos
Position in our current high level stream
159 160 161 |
# File 'lib/binstream/streams/base.rb', line 159 def tell @cur_offset end |
#total_size ⇒ Object Also known as: size
169 170 171 |
# File 'lib/binstream/streams/base.rb', line 169 def total_size stopper - @startpos end |
#valid_position?(proposal) ⇒ Boolean
Is this actually a valid position?
150 151 152 |
# File 'lib/binstream/streams/base.rb', line 150 def valid_position?(proposal) proposal.abs <= size end |