aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/ulikunitz/xz/lzma/header.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/header.go')
-rw-r--r--vendor/github.com/ulikunitz/xz/lzma/header.go167
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
5package lzma
6
7import (
8 "errors"
9 "fmt"
10)
11
12// uint32LE reads an uint32 integer from a byte slice
13func 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.
23func 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.
37func 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.
46func 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.
58const noHeaderSize uint64 = 1<<64 - 1
59
60// HeaderLen provides the length of the LZMA file header.
61const HeaderLen = 13
62
63// header represents the header of an LZMA file.
64type 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.
72func (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.
102func (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.
139func 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.
158func 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}