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.
272 lines
6.8 KiB
272 lines
6.8 KiB
package org.openrs2.buffer
|
|
|
|
import com.google.common.base.Preconditions
|
|
import io.netty.buffer.ByteBuf
|
|
import kotlin.math.min
|
|
|
|
public class BitBuf(
|
|
private val buf: ByteBuf
|
|
) : AutoCloseable {
|
|
private var readerIndex: Long = buf.readerIndex().toLong() shl LOG_BITS_PER_BYTE
|
|
private set(value) {
|
|
field = value
|
|
buf.readerIndex((readerIndex shr LOG_BITS_PER_BYTE).toInt())
|
|
}
|
|
|
|
private var writerIndex: Long = buf.writerIndex().toLong() shl LOG_BITS_PER_BYTE
|
|
private set(value) {
|
|
field = value
|
|
buf.writerIndex((writerIndex shr LOG_BITS_PER_BYTE).toInt())
|
|
}
|
|
|
|
public fun getBoolean(index: Long): Boolean {
|
|
return getBits(index, 1) != 0
|
|
}
|
|
|
|
public fun getBit(index: Long): Int {
|
|
return getBits(index, 1)
|
|
}
|
|
|
|
public fun getBits(index: Long, len: Int): Int {
|
|
Preconditions.checkArgument(len in 1..BITS_PER_INT)
|
|
|
|
if (index < 0 || (index + len) > capacity()) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
|
|
var value = 0
|
|
|
|
var remaining = len
|
|
var byteIndex = (index shr LOG_BITS_PER_BYTE).toInt()
|
|
var bitIndex = (index and MASK_BITS_PER_BYTE.toLong()).toInt()
|
|
|
|
while (remaining > 0) {
|
|
val n = min(BITS_PER_BYTE - bitIndex, remaining)
|
|
val shift = (BITS_PER_BYTE - (bitIndex + n)) and MASK_BITS_PER_BYTE
|
|
val mask = (1 shl n) - 1
|
|
|
|
val v = buf.getUnsignedByte(byteIndex).toInt()
|
|
value = value shl n
|
|
value = value or ((v shr shift) and mask)
|
|
|
|
remaining -= n
|
|
byteIndex++
|
|
bitIndex = 0
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
public fun readBoolean(): Boolean {
|
|
return readBits(1) != 0
|
|
}
|
|
|
|
public fun readBit(): Int {
|
|
return readBits(1)
|
|
}
|
|
|
|
public fun readBits(len: Int): Int {
|
|
checkReadableBits(len)
|
|
|
|
val value = getBits(readerIndex, len)
|
|
readerIndex += len
|
|
return value
|
|
}
|
|
|
|
public fun skipBits(len: Int): BitBuf {
|
|
checkReadableBits(len)
|
|
readerIndex += len
|
|
|
|
return this
|
|
}
|
|
|
|
public fun setBoolean(index: Long, value: Boolean): BitBuf {
|
|
if (value) {
|
|
setBits(index, 1, 1)
|
|
} else {
|
|
setBits(index, 1, 0)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
public fun setBit(index: Long, value: Int): BitBuf {
|
|
setBits(index, 1, value)
|
|
|
|
return this
|
|
}
|
|
|
|
public fun setBits(index: Long, len: Int, value: Int): BitBuf {
|
|
Preconditions.checkArgument(len in 1..BITS_PER_INT)
|
|
|
|
if (index < 0 || (index + len) > capacity()) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
|
|
var remaining = len
|
|
var byteIndex = (index shr LOG_BITS_PER_BYTE).toInt()
|
|
var bitIndex = (index and MASK_BITS_PER_BYTE.toLong()).toInt()
|
|
|
|
while (remaining > 0) {
|
|
val n = min(BITS_PER_BYTE - bitIndex, remaining)
|
|
val shift = (BITS_PER_BYTE - (bitIndex + n)) and MASK_BITS_PER_BYTE
|
|
val mask = (1 shl n) - 1
|
|
|
|
var v = buf.getUnsignedByte(byteIndex).toInt()
|
|
v = v and (mask shl shift).inv()
|
|
v = v or (((value shr (remaining - n)) and mask) shl shift)
|
|
buf.setByte(byteIndex, v)
|
|
|
|
remaining -= n
|
|
byteIndex++
|
|
bitIndex = 0
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
public fun writeBoolean(value: Boolean): BitBuf {
|
|
if (value) {
|
|
writeBits(1, 1)
|
|
} else {
|
|
writeBits(1, 0)
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
public fun writeBit(value: Int): BitBuf {
|
|
writeBits(1, value)
|
|
|
|
return this
|
|
}
|
|
|
|
public fun writeBits(len: Int, value: Int): BitBuf {
|
|
ensureWritable(len.toLong())
|
|
|
|
setBits(writerIndex, len, value)
|
|
writerIndex += len
|
|
|
|
return this
|
|
}
|
|
|
|
public fun writeZero(len: Int): BitBuf {
|
|
writeBits(len, 0)
|
|
|
|
return this
|
|
}
|
|
|
|
private fun checkReadableBits(len: Int) {
|
|
Preconditions.checkArgument(len >= 0)
|
|
|
|
if ((readerIndex + len) > writerIndex) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
}
|
|
|
|
public fun ensureWritable(len: Long): BitBuf {
|
|
Preconditions.checkArgument(len >= 0)
|
|
|
|
if ((writerIndex + len) > maxCapacity()) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
|
|
val currentByteIndex = writerIndex shr LOG_BITS_PER_BYTE
|
|
val nextByteIndex = (writerIndex + len + MASK_BITS_PER_BYTE) shr LOG_BITS_PER_BYTE
|
|
|
|
buf.ensureWritable((nextByteIndex - currentByteIndex).toInt())
|
|
|
|
return this
|
|
}
|
|
|
|
public fun readableBits(): Long {
|
|
return writerIndex - readerIndex
|
|
}
|
|
|
|
public fun writableBits(): Long {
|
|
return capacity() - writerIndex
|
|
}
|
|
|
|
public fun maxWritableBits(): Long {
|
|
return maxCapacity() - writerIndex
|
|
}
|
|
|
|
public fun capacity(): Long {
|
|
return buf.capacity().toLong() shl LOG_BITS_PER_BYTE
|
|
}
|
|
|
|
public fun capacity(len: Long): BitBuf {
|
|
buf.capacity((len shr LOG_BITS_PER_BYTE).toInt())
|
|
return this
|
|
}
|
|
|
|
public fun maxCapacity(): Long {
|
|
return buf.maxCapacity().toLong() shl LOG_BITS_PER_BYTE
|
|
}
|
|
|
|
public fun isReadable(): Boolean {
|
|
return readerIndex < writerIndex
|
|
}
|
|
|
|
public fun isReadable(len: Long): Boolean {
|
|
Preconditions.checkArgument(len >= 0)
|
|
return (readerIndex + len) <= writerIndex
|
|
}
|
|
|
|
public fun isWritable(): Boolean {
|
|
return writerIndex < capacity()
|
|
}
|
|
|
|
public fun isWritable(len: Long): Boolean {
|
|
Preconditions.checkArgument(len >= 0)
|
|
return (writerIndex + len) <= capacity()
|
|
}
|
|
|
|
public fun readerIndex(): Long {
|
|
return readerIndex
|
|
}
|
|
|
|
public fun readerIndex(index: Long): BitBuf {
|
|
if (index < 0 || index > writerIndex) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
|
|
readerIndex = index
|
|
return this
|
|
}
|
|
|
|
public fun writerIndex(): Long {
|
|
return writerIndex
|
|
}
|
|
|
|
public fun writerIndex(index: Long): BitBuf {
|
|
if (index < readerIndex || index > capacity()) {
|
|
throw IndexOutOfBoundsException()
|
|
}
|
|
|
|
writerIndex = index
|
|
return this
|
|
}
|
|
|
|
public fun clear(): BitBuf {
|
|
readerIndex = 0
|
|
writerIndex = 0
|
|
return this
|
|
}
|
|
|
|
override fun close() {
|
|
val bits = (((writerIndex + MASK_BITS_PER_BYTE) and MASK_BITS_PER_BYTE.toLong().inv()) - writerIndex).toInt()
|
|
if (bits != 0) {
|
|
writeZero(bits)
|
|
}
|
|
|
|
readerIndex = (readerIndex + MASK_BITS_PER_BYTE) and MASK_BITS_PER_BYTE.toLong().inv()
|
|
}
|
|
|
|
private companion object {
|
|
private const val LOG_BITS_PER_BYTE = 3
|
|
private const val BITS_PER_BYTE = 1 shl LOG_BITS_PER_BYTE
|
|
private const val MASK_BITS_PER_BYTE = BITS_PER_BYTE - 1
|
|
private const val BITS_PER_INT = 32
|
|
}
|
|
}
|
|
|