Skip to content

Commit

Permalink
Improve initializing and ending z_stream
Browse files Browse the repository at this point in the history
  • Loading branch information
lukellmann committed Mar 25, 2024
1 parent 450323e commit 3944b8d
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions gateway/src/nativeMain/kotlin/Inflater.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,33 @@ import io.ktor.websocket.*
import kotlinx.cinterop.*
import platform.zlib.*

private const val MAX_WBITS = 15 // Maximum window size in bits
private const val CHUNK_SIZE = 256 * 1000
private val ZLIB_SUFFIX = ubyteArrayOf(0x00u, 0x00u, 0xffu, 0xffu)

internal actual fun Inflater(): Inflater = NativeInflater()

@OptIn(ExperimentalForeignApi::class)
private class NativeInflater : Inflater {
// see https://www.zlib.net/manual.html

private var frameBuffer = UByteArray(0)

private val zStream = nativeHeap.alloc<z_stream>().apply {
inflateInit2(ptr, MAX_WBITS).check {
nativeHeap.free(this)
private val zStream = nativeHeap.alloc<z_stream>().also { zStream ->
// next_in, avail_in, zalloc, zfree and opaque must be initialized before calling inflateInit
zStream.next_in = null
zStream.avail_in = 0u
zStream.zalloc = null
zStream.zfree = null
zStream.opaque = null
// initialize msg just in case, we use it for throwing exceptions
zStream.msg = null
val ret = inflateInit(zStream.ptr)
if (ret != Z_OK) {
try {
throwZlibException(zStream.msg, ret)
} finally {
nativeHeap.free(zStream)
}
}
}

Expand Down Expand Up @@ -54,21 +68,31 @@ private class NativeInflater : Inflater {
}

override fun close() {
inflateEnd(zStream.ptr).check { nativeHeap.free(zStream) }
val ret = inflateEnd(zStream.ptr)
try {
if (ret != Z_OK) throwZlibException(zStream.msg, ret)
} finally {
nativeHeap.free(zStream)
}
}
}

@ExperimentalForeignApi
private fun Int.check(validCodes: List<Int> = listOf(Z_OK), cleanup: () -> Unit = {}) {
if (this !in validCodes) {
try {
throw ZLibException(zErrorMessage(this).toString())
throw ZlibException(zErrorMessage(this).toString())
} finally {
cleanup()
}
}
}

private class ZLibException(message: String?) : IllegalStateException(message)
private class ZlibException(message: String?) : IllegalStateException(message)

@OptIn(ExperimentalForeignApi::class)
@ExperimentalForeignApi
private fun zErrorMessage(errorCode: Int) = zError(errorCode)?.toKString() ?: errorCode

@ExperimentalForeignApi
private fun throwZlibException(msg: CPointer<ByteVar>?, ret: Int): Nothing =
throw ZlibException(msg?.toKString() ?: zError(ret)?.toKString() ?: ret.toString())

0 comments on commit 3944b8d

Please sign in to comment.