DmtxPassFail RsEncode(DmtxMessage *message, int sizeIdx) { int i, j; int blockStride, blockIdx; int blockErrorWords, symbolDataWords, symbolErrorWords, symbolTotalWords; DmtxPassFail passFail; DmtxByte val, *eccPtr; DmtxByte genStorage[MAX_ERROR_WORD_COUNT]; DmtxByte eccStorage[MAX_ERROR_WORD_COUNT]; DmtxByteList gen = dmtxByteListBuild(genStorage, sizeof(genStorage)); DmtxByteList ecc = dmtxByteListBuild(eccStorage, sizeof(eccStorage)); blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx); blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx); symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx); symbolTotalWords = symbolDataWords + symbolErrorWords; /* Populate generator polynomial */ RsGenPoly(&gen, blockErrorWords); /* For each interleaved block... */ for(blockIdx = 0; blockIdx < blockStride; blockIdx++) { /* Generate error codewords */ dmtxByteListInit(&ecc, blockErrorWords, 0, &passFail); CHKPASS; for(i = blockIdx; i < symbolDataWords; i += blockStride) { val = GfAdd(ecc.b[blockErrorWords-1], message->code[i]); for(j = blockErrorWords - 1; j > 0; j--) { DMTX_CHECK_BOUNDS(&ecc, j); DMTX_CHECK_BOUNDS(&ecc, j-1); DMTX_CHECK_BOUNDS(&gen, j); ecc.b[j] = GfAdd(ecc.b[j-1], GfMult(gen.b[j], val)); } ecc.b[0] = GfMult(gen.b[0], val); } /* Copy to output message */ eccPtr = ecc.b + blockErrorWords; for(i = symbolDataWords + blockIdx; i < symbolTotalWords; i += blockStride) message->code[i] = *(--eccPtr); assert(ecc.b == eccPtr); } return DmtxPass; }
DmtxBoolean RsFindErrorLocations(DmtxByteList *loc, const DmtxByteList *elp) { int i, j; int lambda = elp->length - 1; DmtxPassFail passFail; DmtxByte q, regStorage[MAX_ERROR_WORD_COUNT]; DmtxByteList reg = dmtxByteListBuild(regStorage, sizeof(regStorage)); dmtxByteListCopy(®, elp, &passFail); CHKPASS; dmtxByteListInit(loc, 0, 0, &passFail); CHKPASS; for(i = 1; i <= NN; i++) { for(q = 1, j = 1; j <= lambda; j++) { reg.b[j] = GfMultAntilog(reg.b[j], j); q = GfAdd(q, reg.b[j]); } if(q == 0) { dmtxByteListPush(loc, NN - i, &passFail); CHKPASS; } } return (loc->length == lambda) ? DmtxTrue : DmtxFalse; }
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; } } }
DmtxPassFail RsRepairErrors(DmtxByteList *rec, const DmtxByteList *loc, const DmtxByteList *elp, const DmtxByteList *syn) { int i, j, q; int lambda = elp->length - 1; DmtxPassFail passFail; DmtxByte zVal, root, err; DmtxByte zStorage[MAX_ERROR_WORD_COUNT+1]; DmtxByteList z = dmtxByteListBuild(zStorage, sizeof(zStorage)); /* Form polynomial z(x) */ dmtxByteListPush(&z, 1, &passFail); CHKPASS; for(i = 1; i <= lambda; i++) { for(zVal = GfAdd(syn->b[i], elp->b[i]), j = 1; j < i; j++) zVal= GfAdd(zVal, GfMult(elp->b[i-j], syn->b[j])); dmtxByteListPush(&z, zVal, &passFail); CHKPASS; } for(i = 0; i < lambda; i++) { /* Calculate numerator of error term */ root = NN - loc->b[i]; for(err = 1, j = 1; j <= lambda; j++) err = GfAdd(err, GfMultAntilog(z.b[j], j * root)); if(err == 0) continue; /* Calculate denominator of error term */ for(q = 0, j = 0; j < lambda; j++) { if(j != i) q += log301[1 ^ antilog301[(loc->b[j] + root) % NN]]; } q %= NN; err = GfMultAntilog(err, NN - q); rec->b[loc->b[i]] = GfAdd(rec->b[loc->b[i]], err); } return DmtxPass; }
/** * 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; }
/** * It's safe to compare output length because all targetState combinations * start on same input and encodes same number of inputs. Only difference * is the number of latches/unlatches that are also encoded */ static void StreamAdvanceFromBest(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int sizeIdxRequest) { enum SchemeState fromState; DmtxScheme targetScheme; DmtxEncodeOption encodeOption; DmtxByte outputTempStorage[4096]; DmtxByteList outputTemp = dmtxByteListBuild(outputTempStorage, sizeof(outputTempStorage)); DmtxEncodeStream streamTemp; DmtxEncodeStream *targetStream = &(streamsNext[targetState]); streamTemp.output = &outputTemp; /* Set directly instead of calling StreamInit() */ targetScheme = GetScheme(targetState); if(targetState == AsciiFull) encodeOption = DmtxEncodeFull; else if(targetState == AsciiCompactOffset0 || targetState == AsciiCompactOffset1) encodeOption = DmtxEncodeCompact; else encodeOption = DmtxEncodeNormal; for(fromState = 0; fromState < SchemeStateCount; fromState++) { if(streamsBest[fromState].status != DmtxStatusEncoding || ValidStateSwitch(fromState, targetState) == DmtxFalse) { continue; } StreamCopy(&streamTemp, &(streamsBest[fromState])); EncodeNextChunk(&streamTemp, targetScheme, encodeOption, sizeIdxRequest); if(fromState == 0 || (streamTemp.status != DmtxStatusInvalid && streamTemp.output->length < targetStream->output->length)) { StreamCopy(targetStream, &streamTemp); } } }
/** * consider receiving instantiated DmtxByteList instead of the output components */ static DmtxByteList EncodeTmpRemainingInAscii(DmtxEncodeStream *stream, DmtxByte *storage, int capacity, DmtxPassFail *passFail) { DmtxEncodeStream streamAscii; DmtxByteList output = dmtxByteListBuild(storage, capacity); /* Create temporary copy of stream that writes to storage */ streamAscii = *stream; streamAscii.currentScheme = DmtxSchemeAscii; streamAscii.outputChainValueCount = 0; streamAscii.outputChainWordCount = 0; streamAscii.reason = NULL; streamAscii.sizeIdx = DmtxUndefined; streamAscii.status = DmtxStatusEncoding; streamAscii.output = &output; while(dmtxByteListHasCapacity(streamAscii.output)) { if(StreamInputHasNext(&streamAscii)) EncodeNextChunkAscii(&streamAscii, DmtxEncodeNormal); /* No CHKERR */ else break; } /* * We stopped encoding before attempting to write beyond output boundary so * any stream errors are truly unexpected. The passFail status indicates * whether output.length can be trusted by the calling function. */ if(streamAscii.status == DmtxStatusInvalid || streamAscii.status == DmtxStatusFatal) *passFail = DmtxFail; else *passFail = DmtxPass; return output; }
DmtxBoolean RsFindErrorLocatorPoly(DmtxByteList *elpOut, const DmtxByteList *syn, int errorWordCount, int maxCorrectable) { int i, iNext, j; int m, mCmp, lambda; DmtxByte disTmp, disStorage[MAX_ERROR_WORD_COUNT+1]; DmtxByte elpStorage[MAX_ERROR_WORD_COUNT+2][MAX_ERROR_WORD_COUNT]; DmtxByteList dis, elp[MAX_ERROR_WORD_COUNT+2]; DmtxPassFail passFail; dis = dmtxByteListBuild(disStorage, sizeof(disStorage)); dmtxByteListInit(&dis, 0, 0, &passFail); CHKPASS; for(i = 0; i < MAX_ERROR_WORD_COUNT + 2; i++) { elp[i] = dmtxByteListBuild(elpStorage[i], sizeof(elpStorage[i])); dmtxByteListInit(&elp[i], 0, 0, &passFail); CHKPASS; } /* iNext = 0 */ dmtxByteListPush(&elp[0], 1, &passFail); CHKPASS; dmtxByteListPush(&dis, 1, &passFail); CHKPASS; /* iNext = 1 */ dmtxByteListPush(&elp[1], 1, &passFail); CHKPASS; dmtxByteListPush(&dis, syn->b[1], &passFail); CHKPASS; for(iNext = 2, i = 1; /* explicit break */; i = iNext++) { if(dis.b[i] == 0) { /* Simple case: Copy directly from previous iteration */ dmtxByteListCopy(&elp[iNext], &elp[i], &passFail); CHKPASS; } else { /* Find earlier iteration (m) that provides maximal (m - lambda) */ for(m = 0, mCmp = 1; mCmp < i; mCmp++) if(dis.b[mCmp] != 0 && (mCmp - elp[mCmp].length) >= (m - elp[m].length)) m = mCmp; /* Calculate error location polynomial elp[i] (set 1st term) */ for(lambda = elp[m].length - 1, j = 0; j <= lambda; j++) elp[iNext].b[j+i-m] = antilog301[(NN - log301[dis.b[m]] + log301[dis.b[i]] + log301[elp[m].b[j]]) % NN]; /* Calculate error location polynomial elp[i] (add 2nd term) */ for(lambda = elp[i].length - 1, j = 0; j <= lambda; j++) elp[iNext].b[j] = GfAdd(elp[iNext].b[j], elp[i].b[j]); elp[iNext].length = max(elp[i].length, elp[m].length + i - m); } lambda = elp[iNext].length - 1; if(i == errorWordCount || i >= lambda + maxCorrectable) break; /* Calculate discrepancy dis.b[i] */ for(disTmp = syn->b[iNext], j = 1; j <= lambda; j++) disTmp = GfAdd(disTmp, GfMult(syn->b[iNext-j], elp[iNext].b[j])); assert(dis.length == iNext); dmtxByteListPush(&dis, disTmp, &passFail); CHKPASS; } dmtxByteListCopy(elpOut, &elp[iNext], &passFail); CHKPASS; return (lambda <= maxCorrectable) ? DmtxTrue : DmtxFalse; }
DmtxPassFail RsDecode(unsigned char *code, int sizeIdx, int fix) { int i; int blockStride, blockIdx; int blockDataWords, blockErrorWords, blockTotalWords, blockMaxCorrectable; int symbolDataWords, symbolErrorWords, symbolTotalWords; DmtxBoolean error, repairable; DmtxPassFail passFail; unsigned char *word; DmtxByte elpStorage[MAX_ERROR_WORD_COUNT]; DmtxByte synStorage[MAX_ERROR_WORD_COUNT+1]; DmtxByte recStorage[NN]; DmtxByte locStorage[NN]; DmtxByteList elp = dmtxByteListBuild(elpStorage, sizeof(elpStorage)); DmtxByteList syn = dmtxByteListBuild(synStorage, sizeof(synStorage)); DmtxByteList rec = dmtxByteListBuild(recStorage, sizeof(recStorage)); DmtxByteList loc = dmtxByteListBuild(locStorage, sizeof(locStorage)); blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx); blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx); blockMaxCorrectable = dmtxGetSymbolAttribute(DmtxSymAttribBlockMaxCorrectable, sizeIdx); symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx); symbolTotalWords = symbolDataWords + symbolErrorWords; /* For each interleaved block */ for(blockIdx = 0; blockIdx < blockStride; blockIdx++) { /* Data word count depends on blockIdx due to special case at 144x144 */ blockDataWords = dmtxGetBlockDataSize(sizeIdx, blockIdx); blockTotalWords = blockErrorWords + blockDataWords; /* Populate received list (rec) with data and error codewords */ dmtxByteListInit(&rec, 0, 0, &passFail); CHKPASS; /* Start with final error word and work backward */ word = code + symbolTotalWords + blockIdx - blockStride; for(i = 0; i < blockErrorWords; i++) { dmtxByteListPush(&rec, *word, &passFail); CHKPASS; word -= blockStride; } /* Start with final data word and work backward */ word = code + blockIdx + (blockStride * (blockDataWords - 1)); for(i = 0; i < blockDataWords; i++) { dmtxByteListPush(&rec, *word, &passFail); CHKPASS; word -= blockStride; } /* Compute syndromes (syn) */ error = RsComputeSyndromes(&syn, &rec, blockErrorWords); /* Error(s) detected: Attempt repair */ if(error) { /* Find error locator polynomial (elp) */ repairable = RsFindErrorLocatorPoly(&elp, &syn, blockErrorWords, blockMaxCorrectable); if(!repairable) return DmtxFail; /* Find error positions (loc) */ repairable = RsFindErrorLocations(&loc, &elp); if(!repairable) return DmtxFail; /* Find error values and repair */ RsRepairErrors(&rec, &loc, &elp, &syn); } /* * Overwrite output with correct/corrected values */ /* Start with first data word and work forward */ word = code + blockIdx; for(i = 0; i < blockDataWords; i++) { *word = dmtxByteListPop(&rec, &passFail); CHKPASS; word += blockStride; } /* Start with first error word and work forward */ word = code + symbolDataWords + blockIdx; for(i = 0; i < blockErrorWords; i++) { *word = dmtxByteListPop(&rec, &passFail); CHKPASS; word += blockStride; } } return DmtxPass; }
/** * 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); } } }
static int EncodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, int fnc1) { enum SchemeState state; int inputNext, c40ValueCount, textValueCount, x12ValueCount; int sizeIdx; DmtxEncodeStream *winner; DmtxPassFail passFail; DmtxEncodeStream streamsBest[SchemeStateCount]; DmtxEncodeStream streamsTemp[SchemeStateCount]; DmtxByte outputsBestStorage[SchemeStateCount][4096]; DmtxByte outputsTempStorage[SchemeStateCount][4096]; DmtxByte ctxTempStorage[4]; DmtxByteList outputsBest[SchemeStateCount]; DmtxByteList outputsTemp[SchemeStateCount]; DmtxByteList ctxTemp = dmtxByteListBuild(ctxTempStorage, sizeof(ctxTempStorage)); /* Initialize all streams with their own output storage */ for(state = 0; state < SchemeStateCount; state++) { outputsBest[state] = dmtxByteListBuild(outputsBestStorage[state], sizeof(outputsBestStorage[state])); outputsTemp[state] = dmtxByteListBuild(outputsTempStorage[state], sizeof(outputsTempStorage[state])); streamsBest[state] = StreamInit(input, &(outputsBest[state])); streamsTemp[state] = StreamInit(input, &(outputsTemp[state])); streamsBest[state].fnc1 = fnc1; streamsTemp[state].fnc1 = fnc1; } c40ValueCount = textValueCount = x12ValueCount = 0; for(inputNext = 0; inputNext < input->length; inputNext++) { StreamAdvanceFromBest(streamsTemp, streamsBest, AsciiFull, sizeIdxRequest); AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset0, inputNext, sizeIdxRequest); AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset1, inputNext, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, C40Offset0, inputNext, c40ValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, C40Offset1, inputNext, c40ValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, C40Offset2, inputNext, c40ValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, TextOffset0, inputNext, textValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, TextOffset1, inputNext, textValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, TextOffset2, inputNext, textValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, X12Offset0, inputNext, x12ValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, X12Offset1, inputNext, x12ValueCount, sizeIdxRequest); AdvanceCTX(streamsTemp, streamsBest, X12Offset2, inputNext, x12ValueCount, sizeIdxRequest); AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset0, inputNext, sizeIdxRequest); AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset1, inputNext, sizeIdxRequest); AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset2, inputNext, sizeIdxRequest); AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset3, inputNext, sizeIdxRequest); StreamAdvanceFromBest(streamsTemp, streamsBest, Base256, sizeIdxRequest); /* Overwrite best streams with new results */ for(state = 0; state < SchemeStateCount; state++) { if(streamsBest[state].status != DmtxStatusComplete) StreamCopy(&(streamsBest[state]), &(streamsTemp[state])); } dmtxByteListClear(&ctxTemp); PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeC40, &passFail, fnc1); c40ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1); dmtxByteListClear(&ctxTemp); PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeText, &passFail, fnc1); textValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1); dmtxByteListClear(&ctxTemp); PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeX12, &passFail, fnc1); x12ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1); #if DUMPSTREAMS DumpStreams(streamsBest); #endif } /* Choose the overall winner */ winner = NULL; for(state = 0; state < SchemeStateCount; state++) { if(streamsBest[state].status == DmtxStatusComplete) { if(winner == NULL || streamsBest[state].output->length < winner->output->length) winner = &(streamsBest[state]); } } /* Copy winner to output */ if(winner == NULL) { sizeIdx = DmtxUndefined; } else { dmtxByteListCopy(output, winner->output, &passFail); sizeIdx = (passFail == DmtxPass) ? winner->sizeIdx : DmtxUndefined; } return sizeIdx; }
/** * \brief Convert message into Data Matrix image * \param enc * \param inputSize * \param inputString * \param sizeIdxRequest * \return DmtxPass | DmtxFail */ extern DmtxPassFail dmtxEncodeDataMatrix(DmtxEncode *enc, int inputSize, unsigned char *inputString) { int sizeIdx; int width, height, bitsPerPixel; unsigned char *pxl; DmtxByte outputStorage[4096]; DmtxByteList output = dmtxByteListBuild(outputStorage, sizeof(outputStorage)); DmtxByteList input = dmtxByteListBuild(inputString, inputSize); input.length = inputSize; /* Future: stream = StreamInit() ... */ /* Future: EncodeDataCodewords(&stream) ... */ /* Encode input string into data codewords */ sizeIdx = EncodeDataCodewords(&input, &output, enc->sizeIdxRequest, enc->scheme, enc->fnc1); if(sizeIdx == DmtxUndefined || output.length <= 0) return DmtxFail; /* EncodeDataCodewords() should have updated any auto sizeIdx to a real one */ assert(sizeIdx != DmtxSymbolSquareAuto && sizeIdx != DmtxSymbolRectAuto); /* XXX we can remove a lot of this redundant data */ enc->region.sizeIdx = sizeIdx; enc->region.symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); enc->region.symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); enc->region.mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx); enc->region.mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx); /* Allocate memory for message and array */ enc->message = dmtxMessageCreate(sizeIdx, DmtxFormatMatrix); enc->message->padCount = 0; /* XXX this needs to be added back */ memcpy(enc->message->code, output.b, output.length); /* Generate error correction codewords */ RsEncode(enc->message, enc->region.sizeIdx); /* Module placement in region */ ModulePlacementEcc200(enc->message->array, enc->message->code, enc->region.sizeIdx, DmtxModuleOnRGB); width = 2 * enc->marginSize + (enc->region.symbolCols * enc->moduleSize); height = 2 * enc->marginSize + (enc->region.symbolRows * enc->moduleSize); bitsPerPixel = GetBitsPerPixel(enc->pixelPacking); if(bitsPerPixel == DmtxUndefined) return DmtxFail; assert(bitsPerPixel % 8 == 0); /* Allocate memory for the image to be generated */ pxl = (unsigned char *)malloc((width * bitsPerPixel / 8 + enc->rowPadBytes) * height); if(pxl == NULL) { perror("pixel malloc error"); return DmtxFail; } enc->image = dmtxImageCreate(pxl, width, height, enc->pixelPacking); if(enc->image == NULL) { perror("image malloc error"); return DmtxFail; } dmtxImageSetProp(enc->image, DmtxPropImageFlip, enc->imageFlip); dmtxImageSetProp(enc->image, DmtxPropRowPadBytes, enc->rowPadBytes); /* Insert finder and aligment pattern modules */ PrintPattern(enc); return DmtxPass; }