diff options
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/distcodec.go')
-rw-r--r-- | vendor/github.com/ulikunitz/xz/lzma/distcodec.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/vendor/github.com/ulikunitz/xz/lzma/distcodec.go b/vendor/github.com/ulikunitz/xz/lzma/distcodec.go new file mode 100644 index 0000000..b053a2d --- /dev/null +++ b/vendor/github.com/ulikunitz/xz/lzma/distcodec.go | |||
@@ -0,0 +1,156 @@ | |||
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 | // Constants used by the distance codec. | ||
8 | const ( | ||
9 | // minimum supported distance | ||
10 | minDistance = 1 | ||
11 | // maximum supported distance, value is used for the eos marker. | ||
12 | maxDistance = 1 << 32 | ||
13 | // number of the supported len states | ||
14 | lenStates = 4 | ||
15 | // start for the position models | ||
16 | startPosModel = 4 | ||
17 | // first index with align bits support | ||
18 | endPosModel = 14 | ||
19 | // bits for the position slots | ||
20 | posSlotBits = 6 | ||
21 | // number of align bits | ||
22 | alignBits = 4 | ||
23 | // maximum position slot | ||
24 | maxPosSlot = 63 | ||
25 | ) | ||
26 | |||
27 | // distCodec provides encoding and decoding of distance values. | ||
28 | type distCodec struct { | ||
29 | posSlotCodecs [lenStates]treeCodec | ||
30 | posModel [endPosModel - startPosModel]treeReverseCodec | ||
31 | alignCodec treeReverseCodec | ||
32 | } | ||
33 | |||
34 | // deepcopy initializes dc as deep copy of the source. | ||
35 | func (dc *distCodec) deepcopy(src *distCodec) { | ||
36 | if dc == src { | ||
37 | return | ||
38 | } | ||
39 | for i := range dc.posSlotCodecs { | ||
40 | dc.posSlotCodecs[i].deepcopy(&src.posSlotCodecs[i]) | ||
41 | } | ||
42 | for i := range dc.posModel { | ||
43 | dc.posModel[i].deepcopy(&src.posModel[i]) | ||
44 | } | ||
45 | dc.alignCodec.deepcopy(&src.alignCodec) | ||
46 | } | ||
47 | |||
48 | // distBits returns the number of bits required to encode dist. | ||
49 | func distBits(dist uint32) int { | ||
50 | if dist < startPosModel { | ||
51 | return 6 | ||
52 | } | ||
53 | // slot s > 3, dist d | ||
54 | // s = 2(bits(d)-1) + bit(d, bits(d)-2) | ||
55 | // s>>1 = bits(d)-1 | ||
56 | // bits(d) = 32-nlz32(d) | ||
57 | // s>>1=31-nlz32(d) | ||
58 | // n = 5 + (s>>1) = 36 - nlz32(d) | ||
59 | return 36 - nlz32(dist) | ||
60 | } | ||
61 | |||
62 | // newDistCodec creates a new distance codec. | ||
63 | func (dc *distCodec) init() { | ||
64 | for i := range dc.posSlotCodecs { | ||
65 | dc.posSlotCodecs[i] = makeTreeCodec(posSlotBits) | ||
66 | } | ||
67 | for i := range dc.posModel { | ||
68 | posSlot := startPosModel + i | ||
69 | bits := (posSlot >> 1) - 1 | ||
70 | dc.posModel[i] = makeTreeReverseCodec(bits) | ||
71 | } | ||
72 | dc.alignCodec = makeTreeReverseCodec(alignBits) | ||
73 | } | ||
74 | |||
75 | // lenState converts the value l to a supported lenState value. | ||
76 | func lenState(l uint32) uint32 { | ||
77 | if l >= lenStates { | ||
78 | l = lenStates - 1 | ||
79 | } | ||
80 | return l | ||
81 | } | ||
82 | |||
83 | // Encode encodes the distance using the parameter l. Dist can have values from | ||
84 | // the full range of uint32 values. To get the distance offset the actual match | ||
85 | // distance has to be decreased by 1. A distance offset of 0xffffffff (eos) | ||
86 | // indicates the end of the stream. | ||
87 | func (dc *distCodec) Encode(e *rangeEncoder, dist uint32, l uint32) (err error) { | ||
88 | // Compute the posSlot using nlz32 | ||
89 | var posSlot uint32 | ||
90 | var bits uint32 | ||
91 | if dist < startPosModel { | ||
92 | posSlot = dist | ||
93 | } else { | ||
94 | bits = uint32(30 - nlz32(dist)) | ||
95 | posSlot = startPosModel - 2 + (bits << 1) | ||
96 | posSlot += (dist >> uint(bits)) & 1 | ||
97 | } | ||
98 | |||
99 | if err = dc.posSlotCodecs[lenState(l)].Encode(e, posSlot); err != nil { | ||
100 | return | ||
101 | } | ||
102 | |||
103 | switch { | ||
104 | case posSlot < startPosModel: | ||
105 | return nil | ||
106 | case posSlot < endPosModel: | ||
107 | tc := &dc.posModel[posSlot-startPosModel] | ||
108 | return tc.Encode(dist, e) | ||
109 | } | ||
110 | dic := directCodec(bits - alignBits) | ||
111 | if err = dic.Encode(e, dist>>alignBits); err != nil { | ||
112 | return | ||
113 | } | ||
114 | return dc.alignCodec.Encode(dist, e) | ||
115 | } | ||
116 | |||
117 | // Decode decodes the distance offset using the parameter l. The dist value | ||
118 | // 0xffffffff (eos) indicates the end of the stream. Add one to the distance | ||
119 | // offset to get the actual match distance. | ||
120 | func (dc *distCodec) Decode(d *rangeDecoder, l uint32) (dist uint32, err error) { | ||
121 | posSlot, err := dc.posSlotCodecs[lenState(l)].Decode(d) | ||
122 | if err != nil { | ||
123 | return | ||
124 | } | ||
125 | |||
126 | // posSlot equals distance | ||
127 | if posSlot < startPosModel { | ||
128 | return posSlot, nil | ||
129 | } | ||
130 | |||
131 | // posSlot uses the individual models | ||
132 | bits := (posSlot >> 1) - 1 | ||
133 | dist = (2 | (posSlot & 1)) << bits | ||
134 | var u uint32 | ||
135 | if posSlot < endPosModel { | ||
136 | tc := &dc.posModel[posSlot-startPosModel] | ||
137 | if u, err = tc.Decode(d); err != nil { | ||
138 | return 0, err | ||
139 | } | ||
140 | dist += u | ||
141 | return dist, nil | ||
142 | } | ||
143 | |||
144 | // posSlots use direct encoding and a single model for the four align | ||
145 | // bits. | ||
146 | dic := directCodec(bits - alignBits) | ||
147 | if u, err = dic.Decode(d); err != nil { | ||
148 | return 0, err | ||
149 | } | ||
150 | dist += u << alignBits | ||
151 | if u, err = dc.alignCodec.Decode(d); err != nil { | ||
152 | return 0, err | ||
153 | } | ||
154 | dist += u | ||
155 | return dist, nil | ||
156 | } | ||