// Copyright 2020+ Klaus Post. All rights reserved.// License information can be found in the LICENSE file.package zstdimport ()// HeaderMaxSize is the maximum size of a Frame and Block Header.// If less is sent to Header.Decode it *may* still contain enough information.constHeaderMaxSize = 14 + 3// Header contains information about the first frame and block within that.typeHeaderstruct {// SingleSegment specifies whether the data is to be decompressed into a // single contiguous memory segment. // It implies that WindowSize is invalid and that FrameContentSize is valid. SingleSegment bool// WindowSize is the window of data to keep while decoding. // Will only be set if SingleSegment is false. WindowSize uint64// Dictionary ID. // If 0, no dictionary. DictionaryID uint32// HasFCS specifies whether FrameContentSize has a valid value. HasFCS bool// FrameContentSize is the expected uncompressed size of the entire frame. FrameContentSize uint64// Skippable will be true if the frame is meant to be skipped. // This implies that FirstBlock.OK is false. Skippable bool// SkippableID is the user-specific ID for the skippable frame. // Valid values are between 0 to 15, inclusive. SkippableID int// SkippableSize is the length of the user data to skip following // the header. SkippableSize uint32// HeaderSize is the raw size of the frame header. // // For normal frames, it includes the size of the magic number and // the size of the header (per section 3.1.1.1). // It does not include the size for any data blocks (section 3.1.1.2) nor // the size for the trailing content checksum. // // For skippable frames, this counts the size of the magic number // along with the size of the size field of the payload. // It does not include the size of the skippable payload itself. // The total frame size is the HeaderSize plus the SkippableSize. HeaderSize int// First block information. FirstBlock struct {// OK will be set if first block could be decoded. OK bool// Is this the last block of a frame? Last bool// Is the data compressed? // If true CompressedSize will be populated. // Unfortunately DecompressedSize cannot be determined // without decoding the blocks. Compressed bool// DecompressedSize is the expected decompressed size of the block. // Will be 0 if it cannot be determined. DecompressedSize int// CompressedSize of the data in the block. // Does not include the block header. // Will be equal to DecompressedSize if not Compressed. CompressedSize int }// If set there is a checksum present for the block content. // The checksum field at the end is always 4 bytes long. HasCheckSum bool}// Decode the header from the beginning of the stream.// This will decode the frame header and the first block header if enough bytes are provided.// It is recommended to provide at least HeaderMaxSize bytes.// If the frame header cannot be read an error will be returned.// If there isn't enough input, io.ErrUnexpectedEOF is returned.// The FirstBlock.OK will indicate if enough information was available to decode the first block header.func ( *Header) ( []byte) error { , := .DecodeAndStrip()return}// DecodeAndStrip will decode the header from the beginning of the stream// and on success return the remaining bytes.// This will decode the frame header and the first block header if enough bytes are provided.// It is recommended to provide at least HeaderMaxSize bytes.// If the frame header cannot be read an error will be returned.// If there isn't enough input, io.ErrUnexpectedEOF is returned.// The FirstBlock.OK will indicate if enough information was available to decode the first block header.func ( *Header) ( []byte) ( []byte, error) { * = Header{}iflen() < 4 {returnnil, io.ErrUnexpectedEOF } .HeaderSize += 4 , := [:4], [4:]ifstring() != frameMagic {ifstring([1:4]) != skippableFrameMagic || [0]&0xf0 != 0x50 {returnnil, ErrMagicMismatch }iflen() < 4 {returnnil, io.ErrUnexpectedEOF } .HeaderSize += 4 .Skippable = true .SkippableID = int([0] & 0xf) .SkippableSize = binary.LittleEndian.Uint32()return [4:], nil }// Read Window_Descriptor // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptoriflen() < 1 {returnnil, io.ErrUnexpectedEOF } , := [0], [1:] .HeaderSize++ .SingleSegment = &(1<<5) != 0 .HasCheckSum = &(1<<2) != 0if &(1<<3) != 0 {returnnil, errors.New("reserved bit set on frame header") }if !.SingleSegment {iflen() < 1 {returnnil, io.ErrUnexpectedEOF }varbyte , = [0], [1:] .HeaderSize++ := 10 + ( >> 3) := uint64(1) << := ( / 8) * uint64(&0x7) .WindowSize = + }// Read Dictionary_ID // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_idif := & 3; != 0 {if == 3 { = 4 }iflen() < int() {returnnil, io.ErrUnexpectedEOF } , = [:], [:] .HeaderSize += int()switchlen() {case1: .DictionaryID = uint32([0])case2: .DictionaryID = uint32([0]) | (uint32([1]) << 8)case4: .DictionaryID = uint32([0]) | (uint32([1]) << 8) | (uint32([2]) << 16) | (uint32([3]) << 24) } }// Read Frame_Content_Size // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_sizevarint := >> 6switch {case0:if .SingleSegment { = 1 }default: = 1 << }if > 0 { .HasFCS = trueiflen() < {returnnil, io.ErrUnexpectedEOF } , = [:], [:] .HeaderSize += int()switchlen() {case1: .FrameContentSize = uint64([0])case2:// When FCS_Field_Size is 2, the offset of 256 is added. .FrameContentSize = uint64([0]) | (uint64([1]) << 8) + 256case4: .FrameContentSize = uint64([0]) | (uint64([1]) << 8) | (uint64([2]) << 16) | (uint64([3]) << 24)case8: := uint32([0]) | (uint32([1]) << 8) | (uint32([2]) << 16) | (uint32([3]) << 24) := uint32([4]) | (uint32([5]) << 8) | (uint32([6]) << 16) | (uint32([7]) << 24) .FrameContentSize = uint64() | (uint64() << 32) } }// Frame Header done, we will not fail from now on.iflen() < 3 {return , nil } := [:3] := uint32([0]) | (uint32([1]) << 8) | (uint32([2]) << 16) .FirstBlock.Last = &1 != 0 := blockType(( >> 1) & 3)// find size. := int( >> 3)switch {caseblockTypeReserved:return , nilcaseblockTypeRLE: .FirstBlock.Compressed = true .FirstBlock.DecompressedSize = .FirstBlock.CompressedSize = 1caseblockTypeCompressed: .FirstBlock.Compressed = true .FirstBlock.CompressedSize = caseblockTypeRaw: .FirstBlock.DecompressedSize = .FirstBlock.CompressedSize = default:panic("Invalid block type") } .FirstBlock.OK = truereturn , nil}// AppendTo will append the encoded header to the dst slice.// There is no error checking performed on the header values.func ( *Header) ( []byte) ([]byte, error) {if .Skippable { := [4]byte{0x50, 0x2a, 0x4d, 0x18} [0] |= byte(.SkippableID & 0xf) = append(, [:]...) := .SkippableSizereturnappend(, uint8(), uint8(>>8), uint8(>>16), uint8(>>24)), nil } := frameHeader{ContentSize: .FrameContentSize,WindowSize: uint32(.WindowSize),SingleSegment: .SingleSegment,Checksum: .HasCheckSum,DictID: .DictionaryID, }return .appendTo(), nil}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.