From c2d900ec74e03e9c782cfe7b7ce06ff62cda6601 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sat, 29 Aug 2026 18:58:06 +0900 Subject: pkg: move from internal Closes #43. Signed-off-by: Ophestra --- pkg/compress.go | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 pkg/compress.go (limited to 'pkg/compress.go') diff --git a/pkg/compress.go b/pkg/compress.go new file mode 100644 index 00000000..22f990f1 --- /dev/null +++ b/pkg/compress.go @@ -0,0 +1,151 @@ +package pkg + +import ( + "compress/bzip2" + "compress/gzip" + "fmt" + "io" + "os" + + "hakurei.app/internal/xz" + "hakurei.app/internal/zstd" +) + +const ( + // Gzip denotes a stream compressed via [gzip]. + Gzip = iota + // Bzip2 denotes a stream compressed via [bzip2]. + Bzip2 + // Zstd denotes a stream compressed via [zstd]. + Zstd + // XZ denotes a stream compressed via [xz]. + XZ +) + +// A decompressArtifact is a [FileArtifact] decompressing a backing +// [FileArtifact] stream. +type decompressArtifact struct { + // Caller-supplied backing stream. + f Artifact + // Compression on top of the stream. + compress uint32 +} + +var _ FileArtifact = new(decompressArtifact) +var _ CuresExempt = new(decompressArtifact) + +// decompressArtifactNamed embeds decompressArtifact for a [fmt.Stringer] stream. +type decompressArtifactNamed struct { + decompressArtifact + // Copied from decompressArtifact.f. + name string +} + +var _ fmt.Stringer = new(decompressArtifactNamed) + +// NewDecompress returns a [FileArtifact] decompressing the supplied [Artifact]. +func NewDecompress(a Artifact, compress uint32) FileArtifact { + da := decompressArtifact{a, compress} + if s, ok := a.(fmt.Stringer); ok { + if name := s.String(); name != "" { + return &decompressArtifactNamed{da, name} + } + } + return &da +} + +// String returns the name of the underlying [Artifact] prefixed with decompress. +func (a *decompressArtifactNamed) String() string { return "decompress-" + a.name } + +// Kind returns the hardcoded [Kind] constant. +func (a *decompressArtifact) Kind() Kind { return KindDecompress } + +// Params writes value of compression enum. +func (a *decompressArtifact) Params(ctx *IContext) { ctx.WriteUint32(a.compress) } + +func init() { + register(KindDecompress, func(r *IRReader) Artifact { + a := NewDecompress(r.Next(), r.ReadUint32()) + if _, ok := r.Finalise(); ok { + panic(ErrUnexpectedChecksum) + } + return a + }) +} + +// Inputs returns a slice containing the backing file. +func (a *decompressArtifact) Inputs() []Artifact { + return []Artifact{a.f} +} + +// IsExclusive returns false: decompressor is fully sequential. +func (a *decompressArtifact) IsExclusive() bool { return false } + +// compoundCloser is an [io.ReadCloser] with an additional [io.Closer] attached. +type compoundCloser struct { + io.ReadCloser + c io.Closer +} + +// Close closes [io.ReadCloser] and the additional [io.Closer]. It returns the +// non-nil error returned by the underlying [io.ReadCloser], otherwise it +// returns the error returned by the additional [io.Closer]. +func (c compoundCloser) Close() error { + err := c.ReadCloser.Close() + if _err := c.c.Close(); err == nil { + err = _err + } + return err +} + +// IsExecutable returns false. +func (*decompressArtifact) IsExecutable() bool { return false } + +// Cure returns a decompressor [io.ReadCloser]. +func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) { + sr, err := r.Open(a.f) + if err != nil { + return nil, err + } + br := r.cache.getReaderRC(sr) + + var dr io.ReadCloser + switch a.compress { + case Gzip: + if dr, err = gzip.NewReader(br); err != nil { + _ = br.Close() + return nil, err + } + return compoundCloser{dr, br}, nil + + case Bzip2: + return struct { + io.Reader + io.Closer + }{bzip2.NewReader(br), br}, nil + + case Zstd: + return struct { + io.Reader + io.Closer + }{zstd.NewReader(br), br}, nil + + case XZ: + var _dr io.Reader + if _dr, err = xz.NewReader(br, 0); err != nil { + _ = br.Close() + return nil, err + } + return struct { + io.Reader + io.Closer + }{_dr, br}, nil + + default: + return nil, os.ErrInvalid + } +} + +// CuresExempt exempts the cheap [KindDecompress] implementation often part of +// a [FileArtifact] pipeline. +func (*decompressArtifact) CuresExempt() {} -- cgit v1.3.1