Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8787b83
Merge pull request #16 from runetopic/development
ultraviolet-jordan Sep 30, 2021
50c7335
Merge pull request #17 from runetopic/development
ultraviolet-jordan Oct 16, 2021
629635f
Merge pull request #18 from runetopic/development
ultraviolet-jordan Oct 19, 2021
8fec609
Merge pull request #19 from runetopic/development
ultraviolet-jordan Oct 23, 2021
47f99c8
Add start to cache writing and push branch.
ultraviolet-jordan Oct 24, 2021
747c68e
Merge pull request #20 from runetopic/development
ultraviolet-jordan Oct 24, 2021
7fa3b4b
Merge branch 'development' of github.com:xlite2/cache-lib into featur…
ultraviolet-jordan Oct 26, 2021
5a832f0
Refactor some of the code for decoding/encoding the data to build an …
ultraviolet-jordan Oct 26, 2021
02bb1c7
Merge pull request #22 from runetopic/development
ultraviolet-jordan Oct 26, 2021
d8f26e5
Add more testing for DatIndexSector.
ultraviolet-jordan Oct 26, 2021
1c12077
Add more tests to DatIndexSector and more work to the encoding.
ultraviolet-jordan Oct 31, 2021
7eca120
Update to Kotlin 1.5.31 and update README.md.
ultraviolet-jordan Oct 31, 2021
9893df4
Removing dat file
ultraviolet-jordan Nov 2, 2021
a81c36a
Merging
ultraviolet-jordan Nov 2, 2021
6623f6e
Update README.md
ultraviolet-jordan Jan 1, 2022
ae5ae4c
Fixing java version
tyler27 Jan 2, 2022
6cf4283
Merge branch 'main' of github.com:runetopic/cache-lib into feature/wr…
ultraviolet-jordan Jan 4, 2022
ccfd73a
Format.
ultraviolet-jordan Jan 4, 2022
e49e5b5
Cache and Loader code refactor.
ultraviolet-jordan Jan 4, 2022
d87da6f
Update README.md
tyler27 Jan 4, 2022
ea752f5
Update README.md
tyler27 Jan 4, 2022
14dbbce
Pulling README.md changes from master
tyler27 Jan 5, 2022
8731b24
Removing IInterface pattern
tyler27 Jan 5, 2022
9cd8c56
Fixing failing test
tyler27 Jan 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cache/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,7 @@ dependencies {
implementation("org.slf4j:slf4j-simple:1.7.32")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.+")
implementation("com.runetopic.cryptography:cryptography:1.0.6-SNAPSHOT")

testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("io.mockk:mockk:1.12.0")
}
18 changes: 18 additions & 0 deletions cache/src/main/kotlin/com/runetopic/cache/extension/ByteBuffer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,27 @@ internal fun ByteBuffer.readUnsignedByte(): Int = get().toInt() and 0xFF
internal fun ByteBuffer.readUnsignedShort(): Int = short.toInt() and 0xFFFF
internal fun ByteBuffer.readUnsignedMedium(): Int = ((readUnsignedByte() shl 16) or (readUnsignedByte() shl 8) or readUnsignedByte())
internal fun ByteBuffer.readUnsignedIntShortSmart(): Int = if (get(position()).toInt() < 0) int and Int.MAX_VALUE else readUnsignedShort()
internal fun ByteBuffer.putIntShortSmart(value: Int) {
val buffer = when {
value >= Short.MAX_VALUE -> ByteBuffer.allocate(Int.SIZE_BYTES).putInt(value - Int.MAX_VALUE - 1)
else -> ByteBuffer.allocate(Short.SIZE_BYTES).putShort(if (value >= 0) value.toShort() else Short.MAX_VALUE)
}
put(buffer)
}

internal fun ByteBuffer.remainingBytes(): ByteArray {
val bytes = ByteArray(remaining())
get(bytes)
return bytes
}

