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

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
}
}