PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/silverlight/datamatrix/decoder/DecodedBitStreamParser.cs

https://bitbucket.org/jrasanen/silverlightzxing
C# | 627 lines | 480 code | 46 blank | 101 comment | 130 complexity | 531486f14f72651415bb0233454954db MD5 | raw file
  1. /*
  2. * Copyright 2008 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using ReaderException = com.google.zxing.ReaderException;
  18. using BitSource = com.google.zxing.common.BitSource;
  19. using DecoderResult = com.google.zxing.common.DecoderResult;
  20. namespace com.google.zxing.datamatrix.decoder
  21. {
  22. /// <summary> <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes
  23. /// in one Data Matrix Code. This class decodes the bits back into text.</p>
  24. ///
  25. /// <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
  26. ///
  27. /// </summary>
  28. /// <author> bbrown@google.com (Brian Brown)
  29. /// </author>
  30. /// <author> Sean Owen
  31. /// </author>
  32. /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
  33. /// </author>
  34. sealed class DecodedBitStreamParser
  35. {
  36. /// <summary> See ISO 16022:2006, Annex C Table C.1
  37. /// The C40 Basic Character Set (*'s used for placeholders for the shift values)
  38. /// </summary>
  39. //UPGRADE_NOTE: Final was removed from the declaration of 'C40_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
  40. private static readonly char[] C40_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
  41. //UPGRADE_NOTE: Final was removed from the declaration of 'C40_SHIFT2_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
  42. private static readonly char[] C40_SHIFT2_SET_CHARS = new char[]{'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'};
  43. /// <summary> See ISO 16022:2006, Annex C Table C.2
  44. /// The Text Basic Character Set (*'s used for placeholders for the shift values)
  45. /// </summary>
  46. //UPGRADE_NOTE: Final was removed from the declaration of 'TEXT_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
  47. private static readonly char[] TEXT_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
  48. private static char[] TEXT_SHIFT3_SET_CHARS = new char[]{'\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127};
  49. private const int PAD_ENCODE = 0; // Not really an encoding
  50. private const int ASCII_ENCODE = 1;
  51. private const int C40_ENCODE = 2;
  52. private const int TEXT_ENCODE = 3;
  53. private const int ANSIX12_ENCODE = 4;
  54. private const int EDIFACT_ENCODE = 5;
  55. private const int BASE256_ENCODE = 6;
  56. private DecodedBitStreamParser()
  57. {
  58. }
  59. internal static DecoderResult decode(sbyte[] bytes)
  60. {
  61. BitSource bits = new BitSource(bytes);
  62. System.Text.StringBuilder result = new System.Text.StringBuilder(100);
  63. System.Text.StringBuilder resultTrailer = new System.Text.StringBuilder(0);
  64. System.Collections.Generic.List<Object> byteSegments = new System.Collections.Generic.List<Object>(1); //GregBray: Removed Synchronized wrapper
  65. int mode = ASCII_ENCODE;
  66. do
  67. {
  68. if (mode == ASCII_ENCODE)
  69. {
  70. mode = decodeAsciiSegment(bits, result, resultTrailer);
  71. }
  72. else
  73. {
  74. switch (mode)
  75. {
  76. case C40_ENCODE:
  77. decodeC40Segment(bits, result);
  78. break;
  79. case TEXT_ENCODE:
  80. decodeTextSegment(bits, result);
  81. break;
  82. case ANSIX12_ENCODE:
  83. decodeAnsiX12Segment(bits, result);
  84. break;
  85. case EDIFACT_ENCODE:
  86. decodeEdifactSegment(bits, result);
  87. break;
  88. case BASE256_ENCODE:
  89. decodeBase256Segment(bits, result, byteSegments);
  90. break;
  91. default:
  92. throw ReaderException.Instance;
  93. }
  94. mode = ASCII_ENCODE;
  95. }
  96. }
  97. while (mode != PAD_ENCODE && bits.available() > 0);
  98. if (resultTrailer.Length > 0)
  99. {
  100. result.Append(resultTrailer.ToString());
  101. }
  102. return new DecoderResult(bytes, result.ToString(), (byteSegments.Count == 0)?null:byteSegments, null);
  103. }
  104. /// <summary> See ISO 16022:2006, 5.2.3 and Annex C, Table C.2</summary>
  105. private static int decodeAsciiSegment(BitSource bits, System.Text.StringBuilder result, System.Text.StringBuilder resultTrailer)
  106. {
  107. bool upperShift = false;
  108. do
  109. {
  110. int oneByte = bits.readBits(8);
  111. if (oneByte == 0)
  112. {
  113. throw ReaderException.Instance;
  114. }
  115. else if (oneByte <= 128)
  116. {
  117. // ASCII data (ASCII value + 1)
  118. oneByte = upperShift?(oneByte + 128):oneByte;
  119. upperShift = false;
  120. result.Append((char) (oneByte - 1));
  121. return ASCII_ENCODE;
  122. }
  123. else if (oneByte == 129)
  124. {
  125. // Pad
  126. return PAD_ENCODE;
  127. }
  128. else if (oneByte <= 229)
  129. {
  130. // 2-digit data 00-99 (Numeric Value + 130)
  131. int value_Renamed = oneByte - 130;
  132. if (value_Renamed < 10)
  133. {
  134. // padd with '0' for single digit values
  135. result.Append('0');
  136. }
  137. result.Append(value_Renamed);
  138. }
  139. else if (oneByte == 230)
  140. {
  141. // Latch to C40 encodation
  142. return C40_ENCODE;
  143. }
  144. else if (oneByte == 231)
  145. {
  146. // Latch to Base 256 encodation
  147. return BASE256_ENCODE;
  148. }
  149. else if (oneByte == 232)
  150. {
  151. // FNC1
  152. //throw ReaderException.getInstance();
  153. // Ignore this symbol for now
  154. }
  155. else if (oneByte == 233)
  156. {
  157. // Structured Append
  158. //throw ReaderException.getInstance();
  159. // Ignore this symbol for now
  160. }
  161. else if (oneByte == 234)
  162. {
  163. // Reader Programming
  164. //throw ReaderException.getInstance();
  165. // Ignore this symbol for now
  166. }
  167. else if (oneByte == 235)
  168. {
  169. // Upper Shift (shift to Extended ASCII)
  170. upperShift = true;
  171. }
  172. else if (oneByte == 236)
  173. {
  174. // 05 Macro
  175. result.Append("[)>\u001E05\u001D");
  176. resultTrailer.Insert(0, "\u001E\u0004");
  177. }
  178. else if (oneByte == 237)
  179. {
  180. // 06 Macro
  181. result.Append("[)>\u001E06\u001D");
  182. resultTrailer.Insert(0, "\u001E\u0004");
  183. }
  184. else if (oneByte == 238)
  185. {
  186. // Latch to ANSI X12 encodation
  187. return ANSIX12_ENCODE;
  188. }
  189. else if (oneByte == 239)
  190. {
  191. // Latch to Text encodation
  192. return TEXT_ENCODE;
  193. }
  194. else if (oneByte == 240)
  195. {
  196. // Latch to EDIFACT encodation
  197. return EDIFACT_ENCODE;
  198. }
  199. else if (oneByte == 241)
  200. {
  201. // ECI Character
  202. // TODO(bbrown): I think we need to support ECI
  203. //throw ReaderException.getInstance();
  204. // Ignore this symbol for now
  205. }
  206. else if (oneByte >= 242)
  207. {
  208. // Not to be used in ASCII encodation
  209. throw ReaderException.Instance;
  210. }
  211. }
  212. while (bits.available() > 0);
  213. return ASCII_ENCODE;
  214. }
  215. /// <summary> See ISO 16022:2006, 5.2.5 and Annex C, Table C.1</summary>
  216. private static void decodeC40Segment(BitSource bits, System.Text.StringBuilder result)
  217. {
  218. // Three C40 values are encoded in a 16-bit value as
  219. // (1600 * C1) + (40 * C2) + C3 + 1
  220. // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
  221. bool upperShift = false;
  222. int[] cValues = new int[3];
  223. do
  224. {
  225. // If there is only one byte left then it will be encoded as ASCII
  226. if (bits.available() == 8)
  227. {
  228. return ;
  229. }
  230. int firstByte = bits.readBits(8);
  231. if (firstByte == 254)
  232. {
  233. // Unlatch codeword
  234. return ;
  235. }
  236. parseTwoBytes(firstByte, bits.readBits(8), cValues);
  237. int shift = 0;
  238. for (int i = 0; i < 3; i++)
  239. {
  240. int cValue = cValues[i];
  241. switch (shift)
  242. {
  243. case 0:
  244. if (cValue < 3)
  245. {
  246. shift = cValue + 1;
  247. }
  248. else
  249. {
  250. if (upperShift)
  251. {
  252. result.Append((char) (C40_BASIC_SET_CHARS[cValue] + 128));
  253. upperShift = false;
  254. }
  255. else
  256. {
  257. result.Append(C40_BASIC_SET_CHARS[cValue]);
  258. }
  259. }
  260. break;
  261. case 1:
  262. if (upperShift)
  263. {
  264. result.Append((char) (cValue + 128));
  265. upperShift = false;
  266. }
  267. else
  268. {
  269. result.Append(cValue);
  270. }
  271. shift = 0;
  272. break;
  273. case 2:
  274. if (cValue < 27)
  275. {
  276. if (upperShift)
  277. {
  278. result.Append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
  279. upperShift = false;
  280. }
  281. else
  282. {
  283. result.Append(C40_SHIFT2_SET_CHARS[cValue]);
  284. }
  285. }
  286. else if (cValue == 27)
  287. {
  288. // FNC1
  289. throw ReaderException.Instance;
  290. }
  291. else if (cValue == 30)
  292. {
  293. // Upper Shift
  294. upperShift = true;
  295. }
  296. else
  297. {
  298. throw ReaderException.Instance;
  299. }
  300. shift = 0;
  301. break;
  302. case 3:
  303. if (upperShift)
  304. {
  305. result.Append((char) (cValue + 224));
  306. upperShift = false;
  307. }
  308. else
  309. {
  310. result.Append((char) (cValue + 96));
  311. }
  312. shift = 0;
  313. break;
  314. default:
  315. throw ReaderException.Instance;
  316. }
  317. }
  318. }
  319. while (bits.available() > 0);
  320. }
  321. /// <summary> See ISO 16022:2006, 5.2.6 and Annex C, Table C.2</summary>
  322. private static void decodeTextSegment(BitSource bits, System.Text.StringBuilder result)
  323. {
  324. // Three Text values are encoded in a 16-bit value as
  325. // (1600 * C1) + (40 * C2) + C3 + 1
  326. // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
  327. bool upperShift = false;
  328. int[] cValues = new int[3];
  329. do
  330. {
  331. // If there is only one byte left then it will be encoded as ASCII
  332. if (bits.available() == 8)
  333. {
  334. return ;
  335. }
  336. int firstByte = bits.readBits(8);
  337. if (firstByte == 254)
  338. {
  339. // Unlatch codeword
  340. return ;
  341. }
  342. parseTwoBytes(firstByte, bits.readBits(8), cValues);
  343. int shift = 0;
  344. for (int i = 0; i < 3; i++)
  345. {
  346. int cValue = cValues[i];
  347. switch (shift)
  348. {
  349. case 0:
  350. if (cValue < 3)
  351. {
  352. shift = cValue + 1;
  353. }
  354. else
  355. {
  356. if (upperShift)
  357. {
  358. result.Append((char) (TEXT_BASIC_SET_CHARS[cValue] + 128));
  359. upperShift = false;
  360. }
  361. else
  362. {
  363. result.Append(TEXT_BASIC_SET_CHARS[cValue]);
  364. }
  365. }
  366. break;
  367. case 1:
  368. if (upperShift)
  369. {
  370. result.Append((char) (cValue + 128));
  371. upperShift = false;
  372. }
  373. else
  374. {
  375. result.Append(cValue);
  376. }
  377. shift = 0;
  378. break;
  379. case 2:
  380. // Shift 2 for Text is the same encoding as C40
  381. if (cValue < 27)
  382. {
  383. if (upperShift)
  384. {
  385. result.Append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));
  386. upperShift = false;
  387. }
  388. else
  389. {
  390. result.Append(C40_SHIFT2_SET_CHARS[cValue]);
  391. }
  392. }
  393. else if (cValue == 27)
  394. {
  395. // FNC1
  396. throw ReaderException.Instance;
  397. }
  398. else if (cValue == 30)
  399. {
  400. // Upper Shift
  401. upperShift = true;
  402. }
  403. else
  404. {
  405. throw ReaderException.Instance;
  406. }
  407. shift = 0;
  408. break;
  409. case 3:
  410. if (upperShift)
  411. {
  412. result.Append((char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128));
  413. upperShift = false;
  414. }
  415. else
  416. {
  417. result.Append(TEXT_SHIFT3_SET_CHARS[cValue]);
  418. }
  419. shift = 0;
  420. break;
  421. default:
  422. throw ReaderException.Instance;
  423. }
  424. }
  425. }
  426. while (bits.available() > 0);
  427. }
  428. /// <summary> See ISO 16022:2006, 5.2.7</summary>
  429. private static void decodeAnsiX12Segment(BitSource bits, System.Text.StringBuilder result)
  430. {
  431. // Three ANSI X12 values are encoded in a 16-bit value as
  432. // (1600 * C1) + (40 * C2) + C3 + 1
  433. int[] cValues = new int[3];
  434. do
  435. {
  436. // If there is only one byte left then it will be encoded as ASCII
  437. if (bits.available() == 8)
  438. {
  439. return ;
  440. }
  441. int firstByte = bits.readBits(8);
  442. if (firstByte == 254)
  443. {
  444. // Unlatch codeword
  445. return ;
  446. }
  447. parseTwoBytes(firstByte, bits.readBits(8), cValues);
  448. for (int i = 0; i < 3; i++)
  449. {
  450. int cValue = cValues[i];
  451. if (cValue == 0)
  452. {
  453. // X12 segment terminator <CR>
  454. result.Append('\r');
  455. }
  456. else if (cValue == 1)
  457. {
  458. // X12 segment separator *
  459. result.Append('*');
  460. }
  461. else if (cValue == 2)
  462. {
  463. // X12 sub-element separator >
  464. result.Append('>');
  465. }
  466. else if (cValue == 3)
  467. {
  468. // space
  469. result.Append(' ');
  470. }
  471. else if (cValue < 14)
  472. {
  473. // 0 - 9
  474. result.Append((char) (cValue + 44));
  475. }
  476. else if (cValue < 40)
  477. {
  478. // A - Z
  479. result.Append((char) (cValue + 51));
  480. }
  481. else
  482. {
  483. throw ReaderException.Instance;
  484. }
  485. }
  486. }
  487. while (bits.available() > 0);
  488. }
  489. private static void parseTwoBytes(int firstByte, int secondByte, int[] result)
  490. {
  491. int fullBitValue = (firstByte << 8) + secondByte - 1;
  492. int temp = fullBitValue / 1600;
  493. result[0] = temp;
  494. fullBitValue -= temp * 1600;
  495. temp = fullBitValue / 40;
  496. result[1] = temp;
  497. result[2] = fullBitValue - temp * 40;
  498. }
  499. /// <summary> See ISO 16022:2006, 5.2.8 and Annex C Table C.3</summary>
  500. private static void decodeEdifactSegment(BitSource bits, System.Text.StringBuilder result)
  501. {
  502. bool unlatch = false;
  503. do
  504. {
  505. // If there is only two or less bytes left then it will be encoded as ASCII
  506. if (bits.available() <= 16)
  507. {
  508. return ;
  509. }
  510. for (int i = 0; i < 4; i++)
  511. {
  512. int edifactValue = bits.readBits(6);
  513. // Check for the unlatch character
  514. if (edifactValue == 0x2B67)
  515. {
  516. // 011111
  517. unlatch = true;
  518. // If we encounter the unlatch code then continue reading because the Codeword triple
  519. // is padded with 0's
  520. }
  521. if (!unlatch)
  522. {
  523. if ((edifactValue & 32) == 0)
  524. {
  525. // no 1 in the leading (6th) bit
  526. edifactValue |= 64; // Add a leading 01 to the 6 bit binary value
  527. }
  528. result.Append(edifactValue);
  529. }
  530. }
  531. }
  532. while (!unlatch && bits.available() > 0);
  533. }
  534. /// <summary> See ISO 16022:2006, 5.2.9 and Annex B, B.2</summary>
  535. private static void decodeBase256Segment(BitSource bits, System.Text.StringBuilder result, System.Collections.Generic.List <Object> byteSegments)
  536. {
  537. // Figure out how long the Base 256 Segment is.
  538. int d1 = bits.readBits(8);
  539. int count;
  540. if (d1 == 0)
  541. {
  542. // Read the remainder of the symbol
  543. count = bits.available() / 8;
  544. }
  545. else if (d1 < 250)
  546. {
  547. count = d1;
  548. }
  549. else
  550. {
  551. count = 250 * (d1 - 249) + bits.readBits(8);
  552. }
  553. sbyte[] bytes = new sbyte[count];
  554. for (int i = 0; i < count; i++)
  555. {
  556. bytes[i] = unrandomize255State(bits.readBits(8), i);
  557. }
  558. byteSegments.Add(SupportClass.ToByteArray(bytes));
  559. try
  560. {
  561. //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"
  562. //result.Append(System.Text.Encoding.GetEncoding("ISO8859_1").GetString(SupportClass.ToByteArray(bytes)));
  563. byte[] btArray = SupportClass.ToByteArray(bytes);
  564. result.Append(System.Text.Encoding.GetEncoding("ISO8859_1").GetString(btArray, 0, btArray.Length)); //GregBray: fixed byte to string conversion.
  565. }
  566. catch (System.IO.IOException uee)
  567. {
  568. //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
  569. throw new System.SystemException("Platform does not support required encoding: " + uee);
  570. }
  571. }
  572. /// <summary> See ISO 16022:2006, Annex B, B.2</summary>
  573. private static sbyte unrandomize255State(int randomizedBase256Codeword, int base256CodewordPosition)
  574. {
  575. int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
  576. int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
  577. return (sbyte) (tempVariable >= 0?tempVariable:(tempVariable + 256));
  578. }
  579. }
  580. }