class Variable {
companion object {
internal fun asSizeBytes(
Comment thread
ultraviolet-jordan marked this conversation as resolved.
Outdated
protocol: Int,
value: Int
): Int {
return if (protocol >= 7) if (value >= Short.MAX_VALUE) 4 else 2 else 2
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ data class Index(
val protocol: Int,
val revision: Int,
val isNamed: Boolean,
val isUsingWhirlpool: Boolean,
private val groups: Map<Int, Group>
): Comparable<Index> {

Expand Down Expand Up @@ -64,6 +65,6 @@ data class Index(
}

internal companion object {
fun default(indexId: Int): Index = Index(indexId, 0, ByteArray(64), -1, -1, 0, false, hashMapOf())
fun default(indexId: Int): Index = Index(indexId, 0, ByteArray(64), -1, -1, 0, false, false, hashMapOf())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package com.runetopic.cache.store.storage.js5
import com.runetopic.cache.codec.Container
import com.runetopic.cache.codec.decompress
import com.runetopic.cache.exception.ProtocolException
import com.runetopic.cache.extension.*
import com.runetopic.cache.extension.readUnsignedByte
import com.runetopic.cache.extension.readUnsignedIntShortSmart
import com.runetopic.cache.extension.readUnsignedShort
import com.runetopic.cache.extension.toByteBuffer
import com.runetopic.cache.hierarchy.index.Index
import com.runetopic.cache.hierarchy.index.group.Group
import com.runetopic.cache.hierarchy.index.group.file.File
Expand All @@ -29,11 +29,11 @@ internal fun decode(
protocol >= 6 -> buffer.int
else -> 0
}
val hash = buffer.readUnsignedByte()
val mask = buffer.readUnsignedByte()
val count = if (protocol >= 7) buffer.readUnsignedIntShortSmart() else buffer.readUnsignedShort()

val isNamed = (0x1 and hash) != 0
val isUsingWhirlpool = (0x2 and hash) != 0
val isNamed = (0x1 and mask) != 0
val isUsingWhirlpool = (0x2 and mask) != 0

val groupIds = decodeGroupIds(count, buffer, protocol)
val maxGroupId = (groupIds.maxOrNull() ?: -1) + 1
Expand Down Expand Up @@ -66,7 +66,7 @@ internal fun decode(
data
))
}
return Index(idxFile.id(), decompressed.crc, whirlpool, decompressed.compression, protocol, revision, isNamed, groups)
return Index(idxFile.id(), decompressed.crc, whirlpool, decompressed.compression, protocol, revision, isNamed, isUsingWhirlpool, groups)
}

private fun decodeGroupIds(
Expand All @@ -83,7 +83,7 @@ private fun decodeGroupIds(
return groupIds
}

private fun decodeGroupFileIds(
fun decodeGroupFileIds(
maxGroupId: Int,
count: Int,
groupIds: IntArray,
Expand All @@ -97,7 +97,7 @@ private fun decodeGroupFileIds(
return groupFileIds
}

private fun decodeGroupRevisions(
fun decodeGroupRevisions(
maxGroupId: Int,
count: Int,
groupIds: IntArray,
Expand All @@ -110,7 +110,7 @@ private fun decodeGroupRevisions(
return revisions
}

private fun decodeGroupWhirlpools(
fun decodeGroupWhirlpools(
maxGroupId: Int,
usesWhirlpool: Boolean,
count: Int,
Expand All @@ -128,7 +128,7 @@ private fun decodeGroupWhirlpools(
return whirlpools
}

private fun decodeGroupCrcs(
fun decodeGroupCrcs(
maxGroupId: Int,
count: Int,
groupIds: IntArray,
Expand All @@ -141,7 +141,7 @@ private fun decodeGroupCrcs(
return crcs
}

private fun decodeGroupNameHashes(
fun decodeGroupNameHashes(
maxGroupId: Int,
count: Int,
isNamed: Boolean,
Expand Down Expand Up @@ -187,12 +187,12 @@ private fun decodeFileNameHashes(
isNamed: Boolean
): Array<IntArray> {
val fileNameHashes = Array(maxGroupId) { IntArray(validFileIds[it]) }
if (isNamed) {
(0 until count).forEach {
val groupId = groupIds[it]
(0 until validFileIds[groupId]).forEach { fileId ->
fileNameHashes[groupId][fileId] = buffer.int
}
if (isNamed.not()) return fileNameHashes

(0 until count).forEach {
val groupId = groupIds[it]
(0 until validFileIds[groupId]).forEach { fileId ->
fileNameHashes[groupId][fileId] = buffer.int
}
}
return fileNameHashes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.runetopic.cache.store.storage.js5

import com.runetopic.cache.extension.Variable
import com.runetopic.cache.extension.putIntShortSmart
import com.runetopic.cache.hierarchy.index.Index
import java.nio.ByteBuffer

/**
* @author Jordan Abraham
*/
internal fun encode(
index: Index
): ByteBuffer {
val header = ByteBuffer.allocate(if (index.protocol >= 7) 6 else 4)
header.put(index.protocol.toByte())

val mask = 0x0
if (index.isNamed) mask or 0x1
if (index.isUsingWhirlpool) mask or 0x2
header.put(mask.toByte())

val count = index.groups().size
if (index.protocol >= 7) header.putIntShortSmart(count) else header.putShort(count.toShort())

val stream = index.groups().stream()
val groupIds = stream.map { it.id }.toList().toIntArray()
val nameHashes = stream.map { it.nameHash }.toList().toIntArray()
val crcs = stream.map { it.crc }.toList().toIntArray()
val whirlpools = stream.map { it.whirlpool }.toList().toTypedArray()
val revisions = stream.map { it.revision }.toList().toIntArray()

val groupNameHashes = encodeGroupNameHashes(count, index.isNamed, groupIds, nameHashes)
val groupCrcs = encodeGroupCrcs(count, groupIds, crcs)
val groupWhirlpools = encodeGroupWhirlpools(count, groupIds, index.isUsingWhirlpool, whirlpools)
val groupRevisions = encodeGroupRevisions(count, groupIds, revisions)

val buffer = ByteBuffer.allocate(header.position()
+ groupNameHashes.position()
+ groupCrcs.position()
+ groupWhirlpools.position()
+ groupRevisions.position())

buffer.put(header)
//TODO Group ids
buffer.put(groupNameHashes)
buffer.put(groupCrcs)
buffer.put(groupWhirlpools)
buffer.put(groupRevisions)
//TODO The rest
return buffer
}

fun encodeGroupFileIds(
count: Int,
groupIds: IntArray,
protocol: Int,
groupFileIds: IntArray
): ByteBuffer {
var capacity = 0
(0 until count).forEach {
capacity += Variable.asSizeBytes(protocol, groupFileIds[groupIds[it]])
}
val buffer = ByteBuffer.allocate(capacity)
(0 until count).forEach {
if (protocol >= 7) buffer.putIntShortSmart(groupFileIds[groupIds[it]]) else buffer.putShort(groupFileIds[groupIds[it]].toShort())
}
return buffer
}

fun encodeGroupRevisions(
count: Int,
groupIds: IntArray,
revisions: IntArray
): ByteBuffer {
val buffer = ByteBuffer.allocate(count * Int.SIZE_BYTES)
(0 until count).forEach {
buffer.putInt(revisions[groupIds[it]])
}
return buffer
}

fun encodeGroupWhirlpools(
count: Int,
groupIds: IntArray,
usesWhirlpool: Boolean,
whirlpools: Array<ByteArray>
): ByteBuffer {
if ((usesWhirlpool.not())) return ByteBuffer.allocate(0)

val buffer = ByteBuffer.allocate(count * 64)
(0 until count).forEach {
buffer.put(whirlpools[groupIds[it]])
}
return buffer
}

fun encodeGroupCrcs(
count: Int,
groupIds: IntArray,
crcs: IntArray
): ByteBuffer {
val buffer = ByteBuffer.allocate(count * Int.SIZE_BYTES)
(0 until count).forEach {
buffer.putInt(crcs[groupIds[it]])
}
return buffer
}

fun encodeGroupNameHashes(
count: Int,
isNamed: Boolean,
groupIds: IntArray,
nameHashes: IntArray
): ByteBuffer {
if (isNamed.not()) return ByteBuffer.allocate(0)

val buffer = ByteBuffer.allocate(count * Int.SIZE_BYTES)
(0 until count).forEach {
buffer.putInt(nameHashes[groupIds[it]])
}
return buffer
}

private fun encodeFileNameHashes(
count: Int,
groupIds: IntArray,
validFileIds: IntArray,
isNamed: Boolean,
fileNameHashes: Array<IntArray>
): ByteBuffer {
if (isNamed.not()) return ByteBuffer.allocate(0)
//TODO Figure out a way to calc the number of bytes without doing it like this.
var bytes = 0
(0 until count).forEach {
(0 until validFileIds[groupIds[it]]).forEach { _ ->
bytes += Int.SIZE_BYTES
}
}
val buffer = ByteBuffer.allocate(bytes)
(0 until count).forEach {
val groupId = groupIds[it]
(0 until validFileIds[groupId]).forEach { fileId ->
buffer.putInt(fileNameHashes[groupId][fileId])
}
}
return buffer
}
Loading