blob: 52b28374bd92ae40506eda8583444d031cb537d1 [file]
package io
import base.Endianness
import base.Endianness.BIG
import base.Endianness.LITTLE
import base.toLongUnsigned
import java.io.ByteArrayOutputStream
import java.io.EOFException
import java.io.InputStream
import java.io.PushbackInputStream
/** Returns new input stream which will read up-to the given number of bytes from this stream. */
fun InputStream.newWithLimit(limit: Int): InputStream = let { base ->
object : InputStream() {
var remaining = limit
override fun read(): Int = when (remaining) {
0 -> -1
else -> base.read().also {
if (it != -1) {
remaining -= 1
}
}
}
}
}
/**
* Invokes the given function with an input stream which will read exactly the given number of bytes
* from this stream.
*/
fun <V> InputStream.readWithSize(size: Int, fn: InputStream.() -> V): V =
newWithLimit(size).let { stream ->
stream.fn().also { stream.skipAll() }
}
fun InputStream.readByteInt(): Int = read().takeIf { it != -1 } ?: throw EOFException()
fun InputStream.readByte(): Byte = readByteInt().toByte()
fun InputStream.readShortInt(endianness: Endianness): Int {
val i1 = this.readByteInt()
val i2 = this.readByteInt()
return when (endianness) {
LITTLE -> i2.shl(8).or(i1)
BIG -> i1.shl(8).or(i2)
}
}
fun InputStream.readShort(endianness: Endianness): Short =
readShortInt(endianness).toShort()
fun InputStream.readInt(endianness: Endianness): Int {
val i1 = readShortInt(endianness)
val i2 = readShortInt(endianness)
return when (endianness) {
LITTLE -> i2.shl(16).or(i1)
BIG -> i1.shl(16).or(i2)
}
}
fun InputStream.readLong(endianness: Endianness): Long {
val l1 = readInt(endianness).toLongUnsigned()
val l2 = readInt(endianness).toLongUnsigned()
return when (endianness) {
LITTLE -> l2.shl(32).or(l1)
BIG -> l1.shl(32).or(l2)
}
}
fun InputStream.readByteArray(size: Int): ByteArray =
ByteArray(size).also {
var off = 0
var len = size
while (true) {
if (len == 0) break
val read = read(it, off, len)
if (read == -1) throw EOFException()
off += read
len -= read
}
}
fun InputStream.skipAll() {
val byteArray = ByteArray(1024)
while (true) {
val read = read(byteArray)
if (read == -1) break
}
}
fun <V> InputStream.readList(size: Int, fn: InputStream.() -> V): List<V> =
buildList {
repeat(size) {
add(fn())
}
}
fun InputStream.readByteArray(): ByteArray =
ByteArrayOutputStream().also {
val byteArray = ByteArray(1024)
while (true) {
val read = read(byteArray)
if (read == -1) break
it.write(byteArray, 0, read)
}
}.toByteArray()
fun InputStream.readCString(): String =
ByteArrayOutputStream().also {
while (true) {
val byte = this.readByteInt()
if (byte == 0) break
it.write(byte)
}
}.toByteArray().toString(Charsets.UTF_8)
fun PushbackInputStream.peek(): Int = read().also { unread(it) }
fun PushbackInputStream.isEof(): Boolean =
peek() == -1
fun <V> PushbackInputStream.readList(fn: PushbackInputStream.() -> V): List<V> =
buildList {
while (!isEof()) {
add(fn())
}
}