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