mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 04:54:04 -08:00
Partial fix for #679: add check digit if absent in UPC-A/E EAN-13/8 encoding, and reject those with invalid check digit
This commit is contained in:
parent
75c51f93fe
commit
2d02cb05ea
|
@ -52,28 +52,43 @@ public final class EAN13Writer extends UPCEANWriter {
|
|||
|
||||
@Override
|
||||
public boolean[] encode(String contents) {
|
||||
if (contents.length() != 13) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 13 digits long, but got " + contents.length());
|
||||
}
|
||||
try {
|
||||
if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) {
|
||||
throw new IllegalArgumentException("Contents do not pass checksum");
|
||||
}
|
||||
} catch (FormatException ignored) {
|
||||
throw new IllegalArgumentException("Illegal contents");
|
||||
int length = contents.length();
|
||||
switch (length) {
|
||||
case 12:
|
||||
// No check digit present, calculate it and add it
|
||||
int check;
|
||||
try {
|
||||
check = UPCEANReader.getStandardUPCEANChecksum(contents);
|
||||
} catch (FormatException fe) {
|
||||
throw new IllegalArgumentException(fe);
|
||||
}
|
||||
contents += check;
|
||||
break;
|
||||
case 13:
|
||||
try {
|
||||
if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) {
|
||||
throw new IllegalArgumentException("Contents do not pass checksum");
|
||||
}
|
||||
} catch (FormatException ignored) {
|
||||
throw new IllegalArgumentException("Illegal contents");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 12 or 13 digits long, but got " + length);
|
||||
}
|
||||
|
||||
int firstDigit = Integer.parseInt(contents.substring(0, 1));
|
||||
|
||||
int firstDigit = Character.digit(contents.charAt(0), 10);
|
||||
int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit];
|
||||
boolean[] result = new boolean[CODE_WIDTH];
|
||||
int pos = 0;
|
||||
|
||||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true);
|
||||
|
||||
// See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded
|
||||
// See EAN13Reader for a description of how the first digit & left bars are encoded
|
||||
for (int i = 1; i <= 6; i++) {
|
||||
int digit = Integer.parseInt(contents.substring(i, i + 1));
|
||||
int digit = Character.digit(contents.charAt(i), 10);
|
||||
if ((parities >> (6 - i) & 1) == 1) {
|
||||
digit += 10;
|
||||
}
|
||||
|
@ -83,7 +98,7 @@ public final class EAN13Writer extends UPCEANWriter {
|
|||
pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false);
|
||||
|
||||
for (int i = 7; i <= 12; i++) {
|
||||
int digit = Integer.parseInt(contents.substring(i, i + 1));
|
||||
int digit = Character.digit(contents.charAt(i), 10);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true);
|
||||
}
|
||||
appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true);
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.google.zxing.oned;
|
|||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
|
@ -55,9 +56,30 @@ public final class EAN8Writer extends UPCEANWriter {
|
|||
*/
|
||||
@Override
|
||||
public boolean[] encode(String contents) {
|
||||
if (contents.length() != 8) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 8 digits long, but got " + contents.length());
|
||||
int length = contents.length();
|
||||
switch (length) {
|
||||
case 7:
|
||||
// No check digit present, calculate it and add it
|
||||
int check;
|
||||
try {
|
||||
check = UPCEANReader.getStandardUPCEANChecksum(contents);
|
||||
} catch (FormatException fe) {
|
||||
throw new IllegalArgumentException(fe);
|
||||
}
|
||||
contents += check;
|
||||
break;
|
||||
case 8:
|
||||
try {
|
||||
if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) {
|
||||
throw new IllegalArgumentException("Contents do not pass checksum");
|
||||
}
|
||||
} catch (FormatException ignored) {
|
||||
throw new IllegalArgumentException("Illegal contents");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 8 digits long, but got " + length);
|
||||
}
|
||||
|
||||
boolean[] result = new boolean[CODE_WIDTH];
|
||||
|
@ -66,14 +88,14 @@ public final class EAN8Writer extends UPCEANWriter {
|
|||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true);
|
||||
|
||||
for (int i = 0; i <= 3; i++) {
|
||||
int digit = Integer.parseInt(contents.substring(i, i + 1));
|
||||
int digit = Character.digit(contents.charAt(i), 10);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], false);
|
||||
}
|
||||
|
||||
pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false);
|
||||
|
||||
for (int i = 4; i <= 7; i++) {
|
||||
int digit = Integer.parseInt(contents.substring(i, i + 1));
|
||||
int digit = Character.digit(contents.charAt(i), 10);
|
||||
pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true);
|
||||
}
|
||||
appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true);
|
||||
|
|
|
@ -48,26 +48,8 @@ public final class UPCAWriter implements Writer {
|
|||
if (format != BarcodeFormat.UPC_A) {
|
||||
throw new IllegalArgumentException("Can only encode UPC-A, but got " + format);
|
||||
}
|
||||
return subWriter.encode(preencode(contents), BarcodeFormat.EAN_13, width, height, hints);
|
||||
// Transform a UPC-A code into the equivalent EAN-13 code and write it that way
|
||||
return subWriter.encode('0' + contents, BarcodeFormat.EAN_13, width, height, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a UPC-A code into the equivalent EAN-13 code, and add a check digit if it is not
|
||||
* already present.
|
||||
*/
|
||||
private static String preencode(String contents) {
|
||||
int length = contents.length();
|
||||
if (length == 11) {
|
||||
// No check digit present, calculate it and add it
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
sum += (contents.charAt(i) - '0') * (i % 2 == 0 ? 3 : 1);
|
||||
}
|
||||
contents += (1000 - sum) % 10;
|
||||
} else if (length != 12) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 11 or 12 digits long, but got " + contents.length());
|
||||
}
|
||||
return '0' + contents;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,16 +265,13 @@ public abstract class UPCEANReader extends OneDReader {
|
|||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
int check = Character.digit(s.charAt(length - 1), 10);
|
||||
return getStandardUPCEANChecksum(s.subSequence(0, length - 1)) == check;
|
||||
}
|
||||
|
||||
static int getStandardUPCEANChecksum(CharSequence s) throws FormatException {
|
||||
int length = s.length();
|
||||
int sum = 0;
|
||||
for (int i = length - 2; i >= 0; i -= 2) {
|
||||
int digit = s.charAt(i) - '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
sum *= 3;
|
||||
for (int i = length - 1; i >= 0; i -= 2) {
|
||||
int digit = s.charAt(i) - '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
|
@ -282,7 +279,15 @@ public abstract class UPCEANReader extends OneDReader {
|
|||
}
|
||||
sum += digit;
|
||||
}
|
||||
return sum % 10 == 0;
|
||||
sum *= 3;
|
||||
for (int i = length - 2; i >= 0; i -= 2) {
|
||||
int digit = s.charAt(i) - '0';
|
||||
if (digit < 0 || digit > 9) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
sum += digit;
|
||||
}
|
||||
return (1000 - sum) % 10;
|
||||
}
|
||||
|
||||
int[] decodeEnd(BitArray row, int endStart) throws NotFoundException {
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Map;
|
|||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
|
@ -49,12 +50,33 @@ public final class UPCEWriter extends UPCEANWriter {
|
|||
|
||||
@Override
|
||||
public boolean[] encode(String contents) {
|
||||
if (contents.length() != 8) {
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 8 digits long, but got " + contents.length());
|
||||
int length = contents.length();
|
||||
switch (length) {
|
||||
case 7:
|
||||
// No check digit present, calculate it and add it
|
||||
int check;
|
||||
try {
|
||||
check = UPCEANReader.getStandardUPCEANChecksum(contents);
|
||||
} catch (FormatException fe) {
|
||||
throw new IllegalArgumentException(fe);
|
||||
}
|
||||
contents += check;
|
||||
break;
|
||||
case 8:
|
||||
try {
|
||||
if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) {
|
||||
throw new IllegalArgumentException("Contents do not pass checksum");
|
||||
}
|
||||
} catch (FormatException ignored) {
|
||||
throw new IllegalArgumentException("Illegal contents");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Requested contents should be 8 digits long, but got " + length);
|
||||
}
|
||||
|
||||
int checkDigit = Integer.parseInt(contents.substring(7, 8));
|
||||
int checkDigit = Character.digit(contents.charAt(7), 10);
|
||||
int parities = UPCEReader.CHECK_DIGIT_ENCODINGS[checkDigit];
|
||||
boolean[] result = new boolean[CODE_WIDTH];
|
||||
int pos = 0;
|
||||
|
@ -62,7 +84,7 @@ public final class UPCEWriter extends UPCEANWriter {
|
|||
pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true);
|
||||
|
||||
for (int i = 1; i <= 6; i++) {
|
||||
int digit = Integer.parseInt(contents.substring(i, i + 1));
|
||||
int digit = Character.digit(contents.charAt(i), 10);
|
||||
if ((parities >> (6 - i) & 1) == 1) {
|
||||
digit += 10;
|
||||
}
|
||||
|
|
|
@ -35,4 +35,11 @@ public final class EAN13WriterTestCase extends Assert {
|
|||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddChecksumAndEncode() throws WriterException {
|
||||
String testStr = "00010100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101000";
|
||||
BitMatrix result = new EAN13Writer().encode("590123412345", BarcodeFormat.EAN_13, testStr.length(), 0);
|
||||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,4 +35,11 @@ public final class EAN8WriterTestCase extends Assert {
|
|||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddChecksumAndEncode() throws WriterException {
|
||||
String testStr = "0001010001011010111101111010110111010101001110111001010001001011100101000";
|
||||
BitMatrix result = new EAN8Writer().encode("9638507", BarcodeFormat.EAN_8, testStr.length(), 0);
|
||||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2016 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.oned;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.BitMatrixTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public final class UPCEWriterTestCase extends Assert {
|
||||
|
||||
@Test
|
||||
public void testEncode() throws WriterException {
|
||||
String testStr = "0000000000010101110010100111000101101011110110111001011101010100000000000";
|
||||
BitMatrix result = new UPCEWriter().encode("05096893", BarcodeFormat.UPC_E, testStr.length(), 0);
|
||||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddChecksumAndEncode() throws WriterException {
|
||||
String testStr = "0000000000010101110010100111000101101011110110111001011101010100000000000";
|
||||
BitMatrix result = new UPCEWriter().encode("0509689", BarcodeFormat.UPC_E, testStr.length(), 0);
|
||||
assertEquals(testStr, BitMatrixTestCase.matrixToString(result));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue