-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomp.go
More file actions
139 lines (125 loc) · 4.26 KB
/
comp.go
File metadata and controls
139 lines (125 loc) · 4.26 KB
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
138
139
package squashfs
import (
"bytes"
"compress/zlib"
"fmt"
"io"
)
// Compression represents the compression algorithm used in a SquashFS filesystem.
// Different compression methods can be used to optimize for size or decompression speed.
// By default, only GZip compression is supported. Additional compression formats can be
// enabled through build tags or manually registering decompressors.
type Compression uint16
const (
GZip Compression = iota + 1 // GZip compression (zlib, always supported)
LZMA // LZMA compression (currently not implemented via build tag)
LZO // LZO compression (currently not implemented via build tag)
XZ // XZ compression (enabled with "xz" build tag)
LZ4 // LZ4 compression (currently not implemented via build tag)
ZSTD // Zstandard compression (enabled with "zstd" build tag)
)
type Decompressor func(buf []byte) ([]byte, error)
type Compressor func(buf []byte) ([]byte, error)
// CompHandler contains both compression and decompression functions for a compression method.
type CompHandler struct {
Decompress Decompressor
Compress Compressor
}
var compHandlers = map[Compression]*CompHandler{
GZip: {
Decompress: MakeDecompressorErr(zlib.NewReader),
Compress: zlibCompress,
},
}
func (s Compression) String() string {
switch s {
case GZip:
return "GZip"
case LZMA:
return "LZMA"
case LZO:
return "LZO"
case XZ:
return "XZ"
case LZ4:
return "LZ4"
case ZSTD:
return "ZSTD"
}
return fmt.Sprintf("Compression(%d)", s)
}
func (s Compression) decompress(buf []byte) ([]byte, error) {
if h, ok := compHandlers[s]; ok && h.Decompress != nil {
return h.Decompress(buf)
}
return nil, fmt.Errorf("unsupported compression format %s", s.String())
}
func (s Compression) compress(buf []byte) ([]byte, error) {
if h, ok := compHandlers[s]; ok && h.Compress != nil {
return h.Compress(buf)
}
return nil, fmt.Errorf("unsupported compression format %s", s.String())
}
// zlibCompress compresses data using zlib (GZip compression)
func zlibCompress(buf []byte) ([]byte, error) {
var out bytes.Buffer
w := zlib.NewWriter(&out)
if _, err := w.Write(buf); err != nil {
_ = w.Close()
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return out.Bytes(), nil
}
// RegisterDecompressor can be used to register a decompressor for squashfs.
//
// Deprecated: Use RegisterCompHandler(method, &CompHandler{Decompress: decompressor}) instead.
func RegisterDecompressor(method Compression, dcomp Decompressor) {
if compHandlers[method] == nil {
compHandlers[method] = &CompHandler{}
}
compHandlers[method].Decompress = dcomp
}
// RegisterCompHandler can be used to register both compressor and decompressor
// for a compression method at once by providing a CompHandler struct.
func RegisterCompHandler(method Compression, handler *CompHandler) {
compHandlers[method] = handler
}
// MakeDecompressor allows using a decompressor made for archive/zip with
// SquashFs. It has some overhead as instead of simply dealing with buffer this
// uses the reader/writer API, but should allow to easily handle some formats.
//
// Example use:
// * squashfs.RegisterDecompressor(squashfs.ZSTD, squashfs.MakeDecompressor(zstd.ZipDecompressor()))
// * squashfs.RegisterDecompressor(squashfs.LZ4, squashfs.MakeDecompressor(lz4.NewReader)))
func MakeDecompressor(dec func(r io.Reader) io.ReadCloser) Decompressor {
return func(buf []byte) ([]byte, error) {
r := bytes.NewReader(buf)
p := dec(r)
defer func() { _ = p.Close() }()
w := &bytes.Buffer{}
_, err := io.Copy(w, p)
return w.Bytes(), err
}
}
// MakeDecompressorErr is similar to MakeDecompressor but the factory method also
// returns an error.
//
// Example use:
// * squashfs.RegisterDecompressor(squashfs.LZMA, squashfs.MakeDecompressorErr(lzma.NewReader))
// * squashfs.RegisterDecompressor(squashfs.XZ, squashfs.MakeDecompressorErr(xz.NewReader))
func MakeDecompressorErr(dec func(r io.Reader) (io.ReadCloser, error)) Decompressor {
return func(buf []byte) ([]byte, error) {
r := bytes.NewReader(buf)
p, err := dec(r)
if err != nil {
return nil, err
}
defer func() { _ = p.Close() }()
w := &bytes.Buffer{}
_, err = io.Copy(w, p)
return w.Bytes(), err
}
}