// Copyright (c) 2022 Klaus Post. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package s2import ()// LZ4sConverter provides conversion from LZ4s.// (Intel modified LZ4 Blocks)// https://cdrdv2-public.intel.com/743912/743912-qat-programmers-guide-v2.0.pdf// LZ4s is a variant of LZ4 block format. LZ4s should be considered as an intermediate compressed block format.// The LZ4s format is selected when the application sets the compType to CPA_DC_LZ4S in CpaDcSessionSetupData.// The LZ4s block returned by the IntelĀ® QAT hardware can be used by an external// software post-processing to generate other compressed data formats.// The following table lists the differences between LZ4 and LZ4s block format. LZ4s block format uses// the same high-level formatting as LZ4 block format with the following encoding changes:// For Min Match of 4 bytes, Copy length value 1-15 means length 4-18 with 18 bytes adding an extra byte.// ONLY "Min match of 4 bytes" is supported.typeLZ4sConverterstruct {}// ConvertBlock will convert an LZ4s block and append it as an S2// block without block length to dst.// The uncompressed size is returned as well.// dst must have capacity to contain the entire compressed block.func ( *LZ4sConverter) (, []byte) ([]byte, int, error) {iflen() == 0 {return , 0, nil }const = falseconst = trueconst = 3 , := 0, len() = [:cap()]if ! && hasAmd64Asm { , := cvtLZ4sBlockAsm([:], )if < 0 {const ( = -1 = -2 )switch {case :returnnil, 0, ErrCorruptcase :returnnil, 0, ErrDstTooSmalldefault:returnnil, 0, fmt.Errorf("unexpected result: %d", ) } }if + > len() {returnnil, 0, ErrDstTooSmall }return [:+], , nil } := len() - 10varuint16varintif {fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(), len()) }for {if >= len() {return [:], 0, ErrCorrupt }// Read literal info := [] := int( >> 4) := int( + ( & 0xf))// If upper nibble is 15, literal length is extendedif >= 0xf0 {for { ++if >= len() {if {fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", , len()) }return [:], 0, ErrCorrupt } := [] += int()if != 255 {break } } }// Skip past tokenif + >= len() {if {fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", , , len()) }returnnil, 0, ErrCorrupt } ++if > 0 {if + > {returnnil, 0, ErrDstTooSmall }if {fmt.Printf("emit %d literals\n", ) } += emitLiteralGo([:], [:+]) += += }// Check if we are done...if == {if == len() {break }// 0 bytes.continue }// 2 byte offsetif >= len()-2 {if {fmt.Printf("s (%d) >= len(src)-2 (%d)", , len()-2) }returnnil, 0, ErrCorrupt } := binary.LittleEndian.Uint16([:]) += 2if == 0 {if {fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", , len()-) }returnnil, 0, ErrCorrupt }ifint() > {if {fmt.Printf("error: offset (%d)> uncompressed (%d)\n", , ) }returnnil, 0, ErrCorrupt }if == +15 {for {if >= len() {if {fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", , len()) }returnnil, 0, ErrCorrupt } := [] ++ += int()if != 255 {if >= len() {if {fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", , len()) }returnnil, 0, ErrCorrupt }break } } }if == {if {fmt.Printf("emit repeat, length: %d, offset: %d\n", , ) }if ! { += emitRepeat16([:], , ) } else { := := [:]forlen() > 5 {// Repeat offset, make length cheaper -= 4if <= 4 { [0] = uint8()<<2 | tagCopy1 [1] = 0 += 2break }if < 8 && < 2048 {// Encode WITH offset [1] = uint8() [0] = uint8(>>8)<<5 | uint8()<<2 | tagCopy1 += 2break }if < (1<<8)+4 { -= 4 [2] = uint8() [1] = 0 [0] = 5<<2 | tagCopy1 += 3break }if < (1<<16)+(1<<8) { -= 1 << 8 [3] = uint8( >> 8) [2] = uint8( >> 0) [1] = 0 [0] = 6<<2 | tagCopy1 += 4break }const = (1 << 24) - 1 -= 1 << 16 := 0if > { = - + 4 = - 4 } [4] = uint8( >> 16) [3] = uint8( >> 8) [2] = uint8( >> 0) [1] = 0 [0] = 7<<2 | tagCopy1if > 0 { += 5 + emitRepeat16([5:], , )break } += 5break } } } else {if {fmt.Printf("emit copy, length: %d, offset: %d\n", , ) }if ! { += emitCopy16([:], , ) } else { := := [:]forlen() > 5 {// Offset no more than 2 bytes.if > 64 { := 3if < 2048 {// emit 8 bytes as tagCopy1, rest as repeats. [1] = uint8() [0] = uint8(>>8)<<5 | uint8(8-4)<<2 | tagCopy1 -= 8 = 2 } else {// Emit a length 60 copy, encoded as 3 bytes. // Emit remaining as repeat value (minimum 4 bytes). [2] = uint8( >> 8) [1] = uint8() [0] = 59<<2 | tagCopy2 -= 60 }// Emit remaining as repeats, at least 4 bytes remain. += + emitRepeat16([:], , )break }if >= 12 || >= 2048 {// Emit the remaining copy, encoded as 3 bytes. [2] = uint8( >> 8) [1] = uint8() [0] = uint8(-1)<<2 | tagCopy2 += 3break }// Emit the remaining copy, encoded as 2 bytes. [1] = uint8() [0] = uint8(>>8)<<5 | uint8(-4)<<2 | tagCopy1 += 2break } } = } += if > {returnnil, 0, ErrDstTooSmall } }return [:], , nil}// ConvertBlockSnappy will convert an LZ4s block and append it// as a Snappy block without block length to dst.// The uncompressed size is returned as well.// dst must have capacity to contain the entire compressed block.func ( *LZ4sConverter) (, []byte) ([]byte, int, error) {iflen() == 0 {return , 0, nil }const = falseconst = 3 , := 0, len() = [:cap()]// Use assembly when possibleif ! && hasAmd64Asm { , := cvtLZ4sBlockSnappyAsm([:], )if < 0 {const ( = -1 = -2 )switch {case :returnnil, 0, ErrCorruptcase :returnnil, 0, ErrDstTooSmalldefault:returnnil, 0, fmt.Errorf("unexpected result: %d", ) } }if + > len() {returnnil, 0, ErrDstTooSmall }return [:+], , nil } := len() - 10varintif {fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(), len()) }for {if >= len() {returnnil, 0, ErrCorrupt }// Read literal info := [] := int( >> 4) := int( + ( & 0xf))// If upper nibble is 15, literal length is extendedif >= 0xf0 {for { ++if >= len() {if {fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", , len()) }returnnil, 0, ErrCorrupt } := [] += int()if != 255 {break } } }// Skip past tokenif + >= len() {if {fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", , , len()) }returnnil, 0, ErrCorrupt } ++if > 0 {if + > {returnnil, 0, ErrDstTooSmall }if {fmt.Printf("emit %d literals\n", ) } += emitLiteralGo([:], [:+]) += += }// Check if we are done...if == {if == len() {break }// 0 bytes.continue }// 2 byte offsetif >= len()-2 {if {fmt.Printf("s (%d) >= len(src)-2 (%d)", , len()-2) }returnnil, 0, ErrCorrupt } := binary.LittleEndian.Uint16([:]) += 2if == 0 {if {fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", , len()-) }returnnil, 0, ErrCorrupt }ifint() > {if {fmt.Printf("error: offset (%d)> uncompressed (%d)\n", , ) }returnnil, 0, ErrCorrupt }if == +15 {for {if >= len() {if {fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", , len()) }returnnil, 0, ErrCorrupt } := [] ++ += int()if != 255 {if >= len() {if {fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", , len()) }returnnil, 0, ErrCorrupt }break } } }if {fmt.Printf("emit copy, length: %d, offset: %d\n", , ) } := // d += emitCopyNoRepeat(dst[d:], int(offset), ml)for > 0 {if >= {returnnil, 0, ErrDstTooSmall }// Offset no more than 2 bytes.if > 64 {// Emit a length 64 copy, encoded as 3 bytes. [+2] = uint8( >> 8) [+1] = uint8() [+0] = 63<<2 | tagCopy2 -= 64 += 3continue }if >= 12 || >= 2048 || < 4 {// Emit the remaining copy, encoded as 3 bytes. [+2] = uint8( >> 8) [+1] = uint8() [+0] = uint8(-1)<<2 | tagCopy2 += 3break }// Emit the remaining copy, encoded as 2 bytes. [+1] = uint8() [+0] = uint8(>>8)<<5 | uint8(-4)<<2 | tagCopy1 += 2break } += if > {returnnil, 0, ErrDstTooSmall } }return [:], , 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.