DecodedBitStreamParser.java (zxing-zxing-3.4.1) | : | DecodedBitStreamParser.java (zxing-zxing-3.5.0) | ||
---|---|---|---|---|
skipping to change at line 26 | skipping to change at line 26 | |||
package com.google.zxing.qrcode.decoder; | package com.google.zxing.qrcode.decoder; | |||
import com.google.zxing.DecodeHintType; | import com.google.zxing.DecodeHintType; | |||
import com.google.zxing.FormatException; | import com.google.zxing.FormatException; | |||
import com.google.zxing.common.BitSource; | import com.google.zxing.common.BitSource; | |||
import com.google.zxing.common.CharacterSetECI; | import com.google.zxing.common.CharacterSetECI; | |||
import com.google.zxing.common.DecoderResult; | import com.google.zxing.common.DecoderResult; | |||
import com.google.zxing.common.StringUtils; | import com.google.zxing.common.StringUtils; | |||
import java.io.UnsupportedEncodingException; | import java.nio.charset.Charset; | |||
import java.util.ArrayList; | import java.util.ArrayList; | |||
import java.util.Collection; | import java.util.Collection; | |||
import java.util.List; | import java.util.List; | |||
import java.util.Map; | import java.util.Map; | |||
/** | /** | |||
* <p>QR Codes can encode text as bits in one of several modes, and can use mult iple modes | * <p>QR Codes can encode text as bits in one of several modes, and can use mult iple modes | |||
* in one QR Code. This class decodes the bits back into text.</p> | * in one QR Code. This class decodes the bits back into text.</p> | |||
* | * | |||
* <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p> | * <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p> | |||
skipping to change at line 61 | skipping to change at line 61 | |||
static DecoderResult decode(byte[] bytes, | static DecoderResult decode(byte[] bytes, | |||
Version version, | Version version, | |||
ErrorCorrectionLevel ecLevel, | ErrorCorrectionLevel ecLevel, | |||
Map<DecodeHintType,?> hints) throws FormatExceptio n { | Map<DecodeHintType,?> hints) throws FormatExceptio n { | |||
BitSource bits = new BitSource(bytes); | BitSource bits = new BitSource(bytes); | |||
StringBuilder result = new StringBuilder(50); | StringBuilder result = new StringBuilder(50); | |||
List<byte[]> byteSegments = new ArrayList<>(1); | List<byte[]> byteSegments = new ArrayList<>(1); | |||
int symbolSequence = -1; | int symbolSequence = -1; | |||
int parityData = -1; | int parityData = -1; | |||
int symbologyModifier; | ||||
try { | try { | |||
CharacterSetECI currentCharacterSetECI = null; | CharacterSetECI currentCharacterSetECI = null; | |||
boolean fc1InEffect = false; | boolean fc1InEffect = false; | |||
boolean hasFNC1first = false; | ||||
boolean hasFNC1second = false; | ||||
Mode mode; | Mode mode; | |||
do { | do { | |||
// While still another segment to read... | // While still another segment to read... | |||
if (bits.available() < 4) { | if (bits.available() < 4) { | |||
// OK, assume we're done. Really, a TERMINATOR mode should have been r ecorded here | // OK, assume we're done. Really, a TERMINATOR mode should have been r ecorded here | |||
mode = Mode.TERMINATOR; | mode = Mode.TERMINATOR; | |||
} else { | } else { | |||
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits | mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits | |||
} | } | |||
switch (mode) { | switch (mode) { | |||
case TERMINATOR: | case TERMINATOR: | |||
break; | break; | |||
case FNC1_FIRST_POSITION: | case FNC1_FIRST_POSITION: | |||
hasFNC1first = true; // symbology detection | ||||
// We do little with FNC1 except alter the parsed result a bit accor | ||||
ding to the spec | ||||
fc1InEffect = true; | ||||
break; | ||||
case FNC1_SECOND_POSITION: | case FNC1_SECOND_POSITION: | |||
hasFNC1second = true; // symbology detection | ||||
// We do little with FNC1 except alter the parsed result a bit accor ding to the spec | // We do little with FNC1 except alter the parsed result a bit accor ding to the spec | |||
fc1InEffect = true; | fc1InEffect = true; | |||
break; | break; | |||
case STRUCTURED_APPEND: | case STRUCTURED_APPEND: | |||
if (bits.available() < 16) { | if (bits.available() < 16) { | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
// sequence number and parity is added later to the result metadata | // sequence number and parity is added later to the result metadata | |||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), th en continue | // Read next 8 bits (symbol sequence #) and 8 bits (parity data), th en continue | |||
symbolSequence = bits.readBits(8); | symbolSequence = bits.readBits(8); | |||
skipping to change at line 131 | skipping to change at line 139 | |||
break; | break; | |||
case KANJI: | case KANJI: | |||
decodeKanjiSegment(bits, result, count); | decodeKanjiSegment(bits, result, count); | |||
break; | break; | |||
default: | default: | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
break; | break; | |||
} | } | |||
} while (mode != Mode.TERMINATOR); | } while (mode != Mode.TERMINATOR); | |||
if (currentCharacterSetECI != null) { | ||||
if (hasFNC1first) { | ||||
symbologyModifier = 4; | ||||
} else if (hasFNC1second) { | ||||
symbologyModifier = 6; | ||||
} else { | ||||
symbologyModifier = 2; | ||||
} | ||||
} else { | ||||
if (hasFNC1first) { | ||||
symbologyModifier = 3; | ||||
} else if (hasFNC1second) { | ||||
symbologyModifier = 5; | ||||
} else { | ||||
symbologyModifier = 1; | ||||
} | ||||
} | ||||
} catch (IllegalArgumentException iae) { | } catch (IllegalArgumentException iae) { | |||
// from readBits() calls | // from readBits() calls | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
return new DecoderResult(bytes, | return new DecoderResult(bytes, | |||
result.toString(), | result.toString(), | |||
byteSegments.isEmpty() ? null : byteSegments, | byteSegments.isEmpty() ? null : byteSegments, | |||
ecLevel == null ? null : ecLevel.toString(), | ecLevel == null ? null : ecLevel.toString(), | |||
symbolSequence, | symbolSequence, | |||
parityData); | parityData, | |||
symbologyModifier); | ||||
} | } | |||
/** | /** | |||
* See specification GBT 18284-2000 | * See specification GBT 18284-2000 | |||
*/ | */ | |||
private static void decodeHanziSegment(BitSource bits, | private static void decodeHanziSegment(BitSource bits, | |||
StringBuilder result, | StringBuilder result, | |||
int count) throws FormatException { | int count) throws FormatException { | |||
// Don't crash trying to read more bits than we have available. | // Don't crash trying to read more bits than we have available. | |||
if (count * 13 > bits.available()) { | if (count * 13 > bits.available()) { | |||
skipping to change at line 176 | skipping to change at line 204 | |||
} else { | } else { | |||
// In the 0xB0A1 to 0xFAFE range | // In the 0xB0A1 to 0xFAFE range | |||
assembledTwoBytes += 0x0A6A1; | assembledTwoBytes += 0x0A6A1; | |||
} | } | |||
buffer[offset] = (byte) ((assembledTwoBytes >> 8) & 0xFF); | buffer[offset] = (byte) ((assembledTwoBytes >> 8) & 0xFF); | |||
buffer[offset + 1] = (byte) (assembledTwoBytes & 0xFF); | buffer[offset + 1] = (byte) (assembledTwoBytes & 0xFF); | |||
offset += 2; | offset += 2; | |||
count--; | count--; | |||
} | } | |||
try { | result.append(new String(buffer, StringUtils.GB2312_CHARSET)); | |||
result.append(new String(buffer, StringUtils.GB2312)); | ||||
} catch (UnsupportedEncodingException ignored) { | ||||
throw FormatException.getFormatInstance(); | ||||
} | ||||
} | } | |||
private static void decodeKanjiSegment(BitSource bits, | private static void decodeKanjiSegment(BitSource bits, | |||
StringBuilder result, | StringBuilder result, | |||
int count) throws FormatException { | int count) throws FormatException { | |||
// Don't crash trying to read more bits than we have available. | // Don't crash trying to read more bits than we have available. | |||
if (count * 13 > bits.available()) { | if (count * 13 > bits.available()) { | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
skipping to change at line 211 | skipping to change at line 235 | |||
assembledTwoBytes += 0x08140; | assembledTwoBytes += 0x08140; | |||
} else { | } else { | |||
// In the 0xE040 to 0xEBBF range | // In the 0xE040 to 0xEBBF range | |||
assembledTwoBytes += 0x0C140; | assembledTwoBytes += 0x0C140; | |||
} | } | |||
buffer[offset] = (byte) (assembledTwoBytes >> 8); | buffer[offset] = (byte) (assembledTwoBytes >> 8); | |||
buffer[offset + 1] = (byte) assembledTwoBytes; | buffer[offset + 1] = (byte) assembledTwoBytes; | |||
offset += 2; | offset += 2; | |||
count--; | count--; | |||
} | } | |||
// Shift_JIS may not be supported in some environments: | result.append(new String(buffer, StringUtils.SHIFT_JIS_CHARSET)); | |||
try { | ||||
result.append(new String(buffer, StringUtils.SHIFT_JIS)); | ||||
} catch (UnsupportedEncodingException ignored) { | ||||
throw FormatException.getFormatInstance(); | ||||
} | ||||
} | } | |||
private static void decodeByteSegment(BitSource bits, | private static void decodeByteSegment(BitSource bits, | |||
StringBuilder result, | StringBuilder result, | |||
int count, | int count, | |||
CharacterSetECI currentCharacterSetECI, | CharacterSetECI currentCharacterSetECI, | |||
Collection<byte[]> byteSegments, | Collection<byte[]> byteSegments, | |||
Map<DecodeHintType,?> hints) throws Form atException { | Map<DecodeHintType,?> hints) throws Form atException { | |||
// Don't crash trying to read more bits than we have available. | // Don't crash trying to read more bits than we have available. | |||
if (8 * count > bits.available()) { | if (8 * count > bits.available()) { | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
byte[] readBytes = new byte[count]; | byte[] readBytes = new byte[count]; | |||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | |||
readBytes[i] = (byte) bits.readBits(8); | readBytes[i] = (byte) bits.readBits(8); | |||
} | } | |||
String encoding; | Charset encoding; | |||
if (currentCharacterSetECI == null) { | if (currentCharacterSetECI == null) { | |||
// The spec isn't clear on this mode; see | // The spec isn't clear on this mode; see | |||
// section 6.4.5: t does not say which encoding to assuming | // section 6.4.5: t does not say which encoding to assuming | |||
// upon decoding. I have seen ISO-8859-1 used as well as | // upon decoding. I have seen ISO-8859-1 used as well as | |||
// Shift_JIS -- without anything like an ECI designator to | // Shift_JIS -- without anything like an ECI designator to | |||
// give a hint. | // give a hint. | |||
encoding = StringUtils.guessEncoding(readBytes, hints); | encoding = StringUtils.guessCharset(readBytes, hints); | |||
} else { | } else { | |||
encoding = currentCharacterSetECI.name(); | encoding = currentCharacterSetECI.getCharset(); | |||
} | ||||
try { | ||||
result.append(new String(readBytes, encoding)); | ||||
} catch (UnsupportedEncodingException ignored) { | ||||
throw FormatException.getFormatInstance(); | ||||
} | } | |||
result.append(new String(readBytes, encoding)); | ||||
byteSegments.add(readBytes); | byteSegments.add(readBytes); | |||
} | } | |||
private static char toAlphaNumericChar(int value) throws FormatException { | private static char toAlphaNumericChar(int value) throws FormatException { | |||
if (value >= ALPHANUMERIC_CHARS.length) { | if (value >= ALPHANUMERIC_CHARS.length) { | |||
throw FormatException.getFormatInstance(); | throw FormatException.getFormatInstance(); | |||
} | } | |||
return ALPHANUMERIC_CHARS[value]; | return ALPHANUMERIC_CHARS[value]; | |||
} | } | |||
End of changes. 13 change blocks. | ||||
21 lines changed or deleted | 37 lines changed or added |