...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package compression
17
18 import (
19 "bufio"
20 "bytes"
21 "io"
22
23 "github.com/google/go-containerregistry/internal/gzip"
24 "github.com/google/go-containerregistry/internal/zstd"
25 "github.com/google/go-containerregistry/pkg/compression"
26 )
27
28
29 type Opener = func() (io.ReadCloser, error)
30
31
32 func GetCompression(opener Opener) (compression.Compression, error) {
33 rc, err := opener()
34 if err != nil {
35 return compression.None, err
36 }
37 defer rc.Close()
38
39 cp, _, err := PeekCompression(rc)
40 if err != nil {
41 return compression.None, err
42 }
43
44 return cp, nil
45 }
46
47
48
49
50
51
52 func PeekCompression(r io.Reader) (compression.Compression, PeekReader, error) {
53 pr := intoPeekReader(r)
54
55 if isGZip, _, err := checkHeader(pr, gzip.MagicHeader); err != nil {
56 return compression.None, pr, err
57 } else if isGZip {
58 return compression.GZip, pr, nil
59 }
60
61 if isZStd, _, err := checkHeader(pr, zstd.MagicHeader); err != nil {
62 return compression.None, pr, err
63 } else if isZStd {
64 return compression.ZStd, pr, nil
65 }
66
67 return compression.None, pr, nil
68 }
69
70
71 type PeekReader interface {
72 io.Reader
73 Peek(n int) ([]byte, error)
74 }
75
76
77
78 func intoPeekReader(r io.Reader) PeekReader {
79 if p, ok := r.(PeekReader); ok {
80 return p
81 }
82
83 return bufio.NewReader(r)
84 }
85
86
87 func checkHeader(pr PeekReader, expectedHeader []byte) (bool, PeekReader, error) {
88 header, err := pr.Peek(len(expectedHeader))
89 if err != nil {
90
91 if err == io.EOF {
92 return false, pr, nil
93 }
94 return false, pr, err
95 }
96 return bytes.Equal(header, expectedHeader), pr, nil
97 }
98
View as plain text