github.com/bir3/gocompiler@v0.9.2202/extra/compress/zstd/frameenc.go (about)

     1  // Copyright 2019+ Klaus Post. All rights reserved.
     2  // License information can be found in the LICENSE file.
     3  // Based on work by Yann Collet, released under BSD License.
     4  
     5  package zstd
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"io"
    11  	"math"
    12  	"math/bits"
    13  )
    14  
    15  type frameHeader struct {
    16  	ContentSize   uint64
    17  	WindowSize    uint32
    18  	SingleSegment bool
    19  	Checksum      bool
    20  	DictID        uint32
    21  }
    22  
    23  const maxHeaderSize = 14
    24  
    25  func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
    26  	dst = append(dst, frameMagic...)
    27  	var fhd uint8
    28  	if f.Checksum {
    29  		fhd |= 1 << 2
    30  	}
    31  	if f.SingleSegment {
    32  		fhd |= 1 << 5
    33  	}
    34  
    35  	var dictIDContent []byte
    36  	if f.DictID > 0 {
    37  		var tmp [4]byte
    38  		if f.DictID < 256 {
    39  			fhd |= 1
    40  			tmp[0] = uint8(f.DictID)
    41  			dictIDContent = tmp[:1]
    42  		} else if f.DictID < 1<<16 {
    43  			fhd |= 2
    44  			binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID))
    45  			dictIDContent = tmp[:2]
    46  		} else {
    47  			fhd |= 3
    48  			binary.LittleEndian.PutUint32(tmp[:4], f.DictID)
    49  			dictIDContent = tmp[:4]
    50  		}
    51  	}
    52  	var fcs uint8
    53  	if f.ContentSize >= 256 {
    54  		fcs++
    55  	}
    56  	if f.ContentSize >= 65536+256 {
    57  		fcs++
    58  	}
    59  	if f.ContentSize >= 0xffffffff {
    60  		fcs++
    61  	}
    62  
    63  	fhd |= fcs << 6
    64  
    65  	dst = append(dst, fhd)
    66  	if !f.SingleSegment {
    67  		const winLogMin = 10
    68  		windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
    69  		dst = append(dst, uint8(windowLog))
    70  	}
    71  	if f.DictID > 0 {
    72  		dst = append(dst, dictIDContent...)
    73  	}
    74  	switch fcs {
    75  	case 0:
    76  		if f.SingleSegment {
    77  			dst = append(dst, uint8(f.ContentSize))
    78  		}
    79  		// Unless SingleSegment is set, framessizes < 256 are nto stored.
    80  	case 1:
    81  		f.ContentSize -= 256
    82  		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8))
    83  	case 2:
    84  		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24))
    85  	case 3:
    86  		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24),
    87  			uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56))
    88  	default:
    89  		panic("invalid fcs")
    90  	}
    91  	return dst, nil
    92  }
    93  
    94  const skippableFrameHeader = 4 + 4
    95  
    96  // calcSkippableFrame will return a total size to be added for written
    97  // to be divisible by multiple.
    98  // The value will always be > skippableFrameHeader.
    99  // The function will panic if written < 0 or wantMultiple <= 0.
   100  func calcSkippableFrame(written, wantMultiple int64) int {
   101  	if wantMultiple <= 0 {
   102  		panic("wantMultiple <= 0")
   103  	}
   104  	if written < 0 {
   105  		panic("written < 0")
   106  	}
   107  	leftOver := written % wantMultiple
   108  	if leftOver == 0 {
   109  		return 0
   110  	}
   111  	toAdd := wantMultiple - leftOver
   112  	for toAdd < skippableFrameHeader {
   113  		toAdd += wantMultiple
   114  	}
   115  	return int(toAdd)
   116  }
   117  
   118  // skippableFrame will add a skippable frame with a total size of bytes.
   119  // total should be >= skippableFrameHeader and < math.MaxUint32.
   120  func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
   121  	if total == 0 {
   122  		return dst, nil
   123  	}
   124  	if total < skippableFrameHeader {
   125  		return dst, fmt.Errorf("requested skippable frame (%d) < 8", total)
   126  	}
   127  	if int64(total) > math.MaxUint32 {
   128  		return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total)
   129  	}
   130  	dst = append(dst, 0x50, 0x2a, 0x4d, 0x18)
   131  	f := uint32(total - skippableFrameHeader)
   132  	dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24))
   133  	start := len(dst)
   134  	dst = append(dst, make([]byte, f)...)
   135  	_, err := io.ReadFull(r, dst[start:])
   136  	return dst, err
   137  }