More refactoring, fixed a small issue in X12 encodation of \r

git-svn-id: https://zxing.googlecode.com/svn/trunk@521 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2008-07-21 21:45:37 +00:00
parent d04099f61b
commit 81ef86b634

View file

@ -26,6 +26,7 @@ import com.google.zxing.common.BitSource;
* <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
*
* @author bbrown@google.com (Brian Brown)
* @author srowen@google.com (Sean Owen)
*/
final class DecodedBitStreamParser {
@ -56,7 +57,7 @@ final class DecodedBitStreamParser {
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', '{', '|', '}', '~', 127
'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
@ -73,28 +74,33 @@ final class DecodedBitStreamParser {
static String decode(byte[] bytes) throws ReaderException {
BitSource bits = new BitSource(bytes);
StringBuffer result = new StringBuffer();
int mode = ASCII_ENCODE;
do {
if (mode != PAD_ENCODE) {
if (mode == ASCII_ENCODE) {
mode = decodeAsciiSegment(bits, result);
} else if (mode == C40_ENCODE) {
mode = decodeC40Segment(bits, result);
} else if (mode == TEXT_ENCODE) {
mode = decodeTextSegment(bits, result);
} else if (mode == ANSIX12_ENCODE) {
mode = decodeAnsiX12Segment(bits, result);
} else if (mode == EDIFACT_ENCODE) {
mode = decodeEdifactSegment(bits, result);
} else if (mode == BASE256_ENCODE) {
mode = decodeBase256Segment(bits, result);
} else {
throw new ReaderException("Unsupported mode indicator");
if (mode == ASCII_ENCODE) {
mode = decodeAsciiSegment(bits, result);
} else {
switch (mode) {
case C40_ENCODE:
decodeC40Segment(bits, result);
break;
case TEXT_ENCODE:
decodeTextSegment(bits, result);
break;
case ANSIX12_ENCODE:
decodeAnsiX12Segment(bits, result);
break;
case EDIFACT_ENCODE:
decodeEdifactSegment(bits, result);
break;
case BASE256_ENCODE:
decodeBase256Segment(bits, result);
break;
default:
throw new ReaderException("Unsupported mode indicator");
}
mode = ASCII_ENCODE;
}
} while (mode != PAD_ENCODE && bits.available() > 0);
return result.toString();
}
@ -107,7 +113,6 @@ final class DecodedBitStreamParser {
do {
int oneByte = bits.readBits(8);
if (oneByte == 0) {
// TODO(bbrown): I think this would be a bug, not sure
throw new ReaderException("0 is an invalid ASCII codeword");
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
oneByte = upperShift ? (oneByte + 128) : oneByte;
@ -117,11 +122,11 @@ final class DecodedBitStreamParser {
} else if (oneByte == 129) { // Pad
return PAD_ENCODE;
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
// TODO(bbrown): Iassume there is some easier way to do this:
if (oneByte - 130 < 10) {
int value = oneByte - 130;
if (value < 10) { // padd with '0' for single digit values
result.append('0');
}
result.append(Integer.toString(oneByte - 130));
result.append(value);
} else if (oneByte == 230) { // Latch to C40 encodation
return C40_ENCODE;
} else if (oneByte == 231) { // Latch to Base 256 encodation
@ -148,7 +153,7 @@ final class DecodedBitStreamParser {
// TODO(bbrown): I think we need to support ECI
throw new ReaderException("Currently not supporting ECI Character");
} else if (oneByte >= 242) { // Not to be used in ASCII encodation
throw new ReaderException(Integer.toString(oneByte) + " should not be used in ASCII encodation");
throw new ReaderException(oneByte + " should not be used in ASCII encodation");
}
} while (bits.available() > 0);
return ASCII_ENCODE;
@ -157,220 +162,188 @@ final class DecodedBitStreamParser {
/**
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
*/
private static int decodeC40Segment(BitSource bits,
StringBuffer result) throws ReaderException {
private static void decodeC40Segment(BitSource bits, StringBuffer result) throws ReaderException {
// Three C40 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
int shift = 0;
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
boolean upperShift = false;
int[] cValues = new int[3];
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return ASCII_ENCODE;
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return ASCII_ENCODE;
return;
}
int fullBitValue = (firstByte << 8) + bits.readBits(8) - 1;
int[] cValues = new int[3];
cValues[0] = fullBitValue / 1600;
fullBitValue -= cValues[0] * 1600;
cValues[1] = fullBitValue / 40;
fullBitValue -= cValues[1] * 40;
cValues[2] = fullBitValue;
parseTwoBytes(firstByte, bits.readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
if (shift == 0) {
if (cValue == 0) { // Shift 1
shift = 1;
continue;
} else if (cValue == 1) { // Shift 2
shift = 2;
continue;
} else if (cValue == 2) { // Shift 3
shift = 3;
continue;
}
if (upperShift) {
result.append((char) (C40_BASIC_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(C40_BASIC_SET_CHARS[cValue]);
}
} else if (shift == 1) {
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append(cValue);
}
shift = 0;
} else if (shift == 2) {
if (cValue < 27) {
if(upperShift) {
result.append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
switch (shift) {
case 0:
if (cValue < 3) {
shift = cValue + 1;
} else {
if (upperShift) {
result.append((char) (C40_BASIC_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(C40_BASIC_SET_CHARS[cValue]);
}
}
break;
case 1:
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append(C40_SHIFT2_SET_CHARS[cValue]);
result.append(cValue);
}
} else if (cValue == 27) { // FNC1
throw new ReaderException("Currently not supporting FNC1");
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
throw new ReaderException(Integer.toString(cValue) + " is not valid in the C40 Shift 2 set");
}
shift = 0;
} else if (shift == 3) {
if (upperShift) {
result.append((char) (cValue + 224));
upperShift = false;
} else {
result.append((char) (cValue + 96));
}
shift = 0;
} else {
throw new ReaderException("Invalid shift value");
shift = 0;
break;
case 2:
if (cValue < 27) {
if (upperShift) {
result.append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(C40_SHIFT2_SET_CHARS[cValue]);
}
} else if (cValue == 27) { // FNC1
throw new ReaderException("Currently not supporting FNC1");
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
throw new ReaderException(cValue + " is not valid in the C40 Shift 2 set");
}
shift = 0;
break;
case 3:
if (upperShift) {
result.append((char) (cValue + 224));
upperShift = false;
} else {
result.append((char) (cValue + 96));
}
shift = 0;
break;
default:
throw new ReaderException("Invalid shift value");
}
}
} while (bits.available() > 0);
return ASCII_ENCODE;
}
/**
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
*/
private static int decodeTextSegment(BitSource bits,
StringBuffer result) throws ReaderException {
private static void decodeTextSegment(BitSource bits, StringBuffer result) throws ReaderException {
// Three Text values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
int shift = 0;
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
boolean upperShift = false;
int[] cValues = new int[3];
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return ASCII_ENCODE;
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return ASCII_ENCODE;
return;
}
int fullBitValue = (firstByte << 8) + bits.readBits(8) - 1;
int[] cValues = new int[3];
cValues[0] = fullBitValue / 1600;
fullBitValue -= cValues[0] * 1600;
cValues[1] = fullBitValue / 40;
fullBitValue -= cValues[1] * 40;
cValues[2] = fullBitValue;
parseTwoBytes(firstByte, bits.readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
if (shift == 0) {
if (cValue == 0) { // Shift 1
shift = 1;
continue;
} else if (cValue == 1) { // Shift 2
shift = 2;
continue;
} else if (cValue == 2) { // Shift 3
shift = 3;
continue;
}
if (upperShift) {
result.append((char) (TEXT_BASIC_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(TEXT_BASIC_SET_CHARS[cValue]);
}
} else if (shift == 1) {
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append(cValue);
}
shift = 0;
} else if (shift == 2) {
// Shift 2 for Text is the same encoding as C40
if (cValue < 27) {
if(upperShift) {
result.append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
switch (shift) {
case 0:
if (cValue < 3) {
shift = cValue + 1;
} else {
if (upperShift) {
result.append((char) (TEXT_BASIC_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(TEXT_BASIC_SET_CHARS[cValue]);
}
}
break;
case 1:
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append(C40_SHIFT2_SET_CHARS[cValue]);
result.append(cValue);
}
} else if (cValue == 27) { // FNC1
throw new ReaderException("Currently not supporting FNC1");
} else if (cValue == 30) { // Upper Shirt
upperShift = true;
} else {
throw new ReaderException(Integer.toString(cValue) + " is not valid in the C40 Shift 2 set");
}
shift = 0;
} else if (shift == 3) {
if (upperShift) {
result.append((char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(TEXT_SHIFT3_SET_CHARS[cValue]);
}
shift = 0;
} else {
throw new ReaderException("Invalid shift value");
shift = 0;
break;
case 2:
// Shift 2 for Text is the same encoding as C40
if (cValue < 27) {
if (upperShift) {
result.append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(C40_SHIFT2_SET_CHARS[cValue]);
}
} else if (cValue == 27) { // FNC1
throw new ReaderException("Currently not supporting FNC1");
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
throw new ReaderException(cValue + " is not valid in the C40 Shift 2 set");
}
shift = 0;
break;
case 3:
if (upperShift) {
result.append((char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128));
upperShift = false;
} else {
result.append(TEXT_SHIFT3_SET_CHARS[cValue]);
}
shift = 0;
break;
default:
throw new ReaderException("Invalid shift value");
}
}
} while (bits.available() > 0);
return ASCII_ENCODE;
}
/**
* See ISO 16022:2006, 5.2.7
*/
private static int decodeAnsiX12Segment(BitSource bits,
StringBuffer result) throws ReaderException {
private static void decodeAnsiX12Segment(BitSource bits, StringBuffer result) throws ReaderException {
// Three ANSI X12 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
int[] cValues = new int[3];
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return ASCII_ENCODE;
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return ASCII_ENCODE;
return;
}
int fullBitValue = (firstByte << 8) + bits.readBits(8) - 1;
int[] cValues = new int[3];
cValues[0] = fullBitValue / 1600;
fullBitValue -= cValues[0] * 1600;
cValues[1] = fullBitValue / 40;
fullBitValue -= cValues[1] * 40;
cValues[2] = fullBitValue;
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++) {
// TODO(bbrown): These really aren't X12 symbols, we are converting to ASCII chars
int cValue = cValues[i];
if (cValue == 0) { // X12 segment terminator <CR>
result.append("<CR>");
result.append('\r');
} else if (cValue == 1) { // X12 segment separator *
result.append('*');
} else if (cValue == 2) { // X12 sub-element separator >
@ -382,23 +355,31 @@ final class DecodedBitStreamParser {
} else if (cValue < 40) { // A - Z
result.append((char) (cValue + 51));
} else {
throw new ReaderException(Integer.toString(cValue) + " is not valid in the ANSI X12 set");
throw new ReaderException(cValue + " is not valid in the ANSI X12 set");
}
}
} while (bits.available() > 0);
return ASCII_ENCODE;
}
private static void parseTwoBytes(int firstByte, int secondByte, int[] result) {
int fullBitValue = (firstByte << 8) + secondByte - 1;
int temp = fullBitValue / 1600;
result[0] = temp;
fullBitValue -= temp * 1600;
temp = fullBitValue / 40;
result[1] = temp;
result[2] = fullBitValue - temp * 40;
}
/**
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
*/
private static int decodeEdifactSegment(BitSource bits, StringBuffer result) {
private static void decodeEdifactSegment(BitSource bits, StringBuffer result) {
boolean unlatch = false;
do {
// If there is only two or less bytes left then it will be encoded as ASCII
if (bits.available() <= 16) {
return ASCII_ENCODE;
return;
}
for (int i = 0; i < 4; i++) {
@ -419,14 +400,12 @@ final class DecodedBitStreamParser {
}
}
} while (!unlatch && bits.available() > 0);
return ASCII_ENCODE;
}
/**
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/
private static int decodeBase256Segment(BitSource bits, StringBuffer result) {
private static void decodeBase256Segment(BitSource bits, StringBuffer result) {
// Figure out how long the Base 256 Segment is.
int d1 = bits.readBits(8);
int count;
@ -440,8 +419,6 @@ final class DecodedBitStreamParser {
for (int i = 0; i < count; i++) {
result.append(unrandomize255State(bits.readBits(8), count));
}
return ASCII_ENCODE;
}
/**