 30802fac73
			
		
	
	30802fac73
	
	
	
		
			
			zstd is a compression algorithm that has a very fast decoder, while providing also good compression ratios. The fast decoder makes it suitable for container images, as decompressing the tarballs is a very expensive operation. https://github.com/opencontainers/image-spec/pull/788 added support for zstd to the OCI image specs. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
		
			
				
	
	
		
			138 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019+ Klaus Post. All rights reserved.
 | |
| // License information can be found in the LICENSE file.
 | |
| // Based on work by Yann Collet, released under BSD License.
 | |
| 
 | |
| package zstd
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"math"
 | |
| 	"math/bits"
 | |
| )
 | |
| 
 | |
| type frameHeader struct {
 | |
| 	ContentSize   uint64
 | |
| 	WindowSize    uint32
 | |
| 	SingleSegment bool
 | |
| 	Checksum      bool
 | |
| 	DictID        uint32
 | |
| }
 | |
| 
 | |
| const maxHeaderSize = 14
 | |
| 
 | |
| func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
 | |
| 	dst = append(dst, frameMagic...)
 | |
| 	var fhd uint8
 | |
| 	if f.Checksum {
 | |
| 		fhd |= 1 << 2
 | |
| 	}
 | |
| 	if f.SingleSegment {
 | |
| 		fhd |= 1 << 5
 | |
| 	}
 | |
| 
 | |
| 	var dictIDContent []byte
 | |
| 	if f.DictID > 0 {
 | |
| 		var tmp [4]byte
 | |
| 		if f.DictID < 256 {
 | |
| 			fhd |= 1
 | |
| 			tmp[0] = uint8(f.DictID)
 | |
| 			dictIDContent = tmp[:1]
 | |
| 		} else if f.DictID < 1<<16 {
 | |
| 			fhd |= 2
 | |
| 			binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID))
 | |
| 			dictIDContent = tmp[:2]
 | |
| 		} else {
 | |
| 			fhd |= 3
 | |
| 			binary.LittleEndian.PutUint32(tmp[:4], f.DictID)
 | |
| 			dictIDContent = tmp[:4]
 | |
| 		}
 | |
| 	}
 | |
| 	var fcs uint8
 | |
| 	if f.ContentSize >= 256 {
 | |
| 		fcs++
 | |
| 	}
 | |
| 	if f.ContentSize >= 65536+256 {
 | |
| 		fcs++
 | |
| 	}
 | |
| 	if f.ContentSize >= 0xffffffff {
 | |
| 		fcs++
 | |
| 	}
 | |
| 
 | |
| 	fhd |= fcs << 6
 | |
| 
 | |
| 	dst = append(dst, fhd)
 | |
| 	if !f.SingleSegment {
 | |
| 		const winLogMin = 10
 | |
| 		windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
 | |
| 		dst = append(dst, uint8(windowLog))
 | |
| 	}
 | |
| 	if f.DictID > 0 {
 | |
| 		dst = append(dst, dictIDContent...)
 | |
| 	}
 | |
| 	switch fcs {
 | |
| 	case 0:
 | |
| 		if f.SingleSegment {
 | |
| 			dst = append(dst, uint8(f.ContentSize))
 | |
| 		}
 | |
| 		// Unless SingleSegment is set, framessizes < 256 are nto stored.
 | |
| 	case 1:
 | |
| 		f.ContentSize -= 256
 | |
| 		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8))
 | |
| 	case 2:
 | |
| 		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24))
 | |
| 	case 3:
 | |
| 		dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24),
 | |
| 			uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56))
 | |
| 	default:
 | |
| 		panic("invalid fcs")
 | |
| 	}
 | |
| 	return dst, nil
 | |
| }
 | |
| 
 | |
| const skippableFrameHeader = 4 + 4
 | |
| 
 | |
| // calcSkippableFrame will return a total size to be added for written
 | |
| // to be divisible by multiple.
 | |
| // The value will always be > skippableFrameHeader.
 | |
| // The function will panic if written < 0 or wantMultiple <= 0.
 | |
| func calcSkippableFrame(written, wantMultiple int64) int {
 | |
| 	if wantMultiple <= 0 {
 | |
| 		panic("wantMultiple <= 0")
 | |
| 	}
 | |
| 	if written < 0 {
 | |
| 		panic("written < 0")
 | |
| 	}
 | |
| 	leftOver := written % wantMultiple
 | |
| 	if leftOver == 0 {
 | |
| 		return 0
 | |
| 	}
 | |
| 	toAdd := wantMultiple - leftOver
 | |
| 	for toAdd < skippableFrameHeader {
 | |
| 		toAdd += wantMultiple
 | |
| 	}
 | |
| 	return int(toAdd)
 | |
| }
 | |
| 
 | |
| // skippableFrame will add a skippable frame with a total size of bytes.
 | |
| // total should be >= skippableFrameHeader and < math.MaxUint32.
 | |
| func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
 | |
| 	if total == 0 {
 | |
| 		return dst, nil
 | |
| 	}
 | |
| 	if total < skippableFrameHeader {
 | |
| 		return dst, fmt.Errorf("requested skippable frame (%d) < 8", total)
 | |
| 	}
 | |
| 	if int64(total) > math.MaxUint32 {
 | |
| 		return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total)
 | |
| 	}
 | |
| 	dst = append(dst, 0x50, 0x2a, 0x4d, 0x18)
 | |
| 	f := uint32(total - skippableFrameHeader)
 | |
| 	dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24))
 | |
| 	start := len(dst)
 | |
| 	dst = append(dst, make([]byte, f)...)
 | |
| 	_, err := io.ReadFull(r, dst[start:])
 | |
| 	return dst, err
 | |
| }
 |