Style changes mostly
[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.ReaderException;\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 ReaderException {\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 numberous 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 ReaderException.getInstance();\r
124       }\r
125     }\r
126     return new DecoderResult(null, result.toString(), 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] * 2];\r
142     // Used to hold the byte compaction value if there is a mode shift\r
143     int[] byteCompactionData = new int[codewords[0] * 2];\r
144 \r
145     int index = 0;\r
146     int code = 0;\r
147     boolean end = false;\r
148     while ((codeIndex < codewords[0]) && !end) {\r
149       code = codewords[codeIndex++];\r
150       if (code < TEXT_COMPACTION_MODE_LATCH) {\r
151         textCompactionData[index] = code / 30;\r
152         textCompactionData[index + 1] = code % 30;\r
153         index += 2;\r
154       } else {\r
155         switch (code) {\r
156           case TEXT_COMPACTION_MODE_LATCH: {\r
157             codeIndex--;\r
158             end = true;\r
159             break;\r
160           }\r
161           case BYTE_COMPACTION_MODE_LATCH: {\r
162             codeIndex--;\r
163             end = true;\r
164             break;\r
165           }\r
166           case NUMERIC_COMPACTION_MODE_LATCH: {\r
167             codeIndex--;\r
168             end = true;\r
169             break;\r
170           }\r
171           case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
172             // The Mode Shift codeword 913 shall cause a temporary\r
173             // switch from Text Compaction mode to Byte Compaction mode.\r
174             // This switch shall be in effect for only the next codeword,\r
175             // after which the mode shall revert to the prevailing sub-mode\r
176             // of the Text Compaction mode. Codeword 913 is only available\r
177             // in Text Compaction mode; its use is described in 5.4.2.4.\r
178             textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;\r
179             byteCompactionData[index] = code; //Integer.toHexString(code);\r
180             index++;\r
181             break;\r
182           }\r
183           case BYTE_COMPACTION_MODE_LATCH_6: {\r
184             codeIndex--;\r
185             end = true;\r
186             break;\r
187           }\r
188         }\r
189       }\r
190     }\r
191     decodeTextCompaction(textCompactionData, byteCompactionData, index, result);\r
192     return codeIndex;\r
193   }\r
194 \r
195   /**\r
196    * The Text Compaction mode includes all the printable ASCII characters\r
197    * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab\r
198    * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage\r
199    * return (ASCII value 13). The Text Compaction mode also includes various latch\r
200    * and shift characters which are used exclusively within the mode. The Text\r
201    * Compaction mode encodes up to 2 characters per codeword. The compaction rules\r
202    * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode\r
203    * switches are defined in 5.4.2.3.\r
204    *\r
205    * @param textCompactionData The text compaction data.\r
206    * @param byteCompactionData The byte compaction data if there\r
207    *                           was a mode shift.\r
208    * @param length             The size of the text compaction and byte compaction data.\r
209    * @param result             The decoded data is appended to the result.\r
210    */\r
211   private static void decodeTextCompaction(int[] textCompactionData,\r
212                                            int[] byteCompactionData,\r
213                                            int length,\r
214                                            StringBuffer result) {\r
215     // Beginning from an initial state of the Alpha sub-mode\r
216     // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text\r
217     // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text\r
218     // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.\r
219     int subMode = ALPHA;\r
220     int priorToShiftMode = ALPHA;\r
221     int i = 0;\r
222     while (i < length) {\r
223       int subModeCh = textCompactionData[i];\r
224       char ch = 0;\r
225       switch (subMode) {\r
226         case ALPHA:\r
227           // Alpha (uppercase alphabetic)\r
228           if (subModeCh < 26) {\r
229             // Upper case Alpha Character\r
230             ch = (char) ('A' + subModeCh);\r
231           } else {\r
232             if (subModeCh == 26) {\r
233               ch = ' ';\r
234             } else if (subModeCh == LL) {\r
235               subMode = LOWER;\r
236             } else if (subModeCh == ML) {\r
237               subMode = MIXED;\r
238             } else if (subModeCh == PS) {\r
239               // Shift to punctuation\r
240               priorToShiftMode = subMode;\r
241               subMode = PUNCT_SHIFT;\r
242             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
243               result.append((char) byteCompactionData[i]);\r
244             }\r
245           }\r
246           break;\r
247 \r
248         case LOWER:\r
249           // Lower (lowercase alphabetic)\r
250           if (subModeCh < 26) {\r
251             ch = (char) ('a' + subModeCh);\r
252           } else {\r
253             if (subModeCh == 26) {\r
254               ch = ' ';\r
255             } else if (subModeCh == AL) {\r
256               subMode = ALPHA;\r
257             } else if (subModeCh == ML) {\r
258               subMode = MIXED;\r
259             } else if (subModeCh == PS) {\r
260               // Shift to punctuation\r
261               priorToShiftMode = subMode;\r
262               subMode = PUNCT_SHIFT;\r
263             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
264               result.append((char) byteCompactionData[i]);\r
265             }\r
266           }\r
267           break;\r
268 \r
269         case MIXED:\r
270           // Mixed (numeric and some punctuation)\r
271           if (subModeCh < PL) {\r
272             ch = MIXED_CHARS[subModeCh];\r
273           } else {\r
274             if (subModeCh == PL) {\r
275               subMode = PUNCT;\r
276             } else if (subModeCh == 26) {\r
277               ch = ' ';\r
278             } else if (subModeCh == AS) {\r
279               //mode_change = true;\r
280             } else if (subModeCh == AL) {\r
281               subMode = ALPHA;\r
282             } else if (subModeCh == PS) {\r
283               // Shift to punctuation\r
284               priorToShiftMode = subMode;\r
285               subMode = PUNCT_SHIFT;\r
286             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
287               result.append((char) byteCompactionData[i]);\r
288             }\r
289           }\r
290           break;\r
291 \r
292         case PUNCT:\r
293           // Punctuation\r
294           if (subModeCh < PS) {\r
295             ch = PUNCT_CHARS[subModeCh];\r
296           } else {\r
297             if (subModeCh == PAL) {\r
298               subMode = ALPHA;\r
299             } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
300               result.append((char) byteCompactionData[i]);\r
301             }\r
302           }\r
303           break;\r
304 \r
305         case PUNCT_SHIFT:\r
306           // Restore sub-mode\r
307           subMode = priorToShiftMode;\r
308           if (subModeCh < PS) {\r
309             ch = PUNCT_CHARS[subModeCh];\r
310           } else {\r
311             if (subModeCh == PAL) {\r
312               subMode = ALPHA;\r
313             }\r
314           }\r
315           break;\r
316       }\r
317       if (ch != 0) {\r
318         // Append decoded character to result\r
319         result.append(ch);\r
320       }\r
321       i++;\r
322     }\r
323   }\r
324 \r
325   /**\r
326    * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.\r
327    * This includes all ASCII characters value 0 to 127 inclusive and provides for international\r
328    * character set support.\r
329    *\r
330    * @param mode      The byte compaction mode i.e. 901 or 924\r
331    * @param codewords The array of codewords (data + error)\r
332    * @param codeIndex The current index into the codeword array.\r
333    * @param result    The decoded data is appended to the result.\r
334    * @return The next index into the codeword array.\r
335    */\r
336   private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuffer result) {\r
337     if (mode == BYTE_COMPACTION_MODE_LATCH) {\r
338       // Total number of Byte Compaction characters to be encoded\r
339       // is not a multiple of 6\r
340       int count = 0;\r
341       long value = 0;\r
342       char[] decodedData = new char[6];\r
343       int[] byteCompactedCodewords = new int[6];\r
344       int code = 0;\r
345       boolean end = false;\r
346       while ((codeIndex < codewords[0]) && !end) {\r
347         code = codewords[codeIndex++];\r
348         if (code < TEXT_COMPACTION_MODE_LATCH) {\r
349           byteCompactedCodewords[count] = code;\r
350           count++;\r
351           // Base 900\r
352           value *= 900;\r
353           value += code;\r
354         } else {\r
355           if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
356               (code == BYTE_COMPACTION_MODE_LATCH) ||\r
357               (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
358               (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
359               (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
360               (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
361               (code == MACRO_PDF417_TERMINATOR)) {\r
362           }\r
363           codeIndex--;\r
364           end = true;\r
365         }\r
366         if ((count % 5 == 0) && (count > 0)) {\r
367           // Decode every 5 codewords\r
368           // Convert to Base 256\r
369           for (int j = 0; j < 6; ++j) {\r
370             decodedData[5 - j] = (char) (value % 256);\r
371             value >>= 8;\r
372           }\r
373           result.append(decodedData);\r
374           count = 0;\r
375         }\r
376       }\r
377       // If Byte Compaction mode is invoked with codeword 901,\r
378       // the final group of codewords is interpreted directly\r
379       // as one byte per codeword, without compaction.\r
380       for (int i = ((count / 5) * 5); i < count; i++) {\r
381         result.append((char) byteCompactedCodewords[i]);\r
382       }\r
383 \r
384     } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {\r
385       // Total number of Byte Compaction characters to be encoded\r
386       // is an integer multiple of 6\r
387       int count = 0;\r
388       long value = 0;\r
389       int code = 0;\r
390       boolean end = false;\r
391       while ((codeIndex < codewords[0]) && !end) {\r
392         code = codewords[codeIndex++];\r
393         if (code < TEXT_COMPACTION_MODE_LATCH) {\r
394           count += 1;\r
395           // Base 900\r
396           value *= 900;\r
397           value += code;\r
398         } else {\r
399           if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
400               (code == BYTE_COMPACTION_MODE_LATCH) ||\r
401               (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
402               (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
403               (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
404               (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
405               (code == MACRO_PDF417_TERMINATOR)) {\r
406           }\r
407           codeIndex--;\r
408           end = true;\r
409         }\r
410         if ((count % 5 == 0) && (count > 0)) {\r
411           // Decode every 5 codewords\r
412           // Convert to Base 256\r
413           char[] decodedData = new char[6];\r
414           for (int j = 0; j < 6; ++j) {\r
415             decodedData[5 - j] = (char) (value % 256);\r
416             value >>= 8;\r
417           }\r
418           result.append(decodedData);\r
419         }\r
420       }\r
421     }\r
422     return codeIndex;\r
423   }\r
424 \r
425   /**\r
426    * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.\r
427    *\r
428    * @param codewords The array of codewords (data + error)\r
429    * @param codeIndex The current index into the codeword array.\r
430    * @param result    The decoded data is appended to the result.\r
431    * @return The next index into the codeword array.\r
432    */\r
433   private static int numericCompaction(int[] codewords, int codeIndex, StringBuffer result) {\r
434     int count = 0;\r
435     boolean end = false;\r
436 \r
437     int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];\r
438 \r
439     while ((codeIndex < codewords.length) && !end) {\r
440       int code = codewords[codeIndex++];\r
441       if (code < TEXT_COMPACTION_MODE_LATCH) {\r
442         numericCodewords[count] = code;\r
443         count++;\r
444       } else {\r
445         if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
446             (code == BYTE_COMPACTION_MODE_LATCH) ||\r
447             (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
448             (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
449             (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
450             (code == MACRO_PDF417_TERMINATOR)) {\r
451         }\r
452         codeIndex--;\r
453         end = true;\r
454       }\r
455       if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||\r
456           code == NUMERIC_COMPACTION_MODE_LATCH) {\r
457         // Re-invoking Numeric Compaction mode (by using codeword 902\r
458         // while in Numeric Compaction mode) serves  to terminate the\r
459         // current Numeric Compaction mode grouping as described in 5.4.4.2,\r
460         // and then to start a new one grouping.\r
461         String s = decodeBase900toBase10(numericCodewords, count);\r
462         result.append(s);\r
463         count = 0;\r
464       }\r
465     }\r
466     return codeIndex;\r
467   }\r
468 \r
469   /**\r
470    * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.\r
471    *\r
472    * @param codewords The array of codewords\r
473    * @param count     The number of codewords\r
474    * @return The decoded string representing the Numeric data.\r
475    */\r
476   /*\r
477      EXAMPLE\r
478      Encode the fifteen digit numeric string 000213298174000\r
479      Prefix the numeric string with a 1 and set the initial value of\r
480      t = 1 000 213 298 174 000\r
481      Calculate codeword 0\r
482      d0 = 1 000 213 298 174 000 mod 900 = 200\r
483 \r
484      t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082\r
485      Calculate codeword 1\r
486      d1 = 1 111 348 109 082 mod 900 = 282\r
487 \r
488      t = 1 111 348 109 082 div 900 = 1 234 831 232\r
489      Calculate codeword 2\r
490      d2 = 1 234 831 232 mod 900 = 632\r
491 \r
492      t = 1 234 831 232 div 900 = 1 372 034\r
493      Calculate codeword 3\r
494      d3 = 1 372 034 mod 900 = 434\r
495 \r
496      t = 1 372 034 div 900 = 1 524\r
497      Calculate codeword 4\r
498      d4 = 1 524 mod 900 = 624\r
499 \r
500      t = 1 524 div 900 = 1\r
501      Calculate codeword 5\r
502      d5 = 1 mod 900 = 1\r
503      t = 1 div 900 = 0\r
504      Codeword sequence is: 1, 624, 434, 632, 282, 200\r
505 \r
506      Decode the above codewords involves\r
507        1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +\r
508      632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000\r
509 \r
510      Remove leading 1 =>  Result is 000213298174000\r
511 \r
512      As there are huge numbers involved here we must use fake out the maths using string\r
513      tokens for the numbers.\r
514      BigDecimal is not supported by J2ME.\r
515    */\r
516   private static String decodeBase900toBase10(int[] codewords, int count) {\r
517     StringBuffer accum = null;\r
518     StringBuffer value = null;\r
519     for (int i = 0; i < count; i++) {\r
520       value = multiply(EXP900[count - i - 1], codewords[i]);\r
521       if (accum == null) {\r
522         // First time in accum=0\r
523         accum = value;\r
524       } else {\r
525         accum = add(accum.toString(), value.toString());\r
526       }\r
527     }\r
528     String result = null;\r
529     // Remove leading '1' which was inserted to preserce\r
530     // leading zeros\r
531     for (int i = 0; i < accum.length(); i++) {\r
532       if (accum.charAt(i) == '1') {\r
533         //result = accum.substring(i + 1);\r
534         result = accum.toString().substring(i + 1);\r
535         break;\r
536       }\r
537     }\r
538     if (result == null) {\r
539       // No leading 1 => just write the converted number.\r
540       result = accum.toString();\r
541     }\r
542     return result;\r
543   }\r
544 \r
545   /**\r
546    * Multiplies two String numbers\r
547    *\r
548    * @param value1 Any number represented as a string.\r
549    * @param value2 A number <= 999.\r
550    * @return the result of value1 * value2.\r
551    */\r
552   private static StringBuffer multiply(String value1, int value2) {\r
553     StringBuffer result = new StringBuffer(value1.length());\r
554     for (int i = 0; i < value1.length(); i++) {\r
555       // Put zeros into the result.\r
556       result.append('0');\r
557     }\r
558     int hundreds = value2 / 100;\r
559     int tens = (value2 / 10) % 10;\r
560     int ones = value2 % 10;\r
561     // Multiply by ones\r
562     for (int j = 0; j < ones; j++) {\r
563       result = add(result.toString(), value1);\r
564     }\r
565     // Multiply by tens\r
566     for (int j = 0; j < tens; j++) {\r
567       result = add(result.toString(), (value1 + '0').substring(1));\r
568     }\r
569     // Multiply by hundreds\r
570     for (int j = 0; j < hundreds; j++) {\r
571       result = add(result.toString(), (value1 + "00").substring(2));\r
572     }\r
573     return result;\r
574   }\r
575 \r
576   /**\r
577    * Add two numbers which are represented as strings.\r
578    *\r
579    * @param value1\r
580    * @param value2\r
581    * @return the result of value1 + value2\r
582    */\r
583   private static StringBuffer add(String value1, String value2) {\r
584     StringBuffer temp1 = new StringBuffer(5);\r
585     StringBuffer temp2 = new StringBuffer(5);\r
586     StringBuffer result = new StringBuffer(value1.length());\r
587     for (int i = 0; i < value1.length(); i++) {\r
588       // Put zeros into the result.\r
589       result.append('0');\r
590     }\r
591     int carry = 0;\r
592     for (int i = value1.length() - 3; i > -1; i -= 3) {\r
593 \r
594       temp1.setLength(0);\r
595       temp1.append(value1.charAt(i));\r
596       temp1.append(value1.charAt(i + 1));\r
597       temp1.append(value1.charAt(i + 2));\r
598 \r
599       temp2.setLength(0);\r
600       temp2.append(value2.charAt(i));\r
601       temp2.append(value2.charAt(i + 1));\r
602       temp2.append(value2.charAt(i + 2));\r
603 \r
604       int intValue1 = Integer.parseInt(temp1.toString());\r
605       int intValue2 = Integer.parseInt(temp2.toString());\r
606 \r
607       int sumval = (intValue1 + intValue2 + carry) % 1000;\r
608       carry = (intValue1 + intValue2 + carry) / 1000;\r
609 \r
610       result.setCharAt(i + 2, (char) ((sumval % 10) + '0'));\r
611       result.setCharAt(i + 1, (char) (((sumval / 10) % 10) + '0'));\r
612       result.setCharAt(i, (char) ((sumval / 100) + '0'));\r
613     }\r
614     return result;\r
615   }\r
616 \r
617   /*\r
618    private static String decodeBase900toBase10(int codewords[], int count) {\r
619      BigInteger accum = BigInteger.valueOf(0);\r
620      BigInteger value = null;\r
621      for (int i = 0; i < count; i++) {\r
622        value = BigInteger.valueOf(900).pow(count - i - 1);\r
623        value = value.multiply(BigInteger.valueOf(codewords[i]));\r
624        accum = accum.add(value);\r
625      }\r
626      if (debug) System.out.println("Big Integer " + accum);\r
627      String result = accum.toString().substring(1);\r
628      return result;\r
629    }\r
630    */\r
631 }\r