Beispiel #1
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;
         }
      }
   }
}
Beispiel #2
0
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;
      }
   }
}
static void
EncodeNextChunkBase256(DmtxEncodeStream *stream)
{
   DmtxByte value;

   if(StreamInputHasNext(stream))
   {
      value = StreamInputAdvanceNext(stream); CHKERR;
      AppendValueBase256(stream, value); CHKERR;
   }
}
/**
 * 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 #5
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);
   }
}
Beispiel #6
0
/**
 * 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;
}
/**
 * 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);
   }
}
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
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);
   }
}