Spell checker fixes, narrowed scope / made less visible where possible. Little stuff
[zxing.git] / core / src / com / google / zxing / pdf417 / decoder / DecodedBitStreamParser.java
index 7e7c9ca..a8cf592 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * Copyright 2007 ZXing authors\r
+ * Copyright 2009 ZXing authors\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
  */\r
+\r
 package com.google.zxing.pdf417.decoder;\r
 \r
 import com.google.zxing.ReaderException;\r
@@ -24,607 +25,603 @@ import com.google.zxing.common.DecoderResult;
  * @author SITA Lab (kevin.osullivan@sita.aero)\r
  */\r
 final class DecodedBitStreamParser {\r
-       public static final boolean debug = true;\r
-       \r
-       private static final int TEXT_COMPACTION_MODE_LATCH = 900;\r
-       private static final int BYTE_COMPACTION_MODE_LATCH = 901;\r
-       private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;\r
-       private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;\r
-       private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;\r
-       private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;\r
-       private static final int MACRO_PDF417_TERMINATOR = 922;\r
-       private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;\r
-       private static final int MAX_NUMERIC_CODEWORDS = 15;\r
-\r
-       private static final int ALPHA = 0;\r
-       private static final int LOWER = 1;\r
-       private static final int MIXED = 2;\r
-       private static final int PUNCT = 3;\r
-       private static final int PUNCT_SHIFT = 4;\r
-\r
-    private static final int PL = 25;\r
-    private static final int LL = 27;\r
-    private static final int AS = 27;\r
-    private static final int ML = 28;\r
-    private static final int AL = 28;\r
-    private static final int PS = 29;\r
-    private static final int PAL = 29;\r
\r
-       private static final char punct_chars[] = {';', '<', '>', '@', '[', 92, '}', '_', 96, '~', '!',\r
-                                                                                               13, 9, ',', ':', 10, '-', '.', '$', '/', 34, '|', '*',\r
-                                                                                               '(', ')', '?', '{', '}', 39};\r
-\r
-       private static final char mixed_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',\r
-                                                                                           13, 9, ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',\r
-                                                                                           '=', '^'};\r
-\r
-       // Table containing values for the exponent of 900.\r
-       // This is used in the numeric compaction decode algorithm.\r
-       private static final String exp900[] = \r
-        {"000000000000000000000000000000000000000000001",\r
-         "000000000000000000000000000000000000000000900",\r
-         "000000000000000000000000000000000000000810000",\r
-         "000000000000000000000000000000000000729000000",\r
-         "000000000000000000000000000000000656100000000",\r
-         "000000000000000000000000000000590490000000000",\r
-         "000000000000000000000000000531441000000000000",\r
-         "000000000000000000000000478296900000000000000",\r
-         "000000000000000000000430467210000000000000000",\r
-         "000000000000000000387420489000000000000000000",\r
-         "000000000000000348678440100000000000000000000",\r
-         "000000000000313810596090000000000000000000000",\r
-         "000000000282429536481000000000000000000000000",\r
-         "000000254186582832900000000000000000000000000",\r
-         "000228767924549610000000000000000000000000000",\r
-         "205891132094649000000000000000000000000000000"};\r
-       \r
-       private DecodedBitStreamParser() {\r
-       }\r
-\r
-       static DecoderResult decode(int codewords[]) throws ReaderException {\r
-               StringBuffer result = new StringBuffer(100);\r
-               // Get compaction mode\r
-               int codeIndex = 1;\r
-               int code = codewords[codeIndex++];\r
-               while (codeIndex < codewords[0]) {\r
-                       switch(code) {\r
-                               case TEXT_COMPACTION_MODE_LATCH: {\r
-                                       codeIndex = textCompaction(codewords, codeIndex, result);\r
-                                       break;\r
-                               }\r
-                               case BYTE_COMPACTION_MODE_LATCH: {  \r
-                                       codeIndex = byteCompaction(code, codewords, codeIndex, result);   \r
-                                       break;\r
-                               }\r
-                               case NUMERIC_COMPACTION_MODE_LATCH: {\r
-                                       codeIndex = numericCompaction(codewords, codeIndex, result);\r
-                                       break;\r
-                               }       \r
-                               case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
-                                       codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
-                                       break;\r
-                               }\r
-                               case BYTE_COMPACTION_MODE_LATCH_6: {     \r
-                                       codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
-                                       break;\r
-                               } \r
-                               default: {\r
-                                       // Default to text compaction. During testing numberous barcodes\r
-                                       // appeared to be missing the starting mode. In these cases defaulting\r
-                                       // to text compaction seems to work.\r
-                                       codeIndex--;\r
-                                       codeIndex = textCompaction(codewords, codeIndex, result);\r
-                                       break;\r
-                               }     \r
-                       }\r
-                       if (codeIndex < codewords.length) {\r
-                               code = codewords[codeIndex++];\r
-                       } else {\r
-                               throw ReaderException.getInstance();\r
-                       }\r
-               }\r
-               if (debug) System.out.println(result);\r
-               return new DecoderResult(null, result.toString(), null);\r
-       }       \r
-\r
-       /**\r
-        * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be \r
-        * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as \r
-        * well as selected control characters.\r
-        * \r
-        * @param codewords The array of codewords (data + error)\r
-        * @param codeIndex The current index into the codeword array.\r
-        * @param result The decoded data is appended to the result.\r
-        * @return The next index into the codeword array.\r
-        */\r
-       private static int textCompaction(int codewords[], int codeIndex, StringBuffer result) {\r
-               // 2 character per codeword\r
-               int textCompactionData[] = new int[codewords[0] * 2];\r
-               // Used to hold the byte compaction value if there is a mode shift\r
-               int byteCompactionData[] = new int[codewords[0] * 2];\r
-\r
-               int index = 0;\r
-               int code = 0;\r
-               boolean end = false;\r
-               while((codeIndex < codewords[0]) && !end) {\r
-                       code = codewords[codeIndex++];\r
-                       if (code < TEXT_COMPACTION_MODE_LATCH) {\r
-                               textCompactionData[index] = code / 30;\r
-                               textCompactionData[index+1] = code % 30;\r
-                               index += 2;\r
-              } else {\r
-                  switch (code) {\r
-                               case TEXT_COMPACTION_MODE_LATCH: {\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                                       break;\r
-                               }\r
-                               case BYTE_COMPACTION_MODE_LATCH: {\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                                       break;\r
-                               }\r
-                               case NUMERIC_COMPACTION_MODE_LATCH: {\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                                       break;\r
-                               }       \r
-                               case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
-                                       // The Mode Shift codeword 913 shall cause a temporary \r
-                                       // switch from Text Compaction mode to Byte Compaction mode. \r
-                                       // This switch shall be in effect for only the next codeword, \r
-                                       // after which the mode shall revert to the prevailing sub-mode\r
-                                       // of the Text Compaction mode. Codeword 913 is only available\r
-                                       // in Text Compaction mode; its use is described in 5.4.2.4.                       \r
-                                       textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;\r
-                                       byteCompactionData[index] = code; //Integer.toHexString(code);\r
-                                       index++;\r
-                                       break;\r
-                               }\r
-                               case BYTE_COMPACTION_MODE_LATCH_6: {\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                                       break;\r
-                               }       \r
-                       }\r
-               }\r
-               } \r
-               decodeTextCompaction(textCompactionData, byteCompactionData, index, result);\r
-               return codeIndex;\r
-       }\r
-\r
-       /**\r
-        * The Text Compaction mode includes all the printable ASCII characters \r
-        * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab\r
-        * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage\r
-        * return (ASCII value 13). The Text Compaction mode also includes various latch\r
-        * and shift characters which are used exclusively within the mode. The Text \r
-        * Compaction mode encodes up to 2 characters per codeword. The compaction rules\r
-        * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode\r
-        * switches are defined in 5.4.2.3.\r
-        * \r
-        * @param textCompactionData The text compaction data.\r
-        * @param byteCompactionData The byte compaction data if there\r
-        *                was a mode shift.\r
-        * @param length The size of the text compaction and byte compaction data.\r
-        * @param result The decoded data is appended to the result.\r
-        */\r
-       private static void decodeTextCompaction(int textCompactionData[], \r
-                                                                                int byteCompactionData[], \r
-                                                                                int length, \r
-                                                                                StringBuffer result) {\r
-               // Beginning from an initial state of the Alpha sub-mode\r
-               // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text\r
-               // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text\r
-               // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.           \r
-               int subMode = ALPHA;\r
-               int priorToShiftMode = ALPHA;\r
-               int i = 0;\r
-               while (i < length) {\r
-                       int subModeCh = textCompactionData[i];\r
-                       char ch = 0;\r
-                       switch(subMode) {\r
-                               case ALPHA :\r
-                                       // Alpha (uppercase alphabetic)\r
-                                       if (subModeCh < 26) {\r
-                                               // Upper case Alpha Character\r
-                                               ch = (char)('A' + subModeCh);\r
-                                       } else {\r
-                                               if (subModeCh == 26) {\r
-                                                       ch = ' ';\r
-                                               } else if (subModeCh == LL) {\r
-                                                       subMode = LOWER;\r
-                           } else if (subModeCh == ML) {\r
-                                                       subMode = MIXED;\r
-                                               } else if (subModeCh == PS) {\r
-                                                       // Shift to punctuation\r
-                                                       priorToShiftMode = subMode;\r
-                                                       subMode = PUNCT_SHIFT;\r
-                                               } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
-                                                       result.append((char)byteCompactionData[i]);\r
-                                               }             \r
-                                       }\r
-                                       break;\r
-       \r
-                               case LOWER :\r
-                                       // Lower (lowercase alphabetic)\r
-                                       if (subModeCh < 26) {\r
-                                               ch = (char)('a' + subModeCh);\r
-                                       } else {\r
-                                               if (subModeCh == 26) {\r
-                                                       ch = ' ';\r
-                                               } else if (subModeCh == AL) {\r
-                                                       subMode = ALPHA;\r
-                           } else if (subModeCh == ML) {\r
-                                                       subMode = MIXED;  \r
-                                               } else if (subModeCh == PS) {\r
-                                                       // Shift to punctuation\r
-                                                       priorToShiftMode = subMode;\r
-                                                       subMode = PUNCT_SHIFT;\r
-                                               } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
-                                                       result.append((char)byteCompactionData[i]);\r
-                                               }\r
-                                       }\r
-                                       break;\r
-       \r
-                               case MIXED :\r
-                                       // Mixed (numeric and some punctuation)\r
-                                       if ( subModeCh < PL ) {\r
-                                               ch = mixed_chars[subModeCh];\r
-                                       } else {\r
-                                               if (subModeCh == PL) {\r
-                                                       subMode = PUNCT;\r
-                                               } else if (subModeCh == 26) {\r
-                                                       ch = ' ';\r
-                           } else if (subModeCh == AS) {\r
-                                                       //mode_change = true;\r
-                                               } else if (subModeCh == AL) {\r
-                                                       subMode = ALPHA;\r
-                                               } else if (subModeCh == PS) {\r
-                                                       // Shift to punctuation\r
-                                                       priorToShiftMode = subMode;\r
-                                                       subMode = PUNCT_SHIFT;\r
-                           } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
-                                                       result.append((char)byteCompactionData[i]);\r
-                                               }\r
-                                       }\r
-                                       break;\r
-       \r
-                               case PUNCT :\r
-                                       // Punctuation                  \r
-                                       if (subModeCh < PS) {\r
-                                               ch = punct_chars[subModeCh];\r
-                                       } else {\r
-                                               if (subModeCh == PAL) {\r
-                                                       subMode = ALPHA;\r
-                                               } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
-                                                       result.append((char)byteCompactionData[i]);\r
-                                               }\r
-                                       }\r
-                                       break;\r
-       \r
-                               case PUNCT_SHIFT :\r
-                                       // Restore sub-mode\r
-                                       subMode = priorToShiftMode;\r
-                                       if (subModeCh < PS) {\r
-                                               ch = punct_chars[subModeCh];\r
-                                       } else {\r
-                                               if (subModeCh == PAL) {\r
-                                                       subMode = ALPHA;\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                       }\r
-                       if (ch !=0) {\r
-                               // Append decoded character to result\r
-                               result.append(ch);\r
-                       }\r
-                       i++;\r
-               } \r
-       }\r
-       \r
-       /**\r
-        * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.\r
-        * This includes all ASCII characters value 0 to 127 inclusive and provides for international \r
-        * character set support.\r
-        * @param mode The byte compaction mode i.e. 901 or 924\r
-        * @param codewords The array of codewords (data + error)\r
-        * @param codeIndex The current index into the codeword array.\r
-        * @param result The decoded data is appended to the result.\r
-        * @return The next index into the codeword array.\r
-        */\r
-       private static int byteCompaction(int mode, int codewords[], int codeIndex, StringBuffer result) {\r
-               if (mode == BYTE_COMPACTION_MODE_LATCH) { \r
-                       // Total number of Byte Compaction characters to be encoded \r
-                       // is not a multiple of 6\r
-                       int count = 0;\r
-                       long value = 0; \r
-                       char decodedData[] = new char[6];\r
-                       int byteCompactedCodewords[] = new int[6];\r
-                       int code = 0;\r
-                       boolean end = false;\r
-                       while(( codeIndex < codewords[0]) && !end) {\r
-                               code = codewords[codeIndex++];\r
-                               if (code < TEXT_COMPACTION_MODE_LATCH) {\r
-                                       byteCompactedCodewords[count] = code;\r
-                                       count++;\r
-                                       // Base 900\r
-                                       value *= 900;\r
-                                       value += code;\r
-                               } else {\r
-                               if ((code == TEXT_COMPACTION_MODE_LATCH) || \r
-                                       (code == BYTE_COMPACTION_MODE_LATCH) ||\r
-                                       (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
-                                       (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
-                                       (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
-                                       (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
-                                       (code == MACRO_PDF417_TERMINATOR)) {\r
-                                       }\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                               }\r
-                               if ((count % 5 == 0) && (count > 0)) {\r
-                                       // Decode every 5 codewords\r
-                                       // Convert to Base 256\r
-                                       for (int j = 0; j < 6; ++j) {\r
-                                               decodedData[5 - j] = (char) (value % 256);\r
-                                               value >>= 8;\r
-                                       }\r
-                                       result.append(decodedData);\r
-                                       count = 0;\r
-                               }         \r
-                       }\r
-                       // If Byte Compaction mode is invoked with codeword 901, \r
-                       // the final group of codewords is interpreted directly \r
-                       // as one byte per codeword, without compaction.                        \r
-                       for (int i = (( count / 5) * 5); i < count; i++) {\r
-                               result.append((char)byteCompactedCodewords[i]);\r
-                       }\r
-               \r
-               } else if (mode == BYTE_COMPACTION_MODE_LATCH_6)  { \r
-                       // Total number of Byte Compaction characters to be encoded \r
-                       // is an integer multiple of 6\r
-                       int count = 0;\r
-                       long value = 0; \r
-                       int code = 0;\r
-                       boolean end = false;\r
-                       while(( codeIndex < codewords[0]) && !end) {\r
-                               code = codewords[codeIndex++];\r
-                               char decodedData[] = new char[6];\r
-                               if (code < TEXT_COMPACTION_MODE_LATCH) {\r
-                                       count += 1;\r
-                                       // Base 900\r
-                                       value *= 900;\r
-                                       value += code;\r
-                               } else {\r
-                               if ((code == TEXT_COMPACTION_MODE_LATCH) || \r
-                                       (code == BYTE_COMPACTION_MODE_LATCH) ||\r
-                                       (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
-                                       (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
-                                       (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
-                                       (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
-                                       (code == MACRO_PDF417_TERMINATOR)) {\r
-                                       }\r
-                                       codeIndex--;\r
-                                       end = true;\r
-                               }\r
-                               if ((count % 5 == 0) && ( count > 0)) {\r
-                                       // Decode every 5 codewords\r
-                                       // Convert to Base 256\r
-                                       for (int j = 0; j < 6; ++j) {\r
-                                               decodedData[5 - j] = (char) (value % 256);\r
-                                               value >>= 8;\r
-                                       }\r
-                                       result.append(decodedData);\r
-                               }         \r
-                       }\r
-               }\r
-               return codeIndex;\r
-       }\r
-\r
-       /**\r
-        * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.\r
-        * \r
-        * @param codewords The array of codewords (data + error)\r
-        * @param codeIndex The current index into the codeword array.\r
-        * @param result The decoded data is appended to the result.\r
-        * @return The next index into the codeword array.\r
-        */\r
-       private static int numericCompaction(int codewords[], int codeIndex, StringBuffer result) {\r
-               int code;\r
-           int count = 0;  \r
-           boolean end = false;\r
-           \r
-           int numericCodewords[] = new int[MAX_NUMERIC_CODEWORDS];\r
-           \r
-           while ((codeIndex < codewords.length) && !end) {\r
-               code = codewords[codeIndex++];\r
-               if (code < TEXT_COMPACTION_MODE_LATCH) {\r
-                       numericCodewords[count] = code;\r
-                       count++;\r
-               } else {\r
-                       if ((code == TEXT_COMPACTION_MODE_LATCH) || \r
-                               (code == BYTE_COMPACTION_MODE_LATCH) ||\r
-                               (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
-                               (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
-                               (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
-                               (code == MACRO_PDF417_TERMINATOR)) {\r
-                   }\r
-                               codeIndex--;\r
-                       end = true;\r
-               }\r
-               if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||\r
-                        code == NUMERIC_COMPACTION_MODE_LATCH) {\r
-                       // Re-invoking Numeric Compaction mode (by using codeword 902 \r
-                       // while in Numeric Compaction mode) serves  to terminate the \r
-                       // current Numeric Compaction mode grouping as described in 5.4.4.2, \r
-                       // and then to start a new one grouping.\r
-                       String s = decodeBase900toBase10(numericCodewords, count);\r
-                       result.append(s);\r
-                       count = 0;\r
-               }\r
-           }\r
-           return codeIndex;\r
-       }\r
-\r
-       /**\r
-        * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.\r
-        * @param codewords The array of codewords\r
-        * @param count The number of codewords\r
-        * @return The decoded string representing the Numeric data.\r
-        */\r
-       /*\r
-               EXAMPLE\r
-               Encode the fifteen digit numeric string 000213298174000\r
-               Prefix the numeric string with a 1 and set the initial value of\r
-               t = 1 000 213 298 174 000\r
-               Calculate codeword 0\r
-               d0 = 1 000 213 298 174 000 mod 900 = 200\r
-               \r
-               t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082\r
-               Calculate codeword 1\r
-               d1 = 1 111 348 109 082 mod 900 = 282\r
-               \r
-               t = 1 111 348 109 082 div 900 = 1 234 831 232\r
-               Calculate codeword 2\r
-               d2 = 1 234 831 232 mod 900 = 632\r
-               \r
-               t = 1 234 831 232 div 900 = 1 372 034\r
-               Calculate codeword 3\r
-               d3 = 1 372 034 mod 900 = 434\r
-               \r
-               t = 1 372 034 div 900 = 1 524\r
-               Calculate codeword 4\r
-               d4 = 1 524 mod 900 = 624\r
-               \r
-               t = 1 524 div 900 = 1\r
-               Calculate codeword 5\r
-               d5 = 1 mod 900 = 1\r
-               t = 1 div 900 = 0\r
-               Codeword sequence is: 1, 624, 434, 632, 282, 200\r
-               \r
-               Decode the above codewords involves\r
-                 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +\r
-               632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000\r
-               \r
-               Remove leading 1 =>  Result is 000213298174000\r
-               \r
-               As there are huge numbers involved here we must use fake out the maths using string\r
-               tokens for the numbers.\r
-               BigDecimal is not supported by J2ME.\r
-       */\r
-       private static String decodeBase900toBase10(int codewords[], int count) {\r
-               StringBuffer accum = null;\r
-               StringBuffer value = null;\r
-               for (int i = 0; i < count; i++) {\r
-                       value = multiply(exp900[count - i - 1], codewords[i]);\r
-                       if (accum == null) {\r
-                               // First time in accum=0\r
-                               accum = value;\r
-                       } else {\r
-                               accum = add(accum.toString(), value.toString());\r
-                       }\r
-               }\r
-               String result = null;\r
-               // Remove leading '1' which was inserted to preserce\r
-               // leading zeros\r
-               for (int i = 0; i < accum.length(); i++) {\r
-                       if (accum.charAt(i) == '1') {\r
-                               //result = accum.substring(i + 1);\r
-                               result = accum.toString().substring(i+1);\r
-                               break;\r
-                       }\r
-               }\r
-               if (result == null) {\r
-                       // No leading 1 => just write the converted number.\r
-                       result = accum.toString();\r
-               }\r
-               if (debug) System.out.println("Big Integer=" + result);\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Multiplies two String numbers\r
-        * @param value1 Any number represented as a string.\r
-        * @param value2 A number <= 999.\r
-        * @return the result of value1 * value2.\r
-        */\r
-       private static StringBuffer multiply(String value1, int value2) {\r
-               StringBuffer result = new StringBuffer(value1.length());\r
-               for (int i = 0; i < value1.length(); i++) {\r
-                       // Put zeros into the result.\r
-                       result.append('0');\r
-               }\r
-               int hundreds = value2 / 100;\r
-               int tens  = (value2 / 10) % 10;\r
-               int ones = value2 % 10;\r
-               // Multiply by ones\r
-               for (int j = 0; j < ones ; j++) {\r
-                       result = add(result.toString(), value1);\r
+\r
+  private static final int TEXT_COMPACTION_MODE_LATCH = 900;\r
+  private static final int BYTE_COMPACTION_MODE_LATCH = 901;\r
+  private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;\r
+  private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;\r
+  private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;\r
+  private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;\r
+  private static final int MACRO_PDF417_TERMINATOR = 922;\r
+  private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;\r
+  private static final int MAX_NUMERIC_CODEWORDS = 15;\r
+\r
+  private static final int ALPHA = 0;\r
+  private static final int LOWER = 1;\r
+  private static final int MIXED = 2;\r
+  private static final int PUNCT = 3;\r
+  private static final int PUNCT_SHIFT = 4;\r
+\r
+  private static final int PL = 25;\r
+  private static final int LL = 27;\r
+  private static final int AS = 27;\r
+  private static final int ML = 28;\r
+  private static final int AL = 28;\r
+  private static final int PS = 29;\r
+  private static final int PAL = 29;\r
+\r
+  private static final char[] PUNCT_CHARS = {';', '<', '>', '@', '[', 92, '}', '_', 96, '~', '!',\r
+      13, 9, ',', ':', 10, '-', '.', '$', '/', 34, '|', '*',\r
+      '(', ')', '?', '{', '}', 39};\r
+\r
+  private static final char[] MIXED_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',\r
+      13, 9, ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',\r
+      '=', '^'};\r
+\r
+  // Table containing values for the exponent of 900.\r
+  // This is used in the numeric compaction decode algorithm.\r
+  private static final String[] EXP900 =\r
+      {   "000000000000000000000000000000000000000000001",\r
+          "000000000000000000000000000000000000000000900",\r
+          "000000000000000000000000000000000000000810000",\r
+          "000000000000000000000000000000000000729000000",\r
+          "000000000000000000000000000000000656100000000",\r
+          "000000000000000000000000000000590490000000000",\r
+          "000000000000000000000000000531441000000000000",\r
+          "000000000000000000000000478296900000000000000",\r
+          "000000000000000000000430467210000000000000000",\r
+          "000000000000000000387420489000000000000000000",\r
+          "000000000000000348678440100000000000000000000",\r
+          "000000000000313810596090000000000000000000000",\r
+          "000000000282429536481000000000000000000000000",\r
+          "000000254186582832900000000000000000000000000",\r
+          "000228767924549610000000000000000000000000000",\r
+          "205891132094649000000000000000000000000000000"};\r
+\r
+  private DecodedBitStreamParser() {\r
+  }\r
+\r
+  static DecoderResult decode(int[] codewords) throws ReaderException {\r
+    StringBuffer result = new StringBuffer(100);\r
+    // Get compaction mode\r
+    int codeIndex = 1;\r
+    int code = codewords[codeIndex++];\r
+    while (codeIndex < codewords[0]) {\r
+      switch (code) {\r
+        case TEXT_COMPACTION_MODE_LATCH: {\r
+          codeIndex = textCompaction(codewords, codeIndex, result);\r
+          break;\r
+        }\r
+        case BYTE_COMPACTION_MODE_LATCH: {\r
+          codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
+          break;\r
+        }\r
+        case NUMERIC_COMPACTION_MODE_LATCH: {\r
+          codeIndex = numericCompaction(codewords, codeIndex, result);\r
+          break;\r
+        }\r
+        case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
+          codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
+          break;\r
+        }\r
+        case BYTE_COMPACTION_MODE_LATCH_6: {\r
+          codeIndex = byteCompaction(code, codewords, codeIndex, result);\r
+          break;\r
+        }\r
+        default: {\r
+          // Default to text compaction. During testing numerous barcodes\r
+          // appeared to be missing the starting mode. In these cases defaulting\r
+          // to text compaction seems to work.\r
+          codeIndex--;\r
+          codeIndex = textCompaction(codewords, codeIndex, result);\r
+          break;\r
+        }\r
+      }\r
+      if (codeIndex < codewords.length) {\r
+        code = codewords[codeIndex++];\r
+      } else {\r
+        throw ReaderException.getInstance();\r
+      }\r
+    }\r
+    return new DecoderResult(null, result.toString(), null, null);\r
+  }\r
+\r
+  /**\r
+   * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be\r
+   * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as\r
+   * well as selected control characters.\r
+   *\r
+   * @param codewords The array of codewords (data + error)\r
+   * @param codeIndex The current index into the codeword array.\r
+   * @param result    The decoded data is appended to the result.\r
+   * @return The next index into the codeword array.\r
+   */\r
+  private static int textCompaction(int[] codewords, int codeIndex, StringBuffer result) {\r
+    // 2 character per codeword\r
+    int[] textCompactionData = new int[codewords[0] << 1];\r
+    // Used to hold the byte compaction value if there is a mode shift\r
+    int[] byteCompactionData = new int[codewords[0] << 1];\r
+\r
+    int index = 0;\r
+    boolean end = false;\r
+    while ((codeIndex < codewords[0]) && !end) {\r
+      int code = codewords[codeIndex++];\r
+      if (code < TEXT_COMPACTION_MODE_LATCH) {\r
+        textCompactionData[index] = code / 30;\r
+        textCompactionData[index + 1] = code % 30;\r
+        index += 2;\r
+      } else {\r
+        switch (code) {\r
+          case TEXT_COMPACTION_MODE_LATCH: {\r
+            codeIndex--;\r
+            end = true;\r
+            break;\r
+          }\r
+          case BYTE_COMPACTION_MODE_LATCH: {\r
+            codeIndex--;\r
+            end = true;\r
+            break;\r
+          }\r
+          case NUMERIC_COMPACTION_MODE_LATCH: {\r
+            codeIndex--;\r
+            end = true;\r
+            break;\r
+          }\r
+          case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {\r
+            // The Mode Shift codeword 913 shall cause a temporary\r
+            // switch from Text Compaction mode to Byte Compaction mode.\r
+            // This switch shall be in effect for only the next codeword,\r
+            // after which the mode shall revert to the prevailing sub-mode\r
+            // of the Text Compaction mode. Codeword 913 is only available\r
+            // in Text Compaction mode; its use is described in 5.4.2.4.\r
+            textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;\r
+            byteCompactionData[index] = code; //Integer.toHexString(code);\r
+            index++;\r
+            break;\r
+          }\r
+          case BYTE_COMPACTION_MODE_LATCH_6: {\r
+            codeIndex--;\r
+            end = true;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+    decodeTextCompaction(textCompactionData, byteCompactionData, index, result);\r
+    return codeIndex;\r
+  }\r
+\r
+  /**\r
+   * The Text Compaction mode includes all the printable ASCII characters\r
+   * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab\r
+   * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage\r
+   * return (ASCII value 13). The Text Compaction mode also includes various latch\r
+   * and shift characters which are used exclusively within the mode. The Text\r
+   * Compaction mode encodes up to 2 characters per codeword. The compaction rules\r
+   * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode\r
+   * switches are defined in 5.4.2.3.\r
+   *\r
+   * @param textCompactionData The text compaction data.\r
+   * @param byteCompactionData The byte compaction data if there\r
+   *                           was a mode shift.\r
+   * @param length             The size of the text compaction and byte compaction data.\r
+   * @param result             The decoded data is appended to the result.\r
+   */\r
+  private static void decodeTextCompaction(int[] textCompactionData,\r
+                                           int[] byteCompactionData,\r
+                                           int length,\r
+                                           StringBuffer result) {\r
+    // Beginning from an initial state of the Alpha sub-mode\r
+    // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text\r
+    // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text\r
+    // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.\r
+    int subMode = ALPHA;\r
+    int priorToShiftMode = ALPHA;\r
+    int i = 0;\r
+    while (i < length) {\r
+      int subModeCh = textCompactionData[i];\r
+      char ch = 0;\r
+      switch (subMode) {\r
+        case ALPHA:\r
+          // Alpha (uppercase alphabetic)\r
+          if (subModeCh < 26) {\r
+            // Upper case Alpha Character\r
+            ch = (char) ('A' + subModeCh);\r
+          } else {\r
+            if (subModeCh == 26) {\r
+              ch = ' ';\r
+            } else if (subModeCh == LL) {\r
+              subMode = LOWER;\r
+            } else if (subModeCh == ML) {\r
+              subMode = MIXED;\r
+            } else if (subModeCh == PS) {\r
+              // Shift to punctuation\r
+              priorToShiftMode = subMode;\r
+              subMode = PUNCT_SHIFT;\r
+            } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
+              result.append((char) byteCompactionData[i]);\r
+            }\r
+          }\r
+          break;\r
+\r
+        case LOWER:\r
+          // Lower (lowercase alphabetic)\r
+          if (subModeCh < 26) {\r
+            ch = (char) ('a' + subModeCh);\r
+          } else {\r
+            if (subModeCh == 26) {\r
+              ch = ' ';\r
+            } else if (subModeCh == AL) {\r
+              subMode = ALPHA;\r
+            } else if (subModeCh == ML) {\r
+              subMode = MIXED;\r
+            } else if (subModeCh == PS) {\r
+              // Shift to punctuation\r
+              priorToShiftMode = subMode;\r
+              subMode = PUNCT_SHIFT;\r
+            } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
+              result.append((char) byteCompactionData[i]);\r
+            }\r
+          }\r
+          break;\r
+\r
+        case MIXED:\r
+          // Mixed (numeric and some punctuation)\r
+          if (subModeCh < PL) {\r
+            ch = MIXED_CHARS[subModeCh];\r
+          } else {\r
+            if (subModeCh == PL) {\r
+              subMode = PUNCT;\r
+            } else if (subModeCh == 26) {\r
+              ch = ' ';\r
+            } else if (subModeCh == AS) {\r
+              //mode_change = true;\r
+            } else if (subModeCh == AL) {\r
+              subMode = ALPHA;\r
+            } else if (subModeCh == PS) {\r
+              // Shift to punctuation\r
+              priorToShiftMode = subMode;\r
+              subMode = PUNCT_SHIFT;\r
+            } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
+              result.append((char) byteCompactionData[i]);\r
+            }\r
+          }\r
+          break;\r
+\r
+        case PUNCT:\r
+          // Punctuation\r
+          if (subModeCh < PS) {\r
+            ch = PUNCT_CHARS[subModeCh];\r
+          } else {\r
+            if (subModeCh == PAL) {\r
+              subMode = ALPHA;\r
+            } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {\r
+              result.append((char) byteCompactionData[i]);\r
+            }\r
+          }\r
+          break;\r
+\r
+        case PUNCT_SHIFT:\r
+          // Restore sub-mode\r
+          subMode = priorToShiftMode;\r
+          if (subModeCh < PS) {\r
+            ch = PUNCT_CHARS[subModeCh];\r
+          } else {\r
+            if (subModeCh == PAL) {\r
+              subMode = ALPHA;\r
+            }\r
+          }\r
+          break;\r
+      }\r
+      if (ch != 0) {\r
+        // Append decoded character to result\r
+        result.append(ch);\r
+      }\r
+      i++;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.\r
+   * This includes all ASCII characters value 0 to 127 inclusive and provides for international\r
+   * character set support.\r
+   *\r
+   * @param mode      The byte compaction mode i.e. 901 or 924\r
+   * @param codewords The array of codewords (data + error)\r
+   * @param codeIndex The current index into the codeword array.\r
+   * @param result    The decoded data is appended to the result.\r
+   * @return The next index into the codeword array.\r
+   */\r
+  private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuffer result) {\r
+    if (mode == BYTE_COMPACTION_MODE_LATCH) {\r
+      // Total number of Byte Compaction characters to be encoded\r
+      // is not a multiple of 6\r
+      int count = 0;\r
+      long value = 0;\r
+      char[] decodedData = new char[6];\r
+      int[] byteCompactedCodewords = new int[6];\r
+      boolean end = false;\r
+      while ((codeIndex < codewords[0]) && !end) {\r
+        int code = codewords[codeIndex++];\r
+        if (code < TEXT_COMPACTION_MODE_LATCH) {\r
+          byteCompactedCodewords[count] = code;\r
+          count++;\r
+          // Base 900\r
+          value *= 900;\r
+          value += code;\r
+        } else {\r
+          if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
+              (code == BYTE_COMPACTION_MODE_LATCH) ||\r
+              (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
+              (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
+              (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
+              (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
+              (code == MACRO_PDF417_TERMINATOR)) {\r
+          }\r
+          codeIndex--;\r
+          end = true;\r
+        }\r
+        if ((count % 5 == 0) && (count > 0)) {\r
+          // Decode every 5 codewords\r
+          // Convert to Base 256\r
+          for (int j = 0; j < 6; ++j) {\r
+            decodedData[5 - j] = (char) (value % 256);\r
+            value >>= 8;\r
+          }\r
+          result.append(decodedData);\r
+          count = 0;\r
         }\r
-               // Multiply by tens\r
-               for (int j = 0; j < tens ; j++) {\r
-                       result = add(result.toString(), (value1 + "0").substring(1));\r
-               }\r
-               // Multiply by hundreds\r
-               for (int j = 0; j < hundreds ; j++) {\r
-                       result = add(result.toString(), (value1 + "00").substring(2));\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * Add two numbers which are represented as strings.\r
-        * @param value1\r
-        * @param value2\r
-        * @return the result of value1 + value2\r
-        */\r
-       private static StringBuffer add(String value1, String value2) {\r
-               StringBuffer temp1 = new StringBuffer(5);\r
-               StringBuffer temp2 = new StringBuffer(5);\r
-               StringBuffer result = new StringBuffer(value1.length());\r
-               for (int i = 0; i < value1.length(); i++) {\r
-                       // Put zeros into the result.\r
-                       result.append('0');\r
-               }\r
-               int carry = 0;\r
-               for (int i = value1.length()-3; i >  -1 ; i-=3) {\r
-                       \r
-                       temp1.setLength(0);\r
-                       temp1.append(value1.charAt(i));\r
-                       temp1.append(value1.charAt(i + 1));\r
-                       temp1.append(value1.charAt(i + 2));\r
-\r
-                       temp2.setLength(0);\r
-                       temp2.append(value2.charAt(i));\r
-                       temp2.append(value2.charAt(i + 1));\r
-                       temp2.append(value2.charAt(i + 2));\r
-\r
-                       int intValue1 = Integer.parseInt(temp1.toString());\r
-                       int intValue2 = Integer.parseInt(temp2.toString());\r
-\r
-                       int sumval = ( intValue1 + intValue2 + carry) % 1000;\r
-                       carry = (intValue1 + intValue2 + carry) / 1000;\r
-            \r
-                       result.setCharAt(i + 2, (char)((sumval % 10) + '0'));\r
-                       result.setCharAt(i + 1, (char)(((sumval / 10) % 10) + '0'));\r
-                       result.setCharAt(i, (char) (( sumval / 100) + '0'));\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /*      \r
-       private static String decodeBase900toBase10(int codewords[], int count) {\r
-               BigInteger accum = BigInteger.valueOf(0);\r
-               BigInteger value = null;\r
-               for (int i = 0; i < count; i++) {\r
-                       value = BigInteger.valueOf(900).pow(count - i - 1);\r
-                       value = value.multiply(BigInteger.valueOf(codewords[i]));\r
-                       accum = accum.add(value);\r
-               }\r
-               if (debug) System.out.println("Big Integer " + accum);\r
-               String result = accum.toString().substring(1);\r
-               return result;\r
-       }\r
-       */      \r
+      }\r
+      // If Byte Compaction mode is invoked with codeword 901,\r
+      // the final group of codewords is interpreted directly\r
+      // as one byte per codeword, without compaction.\r
+      for (int i = ((count / 5) * 5); i < count; i++) {\r
+        result.append((char) byteCompactedCodewords[i]);\r
+      }\r
+\r
+    } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {\r
+      // Total number of Byte Compaction characters to be encoded\r
+      // is an integer multiple of 6\r
+      int count = 0;\r
+      long value = 0;\r
+      boolean end = false;\r
+      while ((codeIndex < codewords[0]) && !end) {\r
+        int code = codewords[codeIndex++];\r
+        if (code < TEXT_COMPACTION_MODE_LATCH) {\r
+          count += 1;\r
+          // Base 900\r
+          value *= 900;\r
+          value += code;\r
+        } else {\r
+          if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
+              (code == BYTE_COMPACTION_MODE_LATCH) ||\r
+              (code == NUMERIC_COMPACTION_MODE_LATCH) ||\r
+              (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
+              (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
+              (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
+              (code == MACRO_PDF417_TERMINATOR)) {\r
+          }\r
+          codeIndex--;\r
+          end = true;\r
+        }\r
+        if ((count % 5 == 0) && (count > 0)) {\r
+          // Decode every 5 codewords\r
+          // Convert to Base 256\r
+          char[] decodedData = new char[6];\r
+          for (int j = 0; j < 6; ++j) {\r
+            decodedData[5 - j] = (char) (value % 256);\r
+            value >>= 8;\r
+          }\r
+          result.append(decodedData);\r
+        }\r
+      }\r
+    }\r
+    return codeIndex;\r
+  }\r
+\r
+  /**\r
+   * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.\r
+   *\r
+   * @param codewords The array of codewords (data + error)\r
+   * @param codeIndex The current index into the codeword array.\r
+   * @param result    The decoded data is appended to the result.\r
+   * @return The next index into the codeword array.\r
+   */\r
+  private static int numericCompaction(int[] codewords, int codeIndex, StringBuffer result) {\r
+    int count = 0;\r
+    boolean end = false;\r
+\r
+    int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];\r
+\r
+    while ((codeIndex < codewords.length) && !end) {\r
+      int code = codewords[codeIndex++];\r
+      if (code < TEXT_COMPACTION_MODE_LATCH) {\r
+        numericCodewords[count] = code;\r
+        count++;\r
+      } else {\r
+        if ((code == TEXT_COMPACTION_MODE_LATCH) ||\r
+            (code == BYTE_COMPACTION_MODE_LATCH) ||\r
+            (code == BYTE_COMPACTION_MODE_LATCH_6) ||\r
+            (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||\r
+            (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||\r
+            (code == MACRO_PDF417_TERMINATOR)) {\r
+        }\r
+        codeIndex--;\r
+        end = true;\r
+      }\r
+      if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||\r
+          code == NUMERIC_COMPACTION_MODE_LATCH) {\r
+        // Re-invoking Numeric Compaction mode (by using codeword 902\r
+        // while in Numeric Compaction mode) serves  to terminate the\r
+        // current Numeric Compaction mode grouping as described in 5.4.4.2,\r
+        // and then to start a new one grouping.\r
+        String s = decodeBase900toBase10(numericCodewords, count);\r
+        result.append(s);\r
+        count = 0;\r
+      }\r
+    }\r
+    return codeIndex;\r
+  }\r
+\r
+  /**\r
+   * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.\r
+   *\r
+   * @param codewords The array of codewords\r
+   * @param count     The number of codewords\r
+   * @return The decoded string representing the Numeric data.\r
+   */\r
+  /*\r
+     EXAMPLE\r
+     Encode the fifteen digit numeric string 000213298174000\r
+     Prefix the numeric string with a 1 and set the initial value of\r
+     t = 1 000 213 298 174 000\r
+     Calculate codeword 0\r
+     d0 = 1 000 213 298 174 000 mod 900 = 200\r
+\r
+     t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082\r
+     Calculate codeword 1\r
+     d1 = 1 111 348 109 082 mod 900 = 282\r
+\r
+     t = 1 111 348 109 082 div 900 = 1 234 831 232\r
+     Calculate codeword 2\r
+     d2 = 1 234 831 232 mod 900 = 632\r
+\r
+     t = 1 234 831 232 div 900 = 1 372 034\r
+     Calculate codeword 3\r
+     d3 = 1 372 034 mod 900 = 434\r
+\r
+     t = 1 372 034 div 900 = 1 524\r
+     Calculate codeword 4\r
+     d4 = 1 524 mod 900 = 624\r
+\r
+     t = 1 524 div 900 = 1\r
+     Calculate codeword 5\r
+     d5 = 1 mod 900 = 1\r
+     t = 1 div 900 = 0\r
+     Codeword sequence is: 1, 624, 434, 632, 282, 200\r
+\r
+     Decode the above codewords involves\r
+       1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +\r
+     632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000\r
+\r
+     Remove leading 1 =>  Result is 000213298174000\r
+\r
+     As there are huge numbers involved here we must use fake out the maths using string\r
+     tokens for the numbers.\r
+     BigDecimal is not supported by J2ME.\r
+   */\r
+  private static String decodeBase900toBase10(int[] codewords, int count) {\r
+    StringBuffer accum = null;\r
+    for (int i = 0; i < count; i++) {\r
+      StringBuffer value = multiply(EXP900[count - i - 1], codewords[i]);\r
+      if (accum == null) {\r
+        // First time in accum=0\r
+        accum = value;\r
+      } else {\r
+        accum = add(accum.toString(), value.toString());\r
+      }\r
+    }\r
+    String result = null;\r
+    // Remove leading '1' which was inserted to preserve\r
+    // leading zeros\r
+    for (int i = 0; i < accum.length(); i++) {\r
+      if (accum.charAt(i) == '1') {\r
+        //result = accum.substring(i + 1);\r
+        result = accum.toString().substring(i + 1);\r
+        break;\r
+      }\r
+    }\r
+    if (result == null) {\r
+      // No leading 1 => just write the converted number.\r
+      result = accum.toString();\r
+    }\r
+    return result;\r
+  }\r
+\r
+  /**\r
+   * Multiplies two String numbers\r
+   *\r
+   * @param value1 Any number represented as a string.\r
+   * @param value2 A number <= 999.\r
+   * @return the result of value1 * value2.\r
+   */\r
+  private static StringBuffer multiply(String value1, int value2) {\r
+    StringBuffer result = new StringBuffer(value1.length());\r
+    for (int i = 0; i < value1.length(); i++) {\r
+      // Put zeros into the result.\r
+      result.append('0');\r
+    }\r
+    int hundreds = value2 / 100;\r
+    int tens = (value2 / 10) % 10;\r
+    int ones = value2 % 10;\r
+    // Multiply by ones\r
+    for (int j = 0; j < ones; j++) {\r
+      result = add(result.toString(), value1);\r
+    }\r
+    // Multiply by tens\r
+    for (int j = 0; j < tens; j++) {\r
+      result = add(result.toString(), (value1 + '0').substring(1));\r
+    }\r
+    // Multiply by hundreds\r
+    for (int j = 0; j < hundreds; j++) {\r
+      result = add(result.toString(), (value1 + "00").substring(2));\r
+    }\r
+    return result;\r
+  }\r
+\r
+  /**\r
+   * Add two numbers which are represented as strings.\r
+   *\r
+   * @param value1\r
+   * @param value2\r
+   * @return the result of value1 + value2\r
+   */\r
+  private static StringBuffer add(String value1, String value2) {\r
+    StringBuffer temp1 = new StringBuffer(5);\r
+    StringBuffer temp2 = new StringBuffer(5);\r
+    StringBuffer result = new StringBuffer(value1.length());\r
+    for (int i = 0; i < value1.length(); i++) {\r
+      // Put zeros into the result.\r
+      result.append('0');\r
+    }\r
+    int carry = 0;\r
+    for (int i = value1.length() - 3; i > -1; i -= 3) {\r
+\r
+      temp1.setLength(0);\r
+      temp1.append(value1.charAt(i));\r
+      temp1.append(value1.charAt(i + 1));\r
+      temp1.append(value1.charAt(i + 2));\r
+\r
+      temp2.setLength(0);\r
+      temp2.append(value2.charAt(i));\r
+      temp2.append(value2.charAt(i + 1));\r
+      temp2.append(value2.charAt(i + 2));\r
+\r
+      int intValue1 = Integer.parseInt(temp1.toString());\r
+      int intValue2 = Integer.parseInt(temp2.toString());\r
+\r
+      int sumval = (intValue1 + intValue2 + carry) % 1000;\r
+      carry = (intValue1 + intValue2 + carry) / 1000;\r
+\r
+      result.setCharAt(i + 2, (char) ((sumval % 10) + '0'));\r
+      result.setCharAt(i + 1, (char) (((sumval / 10) % 10) + '0'));\r
+      result.setCharAt(i, (char) ((sumval / 100) + '0'));\r
+    }\r
+    return result;\r
+  }\r
+\r
+  /*\r
+   private static String decodeBase900toBase10(int codewords[], int count) {\r
+     BigInteger accum = BigInteger.valueOf(0);\r
+     BigInteger value = null;\r
+     for (int i = 0; i < count; i++) {\r
+       value = BigInteger.valueOf(900).pow(count - i - 1);\r
+       value = value.multiply(BigInteger.valueOf(codewords[i]));\r
+       accum = accum.add(value);\r
+     }\r
+     if (debug) System.out.println("Big Integer " + accum);\r
+     String result = accum.toString().substring(1);\r
+     return result;\r
+   }\r
+   */\r
 }\r