1 /**
2 * libdmtx - Data Matrix Encoding/Decoding Library
3 * Copyright 2011 Mike Laughton. All rights reserved.
4 * Copyright 2012-2016 Vadim A. Misbakh-Soloviov. All rights reserved.
5 *
6 * See LICENSE file in the main project directory for full
7 * terms of use and distribution.
8 *
9 * Contact:
10 * Vadim A. Misbakh-Soloviov <dmtx@mva.name>
11 * Mike Laughton <mike@dragonflylogic.com>
12 *
13 * \file dmtxencodeedifact.c
14 * \brief Edifact encoding rules
15 */
16
17 /**
18 *
19 *
20 */
21 static void
EncodeNextChunkEdifact(DmtxEncodeStream * stream)22 EncodeNextChunkEdifact(DmtxEncodeStream *stream)
23 {
24 DmtxByte value;
25
26 if(StreamInputHasNext(stream))
27 {
28 /* Check for FNC1 character, which needs to be sent in ASCII */
29 value = StreamInputPeekNext(stream); CHKERR;
30 if(stream->fnc1 != DmtxUndefined && (int)value == stream->fnc1) {
31 EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
32
33 StreamInputAdvanceNext(stream); CHKERR;
34 AppendValueAscii(stream, DmtxValueFNC1); CHKERR;
35 return;
36 }
37
38 value = StreamInputAdvanceNext(stream); CHKERR;
39 AppendValueEdifact(stream, value); CHKERR;
40 }
41 }
42
43 /**
44 *
45 *
46 */
47 static void
AppendValueEdifact(DmtxEncodeStream * stream,DmtxByte value)48 AppendValueEdifact(DmtxEncodeStream *stream, DmtxByte value)
49 {
50 DmtxByte edifactValue, previousOutput;
51
52 CHKSCHEME(DmtxSchemeEdifact);
53
54 /*
55 * TODO: KECA -> korean, circles
56 * TODO: UNOX -> ISO-2022-JP
57 * TODO: and so on
58 */
59 if(value < 32 || value > 94)
60 {
61 StreamMarkInvalid(stream, DmtxChannelUnsupportedChar);
62 return;
63 }
64
65 edifactValue = (value & 0x3f) << 2;
66
67 switch(stream->outputChainValueCount % 4)
68 {
69 case 0:
70 StreamOutputChainAppend(stream, edifactValue); CHKERR;
71 break;
72 case 1:
73 previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
74 StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 6)); CHKERR;
75 StreamOutputChainAppend(stream, edifactValue << 2); CHKERR;
76 break;
77 case 2:
78 previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
79 StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 4)); CHKERR;
80 StreamOutputChainAppend(stream, edifactValue << 4); CHKERR;
81 break;
82 case 3:
83 previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
84 StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 2)); CHKERR;
85 break;
86 }
87
88 stream->outputChainValueCount++;
89 }
90
91 /**
92 * Complete EDIFACT encoding if it matches a known end-of-symbol condition.
93 *
94 * Term Clean Symbol ASCII Codeword
95 * Cond Bound Remain Remain Sequence
96 * ---- ----- ------ ------ -----------
97 * (a) Y 0 0 [none]
98 * (b) Y 1 0 PAD
99 * (c) Y 1 1 ASCII
100 * (d) Y 2 0 PAD PAD
101 * (e) Y 2 1 ASCII PAD
102 * (f) Y 2 2 ASCII ASCII
103 * - - 0 UNLATCH
104 *
105 * If not matching any of the above, continue without doing anything.
106 */
107 static void
CompleteIfDoneEdifact(DmtxEncodeStream * stream,int sizeIdxRequest)108 CompleteIfDoneEdifact(DmtxEncodeStream *stream, int sizeIdxRequest)
109 {
110 int i;
111 int sizeIdx;
112 int symbolRemaining;
113 DmtxBoolean cleanBoundary;
114 DmtxPassFail passFail;
115 DmtxByte outputTmpStorage[3];
116 DmtxByteList outputTmp;
117
118 if(stream->status == DmtxStatusComplete)
119 return;
120
121 /*
122 * If we just completed a triplet (cleanBoundary), 1 or 2 symbol codewords
123 * remain, and our remaining inputs (if any) represented in ASCII would fit
124 * in the remaining space, encode them in ASCII with an implicit unlatch.
125 */
126
127 cleanBoundary = (stream->outputChainValueCount % 4 == 0) ? DmtxTrue : DmtxFalse;
128
129 if(cleanBoundary == DmtxTrue)
130 {
131 /* Encode up to 3 codewords to a temporary stream */
132 outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage,
133 sizeof(outputTmpStorage), &passFail);
134
135 if(passFail == DmtxFail)
136 {
137 StreamMarkFatal(stream, DmtxErrorUnknown);
138 return;
139 }
140
141 if(outputTmp.length < 3)
142 {
143 /* Find minimum symbol size for projected length */
144 sizeIdx = FindSymbolSize(stream->output->length + outputTmp.length, sizeIdxRequest); CHKSIZE;
145
146 /* Find remaining capacity over current length */
147 symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); CHKERR;
148
149 if(symbolRemaining < 3 && outputTmp.length <= symbolRemaining)
150 {
151 EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR;
152
153 for(i = 0; i < outputTmp.length; i++)
154 {
155 AppendValueAscii(stream, outputTmp.b[i]); CHKERR;
156 }
157
158 /* Register progress since encoding happened outside normal path */
159 stream->inputNext = stream->input->length;
160
161 /* Pad remaining if necessary */
162 PadRemainingInAscii(stream, sizeIdx); CHKERR;
163 StreamMarkComplete(stream, sizeIdx);
164 return;
165 }
166 }
167 }
168
169 if(!StreamInputHasNext(stream))
170 {
171 sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
172 symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); CHKERR;
173
174 /* Explicit unlatch required unless on clean boundary and full symbol */
175 if(cleanBoundary == DmtxFalse || symbolRemaining > 0)
176 {
177 EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
178 sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
179 PadRemainingInAscii(stream, sizeIdx); CHKERR;
180 }
181
182 StreamMarkComplete(stream, sizeIdx);
183 }
184 }
185