Fixed the build.
[zxing.git] / core / src / com / google / zxing / qrcode / decoder / DecodedBitStreamParser.java
index 059007d..05339f5 100644 (file)
@@ -17,6 +17,7 @@
 package com.google.zxing.qrcode.decoder;
 
 import com.google.zxing.ReaderException;
+import com.google.zxing.common.BitSource;
 
 import java.io.UnsupportedEncodingException;
 
@@ -33,7 +34,7 @@ final class DecodedBitStreamParser {
   /**
    * See ISO 18004:2006, 6.4.4 Table 5
    */
-  private static final char[] ALPHANUMERIC_CHARS = new char[]{
+  private static final char[] ALPHANUMERIC_CHARS = {
       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
       'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
       'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
@@ -59,20 +60,34 @@ final class DecodedBitStreamParser {
     Mode mode;
     do {
       // While still another segment to read...
-      mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
+      if (bits.available() == 0) {
+        // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
+        mode = Mode.TERMINATOR;
+      } else {
+        mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
+      }
       if (!mode.equals(Mode.TERMINATOR)) {
-        // How many characters will follow, encoded in this mode?
-        int count = bits.readBits(mode.getCharacterCountBits(version));
-        if (mode.equals(Mode.NUMERIC)) {
-          decodeNumericSegment(bits, result, count);
-        } else if (mode.equals(Mode.ALPHANUMERIC)) {
-          decodeAlphanumericSegment(bits, result, count);
-        } else if (mode.equals(Mode.BYTE)) {
-          decodeByteSegment(bits, result, count);
-        } else if (mode.equals(Mode.KANJI)) {
-          decodeKanjiSegment(bits, result, count);
+        if (mode.equals(Mode.ECI)) {
+          // Count doesn't apply to ECI
+          parseECI(bits);
+          // We don't currently do anything with ECI, since there seems to be no reference
+          // defining what each value means. AIM's "Extended Channel Interpretations" does
+          // not define it. I have never observed a QR Code using it. So for now, we at least
+          // parse it but don't know how to take action on it.
         } else {
-          throw new ReaderException("Unsupported mode indicator");
+          // How many characters will follow, encoded in this mode?
+         int count = bits.readBits(mode.getCharacterCountBits(version));
+          if (mode.equals(Mode.NUMERIC)) {
+            decodeNumericSegment(bits, result, count);
+          } else if (mode.equals(Mode.ALPHANUMERIC)) {
+            decodeAlphanumericSegment(bits, result, count);
+          } else if (mode.equals(Mode.BYTE)) {
+            decodeByteSegment(bits, result, count);
+          } else if (mode.equals(Mode.KANJI)) {
+            decodeKanjiSegment(bits, result, count);
+          } else {
+            throw new ReaderException("Unsupported mode indicator");
+          }
         }
       }
     } while (!mode.equals(Mode.TERMINATOR));
@@ -89,6 +104,25 @@ final class DecodedBitStreamParser {
     return result.toString();
   }
 
+  private static int parseECI(BitSource bits) {
+    int firstByte = bits.readBits(8);
+    if ((firstByte & 0x80) == 0) {
+      // just one byte
+      return firstByte & 0x7F;
+    } else if ((firstByte & 0xC0) == 0x80) {
+      // two bytes
+      int secondByte = bits.readBits(8);
+      return ((firstByte & 0x3F) << 8) | secondByte;
+    } else if ((firstByte & 0xE0) == 0xC0) {
+      // three bytes
+      int secondByte = bits.readBits(8);
+      int thirdByte = bits.readBits(8);
+      return ((firstByte & 0x1F) << 16) | (secondByte << 8) | thirdByte;
+    }
+    // FIXME: What should we return here?
+    return 0;
+  }
+
   private static void decodeKanjiSegment(BitSource bits,
                                          StringBuffer result,
                                          int count) throws ReaderException {