Class: Baikal::Pool

Inherits:
Object
  • Object
show all
Defined in:
lib/baikal.rb,
lib/baikal/tweak.rb

Overview

Represents a byte pool. Byte pools are resizeable arrays of bytes. Data can be stored into or read from byte pool as integers or as blobs.

Each byte pool has an associated /integer byte order indicator/; see go_network_byte_order, go_reverse_network_byte_order and go_native_byte_order.

Byte pools have no concept of current position; for linear traversal, see Cursor.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(initial_content = '') ⇒ Pool

Creates a new byte pool of the host system’s native byte order. If initial_content is given, loads its bytes to the newly created byte pool. Otherwise, the byte pool will be empty after creation.



29
30
31
32
33
34
35
36
# File 'lib/baikal.rb', line 29

def initialize initial_content = ''
  raise 'Type mismatch' unless initial_content.is_a? String
  super()
  @bytes = initial_content.dup
  @bytes.force_encoding Encoding::ASCII_8BIT
  @byte_order = '!' # native
  return
end

Instance Attribute Details

#bytesObject (readonly)

A Ruby string containing all the bytes currently in this pool.



22
23
24
# File 'lib/baikal.rb', line 22

def bytes
  @bytes
end

Class Method Details

.new_of_network_byte_order(initial_content = '') ⇒ Object

Creates a new byte pool of the network byte order. If initial_content is given, loads its bytes to the newly created byte pool. Otherwise, the byte pool will be empty after creation.



43
44
45
46
47
48
# File 'lib/baikal.rb', line 43

def Pool::new_of_network_byte_order initial_content = ''
  raise 'Type mismatch' unless initial_content.is_a? String
  pool = Pool.new(initial_content)
  pool.go_network_byte_order
  return pool
end

.new_of_reverse_network_byte_order(initial_content = '') ⇒ Object

Creates a new byte pool of the reverse network byte order. If initial_content is given, loads its bytes to the newly created byte pool. Otherwise, the byte pool will be empty after creation.



55
56
57
58
59
60
# File 'lib/baikal.rb', line 55

def Pool::new_of_reverse_network_byte_order initial_content = ''
  raise 'Type mismatch' unless initial_content.is_a? String
  pool = Pool.new(initial_content)
  pool.go_reverse_network_byte_order
  return pool
end

Instance Method Details

#align(alignment, padding = 0) ⇒ Object

Pads the byte pool to the specified alignment using the specified padding byte. If padding is not given, zero is used by default.



374
375
376
377
378
379
# File 'lib/baikal.rb', line 374

def align alignment, padding = 0
  raise 'Type mismatch' unless alignment.is_a? Integer
  raise 'Type mismatch' unless padding.is_a? Integer
  emit_repeated_bytes bytes_until_alignment(alignment), padding
  return
end

#byte_orderObject

