123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- package aztec
- import (
- "fmt"
- "github.com/boombuler/barcode/utils"
- )
- type encodingMode byte
- const (
- mode_upper encodingMode = iota // 5 bits
- mode_lower // 5 bits
- mode_digit // 4 bits
- mode_mixed // 5 bits
- mode_punct // 5 bits
- )
- var (
- // The Latch Table shows, for each pair of Modes, the optimal method for
- // getting from one mode to another. In the worst possible case, this can
- // be up to 14 bits. In the best possible case, we are already there!
- // The high half-word of each entry gives the number of bits.
- // The low half-word of each entry are the actual bits necessary to change
- latchTable = map[encodingMode]map[encodingMode]int{
- mode_upper: {
- mode_upper: 0,
- mode_lower: (5 << 16) + 28,
- mode_digit: (5 << 16) + 30,
- mode_mixed: (5 << 16) + 29,
- mode_punct: (10 << 16) + (29 << 5) + 30,
- },
- mode_lower: {
- mode_upper: (9 << 16) + (30 << 4) + 14,
- mode_lower: 0,
- mode_digit: (5 << 16) + 30,
- mode_mixed: (5 << 16) + 29,
- mode_punct: (10 << 16) + (29 << 5) + 30,
- },
- mode_digit: {
- mode_upper: (4 << 16) + 14,
- mode_lower: (9 << 16) + (14 << 5) + 28,
- mode_digit: 0,
- mode_mixed: (9 << 16) + (14 << 5) + 29,
- mode_punct: (14 << 16) + (14 << 10) + (29 << 5) + 30,
- },
- mode_mixed: {
- mode_upper: (5 << 16) + 29,
- mode_lower: (5 << 16) + 28,
- mode_digit: (10 << 16) + (29 << 5) + 30,
- mode_mixed: 0,
- mode_punct: (5 << 16) + 30,
- },
- mode_punct: {
- mode_upper: (5 << 16) + 31,
- mode_lower: (10 << 16) + (31 << 5) + 28,
- mode_digit: (10 << 16) + (31 << 5) + 30,
- mode_mixed: (10 << 16) + (31 << 5) + 29,
- mode_punct: 0,
- },
- }
- // A map showing the available shift codes. (The shifts to BINARY are not shown)
- shiftTable = map[encodingMode]map[encodingMode]int{
- mode_upper: {
- mode_punct: 0,
- },
- mode_lower: {
- mode_punct: 0,
- mode_upper: 28,
- },
- mode_mixed: {
- mode_punct: 0,
- },
- mode_digit: {
- mode_punct: 0,
- mode_upper: 15,
- },
- }
- charMap map[encodingMode][]int
- )
- type state struct {
- mode encodingMode
- tokens token
- bShiftByteCount int
- bitCount int
- }
- type stateSlice []*state
- var initialState *state = &state{
- mode: mode_upper,
- tokens: nil,
- bShiftByteCount: 0,
- bitCount: 0,
- }
- func init() {
- charMap = make(map[encodingMode][]int)
- charMap[mode_upper] = make([]int, 256)
- charMap[mode_lower] = make([]int, 256)
- charMap[mode_digit] = make([]int, 256)
- charMap[mode_mixed] = make([]int, 256)
- charMap[mode_punct] = make([]int, 256)
- charMap[mode_upper][' '] = 1
- for c := 'A'; c <= 'Z'; c++ {
- charMap[mode_upper][int(c)] = int(c - 'A' + 2)
- }
- charMap[mode_lower][' '] = 1
- for c := 'a'; c <= 'z'; c++ {
- charMap[mode_lower][c] = int(c - 'a' + 2)
- }
- charMap[mode_digit][' '] = 1
- for c := '0'; c <= '9'; c++ {
- charMap[mode_digit][c] = int(c - '0' + 2)
- }
- charMap[mode_digit][','] = 12
- charMap[mode_digit]['.'] = 13
- mixedTable := []int{
- 0, ' ', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 12, 13, 27, 28, 29, 30, 31, '@', '\\', '^',
- '_', '`', '|', '~', 127,
- }
- for i, v := range mixedTable {
- charMap[mode_mixed][v] = i
- }
- punctTable := []int{
- 0, '\r', 0, 0, 0, 0, '!', '\'', '#', '$', '%', '&', '\'',
- '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
- '[', ']', '{', '}',
- }
- for i, v := range punctTable {
- if v > 0 {
- charMap[mode_punct][v] = i
- }
- }
- }
- func (em encodingMode) BitCount() byte {
- if em == mode_digit {
- return 4
- }
- return 5
- }
- // Create a new state representing this state with a latch to a (not
- // necessary different) mode, and then a code.
- func (s *state) latchAndAppend(mode encodingMode, value int) *state {
- bitCount := s.bitCount
- tokens := s.tokens
- if mode != s.mode {
- latch := latchTable[s.mode][mode]
- tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
- bitCount += latch >> 16
- }
- tokens = newSimpleToken(tokens, value, mode.BitCount())
- return &state{
- mode: mode,
- tokens: tokens,
- bShiftByteCount: 0,
- bitCount: bitCount + int(mode.BitCount()),
- }
- }
- // Create a new state representing this state, with a temporary shift
- // to a different mode to output a single value.
- func (s *state) shiftAndAppend(mode encodingMode, value int) *state {
- tokens := s.tokens
- // Shifts exist only to UPPER and PUNCT, both with tokens size 5.
- tokens = newSimpleToken(tokens, shiftTable[s.mode][mode], s.mode.BitCount())
- tokens = newSimpleToken(tokens, value, 5)
- return &state{
- mode: s.mode,
- tokens: tokens,
- bShiftByteCount: 0,
- bitCount: s.bitCount + int(s.mode.BitCount()) + 5,
- }
- }
- // Create a new state representing this state, but an additional character
- // output in Binary Shift mode.
- func (s *state) addBinaryShiftChar(index int) *state {
- tokens := s.tokens
- mode := s.mode
- bitCnt := s.bitCount
- if s.mode == mode_punct || s.mode == mode_digit {
- latch := latchTable[s.mode][mode_upper]
- tokens = newSimpleToken(tokens, latch&0xFFFF, byte(latch>>16))
- bitCnt += latch >> 16
- mode = mode_upper
- }
- deltaBitCount := 8
- if s.bShiftByteCount == 0 || s.bShiftByteCount == 31 {
- deltaBitCount = 18
- } else if s.bShiftByteCount == 62 {
- deltaBitCount = 9
- }
- result := &state{
- mode: mode,
- tokens: tokens,
- bShiftByteCount: s.bShiftByteCount + 1,
- bitCount: bitCnt + deltaBitCount,
- }
- if result.bShiftByteCount == 2047+31 {
- // The string is as long as it's allowed to be. We should end it.
- result = result.endBinaryShift(index + 1)
- }
- return result
- }
- // Create the state identical to this one, but we are no longer in
- // Binary Shift mode.
- func (s *state) endBinaryShift(index int) *state {
- if s.bShiftByteCount == 0 {
- return s
- }
- tokens := newShiftToken(s.tokens, index-s.bShiftByteCount, s.bShiftByteCount)
- return &state{
- mode: s.mode,
- tokens: tokens,
- bShiftByteCount: 0,
- bitCount: s.bitCount,
- }
- }
- // Returns true if "this" state is better (or equal) to be in than "that"
- // state under all possible circumstances.
- func (this *state) isBetterThanOrEqualTo(other *state) bool {
- mySize := this.bitCount + (latchTable[this.mode][other.mode] >> 16)
- if other.bShiftByteCount > 0 && (this.bShiftByteCount == 0 || this.bShiftByteCount > other.bShiftByteCount) {
- mySize += 10 // Cost of entering Binary Shift mode.
- }
- return mySize <= other.bitCount
- }
- func (s *state) toBitList(text []byte) *utils.BitList {
- tokens := make([]token, 0)
- se := s.endBinaryShift(len(text))
- for t := se.tokens; t != nil; t = t.prev() {
- tokens = append(tokens, t)
- }
- res := new(utils.BitList)
- for i := len(tokens) - 1; i >= 0; i-- {
- tokens[i].appendTo(res, text)
- }
- return res
- }
- func (s *state) String() string {
- tokens := make([]token, 0)
- for t := s.tokens; t != nil; t = t.prev() {
- tokens = append([]token{t}, tokens...)
- }
- return fmt.Sprintf("M:%d bits=%d bytes=%d: %v", s.mode, s.bitCount, s.bShiftByteCount, tokens)
- }
|