Beispiel #1
0
static void
AppendValuesCTX(DmtxEncodeStream *stream, DmtxByteList *valueList)
{
   int pairValue;
   DmtxByte cw0, cw1;

   if(!IsCTX(stream->currentScheme))
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   if(valueList->length < 3)
   {
      StreamMarkFatal(stream, DmtxErrorIncompleteValueList);
      return;
   }

   /* Build codewords from computed value */
   pairValue = (1600 * valueList->b[0]) + (40 * valueList->b[1]) + valueList->b[2] + 1;
   cw0 = pairValue / 256;
   cw1 = pairValue % 256;

   /* Append 2 codewords */
   StreamOutputChainAppend(stream, cw0); CHKERR;
   StreamOutputChainAppend(stream, cw1); CHKERR;

   /* Update count for 3 encoded values */
   stream->outputChainValueCount += 3;
}
/**
 * used as each input cw is processed
 *
 * \param value Value to populate, can be null (for blind dequeues)
 * \param stream
 */
static void
StreamInputAdvancePrev(DmtxEncodeStream *stream)
{
   if(stream->inputNext > 0)
      stream->inputNext--;
   else
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);
}
/**
 * overwrite arbitrary element
 * used for binary length changes
 */
static void
StreamOutputSet(DmtxEncodeStream *stream, int index, DmtxByte value)
{
   if(index < 0 || index >= stream->output->length)
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);
   else
      stream->output->b[index] = value;
}
Beispiel #4
0
/**
 * 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);
   }
}
/**
 * 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);
}
/**
 * peek at first/oldest
 * used for ascii double digit
 */
