예제 #1
0
        private int EncodeSingleScheme(byte[] buf, byte[] codewords, DmtxScheme scheme)
        {
            int size;
            bool err;
            DmtxChannel channel = new DmtxChannel();

            InitChannel(channel, codewords);

            while (channel.InputIndex < channel.Input.Length)
            {
                err = EncodeNextWord(channel, scheme);
                if (!err)
                    return 0;

                /* DumpChannel(&channel); */

                if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid)
                {
                    return 0;
                }
            }
            /* DumpChannel(&channel); */

            size = channel.EncodedLength / 12;
            for (int i = 0; i < size; i++)
            {
                buf[i] = channel.EncodedWords[i];
            }

            return size;
        }
예제 #2
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;
        }
예제 #3
0
        private bool EncodeEdifactCodeword(DmtxChannel channel)
        {
            byte inputValue;

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

            inputValue = channel.Input[channel.InputIndex];

            if (inputValue < 32 || inputValue > 94)
            {
                channel.Invalid = DmtxChannelStatus.DmtxChannelUnsupportedChar;
                return false;
            }

            PushInputWord(channel, (byte)(inputValue & 0x3f));
            IncrementProgress(channel, 9);
            channel.InputIndex++;

            CheckForEndOfSymbolEdifact(channel);

            return true;
        }
예제 #4
0
        private bool EncodeNextWord(DmtxChannel channel, DmtxScheme targetScheme)
        {
            /* Change to new encodation scheme if necessary */
            if (channel.EncScheme != targetScheme)
            {
                ChangeEncScheme(channel, targetScheme, DmtxUnlatch.Explicit);
                if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid)
                    return false;
            }

            if (channel.EncScheme != targetScheme)
            {
                throw new Exception("For encoding, channel scheme must equal target scheme!");
            }

            /* Encode next input value */
            switch (channel.EncScheme)
            {
                case DmtxScheme.DmtxSchemeAscii:
                    return EncodeAsciiCodeword(channel);
                case DmtxScheme.DmtxSchemeC40:
                    return EncodeTripletCodeword(channel);
                case DmtxScheme.DmtxSchemeText:
                    return EncodeTripletCodeword(channel);
                case DmtxScheme.DmtxSchemeX12:
                    return EncodeTripletCodeword(channel);
                case DmtxScheme.DmtxSchemeEdifact:
                    return EncodeEdifactCodeword(channel);
                case DmtxScheme.DmtxSchemeBase256:
                    return EncodeBase256Codeword(channel);
                default:
                    return false;
            }
        }
예제 #5
0
        private bool EncodeAsciiCodeword(DmtxChannel channel)
        {
            byte inputValue, prevValue, prevPrevValue;
            int prevIndex;

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

            inputValue = channel.Input[channel.InputIndex];

            /* XXX this is problematic ... We should not be looking backward in the
               channel to determine what state we're in. Add the necessary logic to
               fix the current bug (prevprev != 253) but when rewriting encoder later
               make sure double digit ascii as treated as a forward-encoded condition.
               i.e., encode ahead of where we currently stand, and not comparable to other
               channels because currently sitting between byte boundaries (like the
               triplet-based schemes). Much simpler. */

            /* XXX another thought on the future rewrite: if adopting a forward-encoding
               approach on double digits then the following input situation:

                  digit digit c40a c40b c40c

               would create:

                  ASCII_double C40_triplet1ab C40_triplet2bc

               although it might be more efficient in some cases to do

                  digit C40_triplet1(digit a) C40_triplet2(a b)

               (I can't think of a situation like this, but I can't rule it out either)
               Unfortunately the forward encoding approach would never allow ascii to unlatch
               between the ASCII_double input words.

               One approach that would definitely avoid this is to treat ASCII_dd as a
               separate channel when using "--best".  However, when encoding to single-
               scheme ascii you would always use the ASCII_dd approach.

               This function, EncodeAsciiCodeword(), should have another parameter to flag
               whether or not to compress double digits. When encoding in single scheme
               ascii, then compress the double digits. If using --best then use both options
               as separate channels. */

            /* 2nd digit char in a row - overwrite first digit word with combined value */
            if (IsDigit(inputValue) && channel.CurrentLength >= channel.FirstCodeWord + 12)
            {
                prevIndex = (channel.CurrentLength - 12) / 12;
                prevValue = (byte)(channel.EncodedWords[prevIndex] - 1);

                prevPrevValue = (byte)((prevIndex > channel.FirstCodeWord / 12) ? channel.EncodedWords[prevIndex - 1] : 0);

                if (prevPrevValue != 235 && IsDigit(prevValue))
                {
                    channel.EncodedWords[prevIndex] = (byte)(10 * (prevValue - '0') + (inputValue - '0') + 130);
                    channel.InputIndex++;
                    return true;
                }
            }

            /* Extended ASCII char */
            if (inputValue >= 128)
            {
                PushInputWord(channel, DmtxConstants.DmtxCharAsciiUpperShift);
                IncrementProgress(channel, 12);
                inputValue -= 128;
            }

            PushInputWord(channel, (byte)(inputValue + 1));
            IncrementProgress(channel, 12);
            channel.InputIndex++;

            return true;
        }
