Ejemplo n.º 1
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;
      }
   }
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 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);
      }
   }
}
Ejemplo n.º 4
0
static int
EncodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, int fnc1)
{
   enum SchemeState state;
   int inputNext, c40ValueCount, textValueCount, x12ValueCount;
   int sizeIdx;
   DmtxEncodeStream *winner;
   DmtxPassFail passFail;
   DmtxEncodeStream streamsBest[SchemeStateCount];
   DmtxEncodeStream streamsTemp[SchemeStateCount];
   DmtxByte outputsBestStorage[SchemeStateCount][4096];
   DmtxByte outputsTempStorage[SchemeStateCount][4096];
   DmtxByte ctxTempStorage[4];
   DmtxByteList outputsBest[SchemeStateCount];
   DmtxByteList outputsTemp[SchemeStateCount];
   DmtxByteList ctxTemp = dmtxByteListBuild(ctxTempStorage, sizeof(ctxTempStorage));

   /* Initialize all streams with their own output storage */
   for(state = 0; state < SchemeStateCount; state++)
   {
      outputsBest[state] = dmtxByteListBuild(outputsBestStorage[state], sizeof(outputsBestStorage[state]));
      outputsTemp[state] = dmtxByteListBuild(outputsTempStorage[state], sizeof(outputsTempStorage[state]));
      streamsBest[state] = StreamInit(input, &(outputsBest[state]));
      streamsTemp[state] = StreamInit(input, &(outputsTemp[state]));
      streamsBest[state].fnc1 = fnc1;
      streamsTemp[state].fnc1 = fnc1;
   }

   c40ValueCount = textValueCount = x12ValueCount = 0;

   for(inputNext = 0; inputNext < input->length; inputNext++)
   {
      StreamAdvanceFromBest(streamsTemp, streamsBest, AsciiFull, sizeIdxRequest);

      AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset0, inputNext, sizeIdxRequest);
      AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset1, inputNext, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, C40Offset0, inputNext, c40ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, C40Offset1, inputNext, c40ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, C40Offset2, inputNext, c40ValueCount, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, TextOffset0, inputNext, textValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, TextOffset1, inputNext, textValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, TextOffset2, inputNext, textValueCount, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, X12Offset0, inputNext, x12ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, X12Offset1, inputNext, x12ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, X12Offset2, inputNext, x12ValueCount, sizeIdxRequest);

      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset0, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset1, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset2, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset3, inputNext, sizeIdxRequest);

      StreamAdvanceFromBest(streamsTemp, streamsBest, Base256, sizeIdxRequest);

      /* Overwrite best streams with new results */
      for(state = 0; state < SchemeStateCount; state++)
      {
         if(streamsBest[state].status != DmtxStatusComplete)
            StreamCopy(&(streamsBest[state]), &(streamsTemp[state]));
      }

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeC40, &passFail, fnc1);
      c40ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeText, &passFail, fnc1);
      textValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeX12, &passFail, fnc1);
      x12ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

#if DUMPSTREAMS
      DumpStreams(streamsBest);
#endif
   }

   /* Choose the overall winner */
   winner = NULL;
   for(state = 0; state < SchemeStateCount; state++)
   {
      if(streamsBest[state].status == DmtxStatusComplete)
      {
         if(winner == NULL || streamsBest[state].output->length < winner->output->length)
            winner = &(streamsBest[state]);
      }
   }

   /* Copy winner to output */
   if(winner == NULL)
   {
      sizeIdx = DmtxUndefined;
   }
   else
   {
      dmtxByteListCopy(output, winner->output, &passFail);
      sizeIdx = (passFail == DmtxPass) ? winner->sizeIdx : DmtxUndefined;
   }

   return sizeIdx;
}