예제 #1
0
        private bool EncodeTripletCodeword(DmtxChannel channel)
        {
            int i;
            int inputCount;
            int tripletCount;
            int count;
            int[] outputWords = new int[4];       /* biggest: upper shift to non-basic set */
            byte[] buffer = new byte[6];  /* biggest: 2 words followed by 4-word upper shift */
            bool err;
            DmtxTriplet triplet = new DmtxTriplet();
            byte inputWord;
            int ptrIndex;

            if (channel.EncScheme != DmtxScheme.DmtxSchemeX12 &&
                channel.EncScheme != DmtxScheme.DmtxSchemeText &&
                channel.EncScheme != DmtxScheme.DmtxSchemeC40)
            {
                throw new Exception("Invalid encoding scheme selected!");
            }

            if (channel.CurrentLength > channel.EncodedLength)
            {
                throw new Exception("Encoding length out of range!");
            }

            /* If there are no pre-encoded codewords then generate some */
            if (channel.CurrentLength == channel.EncodedLength)
            {

                if (channel.CurrentLength % 12 != 0)
                {
                    throw new Exception("Invalid encoding length!");
                }

                /* Ideally we would only encode one codeword triplet here (the
                   minimum that you can do at a time) but we can't leave the channel
                   with the last encoded word as a shift.  The following loop
                   prevents this condition by encoding until we have a clean break or
                   until we reach the end of the input data. */

                ptrIndex = channel.InputIndex;

                tripletCount = 0;
                for (; ; )
                {

                    /* Fill array with at least 3 values (the minimum necessary to
                       encode a triplet), but possibly up to 6 values due to presence
                       of upper shifts.  Note that buffer may already contain values
                       from a previous iteration of the outer loop, and this step
                       "tops off" the buffer to make sure there are at least 3 values. */

                    while (tripletCount < 3 && ptrIndex < channel.Input.Length)
                    {
                        inputWord = channel.Input[ptrIndex++];
                        count = GetC40TextX12Words(outputWords, inputWord, channel.EncScheme);

                        if (count == 0)
                        {
                            channel.Invalid = DmtxChannelStatus.DmtxChannelUnsupportedChar;
                            return false;
                        }

                        for (i = 0; i < count; i++)
                        {
                            buffer[tripletCount++] = (byte)outputWords[i];
                        }
                    }

                    /* Take the next 3 values from buffer to encode */
                    triplet.Value[0] = buffer[0];
                    triplet.Value[1] = buffer[1];
                    triplet.Value[2] = buffer[2];

                    if (tripletCount >= 3)
                    {
                        PushTriplet(channel, triplet);
                        buffer[0] = buffer[3];
                        buffer[1] = buffer[4];
                        buffer[2] = buffer[5];
                        tripletCount -= 3;
                    }

                    /* If we reach the end of input and have not encountered a clean
                       break opportunity then complete the symbol here */

                    if (ptrIndex == channel.Input.Length)
                    {
                        /* tripletCount represents the number of values in triplet waiting to be pushed
                           inputCount represents the number of values after inputPtr waiting to be pushed */
                        while (channel.CurrentLength < channel.EncodedLength)
                        {
                            IncrementProgress(channel, 8);
                            channel.InputIndex++;
                        }

                        /* If final triplet value was shift then IncrementProgress will
                           overextend us .. hack it back a little.  Note that this means
                           this barcode is invalid unless one of the specific end-of-symbol
                           conditions explicitly allows it. */
                        if (channel.CurrentLength == channel.EncodedLength + 8)
                        {
                            channel.CurrentLength = channel.EncodedLength;
                            channel.InputIndex--;
                        }

                        if (channel.Input.Length < channel.InputIndex)
                        {
                            throw new Exception("Channel input index exceeds range!");
                        }

                        inputCount = (int)(channel.Input.Length - channel.InputIndex);

                        err = ProcessEndOfSymbolTriplet(channel, triplet, tripletCount, inputCount);
                        if (err == false)
                            return false;
                        break;
                    }

                    /* If there are no triplet values remaining in the buffer then
                       break.  This guarantees that we will always stop encoding on a
                       clean "unshifted" break */

                    if (tripletCount == 0)
                        break;
                }
            }

            /* Pre-encoded codeword is available for consumption */
            if (channel.CurrentLength < channel.EncodedLength)
            {
                IncrementProgress(channel, 8);
                channel.InputIndex++;
            }

            return true;
        }
예제 #2
0
 private void PushTriplet(DmtxChannel channel, DmtxTriplet triplet)
 {
     int tripletValue = (1600 * triplet.Value[0]) + (40 * triplet.Value[1]) + triplet.Value[2] + 1;
     PushInputWord(channel, (byte)(tripletValue / 256));
     PushInputWord(channel, (byte)(tripletValue % 256));
 }
예제 #3
0
        private static DmtxTriplet GetTripletValues(byte cw1, byte cw2)
        {
            DmtxTriplet triplet = new DmtxTriplet();

            /* XXX this really belongs with the decode functions */

            int compact = (cw1 << 8) | cw2;
            triplet.Value[0] = (byte)((compact - 1) / 1600);
            triplet.Value[1] = (byte)(((compact - 1) / 40) % 40);
            triplet.Value[2] = (byte)((compact - 1) % 40);

            return triplet;
        }
