decodeheader.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2020+ Klaus Post. All rights reserved.
  2. // License information can be found in the LICENSE file.
  3. package zstd
  4. import (
  5. "encoding/binary"
  6. "errors"
  7. "io"
  8. )
  9. // HeaderMaxSize is the maximum size of a Frame and Block Header.
  10. // If less is sent to Header.Decode it *may* still contain enough information.
  11. const HeaderMaxSize = 14 + 3
  12. // Header contains information about the first frame and block within that.
  13. type Header struct {
  14. // SingleSegment specifies whether the data is to be decompressed into a
  15. // single contiguous memory segment.
  16. // It implies that WindowSize is invalid and that FrameContentSize is valid.
  17. SingleSegment bool
  18. // WindowSize is the window of data to keep while decoding.
  19. // Will only be set if SingleSegment is false.
  20. WindowSize uint64
  21. // Dictionary ID.
  22. // If 0, no dictionary.
  23. DictionaryID uint32
  24. // HasFCS specifies whether FrameContentSize has a valid value.
  25. HasFCS bool
  26. // FrameContentSize is the expected uncompressed size of the entire frame.
  27. FrameContentSize uint64
  28. // Skippable will be true if the frame is meant to be skipped.
  29. // This implies that FirstBlock.OK is false.
  30. Skippable bool
  31. // SkippableID is the user-specific ID for the skippable frame.
  32. // Valid values are between 0 to 15, inclusive.
  33. SkippableID int
  34. // SkippableSize is the length of the user data to skip following
  35. // the header.
  36. SkippableSize uint32
  37. // HeaderSize is the raw size of the frame header.
  38. //
  39. // For normal frames, it includes the size of the magic number and
  40. // the size of the header (per section 3.1.1.1).
  41. // It does not include the size for any data blocks (section 3.1.1.2) nor
  42. // the size for the trailing content checksum.
  43. //
  44. // For skippable frames, this counts the size of the magic number
  45. // along with the size of the size field of the payload.
  46. // It does not include the size of the skippable payload itself.
  47. // The total frame size is the HeaderSize plus the SkippableSize.
  48. HeaderSize int
  49. // First block information.
  50. FirstBlock struct {
  51. // OK will be set if first block could be decoded.
  52. OK bool
  53. // Is this the last block of a frame?
  54. Last bool
  55. // Is the data compressed?
  56. // If true CompressedSize will be populated.
  57. // Unfortunately DecompressedSize cannot be determined
  58. // without decoding the blocks.
  59. Compressed bool
  60. // DecompressedSize is the expected decompressed size of the block.
  61. // Will be 0 if it cannot be determined.
  62. DecompressedSize int
  63. // CompressedSize of the data in the block.
  64. // Does not include the block header.
  65. // Will be equal to DecompressedSize if not Compressed.
  66. CompressedSize int
  67. }
  68. // If set there is a checksum present for the block content.
  69. // The checksum field at the end is always 4 bytes long.
  70. HasCheckSum bool
  71. }
  72. // Decode the header from the beginning of the stream.
  73. // This will decode the frame header and the first block header if enough bytes are provided.
  74. // It is recommended to provide at least HeaderMaxSize bytes.
  75. // If the frame header cannot be read an error will be returned.
  76. // If there isn't enough input, io.ErrUnexpectedEOF is returned.
  77. // The FirstBlock.OK will indicate if enough information was available to decode the first block header.
  78. func (h *Header) Decode(in []byte) error {
  79. *h = Header{}
  80. if len(in) < 4 {
  81. return io.ErrUnexpectedEOF
  82. }
  83. h.HeaderSize += 4
  84. b, in := in[:4], in[4:]
  85. if string(b) != frameMagic {
  86. if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 {
  87. return ErrMagicMismatch
  88. }
  89. if len(in) < 4 {
  90. return io.ErrUnexpectedEOF
  91. }
  92. h.HeaderSize += 4
  93. h.Skippable = true
  94. h.SkippableID = int(b[0] & 0xf)
  95. h.SkippableSize = binary.LittleEndian.Uint32(in)
  96. return nil
  97. }
  98. // Read Window_Descriptor
  99. // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
  100. if len(in) < 1 {
  101. return io.ErrUnexpectedEOF
  102. }
  103. fhd, in := in[0], in[1:]
  104. h.HeaderSize++
  105. h.SingleSegment = fhd&(1<<5) != 0
  106. h.HasCheckSum = fhd&(1<<2) != 0
  107. if fhd&(1<<3) != 0 {
  108. return errors.New("reserved bit set on frame header")
  109. }
  110. if !h.SingleSegment {
  111. if len(in) < 1 {
  112. return io.ErrUnexpectedEOF
  113. }
  114. var wd byte
  115. wd, in = in[0], in[1:]
  116. h.HeaderSize++
  117. windowLog := 10 + (wd >> 3)
  118. windowBase := uint64(1) << windowLog
  119. windowAdd := (windowBase / 8) * uint64(wd&0x7)
  120. h.WindowSize = windowBase + windowAdd
  121. }
  122. // Read Dictionary_ID
  123. // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
  124. if size := fhd & 3; size != 0 {
  125. if size == 3 {
  126. size = 4
  127. }
  128. if len(in) < int(size) {
  129. return io.ErrUnexpectedEOF
  130. }
  131. b, in = in[:size], in[size:]
  132. h.HeaderSize += int(size)
  133. switch len(b) {
  134. case 1:
  135. h.DictionaryID = uint32(b[0])
  136. case 2:
  137. h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
  138. case 4:
  139. h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
  140. }
  141. }
  142. // Read Frame_Content_Size
  143. // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
  144. var fcsSize int
  145. v := fhd >> 6
  146. switch v {
  147. case 0:
  148. if h.SingleSegment {
  149. fcsSize = 1
  150. }
  151. default:
  152. fcsSize = 1 << v
  153. }
  154. if fcsSize > 0 {
  155. h.HasFCS = true
  156. if len(in) < fcsSize {
  157. return io.ErrUnexpectedEOF
  158. }
  159. b, in = in[:fcsSize], in[fcsSize:]
  160. h.HeaderSize += int(fcsSize)
  161. switch len(b) {
  162. case 1:
  163. h.FrameContentSize = uint64(b[0])
  164. case 2:
  165. // When FCS_Field_Size is 2, the offset of 256 is added.
  166. h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
  167. case 4:
  168. h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
  169. case 8:
  170. d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
  171. d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
  172. h.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
  173. }
  174. }
  175. // Frame Header done, we will not fail from now on.
  176. if len(in) < 3 {
  177. return nil
  178. }
  179. tmp := in[:3]
  180. bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
  181. h.FirstBlock.Last = bh&1 != 0
  182. blockType := blockType((bh >> 1) & 3)
  183. // find size.
  184. cSize := int(bh >> 3)
  185. switch blockType {
  186. case blockTypeReserved:
  187. return nil
  188. case blockTypeRLE:
  189. h.FirstBlock.Compressed = true
  190. h.FirstBlock.DecompressedSize = cSize
  191. h.FirstBlock.CompressedSize = 1
  192. case blockTypeCompressed:
  193. h.FirstBlock.Compressed = true
  194. h.FirstBlock.CompressedSize = cSize
  195. case blockTypeRaw:
  196. h.FirstBlock.DecompressedSize = cSize
  197. h.FirstBlock.CompressedSize = cSize
  198. default:
  199. panic("Invalid block type")
  200. }
  201. h.FirstBlock.OK = true
  202. return nil
  203. }