Class: Sabrina::Bytestream

Inherits:
Object
  • Object
show all
Extended by:
ByteInput
Includes:
ByteOutput, RomOperations
Defined in:
lib/sabrina/bytestream.rb,
lib/sabrina/bytestream/byte_input.rb,
lib/sabrina/bytestream/byte_output.rb,
lib/sabrina/bytestream/rom_operations.rb

Overview

A generic class for dealing with byte data related to a ROM.

It is required that :rom and either :table and :index (recommended) or :offset be set in order to enable writing back to a ROM file.

There should be no need to use this class directly.

Direct Known Subclasses

GBAString, Palette, Sprite

Defined Under Namespace

Modules: ByteInput, ByteOutput, RomOperations

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ByteInput

from_bytes, from_hex, from_rom, from_rom_as_lz77, from_table, from_table_as_pointer

Methods included from RomOperations

#calculate_length, #clear_cache, #reload_from_rom, #write_to_rom

Methods included from ByteOutput

#generate_bytes, #present, #to_b, #to_bytes, #to_hex, #to_hex_reverse, #to_i, #to_lz77, #to_s

Constructor Details

#initialize(h = {}) ⇒ Bytestream

Returns a new instance of Bytestream, taking a hash of arguments as the option. The hash may contain the following keys, all of which are optional and init to nil or false. Any invalid keys should be ignored.

Subclasses should call this method with subclass-specific data. There should be no need to call this method directly.

Subclasses should override the load_settings(h) private method to allow for additional options.

Parameters:

  • h (Hash) (defaults to: {})

Options Hash (h):

  • :representation (Object)

    The internal representation of the byte data. Subclasses should be able to convert bytes to and from the representation via the Sabrina::Bytestream::ByteOutput#present and Sabrina::Bytestream::ByteOutput#generate_bytes methods.

  • :pointer_mode (Boolean)

    Whether to expect pointers in the table instead of actual data. This voids :index_length.

  • :lz77 (Boolean)

    Whether to read and write ROM data as Lz77-compressed.

  • :is_gba_string (Boolean)

    Whether to read ROM data as a GBA-encoded, 0xFF-terminated string.

  • :rom (Rom)

    A ROM to be used for reading and writing data.

  • :table (Symbol, String)

    The table to read offset data from. This should be the name of an option specified in the rom_data hash. :table and :index will take precedence over :offset if present. This is the recommended way of dealing with monster data, as it will allow automagically updating the offset upon writing or switching ROMs.

  • :index (Integer)

    The index to read from the table. See #index= for details.

  • :index_length (Integer)

    The length of a single table entry, necessary for seeking.

  • :offset (Integer)

    The position in ROM to read and write to. This will only be used if :table or :index are not present. See parse_offset for details.

  • :length (Integer)

    The byte length to read from the ROM. This will be ignored if :lz77 compression is enabled.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/sabrina/bytestream.rb', line 106

def initialize(h = {})
  # Subclasses may want to override defaults, hence ||=
  @work_dir ||= nil
  @filename ||= nil

  @representation ||= nil
  @bytes_cache ||= nil
  @lz77_cache ||= nil
  @length_cache ||= nil

  @last_write ||= nil

  @old_offset ||= nil
  @old_length ||= nil

  @lz77 ||= false
  @is_gba_string ||= false

  @rom ||= nil
  @table ||= nil
  @index ||= nil
  @offset ||= nil
  @length ||= nil

  @pointer_mode ||= false
  @index_length ||= nil

  load_settings(h)
  present
end

Instance Attribute Details

#filenameString

The filename to save to, sans the extension. Subclass to_file methods should take care of adding the right extension.

Returns:

  • (String)


47
48
49
# File 'lib/sabrina/bytestream.rb', line 47

def filename
  @filename
end

#indexInteger

The index in the ROM table.

Returns:

  • (Integer)

See Also:



29
30
31
# File 'lib/sabrina/bytestream.rb', line 29

def index
  @index
end

#last_writeArray (readonly)

Stores an array of debug strings related to the latest write to ROM.



17
18
19
# File 'lib/sabrina/bytestream.rb', line 17

def last_write
  @last_write
end

#romRom

The ROM being used for operations.

Returns:

See Also:



23
24
25
# File 'lib/sabrina/bytestream.rb', line 23

def rom
  @rom
end

#tableString or Symbol

The table code to search for data.

Returns:

  • (String or Symbol)

See Also:



35
36
37
# File 'lib/sabrina/bytestream.rb', line 35

def table
  @table
end

#work_dirString

The directory for saving files. Should be created if specified but not existing.

Returns:

  • (String)


41
42
43
# File 'lib/sabrina/bytestream.rb', line 41

def work_dir
  @work_dir
end

Class Method Details

.parse_offset(p_offset) ⇒ Integer

Takes an integer or a “0x”- or “x”-prefixed string and converts it to a valid numerical offset.

Parameters:

  • p_offset (Integer)

Returns:

  • (Integer)


55
56
57
58
59
60
61
62
63
64
65
# File 'lib/sabrina/bytestream.rb', line 55

def parse_offset(p_offset)
  o = p_offset.to_s.downcase

  if /[^0-9a-fx]/ =~ o
    fail "\'#{p_offset}\' does not look like a valid offset." \
      ' Supply an integer, or a hex optionally prefixed' \
      " with \'0x\' or \'x\'."
  end

  /[a-fx]/ =~ o ? p_offset.rpartition('x').last.hex : p_offset.to_i
end

Instance Method Details

#lz77_modeself

Tells the object that the ROM uses Lz77 compression for the data. This is the same as setting :lz77=>true in the options hash.

Returns:

  • (self)


225
226
227
228
# File 'lib/sabrina/bytestream.rb', line 225

def lz77_mode
  @lz77 = true
  self
end

#offsetInteger

Returns the associated offset, first trying the table and then :offset. Returns nil if neither has sufficient data.

Returns:

  • (Integer)


141
142
143
144
145
146
147
# File 'lib/sabrina/bytestream.rb', line 141

def offset
  if @rom && @table && @index
    return @rom.read_offset_from_table(@table, @index) if @pointer_mode
    return @rom.table_to_offset(@table, @index, @index_length)
  end
  @offset
end

#offset=(p_offset) ⇒ Integer

Sets the offset of the data in :rom. This is the same as setting :offset in the options hash.

This will clear the internal cache.

Parameters:

  • p_offset (Integer, String)

    See parse_offset for details.

Returns:

  • (Integer)

    new offset.



212
213
214
215
216
217
218
# File 'lib/sabrina/bytestream.rb', line 212

def offset=(p_offset)
  return self if p_offset == @offset
  @old_offset = @offset
  @offset = Bytestream.parse_offset(p_offset)
  clear_cache
  @offset
end

#pointerString

Returns the offset as a reversed byte string. This is the format used internally by ROMs to reference data.

Returns:

  • (String)


153
154
155
# File 'lib/sabrina/bytestream.rb', line 153

def pointer
  Rom.offset_to_pointer(offset)
end

#string_modeself

Tells the object that the data is a GBA-encoded, 0xFF-terminated string. This is the same as setting :is_gba_string=>true in the options hash.

Returns:

  • (self)


235
236
237
238
# File 'lib/sabrina/bytestream.rb', line 235

def string_mode
  @is_gba_string = true
  self
end