예제 #6
0
        private bool EncodeBase256Codeword(DmtxChannel channel)
        {
            int i;
            int newDataLength;
            int headerByteCount;
            byte valueTmp;
            int firstBytePtrIndex;
            byte[] headerByte = new byte[2];

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

            firstBytePtrIndex = channel.FirstCodeWord / 12;
            headerByte[0] = DmtxMessage.UnRandomize255State(channel.EncodedWords[firstBytePtrIndex], channel.FirstCodeWord / 12 + 1);

            /* newSchemeLength contains size byte(s) too */
            if (headerByte[0] <= 249)
            {
                newDataLength = headerByte[0];
            }
            else
            {
                newDataLength = 250 * (headerByte[0] - 249);
                newDataLength += DmtxMessage.UnRandomize255State(channel.EncodedWords[firstBytePtrIndex + 1], channel.FirstCodeWord / 12 + 2);
            }

            newDataLength++;

            if (newDataLength <= 249)
            {
                headerByteCount = 1;
                headerByte[0] = (byte)newDataLength;
                headerByte[1] = 0; /* unused */
            }
            else
            {
                headerByteCount = 2;
                headerByte[0] = (byte)(newDataLength / 250 + 249);
                headerByte[1] = (byte)(newDataLength % 250);
            }

            /* newDataLength does not include header bytes */
            if (newDataLength <= 0 || newDataLength > 1555)
            {
                throw new Exception("Encoding failed, data length out of range!");
            }

            /* One time shift of codewords when passing the 250 byte size threshold */
            if (newDataLength == 250)
            {
                for (i = channel.CurrentLength / 12 - 1; i > channel.FirstCodeWord / 12; i--)
                {
                    valueTmp = DmtxMessage.UnRandomize255State(channel.EncodedWords[i], i + 1);
                    channel.EncodedWords[i + 1] = Randomize255State(valueTmp, i + 2);
                }
                IncrementProgress(channel, 12);
                channel.EncodedLength += 12; /* ugly */
            }

            /* Update scheme length in Base 256 header */
            for (i = 0; i < headerByteCount; i++)
            {
                channel.EncodedWords[firstBytePtrIndex + i] = Randomize255State(headerByte[i], channel.FirstCodeWord / 12 + i + 1);
            }

            PushInputWord(channel, Randomize255State(channel.Input[channel.InputIndex], channel.CurrentLength / 12 + 1));
            IncrementProgress(channel, 12);
            channel.InputIndex++;

            /* XXX will need to introduce an EndOfSymbolBase256() that recognizes
               opportunity to encode headerLength of 0 if remaining Base 256 message
               exactly matches symbol capacity */

            return true;
        }
