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 dmtxencodestream.c
14  * \brief DmtxEncodeStream implementation
15  */
16 
17 /**
18  *
19  *
20  */
21 static DmtxEncodeStream
StreamInit(DmtxByteList * input,DmtxByteList * output)22 StreamInit(DmtxByteList *input, DmtxByteList *output)
23 {
24    DmtxEncodeStream stream;
25 
26    stream.input = input;
27    stream.output = output;
28 
29    stream.currentScheme = DmtxSchemeAscii;
30    stream.inputNext = 0;
31    stream.outputChainValueCount = 0;
32    stream.outputChainWordCount = 0;
33    stream.reason = NULL;
34    stream.sizeIdx = DmtxUndefined;
35    stream.status = DmtxStatusEncoding;
36 
37    return stream;
38 }
39 
40 /**
41  *
42  *
43  */
44 static void
StreamCopy(DmtxEncodeStream * dst,DmtxEncodeStream * src)45 StreamCopy(DmtxEncodeStream *dst, DmtxEncodeStream *src)
46 {
47    DmtxPassFail passFail;
48 
49    dst->currentScheme = src->currentScheme;
50    dst->inputNext = src->inputNext;
51    dst->outputChainValueCount = src->outputChainValueCount;
52    dst->outputChainWordCount = src->outputChainWordCount;
53    dst->reason = src->reason;
54    dst->sizeIdx = src->sizeIdx;
55    dst->status = src->status;
56    dst->input = src->input;
57    dst->fnc1 = src->fnc1;
58 
59    dmtxByteListCopy(dst->output, src->output, &passFail);
60 }
61 
62 /**
63  *
64  *
65  */
66 static void
StreamMarkComplete(DmtxEncodeStream * stream,int sizeIdx)67 StreamMarkComplete(DmtxEncodeStream *stream, int sizeIdx)
68 {
69    if(stream->status == DmtxStatusEncoding)
70    {
71       stream->sizeIdx = sizeIdx;
72       stream->status = DmtxStatusComplete;
73       assert(stream->reason == NULL);
74    }
75 }
76 
77 /**
78  *
79  *
80  */
81 static void
StreamMarkInvalid(DmtxEncodeStream * stream,int reasonIdx)82 StreamMarkInvalid(DmtxEncodeStream *stream, int reasonIdx)
83 {
84    stream->status = DmtxStatusInvalid;
85    stream->reason = dmtxErrorMessage[reasonIdx];
86 }
87 
88 /**
89  *
90  *
91  */
92 static void
StreamMarkFatal(DmtxEncodeStream * stream,int reasonIdx)93 StreamMarkFatal(DmtxEncodeStream *stream, int reasonIdx)
94 {
95    stream->status = DmtxStatusFatal;
96    stream->reason = dmtxErrorMessage[reasonIdx];
97 }
98 
99 /**
100  * push on newest/last append
101  * used for encoding each output cw
102  */
103 static void
StreamOutputChainAppend(DmtxEncodeStream * stream,DmtxByte value)104 StreamOutputChainAppend(DmtxEncodeStream *stream, DmtxByte value)
105 {
106    DmtxPassFail passFail;
107 
108    dmtxByteListPush(stream->output, value, &passFail);
109 
110    if(passFail == DmtxPass)
111       stream->outputChainWordCount++;
112    else
113       StreamMarkFatal(stream, DmtxErrorOutOfBounds);
114 }
115 
116 /**
117  * pop off newest/last
118  * used for edifact
119  */
120 static DmtxByte
StreamOutputChainRemoveLast(DmtxEncodeStream * stream)121 StreamOutputChainRemoveLast(DmtxEncodeStream *stream)
122 {
123    DmtxByte value;
124    DmtxPassFail passFail;
125 
126    if(stream->outputChainWordCount > 0)
127    {
128       value = dmtxByteListPop(stream->output, &passFail);
129       stream->outputChainWordCount--;
130    }
131    else
132    {
133       value = 0;
134       StreamMarkFatal(stream, DmtxErrorEmptyList);
135    }
136 
137    return value;
138 }
139 
140 /**
141  * overwrite arbitrary element
142  * used for binary length changes
143  */
144 static void
StreamOutputSet(DmtxEncodeStream * stream,int index,DmtxByte value)145 StreamOutputSet(DmtxEncodeStream *stream, int index, DmtxByte value)
146 {
147    if(index < 0 || index >= stream->output->length)
148       StreamMarkFatal(stream, DmtxErrorOutOfBounds);
149    else
150       stream->output->b[index] = value;
151 }
152 
153 /**
154  *
155  *
156  */
157 static DmtxBoolean
StreamInputHasNext(DmtxEncodeStream * stream)158 StreamInputHasNext(DmtxEncodeStream *stream)
159 {
160    return (stream->inputNext < stream->input->length) ? DmtxTrue : DmtxFalse;
161 }
162 
163 /**
164  * peek at first/oldest
165  * used for ascii double digit
166  */
167 static DmtxByte
StreamInputPeekNext(DmtxEncodeStream * stream)168 StreamInputPeekNext(DmtxEncodeStream *stream)
169 {
170    DmtxByte value = 0;
171 
172    if(StreamInputHasNext(stream))
173       value = stream->input->b[stream->inputNext];
174    else
175       StreamMarkFatal(stream, DmtxErrorOutOfBounds);
176 
177    return value;
178 }
179 
180 /**
181  * used as each input cw is processed
182  *
183  * \param value Value to populate, can be null (for blind dequeues)
184  * \param stream
185  */
186 static DmtxByte
StreamInputAdvanceNext(DmtxEncodeStream * stream)187 StreamInputAdvanceNext(DmtxEncodeStream *stream)
188 {
189    DmtxByte value;
190 
191    value = StreamInputPeekNext(stream);
192 
193    if(stream->status == DmtxStatusEncoding)
194       stream->inputNext++; /* XXX is this what we really mean here? */
195 
196    return value;
197 }
198 
199 /**
200  * used as each input cw is processed
201  *
202  * \param value Value to populate, can be null (for blind dequeues)
203  * \param stream
204  */
205 static void
StreamInputAdvancePrev(DmtxEncodeStream * stream)206 StreamInputAdvancePrev(DmtxEncodeStream *stream)
207 {
208    if(stream->inputNext > 0)
209       stream->inputNext--;
210    else
211       StreamMarkFatal(stream, DmtxErrorOutOfBounds);
212 }
213