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