Returns the byte order indicator for the currently selected endianness: > for BigEndian, < for LittleEndian, or ! for whatever the native byte order is. (+Array#pack+ can accept such since Ruby 1.9.3.)



427
428
429
# File 'lib/baikal.rb', line 427

def byte_order
  return @byte_order
end

#bytes_until_alignment(alignment) ⇒ Object

Returns the difference between current size of the byte pool and the alignment requirement given by alignment. alignment needs not be a two’s power.



364
365
366
367
368
# File 'lib/baikal.rb', line 364

def bytes_until_alignment alignment
  raise 'Type mismatch' unless alignment.is_a? Integer
  raise 'Invalid alignment requirement' unless alignment > 0
  return -@bytes.size % alignment
end

#emit_blob(blob) ⇒ Object

Appends blob given as a Ruby string to this byte pool, growing the byte pool by the blob’s length.



318
319
320
321
# File 'lib/baikal.rb', line 318

def emit_blob blob
  @bytes << blob.to_s
  return
end

#emit_byte(value) ⇒ Object

Appends the byte given by value to this byte pool, growing the byte pool by one byte.



66
67
68
69
# File 'lib/baikal.rb', line 66

def emit_byte value
  set_byte @bytes.size, value
  return
end

#emit_octa(value) ⇒ Object

Appends the octabyte given by value to this byte pool using the currently selected byte order, growing the byte pool by eight bytes.



93
94
95
96
# File 'lib/baikal.rb', line 93

def emit_octa value
  set_octa @bytes.size, value
  return
end

#emit_repeated_bytes(count, value = 0) ⇒ Object

Appends count copies of the byte given by value to this byte pool, growing the byte pool by as many bytes. If value is not given, zero is used by default.



103
104
105
106
107
108
# File 'lib/baikal.rb', line 103

def emit_repeated_bytes count, value = 0
  raise 'Type mismatch' unless count.is_a? Integer
  raise 'Type mismatch' unless value.is_a? Integer
  @bytes << [value].pack('C') * count
  return
end

#emit_tetra(value) ⇒ Object

Appends the tetrabyte given by value to this byte pool using the currently selected byte order, growing the byte pool by four bytes.



84
85
86
87
# File 'lib/baikal.rb', line 84

def emit_tetra value
  set_tetra @bytes.size, value
  return
end

#emit_wyde(value) ⇒ Object

Appends the wyde given by value to this byte pool using the currently selected byte order, growing the byte pool by two bytes.



75
76
77
78
# File 'lib/baikal.rb', line 75

def emit_wyde value
  set_wyde @bytes.size, value
  return
end

#get_blob(offset, size) ⇒ Object

Extracts a blob of given size from this byte pool’s given offset and returns it as a Ruby string.

Error if such a blob lies outside of the boundaries of the pool, even partially.



329
330
331
332
333
334
335
# File 'lib/baikal.rb', line 329

def get_blob offset, size
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Type mismatch' unless size.is_a? Integer
  raise 'Invalid blob size' if size < 0
  raise 'Offset out of range' if offset < 0 or offset + size > @bytes.size
  return @bytes[offset, size]
end

#get_signed_byte(offset) ⇒ Object

Retrieves one signed byte from this byte pool from the given offset.

Error if such a byte lies outside the boundaries of the pool.



167
168
169
170
171
# File 'lib/baikal.rb', line 167

def get_signed_byte offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 1 > @bytes.size
  return @bytes.unpack("@#{offset} c").first
end

#get_signed_octa(offset) ⇒ Object

Retrieves one signed octabyte from this byte pool from the given offset, using the currently selected byte order.

Error if such an octa lies outside the boundaries of the pool, even partially.



206
207
208
209
210
# File 'lib/baikal.rb', line 206

def get_signed_octa offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 8 > @bytes.size
  return @bytes.unpack("@#{offset} q#@byte_order").first
end

#get_signed_tetra(offset) ⇒ Object

Retrieves one signed tetrabyte from this byte pool from the given offset, using the currently selected byte order.

Error if such a tetra lies outside the boundaries of the pool, even partially.



193
194
195
196
197
# File 'lib/baikal.rb', line 193

def get_signed_tetra offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 4 > @bytes.size
  return @bytes.unpack("@#{offset} l#@byte_order").first
end

#get_signed_wyde(offset) ⇒ Object

Retrieves one signed wyde from this byte pool from the given offset, using the currently selected byte order.

Error if such a wyde lies outside the boundaries of the pool, even partially.



180
181
182
183
184
# File 'lib/baikal.rb', line 180

def get_signed_wyde offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 2 > @bytes.size
  return @bytes.unpack("@#{offset} s#@byte_order").first
end

#get_unsigned_byte(offset) ⇒ Object

Retrieves one unsigned byte from this byte pool from the given offset.

Error if such a byte lies outside the boundaries of the pool.



116
117
118
119
120
# File 'lib/baikal.rb', line 116

def get_unsigned_byte offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 1 > @bytes.size
  return @bytes.unpack("@#{offset}C").first
end

#get_unsigned_integer(size, offset) ⇒ Object

Retrieves an unsigned integer of the given size (which must be either 1, 2, 4 or 8) from this byte pool from the given offset, using the currently selected byte order.

Error if such an integer lies outside the boundaries of the pool, even partially.



220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/baikal.rb', line 220

def get_unsigned_integer size, offset
  raise 'Type mismatch' unless offset.is_a? Integer
  pack_code = case size
  when 1 then 'C'
  when 2 then "S#@byte_order"
  when 4 then "L#@byte_order"
  when 8 then "Q#@byte_order"
  else raise "Unsupported integer size #{size.inspect}"
  end
  raise 'Offset out of range' if offset < 0 or offset + size > @bytes.size
  return @bytes.unpack("@#{offset} #{pack_code}").first
end

#get_unsigned_octa(offset) ⇒ Object

Retrieves one unsigned octabyte from this byte pool from the given offset, using the currently selected byte order.

Error if such an octa lies outside the boundaries of the pool, even partially.



155
156
157
158
159
# File 'lib/baikal.rb', line 155

def get_unsigned_octa offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 8 > @bytes.size
  return @bytes.unpack("@#{offset} Q#@byte_order").first
end

#get_unsigned_tetra(offset) ⇒ Object

Retrieves one unsigned tetrabyte from this byte pool from the given offset, using the currently selected byte order.

Error if such a tetra lies outside the boundaries of the pool, even partially.



142
143
144
145
146
# File 'lib/baikal.rb', line 142

def get_unsigned_tetra offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 4 > @bytes.size
  return @bytes.unpack("@#{offset} L#@byte_order").first
end

#get_unsigned_wyde(offset) ⇒ Object

Retrieves one unsigned wyde from this byte pool from the given offset, using the currently selected byte order.

Error if such a wyde lies outside the boundaries of the pool, even partially.



129
130
131
132
133
# File 'lib/baikal.rb', line 129

def get_unsigned_wyde offset
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset + 2 > @bytes.size
  return @bytes.unpack("@#{offset} S#@byte_order").first
end

#go_native_byte_orderObject

Selects the host system’s native byte order for following multibyte integer read or write operations.



417
418
419
420
# File 'lib/baikal.rb', line 417

def go_native_byte_order
  @byte_order = '!'
  return
end

#go_network_byte_orderObject

Selects the network byte order for following multibyte integer read or write operations.



399
400
401
402
# File 'lib/baikal.rb', line 399

def go_network_byte_order
  @byte_order = '>'
  return
end

#go_reverse_network_byte_orderObject

Selects the reverse network byte order for following multibyte integer read or write operations.



408
409
410
411
# File 'lib/baikal.rb', line 408

def go_reverse_network_byte_order
  @byte_order = '<'
  return
end

#native_byte_order_selected?Boolean

Returns whether this byte pool’s currently selected byte order is the host system’s native byte order.

Returns:

  • (Boolean)


451
452
453
# File 'lib/baikal.rb', line 451

def native_byte_order_selected?
  return @byte_order == '!'
end

#network_byte_order_selected?Boolean

Returns whether this byte pool’s currently selected byte order is the network byte order.

Returns:

  • (Boolean)


435
436
437
# File 'lib/baikal.rb', line 435

def network_byte_order_selected?
  return @byte_order == '>'
end

#reverse_network_byte_order_selected?Boolean

Returns whether this byte pool’s currently selected byte order is the reverse network byte order.

Returns:

  • (Boolean)


443
444
445
# File 'lib/baikal.rb', line 443

def reverse_network_byte_order_selected?
  return @byte_order == '<'
end

#set_blob(offset, blob) ⇒ Object

Stores a blob, given as a Ruby string, into this byte pool at the given offset.

Error if the offset lies outside the boundaries of the pool. (But it’s OK for it to point at the end of the pool.)



344
345
346
347
348
349
350
# File 'lib/baikal.rb', line 344

def set_blob offset, blob
  raise 'Type mismatch' unless offset.is_a? Integer
  blob = blob.to_s.dup.force_encoding Encoding::ASCII_8BIT
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset, blob.bytesize] = blob
  return
