Class: Feh::Bin::LZ11
- Inherits:
-
Object
- Object
- Feh::Bin::LZ11
- Defined in:
- lib/feh/bin/lz11.rb
Overview
Converter for the LZ11 archive format used in Fire Emblem Heroes. Ported from DSDecmp.
Instance Attribute Summary collapse
-
#buf ⇒ ArrayIStream
readonly
The input buffer of the converter.
Instance Method Summary collapse
-
#compress ⇒ Array<Integer>, Symbol
Compresses a byte buffer.
-
#decompress ⇒ Array<Integer>, Symbol
Decompresses an LZ11 archive.
-
#initialize(buffer) ⇒ LZ11
constructor
Initializes the LZ11 converter.
Constructor Details
#initialize(buffer) ⇒ LZ11
Initializes the LZ11 converter.
16 17 18 |
# File 'lib/feh/bin/lz11.rb', line 16 def initialize(buffer) @buf = ArrayIStream.new(buffer) end |
Instance Attribute Details
#buf ⇒ ArrayIStream (readonly)
Returns the input buffer of the converter.
12 13 14 |
# File 'lib/feh/bin/lz11.rb', line 12 def buf @buf end |
Instance Method Details
#compress ⇒ Array<Integer>, Symbol
Compresses a byte buffer. This function is not required to produce exactly the same results as existing archives in Fire Emblem Heroes when given the same inputs.
102 103 104 105 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/feh/bin/lz11.rb', line 102 def compress return :input_too_short if buf.size < 2 return :input_too_large if buf.size > 0xFFFFFF outstream = ArrayOStream.new .u8(0x11).u16(buf.size).u8(buf.size >> 16) outbuffer = [8 * 4 + 1] * 33 outbuffer[0] = 0 bufferlength = 1 bufferedBlocks = 0 readBytes = 0 while readBytes < buf.size if bufferedBlocks == 8 outstream.write(outbuffer[0, bufferlength]) outbuffer[0] = 0 bufferlength = 1 bufferedBlocks = 0 end oldLength = [readBytes, 0x1000].min disp, length = occurrence_length(readBytes, [buf.size - readBytes, 0x10110].min, readBytes - oldLength, oldLength) if length < 3 outbuffer[bufferlength] = buf[readBytes] readBytes += 1 bufferlength += 1 else readBytes += length outbuffer[0] |= (1 << (7 - bufferedBlocks)) & 0xFF case when length > 0x110 outbuffer[bufferlength] = 0x10 outbuffer[bufferlength] |= ((length - 0x111) >> 12) & 0x0F bufferlength += 1 outbuffer[bufferlength] = ((length - 0x111) >> 4) & 0xFF bufferlength += 1 outbuffer[bufferlength] = ((length - 0x111) << 4) & 0xF0 when length > 0x10 outbuffer[bufferlength] = 0x00 outbuffer[bufferlength] |= ((length - 0x111) >> 4) & 0x0F bufferlength += 1 outbuffer[bufferlength] = ((length - 0x111) << 4) & 0xF0 else outbuffer[bufferlength] = ((length - 1) << 4) & 0xF0 end outbuffer[bufferlength] |= ((disp - 1) >> 8) & 0x0F bufferlength += 1 outbuffer[bufferlength] = (disp - 1) & 0xFF bufferlength += 1 end bufferedBlocks += 1 end if bufferedBlocks > 0 outstream.write(outbuffer[0, bufferlength]) end outstream.buf end |
#decompress ⇒ Array<Integer>, Symbol
Decompresses an LZ11 archive.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/feh/bin/lz11.rb', line 24 def decompress header = buf.u32 return :invalid_data if (header & 0xFF) != 0x11 decompressedSize = header >> 8 decompressedSize = buf.u32 if decompressedSize == 0 bufferLength = 0x1000 buffer = Array.new(bufferLength) bufferOffset = 0 flags = 0 mask = 1 outbuf = [] until outbuf.size >= decompressedSize if mask == 1 flags = buf.u8 return :stream_too_short if flags.nil? mask = 0x80 else mask >>= 1 end if (flags & mask) > 0 byte1 = buf.u8 return :stream_too_short if byte1.nil? length = byte1 >> 4 disp = -1 case length when 0 byte2 = buf.u8 byte3 = buf.u8 return :stream_too_short if byte3.nil? length = (((byte1 & 0x0F) << 4) | (byte2 >> 4)) + 0x11 disp = (((byte2 & 0x0F) << 8) | byte3) + 0x1 when 1 byte2 = buf.u8 byte3 = buf.u8 byte4 = buf.u8 return :stream_too_short if byte4.nil? length = (((byte1 & 0x0F) << 12) | (byte2 << 4) | (byte3 >> 4)) + 0x111 disp = (((byte3 & 0x0F) << 8) | byte4) + 0x1 else byte2 = buf.u8 return :stream_too_short if byte2.nil? length = ((byte1 & 0xF0) >> 4) + 0x1 disp = (((byte1 & 0x0F) << 8) | byte2) + 0x1 end return :invalid_data if disp > outbuf.size bufIdx = bufferOffset + bufferLength - disp length.times do next_byte = buffer[bufIdx % bufferLength] bufIdx += 1 outbuf << next_byte buffer[bufferOffset] = next_byte bufferOffset = (bufferOffset + 1) % bufferLength end else next_byte = buf.u8 return :stream_too_short if next_byte.nil? outbuf << next_byte buffer[bufferOffset] = next_byte bufferOffset = (bufferOffset + 1) % bufferLength end end outbuf end |