예제 #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);
   }
}
예제 #2
0
/**
 * Simple single scheme encoding uses "Normal"
 * The optimizer needs to track "Expanded" and "Compact" streams separately, so they
 * are called explicitly.
 *
 *   Normal:   Automatically collapses 2 consecutive digits into one codeword
 *   Expanded: Uses a whole codeword to represent a digit (never collapses)
 *   Compact:  Collapses 2 digits into a single codeword or marks the stream
 *             invalid if either values are not digits
 *
 * \param stream
 * \param option [Expanded|Compact|Normal]
 */
static void
EncodeNextChunkAscii(DmtxEncodeStream *stream, int option)
{
   DmtxByte v0, v1;
   DmtxBoolean compactDigits;

   if(StreamInputHasNext(stream))
   {
      v0 = StreamInputAdvanceNext(stream); CHKERR;

      if((option == DmtxEncodeCompact || option == DmtxEncodeNormal) &&
            StreamInputHasNext(stream))
      {
         v1 = StreamInputPeekNext(stream); CHKERR;
         compactDigits = (ISDIGIT(v0) && ISDIGIT(v1)) ? DmtxTrue : DmtxFalse;
      }
      else /* option == DmtxEncodeFull */
      {
         v1 = 0;
         compactDigits = DmtxFalse;
      }

      if(compactDigits == DmtxTrue)
      {
         /* Two adjacent digit chars: Make peek progress official and encode */
         StreamInputAdvanceNext(stream); CHKERR;
         AppendValueAscii(stream, 10 * (v0-'0') + (v1-'0') + 130); CHKERR;
      }
      else if(option == DmtxEncodeCompact)
      {
         /* Can't compact non-digits */
         StreamMarkInvalid(stream, DmtxErrorCantCompactNonDigits);
      }
      else
      {
         /* Encode single ASCII value */
         if(v0 < 128)
         {
            /* Regular ASCII */
            AppendValueAscii(stream, v0 + 1); CHKERR;
         }
         else
         {
            /* Extended ASCII */
            AppendValueAscii(stream, DmtxValueAsciiUpperShift); CHKERR;
            AppendValueAscii(stream, v0 - 127); CHKERR;
         }
      }
   }
}
예제 #3
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);
      }
   }
}