/** * Simple single scheme encoding uses "Normal" * The optimizer needs to track "Expanded" and "Compact" streams separately, so they * are called explicitly. * * Normal: Automatically collapses 2 consecutive digits into one codeword * Expanded: Uses a whole codeword to represent a digit (never collapses) * Compact: Collapses 2 digits into a single codeword or marks the stream * invalid if either values are not digits * * \param stream * \param option [Expanded|Compact|Normal] */ static void EncodeNextChunkAscii(DmtxEncodeStream *stream, int option) { DmtxByte v0, v1; DmtxBoolean compactDigits; if(StreamInputHasNext(stream)) { v0 = StreamInputAdvanceNext(stream); CHKERR; if((option == DmtxEncodeCompact || option == DmtxEncodeNormal) && StreamInputHasNext(stream)) { v1 = StreamInputPeekNext(stream); CHKERR; compactDigits = (ISDIGIT(v0) && ISDIGIT(v1)) ? DmtxTrue : DmtxFalse; } else /* option == DmtxEncodeFull */ { v1 = 0; compactDigits = DmtxFalse; } if(compactDigits == DmtxTrue) { /* Two adjacent digit chars: Make peek progress official and encode */ StreamInputAdvanceNext(stream); CHKERR; AppendValueAscii(stream, 10 * (v0-'0') + (v1-'0') + 130); CHKERR; } else if(option == DmtxEncodeCompact) { /* Can't compact non-digits */ StreamMarkInvalid(stream, DmtxErrorCantCompactNonDigits); } else { /* Encode single ASCII value */ if(v0 < 128) { /* Regular ASCII */ AppendValueAscii(stream, v0 + 1); CHKERR; } else { /* Extended ASCII */ AppendValueAscii(stream, DmtxValueAsciiUpperShift); CHKERR; AppendValueAscii(stream, v0 - 127); CHKERR; } } } }
static void EncodeNextChunkBase256(DmtxEncodeStream *stream) { DmtxByte value; if(StreamInputHasNext(stream)) { value = StreamInputAdvanceNext(stream); CHKERR; AppendValueBase256(stream, value); CHKERR; } }
static void EncodeNextChunkCTX(DmtxEncodeStream *stream, int sizeIdxRequest) { DmtxPassFail passFail; DmtxByte inputValue; DmtxByte valueListStorage[6]; DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage)); while(StreamInputHasNext(stream)) { inputValue = StreamInputAdvanceNext(stream); CHKERR; /* Expand next input value into up to 4 CTX values and add to valueList */ PushCTXValues(&valueList, inputValue, stream->currentScheme, &passFail); if(passFail == DmtxFail) { /* XXX Perhaps PushCTXValues should return this error code */ StreamMarkInvalid(stream, DmtxErrorUnsupportedCharacter); return; } /* If there at least 3 CTX values available encode them to output */ while(valueList.length >= 3) { AppendValuesCTX(stream, &valueList); CHKERR; ShiftValueListBy3(&valueList, &passFail); CHKPASS; } /* Finished on byte boundary -- done with current chunk */ if(valueList.length == 0) break; } /* * Special case: If all input values have been consumed and 1 or 2 unwritten * C40/Text/X12 values remain, finish encoding the symbol according to the * established end-of-symbol conditions. */ if(!StreamInputHasNext(stream) && valueList.length > 0) { if(stream->currentScheme == DmtxSchemeX12) { CompletePartialX12(stream, &valueList, sizeIdxRequest); CHKERR; } else { CompletePartialC40Text(stream, &valueList, sizeIdxRequest); CHKERR; } } }
/** * Return DmtxTrue 1 or 2 X12 values remain, otherwise DmtxFalse */ static DmtxBoolean PartialX12ChunkRemains(DmtxEncodeStream *stream) { DmtxEncodeStream streamTmp; DmtxByte inputValue; DmtxByte valueListStorage[6]; DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage)); DmtxPassFail passFail; /* Create temporary copy of stream to track test input progress */ streamTmp = *stream; streamTmp.currentScheme = DmtxSchemeX12; streamTmp.outputChainValueCount = 0; streamTmp.outputChainWordCount = 0; streamTmp.reason = NULL; streamTmp.sizeIdx = DmtxUndefined; streamTmp.status = DmtxStatusEncoding; streamTmp.output = NULL; while(StreamInputHasNext(&streamTmp)) { inputValue = StreamInputAdvanceNext(&streamTmp); if(stream->status != DmtxStatusEncoding) { StreamMarkInvalid(stream, DmtxErrorUnknown); return DmtxFalse; } /* Expand next input value into up to 4 CTX values and add to valueList */ PushCTXValues(&valueList, inputValue, streamTmp.currentScheme, &passFail); if(passFail == DmtxFail) { StreamMarkInvalid(stream, DmtxErrorUnknown); return DmtxFalse; } /* Not a final partial chunk */ if(valueList.length >= 3) return DmtxFalse; } return (valueList.length == 0) ? DmtxFalse : DmtxTrue; }