Issue 361
[zxing.git] / core / test / src / com / google / zxing / qrcode / encoder / EncoderTestCase.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.google.zxing.qrcode.encoder;
18
19 import com.google.zxing.WriterException;
20 import com.google.zxing.common.BitArray;
21 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
22 import com.google.zxing.qrcode.decoder.Mode;
23 import junit.framework.TestCase;
24
25 import java.io.UnsupportedEncodingException;
26
27 /**
28  * @author satorux@google.com (Satoru Takabayashi) - creator
29  * @author mysen@google.com (Chris Mysen) - ported from C++
30  */
31 public final class EncoderTestCase extends TestCase {
32
33   public void testGetAlphanumericCode() {
34     // The first ten code points are numbers.
35     for (int i = 0; i < 10; ++i) {
36       assertEquals(i, Encoder.getAlphanumericCode('0' + i));
37     }
38
39     // The next 26 code points are capital alphabet letters.
40     for (int i = 10; i < 36; ++i) {
41       assertEquals(i, Encoder.getAlphanumericCode('A' + i - 10));
42     }
43
44     // Others are symbol letters
45     assertEquals(36, Encoder.getAlphanumericCode(' '));
46     assertEquals(37, Encoder.getAlphanumericCode('$'));
47     assertEquals(38, Encoder.getAlphanumericCode('%'));
48     assertEquals(39, Encoder.getAlphanumericCode('*'));
49     assertEquals(40, Encoder.getAlphanumericCode('+'));
50     assertEquals(41, Encoder.getAlphanumericCode('-'));
51     assertEquals(42, Encoder.getAlphanumericCode('.'));
52     assertEquals(43, Encoder.getAlphanumericCode('/'));
53     assertEquals(44, Encoder.getAlphanumericCode(':'));
54
55     // Should return -1 for other letters;
56     assertEquals(-1, Encoder.getAlphanumericCode('a'));
57     assertEquals(-1, Encoder.getAlphanumericCode('#'));
58     assertEquals(-1, Encoder.getAlphanumericCode('\0'));
59   }
60
61   public void testChooseMode() throws WriterException {
62     // Numeric mode.
63     assertSame(Mode.NUMERIC, Encoder.chooseMode("0"));
64     assertSame(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
65     // Alphanumeric mode.
66     assertSame(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
67     assertSame(Mode.ALPHANUMERIC,
68                Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
69     // 8-bit byte mode.
70     assertSame(Mode.BYTE, Encoder.chooseMode("a"));
71     assertSame(Mode.BYTE, Encoder.chooseMode("#"));
72     assertSame(Mode.BYTE, Encoder.chooseMode(""));
73     // Kanji mode.  We used to use MODE_KANJI for these, but we stopped
74     // doing that as we cannot distinguish Shift_JIS from other encodings
75     // from data bytes alone.  See also comments in qrcode_encoder.h.
76
77     // AIUE in Hiragana in Shift_JIS
78     assertSame(Mode.BYTE,
79                Encoder.chooseMode(shiftJISString(new byte[]{0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, (byte) 0xa6})));
80
81     // Nihon in Kanji in Shift_JIS.
82     assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[]{0x9, 0xf, 0x9, 0x7b})));
83
84     // Sou-Utsu-Byou in Kanji in Shift_JIS.
85     assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[]{0xe, 0x4, 0x9, 0x5, 0x9, 0x61})));
86   }
87
88   public void testEncode() throws WriterException {
89     QRCode qrCode = new QRCode();
90     Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, qrCode);
91     // The following is a valid QR Code that can be read by cell phones.
92     String expected =
93       "<<\n" +
94       " mode: ALPHANUMERIC\n" +
95       " ecLevel: H\n" +
96       " version: 1\n" +
97       " matrixWidth: 21\n" +
98       " maskPattern: 0\n" +
99       " numTotalBytes: 26\n" +
100       " numDataBytes: 9\n" +
101       " numECBytes: 17\n" +
102       " numRSBlocks: 1\n" +
103       " matrix:\n" +
104       " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
105       " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" +
106       " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" +
107       " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" +
108       " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" +
109       " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" +
110       " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
111       " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" +
112       " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" +
113       " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" +
114       " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" +
115       " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" +
116       " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" +
117       " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" +
118       " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" +
119       " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" +
120       " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" +
121       " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" +
122       " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" +
123       " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" +
124       " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" +
125       ">>\n";
126     assertEquals(expected, qrCode.toString());
127   }
128
129   public void testAppendModeInfo() {
130     BitArray bits = new BitArray();
131     Encoder.appendModeInfo(Mode.NUMERIC, bits);
132     assertEquals(" ...X", bits.toString());
133   }
134
135   public void testAppendLengthInfo() throws WriterException {
136     {
137       BitArray bits = new BitArray();
138       Encoder.appendLengthInfo(1,  // 1 letter (1/1).
139                                                   1,  // version 1.
140                                                   Mode.NUMERIC,
141                                                   bits);
142       assertEquals(" ........ .X", bits.toString());  // 10 bits.
143     }
144     {
145       BitArray bits = new BitArray();
146       Encoder.appendLengthInfo(2,  // 2 letters (2/1).
147                                                   10,  // version 10.
148                                                   Mode.ALPHANUMERIC,
149                                                   bits);
150       assertEquals(" ........ .X.", bits.toString());  // 11 bits.
151     }
152     {
153       BitArray bits = new BitArray();
154       Encoder.appendLengthInfo(255,  // 255 letter (255/1).
155                                                   27,  // version 27.
156                                                   Mode.BYTE,
157                                                   bits);
158       assertEquals(" ........ XXXXXXXX", bits.toString());  // 16 bits.
159     }
160     {
161       BitArray bits = new BitArray();
162       Encoder.appendLengthInfo(512,  // 512 letters (1024/2).
163                                                   40,  // version 40.
164                                                   Mode.KANJI,
165                                                   bits);
166       assertEquals(" ..X..... ....", bits.toString());  // 12 bits.
167     }
168   }
169
170   public void testAppendBytes() throws WriterException {
171     {
172       // Should use appendNumericBytes.
173       // 1 = 01 = 0001 in 4 bits.
174       BitArray bits = new BitArray();
175       Encoder.appendBytes("1", Mode.NUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
176       assertEquals(" ...X" , bits.toString());
177     }
178     {
179       // Should use appendAlphanumericBytes.
180       // A = 10 = 0xa = 001010 in 6 bits
181       BitArray bits = new BitArray();
182       Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
183       assertEquals(" ..X.X." , bits.toString());
184       // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
185       try {
186         Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
187       } catch (WriterException we) {
188         // good
189       }
190     }
191     {
192       // Should use append8BitBytes.
193       // 0x61, 0x62, 0x63
194       BitArray bits = new BitArray();
195       Encoder.appendBytes("abc", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
196       assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
197       // Anything can be encoded in QRCode.MODE_8BIT_BYTE.
198       Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
199     }
200     {
201       // Should use appendKanjiBytes.
202       // 0x93, 0x5f
203       BitArray bits = new BitArray();
204       Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
205       assertEquals(" .XX.XX.. XXXXX", bits.toString());
206     }
207   }
208
209   public void testTerminateBits() throws WriterException {
210     {
211       BitArray v = new BitArray();
212       Encoder.terminateBits(0, v);
213       assertEquals("", v.toString());
214     }
215     {
216       BitArray v = new BitArray();
217       Encoder.terminateBits(1, v);
218       assertEquals(" ........", v.toString());
219     }
220     {
221       BitArray v = new BitArray();
222       v.appendBits(0, 3);  // Append 000
223       Encoder.terminateBits(1, v);
224       assertEquals(" ........", v.toString());
225     }
226     {
227       BitArray v = new BitArray();
228       v.appendBits(0, 5);  // Append 00000
229       Encoder.terminateBits(1, v);
230       assertEquals(" ........", v.toString());
231     }
232     {
233       BitArray v = new BitArray();
234       v.appendBits(0, 8);  // Append 00000000
235       Encoder.terminateBits(1, v);
236       assertEquals(" ........", v.toString());
237     }
238     {
239       BitArray v = new BitArray();
240       Encoder.terminateBits(2, v);
241       assertEquals(" ........ XXX.XX..", v.toString());
242     }
243     {
244       BitArray v = new BitArray();
245       v.appendBits(0, 1);  // Append 0
246       Encoder.terminateBits(3, v);
247       assertEquals(" ........ XXX.XX.. ...X...X", v.toString());
248     }
249   }
250
251   public void testGetNumDataBytesAndNumECBytesForBlockID() throws WriterException {
252     int[] numDataBytes = new int[1];
253     int[] numEcBytes = new int[1];
254     // Version 1-H.
255     Encoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
256     assertEquals(9, numDataBytes[0]);
257     assertEquals(17, numEcBytes[0]);
258
259     // Version 3-H.  2 blocks.
260     Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
261     assertEquals(13, numDataBytes[0]);
262     assertEquals(22, numEcBytes[0]);
263     Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
264     assertEquals(13, numDataBytes[0]);
265     assertEquals(22, numEcBytes[0]);
266
267     // Version 7-H. (4 + 1) blocks.
268     Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
269     assertEquals(13, numDataBytes[0]);
270     assertEquals(26, numEcBytes[0]);
271     Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
272     assertEquals(14, numDataBytes[0]);
273     assertEquals(26, numEcBytes[0]);
274
275     // Version 40-H. (20 + 61) blocks.
276     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
277     assertEquals(15, numDataBytes[0]);
278     assertEquals(30, numEcBytes[0]);
279     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
280     assertEquals(16, numDataBytes[0]);
281     assertEquals(30, numEcBytes[0]);
282     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
283     assertEquals(16, numDataBytes[0]);
284     assertEquals(30, numEcBytes[0]);
285   }
286
287   public void testInterleaveWithECBytes() throws WriterException {
288     {
289       byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
290       BitArray in = new BitArray();
291       for (byte dataByte: dataBytes) {
292         in.appendBits(dataByte, 8);
293       }
294       BitArray out = new BitArray();
295       Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
296       byte[] expected = {
297           // Data bytes.
298           32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
299           // Error correction bytes.
300           42, (byte)159, 74, (byte)221, (byte)244, (byte)169, (byte)239, (byte)150, (byte)138, 70,
301           (byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
302       };
303       assertEquals(expected.length, out.getSizeInBytes());
304       byte[] outArray = new byte[expected.length];
305       out.toBytes(0, outArray, 0, expected.length);
306       // Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
307       for (int x = 0; x < expected.length; x++) {
308         assertEquals(expected[x], outArray[x]);
309       }
310     }
311     // Numbers are from http://www.swetake.com/qr/qr8.html
312     {
313       byte[] dataBytes = {
314           67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182,
315           (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119, (byte)135,
316           (byte)151, (byte)166, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166,
317           (byte)182, (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119,
318           (byte)135, (byte)151, (byte)160, (byte)236, 17, (byte)236, 17, (byte)236, 17, (byte)236,
319           17
320       };
321       BitArray in = new BitArray();
322       for (byte dataByte: dataBytes) {
323         in.appendBits(dataByte, 8);
324       }
325       BitArray out = new BitArray();
326       Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
327       byte[] expected = {
328           // Data bytes.
329           67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
330           118, 119, 70, 55, (byte)134, (byte)135, 86, 71, (byte)150, (byte)151, 102, 87, (byte)166,
331           (byte)160, 118, 103, (byte)182, (byte)236, (byte)134, 119, (byte)198, 17, (byte)150,
332           (byte)135, (byte)214, (byte)236, (byte)166, (byte)151, (byte)230, 17, (byte)182,
333           (byte)166, (byte)247, (byte)236, (byte)198, 22, 7, 17, (byte)214, 38, 23, (byte)236, 39,
334           17,
335           // Error correction bytes.
336           (byte)175, (byte)155, (byte)245, (byte)236, 80, (byte)146, 56, 74, (byte)155, (byte)165,
337           (byte)133, (byte)142, 64, (byte)183, (byte)132, 13, (byte)178, 54, (byte)132, 108, 45,
338           113, 53, 50, (byte)214, 98, (byte)193, (byte)152, (byte)233, (byte)147, 50, 71, 65,
339           (byte)190, 82, 51, (byte)209, (byte)199, (byte)171, 54, 12, 112, 57, 113, (byte)155, 117,
340           (byte)211, (byte)164, 117, 30, (byte)158, (byte)225, 31, (byte)190, (byte)242, 38,
341           (byte)140, 61, (byte)179, (byte)154, (byte)214, (byte)138, (byte)147, 87, 27, 96, 77, 47,
342           (byte)187, 49, (byte)156, (byte)214,
343       };
344       assertEquals(expected.length, out.getSizeInBytes());
345       byte[] outArray = new byte[expected.length];
346       out.toBytes(0, outArray, 0, expected.length);
347       for (int x = 0; x < expected.length; x++) {
348         assertEquals(expected[x], outArray[x]);
349       }
350     }
351   }
352
353   public void testAppendNumericBytes() {
354     {
355       // 1 = 01 = 0001 in 4 bits.
356       BitArray bits = new BitArray();
357       Encoder.appendNumericBytes("1", bits);
358       assertEquals(" ...X" , bits.toString());
359     }
360     {
361       // 12 = 0xc = 0001100 in 7 bits.
362       BitArray bits = new BitArray();
363       Encoder.appendNumericBytes("12", bits);
364       assertEquals(" ...XX.." , bits.toString());
365     }
366     {
367       // 123 = 0x7b = 0001111011 in 10 bits.
368       BitArray bits = new BitArray();
369       Encoder.appendNumericBytes("123", bits);
370       assertEquals(" ...XXXX. XX" , bits.toString());
371     }
372     {
373       // 1234 = "123" + "4" = 0001111011 + 0100
374       BitArray bits = new BitArray();
375       Encoder.appendNumericBytes("1234", bits);
376       assertEquals(" ...XXXX. XX.X.." , bits.toString());
377     }
378     {
379       // Empty.
380       BitArray bits = new BitArray();
381       Encoder.appendNumericBytes("", bits);
382       assertEquals("" , bits.toString());
383     }
384   }
385
386   public void testAppendAlphanumericBytes() throws WriterException {
387     {
388       // A = 10 = 0xa = 001010 in 6 bits
389       BitArray bits = new BitArray();
390       Encoder.appendAlphanumericBytes("A", bits);
391       assertEquals(" ..X.X." , bits.toString());
392     }
393     {
394       // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
395       BitArray bits = new BitArray();
396       Encoder.appendAlphanumericBytes("AB", bits);
397       assertEquals(" ..XXX..X X.X", bits.toString());
398     }
399     {
400       // ABC = "AB" + "C" = 00111001101 + 001100
401       BitArray bits = new BitArray();
402       Encoder.appendAlphanumericBytes("ABC", bits);
403       assertEquals(" ..XXX..X X.X..XX. ." , bits.toString());
404     }
405     {
406       // Empty.
407       BitArray bits = new BitArray();
408       Encoder.appendAlphanumericBytes("", bits);
409       assertEquals("" , bits.toString());
410     }
411     {
412       // Invalid data.
413       BitArray bits = new BitArray();
414       try {
415         Encoder.appendAlphanumericBytes("abc", bits);
416       } catch (WriterException we) {
417         // good
418       }
419     }
420   }
421
422   public void testAppend8BitBytes() throws WriterException {
423     {
424       // 0x61, 0x62, 0x63
425       BitArray bits = new BitArray();
426       Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
427       assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
428     }
429     {
430       // Empty.
431       BitArray bits = new BitArray();
432       Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
433       assertEquals("", bits.toString());
434     }
435   }
436
437   // Numbers are from page 21 of JISX0510:2004
438   public void testAppendKanjiBytes() throws WriterException {
439     BitArray bits = new BitArray();
440       Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), bits);
441       assertEquals(" .XX.XX.. XXXXX", bits.toString());
442       Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0xe4,(byte)0xaa}), bits);
443       assertEquals(" .XX.XX.. XXXXXXX. X.X.X.X. X.", bits.toString());
444   }
445
446   // Numbers are from http://www.swetake.com/qr/qr3.html and
447   // http://www.swetake.com/qr/qr9.html
448   public void testGenerateECBytes() {
449     {
450       byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
451       byte[] ecBytes = Encoder.generateECBytes(dataBytes, 17);
452       int[] expected = {
453           42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
454       };
455       assertEquals(expected.length, ecBytes.length);
456       for (int x = 0; x < expected.length; x++) {
457         assertEquals(expected[x], ecBytes[x] & 0xFF);
458       }
459     }
460     {
461       byte[] dataBytes = {67, 70, 22, 38, 54, 70, 86, 102, 118,
462           (byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214};
463       byte[] ecBytes = Encoder.generateECBytes(dataBytes, 18);
464       int[] expected = {
465           175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
466       };
467       assertEquals(expected.length, ecBytes.length);
468       for (int x = 0; x < expected.length; x++) {
469         assertEquals(expected[x], ecBytes[x] & 0xFF);
470       }
471     }
472     {
473       // High-order zero coefficient case.
474       byte[] dataBytes = {32, 49, (byte)205, 69, 42, 20, 0, (byte)236, 17};
475       byte[] ecBytes = Encoder.generateECBytes(dataBytes, 17);
476       int[] expected = {
477           0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
478       };
479       assertEquals(expected.length, ecBytes.length);
480       for (int x = 0; x < expected.length; x++) {
481         assertEquals(expected[x], ecBytes[x] & 0xFF);
482       }
483     }
484   }
485
486   public void testBugInBitVectorNumBytes() throws WriterException {
487     // There was a bug in BitVector.sizeInBytes() that caused it to return a
488     // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
489     // in the vector is not 8-bit aligned.  In QRCodeEncoder::InitQRCode(),
490     // BitVector::sizeInBytes() is used for finding the smallest QR Code
491     // version that can fit the given data.  Hence there were corner cases
492     // where we chose a wrong QR Code version that cannot fit the given
493     // data.  Note that the issue did not occur with MODE_8BIT_BYTE, as the
494     // bits in the bit vector are always 8-bit aligned.
495     //
496     // Before the bug was fixed, the following test didn't pass, because:
497     //
498     // - MODE_NUMERIC is chosen as all bytes in the data are '0'
499     // - The 3518-byte numeric data needs 1466 bytes
500     //   - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
501     //   - 3 numeric bytes are encoded in 10 bits, hence the first
502     //     3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
503     //   - 2 numeric bytes can be encoded in 7 bits, hence the last
504     //     2 bytes are encoded in 7 bits.
505     // - The version 27 QR Code with the EC level L has 1468 bytes for data.
506     //   - 1828 - 360 = 1468
507     // - In InitQRCode(), 3 bytes are reserved for a header.  Hence 1465 bytes
508     //   (1468 -3) are left for data.
509     // - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
510     //   the given data can fit in 1465 bytes, despite it needs 1466 bytes.
511     // - Hence QRCodeEncoder.encode() failed and returned false.
512     //   - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
513     //     11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
514     //     bytes).
515     StringBuilder builder = new StringBuilder(3518);
516     for (int x = 0; x < 3518; x++) {
517       builder.append('0');
518     }
519     QRCode qrCode = new QRCode();
520     Encoder.encode(builder.toString(), ErrorCorrectionLevel.L, qrCode);
521   }
522
523   private static String shiftJISString(byte[] bytes) throws WriterException {
524     try {
525       return new String(bytes, "Shift_JIS");
526     } catch (UnsupportedEncodingException uee) {
527       throw new WriterException(uee.toString());
528     }
529   }
530
531 }