static DmtxByte
StreamInputPeekNext(DmtxEncodeStream *stream)
{
   DmtxByte value = 0;

   if(StreamInputHasNext(stream))
      value = stream->input->b[stream->inputNext];
   else
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);

   return value;
}
Beispiel #7
0
static void
AdvanceCTX(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int ctxValueCount, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   /* we won't actually use inputNext here */
   switch(targetState)
   {
      case C40Offset0:
      case TextOffset0:
      case X12Offset0:
         isStartState = (ctxValueCount % 3 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case C40Offset1:
      case TextOffset1:
      case X12Offset1:
         isStartState = (ctxValueCount % 3 == 1) ? DmtxTrue : DmtxFalse;
         break;

      case C40Offset2:
      case TextOffset2:
      case X12Offset2:
         isStartState = (ctxValueCount % 3 == 2) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(inputNext < currentStream->inputNext)
   {
      StreamCopy(targetStream, currentStream);
   }
   else if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}
Beispiel #8
0
static void
AdvanceEdifact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   switch(targetState)
   {
      case EdifactOffset0:
         isStartState = (inputNext % 4 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset1:
         isStartState = (inputNext % 4 == 1) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset2:
         isStartState = (inputNext % 4 == 2) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset3:
         isStartState = (inputNext % 4 == 3) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      if(currentStream->status == DmtxStatusEncoding && currentStream->currentScheme == DmtxSchemeEdifact)
         EncodeNextChunk(targetStream, DmtxSchemeEdifact, DmtxEncodeNormal, sizeIdxRequest);
      else
         StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}
/**
 * pop off newest/last
 * used for edifact
 */
static DmtxByte
StreamOutputChainRemoveLast(DmtxEncodeStream *stream)
{
   DmtxByte value;
   DmtxPassFail passFail;

   if(stream->outputChainWordCount > 0)
   {
      value = dmtxByteListPop(stream->output, &passFail);
      stream->outputChainWordCount--;
   }
   else
   {
      value = 0;
      StreamMarkFatal(stream, DmtxErrorEmptyList);
   }

   return value;
}
Beispiel #10
0
static void
AppendUnlatchCTX(DmtxEncodeStream *stream)
{
   if(!IsCTX(stream->currentScheme))
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   /* Verify we are on byte boundary */
   if(stream->outputChainValueCount % 3 != 0)
   {
      StreamMarkInvalid(stream, DmtxErrorNotOnByteBoundary);
      return;
   }

   StreamOutputChainAppend(stream, DmtxValueCTXUnlatch); CHKERR;

   stream->outputChainValueCount++;
}
/**
 * remove first element from chain, shifting all following elements back by one
 * used for binary length changes end condition
 */
static void
Base256OutputChainRemoveFirst(DmtxEncodeStream *stream)
{
   DmtxByte value;
   DmtxPassFail passFail;
   int i, chainStart;

   chainStart = stream->output->length - stream->outputChainWordCount;

   for(i = chainStart; i < stream->output->length - 1; i++)
   {
      value = UnRandomize255State(stream->output->b[i+1], i+2);
      stream->output->b[i] = Randomize255State(value, i + 1);
   }

   dmtxByteListPop(stream->output, &passFail);
   if(passFail == DmtxPass)
      stream->outputChainWordCount--;
   else
      StreamMarkFatal(stream, DmtxErrorUnknown);
}
Beispiel #12
0
static void
AdvanceAsciiCompact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   switch(targetState)
   {
      case AsciiCompactOffset0:
         isStartState = (inputNext % 2 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case AsciiCompactOffset1:
         isStartState = (inputNext % 2 == 1) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(inputNext < currentStream->inputNext)
   {
      StreamCopy(targetStream, currentStream);
   }
   else if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}
/**
 * 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);
   }
}
static void
UpdateBase256ChainHeader(DmtxEncodeStream *stream, int perfectSizeIdx)
{
   int headerIndex;
   int outputLength;
   int headerByteCount;
   int symbolDataWords;
   DmtxBoolean perfectFit;
   DmtxByte headerValue0;
   DmtxByte headerValue1;

   outputLength = stream->outputChainValueCount;
   headerIndex = stream->output->length - stream->outputChainWordCount;
   headerByteCount = stream->outputChainWordCount - stream->outputChainValueCount;
   perfectFit = (perfectSizeIdx == DmtxUndefined) ? DmtxFalse : DmtxTrue;

   /*
    * If requested perfect fit verify symbol capacity against final length
    */

   if(perfectFit)
   {
      symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, perfectSizeIdx);
      if(symbolDataWords != stream->output->length - 1)
      {
         StreamMarkFatal(stream, DmtxErrorUnknown);
         return;
      }
   }

   /*
    * Adjust header to hold correct number of bytes, not worrying about the
    * values held there until below. Note: Header bytes are not considered
    * scheme "values" so we can insert or remove them without updating the
    * outputChainValueCount.
    */

   if(headerByteCount == 0 && stream->outputChainWordCount == 0)
   {
      /* No output words written yet -- insert single header byte */
      StreamOutputChainAppend(stream, 0); CHKERR;
      headerByteCount++;
   }
   else if(!perfectFit && headerByteCount == 1 && outputLength > 249)
   {
      /* Beyond 249 bytes requires a second header byte */
      Base256OutputChainInsertFirst(stream); CHKERR;
      headerByteCount++;
   }
   else if(perfectFit && headerByteCount == 2)
   {
      /* Encoding to exact end of symbol only requires single byte */
      Base256OutputChainRemoveFirst(stream); CHKERR;
      headerByteCount--;
   }

   /*
    * Encode header byte(s) with current length
    */

   if(!perfectFit && headerByteCount == 1 && outputLength <= 249)
   {
      /* Normal condition for chain length < 250 bytes */
      headerValue0 = Randomize255State(outputLength, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else if(!perfectFit && headerByteCount == 2 && outputLength > 249)
   {
      /* Normal condition for chain length >= 250 bytes */
      headerValue0 = Randomize255State(outputLength/250 + 249, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;

      headerValue1 = Randomize255State(outputLength%250, headerIndex + 2);
      StreamOutputSet(stream, headerIndex + 1, headerValue1); CHKERR;
   }
   else if(perfectFit && headerByteCount == 1)
   {
      /* Special condition when Base 256 stays in effect to end of symbol */
      headerValue0 = Randomize255State(0, headerIndex + 1); /* XXX replace magic value 0? */
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else
   {
      StreamMarkFatal(stream, DmtxErrorUnknown);
      return;
   }
}
Beispiel #15
0
/**
 * 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);
      }
   }
}