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; }
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; }
/** * push on newest/last append * used for encoding each output cw */ static void StreamOutputChainAppend(DmtxEncodeStream *stream, DmtxByte value) { DmtxPassFail passFail; dmtxByteListPush(stream->output, value, &passFail); if(passFail == DmtxPass) stream->outputChainWordCount++; else StreamMarkFatal(stream, DmtxErrorOutOfBounds); }
/** * insert element at beginning of chain, shifting all following elements forward by one * used for binary length changes */ static void Base256OutputChainInsertFirst(DmtxEncodeStream *stream) { DmtxByte value; DmtxPassFail passFail; int i, chainStart; chainStart = stream->output->length - stream->outputChainWordCount; dmtxByteListPush(stream->output, 0, &passFail); if(passFail == DmtxPass) { for(i = stream->output->length - 1; i > chainStart; i--) { value = UnRandomize255State(stream->output->b[i-1], i); stream->output->b[i] = Randomize255State(value, i + 1); } stream->outputChainWordCount++; } else { StreamMarkFatal(stream, DmtxErrorUnknown); } }
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; }
static void PushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme, DmtxPassFail *passFail) { assert(valueList->length <= 2); /* Handle extended ASCII with Upper Shift character */ if(inputValue > 127) { if(targetScheme == DmtxSchemeX12) { *passFail = DmtxFail; return; } else { dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, 30, passFail); RETURN_IF_FAIL; inputValue -= 128; } } /* Handle all other characters according to encodation scheme */ if(targetScheme == DmtxSchemeX12) { if(inputValue == 13) { dmtxByteListPush(valueList, 0, passFail); RETURN_IF_FAIL; } else if(inputValue == 42) { dmtxByteListPush(valueList, 1, passFail); RETURN_IF_FAIL; } else if(inputValue == 62) { dmtxByteListPush(valueList, 2, passFail); RETURN_IF_FAIL; } else if(inputValue == 32) { dmtxByteListPush(valueList, 3, passFail); RETURN_IF_FAIL; } else if(inputValue >= 48 && inputValue <= 57) { dmtxByteListPush(valueList, inputValue - 44, passFail); RETURN_IF_FAIL; } else if(inputValue >= 65 && inputValue <= 90) { dmtxByteListPush(valueList, inputValue - 51, passFail); RETURN_IF_FAIL; } else { *passFail = DmtxFail; return; } } else { /* targetScheme is C40 or Text */ if(inputValue <= 31) { dmtxByteListPush(valueList, DmtxValueCTXShift1, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue, passFail); RETURN_IF_FAIL; } else if(inputValue == 32) { dmtxByteListPush(valueList, 3, passFail); RETURN_IF_FAIL; } else if(inputValue <= 47) { dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue - 33, passFail); RETURN_IF_FAIL; } else if(inputValue <= 57) { dmtxByteListPush(valueList, inputValue - 44, passFail); RETURN_IF_FAIL; } else if(inputValue <= 64) { dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue - 43, passFail); RETURN_IF_FAIL; } else if(inputValue <= 90 && targetScheme == DmtxSchemeC40) { dmtxByteListPush(valueList, inputValue - 51, passFail); RETURN_IF_FAIL; } else if(inputValue <= 90 && targetScheme == DmtxSchemeText) { dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue - 64, passFail); RETURN_IF_FAIL; } else if(inputValue <= 95) { dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue - 69, passFail); RETURN_IF_FAIL; } else if(inputValue == 96 && targetScheme == DmtxSchemeText) { dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, 0, passFail); RETURN_IF_FAIL; } else if(inputValue <= 122 && targetScheme == DmtxSchemeText) { dmtxByteListPush(valueList, inputValue - 83, passFail); RETURN_IF_FAIL; } else if(inputValue <= 127) { dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL; dmtxByteListPush(valueList, inputValue - 96, passFail); RETURN_IF_FAIL; } else { *passFail = DmtxFail; return; } } *passFail = 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); } } }