Module: Feh::Bin

Defined in:
lib/feh/bin.rb,
lib/feh/bin/lz11.rb,
lib/feh/bin/version.rb,
lib/feh/bin/array_istream.rb,
lib/feh/bin/array_ostream.rb

Defined Under Namespace

Classes: ArrayIStream, ArrayOStream, LZ11

Constant Summary collapse

VERSION =

Version number.

"0.2.0"

Class Method Summary collapse

Class Method Details

.compress(buf, no_compress = false) ⇒ Array<Integer>, Symbol

Compresses data into a .bin.lz file.

Parameters:

  • buf (Array<Integer>, String)

    content of the data to compress

  • no_compress (Boolean) (defaults to: false)

    true if LZ11 is not used to compress the data

Returns:

  • (Array<Integer>)

    content of the .bin.lz file

  • (Symbol)

    error code if the input is not a valid data buffer



23
24
25
26
27
28
29
30
31
32
# File 'lib/feh/bin.rb', line 23

def self.compress(buf, no_compress = false)
  buf = buf.bytes if buf.is_a?(String)
  if no_compress
    write_bin_lz04(buf, buf.size)
  else
    buf2 = LZ11.new(buf).compress
    return buf2 if buf2.is_a?(Symbol)
    write_bin_lz(buf2, buf.size)
  end
end

.decompress(buf) ⇒ Array<Integer>, Symbol

Decompresses a .bin.lz file.

Parameters:

  • buf (Array<Integer>, String)

    content of the .bin.lz file

Returns:

  • (Array<Integer>)

    content of the decompressed asset data

  • (Symbol)

    error code if the input is not a valid .bin.lz file



11
12
13
14
15
16
# File 'lib/feh/bin.rb', line 11

def self.decompress(buf)
  buf = buf.bytes if buf.is_a?(String)
  buf2 = read_bin_lz(buf)
  return buf2 if buf2.is_a?(Symbol)
  LZ11.new(buf2).decompress
end

.read_bin_lz(buf) ⇒ Array<Integer>, Symbol

Unpacks a Fire Emblem Heroes .bin.lz file.

Parameters:

  • buf (Array<Integer>, String)

    content of the .bin.lz file

Returns:

  • (Array<Integer>)

    content of the unpacked LZ11 archive

  • (Symbol)

    error code if the input is not a valid .bin.lz file



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/feh/bin.rb', line 38

def self.read_bin_lz(buf)
  buf = buf.bytes if buf.is_a?(String)
  header = buf.shift(4)
  xorseed = header[1] | (header[2] << 8) | (header[3] << 16)
  if (header.first & 0xFF) == 0x17 && (buf.first & 0xFF) == 0x11
    xorkey = [0x8083 * xorseed].pack('l<').bytes
    (4...buf.size).step(4).each do |i|
      4.times {|j| buf[i + j] ^= xorkey[j]}
      4.times {|j| xorkey[j] ^= buf[i + j]}
    end
    buf
  else
    :invalid_archive
  end
end

.read_bin_lz04(buf) ⇒ Array<Integer>, Symbol

Unpacks a Fire Emblem Heroes .bin.lz file. Used for files that are XOR-encrypted for FEH but not LZ11-compressed.

Parameters:

  • buf (Array<Integer>, String)

    content of the .bin.lz file

Returns:

  • (Array<Integer>)

    content of the unpacked archive

  • (Symbol)

    error code if the input is not a valid .bin.lz file



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/feh/bin.rb', line 59

def self.read_bin_lz04(buf)
  buf = buf.bytes if buf.is_a?(String)
  header = buf.shift(4)
  xorseed = header[1] | (header[2] << 8) | (header[3] << 16)
  if header.first == 0x04 && xorseed == buf.size
    xorkey = [0x8083 * xorseed].pack('l<').bytes
    (0...buf.size).step(4).each do |i|
      4.times {|j| buf[i + j] ^= xorkey[j]}
      4.times {|j| xorkey[j] ^= buf[i + j]}
    end
    buf
  else
    :invalid_archive
  end
end

.write_bin_lz(bytes, xorseed = nil) ⇒ Array<Integer>

Packs a Fire Emblem Heroes .bin.lz file.

Parameters:

  • bytes (Array<Integer>, String)

    content of an LZ11 archive

  • xorseed (Integer, nil) (defaults to: nil)

    optional XOR encryption value

Returns:

  • (Array<Integer>)

    content of the packed .bin.lz file



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/feh/bin.rb', line 79

def self.write_bin_lz(bytes, xorseed = nil)
  bytes = bytes.bytes if bytes.is_a?(String)
  bytes += [0] * ((-bytes.size) % 4)
  xorseed = bytes.size if xorseed.nil?
  header = [xorseed * 0x100 + 0x17].pack('l<').bytes
  xorkey = [0x8083 * xorseed].pack('l<').bytes
  4.times {|j| bytes[4 + j] ^= xorkey[j]}
  (8...bytes.size).step(4).each do |i|
    4.times {|j| bytes[i + j] ^= bytes[i - 4 + j]}
  end
  header + bytes
end

.write_bin_lz04(bytes, xorseed = nil) ⇒ Array<Integer>

Packs a Fire Emblem Heroes .bin.lz file. Used for files that are XOR-encrypted for FEH but not LZ11-compressed.

Parameters:

  • bytes (Array<Integer>, String)

    content of an archive

  • xorseed (Integer, nil) (defaults to: nil)

    optional XOR encryption value

Returns:

  • (Array<Integer>)

    content of the packed .bin.lz file



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/feh/bin.rb', line 97

def self.write_bin_lz04(bytes, xorseed = nil)
  bytes = bytes.bytes if bytes.is_a?(String)
  bytes += [0] * ((-bytes.size) % 4)
  xorseed = bytes.size if xorseed.nil?
  header = [xorseed * 0x100 + 0x04].pack('l<').bytes
  xorkey = [0x8083 * xorseed].pack('l<').bytes
  4.times {|j| bytes[j] ^= xorkey[j]}
  (4...bytes.size).step(4).each do |i|
    4.times {|j| bytes[i + j] ^= bytes[i - 4 + j]}
  end
  header + bytes
end