end

#set_byte(offset, value) ⇒ Object

Sets the byte in this byte pool on the given offset to the given value.

Error if the offset lies outside the boundaries of the pool. (But it’s OK for it to point at the end of the pool.)



239
240
241
242
243
244
245
# File 'lib/baikal.rb', line 239

def set_byte offset, value
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Type mismatch' unless value.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset] = [value].pack('c')
  return
end

#set_integer(size, offset, value) ⇒ Object

Sets integer of the given size (which must be either 1, 2, 4 or 8) in this byte pool on the given offset to the given value, using the currently selected byte order.

Error if such an integer lies outside the boundaries of the pool, even partially.



300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/baikal.rb', line 300

def set_integer size, offset, value
  raise 'Type mismatch' unless offset.is_a? Integer
  pack_code = case size
  when 1 then 'C'
  when 2 then "S#@byte_order"
  when 4 then "L#@byte_order"
  when 8 then "Q#@byte_order"
  else raise "Unsupported integer size #{size.inspect}"
  end
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset, size] = [value].pack(pack_code)
  return
end

#set_octa(offset, value) ⇒ Object

Sets the octabyte in this byte pool on the given offset to the given value, using the currently selected byte order.

Error if the offset lies outside the boundaries of the pool. (But it’s OK for it to point at the end of the pool.)



284
285
286
287
288
289
290
# File 'lib/baikal.rb', line 284

def set_octa offset, value
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Type mismatch' unless value.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset, 8] = [value].pack("q#@byte_order")
  return
end

#set_tetra(offset, value) ⇒ Object

Sets the tetrabyte in this byte pool on the given offset to the given value, using the currently selected byte order.

Error if the offset lies outside the boundaries of the pool. (But it’s OK for it to point at the end of the pool.)



269
270
271
272
273
274
275
# File 'lib/baikal.rb', line 269

def set_tetra offset, value
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Type mismatch' unless value.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset, 4] = [value].pack("l#@byte_order")
  return
end

#set_wyde(offset, value) ⇒ Object

Sets the wyde in this byte pool on the given offset to the given value, using the currently selected byte order.

Error if the offset lies outside the boundaries of the pool. (But it’s OK for it to point at the end of the pool.)



254
255
256
257
258
259
260
# File 'lib/baikal.rb', line 254

