forked from openrs2/openrs2
Equivalent to the built-in GZIPOutputStream, except it produces output that is bit-for-bit identical to Jagex's implementation. Signed-off-by: Graham <gpe@openrs2.org>bzip2
parent
a761a26cc8
commit
6c508922fc
@ -0,0 +1,75 @@ |
||||
package org.openrs2.compress.gzip |
||||
|
||||
import com.google.common.io.LittleEndianDataOutputStream |
||||
import java.io.DataOutputStream |
||||
import java.io.OutputStream |
||||
import java.util.zip.CRC32 |
||||
import java.util.zip.Deflater |
||||
|
||||
public class JagexGzipOutputStream( |
||||
private val output: OutputStream |
||||
) : OutputStream() { |
||||
private val deflater = Deflater(Deflater.DEFAULT_COMPRESSION, true) |
||||
private val buffer = ByteArray(4096) |
||||
private val checksum = CRC32() |
||||
private var size = 0 |
||||
private var closed = false |
||||
|
||||
init { |
||||
val dataOutput = DataOutputStream(output) |
||||
dataOutput.writeShort(HEADER_MAGIC) |
||||
dataOutput.writeByte(METHOD_DEFLATE) |
||||
dataOutput.writeByte(0) // FLG |
||||
dataOutput.writeInt(0) // MTIME |
||||
dataOutput.writeByte(0) // XFL |
||||
dataOutput.writeByte(0) // OS |
||||
} |
||||
|
||||
override fun write(b: Int) { |
||||
buffer[0] = b.toByte() |
||||
write(buffer, 0, 1) |
||||
} |
||||
|
||||
override fun write(b: ByteArray, off: Int, len: Int) { |
||||
checksum.update(b, off, len) |
||||
size += len |
||||
|
||||
deflater.setInput(b, off, len) |
||||
|
||||
while (!deflater.needsInput()) { |
||||
drain() |
||||
} |
||||
} |
||||
|
||||
private fun drain() { |
||||
val n = deflater.deflate(buffer) |
||||
if (n != 0) { |
||||
output.write(buffer, 0, n) |
||||
} |
||||
} |
||||
|
||||
override fun close() { |
||||
if (!closed) { |
||||
deflater.finish() |
||||
|
||||
while (!deflater.finished()) { |
||||
drain() |
||||
} |
||||
|
||||
val dataOutput = LittleEndianDataOutputStream(output) |
||||
dataOutput.writeInt(checksum.value.toInt()) |
||||
dataOutput.writeInt(size) |
||||
|
||||
deflater.end() |
||||
output.close() |
||||
|
||||
closed = true |
||||
} |
||||
} |
||||
|
||||
private companion object { |
||||
private const val HEADER_MAGIC = 0x1F8B |
||||
|
||||
private const val METHOD_DEFLATE = 8 |
||||
} |
||||
} |
Loading…
Reference in new issue