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; }
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; }
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; }
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; } }
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; }
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; }
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!"); } }
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; }
private static void InitChannel(DmtxChannel channel, byte[] codewords) { channel.EncScheme = DmtxScheme.DmtxSchemeAscii; channel.Invalid = DmtxChannelStatus.DmtxChannelValid; channel.InputIndex = 0; channel.Input = codewords; }
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)); }
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; } }
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; }
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; }