...
1
2
3
4 package zstd
5
6 import (
7 "encoding/binary"
8 "errors"
9 "io"
10 )
11
12
13
14 const HeaderMaxSize = 14 + 3
15
16
17 type Header struct {
18
19
20
21 SingleSegment bool
22
23
24
25 WindowSize uint64
26
27
28
29 DictionaryID uint32
30
31
32 HasFCS bool
33
34
35 FrameContentSize uint64
36
37
38
39 Skippable bool
40
41
42
43 SkippableID int
44
45
46
47 SkippableSize uint32
48
49
50
51
52
53
54
55
56
57
58
59
60 HeaderSize int
61
62
63 FirstBlock struct {
64
65 OK bool
66
67
68 Last bool
69
70
71
72
73
74 Compressed bool
75
76
77
78 DecompressedSize int
79
80
81
82
83 CompressedSize int
84 }
85
86
87
88 HasCheckSum bool
89 }
90
91
92
93
94
95
96
97 func (h *Header) Decode(in []byte) error {
98 _, err := h.DecodeAndStrip(in)
99 return err
100 }
101
102
103
104
105
106
107
108
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
131
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
157
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)
167 switch len(b) {
168 case 1:
169 h.DictionaryID = uint32(b[0])
170 case 2:
171 h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
172 case 4:
173 h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
174 }
175 }
176
177
178
179 var fcsSize int
180 v := fhd >> 6
181 switch v {
182 case 0:
183 if h.SingleSegment {
184 fcsSize = 1
185 }
186 default:
187 fcsSize = 1 << v
188 }
189
190 if fcsSize > 0 {
191 h.HasFCS = true
192 if len(in) < fcsSize {
193 return nil, io.ErrUnexpectedEOF
194 }
195 b, in = in[:fcsSize], in[fcsSize:]
196 h.HeaderSize += int(fcsSize)
197 switch len(b) {
198 case 1:
199 h.FrameContentSize = uint64(b[0])
200 case 2:
201
202 h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
203 case 4:
204 h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
205 case 8:
206 d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
207 d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
208 h.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
209 }
210 }
211
212
213 if len(in) < 3 {
214 return in, nil
215 }
216 tmp := in[:3]
217 bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
218 h.FirstBlock.Last = bh&1 != 0
219 blockType := blockType((bh >> 1) & 3)
220
221 cSize := int(bh >> 3)
222 switch blockType {
223 case blockTypeReserved:
224 return in, nil
225 case blockTypeRLE:
226 h.FirstBlock.Compressed = true
227 h.FirstBlock.DecompressedSize = cSize
228 h.FirstBlock.CompressedSize = 1
229 case blockTypeCompressed:
230 h.FirstBlock.Compressed = true
231 h.FirstBlock.CompressedSize = cSize
232 case blockTypeRaw:
233 h.FirstBlock.DecompressedSize = cSize
234 h.FirstBlock.CompressedSize = cSize
235 default:
236 panic("Invalid block type")
237 }
238
239 h.FirstBlock.OK = true
240 return in, nil
241 }
242
243
244
245 func (h *Header) AppendTo(dst []byte) ([]byte, error) {
246 if h.Skippable {
247 magic := [4]byte{0x50, 0x2a, 0x4d, 0x18}
248 magic[0] |= byte(h.SkippableID & 0xf)
249 dst = append(dst, magic[:]...)
250 f := h.SkippableSize
251 return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil
252 }
253 f := frameHeader{
254 ContentSize: h.FrameContentSize,
255 WindowSize: uint32(h.WindowSize),
256 SingleSegment: h.SingleSegment,
257 Checksum: h.HasCheckSum,
258 DictID: h.DictionaryID,
259 }
260 return f.appendTo(dst), nil
261 }
262
View as plain text