69 lines
1.5 KiB
Go
69 lines
1.5 KiB
Go
package compression
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"github.com/icza/bitio"
|
|
)
|
|
|
|
func FirmwareBlockCompress(data []byte, exhaustive bool) (output []byte, err error) {
|
|
if len(data) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
if len(data) > DataMaxSize {
|
|
return nil, errors.New("out of bounds input")
|
|
}
|
|
|
|
windowIndex := WindowInitialIndex
|
|
|
|
window := CreateWindow()
|
|
|
|
outputBuffer := bytes.NewBuffer(make([]byte, 0, DataMaxSize))
|
|
w := bitio.NewWriter(outputBuffer)
|
|
|
|
for len(data) > 0 {
|
|
// Find maximum pattern in window
|
|
|
|
offsetIndex, length := window.Find(windowIndex, data, exhaustive)
|
|
|
|
if offsetIndex != -1 {
|
|
// write false for not encoding a literal
|
|
if err = w.WriteBool(false); err != nil {
|
|
return nil, err
|
|
}
|
|
// write index in table
|
|
if err = w.WriteBits(uint64(offsetIndex), OffsetBits); err != nil {
|
|
return nil, err
|
|
}
|
|
// write size of match
|
|
if err = w.WriteBits(uint64(length-MaxUncoded), LengthBits); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
windowIndex = window.Set(windowIndex, data[:length])
|
|
data = data[length:]
|
|
} else {
|
|
// write true for encoding a literal
|
|
if err = w.WriteBool(true); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
literal := data[0]
|
|
data = data[1:]
|
|
windowIndex = window.SetByte(windowIndex, literal)
|
|
|
|
// Write literal value
|
|
if err = w.WriteBits(uint64(literal), LiteralBits); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
if err = w.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return outputBuffer.Bytes(), nil
|
|
}
|