diff options
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/header.go')
-rw-r--r-- | vendor/github.com/ulikunitz/xz/lzma/header.go | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/vendor/github.com/ulikunitz/xz/lzma/header.go b/vendor/github.com/ulikunitz/xz/lzma/header.go new file mode 100644 index 0000000..bc70896 --- /dev/null +++ b/vendor/github.com/ulikunitz/xz/lzma/header.go | |||
@@ -0,0 +1,167 @@ | |||
1 | // Copyright 2014-2017 Ulrich Kunitz. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE file. | ||
4 | |||
5 | package lzma | ||
6 | |||
7 | import ( | ||
8 | "errors" | ||
9 | "fmt" | ||
10 | ) | ||
11 | |||
12 | // uint32LE reads an uint32 integer from a byte slice | ||
13 | func uint32LE(b []byte) uint32 { | ||
14 | x := uint32(b[3]) << 24 | ||
15 | x |= uint32(b[2]) << 16 | ||
16 | x |= uint32(b[1]) << 8 | ||
17 | x |= uint32(b[0]) | ||
18 | return x | ||
19 | } | ||
20 | |||
21 | // uint64LE converts the uint64 value stored as little endian to an uint64 | ||
22 | // value. | ||
23 | func uint64LE(b []byte) uint64 { | ||
24 | x := uint64(b[7]) << 56 | ||
25 | x |= uint64(b[6]) << 48 | ||
26 | x |= uint64(b[5]) << 40 | ||
27 | x |= uint64(b[4]) << 32 | ||
28 | x |= uint64(b[3]) << 24 | ||
29 | x |= uint64(b[2]) << 16 | ||
30 | x |= uint64(b[1]) << 8 | ||
31 | x |= uint64(b[0]) | ||
32 | return x | ||
33 | } | ||
34 | |||
35 | // putUint32LE puts an uint32 integer into a byte slice that must have at least | ||
36 | // a length of 4 bytes. | ||
37 | func putUint32LE(b []byte, x uint32) { | ||
38 | b[0] = byte(x) | ||
39 | b[1] = byte(x >> 8) | ||
40 | b[2] = byte(x >> 16) | ||
41 | b[3] = byte(x >> 24) | ||
42 | } | ||
43 | |||
44 | // putUint64LE puts the uint64 value into the byte slice as little endian | ||
45 | // value. The byte slice b must have at least place for 8 bytes. | ||
46 | func putUint64LE(b []byte, x uint64) { | ||
47 | b[0] = byte(x) | ||
48 | b[1] = byte(x >> 8) | ||
49 | b[2] = byte(x >> 16) | ||
50 | b[3] = byte(x >> 24) | ||
51 | b[4] = byte(x >> 32) | ||
52 | b[5] = byte(x >> 40) | ||
53 | b[6] = byte(x >> 48) | ||
54 | b[7] = byte(x >> 56) | ||
55 | } | ||
56 | |||
57 | // noHeaderSize defines the value of the length field in the LZMA header. | ||
58 | const noHeaderSize uint64 = 1<<64 - 1 | ||
59 | |||
60 | // HeaderLen provides the length of the LZMA file header. | ||
61 | const HeaderLen = 13 | ||
62 | |||
63 | // header represents the header of an LZMA file. | ||
64 | type header struct { | ||
65 | properties Properties | ||
66 | dictCap int | ||
67 | // uncompressed size; negative value if no size is given | ||
68 | size int64 | ||
69 | } | ||
70 | |||
71 | // marshalBinary marshals the header. | ||
72 | func (h *header) marshalBinary() (data []byte, err error) { | ||
73 | if err = h.properties.verify(); err != nil { | ||
74 | return nil, err | ||
75 | } | ||
76 | if !(0 <= h.dictCap && int64(h.dictCap) <= MaxDictCap) { | ||
77 | return nil, fmt.Errorf("lzma: DictCap %d out of range", | ||
78 | h.dictCap) | ||
79 | } | ||
80 | |||
81 | data = make([]byte, 13) | ||
82 | |||
83 | // property byte | ||
84 | data[0] = h.properties.Code() | ||
85 | |||
86 | // dictionary capacity | ||
87 | putUint32LE(data[1:5], uint32(h.dictCap)) | ||
88 | |||
89 | // uncompressed size | ||
90 | var s uint64 | ||
91 | if h.size > 0 { | ||
92 | s = uint64(h.size) | ||
93 | } else { | ||
94 | s = noHeaderSize | ||
95 | } | ||
96 | putUint64LE(data[5:], s) | ||
97 | |||
98 | return data, nil | ||
99 | } | ||
100 | |||
101 | // unmarshalBinary unmarshals the header. | ||
102 | func (h *header) unmarshalBinary(data []byte) error { | ||
103 | if len(data) != HeaderLen { | ||
104 | return errors.New("lzma.unmarshalBinary: data has wrong length") | ||
105 | } | ||
106 | |||
107 | // properties | ||
108 | var err error | ||
109 | if h.properties, err = PropertiesForCode(data[0]); err != nil { | ||
110 | return err | ||
111 | } | ||
112 | |||
113 | // dictionary capacity | ||
114 | h.dictCap = int(uint32LE(data[1:])) | ||
115 | if h.dictCap < 0 { | ||
116 | return errors.New( | ||
117 | "LZMA header: dictionary capacity exceeds maximum " + | ||
118 | "integer") | ||
119 | } | ||
120 | |||
121 | // uncompressed size | ||
122 | s := uint64LE(data[5:]) | ||
123 | if s == noHeaderSize { | ||
124 | h.size = -1 | ||
125 | } else { | ||
126 | h.size = int64(s) | ||
127 | if h.size < 0 { | ||
128 | return errors.New( | ||
129 | "LZMA header: uncompressed size " + | ||
130 | "out of int64 range") | ||
131 | } | ||
132 | } | ||
133 | |||
134 | return nil | ||
135 | } | ||
136 | |||
137 | // validDictCap checks whether the dictionary capacity is correct. This | ||
138 | // is used to weed out wrong file headers. | ||
139 | func validDictCap(dictcap int) bool { | ||
140 | if int64(dictcap) == MaxDictCap { | ||
141 | return true | ||
142 | } | ||
143 | for n := uint(10); n < 32; n++ { | ||
144 | if dictcap == 1<<n { | ||
145 | return true | ||
146 | } | ||
147 | if dictcap == 1<<n+1<<(n-1) { | ||
148 | return true | ||
149 | } | ||
150 | } | ||
151 | return false | ||
152 | } | ||
153 | |||
154 | // ValidHeader checks for a valid LZMA file header. It allows only | ||
155 | // dictionary sizes of 2^n or 2^n+2^(n-1) with n >= 10 or 2^32-1. If | ||
156 | // there is an explicit size it must not exceed 256 GiB. The length of | ||
157 | // the data argument must be HeaderLen. | ||
158 | func ValidHeader(data []byte) bool { | ||
159 | var h header | ||
160 | if err := h.unmarshalBinary(data); err != nil { | ||
161 | return false | ||
162 | } | ||
163 | if !validDictCap(h.dictCap) { | ||
164 | return false | ||
165 | } | ||
166 | return h.size < 0 || h.size <= 1<<38 | ||
167 | } | ||