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