DecodeAndStrip will decode the header from the beginning of the stream and on success return the remaining bytes. This will decode the frame header and the first block header if enough bytes are provided. It is recommended to provide at least HeaderMaxSize bytes. If the frame header cannot be read a
(in []byte)
| 107 | // If there isn't enough input, io.ErrUnexpectedEOF is returned. |
| 108 | // The FirstBlock.OK will indicate if enough information was available to decode the first block header. |
| 109 | func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { |
| 110 | *h = Header{} |
| 111 | if len(in) < 4 { |
| 112 | return nil, io.ErrUnexpectedEOF |
| 113 | } |
| 114 | h.HeaderSize += 4 |
| 115 | b, in := in[:4], in[4:] |
| 116 | if string(b) != frameMagic { |
| 117 | if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 { |
| 118 | return nil, ErrMagicMismatch |
| 119 | } |
| 120 | if len(in) < 4 { |
| 121 | return nil, io.ErrUnexpectedEOF |
| 122 | } |
| 123 | h.HeaderSize += 4 |
| 124 | h.Skippable = true |
| 125 | h.SkippableID = int(b[0] & 0xf) |
| 126 | h.SkippableSize = binary.LittleEndian.Uint32(in) |
| 127 | return in[4:], nil |
| 128 | } |
| 129 | |
| 130 | // Read Window_Descriptor |
| 131 | // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor |
| 132 | if len(in) < 1 { |
| 133 | return nil, io.ErrUnexpectedEOF |
| 134 | } |
| 135 | fhd, in := in[0], in[1:] |
| 136 | h.HeaderSize++ |
| 137 | h.SingleSegment = fhd&(1<<5) != 0 |
| 138 | h.HasCheckSum = fhd&(1<<2) != 0 |
| 139 | if fhd&(1<<3) != 0 { |
| 140 | return nil, errors.New("reserved bit set on frame header") |
| 141 | } |
| 142 | |
| 143 | if !h.SingleSegment { |
| 144 | if len(in) < 1 { |
| 145 | return nil, io.ErrUnexpectedEOF |
| 146 | } |
| 147 | var wd byte |
| 148 | wd, in = in[0], in[1:] |
| 149 | h.HeaderSize++ |
| 150 | windowLog := 10 + (wd >> 3) |
| 151 | windowBase := uint64(1) << windowLog |
| 152 | windowAdd := (windowBase / 8) * uint64(wd&0x7) |
| 153 | h.WindowSize = windowBase + windowAdd |
| 154 | } |
| 155 | |
| 156 | // Read Dictionary_ID |
| 157 | // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id |
| 158 | if size := fhd & 3; size != 0 { |
| 159 | if size == 3 { |
| 160 | size = 4 |
| 161 | } |
| 162 | if len(in) < int(size) { |
| 163 | return nil, io.ErrUnexpectedEOF |
| 164 | } |
| 165 | b, in = in[:size], in[size:] |
| 166 | h.HeaderSize += int(size) |