2 * Copyright 2007 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.qrcode.decoder;
19 import com.google.zxing.ReaderException;
21 import java.io.UnsupportedEncodingException;
24 * See ISO 18004:2006, 6.4.3 - 6.4.7
26 * @author srowen@google.com (Sean Owen)
28 final class DecodedBitStreamParser {
31 * See ISO 18004:2006, 6.4.4 Table 5
33 private static final char[] ALPHANUMERIC_CHARS = new char[]{
34 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
35 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
36 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
37 ' ', '$', '%', '*', '+', '-', '.', '/', ':'
39 private static final String SHIFT_JIS = "Shift_JIS";
40 private static final boolean ASSUME_SHIFT_JIS;
43 String platformDefault = System.getProperty("file.encoding");
44 ASSUME_SHIFT_JIS = SHIFT_JIS.equalsIgnoreCase(platformDefault) ||
45 "EUC-JP".equalsIgnoreCase(platformDefault);
48 private DecodedBitStreamParser() {
51 static String decode(byte[] bytes, Version version) throws ReaderException {
52 BitSource bits = new BitSource(bytes);
53 StringBuffer result = new StringBuffer();
56 // While still another segment to read...
57 mode = Mode.forBits(bits.readBits(4));
58 if (!mode.equals(Mode.TERMINATOR)) {
59 int count = bits.readBits(mode.getCharacterCountBits(version));
60 if (mode.equals(Mode.NUMERIC)) {
61 decodeNumericSegment(bits, result, count);
62 } else if (mode.equals(Mode.ALPHANUMERIC)) {
63 decodeAlphanumericSegment(bits, result, count);
64 } else if (mode.equals(Mode.BYTE)) {
65 decodeByteSegment(bits, result, count);
66 } else if (mode.equals(Mode.KANJI)) {
67 decodeKanjiSegment(bits, result, count);
69 throw new ReaderException("Unsupported mode indicator: " + mode);
72 } while (!mode.equals(Mode.TERMINATOR));
75 int bitsLeft = bits.available();
77 if (bitsLeft > 6 || bits.readBits(bitsLeft) != 0) {
78 throw new ReaderException("Excess bits or non-zero bits after terminator mode indicator");
82 return result.toString();
85 private static void decodeKanjiSegment(BitSource bits,
87 int count) throws ReaderException {
88 byte[] buffer = new byte[2 * count];
91 int twoBytes = bits.readBits(13);
92 int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
93 if (assembledTwoBytes < 0x01F00) {
94 // In the 0x8140 to 0x9FFC range
95 assembledTwoBytes += 0x08140;
97 // In the 0xE040 to 0xEBBF range
98 assembledTwoBytes += 0x0C140;
100 buffer[offset] = (byte) (assembledTwoBytes >> 8);
101 buffer[offset + 1] = (byte) assembledTwoBytes;
105 // Shift_JIS may not be supported in some environments:
107 result.append(new String(buffer, "Shift_JIS"));
108 } catch (UnsupportedEncodingException uee) {
109 throw new ReaderException("Can't decode SHIFT_JIS string: " + uee);
113 private static void decodeByteSegment(BitSource bits,
115 int count) throws ReaderException {
116 byte[] readBytes = new byte[count];
117 if (count << 3 > bits.available()) {
118 throw new ReaderException("Count too large: " + count);
120 for (int i = 0; i < count; i++) {
121 readBytes[i] = (byte) bits.readBits(8);
123 // The spec isn't clear on this mode; see
124 // section 6.4.5: t does not say which encoding to assuming
125 // upon decoding. I have seen ISO-8859-1 used as well as
126 // Shift_JIS -- without anything like an ECI designator to
128 String encoding = guessEncoding(readBytes);
130 result.append(new String(readBytes, encoding));
131 } catch (UnsupportedEncodingException uce) {
132 throw new ReaderException(uce.toString());
136 private static void decodeAlphanumericSegment(BitSource bits,
139 // Read two characters at a time
141 int nextTwoCharsBits = bits.readBits(11);
142 result.append(ALPHANUMERIC_CHARS[nextTwoCharsBits / 45]);
143 result.append(ALPHANUMERIC_CHARS[nextTwoCharsBits % 45]);
147 // special case on char left
148 result.append(ALPHANUMERIC_CHARS[bits.readBits(6)]);
152 private static void decodeNumericSegment(BitSource bits,
154 int count) throws ReaderException {
156 int threeDigitsBits = bits.readBits(10);
157 if (threeDigitsBits >= 1000) {
158 throw new ReaderException("Illegal value for 3-digit unit: " + threeDigitsBits);
160 result.append(ALPHANUMERIC_CHARS[threeDigitsBits / 100]);
161 result.append(ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]);
162 result.append(ALPHANUMERIC_CHARS[threeDigitsBits % 10]);
166 int twoDigitsBits = bits.readBits(7);
167 if (twoDigitsBits >= 100) {
168 throw new ReaderException("Illegal value for 2-digit unit: " + twoDigitsBits);
170 result.append(ALPHANUMERIC_CHARS[twoDigitsBits / 10]);
171 result.append(ALPHANUMERIC_CHARS[twoDigitsBits % 10]);
172 } else if (count == 1) {
173 int digitBits = bits.readBits(4);
174 if (digitBits >= 10) {
175 throw new ReaderException("Illegal value for digit unit: " + digitBits);
177 result.append(ALPHANUMERIC_CHARS[digitBits]);
181 private static String guessEncoding(byte[] bytes) {
182 if (ASSUME_SHIFT_JIS) {
185 // For now, merely tries to distinguish ISO-8859-1 and Shift_JIS,
186 // which should be by far the most common encodings. ISO-8859-1
187 // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
188 // uses this as a first byte of a two-byte character. If we see this
189 // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
190 int length = bytes.length;
191 for (int i = 0; i < length; i++) {
192 int value = bytes[i] & 0xFF;
193 if (value >= 0x80 && value <= 0x9F && i < length - 1) {
194 // ISO-8859-1 shouldn't use this, but before we decide it is Shift_JIS,
195 // just double check that it is followed by a byte that's valid in
196 // the Shift_JIS encoding
197 int nextValue = bytes[i + 1] & 0xFF;
198 if ((value & 0x1) == 0) {
200 if (nextValue >= 0x40 && nextValue <= 0x9E) {
204 if (nextValue >= 0x9F && nextValue <= 0x7C) {