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