From c95fe48a7660eadde7c938438cba6cac0f2b2f16 Mon Sep 17 00:00:00 2001 From: dswitkin Date: Tue, 18 Nov 2008 22:54:04 +0000 Subject: [PATCH] Made several good fixes to and because of the unit tests. Turns out the EC array was never being set to the right size. I've now established that the Reed Solomon code is generating one fewer coefficient than the layer above it asked for. git-svn-id: https://zxing.googlecode.com/svn/trunk@726 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../reedsolomon/ReedSolomonEncoder.java | 10 +++++++++- .../zxing/qrcode/encoder/ByteArray.java | 11 ++++++++--- .../google/zxing/qrcode/encoder/Encoder.java | 19 ++++++++++--------- .../zxing/qrcode/encoder/EncoderTestCase.java | 9 +++------ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/core/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java b/core/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java index c638b044b..e1b06d3a9 100644 --- a/core/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java +++ b/core/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java @@ -52,13 +52,21 @@ public final class ReedSolomonEncoder { public void encode(int[] toEncode, int ecBytes) { int dataBytes = toEncode.length - ecBytes; + if (dataBytes < 0) { + throw new IllegalArgumentException("Too few data bytes provided: " + dataBytes); + } GF256Poly generator = buildGenerator(ecBytes); int[] infoCoefficients = new int[dataBytes]; System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); GF256Poly info = new GF256Poly(field, infoCoefficients); info = info.multiplyByMonomial(ecBytes, 1); GF256Poly remainder = info.divide(generator)[1]; - System.arraycopy(remainder.getCoefficients(), 0, toEncode, dataBytes, ecBytes); + int[] coefficients = remainder.getCoefficients(); + if (coefficients.length < ecBytes) { + throw new RuntimeException("Coefficients array is smaller than EC array (" + + coefficients.length + " < " + ecBytes + ")"); + } + System.arraycopy(coefficients, 0, toEncode, dataBytes, ecBytes); } } diff --git a/core/src/com/google/zxing/qrcode/encoder/ByteArray.java b/core/src/com/google/zxing/qrcode/encoder/ByteArray.java index 8bfe06899..1b8fc5141 100644 --- a/core/src/com/google/zxing/qrcode/encoder/ByteArray.java +++ b/core/src/com/google/zxing/qrcode/encoder/ByteArray.java @@ -33,6 +33,11 @@ public final class ByteArray { size = 0; } + public ByteArray(int size) { + bytes = new byte[size]; + this.size = size; + } + public ByteArray(String string) { bytes = string.getBytes(); size = bytes.length; @@ -83,12 +88,12 @@ public final class ByteArray { } } - // This could probably be generalized to take a byte[] instead of a BitVector. - public void set(BitVector bits, int offset, int count) { + // Copy count bytes from array source starting at offset. + public void set(byte[] source, int offset, int count) { bytes = new byte[count]; size = count; for (int x = 0; x < count; x++) { - bytes[x] = (byte) bits.at(x + offset); + bytes[x] = source[offset + x]; } } diff --git a/core/src/com/google/zxing/qrcode/encoder/Encoder.java b/core/src/com/google/zxing/qrcode/encoder/Encoder.java index 8935c1819..8b4fce425 100644 --- a/core/src/com/google/zxing/qrcode/encoder/Encoder.java +++ b/core/src/com/google/zxing/qrcode/encoder/Encoder.java @@ -16,9 +16,9 @@ package com.google.zxing.qrcode.encoder; -import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; -import com.google.zxing.common.reedsolomon.GF256; import com.google.zxing.common.ByteMatrix; +import com.google.zxing.common.reedsolomon.GF256; +import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; import java.util.Vector; @@ -579,12 +579,10 @@ private static final ECPolyInfo kECPolynomials[] = { num_data_bytes_in_block, num_ec_bytes_in_block); ByteArray data_bytes = new ByteArray(); - ByteArray ec_bytes = new ByteArray(); + data_bytes.set(bits.getArray(), data_bytes_offset, num_data_bytes_in_block[0]); + ByteArray ec_bytes = GenerateECBytes(data_bytes, num_ec_bytes_in_block[0]); blocks.addElement(new BlockPair(data_bytes, ec_bytes)); - data_bytes.set(bits, data_bytes_offset, num_data_bytes_in_block[0]); - GenerateECBytes(data_bytes, num_ec_bytes_in_block[0], ec_bytes); - max_num_data_bytes = Math.max(max_num_data_bytes, data_bytes.size()); max_num_ec_bytes = Math.max(max_num_ec_bytes, ec_bytes.size()); data_bytes_offset += num_data_bytes_in_block[0]; @@ -617,16 +615,19 @@ private static final ECPolyInfo kECPolynomials[] = { return false; } - static void GenerateECBytes(ByteArray data_bytes, int num_ec_bytes_in_block, ByteArray ec_bytes) { + static ByteArray GenerateECBytes(ByteArray data_bytes, int num_ec_bytes_in_block) { int numDataBytes = data_bytes.size(); - int[] toEncode = new int[numDataBytes + ec_bytes.size()]; + int[] toEncode = new int[numDataBytes + num_ec_bytes_in_block]; for (int i = 0; i < numDataBytes; i++) { toEncode[i] = data_bytes.at(i); } new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, num_ec_bytes_in_block); - for (int i = 0; i < ec_bytes.size(); i++) { + + ByteArray ec_bytes = new ByteArray(num_ec_bytes_in_block); + for (int i = 0; i < num_ec_bytes_in_block; i++) { ec_bytes.set(i, toEncode[numDataBytes + i]); } + return ec_bytes; } // Append mode info. On success, store the result in "bits" and return true. On error, return 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 f6a9aedb6..5a1107b3a 100644 --- a/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java @@ -512,9 +512,8 @@ public final class EncoderTestCase extends TestCase { // http://www.swetake.com/qr/qr9.html public void testGenerateECBytes() { { - ByteArray ec_bytes = new ByteArray(); final byte[] data_bytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236}; - Encoder.GenerateECBytes(new ByteArray(data_bytes), 17, ec_bytes); + ByteArray ec_bytes = Encoder.GenerateECBytes(new ByteArray(data_bytes), 17); final byte[] expected = { 42, (byte)159, 74, (byte)221, (byte)244, (byte)169, (byte)239, (byte)150, (byte)138, 70, (byte)237, 85, (byte)224, 96, 74, (byte)219, 61 @@ -522,10 +521,9 @@ public final class EncoderTestCase extends TestCase { assertEquals(new ByteArray(expected), ec_bytes); } { - ByteArray ec_bytes = new ByteArray(); final byte[] data_bytes = {67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214}; - Encoder.GenerateECBytes(new ByteArray(data_bytes), 18, ec_bytes); + ByteArray ec_bytes = Encoder.GenerateECBytes(new ByteArray(data_bytes), 18); final byte[] expected = { (byte)175, 80, (byte)155, 64, (byte)178, 45, (byte)214, (byte)233, 65, (byte)209, 12, (byte)155, 117, 31, (byte)140, (byte)214, 27, (byte)187 @@ -534,9 +532,8 @@ public final class EncoderTestCase extends TestCase { } { // High-order zero cofficient case. - ByteArray ec_bytes = new ByteArray(); final byte[] data_bytes = {32, 49, (byte)205, 69, 42, 20, 0, (byte)236, 17}; - Encoder.GenerateECBytes(new ByteArray(data_bytes), 17, ec_bytes); + ByteArray ec_bytes = Encoder.GenerateECBytes(new ByteArray(data_bytes), 17); final byte[] expected = { 0, 3, (byte)130, (byte)179, (byte)194, 0, 55, (byte)211, 110, 79, 98, 72, (byte)170, 96, (byte)211, (byte)137, (byte)213