def set_wyde offset, value
  raise 'Type mismatch' unless offset.is_a? Integer
  raise 'Type mismatch' unless value.is_a? Integer
  raise 'Offset out of range' if offset < 0 or offset > @bytes.size
  @bytes[offset, 2] = [value].pack("s#@byte_order")
  return
end

#sizeObject

Returns the number of bytes in this byte pool.



355
356
357
# File 'lib/baikal.rb', line 355

def size
  return @bytes.size
end

#truncate(new_size) ⇒ Object

Truncates this byte pool to new_size bytes, discarding all bytes after this offset.

Error if the byte pool is already shorter than new_size bytes.



387
388
389
390
391
392
393
# File 'lib/baikal.rb', line 387

def truncate new_size
  raise 'Type mismatch' unless new_size.is_a? Integer
  raise 'Invalid size' if new_size < 0
  raise 'Unable to truncate to grow' if new_size > @bytes.size
  @bytes[new_size .. -1] = ''
  return
end

#tweak_signed_byte(offset, &thunk) ⇒ Object

Fetches a signed byte from offset in this byte pool, calls thunk with the byte as its argument, and stores the result of calling thunk as a byte at the same offset.

Error if the byte lies outside this byte pool.



24
25
26
27
# File 'lib/baikal/tweak.rb', line 24

def tweak_signed_byte offset, &thunk
  set_byte offset, yield(get_signed_byte(offset))
  return
end

#tweak_signed_octa(offset, &thunk) ⇒ Object

Fetches a signed octa from offset in this byte pool, calls thunk with the octa as its argument, and stores the result of calling thunk as a octa at the same offset.

Error if the octa lies outside this byte pool, even partially.



96
97
98
99
# File 'lib/baikal/tweak.rb', line 96

def tweak_signed_octa offset, &thunk
  set_octa offset, yield(get_signed_octa(offset))
  return
end

#tweak_signed_tetra(offset, &thunk) ⇒ Object

Fetches a signed tetra from offset in this byte pool, calls thunk with the tetra as its argument, and stores the result of calling thunk as a tetra at the same offset.

Error if the tetra lies outside this byte pool, even partially.



72
73
74
75
# File 'lib/baikal/tweak.rb', line 72

def tweak_signed_tetra offset, &thunk
  set_tetra offset, yield(get_signed_tetra(offset))
  return
end

#tweak_signed_wyde(offset, &thunk) ⇒ Object

Fetches a signed wyde from offset in this byte pool, calls thunk with the wyde as its argument, and stores the result of calling thunk as a wyde at the same offset.

Error if the wyde lies outside this byte pool, even partially.



48
49
50
51
# File 'lib/baikal/tweak.rb', line 48

def tweak_signed_wyde offset, &thunk
  set_wyde offset, yield(get_signed_wyde(offset))
  return
end

#tweak_unsigned_byte(offset, &thunk) ⇒ Object

Fetches an unsigned byte from offset in this byte pool, calls thunk with the byte as its argument, and stores the result of calling thunk as a byte at the same offset.

Error if the byte lies outside this byte pool.



12
13
14
15
# File 'lib/baikal/tweak.rb', line 12

def tweak_unsigned_byte offset, &thunk
  set_byte offset, yield(get_unsigned_byte(offset))
  return
end

#tweak_unsigned_octa(offset, &thunk) ⇒ Object

Fetches an unsigned octa from offset in this byte pool, calls thunk with the octa as its argument, and stores the result of calling thunk as a octa at the same offset.

Error if the octa lies outside this byte pool, even partially.



84
85
86
87
# File 'lib/baikal/tweak.rb', line 84

def tweak_unsigned_octa offset, &thunk
  set_octa offset, yield(get_unsigned_octa(offset))
  return
end

#tweak_unsigned_tetra(offset, &thunk) ⇒ Object

Fetches an unsigned tetra from offset in this byte pool, calls thunk with the tetra as its argument, and stores the result of calling thunk as a tetra at the same offset.

Error if the tetra lies outside this byte pool, even partially.



60
61
62
63
# File 'lib/baikal/tweak.rb', line 60

def tweak_unsigned_tetra offset, &thunk
  set_tetra offset, yield(get_unsigned_tetra(offset))
  return
end

#tweak_unsigned_wyde(offset, &thunk) ⇒ Object

Fetches an unsigned wyde from offset in this byte pool, calls thunk with the wyde as its argument, and stores the result of calling thunk as a wyde at the same offset.

Error if the wyde lies outside this byte pool, even partially.



36
37
38
39
# File 'lib/baikal/tweak.rb', line 36

def tweak_unsigned_wyde offset, &thunk
  set_wyde offset, yield(get_unsigned_wyde(offset))
  return
end