KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/io/Streams.kt

209 lines
3.6 KiB
Kotlin

package ru.dbotthepony.kstarbound.io
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import java.io.IOException
import java.io.InputStream
import java.io.RandomAccessFile
/**
* Читает Variable Length Integer как Long
*/
fun RandomAccessFile.readVarLong(): Long {
var result = 0L
var read = read()
while (true) {
result = (result shl 7) or (read.toLong() and 0x7FL)
if (read and 0x80 == 0) {
break
}
read = read()
}
return result
}
data class VarIntReadResult(val value: Int, val cells: Int)
/**
* Читает Variable Length Integer как Int
*/
fun RandomAccessFile.readVarInt(): Int {
var result = 0
var read = read()
while (true) {
result = (result shl 7) or (read and 0x7F)
if (read and 0x80 == 0) {
break
}
read = read()
}
return result
}
/**
* Читает Variable Length Integer как Int
*/
fun RandomAccessFile.readVarIntInfo(): VarIntReadResult {
var result = 0
var read = read()
var i = 1
while (true) {
result = (result shl 7) or (read and 0x7F)
if (read and 0x80 == 0) {
break
}
read = read()
i++
}
return VarIntReadResult(result, i)
}
/**
* Читает Variable Length Integer как Int
*/
fun InputStream.readVarIntInfo(): VarIntReadResult {
var result = 0
var read = read()
var i = 1
while (true) {
result = (result shl 7) or (read and 0x7F)
if (read and 0x80 == 0) {
break
}
read = read()
i++
}
return VarIntReadResult(result, i)
}
/**
* Читает Variable Length Integer как Long
*/
fun InputStream.readVarLong(): Long {
var result = 0L
var read = read()
while (true) {
result = (result shl 7) or (read.toLong() and 0x7FL)
if (read and 0x80 == 0) {
break
}
read = read()
}
return result
}
/**
* Читает Variable Length Integer как Int
*/
fun InputStream.readVarInt(): Int {
var result = 0
var read = read()
while (true) {
result = (result shl 7) or (read and 0x7F)
if (read and 0x80 == 0) {
break
}
read = read()
}
return result
}
fun RandomAccessFile.readString(length: Int): String {
require(length >= 0) { "Invalid length $length" }
val bytes = ByteArray(length)
try {
readFully(bytes)
} catch(err: Throwable) {
throw IOException("Tried to read string with length of $length", err)
}
return bytes.toString(Charsets.UTF_8)
}
fun InputStream.readString(length: Int, allowSmaller: Boolean = false): String {
require(length >= 0) { "Invalid length $length" }
val bytes = ByteArray(length)
try {
val read = readNBytes(bytes, 0, length)
if (!allowSmaller)
require(read == bytes.size) { "Read $read bytes, expected ${bytes.size}" }
} catch(err: Throwable) {
throw IOException("Tried to read string with length of $length", err)
}
return bytes.toString(Charsets.UTF_8)
}
fun RandomAccessFile.readCString(): String {
val bytes = ByteArrayList()
var read = read()
while (read != 0) {
bytes.add(read.toByte())
read = read()
}
return ByteArray(bytes.size).also {
for (i in it.indices) {
it[i] = bytes.getByte(i)
}
}.toString(Charsets.UTF_8)
}
fun InputStream.readCString(): String {
val bytes = ByteArrayList()
var read = read()
while (read != 0) {
bytes.add(read.toByte())
read = read()
}
return ByteArray(bytes.size).also {
for (i in it.indices) {
it[i] = bytes.getByte(i)
}
}.toString(Charsets.UTF_8)
}
fun InputStream.readByteChar(): Char {
return read().toChar()
}
fun InputStream.readHeader(header: String) {
for ((i, char) in header.withIndex()) {
val read = readByteChar()
if (read != char) {
throw IllegalArgumentException("Malformed header at byte $i: expected $char (${char.code}) got $read (${char.code})")
}
}
}