aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/ulikunitz/xz/lzma/distcodec.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/distcodec.go')
-rw-r--r--vendor/github.com/ulikunitz/xz/lzma/distcodec.go156
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
5package lzma
6
7// Constants used by the distance codec.
8const (
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.
28type 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.
35func (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.
49func 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.
63func (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.
76func 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.
87func (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.
120func (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}