1 package aztec
2
3 import (
4 "fmt"
5
6 "github.com/boombuler/barcode/utils"
7 )
8
9 type encodingMode byte
10
11 const (
12 mode_upper encodingMode = iota
13 mode_lower
14 mode_digit
15 mode_mixed
16 mode_punct
17 )
18
19 var (
20
21
22
23
24
25 latchTable = map[encodingMode]map[encodingMode]int{
26 mode_upper: {
27 mode_upper: 0,
28 mode_lower: (5 << 16) + 28,
29 mode_digit: (5 << 16) + 30,
30 mode_mixed: (5 << 16) + 29,
31 mode_punct: (10 << 16) + (29 << 5) + 30,
32 },
33 mode_lower: {
34 mode_upper: (9 << 16) + (30 << 4) + 14,
35 mode_lower: 0,
36 mode_digit: (5 << 16) + 30,
37 mode_mixed: (5 << 16) + 29,
38 mode_punct: (10 << 16) + (29 << 5) + 30,
39 },
40 mode_digit: {
41 mode_upper: (4 << 16) + 14,
42 mode_lower: (9 << 16) + (14 << 5) + 28,
43 mode_digit: 0,
44 mode_mixed: (9 << 16) + (14 << 5) + 29,
45 mode_punct: (14 << 16) + (14 << 10) + (29 << 5) + 30,
46 },
47 mode_mixed: {
48 mode_upper: (5 << 16) + 29,
49 mode_lower: (5 << 16) + 28,
50 mode_digit: (10 << 16) + (29 << 5) + 30,
51 mode_mixed: 0,
52 mode_punct: (5 << 16) + 30,
53 },
54 mode_punct: {
55 mode_upper: (5 << 16) + 31,
56 mode_lower: (10 << 16) + (31 << 5) + 28,
57 mode_digit: (10 << 16) + (31 << 5) + 30,
58 mode_mixed: (10 << 16) + (31 << 5) + 29,
59 mode_punct: 0,
60 },
61 }
62
63 shiftTable = map[encodingMode]map[encodingMode]int{
64 mode_upper: {
65 mode_punct: 0,
66 },
67 mode_lower: {
68 mode_punct: 0,
69 mode_upper: 28,
70 },
71 mode_mixed: {
72 mode_punct: 0,
73 },
74 mode_digit: {
75 mode_punct: 0,
76 mode_upper: 15,
77 },
78 }
79 charMap map[encodingMode][]int
80 )
81
82 type state struct {
83 mode encodingMode
84 tokens token
85 bShiftByteCount int
86 bitCount int
87 }
88 type stateSlice []*state
89
90 var initialState *state = &state{
91 mode: mode_upper,
92 tokens: nil,
93 bShiftByteCount: 0,
94 bitCount: 0,
95 }
96
97 func init() {
98 charMap = make(map[encodingMode][]int)
99 charMap[mode_upper] = make([]int, 256)
100 charMap[mode_lower] = make([]int, 256)
101 charMap[mode_digit] = make([]int, 256)
102 charMap[mode_mixed] = make([]int, 256)
103 charMap[mode_punct] = make([]int, 256)
104
105 charMap[mode_upper][' '] = 1
106 for c := 'A'; c <= 'Z'; c++ {
107 charMap[mode_upper][int(c)] = int(c - 'A' + 2)
108 }
109
110 charMap[mode_lower][' '] = 1
111 for c := 'a'; c <= 'z'; c++ {
112 charMap[mode_lower][c] = int(c - 'a' + 2)
113 }
114 charMap[mode_digit][' '] = 1
115 for c := '0'; c <= '9'; c++ {
116 charMap[mode_digit][c] = int(c - '0' + 2)
117 }
118 charMap[mode_digit][','] = 12
119 charMap[mode_digit]['.'] = 13
120
121 mixedTable := []int{
122 0, ' ', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
123 11, 12, 13, 27, 28, 29, 30, 31, '@', '\\', '^',
124 '_', '`', '|', '~', 127,
125 }
126 for i, v := range mixedTable {
127 charMap[mode_mixed][v] = i
128 }
129
130 punctTable := []int{
131 0, '\r', 0, 0, 0, 0, '!', '\'', '#', '$', '%', '&', '\'',
132 '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
133 '[', ']', '{', '}',
134 }
135 for i, v := range punctTable {
136 if v > 0 {
137 charMap[mode_punct][v] = i
138 }
139 }
140 }
141
142 func (em encodingMode) BitCount() byte {
143 if em == mode_digit {
144 return 4
145 }
146 return 5
147 }
148
149
150
151 func (s *state) latchAndAppend(mode encodingMode, value int) *state {
152 bitCount := s.bitCount
153 tokens := s.tokens
154
155 if mode != s.mode {
156 latch := latchTable[s.mode][mode]
157 tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
158 bitCount += latch >> 16
159 }
160 tokens = newSimpleToken(tokens, value, mode.BitCount())
161 return &state{
162 mode: mode,
163 tokens: tokens,
164 bShiftByteCount: 0,
165 bitCount: bitCount + int(mode.BitCount()),
166 }
167 }
168
169
170
171 func (s *state) shiftAndAppend(mode encodingMode, value int) *state {
172 tokens := s.tokens
173
174
175 tokens = newSimpleToken(tokens, shiftTable[s.mode][mode], s.mode.BitCount())
176 tokens = newSimpleToken(tokens, value, 5)
177
178 return &state{
179 mode: s.mode,
180 tokens: tokens,
181 bShiftByteCount: 0,
182 bitCount: s.bitCount + int(s.mode.BitCount()) + 5,
183 }
184 }
185
186
187
188 func (s *state) addBinaryShiftChar(index int) *state {
189 tokens := s.tokens
190 mode := s.mode
191 bitCnt := s.bitCount
192 if s.mode == mode_punct || s.mode == mode_digit {
193 latch := latchTable[s.mode][mode_upper]
194 tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
195 bitCnt += latch >> 16
196 mode = mode_upper
197 }
198 deltaBitCount := 8
199 if s.bShiftByteCount == 0 || s.bShiftByteCount == 31 {
200 deltaBitCount = 18
201 } else if s.bShiftByteCount == 62 {
202 deltaBitCount = 9
203 }
204 result := &state{
205 mode: mode,
206 tokens: tokens,
207 bShiftByteCount: s.bShiftByteCount + 1,
208 bitCount: bitCnt + deltaBitCount,
209 }
210 if result.bShiftByteCount == 2047+31 {
211
212 result = result.endBinaryShift(index + 1)
213 }
214
215 return result
216 }
217
218
219
220 func (s *state) endBinaryShift(index int) *state {
221 if s.bShiftByteCount == 0 {
222 return s
223 }
224 tokens := newShiftToken(s.tokens, index-s.bShiftByteCount, s.bShiftByteCount)
225 return &state{
226 mode: s.mode,
227 tokens: tokens,
228 bShiftByteCount: 0,
229 bitCount: s.bitCount,
230 }
231 }
232
233
234
235 func (this *state) isBetterThanOrEqualTo(other *state) bool {
236 mySize := this.bitCount + (latchTable[this.mode][other.mode] >> 16)
237
238 if other.bShiftByteCount > 0 && (this.bShiftByteCount == 0 || this.bShiftByteCount > other.bShiftByteCount) {
239 mySize += 10
240 }
241 return mySize <= other.bitCount
242 }
243
244 func (s *state) toBitList(text []byte) *utils.BitList {
245 tokens := make([]token, 0)
246 se := s.endBinaryShift(len(text))
247
248 for t := se.tokens; t != nil; t = t.prev() {
249 tokens = append(tokens, t)
250 }
251 res := new(utils.BitList)
252 for i := len(tokens) - 1; i >= 0; i-- {
253 tokens[i].appendTo(res, text)
254 }
255 return res
256 }
257
258 func (s *state) String() string {
259 tokens := make([]token, 0)
260 for t := s.tokens; t != nil; t = t.prev() {
261 tokens = append([]token{t}, tokens...)
262 }
263 return fmt.Sprintf("M:%d bits=%d bytes=%d: %v", s.mode, s.bitCount, s.bShiftByteCount, tokens)
264 }
265
View as plain text