1 /**
2  * libdmtx - Data Matrix Encoding/Decoding Library
3  * Copyright 2008, 2009 Mike Laughton. All rights reserved.
4  * Copyright 2012-2016 Vadim A. Misbakh-Soloviov. All rights reserved.
5  * Copyright 2016 Tim Zaman. All rights reserved.
6  *
7  * See LICENSE file in the main project directory for full
8  * terms of use and distribution.
9  *
10  * Contact:
11  * Vadim A. Misbakh-Soloviov <dmtx@mva.name>
12  * Mike Laughton <mike@dragonflylogic.com>
13  *
14  * \file dmtxdecodescheme.c
15  */
16 
17 /**
18  * \brief  Translate encoded data stream into final output
19  * \param  msg
20  * \param  sizeIdx
21  * \param  outputStart
22  * \return void
23  */
24 extern void
DecodeDataStream(DmtxMessage * msg,int sizeIdx,unsigned char * outputStart)25 DecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart)
26 {
27    //fprintf(stdout, "libdmtx::DecodeDataStream()\n");
28    //int oned = sqrt(msg->arraySize);
29    //for (int i=0; i<msg->arraySize; i++){
30    //   fprintf(stdout, " %c.", msg->array[i]);
31    //   if (i%oned==oned-1){
32    //      fprintf(stdout, "\n");
33    //   }
34    //}
35 
36    DmtxBoolean macro = DmtxFalse;
37    DmtxScheme encScheme;
38    unsigned char *ptr, *dataEnd;
39 
40    msg->output = (outputStart == NULL) ? msg->output : outputStart;
41    msg->outputIdx = 0;
42 
43    ptr = msg->code;
44    dataEnd = ptr + dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
45 
46    /* Print macro header if first codeword triggers it */
47    if(*ptr == DmtxValue05Macro || *ptr == DmtxValue06Macro) {
48       PushOutputMacroHeader(msg, *ptr);
49       macro = DmtxTrue;
50    }
51 
52    while(ptr < dataEnd) {
53 
54       encScheme = GetEncodationScheme(*ptr);
55       if(encScheme != DmtxSchemeAscii)
56          ptr++;
57 
58       switch(encScheme) {
59          case DmtxSchemeAscii:
60             ptr = DecodeSchemeAscii(msg, ptr, dataEnd);
61             break;
62          case DmtxSchemeC40:
63          case DmtxSchemeText:
64             ptr = DecodeSchemeC40Text(msg, ptr, dataEnd, encScheme);
65             break;
66          case DmtxSchemeX12:
67             ptr = DecodeSchemeX12(msg, ptr, dataEnd);
68             break;
69          case DmtxSchemeEdifact:
70             ptr = DecodeSchemeEdifact(msg, ptr, dataEnd);
71             break;
72          case DmtxSchemeBase256:
73             ptr = DecodeSchemeBase256(msg, ptr, dataEnd);
74             break;
75          default:
76             /* error */
77             break;
78       }
79    }
80 
81    /* Print macro trailer if required */
82    if(macro == DmtxTrue)
83       PushOutputMacroTrailer(msg);
84 }
85 
86 /**
87  * \brief  Determine next encodation scheme
88  * \param  encScheme
89  * \param  cw
90  * \return Pointer to next undecoded codeword
91  */
92 static int
GetEncodationScheme(unsigned char cw)93 GetEncodationScheme(unsigned char cw)
94 {
95    DmtxScheme encScheme;
96 
97    switch(cw) {
98       case DmtxValueC40Latch:
99          encScheme = DmtxSchemeC40;
100          break;
101       case DmtxValueTextLatch:
102          encScheme = DmtxSchemeText;
103          break;
104       case DmtxValueX12Latch:
105          encScheme = DmtxSchemeX12;
106          break;
107       case DmtxValueEdifactLatch:
108          encScheme = DmtxSchemeEdifact;
109          break;
110       case DmtxValueBase256Latch:
111          encScheme = DmtxSchemeBase256;
112          break;
113       default:
114          encScheme = DmtxSchemeAscii;
115          break;
116    }
117 
118    return encScheme;
119 }
120 
121 /**
122  *
123  *
124  */
125 static void
PushOutputWord(DmtxMessage * msg,int value)126 PushOutputWord(DmtxMessage *msg, int value)
127 {
128    assert(value >= 0 && value < 256);
129 
130    msg->output[msg->outputIdx++] = (unsigned char)value;
131 }
132 
133 /**
134  *
135  *
136  */
137 static void
PushOutputC40TextWord(DmtxMessage * msg,C40TextState * state,int value)138 PushOutputC40TextWord(DmtxMessage *msg, C40TextState *state, int value)
139 {
140    assert(value >= 0 && value < 256);
141 
142    msg->output[msg->outputIdx] = (unsigned char)value;
143 
144    if(state->upperShift == DmtxTrue) {
145       assert(value < 128);
146       msg->output[msg->outputIdx] += 128;
147    }
148 
149    msg->outputIdx++;
150 
151    state->shift = DmtxC40TextBasicSet;
152    state->upperShift = DmtxFalse;
153 }
154 
155 /**
156  *
157  *
158  */
159 static void
PushOutputMacroHeader(DmtxMessage * msg,int macroType)160 PushOutputMacroHeader(DmtxMessage *msg, int macroType)
161 {
162    PushOutputWord(msg, '[');
163    PushOutputWord(msg, ')');
164    PushOutputWord(msg, '>');
165    PushOutputWord(msg, 30); /* ASCII RS */
166    PushOutputWord(msg, '0');
167 
168    assert(macroType == DmtxValue05Macro || macroType == DmtxValue06Macro);
169    if(macroType == DmtxValue05Macro)
170       PushOutputWord(msg, '5');
171    else
172       PushOutputWord(msg, '6');
173 
174    PushOutputWord(msg, 29); /* ASCII GS */
175 }
176 
177 /**
178  *
179  *
180  */
181 static void
PushOutputMacroTrailer(DmtxMessage * msg)182 PushOutputMacroTrailer(DmtxMessage *msg)
183 {
184    PushOutputWord(msg, 30); /* ASCII RS */
185    PushOutputWord(msg, 4);  /* ASCII EOT */
186 }
187 
188 /**
189  * \brief  Decode stream assuming standard ASCII encodation
190  * \param  msg
191  * \param  ptr
192  * \param  dataEnd
193  * \return Pointer to next undecoded codeword
194  */
195 static unsigned char *
DecodeSchemeAscii(DmtxMessage * msg,unsigned char * ptr,unsigned char * dataEnd)196 DecodeSchemeAscii(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
197 {
198    int upperShift;
199    int codeword, digits;
200 
201    upperShift = DmtxFalse;
202 
203    while(ptr < dataEnd) {
204 
205       codeword = (int)(*ptr);
206 
207       if(GetEncodationScheme(*ptr) != DmtxSchemeAscii)
208          return ptr;
209       else
210          ptr++;
211 
212       if(upperShift == DmtxTrue) {
213          PushOutputWord(msg, codeword + 127);
214          upperShift = DmtxFalse;
215       }
216       else if(codeword == DmtxValueAsciiUpperShift) {
217          upperShift = DmtxTrue;
218       }
219       else if(codeword == DmtxValueAsciiPad) {
220          assert(dataEnd >= ptr);
221          assert(dataEnd - ptr <= INT_MAX);
222          msg->padCount = (int)(dataEnd - ptr);
223          return dataEnd;
224       }
225       else if(codeword == 0 || codeword >= 242) {
226         return ptr;
227       }
228       else if(codeword <= 128) {
229          PushOutputWord(msg, codeword - 1);
230       }
231       else if(codeword <= 229) {
232          digits = codeword - 130;
233          PushOutputWord(msg, digits/10 + '0');
234          PushOutputWord(msg, digits - (digits/10)*10 + '0');
235       }
236       else if(codeword == DmtxValueFNC1) {
237          if(msg->fnc1 != DmtxUndefined) {
238              PushOutputWord(msg, msg->fnc1);
239          }
240       }
241    }
242 
243    return ptr;
244 }
245 
246 /**
247  * \brief  Decode stream assuming C40 or Text encodation
248  * \param  msg
249  * \param  ptr
250  * \param  dataEnd
251  * \param  encScheme
252  * \return Pointer to next undecoded codeword
253  */
254 static unsigned char *
DecodeSchemeC40Text(DmtxMessage * msg,unsigned char * ptr,unsigned char * dataEnd,DmtxScheme encScheme)255 DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxScheme encScheme)
256 {
257    int i;
258    int packed;
259    int c40Values[3];
260    C40TextState state;
261 
262    state.shift = DmtxC40TextBasicSet;
263    state.upperShift = DmtxFalse;
264 
265    assert(encScheme == DmtxSchemeC40 || encScheme == DmtxSchemeText);
266 
267    /* Unlatch is implied if only one codeword remains */
268    if(dataEnd - ptr < 2)
269       return ptr;
270 
271    while(ptr < dataEnd) {
272 
273       /* FIXME Also check that ptr+1 is safe to access */
274       packed = (*ptr << 8) | *(ptr+1);
275       c40Values[0] = ((packed - 1)/1600);
276       c40Values[1] = ((packed - 1)/40) % 40;
277       c40Values[2] =  (packed - 1) % 40;
278       ptr += 2;
279 
280       for(i = 0; i < 3; i++) {
281          if(state.shift == DmtxC40TextBasicSet) { /* Basic set */
282             if(c40Values[i] <= 2) {
283                state.shift = c40Values[i] + 1;
284             }
285             else if(c40Values[i] == 3) {
286                PushOutputC40TextWord(msg, &state, ' ');
287             }
288             else if(c40Values[i] <= 13) {
289                PushOutputC40TextWord(msg, &state, c40Values[i] - 13 + '9'); /* 0-9 */
290             }
291             else if(c40Values[i] <= 39) {
292                if(encScheme == DmtxSchemeC40) {
293                   PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'Z'); /* A-Z */
294                }
295                else if(encScheme == DmtxSchemeText) {
296                   PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'z'); /* a-z */
297                }
298             }
299          }
300          else if(state.shift == DmtxC40TextShift1) { /* Shift 1 set */
301             PushOutputC40TextWord(msg, &state, c40Values[i]); /* ASCII 0 - 31 */
302          }
303          else if(state.shift == DmtxC40TextShift2) { /* Shift 2 set */
304             if(c40Values[i] <= 14) {
305                PushOutputC40TextWord(msg, &state, c40Values[i] + 33); /* ASCII 33 - 47 */
306             }
307             else if(c40Values[i] <= 21) {
308                PushOutputC40TextWord(msg, &state, c40Values[i] + 43); /* ASCII 58 - 64 */
309             }
310             else if(c40Values[i] <= 26) {
311                PushOutputC40TextWord(msg, &state, c40Values[i] + 69); /* ASCII 91 - 95 */
312             }
313             else if(c40Values[i] == 27) {
314                if(msg->fnc1 != DmtxUndefined) {
315                    PushOutputC40TextWord(msg, &state, msg->fnc1);
316                }
317             }
318             else if(c40Values[i] == 30) {
319                state.upperShift = DmtxTrue;
320                state.shift = DmtxC40TextBasicSet;
321             }
322          }
323          else if(state.shift == DmtxC40TextShift3) { /* Shift 3 set */
324             if(encScheme == DmtxSchemeC40) {
325                PushOutputC40TextWord(msg, &state, c40Values[i] + 96);
326             }
327             else if(encScheme == DmtxSchemeText) {
328                if(c40Values[i] == 0)
329                   PushOutputC40TextWord(msg, &state, c40Values[i] + 96);
330                else if(c40Values[i] <= 26)
331                   PushOutputC40TextWord(msg, &state, c40Values[i] - 26 + 'Z'); /* A-Z */
332                else
333                   PushOutputC40TextWord(msg, &state, c40Values[i] - 31 + 127); /* { | } ~ DEL */
334             }
335          }
336       }
337 
338       /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */
339       if(*ptr == DmtxValueCTXUnlatch)
340          return ptr + 1;
341 
342       /* Unlatch is implied if only one codeword remains */
343       if(dataEnd - ptr < 2)
344          return ptr;
345    }
346 
347    return ptr;
348 }
349 
350 /**
351  * \brief  Decode stream assuming X12 encodation
352  * \param  msg
353  * \param  ptr
354  * \param  dataEnd
355  * \return Pointer to next undecoded codeword
356  */
357 static unsigned char *
DecodeSchemeX12(DmtxMessage * msg,unsigned char * ptr,unsigned char * dataEnd)358 DecodeSchemeX12(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
359 {
360    int i;
361    int packed;
362    int x12Values[3];
363 
364    /* Unlatch is implied if only one codeword remains */
365    if(dataEnd - ptr < 2)
366       return ptr;
367 
368    while(ptr < dataEnd) {
369 
370       /* FIXME Also check that ptr+1 is safe to access */
371       packed = (*ptr << 8) | *(ptr+1);
372       x12Values[0] = ((packed - 1)/1600);
373       x12Values[1] = ((packed - 1)/40) % 40;
374       x12Values[2] =  (packed - 1) % 40;
375       ptr += 2;
376 
377       for(i = 0; i < 3; i++) {
378          if(x12Values[i] == 0)
379             PushOutputWord(msg, 13);
380          else if(x12Values[i] == 1)
381             PushOutputWord(msg, 42);
382          else if(x12Values[i] == 2)
383             PushOutputWord(msg, 62);
384          else if(x12Values[i] == 3)
385             PushOutputWord(msg, 32);
386          else if(x12Values[i] <= 13)
387             PushOutputWord(msg, x12Values[i] + 44);
388          else if(x12Values[i] <= 90)
389             PushOutputWord(msg, x12Values[i] + 51);
390       }
391 
392       /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */
393       if(*ptr == DmtxValueCTXUnlatch)
394          return ptr + 1;
395 
396       /* Unlatch is implied if only one codeword remains */
397       if(dataEnd - ptr < 2)
398          return ptr;
399    }
400 
401    return ptr;
402 }
403 
404 /**
405  * \brief  Decode stream assuming EDIFACT encodation
406  * \param  msg
407  * \param  ptr
408  * \param  dataEnd
409  * \return Pointer to next undecoded codeword
410  */
411 static unsigned char *
DecodeSchemeEdifact(DmtxMessage * msg,unsigned char * ptr,unsigned char * dataEnd)412 DecodeSchemeEdifact(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
413 {
414    int i;
415    unsigned char unpacked[4];
416 
417    /* Unlatch is implied if fewer than 3 codewords remain */
418    if(dataEnd - ptr < 3)
419       return ptr;
420 
421    while(ptr < dataEnd) {
422 
423       /* FIXME Also check that ptr+2 is safe to access -- shouldn't be a
424          problem because I'm guessing you can guarantee there will always
425          be at least 3 error codewords */
426       unpacked[0] = (*ptr & 0xfc) >> 2;
427       unpacked[1] = (*ptr & 0x03) << 4 | (*(ptr+1) & 0xf0) >> 4;
428       unpacked[2] = (*(ptr+1) & 0x0f) << 2 | (*(ptr+2) & 0xc0) >> 6;
429       unpacked[3] = *(ptr+2) & 0x3f;
430 
431       for(i = 0; i < 4; i++) {
432 
433          /* Advance input ptr (4th value comes from already-read 3rd byte) */
434          if(i < 3)
435             ptr++;
436 
437          /* Test for unlatch condition */
438          if(unpacked[i] == DmtxValueEdifactUnlatch) {
439             assert(msg->output[msg->outputIdx] == 0); /* XXX dirty why? */
440             return ptr;
441          }
442 
443          PushOutputWord(msg, unpacked[i] ^ (((unpacked[i] & 0x20) ^ 0x20) << 1));
444       }
445 
446       /* Unlatch is implied if fewer than 3 codewords remain */
447       if(dataEnd - ptr < 3)
448          return ptr;
449    }
450 
451    return ptr;
452 
453 /* XXX the following version should be safer, but requires testing before replacing the old version
454    int bits = 0;
455    int bitCount = 0;
456    int value;
457 
458    while(ptr < dataEnd) {
459 
460       if(bitCount < 6) {
461          bits = (bits << 8) | *(ptr++);
462          bitCount += 8;
463       }
464 
465       value = bits >> (bitCount - 6);
466       bits -= (value << (bitCount - 6));
467       bitCount -= 6;
468 
469       if(value == 0x1f) {
470          assert(bits == 0); // should be padded with zero-value bits
471          return ptr;
472       }
473       PushOutputWord(msg, value ^ (((value & 0x20) ^ 0x20) << 1));
474 
475       // Unlatch implied if just completed triplet and 1 or 2 words are left
476       if(bitCount == 0 && dataEnd - ptr - 1 > 0 && dataEnd - ptr - 1 < 3)
477          return ptr;
478    }
479 
480    assert(bits == 0); // should be padded with zero-value bits
481    assert(bitCount == 0); // should be padded with zero-value bits
482    return ptr;
483 */
484 }
485 
486 /**
487  * \brief  Decode stream assuming Base 256 encodation
488  * \param  msg
489  * \param  ptr
490  * \param  dataEnd
491  * \return Pointer to next undecoded codeword
492  */
493 static unsigned char *
DecodeSchemeBase256(DmtxMessage * msg,unsigned char * ptr,unsigned char * dataEnd)494 DecodeSchemeBase256(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
495 {
496    int d0, d1;
497    int idx;
498    unsigned char *ptrEnd;
499 
500    /* Find positional index used for unrandomizing */
501    assert(ptr + 1 >= msg->code);
502    assert(ptr + 1 - msg->code <= INT_MAX);
503    idx = (int)(ptr + 1 - msg->code);
504 
505    d0 = UnRandomize255State(*(ptr++), idx++);
506    if(d0 == 0) {
507       ptrEnd = dataEnd;
508    }
509    else if(d0 <= 249) {
510       ptrEnd = ptr + d0;
511    }
512    else {
513       d1 = UnRandomize255State(*(ptr++), idx++);
514       ptrEnd = ptr + (d0 - 249) * 250 + d1;
515    }
516 
517    if(ptrEnd > dataEnd)
518       exit(40); /* XXX needs cleaner error handling */
519 
520    while(ptr < ptrEnd)
521       PushOutputWord(msg, UnRandomize255State(*(ptr++), idx++));
522 
523    return ptr;
524 }
525