module Sabrina::Bytestream::RomOperations

Methods related to writing and retrieving various ROM data.

Public Instance Methods

calculate_length() click to toggle source

@todo Return key :original_length for {Lz77.uncompress} is currently

unreliable. Wipe and overwrite in place for table data is disabled.

Returns the length of the {Lz77} data stored on the ROM if :lz77 mode is on and a table of offset is provided. Otherwise, returns the length of the byte data.

@return [Integer]

# File lib/sabrina/bytestream/rom_operations.rb, line 103
def calculate_length
  return @length_cache if @length_cache
  if @lz77 && offset
    return @length_cache = @rom.read_lz77(offset)[:original_length]
  end
  to_bytes.length
end
clear_cache(h = { lz77: true }) click to toggle source

Wipes the internal cache so that the data may be reloaded from ROM if present.

Subclasses should call this whenever the internal representation of data is changed, and define {ByteOutput#generate_bytes} to regenerate the byte data from the internal representation.

@param [Hash] h

@option h [Boolean] :lz77 whether to clear the internal representation
  as well (defaults to +true+).

@return [self]

# File lib/sabrina/bytestream/rom_operations.rb, line 88
def clear_cache(h = { lz77: true })
  @lz77_cache = nil if h.fetch(:lz77, true)
  @length_cache = nil if h.fetch(:lz77, true) && !@lz77
  @bytes_cache = nil
  self
end
reload_from_rom() click to toggle source

Wipes the internal cache AND the representation so that the data may be synced from ROM if present.

@return [self]

# File lib/sabrina/bytestream/rom_operations.rb, line 70
def reload_from_rom
  @representation = nil
  clear_cache
  present
  self
end
write_to_rom() click to toggle source

@todo Return key :original_length for {Lz77.uncompress} is currently

unreliable. Wipe and overwrite in place for table data is disabled.

Writes the byte data to the ROM, trying to use first the table index and then the offset (and failing if neither is known).

If the table index is known, the data will be written to an available free space on the ROM and the table will be updated.

If the table data is unknown, the data will be written in place at the offset.

This method will call {#reload_from_rom} and update and return the {#last_write} array.

@return [Array] see {#last_write}.

# File lib/sabrina/bytestream/rom_operations.rb, line 22
def write_to_rom
  old_length = calculate_length
  b = (@lz77 ? to_lz77 : to_bytes)
  new_length = b.length
  old_offset = offset

  unless @rom && old_offset
    fail 'Rom and offset or table/index must be set before writing.'
  end
  fail 'Byte string is empty. Aborting.' if b.empty?
  fail "Byte string too long #{new_length}. Aborting." if new_length > 10_000

  @last_write = []

  new_offset =
    if !@pointer_mode || !(@table && @index)
      @last_write << 'Bytestream#repoint: Overwriting in place.' \
      " (#{old_offset})"
      old_offset
      # Wipe and overwrite disabled due to
      # Lz77.uncompress[:original_length] inaccuracy.
      #
      # elsif new_length <= old_length
      # @last_write << 'Repoint: New length less than or equal to old' \
      #   'length, overwriting in place.'
      # @last_write << @rom.wipe(old_offset, old_length, true)
      # old_offset
    else
      o = repoint
      @last_write << 'Bytestream#repoint: Wiping disabled in this' \
        "version. Leaving #{old_length} bytes at #{old_offset}" \
        " (#{ format('%06X', old_offset) }) in #{@rom} intact."
      @last_write << "Bytestream#repoint: Repointed to #{o}" \
        " (#{ format('%06X', o) })."
      # @last_write << @rom.wipe(old_offset, old_length)
      o
    end

  @last_write << @rom.write(new_offset, b)
  clear_cache(lz77: false)

  @last_write
end

Private Instance Methods

repoint() click to toggle source

Assigns the data to a suitable free space on the ROM and updates the table accordingly.

This will clear the internal cache.

@return [Integer] The offset found.

# File lib/sabrina/bytestream/rom_operations.rb, line 119
def repoint
  unless @rom && @table && @index
    fail 'Rom, table and index must be set before repointing.'
  end

  l = (@lz77 ? to_lz77.length : to_bytes.length)
  f_offset = @rom.find_free(l)

  unless f_offset
    fail "Bytestream#repoint: Could not find #{l} bytes of free data in" \
      " #{@rom}. Consider using a clean rombase."
  end

  @rom.write_offset_to_table(@table, @index, f_offset)
  clear_cache
  f_offset
end