State.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Copyright 2013 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using System.Collections.Generic;
  18. namespace FastReport.Barcode.Aztec
  19. {
  20. /// <summary>
  21. /// State represents all information about a sequence necessary to generate the current output.
  22. /// Note that a state is immutable.
  23. /// </summary>
  24. internal sealed class State
  25. {
  26. public static readonly State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
  27. // The current mode of the encoding (or the mode to which we'll return if
  28. // we're in Binary Shift mode.
  29. private readonly int mode;
  30. // The list of tokens that we output. If we are in Binary Shift mode, this
  31. // token list does *not* yet included the token for those bytes
  32. private readonly Token token;
  33. // If non-zero, the number of most recent bytes that should be output
  34. // in Binary Shift mode.
  35. private readonly int binaryShiftByteCount;
  36. // The total number of bits generated (including Binary Shift).
  37. private readonly int bitCount;
  38. public State(Token token, int mode, int binaryBytes, int bitCount)
  39. {
  40. this.token = token;
  41. this.mode = mode;
  42. this.binaryShiftByteCount = binaryBytes;
  43. this.bitCount = bitCount;
  44. // Make sure we match the token
  45. //int binaryShiftBitCount = (binaryShiftByteCount * 8) +
  46. // (binaryShiftByteCount == 0 ? 0 :
  47. // binaryShiftByteCount <= 31 ? 10 :
  48. // binaryShiftByteCount <= 62 ? 20 : 21);
  49. //assert this.bitCount == token.getTotalBitCount() + binaryShiftBitCount;
  50. }
  51. public int Mode
  52. {
  53. get { return mode; }
  54. }
  55. public Token Token
  56. {
  57. get { return token; }
  58. }
  59. public int BinaryShiftByteCount
  60. {
  61. get { return binaryShiftByteCount; }
  62. }
  63. public int BitCount
  64. {
  65. get { return bitCount; }
  66. }
  67. /// <summary>
  68. /// Create a new state representing this state with a latch to a (not
  69. /// necessary different) mode, and then a code.
  70. /// </summary>
  71. public State latchAndAppend(int mode, int value)
  72. {
  73. //assert binaryShiftByteCount == 0;
  74. int bitCount = this.bitCount;
  75. Token token = this.token;
  76. if (mode != this.mode)
  77. {
  78. int latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode];
  79. token = token.add(latch & 0xFFFF, latch >> 16);
  80. bitCount += latch >> 16;
  81. }
  82. int latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
  83. token = token.add(value, latchModeBitCount);
  84. return new State(token, mode, 0, bitCount + latchModeBitCount);
  85. }
  86. /// <summary>
  87. /// Create a new state representing this state, with a temporary shift
  88. /// to a different mode to output a single value.
  89. /// </summary>
  90. public State shiftAndAppend(int mode, int value)
  91. {
  92. //assert binaryShiftByteCount == 0 && this.mode != mode;
  93. Token token = this.token;
  94. int thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
  95. // Shifts exist only to UPPER and PUNCT, both with tokens size 5.
  96. token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], thisModeBitCount);
  97. token = token.add(value, 5);
  98. return new State(token, this.mode, 0, this.bitCount + thisModeBitCount + 5);
  99. }
  100. /// <summary>
  101. /// Create a new state representing this state, but an additional character
  102. /// output in Binary Shift mode.
  103. /// </summary>
  104. public State addBinaryShiftChar(int index)
  105. {
  106. Token token = this.token;
  107. int mode = this.mode;
  108. int bitCount = this.bitCount;
  109. if (this.mode == HighLevelEncoder.MODE_PUNCT || this.mode == HighLevelEncoder.MODE_DIGIT)
  110. {
  111. //assert binaryShiftByteCount == 0;
  112. int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER];
  113. token = token.add(latch & 0xFFFF, latch >> 16);
  114. bitCount += latch >> 16;
  115. mode = HighLevelEncoder.MODE_UPPER;
  116. }
  117. int deltaBitCount =
  118. (binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 :
  119. (binaryShiftByteCount == 62) ? 9 : 8;
  120. State result = new State(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount);
  121. if (result.binaryShiftByteCount == 2047 + 31)
  122. {
  123. // The string is as long as it's allowed to be. We should end it.
  124. result = result.endBinaryShift(index + 1);
  125. }
  126. return result;
  127. }
  128. /// <summary>
  129. /// Create the state identical to this one, but we are no longer in
  130. /// Binary Shift mode.
  131. /// </summary>
  132. public State endBinaryShift(int index)
  133. {
  134. if (binaryShiftByteCount == 0)
  135. {
  136. return this;
  137. }
  138. Token token = this.token;
  139. token = token.addBinaryShift(index - binaryShiftByteCount, binaryShiftByteCount);
  140. //assert token.getTotalBitCount() == this.bitCount;
  141. return new State(token, mode, 0, this.bitCount);
  142. }
  143. /// <summary>
  144. /// Returns true if "this" state is better (or equal) to be in than "that"
  145. /// state under all possible circumstances.
  146. /// </summary>
  147. public bool isBetterThanOrEqualTo(State other)
  148. {
  149. int mySize = this.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16);
  150. if (other.binaryShiftByteCount > 0 &&
  151. (this.binaryShiftByteCount == 0 || this.binaryShiftByteCount > other.binaryShiftByteCount))
  152. {
  153. mySize += 10; // Cost of entering Binary Shift mode.
  154. }
  155. return mySize <= other.bitCount;
  156. }
  157. public BitArray toBitArray(byte[] text)
  158. {
  159. // Reverse the tokens, so that they are in the order that they should
  160. // be output
  161. LinkedList<Token> symbols = new LinkedList<Token>();
  162. for (Token token = endBinaryShift(text.Length).token; token != null; token = token.Previous)
  163. {
  164. symbols.AddFirst(token);
  165. }
  166. BitArray bitArray = new BitArray();
  167. // Add each token to the result.
  168. foreach (Token symbol in symbols)
  169. {
  170. symbol.appendTo(bitArray, text);
  171. }
  172. //assert bitArray.getSize() == this.bitCount;
  173. return bitArray;
  174. }
  175. public override String ToString()
  176. {
  177. return String.Format("{0} bits={1} bytes={2}", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
  178. }
  179. }
  180. }