예제 #4
0
        private bool ProcessEndOfSymbolTriplet(DmtxChannel channel, DmtxTriplet triplet, int tripletCount, int inputCount)
        {
            DmtxSymbolSize sizeIdx;
            int currentByte;
            int remainingCodewords;
            int inputAdjust;
            bool err;

            /* In this function we process some special cases from the Data Matrix
             * standard, and as such we circumvent the normal functions for
             * accomplishing certain tasks.  This breaks our internal counts, but this
             * function always marks the end of processing so it will not affect
             * anything downstream.  This approach allows the normal encoding functions
             * to be built with very strict checks and assertions.
             *
             * EXIT CONDITIONS:
             *
             *   triplet  symbol  action
             *   -------  ------  -------------------
             *         1       0  need bigger symbol
             *         1       1  special case (d)
             *         1       2  special case (c)
             *         1       3  unlatch ascii pad
             *         1       4  unlatch ascii pad pad
             *         2       0  need bigger symbol
             *         2       1  need bigger symbol
             *         2       2  special case (b)
             *         2       3  unlatch ascii ascii
             *         2       4  unlatch ascii ascii pad
             *         3       0  need bigger symbol
             *         3       1  need bigger symbol
             *         3       2  special case (a)
             *         3       3  c40 c40 unlatch
             *         3       4  c40 c40 unlatch pad
             */

            /* We should always reach this point on a byte boundary */
            if (channel.CurrentLength % 12 != 0)
            {
                throw new Exception("Invalid current length for encoding!");
            }

            /* XXX Capture how many extra input values will be counted ... for later adjustment */
            inputAdjust = tripletCount - inputCount;

            /* Find minimum symbol size big enough to accomodate remaining codewords */
            currentByte = channel.CurrentLength / 12;

            sizeIdx = FindCorrectSymbolSize(currentByte + ((inputCount == 3) ? 2 : inputCount), this._sizeIdxRequest);

            if (sizeIdx == DmtxSymbolSize.DmtxSymbolShapeAuto)
                return false;

            /* XXX test for sizeIdx == DmtxUndefined here */
            remainingCodewords = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolDataWords, sizeIdx) - currentByte;

            /* XXX the big problem with all of these special cases is what if one of
               these last words requires multiple bytes in ASCII (like upper shift?).
               We probably need to add a test against this and then just force an
               unlatch if we see this coming. */

            /* Special case (d): Unlatch is implied (switch manually) */
            if (inputCount == 1 && remainingCodewords == 1)
            {
                ChangeEncScheme(channel, DmtxScheme.DmtxSchemeAscii, DmtxUnlatch.Implicit);
                err = EncodeNextWord(channel, DmtxScheme.DmtxSchemeAscii);
                if (err == false)
                    return false;
                if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid || channel.InputIndex != channel.Input.Length)
                {
                    throw new Exception("Error processing end of symbol triplet!");
                }
            }
            else if (remainingCodewords == 2)
            {
                /* Special case (a): Unlatch is implied */
                if (tripletCount == 3)
                {
                    PushTriplet(channel, triplet);
                    IncrementProgress(channel, 24);
                    channel.EncScheme = DmtxScheme.DmtxSchemeAscii;
                    channel.InputIndex += 3;
                    channel.InputIndex -= inputAdjust;
                }
                /* Special case (b): Unlatch is implied */
                else if (tripletCount == 2)
                {
                    /*       assert(2nd C40 is not a shift character); */
                    triplet.Value[2] = 0;
                    PushTriplet(channel, triplet);
                    IncrementProgress(channel, 24);
                    channel.EncScheme = DmtxScheme.DmtxSchemeAscii;
                    channel.InputIndex += 2;
                    channel.InputIndex -= inputAdjust;
                }
                /* Special case (c) */
                else if (tripletCount == 1)
                {
                    ChangeEncScheme(channel, DmtxScheme.DmtxSchemeAscii, DmtxUnlatch.Explicit);
                    err = EncodeNextWord(channel, DmtxScheme.DmtxSchemeAscii);
                    if (err == false)
                        return false;
                    if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid)
                    {
                        throw new Exception("Error processing end of symbol triplet!");
                    }
                    /* XXX I can still think of a case that looks ugly here.  What if
                       the final 2 C40 codewords are a Shift word and a non-Shift
                       word.  This special case will unlatch after the shift ... which
                       is probably legal but I'm not loving it.  Give it more thought. */
                }
            }
            else
            {
                /*    assert(remainingCodewords == 0 || remainingCodewords >= 3); */

                currentByte = channel.CurrentLength / 12;
                remainingCodewords = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolDataWords, sizeIdx) - currentByte;

                if (remainingCodewords > 0)
                {
                    ChangeEncScheme(channel, DmtxScheme.DmtxSchemeAscii, DmtxUnlatch.Explicit);

                    while (channel.InputIndex < channel.Input.Length)
                    {
                        err = EncodeNextWord(channel, DmtxScheme.DmtxSchemeAscii);
                        if (err == false)
                            return false;

                        if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid)
                        {
                            throw new Exception("Error processing end of symbol triplet!");
                        }
                    }
                }
            }

            if (channel.InputIndex != channel.Input.Length)
            {
                throw new Exception("Could not fully process end of symbol triplet!");
            }

            return true;
        }