mattermost-community-enterp.../vendor/github.com/minio/minlz/lz4convert.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

455 lines
10 KiB
Go

// Copyright 2025 MinIO Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package minlz
import (
"encoding/binary"
"errors"
"fmt"
"io"
)
// lZ4Converter provides conversion from LZ4 blocks as defined here:
// https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
type lZ4Converter struct {
}
// errDstTooSmall is returned when provided destination is too small.
var errDstTooSmall = errors.New("minlz: destination too small")
// errIncompressible is returned when the block is incompressible.
var errIncompressible = errors.New("minlz: incompressible")
// ConvertBlock will convert an LZ4 block and append it as an MinLZ
// block without a block length to dst.
// The uncompressed size is returned as well.
// dst must have capacity to contain the entire compressed block,
// which may exceed MaxEncodedLen().
func (l *lZ4Converter) ConvertBlock(dst, src []byte) ([]byte, int, error) {
if len(src) == 0 {
return dst, 0, nil
}
const debug = false
const lz4MinMatch = 4
const inlineLits = true
// The block starts with the varint-encoded length of the decompressed bytes.
s, d := 0, len(dst)
dst = dst[:cap(dst)]
if !debug && hasAsm {
res, sz := cvtLZ4BlockAsm(dst[d:], src)
if res < 0 {
const (
errCorrupt = -1
errDstTooSmallRet = -2
)
switch res {
case errCorrupt:
return nil, 0, ErrCorrupt
case errDstTooSmallRet:
return nil, 0, errDstTooSmall
default:
return nil, 0, fmt.Errorf("unexpected result: %d", res)
}
}
if res < sz {
return nil, 0, errIncompressible
}
if d+sz > len(dst) {
return nil, 0, errDstTooSmall
}
return dst[:d+sz], res, nil
}
dLimit := len(dst) - 10
dStart := d
var lastOffset uint16
lastOffset = 1
var uncompressed int
if debug {
fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
}
for {
if s >= len(src) {
return dst[:d], 0, ErrCorrupt
}
if uncompressed > MaxBlockSize {
return dst[:d], 0, ErrTooLarge
}
// Read literal info
token := src[s]
ll := int(token >> 4)
ml := int(lz4MinMatch + (token & 0xf))
// If upper nibble is 15, literal length is extended
if token >= 0xf0 {
for {
s++
if s >= len(src) {
if debug {
fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
}
return dst[:d], 0, ErrCorrupt
}
val := src[s]
ll += int(val)
if val != 255 {
break
}
}
}
// Skip past token
if s+ll >= len(src) {
if debug {
fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
}
return nil, 0, ErrCorrupt
}
s++
var lits []byte
if ll > 0 {
if d+ll > dLimit {
if debug {
fmt.Printf("ERR: emit %d literals, d:%d, dLimit: %d\n", ll, d, dLimit)
}
return nil, 0, errDstTooSmall
}
if debug {
fmt.Printf("emit %d literals, pos:%d\n", ll, uncompressed)
}
lits = src[s : s+ll]
s += ll
}
// Check if we are done...
if s == len(src) && ml == lz4MinMatch {
if uncompressed+ll > MaxBlockSize {
return dst[:d], 0, ErrTooLarge
}
uncompressed += ll
d += emitLiteral(dst[d:], lits)
break
}
// 2 byte offset
if s >= len(src)-2 {
if debug {
fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
}
return nil, 0, ErrCorrupt
}
offset := load16(src, s)
isRepeat := offset == lastOffset
if len(lits) > 0 {
// There are no offset >64K, so copy3 doesn't apply.
if !inlineLits || len(lits) > maxCopy2Lits ||
(offset <= 1024 && ml > copy2LitMaxLen) || // Comment out for speed.
offset < 64 ||
isRepeat {
d += emitLiteral(dst[d:], lits)
lits = nil
}
uncompressed += ll
}
s += 2
if offset == 0 {
if debug {
fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
}
return nil, 0, ErrCorrupt
}
if int(offset) > uncompressed {
if debug {
fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
}
return nil, 0, ErrCorrupt
}
if ml == lz4MinMatch+15 {
for {
if s >= len(src) {
if debug {
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
}
return nil, 0, ErrCorrupt
}
val := src[s]
s++
ml += int(val)
if val != 255 {
if s >= len(src) {
if debug {
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
}
return nil, 0, ErrCorrupt
}
break
}
}
}
if isRepeat {
if debug {
fmt.Printf("emit repeat, length: %d, offset: %d, pos:%d\n", ml, offset, uncompressed)
}
d += emitRepeat(dst[d:], ml)
} else {
if len(lits) > 0 {
if debug {
fmt.Printf("emit %d lits + copy, length: %d, offset: %d, pos:%d\n", len(lits), ml, offset, uncompressed)
}
d += emitCopyLits2(dst[d:], lits, int(offset), ml)
} else {
if debug {
fmt.Printf("emit copy, length: %d, offset: %d, pos:%d\n", ml, offset, uncompressed)
}
d += emitCopy(dst[d:], int(offset), ml)
}
lastOffset = offset
}
uncompressed += ml
if d > dLimit {
return nil, 0, errDstTooSmall
}
}
if uncompressed < d-dStart {
return nil, 0, errIncompressible
}
return dst[:d], uncompressed, nil
}
func (l *lZ4Converter) ConvertStream(w io.Writer, r io.Reader) error {
var tmp [4]byte
const debug = false
for {
// Read magic
_, err := io.ReadFull(r, tmp[:4])
if err != nil {
if err == io.EOF {
return nil
}
return err
}
if binary.LittleEndian.Uint32(tmp[:4]) != 0x184D2204 {
return fmt.Errorf("minlz: invalid lz4 magic: %x", tmp[:4])
}
// Read Frame Descriptor
_, err = io.ReadFull(r, tmp[:2])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
if tmp[0]&(1<<3) != 0 {
// Content Size - ignore
var tmp2 [8]byte
_, err = io.ReadFull(r, tmp2[:8])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
}
if tmp[0]&(1<<0) != 0 {
// DictID - fail if set
var tmp2 [4]byte
_, err = io.ReadFull(r, tmp2[:2])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
if tmp2 != [4]byte{0, 0, 0, 0} {
return fmt.Errorf("minlz: dictID not supported")
}
}
// Version
if tmp[0]>>6 != 1 {
return fmt.Errorf("minlz: unknown version: %d %d", tmp[0]>>6, tmp[0])
}
// Block Independence
if tmp[0]&(1<<5) == 0 {
return fmt.Errorf("minlz: block dependence not supported")
}
blockCrc := tmp[0]&(1<<4) != 0
contentCrc := tmp[0]&(1<<2) != 0
maxBlockSz := 0
// Block Maximum Size
bz := int(tmp[1] >> 4 & 0x7)
switch bz {
case 4:
maxBlockSz = 64 << 10
case 5:
maxBlockSz = 256 << 10
case 6:
maxBlockSz = 1 << 20
case 7:
maxBlockSz = 4 << 20
default:
return fmt.Errorf("minlz: invalid block size: %d", bz)
}
// Header Checksum
_, err = io.ReadFull(r, tmp[:1])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
var n int
n, err = w.Write(makeHeader(maxBlockSz))
if err != nil {
return err
}
if n != len(magicChunk)+1 {
return io.ErrShortWrite
}
block := make([]byte, maxBlockSz)
dst := make([]byte, maxBlockSz)
uncompSize := MaxEncodedLen(maxBlockSz)
if debug {
fmt.Println("hasCrc:", blockCrc)
}
for {
// Read block size
_, err := io.ReadFull(r, tmp[:4])
if err != nil {
if err == io.EOF {
break
}
return err
}
compressed := true
blockSize := int(binary.LittleEndian.Uint32(tmp[:4]))
if blockSize == 0 {
if blockCrc {
_, err = io.ReadFull(r, tmp[:4])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
}
break
}
if blockSize>>31 != 0 {
compressed = false
blockSize &= (1 << 31) - 1
}
if blockSize > maxBlockSize {
return fmt.Errorf("minlz: block size too large: %d", blockSize)
}
_, err = io.ReadFull(r, block[:blockSize])
if err != nil {
return err
}
// Read checksum (ignored)
if blockCrc {
_, err = io.ReadFull(r, tmp[:4])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
}
if !compressed {
var obuf [8]byte
uncompressed := block[:blockSize]
// Set to uncompressed.
chunkType := uint8(chunkTypeUncompressedData)
chunkLen := 4 + len(uncompressed)
// Write as uncompressed.
checksum := crc(uncompressed)
obuf[0] = chunkType
obuf[1] = uint8(chunkLen >> 0)
obuf[2] = uint8(chunkLen >> 8)
obuf[3] = uint8(chunkLen >> 16)
obuf[4] = uint8(checksum >> 0)
obuf[5] = uint8(checksum >> 8)
obuf[6] = uint8(checksum >> 16)
obuf[7] = uint8(checksum >> 24)
_, err = w.Write(obuf[:8])
if err != nil {
return err
}
_, err = w.Write(uncompressed)
if err != nil {
return err
}
uncompSize += len(uncompressed)
continue
}
// Convert block
out, sz, err := l.ConvertBlock(dst[:0], block[:blockSize])
if err != nil {
return err
}
out = out[3:]
if debug {
fmt.Println(blockSize, "=>", len(out), "uncompressed:", sz, "ratio:", 100*float64(len(out))/float64(blockSize))
}
var obuf [8]byte
chunkType := uint8(chunkTypeMinLZCompressedDataCompCRC)
chunkLen := 4 + len(out)
// Write block.
checksum := crc(out)
obuf[0] = chunkType
obuf[1] = uint8(chunkLen >> 0)
obuf[2] = uint8(chunkLen >> 8)
obuf[3] = uint8(chunkLen >> 16)
obuf[4] = uint8(checksum >> 0)
obuf[5] = uint8(checksum >> 8)
obuf[6] = uint8(checksum >> 16)
obuf[7] = uint8(checksum >> 24)
_, err = w.Write(obuf[:8])
if err != nil {
return err
}
_, err = w.Write(out)
uncompSize += sz
}
if contentCrc {
// Read content crc (ignored)
_, err = io.ReadFull(r, tmp[:4])
if err != nil {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
}
var tmp [4 + binary.MaxVarintLen64]byte
tmp[0] = chunkTypeEOF
// Write uncompressed size.
n = binary.PutUvarint(tmp[4:], uint64(uncompSize))
tmp[1] = uint8(n)
n += 4
_, err = w.Write(tmp[:n])
if err != nil {
return err
}
}
}