libdmtx 0.7.8.7
libdmtx is a software library that enables programs to read and write Data Matrix barcodes of the modern ECC200 variety.
Loading...
Searching...
No Matches
dmtxencodec40textx12.c
Go to the documentation of this file.
1
17#include <assert.h>
18
19#include "dmtx.h"
20#include "dmtxstatic.h"
21
22#undef CHKERR
23#define CHKERR \
24 { \
25 if (stream->status != DmtxStatusEncoding) { \
26 return; \
27 } \
28 }
29
30#undef CHKSIZE
31#define CHKSIZE \
32 { \
33 if (sizeIdx == DmtxUndefined) { \
34 streamMarkInvalid(stream, DmtxErrorUnknown); \
35 return; \
36 } \
37 }
38
39#undef CHKPASS
40#define CHKPASS \
41 { \
42 if (passFail == DmtxFail) { \
43 streamMarkFatal(stream, DmtxErrorUnknown); \
44 return; \
45 } \
46 }
47
48#undef RETURN_IF_FAIL
49#define RETURN_IF_FAIL \
50 { \
51 if (*passFail == DmtxFail) \
52 return; \
53 }
54
59static void encodeNextChunkCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
60{
61 int i;
62 DmtxPassFail passFail;
63 DmtxByte inputValue;
64 DmtxByte valueListStorage[6];
65 DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage));
66
67 while (streamInputHasNext(stream)) {
68 if (stream->currentScheme == DmtxSchemeX12) {
69 /* Check for FNC1 character */
70 inputValue = streamInputPeekNext(stream);
71 CHKERR;
72 if (stream->fnc1 != DmtxUndefined && (int)inputValue == stream->fnc1) {
73 /* X12 does not allow partial blocks, resend last 1 or 2 as ASCII */
75 CHKERR;
76 for (i = 0; i < valueList.length % 3; i++) {
78 }
79 CHKERR;
80
81 while (i) {
82 inputValue = streamInputAdvanceNext(stream);
83 CHKERR;
84 appendValueAscii(stream, inputValue + 1);
85 CHKERR;
86 i--;
87 }
88
90 CHKERR;
92 CHKERR;
93 return;
94 }
95 }
96 inputValue = streamInputAdvanceNext(stream);
97 CHKERR;
98
99 /* Expand next input value into up to 4 CTX values and add to valueList */
100 pushCTXValues(&valueList, inputValue, stream->currentScheme, &passFail, stream->fnc1);
101 if (passFail == DmtxFail) {
102 /* XXX Perhaps pushCTXValues should return this error code */
104 return;
105 }
106
107 /* If there at least 3 CTX values available encode them to output */
108 while (valueList.length >= 3) {
109 appendValuesCTX(stream, &valueList);
110 CHKERR;
111 shiftValueListBy3(&valueList, &passFail);
112 CHKPASS;
113 }
114
115 /* Finished on byte boundary -- done with current chunk */
116 if (valueList.length == 0) {
117 break;
118 }
119 }
120
121 /*
122 * Special case: If all input values have been consumed and 1 or 2 unwritten
123 * C40/Text/X12 values remain, finish encoding the symbol according to the
124 * established end-of-symbol conditions.
125 */
126 if (!streamInputHasNext(stream) && valueList.length > 0) {
127 if (stream->currentScheme == DmtxSchemeX12) {
128 completePartialX12(stream, &valueList, sizeIdxRequest);
129 CHKERR;
130 } else {
131 completePartialC40Text(stream, &valueList, sizeIdxRequest);
132 CHKERR;
133 }
134 }
135}
136
141static void appendValuesCTX(DmtxEncodeStream *stream, DmtxByteList *valueList)
142{
143 int pairValue;
144 DmtxByte cw0, cw1;
145
146 if (!isCTX(stream->currentScheme)) {
148 return;
149 }
150
151 if (valueList->length < 3) {
153 return;
154 }
155
156 /* Build codewords from computed value */
157 pairValue = (1600 * valueList->b[0]) + (40 * valueList->b[1]) + valueList->b[2] + 1;
158 cw0 = pairValue / 256;
159 cw1 = pairValue % 256;
160
161 /* Append 2 codewords */
162 streamOutputChainAppend(stream, cw0);
163 CHKERR;
164 streamOutputChainAppend(stream, cw1);
165 CHKERR;
166
167 /* Update count for 3 encoded values */
168 stream->outputChainValueCount += 3;
169}
170
176{
177 if (!isCTX(stream->currentScheme)) {
179 return;
180 }
181
182 /* Verify we are on byte boundary */
183 if (stream->outputChainValueCount % 3 != 0) {
185 return;
186 }
187
189 CHKERR;
190
191 stream->outputChainValueCount++;
192}
193
203static void completeIfDoneCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
204{
205 int sizeIdx;
206 int symbolRemaining;
207
208 if (stream->status == DmtxStatusComplete) {
209 return;
210 }
211
212 if (!streamInputHasNext(stream)) {
213 sizeIdx = findSymbolSize(stream->output->length, sizeIdxRequest);
214 CHKSIZE;
215 symbolRemaining = getRemainingSymbolCapacity(stream->output->length, sizeIdx);
216
217 if (symbolRemaining > 0) {
219 CHKERR;
220 padRemainingInAscii(stream, sizeIdx);
221 }
222
223 streamMarkComplete(stream, sizeIdx);
224 }
225}
226
252static void completePartialC40Text(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
253{
254 int i;
255 int sizeIdx1, sizeIdx2;
256 int symbolRemaining1, symbolRemaining2;
257 DmtxPassFail passFail;
258 DmtxByte inputValue;
259 DmtxByte outputTmpStorage[4];
260 DmtxByteList outputTmp = dmtxByteListBuild(outputTmpStorage, sizeof(outputTmpStorage));
261
262 if (stream->currentScheme != DmtxSchemeC40 && stream->currentScheme != DmtxSchemeText) {
264 return;
265 }
266
267 /* Should have exactly one or two input values left */
268 DmtxAssert(valueList->length == 1 || valueList->length == 2);
269
270 sizeIdx1 = findSymbolSize(stream->output->length + 1, sizeIdxRequest);
271 sizeIdx2 = findSymbolSize(stream->output->length + 2, sizeIdxRequest);
272
273 symbolRemaining1 = getRemainingSymbolCapacity(stream->output->length, sizeIdx1);
274 symbolRemaining2 = getRemainingSymbolCapacity(stream->output->length, sizeIdx2);
275
276 if (valueList->length == 2 && symbolRemaining2 == 2) {
277 /* End of symbol condition (b) -- Use Shift1 to pad final list value */
278 dmtxByteListPush(valueList, DmtxValueCTXShift1, &passFail);
279 CHKPASS;
280 appendValuesCTX(stream, valueList);
281 CHKERR;
282 streamMarkComplete(stream, sizeIdx2);
283 } else {
284 /*
285 * Rollback progress of previously consumed input value(s) since ASCII
286 * encoder will be used to finish the symbol. 2 rollbacks are needed if
287 * valueList holds 2 data words (i.e., not shifts or upper shifts).
288 */
289
291 CHKERR;
292 inputValue = streamInputPeekNext(stream);
293 CHKERR;
294
295 /* Test-encode most recently consumed input value to C40/Text/X12 */
296 pushCTXValues(&outputTmp, inputValue, stream->currentScheme, &passFail, stream->fnc1);
297 if (valueList->length == 2 && outputTmp.length == 1) {
299 }
300 CHKERR;
301
302 /* Re-use outputTmp to hold ASCII representation of 1-2 input values */
303 /* XXX Refactor how the DmtxByteList is passed back here */
304 outputTmp = encodeTmpRemainingInAscii(stream, outputTmpStorage, sizeof(outputTmpStorage), &passFail);
305
306 if (passFail == DmtxFail) {
308 return;
309 }
310
311 if (outputTmp.length == 1 && symbolRemaining1 == 1) {
312 /* End of symbol condition (d) */
314 CHKERR;
315 appendValueAscii(stream, outputTmp.b[0]);
316 CHKERR;
317
318 /* Register progress since encoding happened outside normal path */
319 stream->inputNext = stream->input->length;
320 streamMarkComplete(stream, sizeIdx1);
321 } else {
322 /* Finish in ASCII (c) */
324 CHKERR;
325 for (i = 0; i < outputTmp.length; i++) {
326 appendValueAscii(stream, outputTmp.b[i]);
327 }
328 CHKERR;
329
330 sizeIdx1 = findSymbolSize(stream->output->length, sizeIdxRequest);
331 padRemainingInAscii(stream, sizeIdx1);
332
333 /* Register progress since encoding happened outside normal path */
334 stream->inputNext = stream->input->length;
335 streamMarkComplete(stream, sizeIdx1);
336 }
337 }
338}
339
345static void completePartialX12(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
346{
347 int i;
348 int sizeIdx;
349 int symbolRemaining;
350 DmtxPassFail passFail;
351 DmtxByte outputTmpStorage[2];
352 DmtxByteList outputTmp;
353
354 if (stream->currentScheme != DmtxSchemeX12) {
356 return;
357 }
358
359 /* Should have exactly one or two input values left */
360 DmtxAssert(valueList->length == 1 || valueList->length == 2);
361
362 /* Roll back input progress */
363 for (i = 0; i < valueList->length; i++) {
365 CHKERR;
366 }
367
368 /* Encode up to 2 codewords to a temporary stream */
369 outputTmp = encodeTmpRemainingInAscii(stream, outputTmpStorage, sizeof(outputTmpStorage), &passFail);
370
371 sizeIdx = findSymbolSize(stream->output->length + 1, sizeIdxRequest);
372 symbolRemaining = getRemainingSymbolCapacity(stream->output->length, sizeIdx);
373
374 if (outputTmp.length == 1 && symbolRemaining == 1) {
375 /* End of symbol condition (XXX) */
377 CHKERR;
378 appendValueAscii(stream, outputTmp.b[0]);
379 CHKERR;
380
381 /* Register progress since encoding happened outside normal path */
382 stream->inputNext = stream->input->length;
383 streamMarkComplete(stream, sizeIdx);
384 } else {
385 /* Finish in ASCII (XXX) */
387 CHKERR;
388 for (i = 0; i < outputTmp.length; i++) {
389 appendValueAscii(stream, outputTmp.b[i]);
390 }
391 CHKERR;
392
393 sizeIdx = findSymbolSize(stream->output->length, sizeIdxRequest);
394 padRemainingInAscii(stream, sizeIdx);
395
396 /* Register progress since encoding happened outside normal path */
397 stream->inputNext = stream->input->length;
398 streamMarkComplete(stream, sizeIdx);
399 }
400}
401
406{
407 DmtxEncodeStream streamTmp;
408 DmtxByte inputValue;
409 DmtxByte valueListStorage[6];
410 DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage));
411 DmtxPassFail passFail;
412
413 /* Create temporary copy of stream to track test input progress */
414 streamTmp = *stream;
415 streamTmp.currentScheme = DmtxSchemeX12;
416 streamTmp.outputChainValueCount = 0;
417 streamTmp.outputChainWordCount = 0;
418 streamTmp.reason = NULL;
419 streamTmp.sizeIdx = DmtxUndefined;
420 streamTmp.status = DmtxStatusEncoding;
421 streamTmp.output = NULL;
422
423 while (streamInputHasNext(&streamTmp)) {
424 inputValue = streamInputAdvanceNext(&streamTmp);
425 if (stream->status != DmtxStatusEncoding) {
427 return DmtxFalse;
428 }
429
430 /* Expand next input value into up to 4 CTX values and add to valueList */
431 pushCTXValues(&valueList, inputValue, streamTmp.currentScheme, &passFail, stream->fnc1);
432 if (passFail == DmtxFail) {
434 return DmtxFalse;
435 }
436
437 /* Not a final partial chunk */
438 if (valueList.length >= 3) {
439 return DmtxFalse;
440 }
441 }
442
443 return (valueList.length == 0) ? DmtxFalse : DmtxTrue;
444}
445
450static void pushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme, DmtxPassFail *passFail,
451 int fnc1)
452{
453 DmtxAssert(valueList->length <= 2);
454
455 /* Handle extended ASCII with Upper Shift character */
456 if (inputValue > 127 && (fnc1 == DmtxUndefined || (int)inputValue != fnc1)) {
457 if (targetScheme == DmtxSchemeX12) {
458 *passFail = DmtxFail;
459 return;
460 } else {
461 dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail);
463 dmtxByteListPush(valueList, 30, passFail);
465 inputValue -= 128;
466 }
467 }
468
469 /* Handle all other characters according to encodation scheme */
470 if (targetScheme == DmtxSchemeX12) {
471 if (inputValue == 13) {
472 dmtxByteListPush(valueList, 0, passFail);
474 } else if (inputValue == 42) {
475 dmtxByteListPush(valueList, 1, passFail);
477 } else if (inputValue == 62) {
478 dmtxByteListPush(valueList, 2, passFail);
480 } else if (inputValue == 32) {
481 dmtxByteListPush(valueList, 3, passFail);
483 } else if (inputValue >= 48 && inputValue <= 57) {
484 dmtxByteListPush(valueList, inputValue - 44, passFail);
486 } else if (inputValue >= 65 && inputValue <= 90) {
487 dmtxByteListPush(valueList, inputValue - 51, passFail);
489 } else {
490 *passFail = DmtxFail;
491 return;
492 }
493 } else {
494 /* targetScheme is C40 or Text */
495
496 /* Check for FNC1 character */
497 if (fnc1 != DmtxUndefined && (int)inputValue == fnc1) {
498 dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail);
500 dmtxByteListPush(valueList, 27, passFail);
501 RETURN_IF_FAIL; /* C40 version of FNC1 */
502 } else if (inputValue <= 31) {
503 dmtxByteListPush(valueList, DmtxValueCTXShift1, passFail);
505 dmtxByteListPush(valueList, inputValue, passFail);
507 } else if (inputValue == 32) {
508 dmtxByteListPush(valueList, 3, passFail);
510 } else if (inputValue <= 47) {
511 dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail);
513 dmtxByteListPush(valueList, inputValue - 33, passFail);
515 } else if (inputValue <= 57) {
516 dmtxByteListPush(valueList, inputValue - 44, passFail);
518 } else if (inputValue <= 64) {
519 dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail);
521 dmtxByteListPush(valueList, inputValue - 43, passFail);
523 } else if (inputValue <= 90 && targetScheme == DmtxSchemeC40) {
524 dmtxByteListPush(valueList, inputValue - 51, passFail);
526 } else if (inputValue <= 90 && targetScheme == DmtxSchemeText) {
527 dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail);
529 dmtxByteListPush(valueList, inputValue - 64, passFail);
531 } else if (inputValue <= 95) {
532 dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail);
534 dmtxByteListPush(valueList, inputValue - 69, passFail);
536 } else if (inputValue == 96 && targetScheme == DmtxSchemeText) {
537 dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail);
539 dmtxByteListPush(valueList, 0, passFail);
541 } else if (inputValue <= 122 && targetScheme == DmtxSchemeText) {
542 dmtxByteListPush(valueList, inputValue - 83, passFail);
544 } else if (inputValue <= 127) {
545 dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail);
547 dmtxByteListPush(valueList, inputValue - 96, passFail);
549 } else {
550 *passFail = DmtxFail;
551 return;
552 }
553 }
554
555 *passFail = DmtxPass;
556}
557
562static DmtxBoolean isCTX(int scheme)
563{
565
566 if (scheme == DmtxSchemeC40 || scheme == DmtxSchemeText || scheme == DmtxSchemeX12) {
567 isCTX = DmtxTrue;
568 } else {
570 }
571
572 return isCTX;
573}
574
579static void shiftValueListBy3(DmtxByteList *list, DmtxPassFail *passFail)
580{
581 int i;
582
583 /* Shift values */
584 for (i = 0; i < list->length - 3; i++) {
585 list->b[i] = list->b[i + 3];
586 }
587
588 /* Shorten list by 3 (or less) */
589 for (i = 0; i < 3; i++) {
590 dmtxByteListPop(list, passFail);
591 if (*passFail == DmtxFail) {
592 return;
593 }
594
595 if (list->length == 0) {
596 break;
597 }
598 }
599
600 *passFail = DmtxPass;
601}
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
#define DmtxPassFail
Definition dmtx.h:42
#define DmtxTrue
Definition dmtx.h:47
DmtxByteList dmtxByteListBuild(DmtxByte *storage, int capacity)
void dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail)
#define DmtxBoolean
Definition dmtx.h:46
#define DmtxPass
Definition dmtx.h:43
#define DmtxUndefined
Definition dmtx.h:40
@ DmtxSchemeText
Definition dmtx.h:92
@ DmtxSchemeC40
Definition dmtx.h:91
@ DmtxSchemeX12
Definition dmtx.h:93
@ DmtxSchemeAscii
Definition dmtx.h:90
DmtxByte dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail)
#define DmtxFalse
Definition dmtx.h:48
unsigned char DmtxByte
Definition dmtx.h:293
#define DmtxFail
Definition dmtx.h:44
@ DmtxStatusComplete
Definition dmtx.h:81
@ DmtxStatusEncoding
Definition dmtx.h:80
#define RETURN_IF_FAIL
static void shiftValueListBy3(DmtxByteList *list, DmtxPassFail *passFail)
#define CHKSIZE
static void completePartialX12(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
Partial chunks are not valid in X12.
static void completeIfDoneCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
Complete C40/Text/X12 encoding if it matches a known end-of-symbol condition.
static void appendUnlatchCTX(DmtxEncodeStream *stream)
static DmtxBoolean partialX12ChunkRemains(DmtxEncodeStream *stream)
Return DmtxTrue 1 or 2 X12 values remain, otherwise DmtxFalse.
static void appendValuesCTX(DmtxEncodeStream *stream, DmtxByteList *valueList)
static void encodeNextChunkCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
static void pushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme, DmtxPassFail *passFail, int fnc1)
#define CHKPASS
static void completePartialC40Text(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
The remaining values can exist in 3 possible cases:
#define CHKERR
static DmtxBoolean isCTX(int scheme)
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
static DmtxByte streamInputAdvanceNext(DmtxEncodeStream *stream)
#define DmtxValueCTXShift1
Definition dmtxstatic.h:39
static void streamOutputChainAppend(DmtxEncodeStream *stream, DmtxByte value)
@ DmtxErrorUnsupportedCharacter
Definition dmtxstatic.h:395
@ DmtxErrorIncompleteValueList
Definition dmtxstatic.h:403
@ DmtxErrorUnknown
Definition dmtxstatic.h:394
@ DmtxErrorNotOnByteBoundary
Definition dmtxstatic.h:396
@ DmtxErrorUnexpectedScheme
Definition dmtxstatic.h:402
static void padRemainingInAscii(DmtxEncodeStream *stream, int sizeIdx)
#define DmtxValueCTXShift3
Definition dmtxstatic.h:41
static void streamMarkInvalid(DmtxEncodeStream *stream, int reasonIdx)
#define DmtxAssert(expr)
Definition dmtxstatic.h:96
static DmtxByte streamInputPeekNext(DmtxEncodeStream *stream)
static void streamInputAdvancePrev(DmtxEncodeStream *stream)
static int findSymbolSize(int dataWords, int sizeIdxRequest)
static DmtxByteList encodeTmpRemainingInAscii(DmtxEncodeStream *stream, DmtxByte *storage, int capacity, DmtxPassFail *passFail)
static void streamMarkComplete(DmtxEncodeStream *stream, int sizeIdx)
#define DmtxUnlatchImplicit
Definition dmtxstatic.h:55
static void encodeChangeScheme(DmtxEncodeStream *stream, DmtxScheme targetScheme, int unlatchType)
static int getRemainingSymbolCapacity(int outputLength, int sizeIdx)
static void appendValueAscii(DmtxEncodeStream *stream, DmtxByte value)
#define DmtxUnlatchExplicit
Definition dmtxstatic.h:54
#define DmtxValueCTXShift2
Definition dmtxstatic.h:40
#define DmtxValueFNC1
Definition dmtxstatic.h:42
static void streamMarkFatal(DmtxEncodeStream *stream, int reasonIdx)
static DmtxBoolean streamInputHasNext(DmtxEncodeStream *stream)
#define DmtxValueCTXUnlatch
Definition dmtxstatic.h:34
DmtxByteList Use signed int for length fields instead of size_t to play nicely with RS arithmetic.
DmtxByteList * input
Definition dmtx.h:318
DmtxByteList * output
Definition dmtx.h:319
DmtxStatus status
Definition dmtx.h:317