@@ -95,42 +95,54 @@ type Header struct {
95
95
// If there isn't enough input, io.ErrUnexpectedEOF is returned.
96
96
// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
97
97
func (h * Header ) Decode (in []byte ) error {
98
+ _ , err := h .DecodeAndStrip (in )
99
+ return err
100
+ }
101
+
102
+ // DecodeAndStrip will decode the header from the beginning of the stream
103
+ // and on success return the remaining bytes.
104
+ // This will decode the frame header and the first block header if enough bytes are provided.
105
+ // It is recommended to provide at least HeaderMaxSize bytes.
106
+ // If the frame header cannot be read an error will be returned.
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 ) {
98
110
* h = Header {}
99
111
if len (in ) < 4 {
100
- return io .ErrUnexpectedEOF
112
+ return nil , io .ErrUnexpectedEOF
101
113
}
102
114
h .HeaderSize += 4
103
115
b , in := in [:4 ], in [4 :]
104
116
if string (b ) != frameMagic {
105
117
if string (b [1 :4 ]) != skippableFrameMagic || b [0 ]& 0xf0 != 0x50 {
106
- return ErrMagicMismatch
118
+ return nil , ErrMagicMismatch
107
119
}
108
120
if len (in ) < 4 {
109
- return io .ErrUnexpectedEOF
121
+ return nil , io .ErrUnexpectedEOF
110
122
}
111
123
h .HeaderSize += 4
112
124
h .Skippable = true
113
125
h .SkippableID = int (b [0 ] & 0xf )
114
126
h .SkippableSize = binary .LittleEndian .Uint32 (in )
115
- return nil
127
+ return in [ 4 :], nil
116
128
}
117
129
118
130
// Read Window_Descriptor
119
131
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
120
132
if len (in ) < 1 {
121
- return io .ErrUnexpectedEOF
133
+ return nil , io .ErrUnexpectedEOF
122
134
}
123
135
fhd , in := in [0 ], in [1 :]
124
136
h .HeaderSize ++
125
137
h .SingleSegment = fhd & (1 << 5 ) != 0
126
138
h .HasCheckSum = fhd & (1 << 2 ) != 0
127
139
if fhd & (1 << 3 ) != 0 {
128
- return errors .New ("reserved bit set on frame header" )
140
+ return nil , errors .New ("reserved bit set on frame header" )
129
141
}
130
142
131
143
if ! h .SingleSegment {
132
144
if len (in ) < 1 {
133
- return io .ErrUnexpectedEOF
145
+ return nil , io .ErrUnexpectedEOF
134
146
}
135
147
var wd byte
136
148
wd , in = in [0 ], in [1 :]
@@ -148,7 +160,7 @@ func (h *Header) Decode(in []byte) error {
148
160
size = 4
149
161
}
150
162
if len (in ) < int (size ) {
151
- return io .ErrUnexpectedEOF
163
+ return nil , io .ErrUnexpectedEOF
152
164
}
153
165
b , in = in [:size ], in [size :]
154
166
h .HeaderSize += int (size )
@@ -178,7 +190,7 @@ func (h *Header) Decode(in []byte) error {
178
190
if fcsSize > 0 {
179
191
h .HasFCS = true
180
192
if len (in ) < fcsSize {
181
- return io .ErrUnexpectedEOF
193
+ return nil , io .ErrUnexpectedEOF
182
194
}
183
195
b , in = in [:fcsSize ], in [fcsSize :]
184
196
h .HeaderSize += int (fcsSize )
@@ -199,7 +211,7 @@ func (h *Header) Decode(in []byte) error {
199
211
200
212
// Frame Header done, we will not fail from now on.
201
213
if len (in ) < 3 {
202
- return nil
214
+ return in , nil
203
215
}
204
216
tmp := in [:3 ]
205
217
bh := uint32 (tmp [0 ]) | (uint32 (tmp [1 ]) << 8 ) | (uint32 (tmp [2 ]) << 16 )
@@ -209,7 +221,7 @@ func (h *Header) Decode(in []byte) error {
209
221
cSize := int (bh >> 3 )
210
222
switch blockType {
211
223
case blockTypeReserved :
212
- return nil
224
+ return in , nil
213
225
case blockTypeRLE :
214
226
h .FirstBlock .Compressed = true
215
227
h .FirstBlock .DecompressedSize = cSize
@@ -225,5 +237,25 @@ func (h *Header) Decode(in []byte) error {
225
237
}
226
238
227
239
h .FirstBlock .OK = true
228
- return nil
240
+ return in , nil
241
+ }
242
+
243
+ // AppendTo will append the encoded header to the dst slice.
244
+ // There is no error checking performed on the header values.
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
229
261
}
0 commit comments