예제 #1
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);
   }
}
/**
 * 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);
   }
}
예제 #3
0
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);
   }
}
예제 #4
0
/**
 * 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);
   }
}
예제 #5
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);
      }
   }
}