예제 #7
0
        private void ChangeEncScheme(DmtxChannel channel, DmtxScheme targetScheme, DmtxUnlatch unlatchType)
        {
            int advance;

            if (channel.EncScheme == targetScheme)
            {
                throw new Exception("Target scheme already equals channel scheme, cannot be changed!");
            }

            /* Unlatch to ASCII (base encodation scheme) */
            switch (channel.EncScheme)
            {
                case DmtxScheme.DmtxSchemeAscii:
                    /* Nothing to do */
                    if (channel.CurrentLength % 12 != 0)
                    {
                        throw new Exception("Invalid current length detected encoding ascii code");
                    }
                    break;

                case DmtxScheme.DmtxSchemeC40:
                case DmtxScheme.DmtxSchemeText:
                case DmtxScheme.DmtxSchemeX12:

                    /* Can't unlatch unless currently at a byte boundary */
                    if ((channel.CurrentLength % 12) != 0)
                    {
                        channel.Invalid = DmtxChannelStatus.DmtxChannelCannotUnlatch;
                        return;
                    }

                    /* Can't unlatch if last word in previous triplet is a shift */
                    if (channel.CurrentLength != channel.EncodedLength)
                    {
                        channel.Invalid = DmtxChannelStatus.DmtxChannelCannotUnlatch;
                        return;
                    }

                    /* Unlatch to ASCII and increment progress */
                    if (unlatchType == DmtxUnlatch.Explicit)
                    {
                        PushInputWord(channel, (byte)DmtxConstants.DmtxCharTripletUnlatch);
                        IncrementProgress(channel, 12);
                    }
                    break;

                case DmtxScheme.DmtxSchemeEdifact:

                    /* must overwrite next 6 bits (after current) with 011111 (31) and
                       then fill remaining bits until next byte bounday with zeros
                       then set encodedLength, encodedTwothirdsbits, currentLength,
                       currentTwothirdsbits.  PushInputWord guarantees that remaining
                       bits are padded to 0, so just push the unlatch code and then
                       increment current and encoded length */
                    if (channel.CurrentLength % 3 != 0)
                    {
                        throw new Exception("Error changing encryption scheme, current length is invalid!");
                    }

                    if (unlatchType == DmtxUnlatch.Explicit)
                    {
                        PushInputWord(channel, (byte)DmtxConstants.DmtxCharEdifactUnlatch);
                        IncrementProgress(channel, 9);
                    }

                    /* Advance progress to next byte boundary */
                    advance = (channel.CurrentLength % 4) * 3;
                    channel.CurrentLength += advance;
                    channel.EncodedLength += advance;
                    /* assert(remaining bits are zero); */
                    break;

                case DmtxScheme.DmtxSchemeBase256:

                    /* since Base 256 stores the length value at the beginning of the
                       string instead of using an unlatch character, "unlatching" Base
                       256 involves going to the beginning of this stretch of Base 256
                       codewords and update the placeholder with the current length.
                       Note that the Base 256 length value can either be 1 or 2 bytes,
                       depending on the length of the current stretch of Base 256
                       chars.  However, this value will already have the correct
                       number of codewords allocated since this is checked every time
                       a new Base 256 codeword is pushed to the channel. */
                    break;

                default:
                    break;
            }
            channel.EncScheme = DmtxScheme.DmtxSchemeAscii;

            /* Latch to new encodation scheme */
            switch (targetScheme)
            {
                case DmtxScheme.DmtxSchemeAscii:
                    /* Nothing to do */
                    break;
                case DmtxScheme.DmtxSchemeC40:
                    PushInputWord(channel, (byte)DmtxConstants.DmtxCharC40Latch);
                    IncrementProgress(channel, 12);
                    break;
                case DmtxScheme.DmtxSchemeText:
                    PushInputWord(channel, (byte)DmtxConstants.DmtxCharTextLatch);
                    IncrementProgress(channel, 12);
                    break;
                case DmtxScheme.DmtxSchemeX12:
                    PushInputWord(channel, (byte)DmtxConstants.DmtxCharX12Latch);
                    IncrementProgress(channel, 12);
                    break;
                case DmtxScheme.DmtxSchemeEdifact:
                    PushInputWord(channel, (byte)DmtxConstants.DmtxCharEdifactLatch);
                    IncrementProgress(channel, 12);
                    break;
                case DmtxScheme.DmtxSchemeBase256:
                    PushInputWord(channel, (byte)DmtxConstants.DmtxCharBase256Latch);
                    IncrementProgress(channel, 12);

                    /* Write temporary field length (0 indicates remainder of symbol) */
                    PushInputWord(channel, Randomize255State(0, 2));
                    IncrementProgress(channel, 12);
                    break;
                default:
                    break;
            }
            channel.EncScheme = targetScheme;
            channel.FirstCodeWord = channel.CurrentLength - 12;
            if (channel.FirstCodeWord % 12 != 0)
            {
                throw new Exception("Error while changin encoding scheme, invalid first code word!");
            }
        }
