diff --git a/android/src/com/google/zxing/client/android/DecodeHandler.java b/android/src/com/google/zxing/client/android/DecodeHandler.java index 9a43ed849..e477baf01 100644 --- a/android/src/com/google/zxing/client/android/DecodeHandler.java +++ b/android/src/com/google/zxing/client/android/DecodeHandler.java @@ -38,6 +38,7 @@ final class DecodeHandler extends Handler { private final CaptureActivity activity; private final MultiFormatReader multiFormatReader; + private boolean running = true; DecodeHandler(CaptureActivity activity, Hashtable hints) { multiFormatReader = new MultiFormatReader(); @@ -47,11 +48,15 @@ final class DecodeHandler extends Handler { @Override public void handleMessage(Message message) { + if (!running) { + return; + } switch (message.what) { case R.id.decode: decode((byte[]) message.obj, message.arg1, message.arg2); break; case R.id.quit: + running = false; Looper.myLooper().quit(); break; } diff --git a/core/src/com/google/zxing/datamatrix/decoder/DecodedBitStreamParser.java b/core/src/com/google/zxing/datamatrix/decoder/DecodedBitStreamParser.java index 9343b386d..93964220d 100644 --- a/core/src/com/google/zxing/datamatrix/decoder/DecodedBitStreamParser.java +++ b/core/src/com/google/zxing/datamatrix/decoder/DecodedBitStreamParser.java @@ -43,12 +43,12 @@ final class DecodedBitStreamParser { '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' }; - + private static final char[] C40_SHIFT2_SET_CHARS = { '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_' }; - + /** * See ISO 16022:2006, Annex C Table C.2 * The Text Basic Character Set (*'s used for placeholders for the shift values) @@ -58,12 +58,12 @@ final class DecodedBitStreamParser { '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' }; - + private static final char[] TEXT_SHIFT3_SET_CHARS = { '\'', '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', '{', '|', '}', '~', (char) 127 }; - + private static final int PAD_ENCODE = 0; // Not really an encoding private static final int ASCII_ENCODE = 1; private static final int C40_ENCODE = 2; @@ -112,7 +112,7 @@ final class DecodedBitStreamParser { } return new DecoderResult(bytes, result.toString(), byteSegments.isEmpty() ? null : byteSegments, null); } - + /** * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 */ @@ -257,7 +257,7 @@ final class DecodedBitStreamParser { } } while (bits.available() > 0); } - + /** * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 */ @@ -347,7 +347,7 @@ final class DecodedBitStreamParser { } } while (bits.available() > 0); } - + /** * See ISO 16022:2006, 5.2.7 */ @@ -398,7 +398,7 @@ final class DecodedBitStreamParser { result[1] = temp; result[2] = fullBitValue - temp * 40; } - + /** * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 */ @@ -419,7 +419,7 @@ final class DecodedBitStreamParser { // If we encounter the unlatch code then continue reading because the Codeword triple // is padded with 0's } - + if (!unlatch) { if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit edifactValue |= 64; // Add a leading 01 to the 6 bit binary value @@ -429,7 +429,7 @@ final class DecodedBitStreamParser { } } while (!unlatch && bits.available() > 0); } - + /** * See ISO 16022:2006, 5.2.9 and Annex B, B.2 */ @@ -446,6 +446,12 @@ final class DecodedBitStreamParser { } else { count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++); } + + // We're seeing NegativeArraySizeException errors from users. + if (count < 0) { + throw FormatException.getFormatInstance(); + } + byte[] bytes = new byte[count]; for (int i = 0; i < count; i++) { // Have seen this particular error in the wild, such as at @@ -462,7 +468,7 @@ final class DecodedBitStreamParser { throw new RuntimeException("Platform does not support required encoding: " + uee); } } - + /** * See ISO 16022:2006, Annex B, B.2 */ @@ -472,5 +478,5 @@ final class DecodedBitStreamParser { int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; return (byte) (tempVariable >= 0 ? tempVariable : tempVariable + 256); } - + } diff --git a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java index 085c4d5bc..ff374ac50 100644 --- a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java +++ b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java @@ -126,6 +126,11 @@ final class DecodedBitStreamParser { private static void decodeHanziSegment(BitSource bits, StringBuffer result, int count) throws FormatException { + // Don't crash trying to read more bits than we have available. + if (count * 13 > bits.available()) { + throw FormatException.getFormatInstance(); + } + // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as GB2312 afterwards byte[] buffer = new byte[2 * count]; @@ -146,7 +151,7 @@ final class DecodedBitStreamParser { offset += 2; count--; } - + try { result.append(new String(buffer, StringUtils.GB2312)); } catch (UnsupportedEncodingException uee) { @@ -157,6 +162,11 @@ final class DecodedBitStreamParser { private static void decodeKanjiSegment(BitSource bits, StringBuffer result, int count) throws FormatException { + // Don't crash trying to read more bits than we have available. + if (count * 13 > bits.available()) { + throw FormatException.getFormatInstance(); + } + // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards byte[] buffer = new byte[2 * count]; @@ -191,10 +201,12 @@ final class DecodedBitStreamParser { CharacterSetECI currentCharacterSetECI, Vector byteSegments, Hashtable hints) throws FormatException { - byte[] readBytes = new byte[count]; + // Don't crash trying to read more bits than we have available. if (count << 3 > bits.available()) { throw FormatException.getFormatInstance(); } + + byte[] readBytes = new byte[count]; for (int i = 0; i < count; i++) { readBytes[i] = (byte) bits.readBits(8); } @@ -289,7 +301,7 @@ final class DecodedBitStreamParser { result.append(toAlphaNumericChar(digitBits)); } } - + private static int parseECIValue(BitSource bits) { int firstByte = bits.readBits(8); if ((firstByte & 0x80) == 0) { diff --git a/core/src/com/google/zxing/qrcode/detector/Detector.java b/core/src/com/google/zxing/qrcode/detector/Detector.java index f5bd96351..724d39d59 100644 --- a/core/src/com/google/zxing/qrcode/detector/Detector.java +++ b/core/src/com/google/zxing/qrcode/detector/Detector.java @@ -308,14 +308,19 @@ public class Detector { int dx = Math.abs(toX - fromX); int dy = Math.abs(toY - fromY); int error = -dx >> 1; - int ystep = fromY < toY ? 1 : -1; int xstep = fromX < toX ? 1 : -1; - int state = 0; // In black pixels, looking for white, first or second time - for (int x = fromX, y = fromY; x != toX; x += xstep) { + int ystep = fromY < toY ? 1 : -1; + // In black pixels, looking for white, first or second time. + int state = 0; + for (int x = fromX, y = fromY; x != toX; x += xstep) { int realX = steep ? y : x; int realY = steep ? x : y; - if (state == 1) { // In white pixels, looking for black + + // In white pixels, looking for black. + // FIXME(dswitkin): This method seems to assume square images, which can cause these calls to + // BitMatrix.get() to throw ArrayIndexOutOfBoundsException. + if (state == 1) { if (image.get(realX, realY)) { state++; } @@ -325,7 +330,8 @@ public class Detector { } } - if (state == 3) { // Found black, white, black, and stumbled back onto white; done + // Found black, white, black, and stumbled back onto white, so we're done. + if (state == 3) { int diffX = x - fromX; int diffY = y - fromY; if (xstep < 0) {