68 lines
1.6 KiB
Go
68 lines
1.6 KiB
Go
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
|
|
}
|