예제 #8
0
        private bool CheckForEndOfSymbolEdifact(DmtxChannel channel)
        {
            int currentByte;
            DmtxSymbolSize sizeIdx;
            int symbolCodewords;
            int asciiCodewords;
            int i;
            bool err;

            /* This function tests if the remaining input values can be completed using
             * one of the valid end-of-symbol cases, and finishes encodation if possible.
             *
             * This function must exit in ASCII encodation.  EDIFACT must always be
             * unlatched, although implicit Unlatch is possible.
             *
             * End   Symbol  ASCII  EDIFACT  End        Codeword
             * Case  Words   Words  Values   Condition  Sequence
             * ----  ------  -----  -------  ---------  -------------------------------
             * (a)        1      0           Special    PAD
             * (b)        1      1           Special    ASCII (could be 2 digits)
             * (c)        1   >= 2           Continue   Need larger symbol
             * (d)        2      0           Special    PAD PAD
             * (e)        2      1           Special    ASCII PAD
             * (f)        2      2           Special    ASCII ASCII
             * (g)        2   >= 3           Continue   Need larger symbol
             * (h)      N/A    N/A        0  Normal     UNLATCH
             * (i)      N/A    N/A     >= 1  Continue   Not end of symbol
             *
             * Note: All "Special" cases (a,b,d,e,f) require clean byte boundary to start
             */

            /* Count remaining input values assuming EDIFACT encodation */
            if (channel.InputIndex > channel.Input.Length)
            {
                throw new Exception("Input index out of range while encoding!");
            }

            int edifactValues = channel.Input.Length - channel.InputIndex;

            /* Can't end symbol right now if there are 5+ values remaining
               (noting that '9999' can still terminate in case (f)) */
            if (edifactValues > 4) /* subset of (i) -- performance only */
                return true;

            /* Find minimum symbol size big enough to accomodate remaining codewords */
            /* XXX broken -- what if someone asks for DmtxSymbolRectAuto or specific sizeIdx? */

            currentByte = channel.CurrentLength / 12;
            sizeIdx = FindCorrectSymbolSize(currentByte, DmtxSymbolSize.DmtxSymbolSquareAuto);
            /* XXX test for sizeIdx == DmtxUndefined here */
            symbolCodewords = DmtxCommon.GetSymbolAttribute(DmtxSymAttribute.DmtxSymAttribSymbolDataWords, sizeIdx) - currentByte;

            /* Test for special case condition */
            if (channel.CurrentLength % 12 == 0 &&
                  (symbolCodewords == 1 || symbolCodewords == 2))
            {

                /* Count number of codewords left to write (assuming ASCII) */
                /* XXX temporary hack ... later create function that knows about shifts and digits */
                asciiCodewords = edifactValues;

                if (asciiCodewords <= symbolCodewords)
                { /* (a,b,d,e,f) */
                    ChangeEncScheme(channel, DmtxScheme.DmtxSchemeAscii, DmtxUnlatch.Implicit);

                    /* XXX this loop should produce exactly asciiWords codewords ... assert somehow? */
                    for (i = 0; i < edifactValues; i++)
                    {
                        err = EncodeNextWord(channel, DmtxScheme.DmtxSchemeAscii);
                        if (err == false)
                        {
                            return false;
                        }
                        if (channel.Invalid != DmtxChannelStatus.DmtxChannelValid)
                        {
                            throw new Exception("Error checking for end of symbol edifact");
                        }
                    }
                }
                /* else (c,g) -- do nothing */
            }
            else if (edifactValues == 0)
            { /* (h) */
                ChangeEncScheme(channel, DmtxScheme.DmtxSchemeAscii, DmtxUnlatch.Explicit);
            }
            /* else (i) -- do nothing */

            return true;
        }
예제 #9
0
 private static void InitChannel(DmtxChannel channel, byte[] codewords)
 {
     channel.EncScheme = DmtxScheme.DmtxSchemeAscii;
     channel.Invalid = DmtxChannelStatus.DmtxChannelValid;
     channel.InputIndex = 0;
     channel.Input = codewords;
 }
예제 #10
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));
 }
