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>
125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
// SPDX-FileCopyrightText: 2024 Shun Sakai
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
package lzip
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"hash/crc32"
|
|
"io"
|
|
"slices"
|
|
|
|
"github.com/ulikunitz/xz/lzma"
|
|
)
|
|
|
|
// Reader is an [io.Reader] that can be read to retrieve uncompressed data from
|
|
// a lzip-format compressed file.
|
|
type Reader struct {
|
|
r io.Reader
|
|
decompressor *lzma.Reader
|
|
trailer
|
|
}
|
|
|
|
// NewReader creates a new [Reader] reading the given reader.
|
|
func NewReader(r io.Reader) (*Reader, error) {
|
|
z := new(Reader)
|
|
|
|
var header [headerSize]byte
|
|
if _, err := r.Read(header[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !slices.Equal(header[:magicSize], []byte(magic)) {
|
|
return nil, ErrInvalidMagic
|
|
}
|
|
|
|
switch v := header[4]; v {
|
|
case 0:
|
|
return nil, &UnsupportedVersionError{v}
|
|
case 1:
|
|
default:
|
|
return nil, &UnknownVersionError{v}
|
|
}
|
|
|
|
dictSize := uint32(1 << (header[5] & 0x1f))
|
|
dictSize -= (dictSize / 16) * uint32((header[5]>>5)&0x07)
|
|
|
|
switch {
|
|
case dictSize < MinDictSize:
|
|
return nil, &DictSizeTooSmallError{dictSize}
|
|
case dictSize > MaxDictSize:
|
|
return nil, &DictSizeTooLargeError{dictSize}
|
|
}
|
|
|
|
rb, err := io.ReadAll(r)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var lzmaHeader [lzma.HeaderLen]byte
|
|
lzmaHeader[0] = lzma.Properties{LC: 3, LP: 0, PB: 2}.Code()
|
|
binary.LittleEndian.PutUint32(lzmaHeader[1:5], dictSize)
|
|
copy(lzmaHeader[5:], rb[len(rb)-16:len(rb)-8])
|
|
|
|
z.memberSize = uint64(headerSize + len(rb))
|
|
if memberSize := z.memberSize; memberSize > MaxMemberSize {
|
|
return nil, &MemberSizeTooLargeError{memberSize}
|
|
}
|
|
|
|
rb = slices.Concat(lzmaHeader[:], rb)
|
|
|
|
r = bytes.NewReader(rb)
|
|
|
|
z.decompressor, err = lzma.NewReader(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
z.r = r
|
|
|
|
return z, nil
|
|
}
|
|
|
|
// Read reads uncompressed data from the stream.
|
|
func (z *Reader) Read(p []byte) (n int, err error) {
|
|
for n == 0 {
|
|
n, err = z.decompressor.Read(p)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
z.crc = crc32.Update(z.crc, crc32.IEEETable, p[:n])
|
|
z.dataSize += uint64(n)
|
|
|
|
if !errors.Is(err, io.EOF) {
|
|
return n, err
|
|
}
|
|
|
|
var trailer [trailerSize]byte
|
|
if _, err := io.ReadFull(z.r, trailer[:]); err != nil {
|
|
return n, err
|
|
}
|
|
|
|
crc := binary.LittleEndian.Uint32(trailer[:4])
|
|
if crc != z.crc {
|
|
return n, &InvalidCRCError{crc}
|
|
}
|
|
|
|
dataSize := binary.LittleEndian.Uint64(trailer[4:12])
|
|
if dataSize != z.dataSize {
|
|
return n, &InvalidDataSizeError{dataSize}
|
|
}
|
|
|
|
memberSize := binary.LittleEndian.Uint64(trailer[12:])
|
|
if memberSize != z.memberSize {
|
|
return n, &InvalidMemberSizeError{memberSize}
|
|
}
|
|
}
|
|
|
|
return n, nil
|
|
}
|