/** * Partial chunks are not valid in X12. Encode using ASCII instead, using * an implied unlatch if there is exactly one ascii codeword and one symbol * codeword remaining. Otherwise use explicit unlatch. */ static void CompletePartialX12(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest) { int i; int sizeIdx; int symbolRemaining; DmtxPassFail passFail; DmtxByte outputTmpStorage[2]; DmtxByteList outputTmp; if(stream->currentScheme != DmtxSchemeX12) { StreamMarkFatal(stream, DmtxErrorUnexpectedScheme); return; } /* Should have exactly one or two input values left */ assert(valueList->length == 1 || valueList->length == 2); /* Roll back input progress */ for(i = 0; i < valueList->length; i++) { StreamInputAdvancePrev(stream); CHKERR; } /* Encode up to 2 codewords to a temporary stream */ outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage, sizeof(outputTmpStorage), &passFail); sizeIdx = FindSymbolSize(stream->output->length + 1, sizeIdxRequest); symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); if(outputTmp.length == 1 && symbolRemaining == 1) { /* End of symbol condition (XXX) */ EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR; AppendValueAscii(stream, outputTmp.b[0]); CHKERR; /* Register progress since encoding happened outside normal path */ stream->inputNext = stream->input->length; StreamMarkComplete(stream, sizeIdx); } else { /* Finish in ASCII (XXX) */ EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR; for(i = 0; i < outputTmp.length; i++) AppendValueAscii(stream, outputTmp.b[i]); CHKERR; sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); PadRemainingInAscii(stream, sizeIdx); /* Register progress since encoding happened outside normal path */ stream->inputNext = stream->input->length; StreamMarkComplete(stream, sizeIdx); } }
/** * check remaining symbol capacity and remaining codewords * if the chain can finish perfectly at the end of symbol data words there is a * special one-byte length header value that can be used (i think ... read the * spec again before commiting to anything) */ static void CompleteIfDoneBase256(DmtxEncodeStream *stream, int sizeIdxRequest) { int sizeIdx; int headerByteCount, outputLength, symbolRemaining; if(stream->status == DmtxStatusComplete) return; if(!StreamInputHasNext(stream)) { headerByteCount = stream->outputChainWordCount - stream->outputChainValueCount; assert(headerByteCount == 1 || headerByteCount == 2); /* Check for special case where every last symbol word is used */ if(headerByteCount == 2) { /* Find symbol size as if headerByteCount was only 1 */ outputLength = stream->output->length - 1; sizeIdx = FindSymbolSize(outputLength, sizeIdxRequest); /* No CHKSIZE */ if(sizeIdx != DmtxUndefined) { symbolRemaining = GetRemainingSymbolCapacity(outputLength, sizeIdx); if(symbolRemaining == 0) { /* Perfect fit -- complete encoding */ UpdateBase256ChainHeader(stream, sizeIdx); CHKERR; StreamMarkComplete(stream, sizeIdx); return; } } } /* Normal case */ sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE; EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); PadRemainingInAscii(stream, sizeIdx); StreamMarkComplete(stream, sizeIdx); } }
static void CompleteIfDoneAscii(DmtxEncodeStream *stream, int sizeIdxRequest) { int sizeIdx; if(stream->status == DmtxStatusComplete) return; if(!StreamInputHasNext(stream)) { sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE; PadRemainingInAscii(stream, sizeIdx); CHKERR; StreamMarkComplete(stream, sizeIdx); } }
/** * Complete C40/Text/X12 encoding if it matches a known end-of-symbol condition. * * Term Trip Symbol Codeword * Cond Size Remain Sequence * ---- ---- ------ ----------------------- * (a) 3 2 Special case * - - UNLATCH [PAD] */ static void CompleteIfDoneCTX(DmtxEncodeStream *stream, int sizeIdxRequest) { int sizeIdx; int symbolRemaining; if(stream->status == DmtxStatusComplete) return; if(!StreamInputHasNext(stream)) { sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE; symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); if(symbolRemaining > 0) { EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR; PadRemainingInAscii(stream, sizeIdx); } StreamMarkComplete(stream, sizeIdx); } }
/** * The remaining values can exist in 3 possible cases: * * a) 1 C40/Text/X12 remaining == 1 data * b) 2 C40/Text/X12 remaining == 1 shift + 1 data * c) 2 C40/Text/X12 remaining == 1 data + 1 data * * To distinguish between cases (b) and (c), encode the final input value to * C40/Text/X12 in a temporary location and check the resulting length. If * it expands to multiple values it represents (b); otherwise it is (c). This * accounts for both shift and upper shift conditions. * * Note that in cases (a) and (c) the final C40/Text/X12 value encoded in the * previous chunk may have been a shift value, but this will be ignored by * the decoder due to the implicit shift to ASCII. <-- what if symbol is much * larger though? * * Term Value Symbol Codeword * Cond Count Remain Sequence * ---- ------- ------ ------------------------ * (b) C40 2 2 C40+C40+0 * (d) ASCII 1 1 ASCII (implicit unlatch) * (c) ASCII 1 2 UNLATCH ASCII * - - UNLATCH (finish ASCII) */ static void CompletePartialC40Text(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest) { int i; int sizeIdx1, sizeIdx2; int symbolRemaining1, symbolRemaining2; DmtxPassFail passFail; DmtxByte inputValue; DmtxByte outputTmpStorage[4]; DmtxByteList outputTmp = dmtxByteListBuild(outputTmpStorage, sizeof(outputTmpStorage)); if(stream->currentScheme != DmtxSchemeC40 && stream->currentScheme != DmtxSchemeText) { StreamMarkFatal(stream, DmtxErrorUnexpectedScheme); return; } /* Should have exactly one or two input values left */ assert(valueList->length == 1 || valueList->length == 2); sizeIdx1 = FindSymbolSize(stream->output->length + 1, sizeIdxRequest); sizeIdx2 = FindSymbolSize(stream->output->length + 2, sizeIdxRequest); symbolRemaining1 = GetRemainingSymbolCapacity(stream->output->length, sizeIdx1); symbolRemaining2 = GetRemainingSymbolCapacity(stream->output->length, sizeIdx2); if(valueList->length == 2 && symbolRemaining2 == 2) { /* End of symbol condition (b) -- Use Shift1 to pad final list value */ dmtxByteListPush(valueList, DmtxValueCTXShift1, &passFail); CHKPASS; AppendValuesCTX(stream, valueList); CHKERR; StreamMarkComplete(stream, sizeIdx2); } else { /* * Rollback progress of previously consumed input value(s) since ASCII * encoder will be used to finish the symbol. 2 rollbacks are needed if * valueList holds 2 data words (i.e., not shifts or upper shifts). */ StreamInputAdvancePrev(stream); CHKERR; inputValue = StreamInputPeekNext(stream); CHKERR; /* Test-encode most recently consumed input value to C40/Text/X12 */ PushCTXValues(&outputTmp, inputValue, stream->currentScheme, &passFail); if(valueList->length == 2 && outputTmp.length == 1) StreamInputAdvancePrev(stream); CHKERR; /* Re-use outputTmp to hold ASCII representation of 1-2 input values */ /* XXX Refactor how the DmtxByteList is passed back here */ outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage, sizeof(outputTmpStorage), &passFail); if(passFail == DmtxFail) { StreamMarkFatal(stream, DmtxErrorUnknown); return; } if(outputTmp.length == 1 && symbolRemaining1 == 1) { /* End of symbol condition (d) */ EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR; AppendValueAscii(stream, outputTmp.b[0]); CHKERR; /* Register progress since encoding happened outside normal path */ stream->inputNext = stream->input->length; StreamMarkComplete(stream, sizeIdx1); } else { /* Finish in ASCII (c) */ EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR; for(i = 0; i < outputTmp.length; i++) AppendValueAscii(stream, outputTmp.b[i]); CHKERR; sizeIdx1 = FindSymbolSize(stream->output->length, sizeIdxRequest); PadRemainingInAscii(stream, sizeIdx1); /* Register progress since encoding happened outside normal path */ stream->inputNext = stream->input->length; StreamMarkComplete(stream, sizeIdx1); } } }