/
highlevel.go
171 lines (157 loc) · 5.38 KB
/
highlevel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package aztec
import (
"github.com/boombuler/barcode/utils"
)
func highlevelEncode(data []byte) *utils.BitList {
states := stateSlice{initialState}
for index := 0; index < len(data); index++ {
pairCode := 0
nextChar := byte(0)
if index+1 < len(data) {
nextChar = data[index+1]
}
switch cur := data[index]; {
case cur == '\r' && nextChar == '\n':
pairCode = 2
case cur == '.' && nextChar == ' ':
pairCode = 3
case cur == ',' && nextChar == ' ':
pairCode = 4
case cur == ':' && nextChar == ' ':
pairCode = 5
}
if pairCode > 0 {
// We have one of the four special PUNCT pairs. Treat them specially.
// Get a new set of states for the two new characters.
states = updateStateListForPair(states, data, index, pairCode)
index++
} else {
// Get a new set of states for the new character.
states = updateStateListForChar(states, data, index)
}
}
minBitCnt := int((^uint(0)) >> 1)
var result *state = nil
for _, s := range states {
if s.bitCount < minBitCnt {
minBitCnt = s.bitCount
result = s
}
}
if result != nil {
return result.toBitList(data)
} else {
return new(utils.BitList)
}
}
func simplifyStates(states stateSlice) stateSlice {
var result stateSlice = nil
for _, newState := range states {
add := true
var newResult stateSlice = nil
for _, oldState := range result {
if add && oldState.isBetterThanOrEqualTo(newState) {
add = false
}
if !(add && newState.isBetterThanOrEqualTo(oldState)) {
newResult = append(newResult, oldState)
}
}
if add {
result = append(newResult, newState)
} else {
result = newResult
}
}
return result
}
// We update a set of states for a new character by updating each state
// for the new character, merging the results, and then removing the
// non-optimal states.
func updateStateListForChar(states stateSlice, data []byte, index int) stateSlice {
var result stateSlice = nil
for _, s := range states {
if r := updateStateForChar(s, data, index); len(r) > 0 {
result = append(result, r...)
}
}
return simplifyStates(result)
}
// Return a set of states that represent the possible ways of updating this
// state for the next character. The resulting set of states are added to
// the "result" list.
func updateStateForChar(s *state, data []byte, index int) stateSlice {
var result stateSlice = nil
ch := data[index]
charInCurrentTable := charMap[s.mode][ch] > 0
var stateNoBinary *state = nil
for mode := mode_upper; mode <= mode_punct; mode++ {
charInMode := charMap[mode][ch]
if charInMode > 0 {
if stateNoBinary == nil {
// Only create stateNoBinary the first time it's required.
stateNoBinary = s.endBinaryShift(index)
}
// Try generating the character by latching to its mode
if !charInCurrentTable || mode == s.mode || mode == mode_digit {
// If the character is in the current table, we don't want to latch to
// any other mode except possibly digit (which uses only 4 bits). Any
// other latch would be equally successful *after* this character, and
// so wouldn't save any bits.
res := stateNoBinary.latchAndAppend(mode, charInMode)
result = append(result, res)
}
// Try generating the character by switching to its mode.
if _, ok := shiftTable[s.mode][mode]; !charInCurrentTable && ok {
// It never makes sense to temporarily shift to another mode if the
// character exists in the current mode. That can never save bits.
res := stateNoBinary.shiftAndAppend(mode, charInMode)
result = append(result, res)
}
}
}
if s.bShiftByteCount > 0 || charMap[s.mode][ch] == 0 {
// It's never worthwhile to go into binary shift mode if you're not already
// in binary shift mode, and the character exists in your current mode.
// That can never save bits over just outputting the char in the current mode.
res := s.addBinaryShiftChar(index)
result = append(result, res)
}
return result
}
// We update a set of states for a new character by updating each state
// for the new character, merging the results, and then removing the
// non-optimal states.
func updateStateListForPair(states stateSlice, data []byte, index int, pairCode int) stateSlice {
var result stateSlice = nil
for _, s := range states {
if r := updateStateForPair(s, data, index, pairCode); len(r) > 0 {
result = append(result, r...)
}
}
return simplifyStates(result)
}
func updateStateForPair(s *state, data []byte, index int, pairCode int) stateSlice {
var result stateSlice
stateNoBinary := s.endBinaryShift(index)
// Possibility 1. Latch to MODE_PUNCT, and then append this code
result = append(result, stateNoBinary.latchAndAppend(mode_punct, pairCode))
if s.mode != mode_punct {
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
// Every state except MODE_PUNCT (handled above) can shift
result = append(result, stateNoBinary.shiftAndAppend(mode_punct, pairCode))
}
if pairCode == 3 || pairCode == 4 {
// both characters are in DIGITS. Sometimes better to just add two digits
digitState := stateNoBinary.
latchAndAppend(mode_digit, 16-pairCode). // period or comma in DIGIT
latchAndAppend(mode_digit, 1) // space in DIGIT
result = append(result, digitState)
}
if s.bShiftByteCount > 0 {
// It only makes sense to do the characters as binary if we're already
// in binary mode.
result = append(result, s.addBinaryShiftChar(index).addBinaryShiftChar(index+1))
}
return result
}