class WolfRpg::FileCoder

Constants

CRYPT_HEADER_SIZE

Constants #

DECRYPT_INTERVALS

Attributes

crypt_header[R]
io[R]

Attributes #

Public Class Methods

new(io, crypt_header = nil, filename = nil, seed_indices = nil) click to toggle source

Initialize #

# File lib/wolfrpg/filecoder.rb, line 59
def initialize(io, crypt_header = nil, filename = nil, seed_indices = nil)
  @io = io
  @crypt_header = crypt_header
  @filename = filename
end
open(filename, mode, seed_indices = nil, crypt_header = nil) { |coder| ... } click to toggle source

Class methods #

# File lib/wolfrpg/filecoder.rb, line 18
def self.open(filename, mode, seed_indices = nil, crypt_header = nil)
  case mode
  when :read
    coder = FileCoder.new(File.open(filename, 'rb'))

    # If encryptable,
    # we need to make an extra check to see if it needs decrypting
    if seed_indices
      unless (indicator = coder.read_byte) == 0
        header = [indicator]
        (CRYPT_HEADER_SIZE - 1).times { |i| header << coder.read_byte }
        seeds = seed_indices.map { |i| header[i] }
        data = crypt(coder.read, seeds)
        coder = FileCoder.new(StringIO.new(data, 'rb'), header)
      end
    end
  when :write
    # If encryptable, open a StringIO and pass the encryption options
    # to the FileCoder
    if seed_indices && crypt_header
      coder = FileCoder.new(StringIO.new(''.force_encoding('BINARY'), 'wb'),
                            crypt_header, filename, seed_indices)
      coder.write(crypt_header.pack('C*'))
    else
      coder = FileCoder.new(File.open(filename, 'wb'))
      coder.write_byte(0) if seed_indices
    end
  end

  if block_given?
    begin
      yield coder
    ensure
      coder.close
    end
  end
  return coder
end

Private Class Methods

crypt(data_str, seeds) click to toggle source

Private class #

# File lib/wolfrpg/filecoder.rb, line 214
def self.crypt(data_str, seeds)
  data = data_str.unpack('C*')
  seeds.each_with_index do |seed, s|
    (0...data.size).step(DECRYPT_INTERVALS[s]) do |i|
      seed = (seed * 0x343FD + 0x269EC3) & 0xFFFFFFFF
      data[i] ^= (seed >> 28) & 7
    end
  end
  return data.pack('C*')
end

Public Instance Methods

close() click to toggle source

Other #

# File lib/wolfrpg/filecoder.rb, line 188
def close
  if @crypt_header && @filename && @seed_indices
    File.open(@filename, 'wb') do |file|
      file.write(@crypt_header.pack('C*'))
      seeds = @seed_indices.map { |i| crypt_header[i] }
      file.write(FileCoder.crypt(@io.string, seeds))
    end
  end
  @io.close
end
dump(size) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 126
def dump(size)
  size.times do |i|
    print " %02x" % read_byte
  end
  print "\n"
end
dump_until(pattern) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 133
def dump_until(pattern)
  str = ''.force_encoding('BINARY')
  until str.end_with? pattern
    str << @io.readpartial(1)
  end
  str[0...-pattern.bytesize].each_byte do |byte|
    print " %02x" % byte
  end
  print "\n"
end
encrypted?() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 7
def encrypted?
  @crypt_header != nil
end
eof?() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 199
def eof?
  @io.eof?
end
read(size = nil) click to toggle source

Read #

# File lib/wolfrpg/filecoder.rb, line 67
def read(size = nil)
  if size
    @io.readpartial(size)
  else
    @io.read
  end
end
read_byte() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 75
def read_byte
  @io.readpartial(1).ord
end
read_byte_array() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 91
def read_byte_array
  bytes = Array.new(read_int)
  bytes.each_index do |i|
    bytes[i] = read_byte
  end
  return bytes
end
read_int() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 79
def read_int
  @io.readpartial(4).unpack('l<').first
end
read_int_array() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 99
def read_int_array
  ints = Array.new(read_int)
  ints.each_index do |i|
    ints[i] = read_int
  end
  return ints
end
read_string() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 83
def read_string
  size = read_int
  raise "got a string of size <= 0" unless size > 0
  str = read(size - 1).encode(Encoding::UTF_8, Encoding::WINDOWS_31J)
  raise "string not null-terminated" unless read_byte == 0
  return str
end
read_string_array() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 107
def read_string_array
  strings = Array.new(read_int)
  strings.each_index do |i|
    strings[i] = read_string
  end
  return strings
end
skip(size) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 122
def skip(size)
  @io.seek(size, IO::SEEK_CUR)
end
tell() click to toggle source
# File lib/wolfrpg/filecoder.rb, line 203
def tell
  if encrypted?
    @io.tell + CRYPT_HEADER_SIZE
  else
    @io.tell
  end
end
verify(data) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 115
def verify(data)
  got = read(data.length)
  if got != data
    raise "could not verify magic data (expecting #{data.unpack('C*')}, got #{got.unpack('C*')})"
  end
end
write(data) click to toggle source

Write #

# File lib/wolfrpg/filecoder.rb, line 146
def write(data)
  @io.write(data)
end
write_byte(data) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 150
def write_byte(data)
  @io.write(data.chr)
end
write_byte_array(bytes) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 165
def write_byte_array(bytes)
  write_int(bytes.size)
  bytes.each do |b|
    write_byte(b)
  end
end
write_int(data) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 154
def write_int(data)
  @io.write([data].pack('l<'))
end
write_int_array(ints) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 172
def write_int_array(ints)
  write_int(ints.size)
  ints.each do |i|
    write_int(i)
  end
end
write_string(str) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 158
def write_string(str)
  str = str.encode(Encoding::WINDOWS_31J, Encoding::UTF_8)
  write_int(str.bytesize + 1)
  write(str)
  write_byte(0)
end
write_string_array(strings) click to toggle source
# File lib/wolfrpg/filecoder.rb, line 179
def write_string_array(strings)
  write_int(strings.size)
  strings.each do |s|
    write_string(s)
  end
end