From: dswitkin Date: Thu, 20 Nov 2008 17:08:30 +0000 (+0000) Subject: Ported over the BitVector bug fix and new unit test from Satoru. X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=c1b651ae31e0d8a170ab2173c38ba0964188f8eb;p=zxing.git Ported over the BitVector bug fix and new unit test from Satoru. git-svn-id: http://zxing.googlecode.com/svn/trunk@742 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- diff --git a/core/src/com/google/zxing/qrcode/encoder/BitVector.java b/core/src/com/google/zxing/qrcode/encoder/BitVector.java index e4938af9..82512bc4 100644 --- a/core/src/com/google/zxing/qrcode/encoder/BitVector.java +++ b/core/src/com/google/zxing/qrcode/encoder/BitVector.java @@ -52,10 +52,8 @@ public final class BitVector { } // Return the number of bytes in the bit vector. - // JAVAPORT: I would have made this ((sizeInBits + 7) >> 3), but apparently users of this class - // depend on the number of bytes being rounded down. I don't see how that works though. public int num_bytes() { - return sizeInBits >> 3; + return (sizeInBits + 7) >> 3; } // Append one bit to the bit vector. diff --git a/core/test/src/com/google/zxing/qrcode/encoder/BitVectorTestCase.java b/core/test/src/com/google/zxing/qrcode/encoder/BitVectorTestCase.java index 06397881..5534280d 100644 --- a/core/test/src/com/google/zxing/qrcode/encoder/BitVectorTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/encoder/BitVectorTestCase.java @@ -101,11 +101,15 @@ public class BitVectorTestCase extends TestCase { BitVector v = new BitVector(); assertEquals(0, v.num_bytes()); v.AppendBit(0); - assertEquals(0, v.num_bytes()); + // 1 bit was added in the vector, so 1 byte should be consumed. + assertEquals(1, v.num_bytes()); v.AppendBits(0, 7); assertEquals(1, v.num_bytes()); v.AppendBits(0, 8); assertEquals(2, v.num_bytes()); + v.AppendBits(0, 1); + // We now have 17 bits, so 3 bytes should be consumed. + assertEquals(3, v.num_bytes()); } public void testAppendBitVector() { diff --git a/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java b/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java index 9a13c98c..9353d8b0 100644 --- a/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java @@ -607,4 +607,42 @@ public final class EncoderTestCase extends TestCase { assertFalse(Encoder.IsValidKanjiSequence(new ByteArray("0123"))); assertFalse(Encoder.IsValidKanjiSequence(new ByteArray("ABC"))); } + + public void testBugInBitVectorNumBytes() throws WriterException { + // There was a bug in BitVector::num_bytes() that caused it to return a + // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits + // in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(), + // BitVector::num_bytes() is used for finding the smallest QR Code + // version that can fit the given data. Hence there were corner cases + // where we chose a wrong QR Code version that cannot fit the given + // data. Note that the issue did not occur with MODE_8BIT_BYTE, as the + // bits in the bit vector are always 8-bit aligned. + // + // Before the bug was fixed, the following test didn't pass, because: + // + // - MODE_NUMERIC is chosen as all bytes in the data are '0' + // - The 3518-byte numeric data needs 1466 bytes + // - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes + // - 3 numeric bytes are encoded in 10 bits, hence the first + // 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits. + // - 2 numeric bytes can be encoded in 7 bits, hence the last + // 2 bytes are encoded in 7 bits. + // - The version 27 QR Code with the EC level L has 1468 bytes for data. + // - 1828 - 360 = 1468 + // - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes + // (1468 -3) are left for data. + // - Because of the bug in BitVector::num_bytes(), InitQRCode() determines + // the given data can fit in 1465 bytes, despite it needs 1466 bytes. + // - Hence QRCodeEncoder::Encode() failed and returned false. + // - To be precise, it needs 11727 + 4 (mode info) + 14 (length info) = + // 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468 + // bytes). + final int arraySize = 3518; + byte[] data_bytes = new byte[arraySize]; + for (int x = 0; x < arraySize; x++) { + data_bytes[x] = '0'; + } + QRCode qr_code = new QRCode(); + Encoder.Encode(new ByteArray(data_bytes), QRCode.EC_LEVEL_L, qr_code); + } }