ReadTable will read a table from the input. The size of the input may be larger than the table definition. Any content remaining after the table definition will be returned. If no Scratch is provided a new one is allocated. The returned Scratch can be used for encoding or decoding input using this t
(in []byte, s *Scratch)
| 27 | // If no Scratch is provided a new one is allocated. |
| 28 | // The returned Scratch can be used for encoding or decoding input using this table. |
| 29 | func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) { |
| 30 | s, err = s.prepare(nil) |
| 31 | if err != nil { |
| 32 | return s, nil, err |
| 33 | } |
| 34 | if len(in) <= 1 { |
| 35 | return s, nil, errors.New("input too small for table") |
| 36 | } |
| 37 | iSize := in[0] |
| 38 | in = in[1:] |
| 39 | if iSize >= 128 { |
| 40 | // Uncompressed |
| 41 | oSize := iSize - 127 |
| 42 | iSize = (oSize + 1) / 2 |
| 43 | if int(iSize) > len(in) { |
| 44 | return s, nil, errors.New("input too small for table") |
| 45 | } |
| 46 | for n := uint8(0); n < oSize; n += 2 { |
| 47 | v := in[n/2] |
| 48 | s.huffWeight[n] = v >> 4 |
| 49 | s.huffWeight[n+1] = v & 15 |
| 50 | } |
| 51 | s.symbolLen = uint16(oSize) |
| 52 | in = in[iSize:] |
| 53 | } else { |
| 54 | if len(in) < int(iSize) { |
| 55 | return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in)) |
| 56 | } |
| 57 | // FSE compressed weights |
| 58 | s.fse.DecompressLimit = 255 |
| 59 | hw := s.huffWeight[:] |
| 60 | s.fse.Out = hw |
| 61 | b, err := fse.Decompress(in[:iSize], s.fse) |
| 62 | s.fse.Out = nil |
| 63 | if err != nil { |
| 64 | return s, nil, fmt.Errorf("fse decompress returned: %w", err) |
| 65 | } |
| 66 | if len(b) > 255 { |
| 67 | return s, nil, errors.New("corrupt input: output table too large") |
| 68 | } |
| 69 | s.symbolLen = uint16(len(b)) |
| 70 | in = in[iSize:] |
| 71 | } |
| 72 | |
| 73 | // collect weight stats |
| 74 | var rankStats [16]uint32 |
| 75 | weightTotal := uint32(0) |
| 76 | for _, v := range s.huffWeight[:s.symbolLen] { |
| 77 | if v > tableLogMax { |
| 78 | return s, nil, errors.New("corrupt input: weight too large") |
| 79 | } |
| 80 | v2 := v & 15 |
| 81 | rankStats[v2]++ |
| 82 | // (1 << (v2-1)) is slower since the compiler cannot prove that v2 isn't 0. |
| 83 | weightTotal += (1 << v2) >> 1 |
| 84 | } |
| 85 | if weightTotal == 0 { |
| 86 | return s, nil, errors.New("corrupt input: weights zero") |
searching dependent graphs…