Adding modding folder with a hacked build.

This commit is contained in:
ml
2026-09-26 08:53:08 +02:00
parent cdb960dc71
commit c91080aba7
755 changed files with 50424 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
package rle
import "io"
// Compress compresses the given byte array into the given writer.
// The optional reference array is used as a delta basis. If provided, bytes will be skipped
// where the data equals the reference.
func Compress(writer io.Writer, data []byte, reference []byte) error {
end := len(data)
refLen := len(reference)
ref := func(index int) byte {
if index < refLen {
return reference[index]
}
return 0x00
}
countIdenticalBytes := func(from int) int {
index := from
for (index < end) && (data[index] == ref(index)) {
index++
}
return index - from
}
countConstantBytes := func(from int, value byte) int {
index := from
for (index < end) && (data[index] == value) {
index++
}
return index - from
}
{
trailingSkip := 0
for temp := end - 1; (temp >= 0) && (data[temp] == ref(temp)); temp-- {
trailingSkip++
}
end -= trailingSkip % 0x7FFF
}
start := 0
for start < end {
identicalByteCount := countIdenticalBytes(start)
constByteCount := countConstantBytes(start, data[start])
switch {
case identicalByteCount > 3:
err := skipBytes(writer, identicalByteCount)
if err != nil {
return err
}
start += identicalByteCount
case constByteCount > 3:
err := writeConstant(writer, constByteCount, data[start])
if err != nil {
return err
}
start += constByteCount
default:
diffByteCount := 0
abort := false
for (start+diffByteCount) < end && !abort {
nextIdenticalByteCount := countIdenticalBytes(start + diffByteCount)
nextConstByteCount := countConstantBytes(start+diffByteCount, data[start+diffByteCount])
if nextIdenticalByteCount < 4 && nextConstByteCount < 4 {
if nextIdenticalByteCount > nextConstByteCount {
diffByteCount += nextIdenticalByteCount
} else {
diffByteCount += nextConstByteCount
}
} else {
abort = true
}
}
err := writeRaw(writer, data[start:start+diffByteCount])
if err != nil {
return err
}
start += diffByteCount
}
}
return writeExtended(writer, 0x0000)
}
func writeExtended(writer io.Writer, control uint16, extra ...byte) error {
_, err := writer.Write([]byte{0x80, byte(control & 0xFF), byte((control >> 8) & 0xFF)})
if err != nil {
return err
}
_, err = writer.Write(extra)
return err
}
func skipBytes(writer io.Writer, size int) error {
remain := size
for remain > 0 {
if remain < 0x80 {
_, err := writer.Write([]byte{byte(0x80 + remain)})
if err != nil {
return err
}
remain = 0
} else {
lenControl := 0x7FFF
if remain < lenControl {
lenControl = remain
}
err := writeExtended(writer, uint16(lenControl))
if err != nil {
return err
}
remain -= lenControl
}
}
return nil
}
func writeConstant(writer io.Writer, size int, value byte) error {
start := 0
for start < size {
remain := size - start
if remain < 0x100 {
_, err := writer.Write([]byte{0x00, byte(remain), value})
if err != nil {
return err
}
start = size
} else {
lenControl := 0x3FFF
if remain < lenControl {
lenControl = remain
}
err := writeExtended(writer, 0xC000+uint16(lenControl), value)
if err != nil {
return err
}
start += lenControl
}
}
return nil
}
func writeRaw(writer io.Writer, data []byte) error {
end := len(data)
start := 0
for start < end {
remain := end - start
if remain < 0x80 {
_, err := writer.Write([]byte{byte(remain)})
if err != nil {
return err
}
_, err = writer.Write(data[start:])
if err != nil {
return err
}
start = end
} else {
lenControl := 0x3FFF
if remain < lenControl {
lenControl = remain
}
err := writeExtended(writer, 0x8000+uint16(lenControl), data[start:start+lenControl]...)
if err != nil {
return err
}
start += lenControl
}
}
return nil
}
@@ -0,0 +1,79 @@
package rle_test
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
"github.com/inkyblackness/hacked/ss1/serial/rle"
)
func TestCompressEmptyArrayResultsInTerminator(t *testing.T) {
writer := bytes.NewBuffer(nil)
err := rle.Compress(writer, nil, nil)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x80, 0x00, 0x00}, writer.Bytes())
}
func TestCompressOfZeroBytesLong(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := make([]byte, 1000)
input[len(input)-1] = 1
err := rle.Compress(writer, input, nil)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x80, 0xE7, 0x03, 0x01, 0x01, 0x80, 0x0, 0x0}, writer.Bytes())
}
func TestCompressOfEqualBytesLong(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := make([]byte, 1000)
for i := 0; i < len(input); i++ {
input[i] = 0xAA
}
input[len(input)-1] = 1
err := rle.Compress(writer, input, nil)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x80, 0xE7, 0xC3, 0xAA, 0x01, 0x01, 0x80, 0x0, 0x0}, writer.Bytes())
}
func TestCompressOfEqualBytesShort(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := make([]byte, 40)
for i := 0; i < len(input); i++ {
input[i] = 0xAA
}
input[len(input)-1] = 1
err := rle.Compress(writer, input, nil)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x00, 0x27, 0xAA, 0x01, 0x01, 0x80, 0x0, 0x0}, writer.Bytes())
}
func TestCompressOfRandomBytesShort(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := make([]byte, 10)
for i := 0; i < len(input); i++ {
input[i] = byte(i)
}
err := rle.Compress(writer, input, nil)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x00, 0x00}, writer.Bytes())
}
func TestCompressWithIdenticalReference(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := []byte{0xAA, 0xBB, 0xCC, 0xDD}
reference := input
err := rle.Compress(writer, input, reference)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x80, 0x00, 0x00}, writer.Bytes())
}
func TestCompressWithPartlyIdenticalReference(t *testing.T) {
writer := bytes.NewBuffer(nil)
input := []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
reference := []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x0A}
err := rle.Compress(writer, input, reference)
assert.Nil(t, err, "no error expected")
assert.Equal(t, []byte{0x85, 0x01, 0xFF, 0x80, 0x00, 0x00}, writer.Bytes())
}
@@ -0,0 +1,67 @@
package rle
import (
"io"
"github.com/inkyblackness/hacked/ss1"
)
const (
errUndefinedCase ss1.StringError = "undefined case 80 nn C0"
)
// Decompress decompresses from the given reader and writes into the provided output buffer.
// The output buffer must be pre-allocated.
// If it contains non-zero data, this data may be preserved if the compressed data specifies to.
func Decompress(reader io.Reader, output []byte) (err error) {
outIndex := 0
done := false
nextByte := func() byte {
zz := []byte{0x00}
_, err = reader.Read(zz)
return zz[0]
}
for !done && (err == nil) {
first := nextByte()
switch {
case first == 0x00:
nn := nextByte()
zz := nextByte()
outIndex += writeBytesOfValue(output[outIndex:outIndex+int(nn)], func() byte { return zz })
case first < 0x80:
outIndex += writeBytesOfValue(output[outIndex:outIndex+int(first)], nextByte)
case first == 0x80:
control := uint16(nextByte())
control += uint16(nextByte()) << 8
switch {
case control == 0x0000:
done = true
case control < 0x8000:
outIndex += int(control)
case control < 0xC000:
outIndex += writeBytesOfValue(output[outIndex:outIndex+int(control&0x3FFF)], nextByte)
case (control & 0xFF00) == 0xC000:
err = errUndefinedCase
default:
zz := nextByte()
outIndex += writeBytesOfValue(output[outIndex:outIndex+int(control&0x3FFF)], func() byte { return zz })
}
default:
outIndex += int(first & 0x7F)
}
}
return
}
func writeBytesOfValue(buffer []byte, producer func() byte) int {
count := len(buffer)
for i := 0; i < count; i++ {
buffer[i] = producer()
}
return count
}
@@ -0,0 +1,146 @@
package rle_test
import (
"bytes"
"testing"
"github.com/inkyblackness/hacked/ss1/serial/rle"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDecompressEmptyArrayReturnsError(t *testing.T) {
err := rle.Decompress(bytes.NewReader(nil), make([]byte, 100))
assert.NotNil(t, err)
}
func TestDecompress800000IsEndOfStream(t *testing.T) {
var result []byte
err := rle.Decompress(bytes.NewReader([]byte{0x80, 0x00, 0x00}), result)
assert.Nil(t, err)
}
func TestDecompress800000AppendsRemainingZeroes(t *testing.T) {
result := make([]byte, 10)
err := rle.Decompress(bytes.NewReader([]byte{0x80, 0x00, 0x00}), result)
require.Nil(t, err)
assert.Equal(t, make([]byte, 10), result)
}
func TestDecompress800000IsConsumedAtEnd(t *testing.T) {
var result []byte
reader := bytes.NewReader([]byte{0x80, 0x00, 0x00})
err := rle.Decompress(reader, result)
require.Nil(t, err)
pos, _ := reader.Seek(0, 1)
assert.Equal(t, int64(3), pos)
}
func TestDecompress00WritesNNBytesOfColorZZ(t *testing.T) {
result := make([]byte, 5)
err := rle.Decompress(bytes.NewReader([]byte{0x00, 0x05, 0xCC, 0x80, 0x00, 0x00}), result)
require.Nil(t, err)
assert.Equal(t, []byte{0xCC, 0xCC, 0xCC, 0xCC, 0xCC}, result)
}
func TestDecompress00ReturnsErrorIfZZIsMissing(t *testing.T) {
err := rle.Decompress(bytes.NewReader([]byte{0x00, 0x05}), make([]byte, 5))
assert.NotNil(t, err)
}
func TestDecompress00ReturnsErrorIfNNIsMissing(t *testing.T) {
err := rle.Decompress(bytes.NewReader([]byte{0x00}), make([]byte, 5))
assert.NotNil(t, err)
}
func TestDecompressNNLess80WritesNNFollowingBytes(t *testing.T) {
result := make([]byte, 2)
err := rle.Decompress(bytes.NewReader([]byte{0x02, 0xAA, 0xBB, 0x80, 0x00, 0x00}), result)
require.Nil(t, err)
assert.Equal(t, []byte{0xAA, 0xBB}, result)
}
func TestDecompressNNLess80ReturnsErrorIfEndOfFile(t *testing.T) {
err := rle.Decompress(bytes.NewReader([]byte{0x02, 0xAA}), make([]byte, 2))
assert.NotNil(t, err)
}
func TestDecompress80NNNNSkipsBytes(t *testing.T) {
expected := make([]byte, 0x123)
result := make([]byte, 0x123)
for i := 0; i < len(result); i++ {
result[i] = byte(i)
}
copy(expected, result)
err := rle.Decompress(bytes.NewReader([]byte{0x80, 0x23, 0x01, 0x80, 0x00, 0x00}), result)
require.Nil(t, err)
assert.Equal(t, expected, result)
}
func TestDecompress80CopiesNNBytes(t *testing.T) {
input := bytes.NewBuffer(nil)
input.Write([]byte{0x80, 0x04, 0x80})
input.Write([]byte{0x01, 0x02, 0x03, 0x04})
input.Write([]byte{0x80, 0x00, 0x00})
result := make([]byte, 4)
err := rle.Decompress(bytes.NewReader(input.Bytes()), result)
require.Nil(t, err)
assert.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, result)
}
func TestDecompress80CopiesNNBytesExtended(t *testing.T) {
input := bytes.NewBuffer(nil)
expected := make([]byte, 0x3FFF)
input.Write([]byte{0x80, 0xFF, 0xBF})
input.Write(expected)
input.Write([]byte{0x80, 0x00, 0x00})
result := make([]byte, len(expected))
err := rle.Decompress(bytes.NewReader(input.Bytes()), result)
require.Nil(t, err)
assert.Equal(t, expected, result)
}
func TestDecompress80ReturnsErrorForUndefinedCase(t *testing.T) {
input := bytes.NewBuffer(nil)
input.Write([]byte{0x80, 0x00, 0xC0})
input.Write([]byte{0x80, 0x00, 0x00})
err := rle.Decompress(bytes.NewReader(input.Bytes()), make([]byte, 1))
assert.NotNil(t, err)
}
func TestDecompress80WritesNNBytesOfValue(t *testing.T) {
input := bytes.NewBuffer(nil)
expected := make([]byte, 0x3FFF)
for index := range expected {
expected[index] = 0xCD
}
input.Write([]byte{0x80, 0xFF, 0xFF, 0xCD})
input.Write([]byte{0x80, 0x00, 0x00})
result := make([]byte, len(expected))
err := rle.Decompress(bytes.NewReader(input.Bytes()), result)
require.Nil(t, err)
assert.Equal(t, expected, result)
}
func TestDecompressNNMore80WritesZeroes(t *testing.T) {
result := make([]byte, 3)
err := rle.Decompress(bytes.NewReader([]byte{0x83, 0x80, 0x00, 0x00}), result)
require.Nil(t, err)
assert.Equal(t, []byte{0, 0, 0}, result)
}
@@ -0,0 +1,83 @@
package rle_test
import (
"bytes"
"math/rand"
"testing"
"time"
"github.com/inkyblackness/hacked/ss1/serial/rle"
)
func benchmarkRecompression(b *testing.B, size int, chanceLimit byte, nameSuffix string, seed int64) {
b.Helper()
input := make([]byte, size)
reference := make([]byte, size)
var chance [1]byte
rand.Seed(seed) // nolint:gas
b.ResetTimer()
for run := 0; run < b.N; run++ {
b.StopTimer()
rand.Read(input) // nolint:gas
copy(reference, input)
for i := 0; i < size; i++ {
rand.Read(chance[:]) // nolint:gas
if chance[0] < chanceLimit {
input[i] = chance[0]
}
}
buf := bytes.NewBuffer(nil)
b.StartTimer()
err := rle.Compress(buf, input, reference)
if err != nil {
b.Errorf("Failed compression for %s in run %d of seed %v", nameSuffix, run, seed)
}
err = rle.Decompress(bytes.NewReader(buf.Bytes()), reference)
if err != nil {
b.Errorf("Failed decompression for %s in run %d of seed %v", nameSuffix, run, seed)
}
if !bytes.Equal(input, reference) {
b.Errorf("Data mismatch in %s in run %d of seed %v", nameSuffix, run, seed)
}
}
}
func BenchmarkRecompression64KB_10(b *testing.B) {
benchmarkRecompression(b, 1024*64, 10, "64KB,10", time.Now().UnixNano())
}
func BenchmarkRecompression64KB_128(b *testing.B) {
benchmarkRecompression(b, 1024*64, 128, "64KB,128", time.Now().UnixNano())
}
func BenchmarkRecompression1KB_0(b *testing.B) {
benchmarkRecompression(b, 1024, 0, "1KB,0", time.Now().UnixNano())
}
func BenchmarkRecompression1KB_10(b *testing.B) {
benchmarkRecompression(b, 1024, 10, "1KB,10", time.Now().UnixNano())
}
func BenchmarkRecompression1KB_128(b *testing.B) {
benchmarkRecompression(b, 1024, 128, "1KB,128", time.Now().UnixNano())
}
func BenchmarkRecompression1KB_255(b *testing.B) {
benchmarkRecompression(b, 1024, 255, "1KB,255", time.Now().UnixNano())
}
func BenchmarkRecompression128B_10(b *testing.B) {
benchmarkRecompression(b, 128, 10, "128B,10", time.Now().UnixNano())
}
func BenchmarkRecompression128B_128(b *testing.B) {
benchmarkRecompression(b, 128, 128, "128B,128", time.Now().UnixNano())
}
func BenchmarkRecompression128B_255(b *testing.B) {
benchmarkRecompression(b, 128, 255, "128B,255", time.Now().UnixNano())
}