1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
package pkg
import (
"compress/bzip2"
"compress/gzip"
"fmt"
"io"
"os"
"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
)
// 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
default:
return nil, os.ErrInvalid
}
}
// CuresExempt exempts the cheap [KindDecompress] implementation often part of
// a [FileArtifact] pipeline.
func (*decompressArtifact) CuresExempt() {}
|