Add extension methods for reading/writing null-terminated Cp1252 strings

Signed-off-by: Graham <gpe@openrs2.org>
bzip2
Graham 4 years ago
parent bdbfb61590
commit ea725b3881
  1. 1
      buffer/build.gradle.kts
  2. 37
      buffer/src/main/kotlin/org/openrs2/buffer/ByteBufExtensions.kt
  3. 122
      buffer/src/test/kotlin/org/openrs2/buffer/ByteBufExtensionsTest.kt

@ -7,6 +7,7 @@ dependencies {
api(libs.guice)
api(libs.netty.buffer)
implementation(projects.util)
implementation(libs.guava)
}

@ -4,9 +4,13 @@ import com.google.common.base.Preconditions
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
import io.netty.util.ByteProcessor
import org.openrs2.util.charset.Cp1252Charset
import java.nio.charset.Charset
import java.util.zip.CRC32
private const val STRING_VERSION = 0
public fun wrappedBuffer(vararg bytes: Byte): ByteBuf {
return Unpooled.wrappedBuffer(bytes)
}
@ -91,6 +95,39 @@ public fun ByteBuf.writeUnsignedIntSmart(v: Int): ByteBuf {
return this
}
public fun ByteBuf.readString(): String {
val start = readerIndex()
val end = forEachByte(ByteProcessor.FIND_NUL)
require(end != -1) {
"Unterminated string"
}
val s = toString(start, end - start, Cp1252Charset)
readerIndex(end + 1)
return s
}
public fun ByteBuf.writeString(s: CharSequence): ByteBuf {
writeCharSequence(s, Cp1252Charset)
writeByte(0)
return this
}
public fun ByteBuf.readVersionedString(): String {
val version = readUnsignedByte().toInt()
require(version == STRING_VERSION) {
"Unsupported version number $version"
}
return readString()
}
public fun ByteBuf.writeVersionedString(s: CharSequence): ByteBuf {
writeByte(STRING_VERSION)
writeString(s)
return this
}
public fun ByteBuf.crc32(): Int {
return crc32(readerIndex(), readableBytes())
}

@ -407,6 +407,128 @@ class ByteBufExtensionsTest {
}
}
@Test
fun testReadString() {
wrappedBuffer(0).use { buf ->
assertEquals("", buf.readString())
assertFalse(buf.isReadable)
}
wrappedBuffer(
214.toByte(),
'p'.code.toByte(),
'e'.code.toByte(),
'n'.code.toByte(),
'R'.code.toByte(),
'S'.code.toByte(),
'2'.code.toByte(),
0
).use { buf ->
assertEquals("ÖpenRS2", buf.readString())
assertFalse(buf.isReadable)
}
assertFailsWith<IllegalArgumentException> {
Unpooled.EMPTY_BUFFER.readString()
}
}
@Test
fun testWriteString() {
ByteBufAllocator.DEFAULT.buffer().use { actual ->
actual.writeString("")
wrappedBuffer(0).use { expected ->
assertEquals(expected, actual)
}
}
ByteBufAllocator.DEFAULT.buffer().use { actual ->
actual.writeString("ÖpenRS2")
wrappedBuffer(
214.toByte(),
'p'.code.toByte(),
'e'.code.toByte(),
'n'.code.toByte(),
'R'.code.toByte(),
'S'.code.toByte(),
'2'.code.toByte(),
0
).use { expected ->
assertEquals(expected, actual)
}
}
}
@Test
fun testReadVersionedString() {
wrappedBuffer(0, 0).use { buf ->
assertEquals("", buf.readVersionedString())
assertFalse(buf.isReadable)
}
wrappedBuffer(
0,
214.toByte(),
'p'.code.toByte(),
'e'.code.toByte(),
'n'.code.toByte(),
'R'.code.toByte(),
'S'.code.toByte(),
'2'.code.toByte(),
0
).use { buf ->
assertEquals("ÖpenRS2", buf.readVersionedString())
assertFalse(buf.isReadable)
}
assertFailsWith<IndexOutOfBoundsException> {
Unpooled.EMPTY_BUFFER.readVersionedString()
}
wrappedBuffer(0).use { buf ->
assertFailsWith<IllegalArgumentException> {
buf.readVersionedString()
}
}
wrappedBuffer(1, 0).use { buf ->
assertFailsWith<IllegalArgumentException> {
buf.readVersionedString()
}
}
}
@Test
fun testWriteVersionedString() {
ByteBufAllocator.DEFAULT.buffer().use { actual ->
actual.writeVersionedString("")
wrappedBuffer(0, 0).use { expected ->
assertEquals(expected, actual)
}
}
ByteBufAllocator.DEFAULT.buffer().use { actual ->
actual.writeVersionedString("ÖpenRS2")
wrappedBuffer(
0,
214.toByte(),
'p'.code.toByte(),
'e'.code.toByte(),
'n'.code.toByte(),
'R'.code.toByte(),
'S'.code.toByte(),
'2'.code.toByte(),
0
).use { expected ->
assertEquals(expected, actual)
}
}
}
@Test
fun testCrc32() {
val s = "AAThe quick brown fox jumps over the lazy dogA"

Loading…
Cancel
Save