state.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package aztec
  2. import (
  3. "fmt"
  4. "github.com/boombuler/barcode/utils"
  5. )
  6. type encodingMode byte
  7. const (
  8. mode_upper encodingMode = iota // 5 bits
  9. mode_lower // 5 bits
  10. mode_digit // 4 bits
  11. mode_mixed // 5 bits
  12. mode_punct // 5 bits
  13. )
  14. var (
  15. // The Latch Table shows, for each pair of Modes, the optimal method for
  16. // getting from one mode to another. In the worst possible case, this can
  17. // be up to 14 bits. In the best possible case, we are already there!
  18. // The high half-word of each entry gives the number of bits.
  19. // The low half-word of each entry are the actual bits necessary to change
  20. latchTable = map[encodingMode]map[encodingMode]int{
  21. mode_upper: {
  22. mode_upper: 0,
  23. mode_lower: (5 << 16) + 28,
  24. mode_digit: (5 << 16) + 30,
  25. mode_mixed: (5 << 16) + 29,
  26. mode_punct: (10 << 16) + (29 << 5) + 30,
  27. },
  28. mode_lower: {
  29. mode_upper: (9 << 16) + (30 << 4) + 14,
  30. mode_lower: 0,
  31. mode_digit: (5 << 16) + 30,
  32. mode_mixed: (5 << 16) + 29,
  33. mode_punct: (10 << 16) + (29 << 5) + 30,
  34. },
  35. mode_digit: {
  36. mode_upper: (4 << 16) + 14,
  37. mode_lower: (9 << 16) + (14 << 5) + 28,
  38. mode_digit: 0,
  39. mode_mixed: (9 << 16) + (14 << 5) + 29,
  40. mode_punct: (14 << 16) + (14 << 10) + (29 << 5) + 30,
  41. },
  42. mode_mixed: {
  43. mode_upper: (5 << 16) + 29,
  44. mode_lower: (5 << 16) + 28,
  45. mode_digit: (10 << 16) + (29 << 5) + 30,
  46. mode_mixed: 0,
  47. mode_punct: (5 << 16) + 30,
  48. },
  49. mode_punct: {
  50. mode_upper: (5 << 16) + 31,
  51. mode_lower: (10 << 16) + (31 << 5) + 28,
  52. mode_digit: (10 << 16) + (31 << 5) + 30,
  53. mode_mixed: (10 << 16) + (31 << 5) + 29,
  54. mode_punct: 0,
  55. },
  56. }
  57. // A map showing the available shift codes. (The shifts to BINARY are not shown)
  58. shiftTable = map[encodingMode]map[encodingMode]int{
  59. mode_upper: {
  60. mode_punct: 0,
  61. },
  62. mode_lower: {
  63. mode_punct: 0,
  64. mode_upper: 28,
  65. },
  66. mode_mixed: {
  67. mode_punct: 0,
  68. },
  69. mode_digit: {
  70. mode_punct: 0,
  71. mode_upper: 15,
  72. },
  73. }
  74. charMap map[encodingMode][]int
  75. )
  76. type state struct {
  77. mode encodingMode
  78. tokens token
  79. bShiftByteCount int
  80. bitCount int
  81. }
  82. type stateSlice []*state
  83. var initialState *state = &state{
  84. mode: mode_upper,
  85. tokens: nil,
  86. bShiftByteCount: 0,
  87. bitCount: 0,
  88. }
  89. func init() {
  90. charMap = make(map[encodingMode][]int)
  91. charMap[mode_upper] = make([]int, 256)
  92. charMap[mode_lower] = make([]int, 256)
  93. charMap[mode_digit] = make([]int, 256)
  94. charMap[mode_mixed] = make([]int, 256)
  95. charMap[mode_punct] = make([]int, 256)
  96. charMap[mode_upper][' '] = 1
  97. for c := 'A'; c <= 'Z'; c++ {
  98. charMap[mode_upper][int(c)] = int(c - 'A' + 2)
  99. }
  100. charMap[mode_lower][' '] = 1
  101. for c := 'a'; c <= 'z'; c++ {
  102. charMap[mode_lower][c] = int(c - 'a' + 2)
  103. }
  104. charMap[mode_digit][' '] = 1
  105. for c := '0'; c <= '9'; c++ {
  106. charMap[mode_digit][c] = int(c - '0' + 2)
  107. }
  108. charMap[mode_digit][','] = 12
  109. charMap[mode_digit]['.'] = 13
  110. mixedTable := []int{
  111. 0, ' ', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
  112. 11, 12, 13, 27, 28, 29, 30, 31, '@', '\\', '^',
  113. '_', '`', '|', '~', 127,
  114. }
  115. for i, v := range mixedTable {
  116. charMap[mode_mixed][v] = i
  117. }
  118. punctTable := []int{
  119. 0, '\r', 0, 0, 0, 0, '!', '\'', '#', '$', '%', '&', '\'',
  120. '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
  121. '[', ']', '{', '}',
  122. }
  123. for i, v := range punctTable {
  124. if v > 0 {
  125. charMap[mode_punct][v] = i
  126. }
  127. }
  128. }
  129. func (em encodingMode) BitCount() byte {
  130. if em == mode_digit {
  131. return 4
  132. }
  133. return 5
  134. }
  135. // Create a new state representing this state with a latch to a (not
  136. // necessary different) mode, and then a code.
  137. func (s *state) latchAndAppend(mode encodingMode, value int) *state {
  138. bitCount := s.bitCount
  139. tokens := s.tokens
  140. if mode != s.mode {
  141. latch := latchTable[s.mode][mode]
  142. tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
  143. bitCount += latch >> 16
  144. }
  145. tokens = newSimpleToken(tokens, value, mode.BitCount())
  146. return &state{
  147. mode: mode,
  148. tokens: tokens,
  149. bShiftByteCount: 0,
  150. bitCount: bitCount + int(mode.BitCount()),
  151. }
  152. }
  153. // Create a new state representing this state, with a temporary shift
  154. // to a different mode to output a single value.
  155. func (s *state) shiftAndAppend(mode encodingMode, value int) *state {
  156. tokens := s.tokens
  157. // Shifts exist only to UPPER and PUNCT, both with tokens size 5.
  158. tokens = newSimpleToken(tokens, shiftTable[s.mode][mode], s.mode.BitCount())
  159. tokens = newSimpleToken(tokens, value, 5)
  160. return &state{
  161. mode: s.mode,
  162. tokens: tokens,
  163. bShiftByteCount: 0,
  164. bitCount: s.bitCount + int(s.mode.BitCount()) + 5,
  165. }
  166. }
  167. // Create a new state representing this state, but an additional character
  168. // output in Binary Shift mode.
  169. func (s *state) addBinaryShiftChar(index int) *state {
  170. tokens := s.tokens
  171. mode := s.mode
  172. bitCnt := s.bitCount
  173. if s.mode == mode_punct || s.mode == mode_digit {
  174. latch := latchTable[s.mode][mode_upper]
  175. tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
  176. bitCnt += latch >> 16
  177. mode = mode_upper
  178. }
  179. deltaBitCount := 8
  180. if s.bShiftByteCount == 0 || s.bShiftByteCount == 31 {
  181. deltaBitCount = 18
  182. } else if s.bShiftByteCount == 62 {
  183. deltaBitCount = 9
  184. }
  185. result := &state{
  186. mode: mode,
  187. tokens: tokens,
  188. bShiftByteCount: s.bShiftByteCount + 1,
  189. bitCount: bitCnt + deltaBitCount,
  190. }
  191. if result.bShiftByteCount == 2047+31 {
  192. // The string is as long as it's allowed to be. We should end it.
  193. result = result.endBinaryShift(index + 1)
  194. }
  195. return result
  196. }
  197. // Create the state identical to this one, but we are no longer in
  198. // Binary Shift mode.
  199. func (s *state) endBinaryShift(index int) *state {
  200. if s.bShiftByteCount == 0 {
  201. return s
  202. }
  203. tokens := newShiftToken(s.tokens, index-s.bShiftByteCount, s.bShiftByteCount)
  204. return &state{
  205. mode: s.mode,
  206. tokens: tokens,
  207. bShiftByteCount: 0,
  208. bitCount: s.bitCount,
  209. }
  210. }
  211. // Returns true if "this" state is better (or equal) to be in than "that"
  212. // state under all possible circumstances.
  213. func (this *state) isBetterThanOrEqualTo(other *state) bool {
  214. mySize := this.bitCount + (latchTable[this.mode][other.mode] >> 16)
  215. if other.bShiftByteCount > 0 && (this.bShiftByteCount == 0 || this.bShiftByteCount > other.bShiftByteCount) {
  216. mySize += 10 // Cost of entering Binary Shift mode.
  217. }
  218. return mySize <= other.bitCount
  219. }
  220. func (s *state) toBitList(text []byte) *utils.BitList {
  221. tokens := make([]token, 0)
  222. se := s.endBinaryShift(len(text))
  223. for t := se.tokens; t != nil; t = t.prev() {
  224. tokens = append(tokens, t)
  225. }
  226. res := new(utils.BitList)
  227. for i := len(tokens) - 1; i >= 0; i-- {
  228. tokens[i].appendTo(res, text)
  229. }
  230. return res
  231. }
  232. func (s *state) String() string {
  233. tokens := make([]token, 0)
  234. for t := s.tokens; t != nil; t = t.prev() {
  235. tokens = append([]token{t}, tokens...)
  236. }
  237. return fmt.Sprintf("M:%d bits=%d bytes=%d: %v", s.mode, s.bitCount, s.bShiftByteCount, tokens)
  238. }