Another attack on integrating encoder and decoder: Version is done. Attempted to...
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Wed, 10 Dec 2008 00:22:14 +0000 (00:22 +0000)
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Wed, 10 Dec 2008 00:22:14 +0000 (00:22 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@781 59b500cc-1b3d-0410-9834-0bbf25fbcc57

13 files changed:
core/src/com/google/zxing/common/ByteArray.java
core/src/com/google/zxing/qrcode/QRCodeWriter.java
core/src/com/google/zxing/qrcode/decoder/DataBlock.java
core/src/com/google/zxing/qrcode/decoder/Version.java
core/src/com/google/zxing/qrcode/encoder/BitVector.java
core/src/com/google/zxing/qrcode/encoder/Encoder.java
core/src/com/google/zxing/qrcode/encoder/MaskUtil.java
core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java
core/src/com/google/zxing/qrcode/encoder/QRCode.java
core/test/src/com/google/zxing/qrcode/QRCodeWriterTestCase.java
core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java
core/test/src/com/google/zxing/qrcode/encoder/MatrixUtilTestCase.java
core/test/src/com/google/zxing/qrcode/encoder/QRCodeTestCase.java

index ffcc472..7382b78 100644 (file)
@@ -38,11 +38,6 @@ public final class ByteArray {
     this.size = size;
   }
 
-  public ByteArray(String string) {
-    bytes = string.getBytes();
-    size = bytes.length;
-  }
-
   public ByteArray(byte[] byteArray) {
     bytes = byteArray;
     size = bytes.length;
index 1920465..a870f1c 100644 (file)
@@ -68,7 +68,7 @@ public final class QRCodeWriter implements Writer {
     }
 
     QRCode code = new QRCode();
-    Encoder.encode(new ByteArray(contents), errorCorrectionLevel, code);
+    Encoder.encode(contents, errorCorrectionLevel, code);
     return renderResult(code, width, height);
   }
 
index 259a8ac..a517611 100755 (executable)
@@ -65,7 +65,7 @@ final class DataBlock {
       Version.ECB ecBlock = ecBlockArray[j];\r
       for (int i = 0; i < ecBlock.getCount(); i++) {\r
         int numDataCodewords = ecBlock.getDataCodewords();\r
-        int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
+        int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;\r
         result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
       }\r
     }\r
@@ -86,7 +86,7 @@ final class DataBlock {
     }\r
     longerBlocksStartAt++;\r
 \r
-    int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords();\r
+    int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();\r
     // The last elements of result may be 1 element longer;\r
     // first fill out as many elements as all of them have\r
     int rawCodewordsOffset = 0;\r
index e9de42a..18057a7 100755 (executable)
@@ -57,7 +57,7 @@ public final class Version {
     this.alignmentPatternCenters = alignmentPatternCenters;\r
     this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4};\r
     int total = 0;\r
-    int ecCodewords = ecBlocks1.getECCodewords();\r
+    int ecCodewords = ecBlocks1.getECCodewordsPerBlock();\r
     ECB[] ecbArray = ecBlocks1.getECBlocks();\r
     for (int i = 0; i < ecbArray.length; i++) {\r
       ECB ecBlock = ecbArray[i];\r
@@ -82,7 +82,7 @@ public final class Version {
     return 17 + 4 * versionNumber;\r
   }\r
 \r
-  ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {\r
+  public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {\r
     return ecBlocks[ecLevel.ordinal()];\r
   }\r
 \r
@@ -107,7 +107,7 @@ public final class Version {
     return VERSIONS[versionNumber - 1];\r
   }\r
 \r
-  static Version decodeVersionInformation(int versionBits) throws ReaderException {\r
+  static Version decodeVersionInformation(int versionBits) {\r
     int bestDifference = Integer.MAX_VALUE;\r
     int bestVersion = 0;\r
     for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {\r
@@ -180,25 +180,37 @@ public final class Version {
    * each set of blocks. It also holds the number of error-correction codewords per block since it\r
    * will be the same across all blocks within one version.</p>\r
    */\r
-  static final class ECBlocks {\r
-    private final int ecCodewords;\r
+  public static final class ECBlocks {\r
+    private final int ecCodewordsPerBlock;\r
     private final ECB[] ecBlocks;\r
 \r
-    private ECBlocks(int ecCodewords, ECB ecBlocks) {\r
-      this.ecCodewords = ecCodewords;\r
+    private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {\r
+      this.ecCodewordsPerBlock = ecCodewordsPerBlock;\r
       this.ecBlocks = new ECB[]{ecBlocks};\r
     }\r
 \r
-    private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {\r
-      this.ecCodewords = ecCodewords;\r
+    private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {\r
+      this.ecCodewordsPerBlock = ecCodewordsPerBlock;\r
       this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};\r
     }\r
 \r
-    int getECCodewords() {\r
-      return ecCodewords;\r
+    public int getECCodewordsPerBlock() {\r
+      return ecCodewordsPerBlock;\r
     }\r
 \r
-    ECB[] getECBlocks() {\r
+    public int getNumBlocks() {\r
+      int total = 0;\r
+      for (int i = 0; i < ecBlocks.length; i++) {\r
+        total += ecBlocks[i].getCount();\r
+      }\r
+      return total;\r
+    }\r
+\r
+    public int getTotalECCodewords() {\r
+      return ecCodewordsPerBlock * getNumBlocks();\r
+    }\r
+\r
+    public ECB[] getECBlocks() {\r
       return ecBlocks;\r
     }\r
   }\r
@@ -208,20 +220,20 @@ public final class Version {
    * This includes the number of data codewords, and the number of times a block with these\r
    * parameters is used consecutively in the QR code version's format.</p>\r
    */\r
-  static final class ECB {\r
-    final int count;\r
-    final int dataCodewords;\r
+  public static final class ECB {\r
+    private final int count;\r
+    private final int dataCodewords;\r
 \r
     ECB(int count, int dataCodewords) {\r
       this.count = count;\r
       this.dataCodewords = dataCodewords;\r
     }\r
 \r
-    int getCount() {\r
+    public int getCount() {\r
       return count;\r
     }\r
 \r
-    int getDataCodewords() {\r
+    public int getDataCodewords() {\r
       return dataCodewords;\r
     }\r
   }\r
index ed1e468..a78078b 100644 (file)
@@ -38,11 +38,11 @@ public final class BitVector {
   }
 
   // Return the bit value at "index".
-  public int at(final int index) {
+  public int at(int index) {
     if (index < 0 || index >= sizeInBits) {
       throw new IllegalArgumentException("Bad index: " + index);
     }
-    final int value = array[index >> 3] & 0xff;
+    int value = array[index >> 3] & 0xff;
     return (value >> (7 - (index & 0x7))) & 1;
   }
 
@@ -57,11 +57,11 @@ public final class BitVector {
   }
 
   // Append one bit to the bit vector.
-  public void appendBit(final int bit) {
+  public void appendBit(int bit) {
     if (!(bit == 0 || bit == 1)) {
       throw new IllegalArgumentException("Bad bit");
     }
-    final int numBitsInLastByte = sizeInBits & 0x7;
+    int numBitsInLastByte = sizeInBits & 0x7;
     // We'll expand array if we don't have bits in the last byte.
     if (numBitsInLastByte == 0) {
       appendByte(0);
@@ -79,7 +79,7 @@ public final class BitVector {
   // - appendBits(0x00, 1) adds 0.
   // - appendBits(0x00, 4) adds 0000.
   // - appendBits(0xff, 8) adds 11111111.
-  public void appendBits(final int value, final int numBits) {
+  public void appendBits(int value, int numBits) {
     if (numBits < 0 || numBits > 32) {
       throw new IllegalArgumentException("Num bits must be between 0 and 32");
     }
@@ -87,11 +87,11 @@ public final class BitVector {
     while (numBitsLeft > 0) {
       // Optimization for byte-oriented appending.
       if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8) {
-        final int newByte = (value >> (numBitsLeft - 8)) & 0xff;
+        int newByte = (value >> (numBitsLeft - 8)) & 0xff;
         appendByte(newByte);
         numBitsLeft -= 8;
       } else {
-        final int bit = (value >> (numBitsLeft - 1)) & 1;
+        int bit = (value >> (numBitsLeft - 1)) & 1;
         appendBit(bit);
         --numBitsLeft;
       }
@@ -99,7 +99,7 @@ public final class BitVector {
   }
 
   // Append "bits".
-  public void appendBitVector(final BitVector bits) {
+  public void appendBitVector(BitVector bits) {
     int size = bits.size();
     for (int i = 0; i < size; ++i) {
       appendBit(bits.at(i));
@@ -107,7 +107,7 @@ public final class BitVector {
   }
 
   // Modify the bit vector by XOR'ing with "other"
-  public void xor(final BitVector other) {
+  public void xor(BitVector other) {
     if (sizeInBits != other.size()) {
       throw new IllegalArgumentException("BitVector sizes don't match");
     }
@@ -124,9 +124,9 @@ public final class BitVector {
     StringBuffer result = new StringBuffer(sizeInBits);
     for (int i = 0; i < sizeInBits; ++i) {
       if (at(i) == 0) {
-        result.append("0");
+        result.append('0');
       } else if (at(i) == 1) {
-        result.append("1");
+        result.append('1');
       } else {
         throw new IllegalArgumentException("Byte isn't 0 or 1");
       }
@@ -144,7 +144,7 @@ public final class BitVector {
   // run out of room.
   private void appendByte(int value) {
     if ((sizeInBits >> 3) == array.length) {
-      byte[] newArray = new byte[array.length * 2];
+      byte[] newArray = new byte[(array.length << 1)];
       System.arraycopy(array, 0, newArray, 0, array.length);
       array = newArray;
     }
index f19e81b..0d09dcc 100644 (file)
@@ -26,6 +26,7 @@ import com.google.zxing.qrcode.decoder.Mode;
 import com.google.zxing.qrcode.decoder.Version;
 
 import java.util.Vector;
+import java.io.UnsupportedEncodingException;
 
 /**
  * @author satorux@google.com (Satoru Takabayashi) - creator
@@ -43,70 +44,26 @@ public final class Encoder {
       25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,  // 0x50-0x5f
   };
 
-  private static final class RSBlockInfo {
-
-    final int numBytes;
-    final int[][] blockInfo;
-
-    public RSBlockInfo(int numBytes, int[][] blockInfo) {
-      this.numBytes = numBytes;
-      this.blockInfo = blockInfo;
-    }
-
+  private Encoder() {
   }
 
-  // The table is from table 12 of JISX0510:2004 (p. 30). The "blockInfo" parts are ordered by
-  // L, M, Q, H. Within each blockInfo, the 0th element is getNumECBytes, and the 1st element is
-  // getNumRSBlocks. The table was doublechecked by komatsu.
-  private static final RSBlockInfo[] RS_BLOCK_TABLE = {
-      new RSBlockInfo(  26, new int[][]{ {  7,  1}, {  10,  1}, {  13,  1}, {  17,  1}}),  // Version  1
-      new RSBlockInfo(  44, new int[][]{ { 10,  1}, {  16,  1}, {  22,  1}, {  28,  1}}),  // Version  2
-      new RSBlockInfo(  70, new int[][]{ { 15,  1}, {  26,  1}, {  36,  2}, {  44,  2}}),  // Version  3
-      new RSBlockInfo( 100, new int[][]{ { 20,  1}, {  36,  2}, {  52,  2}, {  64,  4}}),  // Version  4
-      new RSBlockInfo( 134, new int[][]{ { 26,  1}, {  48,  2}, {  72,  4}, {  88,  4}}),  // Version  5
-      new RSBlockInfo( 172, new int[][]{ { 36,  2}, {  64,  4}, {  96,  4}, { 112,  4}}),  // Version  6
-      new RSBlockInfo( 196, new int[][]{ { 40,  2}, {  72,  4}, { 108,  6}, { 130,  5}}),  // Version  7
-      new RSBlockInfo( 242, new int[][]{ { 48,  2}, {  88,  4}, { 132,  6}, { 156,  6}}),  // Version  8
-      new RSBlockInfo( 292, new int[][]{ { 60,  2}, { 110,  5}, { 160,  8}, { 192,  8}}),  // Version  9
-      new RSBlockInfo( 346, new int[][]{ { 72,  4}, { 130,  5}, { 192,  8}, { 224,  8}}),  // Version 10
-      new RSBlockInfo( 404, new int[][]{ { 80,  4}, { 150,  5}, { 224,  8}, { 264, 11}}),  // Version 11
-      new RSBlockInfo( 466, new int[][]{ { 96,  4}, { 176,  8}, { 260, 10}, { 308, 11}}),  // Version 12
-      new RSBlockInfo( 532, new int[][]{ {104,  4}, { 198,  9}, { 288, 12}, { 352, 16}}),  // Version 13
-      new RSBlockInfo( 581, new int[][]{ {120,  4}, { 216,  9}, { 320, 16}, { 384, 16}}),  // Version 14
-      new RSBlockInfo( 655, new int[][]{ {132,  6}, { 240, 10}, { 360, 12}, { 432, 18}}),  // Version 15
-      new RSBlockInfo( 733, new int[][]{ {144,  6}, { 280, 10}, { 408, 17}, { 480, 16}}),  // Version 16
-      new RSBlockInfo( 815, new int[][]{ {168,  6}, { 308, 11}, { 448, 16}, { 532, 19}}),  // Version 17
-      new RSBlockInfo( 901, new int[][]{ {180,  6}, { 338, 13}, { 504, 18}, { 588, 21}}),  // Version 18
-      new RSBlockInfo( 991, new int[][]{ {196,  7}, { 364, 14}, { 546, 21}, { 650, 25}}),  // Version 19
-      new RSBlockInfo(1085, new int[][]{ {224,  8}, { 416, 16}, { 600, 20}, { 700, 25}}),  // Version 20
-      new RSBlockInfo(1156, new int[][]{ {224,  8}, { 442, 17}, { 644, 23}, { 750, 25}}),  // Version 21
-      new RSBlockInfo(1258, new int[][]{ {252,  9}, { 476, 17}, { 690, 23}, { 816, 34}}),  // Version 22
-      new RSBlockInfo(1364, new int[][]{ {270,  9}, { 504, 18}, { 750, 25}, { 900, 30}}),  // Version 23
-      new RSBlockInfo(1474, new int[][]{ {300, 10}, { 560, 20}, { 810, 27}, { 960, 32}}),  // Version 24
-      new RSBlockInfo(1588, new int[][]{ {312, 12}, { 588, 21}, { 870, 29}, {1050, 35}}),  // Version 25
-      new RSBlockInfo(1706, new int[][]{ {336, 12}, { 644, 23}, { 952, 34}, {1110, 37}}),  // Version 26
-      new RSBlockInfo(1828, new int[][]{ {360, 12}, { 700, 25}, {1020, 34}, {1200, 40}}),  // Version 27
-      new RSBlockInfo(1921, new int[][]{ {390, 13}, { 728, 26}, {1050, 35}, {1260, 42}}),  // Version 28
-      new RSBlockInfo(2051, new int[][]{ {420, 14}, { 784, 28}, {1140, 38}, {1350, 45}}),  // Version 29
-      new RSBlockInfo(2185, new int[][]{ {450, 15}, { 812, 29}, {1200, 40}, {1440, 48}}),  // Version 30
-      new RSBlockInfo(2323, new int[][]{ {480, 16}, { 868, 31}, {1290, 43}, {1530, 51}}),  // Version 31
-      new RSBlockInfo(2465, new int[][]{ {510, 17}, { 924, 33}, {1350, 45}, {1620, 54}}),  // Version 32
-      new RSBlockInfo(2611, new int[][]{ {540, 18}, { 980, 35}, {1440, 48}, {1710, 57}}),  // Version 33
-      new RSBlockInfo(2761, new int[][]{ {570, 19}, {1036, 37}, {1530, 51}, {1800, 60}}),  // Version 34
-      new RSBlockInfo(2876, new int[][]{ {570, 19}, {1064, 38}, {1590, 53}, {1890, 63}}),  // Version 35
-      new RSBlockInfo(3034, new int[][]{ {600, 20}, {1120, 40}, {1680, 56}, {1980, 66}}),  // Version 36
-      new RSBlockInfo(3196, new int[][]{ {630, 21}, {1204, 43}, {1770, 59}, {2100, 70}}),  // Version 37
-      new RSBlockInfo(3362, new int[][]{ {660, 22}, {1260, 45}, {1860, 62}, {2220, 74}}),  // Version 38
-      new RSBlockInfo(3532, new int[][]{ {720, 24}, {1316, 47}, {1950, 65}, {2310, 77}}),  // Version 39
-      new RSBlockInfo(3706, new int[][]{ {750, 25}, {1372, 49}, {2040, 68}, {2430, 81}}),  // Version 40
-  };
+  // The mask penalty calculation is complicated.  See Table 21 of JISX0510:2004 (p.45) for details.
+  // Basically it applies four rules and summate all penalties.
+  private static int calculateMaskPenalty(ByteMatrix matrix) {
+    int penalty = 0;
+    penalty += MaskUtil.applyMaskPenaltyRule1(matrix);
+    penalty += MaskUtil.applyMaskPenaltyRule2(matrix);
+    penalty += MaskUtil.applyMaskPenaltyRule3(matrix);
+    penalty += MaskUtil.applyMaskPenaltyRule4(matrix);
+    return penalty;
+  }
 
   private static final class BlockPair {
 
     private final ByteArray dataBytes;
     private final ByteArray errorCorrectionBytes;
 
-    public BlockPair(ByteArray data, ByteArray errorCorrection) {
+    BlockPair(ByteArray data, ByteArray errorCorrection) {
       dataBytes = data;
       errorCorrectionBytes = errorCorrection;
     }
@@ -129,22 +86,22 @@ public final class Encoder {
   //
   // Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
   // with which clients can specify the encoding mode. For now, we don't need the functionality.
-  public static void encode(final ByteArray bytes, ErrorCorrectionLevel ecLevel, QRCode qrCode)
+  public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode)
       throws WriterException {
     // Step 1: Choose the mode (encoding).
-    final Mode mode = chooseMode(bytes);
+    Mode mode = chooseMode(content);
 
     // Step 2: Append "bytes" into "dataBits" in appropriate encoding.
     BitVector dataBits = new BitVector();
-    appendBytes(bytes, mode, dataBits);
+    appendBytes(content, mode, dataBits);
     // Step 3: Initialize QR code that can contain "dataBits".
-    final int numInputBytes = dataBits.sizeInBytes();
+    int numInputBytes = dataBits.sizeInBytes();
     initQRCode(numInputBytes, ecLevel, mode, qrCode);
 
     // Step 4: Build another bit vector that contains header and data.
     BitVector headerAndDataBits = new BitVector();
     appendModeInfo(qrCode.getMode(), headerAndDataBits);
-    appendLengthInfo(bytes.size(), qrCode.getVersion(), qrCode.getMode(), headerAndDataBits);
+    appendLengthInfo(content.length(), qrCode.getVersion(), qrCode.getMode(), headerAndDataBits);
     headerAndDataBits.appendBitVector(dataBits);
 
     // Step 5: Terminate the bits properly.
@@ -179,54 +136,43 @@ public final class Encoder {
     return -1;
   }
 
-  // Choose the best mode by examining the content of "bytes". The function is guaranteed to return
-  // a valid mode.
+  // Choose the best mode by examining the content.
   //
   // Note that this function does not return MODE_KANJI, as we cannot distinguish Shift_JIS from
   // other encodings such as ISO-8859-1, from data bytes alone. For example "\xE0\xE0" can be
   // interpreted as one character in Shift_JIS, but also two characters in ISO-8859-1.
   //
   // JAVAPORT: This MODE_KANJI limitation sounds like a problem for us.
-  public static Mode chooseMode(final ByteArray bytes) throws WriterException {
+  public static Mode chooseMode(String content) {
     boolean hasNumeric = false;
     boolean hasAlphanumeric = false;
-    boolean hasOther = false;
-    for (int i = 0; i < bytes.size(); ++i) {
-      final int oneByte = bytes.at(i);
-      if (oneByte >= '0' && oneByte <= '9') {
+    for (int i = 0; i < content.length(); ++i) {
+      char c = content.charAt(i);
+      if (c >= '0' && c <= '9') {
         hasNumeric = true;
-      } else if (getAlphanumericCode(oneByte) != -1) {
+      } else if (getAlphanumericCode(c) != -1) {
         hasAlphanumeric = true;
       } else {
-        hasOther = true;
+        return Mode.BYTE;
       }
     }
-    if (hasOther) {
-      return Mode.BYTE;
-    } else if (hasAlphanumeric) {
+    if (hasAlphanumeric) {
       return Mode.ALPHANUMERIC;
     } else if (hasNumeric) {
       return Mode.NUMERIC;
     }
-    // "bytes" must be empty to reach here.
-    if (!bytes.empty()) {
-      throw new WriterException("Bytes left over");
-    }
     return Mode.BYTE;
   }
 
-  private static int chooseMaskPattern(final BitVector bits, ErrorCorrectionLevel ecLevel, int version,
+  private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version,
       ByteMatrix matrix) throws WriterException {
-    if (!QRCode.isValidMatrixWidth(matrix.width())) {
-      throw new WriterException("Invalid matrix width: " + matrix.width());
-    }
 
     int minPenalty = Integer.MAX_VALUE;  // Lower penalty is better.
     int bestMaskPattern = -1;
     // We try all mask patterns to choose the best one.
     for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
       MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix);
-      final int penalty = MaskUtil.calculateMaskPenalty(matrix);
+      int penalty = calculateMaskPenalty(matrix);
       if (penalty < minPenalty) {
         minPenalty = penalty;
         bestMaskPattern = maskPattern;
@@ -236,36 +182,37 @@ public final class Encoder {
   }
 
   // Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, modify
-  // "qrCode" and return true.
+  // "qrCode".
   private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, QRCode qrCode)
       throws WriterException {
     qrCode.setECLevel(ecLevel);
     qrCode.setMode(mode);
 
     // In the following comments, we use numbers of Version 7-H.
-    for (int i = 0; i < RS_BLOCK_TABLE.length; ++i) {
-      final RSBlockInfo row = RS_BLOCK_TABLE[i];
+    for (int versionNum = 1; versionNum <= 40; versionNum++) {
+      Version version = Version.getVersionForNumber(versionNum);
       // numBytes = 196
-      final int numBytes = row.numBytes;
+      int numBytes = version.getTotalCodewords();
       // getNumECBytes = 130
-      final int numEcBytes  = row.blockInfo[ecLevel.ordinal()][0];
+      Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
+      int numEcBytes = ecBlocks.getTotalECCodewords();
       // getNumRSBlocks = 5
-      final int numRSBlocks = row.blockInfo[ecLevel.ordinal()][1];
+      int numRSBlocks = ecBlocks.getNumBlocks();
       // getNumDataBytes = 196 - 130 = 66
-      final int numDataBytes = numBytes - numEcBytes;
+      int numDataBytes = numBytes - numEcBytes;
       // We want to choose the smallest version which can contain data of "numInputBytes" + some
       // extra bits for the header (mode info and length info). The header can be three bytes
       // (precisely 4 + 16 bits) at most. Hence we do +3 here.
       if (numDataBytes >= numInputBytes + 3) {
         // Yay, we found the proper rs block info!
-        qrCode.setVersion(i + 1);
+        qrCode.setVersion(versionNum);
         qrCode.setNumTotalBytes(numBytes);
         qrCode.setNumDataBytes(numDataBytes);
         qrCode.setNumRSBlocks(numRSBlocks);
         // getNumECBytes = 196 - 66 = 130
-        qrCode.setNumECBytes(numBytes - numDataBytes);
+        qrCode.setNumECBytes(numEcBytes);
         // matrix width = 21 + 6 * 4 = 45
-        qrCode.setMatrixWidth(21 + i * 4);
+        qrCode.setMatrixWidth(version.getDimensionForVersion());
         return;
       }
     }
@@ -274,7 +221,7 @@ public final class Encoder {
 
   // Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
   static void terminateBits(int numDataBytes, BitVector bits) throws WriterException {
-    final int capacity = numDataBytes * 8;
+    int capacity = numDataBytes << 3;
     if (bits.size() > capacity) {
       throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity);
     }
@@ -282,10 +229,10 @@ public final class Encoder {
     for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
       bits.appendBit(0);
     }
-    final int numBitsInLastByte = bits.size() % 8;
+    int numBitsInLastByte = bits.size() % 8;
     // If the last byte isn't 8-bit aligned, we'll add padding bits.
     if (numBitsInLastByte > 0) {
-      final int numPaddingBits = 8 - numBitsInLastByte;
+      int numPaddingBits = 8 - numBitsInLastByte;
       for (int i = 0; i < numPaddingBits; ++i) {
         bits.appendBit(0);
       }
@@ -295,7 +242,7 @@ public final class Encoder {
       throw new WriterException("Number of bits is not a multiple of 8");
     }
     // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
-    final int numPaddingBytes = numDataBytes - bits.sizeInBytes();
+    int numPaddingBytes = numDataBytes - bits.sizeInBytes();
     for (int i = 0; i < numPaddingBytes; ++i) {
       if (i % 2 == 0) {
         bits.appendBits(0xec, 8);
@@ -318,21 +265,21 @@ public final class Encoder {
       throw new WriterException("Block ID too large");
     }
     // numRsBlocksInGroup2 = 196 % 5 = 1
-    final int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
+    int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
     // numRsBlocksInGroup1 = 5 - 1 = 4
-    final int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
+    int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
     // numTotalBytesInGroup1 = 196 / 5 = 39
-    final int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
+    int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
     // numTotalBytesInGroup2 = 39 + 1 = 40
-    final int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
+    int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
     // numDataBytesInGroup1 = 66 / 5 = 13
-    final int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
+    int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
     // numDataBytesInGroup2 = 13 + 1 = 14
-    final int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
+    int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
     // numEcBytesInGroup1 = 39 - 13 = 26
-    final int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
+    int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
     // numEcBytesInGroup2 = 40 - 14 = 26
-    final int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
+    int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
     // Sanity checks.
     // 26 = 26
     if (numEcBytesInGroup1 != numEcBytesInGroup2) {
@@ -363,7 +310,7 @@ public final class Encoder {
   // Interleave "bits" with corresponding error correction bytes. On success, store the result in
   // "result" and return true. The interleave rule is complicated. See 8.6
   // of JISX0510:2004 (p.37) for details.
-  static void interleaveWithECBytes(final BitVector bits, int numTotalBytes,
+  static void interleaveWithECBytes(BitVector bits, int numTotalBytes,
       int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
 
     // "bits" must have "getNumDataBytes" bytes of data.
@@ -403,7 +350,7 @@ public final class Encoder {
     // First, place data blocks.
     for (int i = 0; i < maxNumDataBytes; ++i) {
       for (int j = 0; j < blocks.size(); ++j) {
-        final ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
+        ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
         if (i < dataBytes.size()) {
           result.appendBits(dataBytes.at(i), 8);
         }
@@ -412,7 +359,7 @@ public final class Encoder {
     // Then, place error correction blocks.
     for (int i = 0; i < maxNumEcBytes; ++i) {
       for (int j = 0; j < blocks.size(); ++j) {
-        final ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
+        ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
         if (i < ecBytes.size()) {
           result.appendBits(ecBytes.at(i), 8);
         }
@@ -448,18 +395,8 @@ public final class Encoder {
 
   // Append length info. On success, store the result in "bits" and return true. On error, return
   // false.
-  static void appendLengthInfo(int numBytes, int version, Mode mode, BitVector bits) throws WriterException {
-    int numLetters = numBytes;
-    // In Kanji mode, a letter is represented in two bytes.
-    if (mode.equals(Mode.KANJI)) {
-      if (numLetters % 2 != 0) {
-        throw new WriterException("Number of letters must be even");
-      }
-      numLetters /= 2;
-    }
-
-    final int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
-
+  static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits) throws WriterException {
+    int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
     if (numLetters > ((1 << numBits) - 1)) {
       throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1));
     }
@@ -468,61 +405,54 @@ public final class Encoder {
 
   // Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
   // and return true.
-  static void appendBytes(final ByteArray bytes, Mode mode, BitVector bits) throws WriterException {
+  static void appendBytes(String content, Mode mode, BitVector bits) throws WriterException {
     if (mode.equals(Mode.NUMERIC)) {
-      appendNumericBytes(bytes, bits);
+      appendNumericBytes(content, bits);
     } else if (mode.equals(Mode.ALPHANUMERIC)) {
-      appendAlphanumericBytes(bytes, bits);
+      appendAlphanumericBytes(content, bits);
     } else if (mode.equals(Mode.BYTE)) {
-      append8BitBytes(bytes, bits);
+      append8BitBytes(content, bits);
     } else if (mode.equals(Mode.KANJI)) {
-      appendKanjiBytes(bytes, bits);
+      appendKanjiBytes(content, bits);
     } else {
       throw new WriterException("Invalid mode: " + mode);
     }
   }
 
-  // Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits"
-  // and return true.
-  static void appendNumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
-    // Validate all the bytes first.
-    for (int i = 0; i < bytes.size(); ++i) {
-      int oneByte = bytes.at(i);
-      if (oneByte < '0' || oneByte > '9') {
-        throw new WriterException("Non-digit found");
-      }
-    }
-    for (int i = 0; i < bytes.size();) {
-      final int num1 = bytes.at(i) - '0';
-      if (i + 2 < bytes.size()) {
+  static void appendNumericBytes(String content, BitVector bits) {
+    int length = content.length();
+    int i = 0;
+    while (i < length) {
+      int num1 = content.charAt(i) - '0';
+      if (i + 2 < length) {
         // Encode three numeric letters in ten bits.
-        final int num2 = bytes.at(i + 1) - '0';
-        final int num3 = bytes.at(i + 2) - '0';
+        int num2 = content.charAt(i + 1) - '0';
+        int num3 = content.charAt(i + 2) - '0';
         bits.appendBits(num1 * 100 + num2 * 10 + num3, 10);
         i += 3;
-      } else if (i + 1 < bytes.size()) {
+      } else if (i + 1 < length) {
         // Encode two numeric letters in seven bits.
-        final int num2 = bytes.at(i + 1) - '0';
+        int num2 = content.charAt(i + 1) - '0';
         bits.appendBits(num1 * 10 + num2, 7);
         i += 2;
       } else {
         // Encode one numeric letter in four bits.
         bits.appendBits(num1, 4);
-        ++i;
+        i++;
       }
     }
   }
 
-  // Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in
-  // "bits" and return true.
-  static void appendAlphanumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
-    for (int i = 0; i < bytes.size();) {
-      final int code1 = getAlphanumericCode(bytes.at(i));
+  static void appendAlphanumericBytes(String content, BitVector bits) throws WriterException {
+    int length = content.length();
+    int i = 0;
+    while (i < length) {
+      int code1 = getAlphanumericCode(content.charAt(i));
       if (code1 == -1) {
         throw new WriterException();
       }
-      if (i + 1 < bytes.size()) {
-        final int code2 = getAlphanumericCode(bytes.at(i + 1));
+      if (i + 1 < length) {
+        int code2 = getAlphanumericCode(content.charAt(i + 1));
         if (code2 == -1) {
           throw new WriterException();
         }
@@ -532,31 +462,35 @@ public final class Encoder {
       } else {
         // Encode one alphanumeric letter in six bits.
         bits.appendBits(code1, 6);
-        ++i;
+        i++;
       }
     }
   }
 
-  // Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in
-  // "bits" and return true.
-  static void append8BitBytes(final ByteArray bytes, BitVector bits) {
-    for (int i = 0; i < bytes.size(); ++i) {
-      bits.appendBits(bytes.at(i), 8);
+  static void append8BitBytes(String content, BitVector bits) throws WriterException {
+    byte[] bytes;
+    try {
+      bytes = content.getBytes("ISO-8859-1"); // TODO support specifying encoding?
+    } catch (UnsupportedEncodingException uee) {
+      throw new WriterException(uee.toString());
+    }
+    for (int i = 0; i < bytes.length; ++i) {
+      bits.appendBits(bytes[i], 8);
     }
   }
 
-  // Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits"
-  // and return true. See 8.4.5 of JISX0510:2004 (p.21) for how to encode
-  // Kanji bytes.
-  static void appendKanjiBytes(final ByteArray bytes, BitVector bits) throws WriterException {
-    if (bytes.size() % 2 != 0) {
-      throw new WriterException("Number of bytes must be even");
-    }
-    for (int i = 0; i < bytes.size(); i += 2) {
-      if (!isValidKanji(bytes.at(i), bytes.at(i + 1))) {
-        throw new WriterException("Invalid Kanji at " + i);
-      }
-      final int code = (bytes.at(i) << 8) | bytes.at(i + 1);
+  static void appendKanjiBytes(String content, BitVector bits) throws WriterException {
+    byte[] bytes;
+    try {
+      bytes = content.getBytes("Shift_JIS");
+    } catch (UnsupportedEncodingException uee) {
+      throw new WriterException(uee.toString());
+    }
+    int length = bytes.length;
+    for (int i = 0; i < length; i += 2) {
+      int byte1 = bytes[i] & 0xFF;
+      int byte2 = bytes[i + 1] & 0xFF;
+      int code = (byte1 << 8) | byte2;
       int subtracted = -1;
       if (code >= 0x8140 && code <= 0x9ffc) {
         subtracted = code - 0x8140;
@@ -564,35 +498,11 @@ public final class Encoder {
         subtracted = code - 0xc140;
       }
       if (subtracted == -1) {
-        throw new WriterException("Invalid byte sequence: " + bytes);
+        throw new WriterException("Invalid byte sequence");
       }
-      final int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
+      int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
       bits.appendBits(encoded, 13);
     }
   }
 
-  // Check if "byte1" and "byte2" can compose a valid Kanji letter (2-byte Shift_JIS letter). The
-  // numbers are from http://ja.wikipedia.org/wiki/Shift_JIS.
-  static boolean isValidKanji(final int byte1, final int byte2) {
-    return (byte2 != 0x7f &&
-        ((byte1 >= 0x81 && byte1 <= 0x9f &&
-            byte2 >= 0x40 && byte2 <= 0xfc) ||
-            ((byte1 >= 0xe0 && byte1 <= 0xfc &&
-                byte2 >= 0x40 && byte2 <= 0xfc))));
-  }
-
-  // Check if "bytes" is a valid Kanji sequence. Used by the unit tests.
-  static boolean isValidKanjiSequence(final ByteArray bytes) {
-    if (bytes.size() % 2 != 0) {
-      return false;
-    }
-    int i = 0;
-    for (; i < bytes.size(); i += 2) {
-      if (!isValidKanji(bytes.at(i), bytes.at(i + 1))) {
-        break;
-      }
-    }
-    return i == bytes.size();  // Consumed all bytes?
-  }
-
 }
index 3c1c00c..d99c68c 100644 (file)
@@ -28,26 +28,15 @@ public final class MaskUtil {
     // do nothing
   }
 
-  // The mask penalty calculation is complicated.  See Table 21 of JISX0510:2004 (p.45) for details.
-  // Basically it applies four rules and summate all penalties.
-  public static int calculateMaskPenalty(final ByteMatrix matrix) {
-    int penalty = 0;
-    penalty += applyMaskPenaltyRule1(matrix);
-    penalty += applyMaskPenaltyRule2(matrix);
-    penalty += applyMaskPenaltyRule3(matrix);
-    penalty += applyMaskPenaltyRule4(matrix);
-    return penalty;
-  }
-
   // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
   // give penalty to them. Example: 00000 or 11111.
-  public static int applyMaskPenaltyRule1(final ByteMatrix matrix) {
+  public static int applyMaskPenaltyRule1(ByteMatrix matrix) {
     return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false);
   }
 
   // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
   // penalty to them.
-  public static int applyMaskPenaltyRule2(final ByteMatrix matrix) {
+  public static int applyMaskPenaltyRule2(ByteMatrix matrix) {
     int penalty = 0;
     byte[][] array = matrix.getArray();
     int width = matrix.width();
@@ -66,7 +55,7 @@ public final class MaskUtil {
   // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or
   // 10111010000, and give penalty to them.  If we find patterns like 000010111010000, we give
   // penalties twice (i.e. 40 * 2).
-  public static int applyMaskPenaltyRule3(final ByteMatrix matrix) {
+  public static int applyMaskPenaltyRule3(ByteMatrix matrix) {
     int penalty = 0;
     byte[][] array = matrix.getArray();
     int width = matrix.width();
@@ -128,7 +117,7 @@ public final class MaskUtil {
   // -  55% =>  10
   // -  55% =>  20
   // - 100% => 100
-  public static int applyMaskPenaltyRule4(final ByteMatrix matrix) {
+  public static int applyMaskPenaltyRule4(ByteMatrix matrix) {
     int numDarkCells = 0;
     byte[][] array = matrix.getArray();
     int width = matrix.width();
@@ -140,14 +129,14 @@ public final class MaskUtil {
         }
       }
     }
-    final int numTotalCells = matrix.height() * matrix.width();
+    int numTotalCells = matrix.height() * matrix.width();
     double darkRatio = (double) numDarkCells / numTotalCells;
     return Math.abs((int) (darkRatio * 100 - 50)) / 5 * 10;
   }
 
   // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
   // pattern conditions.
-  public static int getDataMaskBit(final int maskPattern, final int x, final int y) {
+  public static int getDataMaskBit(int maskPattern, int x, int y) {
     if (!QRCode.isValidMaskPattern(maskPattern)) {
       throw new IllegalArgumentException("Invalid mask pattern");
     }
@@ -174,7 +163,7 @@ public final class MaskUtil {
 
   // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
   // vertical and horizontal orders respectively.
-  private static int applyMaskPenaltyRule1Internal(final ByteMatrix matrix, boolean isHorizontal) {
+  private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) {
     int penalty = 0;
     int numSameBitCells = 0;
     int prevBit = -1;
@@ -186,12 +175,12 @@ public final class MaskUtil {
     //   for (int i = 0; i < matrix.width(); ++i) {
     //     for (int j = 0; j < matrix.height(); ++j) {
     //       int bit = matrix.get(j, i);
-    final int iLimit = isHorizontal ? matrix.height() : matrix.width();
-    final int jLimit = isHorizontal ? matrix.width() : matrix.height();
+    int iLimit = isHorizontal ? matrix.height() : matrix.width();
+    int jLimit = isHorizontal ? matrix.width() : matrix.height();
     byte[][] array = matrix.getArray();
     for (int i = 0; i < iLimit; ++i) {
       for (int j = 0; j < jLimit; ++j) {
-        final int bit = isHorizontal ? array[i][j] : array[j][i];
+        int bit = isHorizontal ? array[i][j] : array[j][i];
         if (bit == prevBit) {
           numSameBitCells += 1;
           // Found five repetitive cells with the same color (bit).
index c3cdc47..493cc79 100644 (file)
@@ -136,9 +136,9 @@ public final class MatrixUtil {
 
   // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
   // success, store the result in "matrix" and return true.
-  public static void buildMatrix(final BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
+  public static void buildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
       int maskPattern, ByteMatrix matrix) throws WriterException {
-    MatrixUtil.clearMatrix(matrix);
+    clearMatrix(matrix);
     embedBasicPatterns(version, matrix);
     // Type information appear with any version.
     embedTypeInfo(ecLevel, maskPattern, matrix);
@@ -175,22 +175,22 @@ public final class MatrixUtil {
     for (int i = 0; i < typeInfoBits.size(); ++i) {
       // Place bits in LSB to MSB order.  LSB (least significant bit) is the last value in
       // "typeInfoBits".
-      final int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);
+      int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);
 
       // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
-      final int x1 = TYPE_INFO_COORDINATES[i][0];
-      final int y1 = TYPE_INFO_COORDINATES[i][1];
+      int x1 = TYPE_INFO_COORDINATES[i][0];
+      int y1 = TYPE_INFO_COORDINATES[i][1];
       matrix.set(y1, x1, bit);
 
       if (i < 8) {
         // Right top corner.
-        final int x2 = matrix.width() - i - 1;
-        final int y2 = 8;
+        int x2 = matrix.width() - i - 1;
+        int y2 = 8;
         matrix.set(y2, x2, bit);
       } else {
         // Left bottom corner.
-        final int x2 = 8;
-        final int y2 = matrix.height() - 7 + (i - 8);
+        int x2 = 8;
+        int y2 = matrix.height() - 7 + (i - 8);
         matrix.set(y2, x2, bit);
       }
     }
@@ -209,7 +209,7 @@ public final class MatrixUtil {
     for (int i = 0; i < 6; ++i) {
       for (int j = 0; j < 3; ++j) {
         // Place bits in LSB (least significant bit) to MSB order.
-        final int bit = versionInfoBits.at(bitIndex);
+        int bit = versionInfoBits.at(bitIndex);
         bitIndex--;
         // Left bottom corner.
         matrix.set(matrix.height() - 11 + j, i, bit);
@@ -222,7 +222,7 @@ public final class MatrixUtil {
   // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
   // For debugging purposes, it skips masking process if "getMaskPattern" is -1.
   // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
-  public static void embedDataBits(final BitVector dataBits, int maskPattern, ByteMatrix matrix)
+  public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix)
       throws WriterException {
     int bitIndex = 0;
     int direction = -1;
@@ -236,7 +236,7 @@ public final class MatrixUtil {
       }
       while (y >= 0 && y < matrix.height()) {
         for (int i = 0; i < 2; ++i) {
-          final int xx = x - i;
+          int xx = x - i;
           // Skip the cell if it's not empty.
           if (!isEmpty(matrix.get(y, xx))) {
             continue;
@@ -253,7 +253,7 @@ public final class MatrixUtil {
 
           // Skip masking if mask_pattern is -1.
           if (maskPattern != -1) {
-            final int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);
+            int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);
             bit ^= mask;
           }
           matrix.set(y, xx, bit);
@@ -266,7 +266,7 @@ public final class MatrixUtil {
     }
     // All bits should be consumed.
     if (bitIndex != dataBits.size()) {
-      throw new WriterException("Not all bits consumed: " + bitIndex + "/" + dataBits.size());
+      throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size());
     }
   }
 
@@ -312,7 +312,7 @@ public final class MatrixUtil {
   public static int calculateBCHCode(int value, int poly) {
     // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1
     // from 13 to make it 12.
-    final int msbSetInPoly = findMSBSet(poly);
+    int msbSetInPoly = findMSBSet(poly);
     value <<= msbSetInPoly - 1;
     // Do the division business using exclusive-or operations.
     while (findMSBSet(value) >= msbSetInPoly) {
@@ -325,15 +325,15 @@ public final class MatrixUtil {
   // Make bit vector of type information. On success, store the result in "bits" and return true.
   // Encode error correction level and mask pattern. See 8.9 of
   // JISX0510:2004 (p.45) for details.
-  public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, final int maskPattern, BitVector bits)
+  public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits)
       throws WriterException {
     if (!QRCode.isValidMaskPattern(maskPattern)) {
       throw new WriterException("Invalid mask pattern");
     }
-    final int typeInfo = (ecLevel.getBits() << 3) | maskPattern;
+    int typeInfo = (ecLevel.getBits() << 3) | maskPattern;
     bits.appendBits(typeInfo, 5);
 
-    final int bchCode = MatrixUtil.calculateBCHCode(typeInfo, TYPE_INFO_POLY);
+    int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY);
     bits.appendBits(bchCode, 10);
 
     BitVector maskBits = new BitVector();
@@ -349,7 +349,7 @@ public final class MatrixUtil {
   // See 8.10 of JISX0510:2004 (p.45) for details.
   public static void makeVersionInfoBits(int version, BitVector bits) throws WriterException {
     bits.appendBits(version, 6);
-    final int bchCode = MatrixUtil.calculateBCHCode(version, VERSION_INFO_POLY);
+    int bchCode = calculateBCHCode(version, VERSION_INFO_POLY);
     bits.appendBits(bchCode, 12);
 
     if (bits.size() != 18) {  // Just in case.
@@ -358,12 +358,12 @@ public final class MatrixUtil {
   }
 
   // Check if "value" is empty.
-  private static boolean isEmpty(final int value) {
+  private static boolean isEmpty(int value) {
     return value == -1;
   }
 
   // Check if "value" is valid.
-  private static boolean isValidValue(final int value) {
+  private static boolean isValidValue(int value) {
     return (value == -1 ||  // Empty.
         value == 0 ||  // Light (white).
         value == 1);  // Dark (black).
@@ -373,7 +373,7 @@ public final class MatrixUtil {
     // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
     // separation patterns (size 1). Thus, 8 = 7 + 1.
     for (int i = 8; i < matrix.width() - 8; ++i) {
-      final int bit = (i + 1) % 2;
+      int bit = (i + 1) % 2;
       // Horizontal line.
       if (!isValidValue(matrix.get(6, i))) {
         throw new WriterException();
@@ -399,7 +399,7 @@ public final class MatrixUtil {
     matrix.set(matrix.height() - 8, 8, 1);
   }
 
-  private static void embedHorizontalSeparationPattern(final int xStart, final int yStart,
+  private static void embedHorizontalSeparationPattern(int xStart, int yStart,
       ByteMatrix matrix) throws WriterException {
     // We know the width and height.
     if (HORIZONTAL_SEPARATION_PATTERN[0].length != 8 || HORIZONTAL_SEPARATION_PATTERN.length != 1) {
@@ -413,7 +413,7 @@ public final class MatrixUtil {
     }
   }
 
-  private static void embedVerticalSeparationPattern(final int xStart, final int yStart,
+  private static void embedVerticalSeparationPattern(int xStart, int yStart,
       ByteMatrix matrix) throws WriterException {
     // We know the width and height.
     if (VERTICAL_SEPARATION_PATTERN[0].length != 1 || VERTICAL_SEPARATION_PATTERN.length != 7) {
@@ -430,7 +430,7 @@ public final class MatrixUtil {
   // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are
   // almost identical, since we cannot write a function that takes 2D arrays in different sizes in
   // C/C++. We should live with the fact.
-  private static void embedPositionAdjustmentPattern(final int xStart, final int yStart,
+  private static void embedPositionAdjustmentPattern(int xStart, int yStart,
       ByteMatrix matrix) throws WriterException {
     // We know the width and height.
     if (POSITION_ADJUSTMENT_PATTERN[0].length != 5 || POSITION_ADJUSTMENT_PATTERN.length != 5) {
@@ -446,7 +446,7 @@ public final class MatrixUtil {
     }
   }
 
-  private static void embedPositionDetectionPattern(final int xStart, final int yStart,
+  private static void embedPositionDetectionPattern(int xStart, int yStart,
       ByteMatrix matrix) throws WriterException {
     // We know the width and height.
     if (POSITION_DETECTION_PATTERN[0].length != 7 || POSITION_DETECTION_PATTERN.length != 7) {
@@ -465,7 +465,7 @@ public final class MatrixUtil {
   // Embed position detection patterns and surrounding vertical/horizontal separators.
   private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException {
     // Embed three big squares at corners.
-    final int pdpWidth = POSITION_DETECTION_PATTERN[0].length;
+    int pdpWidth = POSITION_DETECTION_PATTERN[0].length;
     // Left top corner.
     embedPositionDetectionPattern(0, 0, matrix);
     // Right top corner.
@@ -474,7 +474,7 @@ public final class MatrixUtil {
     embedPositionDetectionPattern(0, matrix.width() - pdpWidth, matrix);
 
     // Embed horizontal separation patterns around the squares.
-    final int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length;
+    int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length;
     // Left top corner.
     embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
     // Right top corner.
@@ -484,7 +484,7 @@ public final class MatrixUtil {
     embedHorizontalSeparationPattern(0, matrix.width() - hspWidth, matrix);
 
     // Embed vertical separation patterns around the squares.
-    final int vspSize = VERTICAL_SEPARATION_PATTERN.length;
+    int vspSize = VERTICAL_SEPARATION_PATTERN.length;
     // Left top corner.
     embedVerticalSeparationPattern(vspSize, 0, matrix);
     // Right top corner.
@@ -495,18 +495,18 @@ public final class MatrixUtil {
   }
 
   // Embed position adjustment patterns if need be.
-  private static void maybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix)
+  private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix)
       throws WriterException {
     if (version < 2) {  // The patterns appear if version >= 2
       return;
     }
-    final int index = version - 1;
-    final int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
-    final int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length;
+    int index = version - 1;
+    int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
+    int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length;
     for (int i = 0; i < numCoordinates; ++i) {
       for (int j = 0; j < numCoordinates; ++j) {
-        final int y = coordinates[i];
-        final int x = coordinates[j];
+        int y = coordinates[i];
+        int x = coordinates[j];
         if (x == -1 || y == -1) {
           continue;
         }
index 248eb8b..7f0a291 100644 (file)
@@ -26,12 +26,6 @@ import com.google.zxing.qrcode.decoder.Mode;
  */
 public final class QRCode {
 
-  // Magic numbers.
-  private static final int MIN_VERSION = 1;
-  private static final int MAX_VERSION = 40;
-  // For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
-  private static final int MIN_MATRIX_WIDTH = 21;  // Version 1
-  private static final int MAX_MATRIX_WIDTH = 177;  // Version 40 (21 + 4 * (40 -1)).
   public static final int NUM_MASK_PATTERNS = 8;
 
   private Mode mode;
@@ -104,7 +98,7 @@ public final class QRCode {
   }
 
   // ByteMatrix data of the QR Code.
-  public final ByteMatrix getMatrix() {
+  public ByteMatrix getMatrix() {
     return matrix;
   }
   
@@ -136,21 +130,18 @@ public final class QRCode {
         numECBytes != -1 &&
         numRSBlocks != -1 &&
         // Then check them in other ways..
-        isValidVersion(version) &&
-        isValidMatrixWidth(matrixWidth) &&
         isValidMaskPattern(maskPattern) &&
         numTotalBytes == numDataBytes + numECBytes &&
         // ByteMatrix stuff.
         matrix != null &&
         matrixWidth == matrix.width() &&
         // See 7.3.1 of JISX0510:2004 (p.5).
-        matrixWidth == MIN_MATRIX_WIDTH + (version - 1) * 4 &&
         matrix.width() == matrix.height(); // Must be square.
   }
 
   // Return debug String.
   public String toString() {
-    StringBuffer result = new StringBuffer();
+    StringBuffer result = new StringBuffer(200);
     result.append("<<\n");
     result.append(" mode: ");
     result.append(mode);
@@ -221,16 +212,6 @@ public final class QRCode {
     matrix = value;
   }
 
-  // Check if "version" is valid.
-  public static boolean isValidVersion(final int version) {
-    return version >= MIN_VERSION && version <= MAX_VERSION;
-  }
-
-  // Check if "width" is valid.
-  public static boolean isValidMatrixWidth(int width) {
-    return width >= MIN_MATRIX_WIDTH && width <= MAX_MATRIX_WIDTH;
-  }
-
   // Check if "mask_pattern" is valid.
   public static boolean isValidMaskPattern(int maskPattern) {
     return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
index 8a280b2..7ca97d3 100644 (file)
@@ -70,34 +70,34 @@ public final class QRCodeWriterTestCase extends TestCase {
 
   public void testQRCodeWriter() throws WriterException {
     // The QR should be multiplied up to fit, with extra padding if necessary
-    final int bigEnough = 256;
+    int bigEnough = 256;
     QRCodeWriter writer = new QRCodeWriter();
     ByteMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
         bigEnough, null);
-    assertTrue(matrix != null);
+    assertNotNull(matrix);
     assertEquals(bigEnough, matrix.width());
     assertEquals(bigEnough, matrix.height());
 
     // The QR will not fit in this size, so the matrix should come back bigger
-    final int tooSmall = 20;
+    int tooSmall = 20;
     matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, tooSmall,
         tooSmall, null);
-    assertTrue(matrix != null);
+    assertNotNull(matrix);
     assertTrue(tooSmall < matrix.width());
     assertTrue(tooSmall < matrix.height());
 
     // We should also be able to handle non-square requests by padding them
-    final int strangeWidth = 500;
-    final int strangeHeight = 100;
+    int strangeWidth = 500;
+    int strangeHeight = 100;
     matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, strangeWidth,
         strangeHeight, null);
-    assertTrue(matrix != null);
+    assertNotNull(matrix);
     assertEquals(strangeWidth, matrix.width());
     assertEquals(strangeHeight, matrix.height());
   }
 
-  private static boolean compareToGoldenFile(final String contents, final ErrorCorrectionLevel ecLevel,
-      final int resolution, final String fileName) throws WriterException {
+  private static void compareToGoldenFile(String contents, ErrorCorrectionLevel ecLevel,
+      int resolution, String fileName) throws WriterException {
 
     BufferedImage image = loadImage(fileName);
     assertNotNull(image);
@@ -116,24 +116,26 @@ public final class QRCodeWriterTestCase extends TestCase {
         resolution, generatedResult.height());
     assertTrue("Expected " + goldenResult.toString() + " but got " + generatedResult.toString(),
         Arrays.deepEquals(goldenResult.getArray(), generatedResult.getArray()));
-    return true;
   }
 
   // Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
   // and cell phones. We expect pixel-perfect results, because the error correction level is known,
   // and the pixel dimensions matches exactly.
-  public void testRegressionTest() throws WriterException {
-    assertTrue(compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
-        "renderer-test-01.png"));
+  public void testRegressionTest() throws WriterException, IOException {
+    compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
+        "renderer-test-01.png");
 
-    assertTrue(compareToGoldenFile("12345", ErrorCorrectionLevel.L, 58, "renderer-test-02.png"));
+    compareToGoldenFile("12345", ErrorCorrectionLevel.L, 58, "renderer-test-02.png");
 
     // Test in Katakana in Shift_JIS.
-    final byte[] KATAKANA_INPUT = {
-        (byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67
-    };
-    assertTrue(compareToGoldenFile(new String(KATAKANA_INPUT), ErrorCorrectionLevel.H, 145,
-        "renderer-test-03.png"));
+    // TODO: this test is bogus now that byte mode has been basically fixed to assuming ISO-8859-1 encoding
+    //  The real solution is to implement Kanji mode, in which case the golden file will be wrong again
+    /*
+    compareToGoldenFile(
+        new String(new byte[] {(byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67}, "Shift_JIS"),
+        ErrorCorrectionLevel.H, 145,
+        "renderer-test-03.png");
+     */
   }
 
 }
index d189798..ca3ac1f 100644 (file)
@@ -22,13 +22,15 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
 import com.google.zxing.qrcode.decoder.Mode;
 import junit.framework.TestCase;
 
+import java.io.UnsupportedEncodingException;
+
 /**
  * @author satorux@google.com (Satoru Takabayashi) - creator
  * @author mysen@google.com (Chris Mysen) - ported from C++
  */
 public final class EncoderTestCase extends TestCase {
 
-  public void testGetAlphanumericCode() throws WriterException {
+  public void testGetAlphanumericCode() {
     // The first ten code points are numbers.
     for (int i = 0; i < 10; ++i) {
       assertEquals(i, Encoder.getAlphanumericCode('0' + i));
@@ -58,36 +60,33 @@ public final class EncoderTestCase extends TestCase {
 
   public void testChooseMode() throws WriterException {
     // Numeric mode.
-    assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0")));
-    assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0123456789")));
+    assertEquals(Mode.NUMERIC, Encoder.chooseMode("0"));
+    assertEquals(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
     // Alphanumeric mode.
-    assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode(new ByteArray("A")));
+    assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
     assertEquals(Mode.ALPHANUMERIC,
-        Encoder.chooseMode(new ByteArray("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")));
+        Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
     // 8-bit byte mode.
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("a")));
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("#")));
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("")));
+    assertEquals(Mode.BYTE, Encoder.chooseMode("a"));
+    assertEquals(Mode.BYTE, Encoder.chooseMode("#"));
+    assertEquals(Mode.BYTE, Encoder.chooseMode(""));
     // Kanji mode.  We used to use MODE_KANJI for these, but we stopped
     // doing that as we cannot distinguish Shift_JIS from other encodings
     // from data bytes alone.  See also comments in qrcode_encoder.h.
 
     // AIUE in Hiragana in Shift_JIS
-    byte[] dat1 = {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6};
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat1)));
+    assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6})));
 
     // Nihon in Kanji in Shift_JIS.
-    byte[] dat2 = {0x9,0xf,0x9,0x7b};
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat2)));
+    assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x9,0xf,0x9,0x7b})));
 
     // Sou-Utsu-Byou in Kanji in Shift_JIS.
-    byte[] dat3 = {0xe,0x4,0x9,0x5,0x9,0x61};
-    assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat3)));
+    assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0xe,0x4,0x9,0x5,0x9,0x61})));
   }
 
   public void testEncode() throws WriterException {
     QRCode qrCode = new QRCode();
-    Encoder.encode(new ByteArray("ABCDEF"), ErrorCorrectionLevel.H, qrCode);
+    Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, qrCode);
     // The following is a valid QR Code that can be read by cell phones.
     String expected =
       "<<\n" +
@@ -159,7 +158,7 @@ public final class EncoderTestCase extends TestCase {
     }
     {
       BitVector bits = new BitVector();
-      Encoder.appendLengthInfo(1024,  // 512 letters (1024/2).
+      Encoder.appendLengthInfo(512,  // 512 letters (1024/2).
                                                  40,  // version 40.
                                                  Mode.KANJI,
                                                  bits);
@@ -172,25 +171,18 @@ public final class EncoderTestCase extends TestCase {
       // Should use appendNumericBytes.
       // 1 = 01 = 0001 in 4 bits.
       BitVector bits = new BitVector();
-      Encoder.appendBytes(new ByteArray("1"), Mode.NUMERIC, bits);
+      Encoder.appendBytes("1", Mode.NUMERIC, bits);
       assertEquals("0001" , bits.toString());
-      // 'A' cannot be encoded in MODE_NUMERIC.
-      try {
-        Encoder.appendBytes(new ByteArray("A"), Mode.NUMERIC, bits);
-        fail("Should have thrown exception");
-      } catch (WriterException we) {
-        // good
-      }
     }
     {
       // Should use appendAlphanumericBytes.
       // A = 10 = 0xa = 001010 in 6 bits
       BitVector bits = new BitVector();
-      Encoder.appendBytes(new ByteArray("A"), Mode.ALPHANUMERIC, bits);
+      Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits);
       assertEquals("001010" , bits.toString());
       // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
       try {
-        Encoder.appendBytes(new ByteArray("a"), Mode.ALPHANUMERIC, bits);
+        Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits);
       } catch (WriterException we) {
         // good
       }
@@ -199,33 +191,20 @@ public final class EncoderTestCase extends TestCase {
       // Should use append8BitBytes.
       // 0x61, 0x62, 0x63
       BitVector bits = new BitVector();
-      Encoder.appendBytes(new ByteArray("abc"), Mode.BYTE, bits);
-      assertEquals("01100001" + "01100010" + "01100011", bits.toString());
+      Encoder.appendBytes("abc", Mode.BYTE, bits);
+      assertEquals("011000010110001001100011", bits.toString());
       // Anything can be encoded in QRCode.MODE_8BIT_BYTE.
-      byte[] bytes = {0x00};
-      Encoder.appendBytes(new ByteArray(bytes), Mode.BYTE, bits);
+      Encoder.appendBytes("\0", Mode.BYTE, bits);
     }
     {
       // Should use appendKanjiBytes.
       // 0x93, 0x5f
       BitVector bits = new BitVector();
-      byte[] bytes = {(byte)0x93,0x5f};
-      Encoder.appendBytes(new ByteArray(bytes), Mode.KANJI, bits);
+      Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits);
       assertEquals("0110110011111", bits.toString());
-      // ASCII characters can not be encoded in QRCode.MODE_KANJI.
-
-      try {
-        Encoder.appendBytes(new ByteArray("a"), Mode.KANJI, bits);
-      } catch (WriterException we) {
-        // good
-      }
     }
   }
 
-  public void testInit() {
-    // TODO: should be implemented.
-  }
-
   public void testTerminateBits() throws WriterException {
     {
       BitVector v = new BitVector();
@@ -306,14 +285,14 @@ public final class EncoderTestCase extends TestCase {
 
   public void testInterleaveWithECBytes() throws WriterException {
     {
-      final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
+      byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
       BitVector in = new BitVector();
       for (byte dataByte: dataBytes) {
         in.appendBits(dataByte, 8);
       }
       BitVector out = new BitVector();
       Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
-      final byte[] expected = {
+      byte[] expected = {
           // Data bytes.
           32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
           // Error correction bytes.
@@ -321,7 +300,7 @@ public final class EncoderTestCase extends TestCase {
           (byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
       };
       assertEquals(expected.length, out.sizeInBytes());
-      final byte[] outArray = out.getArray();
+      byte[] outArray = out.getArray();
       // Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
       for (int x = 0; x < expected.length; x++) {
         assertEquals(expected[x], outArray[x]);
@@ -329,7 +308,7 @@ public final class EncoderTestCase extends TestCase {
     }
     // Numbers are from http://www.swetake.com/qr/qr8.html
     {
-      final byte[] dataBytes = {
+      byte[] dataBytes = {
           67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182,
           (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119, (byte)135,
           (byte)151, (byte)166, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166,
@@ -343,7 +322,7 @@ public final class EncoderTestCase extends TestCase {
       }
       BitVector out = new BitVector();
       Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
-      final byte[] expected = {
+      byte[] expected = {
           // Data bytes.
           67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
           118, 119, 70, 55, (byte)134, (byte)135, 86, 71, (byte)150, (byte)151, 102, 87, (byte)166,
@@ -361,85 +340,76 @@ public final class EncoderTestCase extends TestCase {
           (byte)187, 49, (byte)156, (byte)214,
       };
       assertEquals(expected.length, out.sizeInBytes());
-      final byte[] outArray = out.getArray();
+      byte[] outArray = out.getArray();
       for (int x = 0; x < expected.length; x++) {
         assertEquals(expected[x], outArray[x]);
       }
     }
   }
 
-  public void testAppendNumericBytes() throws WriterException {
+  public void testAppendNumericBytes() {
     {
       // 1 = 01 = 0001 in 4 bits.
       BitVector bits = new BitVector();
-      Encoder.appendNumericBytes(new ByteArray("1"), bits);
+      Encoder.appendNumericBytes("1", bits);
       assertEquals("0001" , bits.toString());
     }
     {
       // 12 = 0xc = 0001100 in 7 bits.
       BitVector bits = new BitVector();
-      Encoder.appendNumericBytes(new ByteArray("12"), bits);
+      Encoder.appendNumericBytes("12", bits);
       assertEquals("0001100" , bits.toString());
     }
     {
       // 123 = 0x7b = 0001111011 in 10 bits.
       BitVector bits = new BitVector();
-      Encoder.appendNumericBytes(new ByteArray("123"), bits);
+      Encoder.appendNumericBytes("123", bits);
       assertEquals("0001111011" , bits.toString());
     }
     {
       // 1234 = "123" + "4" = 0001111011 + 0100
       BitVector bits = new BitVector();
-      Encoder.appendNumericBytes(new ByteArray("1234"), bits);
+      Encoder.appendNumericBytes("1234", bits);
       assertEquals("0001111011" + "0100" , bits.toString());
     }
     {
       // Empty.
       BitVector bits = new BitVector();
-      Encoder.appendNumericBytes(new ByteArray(""), bits);
+      Encoder.appendNumericBytes("", bits);
       assertEquals("" , bits.toString());
     }
-    {
-      // Invalid data.
-      BitVector bits = new BitVector();
-      try {
-        Encoder.appendNumericBytes(new ByteArray("abc"), bits);
-      } catch (WriterException we) {
-        // good
-      }
-    }
   }
 
   public void testAppendAlphanumericBytes() throws WriterException {
     {
       // A = 10 = 0xa = 001010 in 6 bits
       BitVector bits = new BitVector();
-      Encoder.appendAlphanumericBytes(new ByteArray("A"), bits);
+      Encoder.appendAlphanumericBytes("A", bits);
       assertEquals("001010" , bits.toString());
     }
     {
       // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
       BitVector bits = new BitVector();
-      Encoder.appendAlphanumericBytes(new ByteArray("AB"), bits);
+      Encoder.appendAlphanumericBytes("AB", bits);
       assertEquals("00111001101", bits.toString());
     }
     {
       // ABC = "AB" + "C" = 00111001101 + 001100
       BitVector bits = new BitVector();
-      Encoder.appendAlphanumericBytes(new ByteArray("ABC"), bits);
+      Encoder.appendAlphanumericBytes("ABC", bits);
       assertEquals("00111001101" + "001100" , bits.toString());
     }
     {
       // Empty.
       BitVector bits = new BitVector();
-      Encoder.appendAlphanumericBytes(new ByteArray(""), bits);
+      Encoder.appendAlphanumericBytes("", bits);
       assertEquals("" , bits.toString());
     }
     {
       // Invalid data.
       BitVector bits = new BitVector();
       try {
-        Encoder.appendAlphanumericBytes(new ByteArray("abc"), bits);
+        Encoder.appendAlphanumericBytes("abc", bits);
       } catch (WriterException we) {
         // good
       }
@@ -450,93 +420,26 @@ public final class EncoderTestCase extends TestCase {
     {
       // 0x61, 0x62, 0x63
       BitVector bits = new BitVector();
-      Encoder.append8BitBytes(new ByteArray("abc"), bits);
+      Encoder.append8BitBytes("abc", bits);
       assertEquals("01100001" + "01100010" + "01100011", bits.toString());
     }
     {
       // Empty.
       BitVector bits = new BitVector();
-      Encoder.append8BitBytes(new ByteArray(""), bits);
+      Encoder.append8BitBytes("", bits);
       assertEquals("", bits.toString());
     }
   }
 
   // Numbers are from page 21 of JISX0510:2004
   public void testAppendKanjiBytes() throws WriterException {
-    {
       BitVector bits = new BitVector();
-      byte[] dat1 = {(byte)0x93,0x5f};
-      Encoder.appendKanjiBytes(new ByteArray(dat1), bits);
+      Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), bits);
       assertEquals("0110110011111", bits.toString());
-      byte[] dat2 = {(byte)0xe4,(byte)0xaa};
-      Encoder.appendKanjiBytes(new ByteArray(dat2), bits);
+      Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0xe4,(byte)0xaa}), bits);
       assertEquals("0110110011111" + "1101010101010", bits.toString());
-    }
   }
 
-  // JAVAPORT: Uncomment and fix up with new Reed Solomon objects
-//  static boolean ComparePoly(final int[] expected, final int size, final GF_Poly poly) {
-//    if (size != poly.degree() + 1) {
-//      return false;
-//    }
-//    for (int i = 0; i < size; ++i) {
-//      // "expected" is ordered in a reverse order.  We reverse the coeff
-//      // index for comparison.
-//      final int coeff = GaloisField.GetField(8).Log(
-//          poly.coeff(size - i - 1));
-//      if (expected[i] != coeff) {
-//        Debug.LOG_ERROR("values don't match at " + i + ": " +
-//            expected[i] + " vs. " + coeff);
-//        return false;
-//      }
-//    }
-//    return true;
-//  }
-//
-//  // Numbers are from Appendix A of JISX0510 2004 (p.59).
-//  public void testGetECPoly() {
-//    {
-//      final GF_Poly poly = Encoder.GetECPoly(7);
-//      final int[] expected = {0, 87, 229, 146, 149, 238, 102, 21};
-//      assertTrue(ComparePoly(expected, expected.length, poly));
-//    }
-//    {
-//      final GF_Poly poly = Encoder.GetECPoly(17);
-//      final int[] expected = {
-//          0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150,
-//          39, 243, 163, 136
-//      };
-//      assertTrue(ComparePoly(expected, expected.length, poly));
-//    }
-//    {
-//      final GF_Poly poly = Encoder.GetECPoly(34);
-//      final int[] expected = {
-//          0, 111, 77, 146, 94, 26, 21, 108, 19,
-//          105, 94, 113, 193, 86, 140, 163, 125,
-//          58,
-//          158, 229, 239, 218, 103, 56, 70, 114,
-//          61, 183, 129, 167, 13, 98, 62, 129, 51
-//      };
-//      assertTrue(ComparePoly(expected, expected.length, poly));
-//    }
-//    {
-//      final GF_Poly poly = Encoder.GetECPoly(68);
-//      final int[] expected = {
-//          0, 247, 159, 223, 33, 224, 93, 77, 70,
-//          90, 160, 32, 254, 43, 150, 84, 101,
-//          190,
-//          205, 133, 52, 60, 202, 165, 220, 203,
-//          151, 93, 84, 15, 84, 253, 173, 160,
-//          89, 227, 52, 199, 97, 95, 231, 52,
-//          177, 41, 125, 137, 241, 166, 225, 118,
-//          2, 54,
-//          32, 82, 215, 175, 198, 43, 238, 235,
-//          27, 101, 184, 127, 3, 5, 8, 163, 238
-//      };
-//      assertTrue(ComparePoly(expected, expected.length, poly));
-//    }
-//  }
-
   // Numbers are from http://www.swetake.com/qr/qr3.html and
   // http://www.swetake.com/qr/qr9.html
   public void testGenerateECBytes() {
@@ -577,39 +480,6 @@ public final class EncoderTestCase extends TestCase {
     }
   }
 
-  public void testIsValidKanji() {
-    assertTrue(Encoder.isValidKanji(0x82, 0xa0));  // Hiragana "A".
-    assertTrue(Encoder.isValidKanji(0x93, 0xfa));  // Nichi in Kanji.
-    assertTrue(Encoder.isValidKanji(0x8a, 0xbf));  // Kan in Kanji.
-    assertTrue(Encoder.isValidKanji(0xe7, 0x4e));  // Sou in Kanji.
-    assertTrue(Encoder.isValidKanji(0xea, 0xa2));  // Haruka in Kanji.
-
-    assertFalse(Encoder.isValidKanji('0', '1'));
-    assertFalse(Encoder.isValidKanji(0x82, 0x7f));
-    assertFalse(Encoder.isValidKanji(0xa0, 0xa0));
-  }
-
-  public void testIsValidKanjiSequence() {
-    // AIUEO in Katakana
-    byte[] dat1 = {
-        (byte)0x83, 0x41, (byte)0x83, 0x43, (byte)0x83, 0x45, (byte)0x83, 0x47, (byte)0x83, 0x49
-    };
-    assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat1)));
-    // 012345 in multi-byte letters.
-    byte[] dat2 = {
-        (byte)0x82, 0x4f, (byte)0x82, 0x50, (byte)0x82, 0x51, (byte)0x82, 0x52, (byte)0x82, 0x53,
-        (byte)0x82, 0x54
-    };
-    assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat2)));
-    // Yoroshiku in Kanji.
-    byte[] dat3 = {
-        (byte)0x96, (byte)0xe9, (byte)0x98, 0x49, (byte)0x8e, (byte)0x80, (byte)0x8b, (byte)0xea
-    };
-    assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat3)));
-    assertFalse(Encoder.isValidKanjiSequence(new ByteArray("0123")));
-    assertFalse(Encoder.isValidKanjiSequence(new ByteArray("ABC")));
-  }
-
   public void testBugInBitVectorNumBytes() throws WriterException {
     // There was a bug in BitVector.sizeInBytes() that caused it to return a
     // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
@@ -639,12 +509,20 @@ public final class EncoderTestCase extends TestCase {
     //   - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
     //     11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
     //     bytes).
-    final int arraySize = 3518;
-    byte[] dataBytes = new byte[arraySize];
-    for (int x = 0; x < arraySize; x++) {
-      dataBytes[x] = '0';
+    StringBuilder builder = new StringBuilder(3518);
+    for (int x = 0; x < 3518; x++) {
+      builder.append('0');
     }
     QRCode qrCode = new QRCode();
-    Encoder.encode(new ByteArray(dataBytes), ErrorCorrectionLevel.L, qrCode);
+    Encoder.encode(builder.toString(), ErrorCorrectionLevel.L, qrCode);
   }
+
+  private static String shiftJISString(byte[] bytes) throws WriterException {
+    try {
+      return new String(bytes, "Shift_JIS");
+    } catch (UnsupportedEncodingException uee) {
+      throw new WriterException(uee.toString());
+    }
+  }
+
 }
index e379f34..f1965d6 100644 (file)
@@ -234,7 +234,7 @@ public final class MatrixUtilTestCase extends TestCase {
       " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" +
       " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" +
       " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n";
-    char bytes[] = {32, 65, 205, 69, 41, 220, 46, 128, 236,
+    char[] bytes = {32, 65, 205, 69, 41, 220, 46, 128, 236,
                    42, 159, 74, 221, 244, 169, 239, 150, 138,
                    70, 237, 85, 224, 96, 74, 219 , 61};
     BitVector bits = new BitVector();
index 06be392..8166a8c 100644 (file)
@@ -155,20 +155,6 @@ public final class QRCodeTestCase extends TestCase {
     }
   }
 
-  public void testIsValidVersion() {
-    assertFalse(QRCode.isValidVersion(0));
-    assertTrue(QRCode.isValidVersion(1));
-    assertTrue(QRCode.isValidVersion(40));
-    assertFalse(QRCode.isValidVersion(0));
-  }
-
-  public void testIsValidMatrixWidth() {
-    assertFalse(QRCode.isValidMatrixWidth(20));
-    assertTrue(QRCode.isValidMatrixWidth(21));
-    assertTrue(QRCode.isValidMatrixWidth(177));
-    assertFalse(QRCode.isValidMatrixWidth(178));
-  }
-
   public void testIsValidMaskPattern() {
     assertFalse(QRCode.isValidMaskPattern(-1));
     assertTrue(QRCode.isValidMaskPattern(0));