mattermost-community-enterp.../vendor/github.com/sorairolake/lzip-go/reader.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

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
}