mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
288 lines
9.5 KiB
Go
288 lines
9.5 KiB
Go
package lzfse
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"math/bits"
|
|
)
|
|
|
|
// fseBitCount signed type used to represent bit count.
|
|
type fseBitCount int32
|
|
|
|
// fseState unsigned type used to represent FSE state.
|
|
type fseState uint16
|
|
|
|
// fseInStream object representing an input stream.
|
|
type fseInStream struct {
|
|
Accum uint64 // Input bits
|
|
AccumNbits fseBitCount // Number of valid bits in ACCUM, other bits are 0
|
|
}
|
|
|
|
// fseDecoderEntry entry for one state in the decoder table (32b).
|
|
type fseDecoderEntry struct { // DO NOT REORDER THE FIELDS
|
|
k int8 // Number of bits to read
|
|
symbol uint8 // Emitted symbol
|
|
delta int16 // Signed increment used to compute next state (+bias)
|
|
}
|
|
|
|
func (f fseDecoderEntry) ToInt32() int32 {
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.LittleEndian, f)
|
|
return int32(binary.LittleEndian.Uint32(buf.Bytes()))
|
|
}
|
|
|
|
// fseValueDecoderEntry entry for one state in the value decoder table (64b).
|
|
type fseValueDecoderEntry struct {
|
|
TotalBits uint8 // state bits + extra value bits = shift for next decode
|
|
ValueBits uint8 // extra value bits
|
|
Delta int16 // state base (delta)
|
|
Vbase int32 // value base
|
|
}
|
|
|
|
func (f fseValueDecoderEntry) ToInt64() int64 {
|
|
buf := new(bytes.Buffer)
|
|
binary.Write(buf, binary.LittleEndian, f)
|
|
return int64(binary.LittleEndian.Uint64(buf.Bytes()))
|
|
}
|
|
|
|
func fseInitDecoderTable(nstates, nsymbols int, freq [256]uint16, t *[1024]int32) error {
|
|
var sumOfFreq, lDecoderIdx int
|
|
|
|
nClz := bits.LeadingZeros(uint(nstates))
|
|
|
|
for i := range nsymbols {
|
|
f := int(freq[i])
|
|
if f == 0 {
|
|
continue // skip this symbol, no occurrences
|
|
}
|
|
sumOfFreq += f
|
|
|
|
if sumOfFreq > nstates {
|
|
return fmt.Errorf("sumOfFreq > nstates")
|
|
}
|
|
|
|
k := bits.LeadingZeros(uint(f)) - nClz // shift needed to ensure N <= (F<<K) < 2*N
|
|
j0 := ((2 * nstates) >> k) - f
|
|
|
|
// Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
|
|
for j := range f {
|
|
var e fseDecoderEntry
|
|
|
|
e.symbol = uint8(i)
|
|
if j < j0 {
|
|
e.k = int8(k)
|
|
e.delta = int16(((f + j) << k) - nstates)
|
|
} else {
|
|
e.k = int8(k - 1)
|
|
e.delta = int16((j - j0) << (k - 1))
|
|
}
|
|
t[lDecoderIdx] = e.ToInt32()
|
|
lDecoderIdx++
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func fseInitValueLOrMDecoderTable(nstates, nsymbols int, freq []uint16, symbolVbits []uint8,
|
|
symbolVbase []int32, t *[64]fseValueDecoderEntry) {
|
|
var dDecoderIdx int
|
|
|
|
nClz := bits.LeadingZeros(uint(nstates))
|
|
for i := range nsymbols {
|
|
f := int(freq[i])
|
|
|
|
if f == 0 {
|
|
continue // skip this symbol, no occurrences
|
|
}
|
|
k := bits.LeadingZeros(uint(f)) - nClz // shift needed to ensure N <= (F<<K) < 2*N
|
|
j0 := ((2 * nstates) >> k) - f
|
|
|
|
var ei fseValueDecoderEntry
|
|
ei.ValueBits = symbolVbits[i]
|
|
ei.Vbase = symbolVbase[i]
|
|
|
|
// Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
|
|
for j := range f {
|
|
e := ei
|
|
if j < j0 {
|
|
e.TotalBits = uint8(k) + e.ValueBits
|
|
e.Delta = int16(((f + j) << k) - nstates)
|
|
} else {
|
|
e.TotalBits = uint8(k-1) + e.ValueBits
|
|
e.Delta = int16((j - j0) << (k - 1))
|
|
}
|
|
t[dDecoderIdx] = e
|
|
dDecoderIdx++
|
|
}
|
|
}
|
|
}
|
|
|
|
func fseInitValueDDecoderTable(nstates, nsymbols int, freq []uint16, symbolVbits []uint8,
|
|
symbolVbase []int32, t *[256]fseValueDecoderEntry) {
|
|
var dDecoderIdx int
|
|
|
|
nClz := bits.LeadingZeros(uint(nstates))
|
|
for i := range nsymbols {
|
|
f := int(freq[i])
|
|
|
|
if f == 0 {
|
|
continue // skip this symbol, no occurrences
|
|
}
|
|
k := bits.LeadingZeros(uint(f)) - nClz // shift needed to ensure N <= (F<<K) < 2*N
|
|
j0 := ((2 * nstates) >> k) - f
|
|
|
|
var ei fseValueDecoderEntry
|
|
ei.ValueBits = symbolVbits[i]
|
|
ei.Vbase = symbolVbase[i]
|
|
|
|
// Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
|
|
for j := range f {
|
|
e := ei
|
|
if j < j0 {
|
|
e.TotalBits = uint8(k) + e.ValueBits
|
|
e.Delta = int16(((f + j) << k) - nstates)
|
|
} else {
|
|
e.TotalBits = uint8(k-1) + e.ValueBits
|
|
e.Delta = int16((j - j0) << (k - 1))
|
|
}
|
|
t[dDecoderIdx] = e
|
|
dDecoderIdx++
|
|
}
|
|
}
|
|
}
|
|
|
|
/* fseInCheckedInit initialize the fse input stream so that accum holds between 56
|
|
* and 63 bits. We never want to have 64 bits in the stream, because that allows
|
|
* us to avoid a special case in the fseInPull function (eliminating an
|
|
* unpredictable branch), while not requiring any additional fse_flush
|
|
* operations. This is why we have the special case for n == 0 (in which case
|
|
* we want to load only 7 bytes instead of 8). */
|
|
// func fseInCheckedInit(s *fseInStream, n fseBitCount, r *bytes.Reader, buffStart int64) error {
|
|
// func fseInCheckedInit(s *fseInStream, n fseBitCount, r *bytes.Reader) error {
|
|
func fseInCheckedInit(s *fseInStream, n fseBitCount, r *io.SectionReader) error {
|
|
// pbuf := io.NewSectionReader(r, 0, 1<<63-1)
|
|
if n != 0 {
|
|
if _, err := r.Seek(-8, io.SeekCurrent); err != nil {
|
|
return err
|
|
}
|
|
if err := binary.Read(r, binary.LittleEndian, &s.Accum); err != nil {
|
|
return err
|
|
}
|
|
r.Seek(-8, io.SeekCurrent)
|
|
s.AccumNbits = n + 64
|
|
} else {
|
|
r.Seek(-7, io.SeekCurrent)
|
|
if err := binary.Read(r, binary.LittleEndian, &s.Accum); err != nil {
|
|
return err
|
|
}
|
|
r.Seek(-8, io.SeekCurrent)
|
|
s.Accum &= 0xffffffffffffff
|
|
s.AccumNbits = n + 56
|
|
}
|
|
|
|
if (s.AccumNbits < 56 || s.AccumNbits >= 64) || ((s.Accum >> s.AccumNbits) != 0) {
|
|
return fmt.Errorf("the incoming input is wrong (encoder should have zeroed the upper bits)")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/* fseInCheckedFlush - read in new bytes from buffer to ensure that we have a full
|
|
* complement of bits in the stream object (again, between 56 and 63 bits).
|
|
* checking the new value of *pbuf remains >= buf_start.
|
|
* @return 0 if OK.
|
|
* @return -1 on failure. */
|
|
// func fseInCheckedFlush(s *fseInStream, r *bytes.Reader) error {
|
|
func fseInCheckedFlush(s *fseInStream, r *io.SectionReader) error {
|
|
// Get number of bits to add to bring us into the desired range.
|
|
nbits := (63 - s.AccumNbits) & -8
|
|
// Convert bits to bytes and decrement buffer address, then load new data.
|
|
_, err := r.Seek(int64(-(nbits >> 3)), io.SeekCurrent)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var incoming uint64
|
|
if err := binary.Read(r, binary.LittleEndian, &incoming); err != nil {
|
|
return err
|
|
}
|
|
r.Seek(-8, io.SeekCurrent)
|
|
// Update the state object and verify its validity (in DEBUG).
|
|
s.Accum = (s.Accum << nbits) | fseMaskLsb64(incoming, nbits)
|
|
s.AccumNbits += nbits
|
|
if s.AccumNbits < 56 || s.AccumNbits >= 64 {
|
|
return fmt.Errorf("failed to fseInCheckedFlush - s.AccumNbits < 56 || s.AccumNbits >= 64")
|
|
}
|
|
if (s.Accum >> s.AccumNbits) != 0 {
|
|
return fmt.Errorf("failed to fseInCheckedFlush - (s.Accum >> s.AccumNbits) == 0")
|
|
}
|
|
return nil // OK
|
|
}
|
|
|
|
/* fseDecode - decode and return symbol using the decoder table, and update *pstate, in.
|
|
* @note The caller must ensure we have enough bits available in the input
|
|
* stream accumulator. */
|
|
func fseDecode(pstate *uint16, decoderTable [1024]int32, in *fseInStream) uint8 {
|
|
e := decoderTable[*pstate]
|
|
// Update state from K bits of input + DELTA
|
|
*pstate = uint16(e>>16) + uint16(fseInPull(in, fseBitCount(e&0xff)))
|
|
// Return the symbol for this state
|
|
return uint8(fseExtractBits(uint64(e), 8, 8)) // symbol
|
|
}
|
|
|
|
/* fseValueDecode - decode and return value using the decoder table, and update *pstate, in value_decoder_table[nstates]
|
|
* @note The caller must ensure we have enough bits available in the input
|
|
* stream accumulator. */
|
|
func fseValueDecode(pstate *uint16, valueDecoderTable []fseValueDecoderEntry, in *fseInStream) int32 {
|
|
entry := valueDecoderTable[*pstate]
|
|
stateAndValueBits := uint32(fseInPull(in, fseBitCount(entry.TotalBits)))
|
|
*pstate = uint16(entry.Delta) + uint16(stateAndValueBits>>entry.ValueBits)
|
|
return entry.Vbase + int32(fseMaskLsb64(uint64(stateAndValueBits), fseBitCount(entry.ValueBits)))
|
|
}
|
|
|
|
// fseInPull - pull n bits out of the fse stream object.
|
|
func fseInPull(s *fseInStream, n fseBitCount) uint64 {
|
|
// assert(n >= 0 && n <= s.AccumNbits);
|
|
s.AccumNbits -= n
|
|
result := s.Accum >> s.AccumNbits
|
|
s.Accum = fseMaskLsb64(s.Accum, s.AccumNbits)
|
|
return result
|
|
}
|
|
|
|
// Mask the NBITS lsb of X. 0 <= NBITS < 64
|
|
func fseMaskLsb64(x uint64, nbits fseBitCount) uint64 {
|
|
mtable := [65]uint64{
|
|
0x0000000000000000, 0x0000000000000001, 0x0000000000000003,
|
|
0x0000000000000007, 0x000000000000000f, 0x000000000000001f,
|
|
0x000000000000003f, 0x000000000000007f, 0x00000000000000ff,
|
|
0x00000000000001ff, 0x00000000000003ff, 0x00000000000007ff,
|
|
0x0000000000000fff, 0x0000000000001fff, 0x0000000000003fff,
|
|
0x0000000000007fff, 0x000000000000ffff, 0x000000000001ffff,
|
|
0x000000000003ffff, 0x000000000007ffff, 0x00000000000fffff,
|
|
0x00000000001fffff, 0x00000000003fffff, 0x00000000007fffff,
|
|
0x0000000000ffffff, 0x0000000001ffffff, 0x0000000003ffffff,
|
|
0x0000000007ffffff, 0x000000000fffffff, 0x000000001fffffff,
|
|
0x000000003fffffff, 0x000000007fffffff, 0x00000000ffffffff,
|
|
0x00000001ffffffff, 0x00000003ffffffff, 0x00000007ffffffff,
|
|
0x0000000fffffffff, 0x0000001fffffffff, 0x0000003fffffffff,
|
|
0x0000007fffffffff, 0x000000ffffffffff, 0x000001ffffffffff,
|
|
0x000003ffffffffff, 0x000007ffffffffff, 0x00000fffffffffff,
|
|
0x00001fffffffffff, 0x00003fffffffffff, 0x00007fffffffffff,
|
|
0x0000ffffffffffff, 0x0001ffffffffffff, 0x0003ffffffffffff,
|
|
0x0007ffffffffffff, 0x000fffffffffffff, 0x001fffffffffffff,
|
|
0x003fffffffffffff, 0x007fffffffffffff, 0x00ffffffffffffff,
|
|
0x01ffffffffffffff, 0x03ffffffffffffff, 0x07ffffffffffffff,
|
|
0x0fffffffffffffff, 0x1fffffffffffffff, 0x3fffffffffffffff,
|
|
0x7fffffffffffffff, 0xffffffffffffffff,
|
|
}
|
|
return x & mtable[nbits]
|
|
}
|
|
|
|
// fseExtractBits - select nbits at index start from x.
|
|
// 0 <= start <= start+nbits <= 64
|
|
func fseExtractBits(x uint64, start, nbits fseBitCount) uint64 {
|
|
return fseMaskLsb64(x>>start, nbits)
|
|
}
|