"Split" ReaderException into subclasses to enable more useful error reporting
[zxing.git] / core / src / com / google / zxing / pdf417 / decoder / DecodedBitStreamParser.java
1 /*\r
2  * Copyright 2009 ZXing authors\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.google.zxing.pdf417.decoder;\r
18 \r
19 import com.google.zxing.FormatException;\r
20 import com.google.zxing.common.DecoderResult;\r
21 \r
22 /**\r
23  * <p>This class contains the methods for decoding the PDF417 codewords.</p>\r
24  *\r
25  * @author SITA Lab (kevin.osullivan@sita.aero)\r
26  */\r
27 final class DecodedBitStreamParser {\r
28 \r
29   private static final int TEXT_COMPACTION_MODE_LATCH = 900;\r
30   private static final int BYTE_COMPACTION_MODE_LATCH = 901;\r
31   private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;\r
32   private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;\r
33   private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;\r
34   private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;\r
35   private static final int MACRO_PDF417_TERMINATOR = 922;\r
36   private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;\r
37   private static final int MAX_NUMERIC_CODEWORDS = 15;\r
38 \r
39   private static final int ALPHA = 0;\r
40   private static final int LOWER = 1;\r
41   private static final int MIXED = 2;\r
42   private static final int PUNCT = 3;\r
43   private static final int PUNCT_SHIFT = 4;\r
44 \r
45   private static final int PL = 25;\r
46   private static final int LL = 27;\r
47   private static final int AS = 27;\r
48   private static final int ML = 28;\r
49   private static final int AL = 28;\r
50   private static final int PS = 29;\r
51   private static final int PAL = 29;\r
52 \r
53   private static final char[] PUNCT_CHARS = {';', '<', '>', '@', '[', 92, '}', '_', 96, '~', '!',\r
54       13, 9, ',', ':', 10, '-', '.', '$', '/', 34, '|', '*',\r
55       '(', ')', '?', '{', '}', 39};\r
56 \r
57   private static final char[] MIXED_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',\r
58       13, 9, ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',\r
59       '=', '^'};\r
60 \r
61   // Table containing values for the exponent of 900.\r
62   // This is used in the numeric compaction decode algorithm.\r
63   private static final String[] EXP900 =\r
64       {   "000000000000000000000000000000000000000000001",\r
65           "000000000000000000000000000000000000000000900",\r
66           "000000000000000000000000000000000000000810000",\r
67           "000000000000000000000000000000000000729000000",\r
68           "000000000000000000000000000000000656100000000",\r
69           "000000000000000000000000000000590490000000000",\r
70           "000000000000000000000000000531441000000000000",\r
71           "000000000000000000000000478296900000000000000",\r
72           "000000000000000000000430467210000000000000000",\r
73           "000000000000000000387420489000000000000000000",\r
74           "000000000000000348678440100000000000000000000",\r
75           "000000000000313810596090000000000000000000000",\r
76           "000000000282429536481000000000000000000000000",\r
77           "000000254186582832900000000000000000000000000",\r
78           "000228767924549610000000000000000000000000000",\r
79           "205891132094649000000000000000000000000000000"};\r
80 \r
81   private DecodedBitStreamParser() {\r
82   }\r
83 \r
84   static DecoderResult decode(int[] codewords) throws FormatException {\r
85     StringBuffer result = new StringBuffer(100);\r
86     // Get compaction mode\r
87     int codeIndex = 1;\r
88     int code = codewords[codeIndex++];\r
89     while (codeIndex < codewords[0]) {\r
90       switch (code) {\r
91         case TEXT_COMPACTION_MODE_LATCH: {\r
92           codeIndex = textCompaction(codewords, codeIndex, result);\r
93           break;\r
94         }\r
95         case BYTE_COMPACTION_MODE_LATCH: {\r
96           codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
97           break;\r
98         }\r
99         case NUMERIC_COMPACTION_MODE_LATCH: {\r
100           codeIndex = numericCompaction(codewords, codeIndex, result);\r
101           break;\r
102         }\r
103         case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
104           codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
105           break;\r
106         }\r
107         case BYTE_COMPACTION_MODE_LATCH_6: {\r
108           codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
109           break;\r
110         }\r
111         default: {\r
112           // Default to text compaction. During testing numerous barcodes\r
113           // appeared to be missing the starting mode. In these cases defaulting\r
114           // to text compaction seems to work.\r
115           codeIndex--;\r
116           codeIndex = textCompaction(codewords, codeIndex, result);\r
117           break;\r
118         }\r
119       }\r
120       if (codeIndex < codewords.length) {\r
121         code = codewords[codeIndex++];\r
122       } else {\r
123         throw FormatException.getFormatInstance();\r
124       }\r
125     }\r
126     return new DecoderResult(null, result.toString(), null, null);\r
127   }\r
128 \r
129   /**\r
130    * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be\r
131    * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as\r
132    * well as selected control characters.\r
133    *\r
134    * @param codewords The array of codewords (data + error)\r
135    * @param codeIndex The current index into the codeword array.\r
136    * @param result    The decoded data is appended to the result.\r
137    * @return The next index into the codeword array.\r
138    */\r
139   private static int textCompaction(int[] codewords, int codeIndex, StringBuffer result) {\r
140     // 2 character per codeword\r
141     int[] textCompactionData = new int[codewords[0] << 1];\r
142     // Used to hold the byte compaction value if there is a mode shift\r
143     int[] byteCompactionData = new int[codewords[0] << 1];\r
144 \r
145     int index = 0;\r
146     boolean end = false;\r
147     while ((codeIndex < codewords[0]) && !end) {\r
148       int code = codewords[codeIndex++];\r
149       if (code < TEXT_COMPACTION_MODE_LATCH) {\r
150         textCompactionData[index] = code / 30;\r
151         textCompactionData[index + 1] = code % 30;\r
152         index += 2;\r
153       } else {\r
154         switch (code) {\r
155           case TEXT_COMPACTION_MODE_LATCH: {\r
156             codeIndex--;\r
157             end = true;\r
158             break;\r
159           }\r
160           case BYTE_COMPACTION_MODE_LATCH: {\r
161             codeIndex--;\r
162             end = true;\r
163             break;\r
164           }\r
165           case NUMERIC_COMPACTION_MODE_LATCH: {\r
166             codeIndex--;\r
167             end = true;\r
168             break;\r
169           }\r
170           case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
171             // The Mode Shift codeword 913 shall cause a temporary\r
172             // switch from Text Compaction mode to Byte Compaction mode.\r
173             // This switch shall be in effect for only the next codeword,\r
174             // after which the mode shall revert to the prevailing sub-mode\r
175             // of the Text Compaction mode. Codeword 913 is only available\r
176             // in Text Compaction mode; its use is described in 5.4.2.4.\r
177             textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;\r
178             byteCompactionData[index] = code; //Integer.toHexString(code);\r
179             index++;\r
180             break;\r
181           }\r
182           case BYTE_COMPACTION_MODE_LATCH_6: {\r
183             codeIndex--;\r
184             end = true;\r
185             break;\r
186           }\r
187         }\r
188       }\r
189     }\r
190     decodeTextCompaction(textCompactionData, byteCompactionData, index, result);\r
191     return codeIndex;\r
192   }\r
193 \r
194   /**\r
195    * The Text Compaction mode includes all the printable ASCII characters\r
196    * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab\r
197    * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage\r
198    * return (ASCII value 13). The Text Compaction mode also includes various latch\r
199    * and shift characters which are used exclusively within the mode. The Text\r
200    * Compaction mode encodes up to 2 characters per codeword. The compaction rules\r
201    * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode\r
202    * switches are defined in 5.4.2.3.\r
203    *\r
204    * @param textCompactionData The text compaction data.\r
205    * @param byteCompactionData The byte compaction data if there\r
206    *                           was a mode shift.\r
207    * @param length             The size of the text compaction and byte compaction data.\r
208    * @param result             The decoded data is appended to the result.\r
209    */\r
210   private static void decodeTextCompaction(int[] textCompactionData,\r
211                                            int[] byteCompactionData,\r
212                                            int length,\r
213                                            StringBuffer result) {\r
214     // Beginning from an initial state of the Alpha sub-mode\r
215     // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text\r
216     // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text\r
217     // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.\r
218     int subMode = ALPHA;\r
219     int priorToShiftMode = ALPHA;\r
220     int i = 0;\r
221     while (i < length) {\r
222       int subModeCh = textCompactionData[i];\r
223       char ch = 0;\r
224       switch (subMode) {\r
225         case ALPHA:\r
226           // Alpha (uppercase alphabetic)\r
227           if (subModeCh < 26) {\r
228             // Upper case Alpha Character\r
229             ch = (char) ('A' + subModeCh);\r
230           } else {\r
231             if (subModeCh == 26) {\r
232               ch = ' ';\r
233             } else if (subModeCh == LL) {\r
234               subMode = LOWER;\r
235             } else if (subModeCh == ML) {\r
236               subMode = MIXED;\r
237             } else if (subModeCh == PS) {\r
238               // Shift to punctuation\r
239               priorToShiftMode = subMode;\r
240               subMode = PUNCT_SHIFT;\r
241             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
242               result.append((char) byteCompactionData[i]);\r
243             }\r
244           }\r
245           break;\r
246 \r
247         case LOWER:\r
248           // Lower (lowercase alphabetic)\r
249           if (subModeCh < 26) {\r
250             ch = (char) ('a' + subModeCh);\r
251           } else {\r
252             if (subModeCh == 26) {\r
253               ch = ' ';\r
254             } else if (subModeCh == AL) {\r
255               subMode = ALPHA;\r
256             } else if (subModeCh == ML) {\r
257               subMode = MIXED;\r
258             } else if (subModeCh == PS) {\r
259               // Shift to punctuation\r
260               priorToShiftMode = subMode;\r
261               subMode = PUNCT_SHIFT;\r
262             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
263               result.append((char) byteCompactionData[i]);\r
264             }\r
265           }\r
266           break;\r
267 \r
268         case MIXED:\r
269           // Mixed (numeric and some punctuation)\r
270           if (subModeCh < PL) {\r
271             ch = MIXED_CHARS[subModeCh];\r
272           } else {\r
273             if (subModeCh == PL) {\r
274               subMode = PUNCT;\r
275             } else if (subModeCh == 26) {\r
276               ch = ' ';\r
277             } else if (subModeCh == AS) {\r
278               //mode_change = true;\r
279             } else if (subModeCh == AL) {\r
280               subMode = ALPHA;\r
281             } else if (subModeCh == PS) {\r
282               // Shift to punctuation\r
283               priorToShiftMode = subMode;\r
284               subMode = PUNCT_SHIFT;\r
285             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
286               result.append((char) byteCompactionData[i]);\r
287             }\r
288           }\r
289           break;\r
290 \r
291         case PUNCT:\r
292           // Punctuation\r
293           if (subModeCh < PS) {\r
294             ch = PUNCT_CHARS[subModeCh];\r
295           } else {\r
296             if (subModeCh == PAL) {\r
297               subMode = ALPHA;\r
298             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
299               result.append((char) byteCompactionData[i]);\r
300             }\r
301           }\r
302           break;\r
303 \r
304         case PUNCT_SHIFT:\r
305           // Restore sub-mode\r
306           subMode = priorToShiftMode;\r
307           if (subModeCh < PS) {\r
308             ch = PUNCT_CHARS[subModeCh];\r
309           } else {\r
310             if (subModeCh == PAL) {\r
311               subMode = ALPHA;\r
312             }\r
313           }\r
314           break;\r
315       }\r
316       if (ch != 0) {\r
317         // Append decoded character to result\r
318         result.append(ch);\r
319       }\r
320       i++;\r
321     }\r
322   }\r
323 \r
324   /**\r
325    * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.\r
326    * This includes all ASCII characters value 0 to 127 inclusive and provides for international\r
327    * character set support.\r
328    *\r
329    * @param mode      The byte compaction mode i.e. 901 or 924\r
330    * @param codewords The array of codewords (data + error)\r
331    * @param codeIndex The current index into the codeword array.\r
332    * @param result    The decoded data is appended to the result.\r
333    * @return The next index into the codeword array.\r
334    */\r
335   private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuffer result) {\r
336     if (mode == BYTE_COMPACTION_MODE_LATCH) {\r
337       // Total number of Byte Compaction characters to be encoded\r
338       // is not a multiple of 6\r
339       int count = 0;\r
340       long value = 0;\r
341       char[] decodedData = new char[6];\r
342       int[] byteCompactedCodewords = new int[6];\r
343       boolean end = false;\r
344       while ((codeIndex < codewords[0]) && !end) {\r
345         int code = codewords[codeIndex++];\r
346         if (code < TEXT_COMPACTION_MODE_LATCH) {\r
347           byteCompactedCodewords[count] = code;\r
348           count++;\r
349           // Base 900\r
350           value *= 900;\r
351           value += code;\r
352         } else {\r
353           if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
354               (code == BYTE_COMPACTION_MODE_LATCH) ||\r
355               (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
356               (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
357               (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
358               (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
359               (code == MACRO_PDF417_TERMINATOR)) {\r
360           }\r
361           codeIndex--;\r
362           end = true;\r
363         }\r
364         if ((count % 5 == 0) && (count > 0)) {\r
365           // Decode every 5 codewords\r
366           // Convert to Base 256\r
367           for (int j = 0; j < 6; ++j) {\r
368             decodedData[5 - j] = (char) (value % 256);\r
369             value >>= 8;\r
370           }\r
371           result.append(decodedData);\r
372           count = 0;\r
373         }\r
374       }\r
375       // If Byte Compaction mode is invoked with codeword 901,\r
376       // the final group of codewords is interpreted directly\r
377       // as one byte per codeword, without compaction.\r
378       for (int i = ((count / 5) * 5); i < count; i++) {\r
379         result.append((char) byteCompactedCodewords[i]);\r
380       }\r
381 \r
382     } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {\r
383       // Total number of Byte Compaction characters to be encoded\r
384       // is an integer multiple of 6\r
385       int count = 0;\r
386       long value = 0;\r
387       boolean end = false;\r
388       while ((codeIndex < codewords[0]) && !end) {\r
389         int code = codewords[codeIndex++];\r
390         if (code < TEXT_COMPACTION_MODE_LATCH) {\r
391           count += 1;\r
392           // Base 900\r
393           value *= 900;\r
394           value += code;\r
395         } else {\r
396           if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
397               (code == BYTE_COMPACTION_MODE_LATCH) ||\r
398               (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
399               (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
400               (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
401               (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
402               (code == MACRO_PDF417_TERMINATOR)) {\r
403           }\r
404           codeIndex--;\r
405           end = true;\r
406         }\r
407         if ((count % 5 == 0) && (count > 0)) {\r
408           // Decode every 5 codewords\r
409           // Convert to Base 256\r
410           char[] decodedData = new char[6];\r
411           for (int j = 0; j < 6; ++j) {\r
412             decodedData[5 - j] = (char) (value % 256);\r
413             value >>= 8;\r
414           }\r
415           result.append(decodedData);\r
416         }\r
417       }\r
418     }\r
419     return codeIndex;\r
420   }\r
421 \r
422   /**\r
423    * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.\r
424    *\r
425    * @param codewords The array of codewords (data + error)\r
426    * @param codeIndex The current index into the codeword array.\r
427    * @param result    The decoded data is appended to the result.\r
428    * @return The next index into the codeword array.\r
429    */\r
430   private static int numericCompaction(int[] codewords, int codeIndex, StringBuffer result) {\r
431     int count = 0;\r
432     boolean end = false;\r
433 \r
434     int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];\r
435 \r
436     while ((codeIndex < codewords.length) && !end) {\r
437       int code = codewords[codeIndex++];\r
438       if (code < TEXT_COMPACTION_MODE_LATCH) {\r
439         numericCodewords[count] = code;\r
440         count++;\r
441       } else {\r
442         if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
443             (code == BYTE_COMPACTION_MODE_LATCH) ||\r
444             (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
445             (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
446             (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
447             (code == MACRO_PDF417_TERMINATOR)) {\r
448         }\r
449         codeIndex--;\r
450         end = true;\r
451       }\r
452       if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||\r
453           code == NUMERIC_COMPACTION_MODE_LATCH) {\r
454         // Re-invoking Numeric Compaction mode (by using codeword 902\r
455         // while in Numeric Compaction mode) serves  to terminate the\r
456         // current Numeric Compaction mode grouping as described in 5.4.4.2,\r
457         // and then to start a new one grouping.\r
458         String s = decodeBase900toBase10(numericCodewords, count);\r
459         result.append(s);\r
460         count = 0;\r
461       }\r
462     }\r
463     return codeIndex;\r
464   }\r
465 \r
466   /**\r
467    * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.\r
468    *\r
469    * @param codewords The array of codewords\r
470    * @param count     The number of codewords\r
471    * @return The decoded string representing the Numeric data.\r
472    */\r
473   /*\r
474      EXAMPLE\r
475      Encode the fifteen digit numeric string 000213298174000\r
476      Prefix the numeric string with a 1 and set the initial value of\r
477      t = 1 000 213 298 174 000\r
478      Calculate codeword 0\r
479      d0 = 1 000 213 298 174 000 mod 900 = 200\r
480 \r
481      t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082\r
482      Calculate codeword 1\r
483      d1 = 1 111 348 109 082 mod 900 = 282\r
484 \r
485      t = 1 111 348 109 082 div 900 = 1 234 831 232\r
486      Calculate codeword 2\r
487      d2 = 1 234 831 232 mod 900 = 632\r
488 \r
489      t = 1 234 831 232 div 900 = 1 372 034\r
490      Calculate codeword 3\r
491      d3 = 1 372 034 mod 900 = 434\r
492 \r
493      t = 1 372 034 div 900 = 1 524\r
494      Calculate codeword 4\r
495      d4 = 1 524 mod 900 = 624\r
496 \r
497      t = 1 524 div 900 = 1\r
498      Calculate codeword 5\r
499      d5 = 1 mod 900 = 1\r
500      t = 1 div 900 = 0\r
501      Codeword sequence is: 1, 624, 434, 632, 282, 200\r
502 \r
503      Decode the above codewords involves\r
504        1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +\r
505      632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000\r
506 \r
507      Remove leading 1 =>  Result is 000213298174000\r
508 \r
509      As there are huge numbers involved here we must use fake out the maths using string\r
510      tokens for the numbers.\r
511      BigDecimal is not supported by J2ME.\r
512    */\r
513   private static String decodeBase900toBase10(int[] codewords, int count) {\r
514     StringBuffer accum = null;\r
515     for (int i = 0; i < count; i++) {\r
516       StringBuffer value = multiply(EXP900[count - i - 1], codewords[i]);\r
517       if (accum == null) {\r
518         // First time in accum=0\r
519         accum = value;\r
520       } else {\r
521         accum = add(accum.toString(), value.toString());\r
522       }\r
523     }\r
524     String result = null;\r
525     // Remove leading '1' which was inserted to preserve\r
526     // leading zeros\r
527     for (int i = 0; i < accum.length(); i++) {\r
528       if (accum.charAt(i) == '1') {\r
529         //result = accum.substring(i + 1);\r
530         result = accum.toString().substring(i + 1);\r
531         break;\r
532       }\r
533     }\r
534     if (result == null) {\r
535       // No leading 1 => just write the converted number.\r
536       result = accum.toString();\r
537     }\r
538     return result;\r
539   }\r
540 \r
541   /**\r
542    * Multiplies two String numbers\r
543    *\r
544    * @param value1 Any number represented as a string.\r
545    * @param value2 A number <= 999.\r
546    * @return the result of value1 * value2.\r
547    */\r
548   private static StringBuffer multiply(String value1, int value2) {\r
549     StringBuffer result = new StringBuffer(value1.length());\r
550     for (int i = 0; i < value1.length(); i++) {\r
551       // Put zeros into the result.\r
552       result.append('0');\r
553     }\r
554     int hundreds = value2 / 100;\r
555     int tens = (value2 / 10) % 10;\r
556     int ones = value2 % 10;\r
557     // Multiply by ones\r
558     for (int j = 0; j < ones; j++) {\r
559       result = add(result.toString(), value1);\r
560     }\r
561     // Multiply by tens\r
562     for (int j = 0; j < tens; j++) {\r
563       result = add(result.toString(), (value1 + '0').substring(1));\r
564     }\r
565     // Multiply by hundreds\r
566     for (int j = 0; j < hundreds; j++) {\r
567       result = add(result.toString(), (value1 + "00").substring(2));\r
568     }\r
569     return result;\r
570   }\r
571 \r
572   /**\r
573    * Add two numbers which are represented as strings.\r
574    *\r
575    * @param value1\r
576    * @param value2\r
577    * @return the result of value1 + value2\r
578    */\r
579   private static StringBuffer add(String value1, String value2) {\r
580     StringBuffer temp1 = new StringBuffer(5);\r
581     StringBuffer temp2 = new StringBuffer(5);\r
582     StringBuffer result = new StringBuffer(value1.length());\r
583     for (int i = 0; i < value1.length(); i++) {\r
584       // Put zeros into the result.\r
585       result.append('0');\r
586     }\r
587     int carry = 0;\r
588     for (int i = value1.length() - 3; i > -1; i -= 3) {\r
589 \r
590       temp1.setLength(0);\r
591       temp1.append(value1.charAt(i));\r
592       temp1.append(value1.charAt(i + 1));\r
593       temp1.append(value1.charAt(i + 2));\r
594 \r
595       temp2.setLength(0);\r
596       temp2.append(value2.charAt(i));\r
597       temp2.append(value2.charAt(i + 1));\r
598       temp2.append(value2.charAt(i + 2));\r
599 \r
600       int intValue1 = Integer.parseInt(temp1.toString());\r
601       int intValue2 = Integer.parseInt(temp2.toString());\r
602 \r
603       int sumval = (intValue1 + intValue2 + carry) % 1000;\r
604       carry = (intValue1 + intValue2 + carry) / 1000;\r
605 \r
606       result.setCharAt(i + 2, (char) ((sumval % 10) + '0'));\r
607       result.setCharAt(i + 1, (char) (((sumval / 10) % 10) + '0'));\r
608       result.setCharAt(i, (char) ((sumval / 100) + '0'));\r
609     }\r
610     return result;\r
611   }\r
612 \r
613   /*\r
614    private static String decodeBase900toBase10(int codewords[], int count) {\r
615      BigInteger accum = BigInteger.valueOf(0);\r
616      BigInteger value = null;\r
617      for (int i = 0; i < count; i++) {\r
618        value = BigInteger.valueOf(900).pow(count - i - 1);\r
619        value = value.multiply(BigInteger.valueOf(codewords[i]));\r
620        accum = accum.add(value);\r
621      }\r
622      if (debug) System.out.println("Big Integer " + accum);\r
623      String result = accum.toString().substring(1);\r
624      return result;\r
625    }\r
626    */\r
627 }\r