Open-source multiplayer game server compatible with the RuneScape client https://www.openrs2.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
openrs2/compress/src/main/kotlin/org/openrs2/compress/gzip/GzipLaxInputStream.kt

117 lines
2.9 KiB

package org.openrs2.compress.gzip
import java.io.DataInputStream
import java.io.IOException
import java.io.InputStream
import java.util.zip.Inflater
public class GzipLaxInputStream(
private val input: InputStream
) : InputStream() {
private val inflater = Inflater(true)
private val buffer = ByteArray(4096)
private var checkedTrailer = false
init {
val dataInput = DataInputStream(input)
if (dataInput.readUnsignedShort() != HEADER_MAGIC) {
throw IOException("Invalid GZIP header magic")
} else if (dataInput.readUnsignedByte() != METHOD_DEFLATE) {
throw IOException("Unsupported compression method")
}
val flags = dataInput.readUnsignedByte()
dataInput.skip(6)
if ((flags and FLAG_EXTRA) != 0) {
dataInput.skip(dataInput.readUnsignedShort().toLong())
}
if ((flags and FLAG_NAME) != 0) {
while (dataInput.readUnsignedByte() != 0) {
// empty
}
}
if ((flags and FLAG_COMMENT) != 0) {
while (dataInput.readUnsignedByte() != 0) {
// empty
}
}
if ((flags and FLAG_HEADER_CRC) != 0) {
dataInput.skip(2)
}
}
override fun read(): Int {
val n = read(buffer, 0, 1)
return if (n < 0) {
-1
} else {
buffer[0].toInt() and 0xFF
}
}
override fun read(b: ByteArray, off: Int, len: Int): Int {
while (true) {
val n = inflater.inflate(b, off, len)
if (n != 0) {
return n
}
when {
inflater.finished() -> {
checkTrailer()
return -1
}
inflater.needsInput() -> fill()
inflater.needsDictionary() -> throw IOException("Dictionaries not supported")
}
}
}
override fun close() {
inflater.end()
input.close()
}
private fun fill() {
val n = input.read(buffer, 0, buffer.size)
if (n < 0) {
throw IOException("Compressed data truncated")
}
inflater.setInput(buffer, 0, n)
}
private fun checkTrailer() {
if (checkedTrailer) {
return
}
checkedTrailer = true
var len = TRAILER_LEN
len -= inflater.remaining
if (len < 0) {
throw IOException("Compressed data overflow")
} else if (input.skip(len) != len) {
throw IOException("GZIP trailer missing")
}
}
private companion object {
private const val HEADER_MAGIC = 0x1F8B
private const val METHOD_DEFLATE = 8
private const val FLAG_HEADER_CRC = 0x2
private const val FLAG_EXTRA = 0x4
private const val FLAG_NAME = 0x8
private const val FLAG_COMMENT = 0x10
private const val TRAILER_LEN = 8L
}
}