예제 #11
0
        private void PushInputWord(DmtxChannel channel, byte codeword)
        {
            int i;
            int startByte, pos;
            DmtxQuadruplet quad;

            /* XXX should this assertion actually be a legit runtime test? */
            if ((channel.EncodedLength / 12 > 3 * 1558))
            {
                throw new Exception("Can't push input word, encoded length exceeds limits!");
            }/* increased for Mosaic */

            /* XXX this is currently pretty ugly, but can wait until the
               rewrite. What is required is to go through and decide on a
               consistent approach (probably that all encodation schemes use
               currentLength except for triplet-based schemes which use
               currentLength and encodedLength).  All encodation schemes should
               maintain both currentLength and encodedLength though.  Perhaps
               another approach would be to maintain currentLength and "extraLength" */

            switch (channel.EncScheme)
            {
                case DmtxScheme.DmtxSchemeAscii:
                    channel.EncodedWords[channel.CurrentLength / 12] = codeword;
                    channel.EncodedLength += 12;
                    break;

                case DmtxScheme.DmtxSchemeC40:
                    channel.EncodedWords[channel.EncodedLength / 12] = codeword;
                    channel.EncodedLength += 12;
                    break;

                case DmtxScheme.DmtxSchemeText:
                    channel.EncodedWords[channel.EncodedLength / 12] = codeword;
                    channel.EncodedLength += 12;
                    break;

                case DmtxScheme.DmtxSchemeX12:
                    channel.EncodedWords[channel.EncodedLength / 12] = codeword;
                    channel.EncodedLength += 12;
                    break;

                case DmtxScheme.DmtxSchemeEdifact:
                    /* EDIFACT is the only encodation scheme where we don't encode up to the
                       next byte boundary.  This is because EDIFACT can be unlatched at any
                       point, including mid-byte, so we can't guarantee what the next
                       codewords will be.  All other encodation schemes only unlatch on byte
                       boundaries, allowing us to encode to the next boundary knowing that
                       we have predicted the only codewords that could be used while in this
                       scheme. */

                    /* write codeword value to next 6 bits (might span codeword bytes) and
                       then pad any remaining bits until next byte boundary with zero bits. */
                    pos = channel.CurrentLength % 4;
                    startByte = ((channel.CurrentLength + 9) / 12) - pos;

                    quad = GetQuadrupletValues(channel.EncodedWords[startByte],
                                               channel.EncodedWords[startByte + 1],
                                               channel.EncodedWords[startByte + 2]);
                    quad.Value[pos] = codeword;
                    for (i = pos + 1; i < 4; i++)
                        quad.Value[i] = 0;

                    /* Only write the necessary codewords */
                    switch (pos)
                    {
                        case 3:
                            channel.EncodedWords[startByte + 2] = (byte)(((quad.Value[2] & 0x03) << 6) | quad.Value[3]);
                            break;
                        case 2:
                            channel.EncodedWords[startByte + 2] = (byte)(((quad.Value[2] & 0x03) << 6) | quad.Value[3]);
                            break;
                        case 1:
                            channel.EncodedWords[startByte + 1] = (byte)(((quad.Value[1] & 0x0f) << 4) | (quad.Value[2] >> 2));
                            break;
                        case 0:
                            channel.EncodedWords[startByte] = (byte)((quad.Value[0] << 2) | (quad.Value[1] >> 4));
                            break;
                    }

                    channel.EncodedLength += 9;
                    break;

                case DmtxScheme.DmtxSchemeBase256:
                    channel.EncodedWords[channel.CurrentLength / 12] = codeword;
                    channel.EncodedLength += 12;
                    break;

                default:
                    break;
            }
        }
예제 #12
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;
        }
예제 #13
0
        private void IncrementProgress(DmtxChannel channel, int encodedUnits)
        {
            int startByte, pos;
            DmtxTriplet triplet;

            /* XXX this function became a misnomer when we started incrementing by
             * an amount other than what was specified with the C40/Text exception.
             * Maybe a new name/convention is in order.
             */

            /* In C40 and Text encodation schemes while we normally use 5 1/3 bits
             * to encode a regular character, we also must account for the extra
             * 5 1/3 bits (for a total of 10 2/3 bits that gets used for a shifted
             * character.
             */

            if (channel.EncScheme == DmtxScheme.DmtxSchemeC40 || channel.EncScheme == DmtxScheme.DmtxSchemeText)
            {

                pos = (channel.CurrentLength % 6) / 2;
                startByte = (channel.CurrentLength / 12) - (pos >> 1);
                triplet = GetTripletValues(channel.EncodedWords[startByte], channel.EncodedWords[startByte + 1]);

                /* Note that we will alway increment progress according to a whole
                   input codeword, so the value at "pos" is guaranteed to not be in
                   a shifted state. */
                if (triplet.Value[pos] <= 2)
                    channel.CurrentLength += 8;
            }

            channel.CurrentLength += encodedUnits;
        }