You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ZXPDF417DecodedBitStreamParser.m 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Copyright 2012 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. #import "ZXCharacterSetECI.h"
  17. #import "ZXDecoderResult.h"
  18. #import "ZXErrors.h"
  19. #import "ZXIntArray.h"
  20. #import "ZXPDF417DecodedBitStreamParser.h"
  21. #import "ZXPDF417ResultMetadata.h"
  22. typedef enum {
  23. ZXPDF417ModeAlpha = 0,
  24. ZXPDF417ModeLower,
  25. ZXPDF417ModeMixed,
  26. ZXPDF417ModePunct,
  27. ZXPDF417ModeAlphaShift,
  28. ZXPDF417ModePunctShift
  29. } ZXPDF417Mode;
  30. const int ZX_PDF417_TEXT_COMPACTION_MODE_LATCH = 900;
  31. const int ZX_PDF417_BYTE_COMPACTION_MODE_LATCH = 901;
  32. const int ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH = 902;
  33. const int ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 = 924;
  34. const int ZX_PDF417_ECI_USER_DEFINED = 925;
  35. const int ZX_PDF417_ECI_GENERAL_PURPOSE = 926;
  36. const int ZX_PDF417_ECI_CHARSET = 927;
  37. const int ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;
  38. const int ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
  39. const int ZX_PDF417_MACRO_PDF417_TERMINATOR = 922;
  40. const int ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;
  41. const int ZX_PDF417_MAX_NUMERIC_CODEWORDS = 15;
  42. const int ZX_PDF417_PL = 25;
  43. const int ZX_PDF417_LL = 27;
  44. const int ZX_PDF417_AS = 27;
  45. const int ZX_PDF417_ML = 28;
  46. const int ZX_PDF417_AL = 28;
  47. const int ZX_PDF417_PS = 29;
  48. const int ZX_PDF417_PAL = 29;
  49. const unichar ZX_PDF417_PUNCT_CHARS[] = {
  50. ';', '<', '>', '@', '[', '\\', ']', '_', '`', '~', '!',
  51. '\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*',
  52. '(', ')', '?', '{', '}', '\''};
  53. const unichar ZX_PDF417_MIXED_CHARS[] = {
  54. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',
  55. '\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
  56. '=', '^'};
  57. const int ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS = 2;
  58. const NSStringEncoding ZX_PDF417_DECODING_DEFAULT_ENCODING = NSISOLatin1StringEncoding;
  59. /**
  60. * Table containing values for the exponent of 900.
  61. * This is used in the numeric compaction decode algorithm.
  62. */
  63. static NSArray *ZX_PDF417_EXP900 = nil;
  64. @implementation ZXPDF417DecodedBitStreamParser
  65. + (void)initialize {
  66. if ([self class] != [ZXPDF417DecodedBitStreamParser class]) return;
  67. NSMutableArray *exponents = [NSMutableArray arrayWithCapacity:16];
  68. [exponents addObject:[NSDecimalNumber one]];
  69. NSDecimalNumber *nineHundred = [NSDecimalNumber decimalNumberWithString:@"900"];
  70. [exponents addObject:nineHundred];
  71. for (int i = 2; i < 16; i++) {
  72. [exponents addObject:[exponents[i - 1] decimalNumberByMultiplyingBy:nineHundred]];
  73. }
  74. ZX_PDF417_EXP900 = [[NSArray alloc] initWithArray:exponents];
  75. }
  76. + (ZXDecoderResult *)decode:(ZXIntArray *)codewords ecLevel:(NSString *)ecLevel error:(NSError **)error {
  77. NSMutableString *result = [NSMutableString stringWithCapacity:codewords.length * 2];
  78. NSStringEncoding encoding = ZX_PDF417_DECODING_DEFAULT_ENCODING;
  79. // Get compaction mode
  80. int codeIndex = 1;
  81. int code = codewords.array[codeIndex++];
  82. ZXPDF417ResultMetadata *resultMetadata = [[ZXPDF417ResultMetadata alloc] init];
  83. while (codeIndex < codewords.array[0]) {
  84. switch (code) {
  85. case ZX_PDF417_TEXT_COMPACTION_MODE_LATCH:
  86. codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:result];
  87. break;
  88. case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH:
  89. case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6:
  90. codeIndex = [self byteCompaction:code codewords:codewords encoding:encoding codeIndex:codeIndex result:result];
  91. break;
  92. case ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
  93. [result appendFormat:@"%C", (unichar)codewords.array[codeIndex++]];
  94. break;
  95. case ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH:
  96. codeIndex = [self numericCompaction:codewords codeIndex:codeIndex result:result];
  97. if (codeIndex < 0) {
  98. if (error) *error = ZXFormatErrorInstance();
  99. return nil;
  100. }
  101. break;
  102. case ZX_PDF417_ECI_CHARSET: {
  103. ZXCharacterSetECI *charsetECI =
  104. [ZXCharacterSetECI characterSetECIByValue:codewords.array[codeIndex++]];
  105. encoding = charsetECI.encoding;
  106. break;
  107. }
  108. case ZX_PDF417_ECI_GENERAL_PURPOSE:
  109. // Can't do anything with generic ECI; skip its 2 characters
  110. codeIndex += 2;
  111. break;
  112. case ZX_PDF417_ECI_USER_DEFINED:
  113. // Can't do anything with user ECI; skip its 1 character
  114. codeIndex ++;
  115. break;
  116. case ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK:
  117. codeIndex = [self decodeMacroBlock:codewords codeIndex:codeIndex resultMetadata:resultMetadata];
  118. if (codeIndex < 0) {
  119. if (error) *error = ZXFormatErrorInstance();
  120. return nil;
  121. }
  122. break;
  123. case ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
  124. case ZX_PDF417_MACRO_PDF417_TERMINATOR:
  125. // Should not see these outside a macro block
  126. if (error) *error = ZXFormatErrorInstance();
  127. return nil;
  128. default:
  129. // Default to text compaction. During testing numerous barcodes
  130. // appeared to be missing the starting mode. In these cases defaulting
  131. // to text compaction seems to work.
  132. codeIndex--;
  133. codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:result];
  134. break;
  135. }
  136. if (codeIndex < codewords.length) {
  137. code = codewords.array[codeIndex++];
  138. } else {
  139. if (error) *error = ZXFormatErrorInstance();
  140. return nil;
  141. }
  142. }
  143. if ([result length] == 0) {
  144. if (error) *error = ZXFormatErrorInstance();
  145. return nil;
  146. }
  147. ZXDecoderResult *decoderResult = [[ZXDecoderResult alloc] initWithRawBytes:nil text:result byteSegments:nil ecLevel:ecLevel];
  148. decoderResult.other = resultMetadata;
  149. return decoderResult;
  150. }
  151. + (int)decodeMacroBlock:(ZXIntArray *)codewords codeIndex:(int)codeIndex resultMetadata:(ZXPDF417ResultMetadata *)resultMetadata {
  152. if (codeIndex + ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS > codewords.array[0]) {
  153. // we must have at least two bytes left for the segment index
  154. return -1;
  155. }
  156. ZXIntArray *segmentIndexArray = [[ZXIntArray alloc] initWithLength:ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS];
  157. for (int i = 0; i < ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) {
  158. segmentIndexArray.array[i] = codewords.array[codeIndex];
  159. }
  160. resultMetadata.segmentIndex = [[self decodeBase900toBase10:segmentIndexArray count:ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS] intValue];
  161. NSMutableString *fileId = [NSMutableString string];
  162. codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:fileId];
  163. resultMetadata.fileId = [NSString stringWithString:fileId];
  164. if (codewords.array[codeIndex] == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD) {
  165. codeIndex++;
  166. NSMutableArray *additionalOptionCodeWords = [NSMutableArray array];
  167. BOOL end = NO;
  168. while ((codeIndex < codewords.array[0]) && !end) {
  169. int code = codewords.array[codeIndex++];
  170. if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  171. [additionalOptionCodeWords addObject:@(code)];
  172. } else {
  173. switch (code) {
  174. case ZX_PDF417_MACRO_PDF417_TERMINATOR:
  175. resultMetadata.lastSegment = YES;
  176. codeIndex++;
  177. end = YES;
  178. break;
  179. default:
  180. return -1;
  181. }
  182. }
  183. }
  184. resultMetadata.optionalData = additionalOptionCodeWords;
  185. } else if (codewords.array[codeIndex] == ZX_PDF417_MACRO_PDF417_TERMINATOR) {
  186. resultMetadata.lastSegment = YES;
  187. codeIndex++;
  188. }
  189. return codeIndex;
  190. }
  191. /**
  192. * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be
  193. * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as
  194. * well as selected control characters.
  195. *
  196. * @param codewords The array of codewords (data + error)
  197. * @param codeIndex The current index into the codeword array.
  198. * @param result The decoded data is appended to the result.
  199. * @return The next index into the codeword array.
  200. */
  201. + (int)textCompaction:(ZXIntArray *)codewords codeIndex:(int)codeIndex result:(NSMutableString *)result {
  202. // 2 character per codeword
  203. ZXIntArray *textCompactionData = [[ZXIntArray alloc] initWithLength:(codewords.array[0] - codeIndex) * 2];
  204. // Used to hold the byte compaction value if there is a mode shift
  205. ZXIntArray *byteCompactionData = [[ZXIntArray alloc] initWithLength:(codewords.array[0] - codeIndex) * 2];
  206. int index = 0;
  207. BOOL end = NO;
  208. while ((codeIndex < codewords.array[0]) && !end) {
  209. int code = codewords.array[codeIndex++];
  210. if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  211. textCompactionData.array[index] = code / 30;
  212. textCompactionData.array[index + 1] = code % 30;
  213. index += 2;
  214. } else {
  215. switch (code) {
  216. case ZX_PDF417_TEXT_COMPACTION_MODE_LATCH:
  217. // reinitialize text compaction mode to alpha sub mode
  218. textCompactionData.array[index++] = ZX_PDF417_TEXT_COMPACTION_MODE_LATCH;
  219. break;
  220. case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH:
  221. case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6:
  222. case ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH:
  223. case ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK:
  224. case ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
  225. case ZX_PDF417_MACRO_PDF417_TERMINATOR:
  226. codeIndex--;
  227. end = YES;
  228. break;
  229. case ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
  230. // The Mode Shift codeword 913 shall cause a temporary
  231. // switch from Text Compaction mode to Byte Compaction mode.
  232. // This switch shall be in effect for only the next codeword,
  233. // after which the mode shall revert to the prevailing sub-mode
  234. // of the Text Compaction mode. Codeword 913 is only available
  235. // in Text Compaction mode; its use is described in 5.4.2.4.
  236. textCompactionData.array[index] = ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
  237. code = codewords.array[codeIndex++];
  238. byteCompactionData.array[index] = code;
  239. index++;
  240. break;
  241. }
  242. }
  243. }
  244. [self decodeTextCompaction:textCompactionData byteCompactionData:byteCompactionData length:index result:result];
  245. return codeIndex;
  246. }
  247. /**
  248. * The Text Compaction mode includes all the printable ASCII characters
  249. * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
  250. * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
  251. * return (ASCII value 13). The Text Compaction mode also includes various latch
  252. * and shift characters which are used exclusively within the mode. The Text
  253. * Compaction mode encodes up to 2 characters per codeword. The compaction rules
  254. * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
  255. * switches are defined in 5.4.2.3.
  256. *
  257. * @param textCompactionData The text compaction data.
  258. * @param byteCompactionData The byte compaction data if there
  259. * was a mode shift.
  260. * @param length The size of the text compaction and byte compaction data.
  261. * @param result The decoded data is appended to the result.
  262. */
  263. + (void)decodeTextCompaction:(ZXIntArray *)textCompactionData byteCompactionData:(ZXIntArray *)byteCompactionData length:(unsigned int)length result:(NSMutableString *)result {
  264. // Beginning from an initial state of the Alpha sub-mode
  265. // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
  266. // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
  267. // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.
  268. ZXPDF417Mode subMode = ZXPDF417ModeAlpha;
  269. ZXPDF417Mode priorToShiftMode = ZXPDF417ModeAlpha;
  270. int i = 0;
  271. while (i < length) {
  272. int subModeCh = textCompactionData.array[i];
  273. unichar ch = 0;
  274. switch (subMode) {
  275. case ZXPDF417ModeAlpha:
  276. // Alpha (uppercase alphabetic)
  277. if (subModeCh < 26) {
  278. // Upper case Alpha Character
  279. ch = (unichar)('A' + subModeCh);
  280. } else {
  281. if (subModeCh == 26) {
  282. ch = ' ';
  283. } else if (subModeCh == ZX_PDF417_LL) {
  284. subMode = ZXPDF417ModeLower;
  285. } else if (subModeCh == ZX_PDF417_ML) {
  286. subMode = ZXPDF417ModeMixed;
  287. } else if (subModeCh == ZX_PDF417_PS) {
  288. // Shift to punctuation
  289. priorToShiftMode = subMode;
  290. subMode = ZXPDF417ModePunctShift;
  291. } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
  292. // TODO Does this need to use the current character encoding? See other occurrences below
  293. [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]];
  294. } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  295. subMode = ZXPDF417ModeAlpha;
  296. }
  297. }
  298. break;
  299. case ZXPDF417ModeLower:
  300. // Lower (lowercase alphabetic)
  301. if (subModeCh < 26) {
  302. ch = (unichar)('a' + subModeCh);
  303. } else {
  304. if (subModeCh == 26) {
  305. ch = ' ';
  306. } else if (subModeCh == ZX_PDF417_AS) {
  307. // Shift to alpha
  308. priorToShiftMode = subMode;
  309. subMode = ZXPDF417ModeAlphaShift;
  310. } else if (subModeCh == ZX_PDF417_ML) {
  311. subMode = ZXPDF417ModeMixed;
  312. } else if (subModeCh == ZX_PDF417_PS) {
  313. // Shift to punctuation
  314. priorToShiftMode = subMode;
  315. subMode = ZXPDF417ModePunctShift;
  316. } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
  317. [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]];
  318. } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  319. subMode = ZXPDF417ModeAlpha;
  320. }
  321. }
  322. break;
  323. case ZXPDF417ModeMixed:
  324. // Mixed (numeric and some punctuation)
  325. if (subModeCh < ZX_PDF417_PL) {
  326. ch = ZX_PDF417_MIXED_CHARS[subModeCh];
  327. } else {
  328. if (subModeCh == ZX_PDF417_PL) {
  329. subMode = ZXPDF417ModePunct;
  330. } else if (subModeCh == 26) {
  331. ch = ' ';
  332. } else if (subModeCh == ZX_PDF417_LL) {
  333. subMode = ZXPDF417ModeLower;
  334. } else if (subModeCh == ZX_PDF417_AL) {
  335. subMode = ZXPDF417ModeAlpha;
  336. } else if (subModeCh == ZX_PDF417_PS) {
  337. // Shift to punctuation
  338. priorToShiftMode = subMode;
  339. subMode = ZXPDF417ModePunctShift;
  340. } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
  341. [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]];
  342. } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  343. subMode = ZXPDF417ModeAlpha;
  344. }
  345. }
  346. break;
  347. case ZXPDF417ModePunct:
  348. // Punctuation
  349. if (subModeCh < ZX_PDF417_PAL) {
  350. ch = ZX_PDF417_PUNCT_CHARS[subModeCh];
  351. } else {
  352. if (subModeCh == ZX_PDF417_PAL) {
  353. subMode = ZXPDF417ModeAlpha;
  354. } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
  355. [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]];
  356. } else if (ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  357. subMode = ZXPDF417ModeAlpha;
  358. }
  359. }
  360. break;
  361. case ZXPDF417ModeAlphaShift:
  362. // Restore sub-mode
  363. subMode = priorToShiftMode;
  364. if (subModeCh < 26) {
  365. ch = (unichar)('A' + subModeCh);
  366. } else {
  367. if (subModeCh == 26) {
  368. ch = ' ';
  369. } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  370. subMode = ZXPDF417ModeAlpha;
  371. }
  372. }
  373. break;
  374. case ZXPDF417ModePunctShift:
  375. // Restore sub-mode
  376. subMode = priorToShiftMode;
  377. if (subModeCh < ZX_PDF417_PAL) {
  378. ch = ZX_PDF417_PUNCT_CHARS[subModeCh];
  379. } else {
  380. if (subModeCh == ZX_PDF417_PAL) {
  381. subMode = ZXPDF417ModeAlpha;
  382. } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
  383. // PS before Shift-to-Byte is used as a padding character,
  384. // see 5.4.2.4 of the specification
  385. [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]];
  386. } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  387. subMode = ZXPDF417ModeAlpha;
  388. }
  389. }
  390. break;
  391. }
  392. if (ch != 0) {
  393. // Append decoded character to result
  394. [result appendFormat:@"%C", ch];
  395. }
  396. i++;
  397. }
  398. }
  399. /**
  400. * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
  401. * This includes all ASCII characters value 0 to 127 inclusive and provides for international
  402. * character set support.
  403. *
  404. * @param mode The byte compaction mode i.e. 901 or 924
  405. * @param codewords The array of codewords (data + error)
  406. * @param encoding Currently active character encoding
  407. * @param codeIndex The current index into the codeword array.
  408. * @param result The decoded data is appended to the result.
  409. * @return The next index into the codeword array.
  410. */
  411. + (int)byteCompaction:(int)mode
  412. codewords:(ZXIntArray *)codewords
  413. encoding:(NSStringEncoding)encoding
  414. codeIndex:(int)codeIndex
  415. result:(NSMutableString *)result {
  416. NSMutableData *decodedBytes = [NSMutableData data];
  417. if (mode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH) {
  418. // Total number of Byte Compaction characters to be encoded
  419. // is not a multiple of 6
  420. int count = 0;
  421. long long value = 0;
  422. ZXIntArray *byteCompactedCodewords = [[ZXIntArray alloc] initWithLength:6];
  423. BOOL end = NO;
  424. int nextCode = codewords.array[codeIndex++];
  425. while ((codeIndex < codewords.array[0]) && !end) {
  426. byteCompactedCodewords.array[count++] = nextCode;
  427. // Base 900
  428. value = 900 * value + nextCode;
  429. nextCode = codewords.array[codeIndex++];
  430. // perhaps it should be ok to check only nextCode >= TEXT_COMPACTION_MODE_LATCH
  431. if (nextCode == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH ||
  432. nextCode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH ||
  433. nextCode == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH ||
  434. nextCode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 ||
  435. nextCode == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
  436. nextCode == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
  437. nextCode == ZX_PDF417_MACRO_PDF417_TERMINATOR) {
  438. codeIndex--;
  439. end = YES;
  440. } else {
  441. if ((count % 5 == 0) && (count > 0)) {
  442. // Decode every 5 codewords
  443. // Convert to Base 256
  444. for (int j = 0; j < 6; ++j) {
  445. int8_t byte = (int8_t) (value >> (8 * (5 - j)));
  446. [decodedBytes appendBytes:&byte length:1];
  447. }
  448. value = 0;
  449. count = 0;
  450. }
  451. }
  452. }
  453. // if the end of all codewords is reached the last codeword needs to be added
  454. if (codeIndex == codewords.array[0] && nextCode < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  455. byteCompactedCodewords.array[count++] = nextCode;
  456. }
  457. // If Byte Compaction mode is invoked with codeword 901,
  458. // the last group of codewords is interpreted directly
  459. // as one byte per codeword, without compaction.
  460. for (int i = 0; i < count; i++) {
  461. int8_t byte = (int8_t)byteCompactedCodewords.array[i];
  462. [decodedBytes appendBytes:&byte length:1];
  463. }
  464. } else if (mode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6) {
  465. // Total number of Byte Compaction characters to be encoded
  466. // is an integer multiple of 6
  467. int count = 0;
  468. long long value = 0;
  469. BOOL end = NO;
  470. while (codeIndex < codewords.array[0] && !end) {
  471. int code = codewords.array[codeIndex++];
  472. if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  473. count++;
  474. // Base 900
  475. value = 900 * value + code;
  476. } else {
  477. if (code == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH ||
  478. code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH ||
  479. code == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH ||
  480. code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 ||
  481. code == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
  482. code == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
  483. code == ZX_PDF417_MACRO_PDF417_TERMINATOR) {
  484. codeIndex--;
  485. end = YES;
  486. }
  487. }
  488. if ((count % 5 == 0) && (count > 0)) {
  489. // Decode every 5 codewords
  490. // Convert to Base 256
  491. for (int j = 0; j < 6; ++j) {
  492. int8_t byte = (int8_t) (value >> (8 * (5 - j)));
  493. [decodedBytes appendBytes:&byte length:1];
  494. }
  495. value = 0;
  496. count = 0;
  497. }
  498. }
  499. }
  500. [result appendString:[[NSString alloc] initWithData:decodedBytes encoding:encoding]];
  501. return codeIndex;
  502. }
  503. /**
  504. * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
  505. *
  506. * @param codewords The array of codewords (data + error)
  507. * @param codeIndex The current index into the codeword array.
  508. * @param result The decoded data is appended to the result.
  509. * @return The next index into the codeword array.
  510. */
  511. + (int)numericCompaction:(ZXIntArray *)codewords codeIndex:(int)codeIndex result:(NSMutableString *)result {
  512. int count = 0;
  513. BOOL end = NO;
  514. ZXIntArray *numericCodewords = [[ZXIntArray alloc] initWithLength:ZX_PDF417_MAX_NUMERIC_CODEWORDS];
  515. while (codeIndex < codewords.array[0] && !end) {
  516. int code = codewords.array[codeIndex++];
  517. if (codeIndex == codewords.array[0]) {
  518. end = YES;
  519. }
  520. if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) {
  521. numericCodewords.array[count] = code;
  522. count++;
  523. } else {
  524. if (code == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH ||
  525. code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH ||
  526. code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 ||
  527. code == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
  528. code == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
  529. code == ZX_PDF417_MACRO_PDF417_TERMINATOR) {
  530. codeIndex--;
  531. end = YES;
  532. }
  533. }
  534. if (count % ZX_PDF417_MAX_NUMERIC_CODEWORDS == 0 ||
  535. code == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH ||
  536. end) {
  537. // Re-invoking Numeric Compaction mode (by using codeword 902
  538. // while in Numeric Compaction mode) serves to terminate the
  539. // current Numeric Compaction mode grouping as described in 5.4.4.2,
  540. // and then to start a new one grouping.
  541. if (count > 0) {
  542. NSString *s = [self decodeBase900toBase10:numericCodewords count:count];
  543. if (s == nil) {
  544. return -1;
  545. }
  546. [result appendString:s];
  547. count = 0;
  548. }
  549. }
  550. }
  551. return codeIndex;
  552. }
  553. /**
  554. * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
  555. *
  556. * @param codewords The array of codewords
  557. * @param count The number of codewords
  558. * @return The decoded string representing the Numeric data.
  559. */
  560. /*
  561. EXAMPLE
  562. Encode the fifteen digit numeric string 000213298174000
  563. Prefix the numeric string with a 1 and set the initial value of
  564. t = 1 000 213 298 174 000
  565. Calculate codeword 0
  566. d0 = 1 000 213 298 174 000 mod 900 = 200
  567. t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
  568. Calculate codeword 1
  569. d1 = 1 111 348 109 082 mod 900 = 282
  570. t = 1 111 348 109 082 div 900 = 1 234 831 232
  571. Calculate codeword 2
  572. d2 = 1 234 831 232 mod 900 = 632
  573. t = 1 234 831 232 div 900 = 1 372 034
  574. Calculate codeword 3
  575. d3 = 1 372 034 mod 900 = 434
  576. t = 1 372 034 div 900 = 1 524
  577. Calculate codeword 4u
  578. d4 = 1 524 mod 900 = 624
  579. t = 1 524 div 900 = 1
  580. Calculate codeword 5
  581. d5 = 1 mod 900 = 1
  582. t = 1 div 900 = 0
  583. Codeword sequence is: 1, 624, 434, 632, 282, 200
  584. Decode the above codewords involves
  585. 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
  586. 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
  587. Remove leading 1 => Result is 000213298174000
  588. */
  589. + (NSString *)decodeBase900toBase10:(ZXIntArray *)codewords count:(int)count {
  590. NSDecimalNumber *result = [NSDecimalNumber zero];
  591. for (int i = 0; i < count; i++) {
  592. result = [result decimalNumberByAdding:[ZX_PDF417_EXP900[count - i - 1] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithDecimal:[@(codewords.array[i]) decimalValue]]]];
  593. }
  594. NSString *resultString = [result stringValue];
  595. if (![resultString hasPrefix:@"1"]) {
  596. return nil;
  597. }
  598. return [resultString substringFromIndex:1];
  599. }
  600. @end