@@ -95,42 +95,54 @@ type Header struct {
9595// If there isn't enough input, io.ErrUnexpectedEOF is returned.
9696// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
9797func (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 ) {
98110 * h = Header {}
99111 if len (in ) < 4 {
100- return io .ErrUnexpectedEOF
112+ return nil , io .ErrUnexpectedEOF
101113 }
102114 h .HeaderSize += 4
103115 b , in := in [:4 ], in [4 :]
104116 if string (b ) != frameMagic {
105117 if string (b [1 :4 ]) != skippableFrameMagic || b [0 ]& 0xf0 != 0x50 {
106- return ErrMagicMismatch
118+ return nil , ErrMagicMismatch
107119 }
108120 if len (in ) < 4 {
109- return io .ErrUnexpectedEOF
121+ return nil , io .ErrUnexpectedEOF
110122 }
111123 h .HeaderSize += 4
112124 h .Skippable = true
113125 h .SkippableID = int (b [0 ] & 0xf )
114126 h .SkippableSize = binary .LittleEndian .Uint32 (in )
115- return nil
127+ return in [ 4 :], nil
116128 }
117129
118130 // Read Window_Descriptor
119131 // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
120132 if len (in ) < 1 {
121- return io .ErrUnexpectedEOF
133+ return nil , io .ErrUnexpectedEOF
122134 }
123135 fhd , in := in [0 ], in [1 :]
124136 h .HeaderSize ++
125137 h .SingleSegment = fhd & (1 << 5 ) != 0
126138 h .HasCheckSum = fhd & (1 << 2 ) != 0
127139 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" )
129141 }
130142
131143 if ! h .SingleSegment {
132144 if len (in ) < 1 {
133- return io .ErrUnexpectedEOF
145+ return nil , io .ErrUnexpectedEOF
134146 }
135147 var wd byte
136148 wd , in = in [0 ], in [1 :]
@@ -148,7 +160,7 @@ func (h *Header) Decode(in []byte) error {
148160 size = 4
149161 }
150162 if len (in ) < int (size ) {
151- return io .ErrUnexpectedEOF
163+ return nil , io .ErrUnexpectedEOF
152164 }
153165 b , in = in [:size ], in [size :]
154166 h .HeaderSize += int (size )
@@ -178,7 +190,7 @@ func (h *Header) Decode(in []byte) error {
178190 if fcsSize > 0 {
179191 h .HasFCS = true
180192 if len (in ) < fcsSize {
181- return io .ErrUnexpectedEOF
193+ return nil , io .ErrUnexpectedEOF
182194 }
183195 b , in = in [:fcsSize ], in [fcsSize :]
184196 h .HeaderSize += int (fcsSize )
@@ -199,7 +211,7 @@ func (h *Header) Decode(in []byte) error {
199211
200212 // Frame Header done, we will not fail from now on.
201213 if len (in ) < 3 {
202- return nil
214+ return in , nil
203215 }
204216 tmp := in [:3 ]
205217 bh := uint32 (tmp [0 ]) | (uint32 (tmp [1 ]) << 8 ) | (uint32 (tmp [2 ]) << 16 )
@@ -209,7 +221,7 @@ func (h *Header) Decode(in []byte) error {
209221 cSize := int (bh >> 3 )
210222 switch blockType {
211223 case blockTypeReserved :
212- return nil
224+ return in , nil
213225 case blockTypeRLE :
214226 h .FirstBlock .Compressed = true
215227 h .FirstBlock .DecompressedSize = cSize
@@ -225,5 +237,25 @@ func (h *Header) Decode(in []byte) error {
225237 }
226238
227239 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
229261}
0 commit comments