/*\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
* 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
* @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