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// states defines the overall state count
8const states = 12
9
10// State maintains the full state of the operation encoding or decoding
11// process.
12type state struct {
13	rep         [4]uint32
14	isMatch     [states << maxPosBits]prob
15	isRepG0Long [states << maxPosBits]prob
16	isRep       [states]prob
17	isRepG0     [states]prob
18	isRepG1     [states]prob
19	isRepG2     [states]prob
20	litCodec    literalCodec
21	lenCodec    lengthCodec
22	repLenCodec lengthCodec
23	distCodec   distCodec
24	state       uint32
25	posBitMask  uint32
26	Properties  Properties
27}
28
29// initProbSlice initializes a slice of probabilities.
30func initProbSlice(p []prob) {
31	for i := range p {
32		p[i] = probInit
33	}
34}
35
36// Reset sets all state information to the original values.
37func (s *state) Reset() {
38	p := s.Properties
39	*s = state{
40		Properties: p,
41		// dict:       s.dict,
42		posBitMask: (uint32(1) << uint(p.PB)) - 1,
43	}
44	initProbSlice(s.isMatch[:])
45	initProbSlice(s.isRep[:])
46	initProbSlice(s.isRepG0[:])
47	initProbSlice(s.isRepG1[:])
48	initProbSlice(s.isRepG2[:])
49	initProbSlice(s.isRepG0Long[:])
50	s.litCodec.init(p.LC, p.LP)
51	s.lenCodec.init()
52	s.repLenCodec.init()
53	s.distCodec.init()
54}
55
56// initState initializes the state.
57func initState(s *state, p Properties) {
58	*s = state{Properties: p}
59	s.Reset()
60}
61
62// newState creates a new state from the give Properties.
63func newState(p Properties) *state {
64	s := &state{Properties: p}
65	s.Reset()
66	return s
67}
68
69// deepcopy initializes s as a deep copy of the source.
70func (s *state) deepcopy(src *state) {
71	if s == src {
72		return
73	}
74	s.rep = src.rep
75	s.isMatch = src.isMatch
76	s.isRepG0Long = src.isRepG0Long
77	s.isRep = src.isRep
78	s.isRepG0 = src.isRepG0
79	s.isRepG1 = src.isRepG1
80	s.isRepG2 = src.isRepG2
81	s.litCodec.deepcopy(&src.litCodec)
82	s.lenCodec.deepcopy(&src.lenCodec)
83	s.repLenCodec.deepcopy(&src.repLenCodec)
84	s.distCodec.deepcopy(&src.distCodec)
85	s.state = src.state
86	s.posBitMask = src.posBitMask
87	s.Properties = src.Properties
88}
89
90// cloneState creates a new clone of the give state.
91func cloneState(src *state) *state {
92	s := new(state)
93	s.deepcopy(src)
94	return s
95}
96
97// updateStateLiteral updates the state for a literal.
98func (s *state) updateStateLiteral() {
99	switch {
100	case s.state < 4:
101		s.state = 0
102		return
103	case s.state < 10:
104		s.state -= 3
105		return
106	}
107	s.state -= 6
108}
109
110// updateStateMatch updates the state for a match.
111func (s *state) updateStateMatch() {
112	if s.state < 7 {
113		s.state = 7
114	} else {
115		s.state = 10
116	}
117}
118
119// updateStateRep updates the state for a repetition.
120func (s *state) updateStateRep() {
121	if s.state < 7 {
122		s.state = 8
123	} else {
124		s.state = 11
125	}
126}
127
128// updateStateShortRep updates the state for a short repetition.
129func (s *state) updateStateShortRep() {
130	if s.state < 7 {
131		s.state = 9
132	} else {
133		s.state = 11
134	}
135}
136
137// states computes the states of the operation codec.
138func (s *state) states(dictHead int64) (state1, state2, posState uint32) {
139	state1 = s.state
140	posState = uint32(dictHead) & s.posBitMask
141	state2 = (s.state << maxPosBits) | posState
142	return
143}
144
145// litState computes the literal state.
146func (s *state) litState(prev byte, dictHead int64) uint32 {
147	lp, lc := uint(s.Properties.LP), uint(s.Properties.LC)
148	litState := ((uint32(dictHead) & ((1 << lp) - 1)) << lc) |
149		(uint32(prev) >> (8 - lc))
150	return litState
151}
152