📄 dmtxencode.c
字号:
inputWord = *(ptr++); count = GetC40TextX12Words(outputWords, inputWord, channel->encScheme); if(count == 0) { channel->invalid = DMTX_CHANNEL_UNSUPPORTED_CHAR; return; } for(i = 0; i < count; i++) { buffer[tripletCount++] = 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(ptr == channel->inputStop) { /* 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->inputPtr++; } /* If final triplet value was shift then InrementProgress 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->inputPtr--; } inputCount = channel->inputStop - channel->inputPtr; ProcessEndOfSymbolTriplet(channel, &triplet, tripletCount, inputCount); 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->inputPtr++; }}/** * @brief Encode value using EDIFACT encodation * @param channel * @return void */static voidEncodeEdifactCodeword(DmtxChannel *channel){ unsigned char inputValue; assert(channel->encScheme == DmtxSchemeEncodeEdifact); inputValue = *(channel->inputPtr); if(inputValue < 32 || inputValue > 94) { channel->invalid = DMTX_CHANNEL_UNSUPPORTED_CHAR; return; } PushInputWord(channel, inputValue & 0x3f); IncrementProgress(channel, 9); channel->inputPtr++; /* XXX rename this to CheckforEndOfSymbolEdifact() */ TestForEndOfSymbolEdifact(channel);}/** * @brief Encode value using Base 256 encodation * @param channel * @return void */static voidEncodeBase256Codeword(DmtxChannel *channel){ int i; int newDataLength; int headerByteCount; unsigned char valueTmp; unsigned char *firstBytePtr; unsigned char headerByte[2]; assert(channel->encScheme == DmtxSchemeEncodeBase256); firstBytePtr = &(channel->encodedWords[channel->firstCodeWord/12]); headerByte[0] = UnRandomize255State(*firstBytePtr, channel->firstCodeWord/12 + 1); /* newSchemeLength contains size byte(s) too */ if(headerByte[0] <= 249) { newDataLength = headerByte[0]; } else { newDataLength = 250 * (headerByte[0] - 249); newDataLength += UnRandomize255State(*(firstBytePtr+1), channel->firstCodeWord/12 + 2); } newDataLength++; if(newDataLength <= 249) { headerByteCount = 1; headerByte[0] = newDataLength; headerByte[1] = 0; /* unused */ } else { headerByteCount = 2; headerByte[0] = newDataLength/250 + 249; headerByte[1] = newDataLength%250; } /* newDataLength does not include header bytes */ assert(newDataLength > 0 && newDataLength <= 1555); /* 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 = 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++) *(firstBytePtr+i) = Randomize255State(headerByte[i], channel->firstCodeWord/12 + i + 1); PushInputWord(channel, Randomize255State(*(channel->inputPtr), channel->currentLength/12 + 1)); IncrementProgress(channel, 12); channel->inputPtr++; /* XXX will need to introduce an EndOfSymbolBase256() that recognizes opportunity to encode headerLength of 0 if remaining Base 256 message exactly matches symbol capacity */}/** * @brief Change from one encodation scheme to another * @param channel * @param targetScheme * @param unlatchType * @return void */static voidChangeEncScheme(DmtxChannel *channel, DmtxSchemeEncode targetScheme, int unlatchType){ int advance; assert(channel->encScheme != targetScheme); /* Unlatch to ASCII (base encodation scheme) */ switch(channel->encScheme) { case DmtxSchemeEncodeAscii: /* Nothing to do */ assert(channel->currentLength % 12 == 0); break; case DmtxSchemeEncodeC40: case DmtxSchemeEncodeText: case DmtxSchemeEncodeX12: /* Can't unlatch unless currently at a byte boundary */ if((channel->currentLength % 12) != 0) { channel->invalid = DMTX_CHANNEL_CANNOT_UNLATCH; return; } /* Can't unlatch if last word in previous triplet is a shift */ if(channel->currentLength != channel->encodedLength) { channel->invalid = DMTX_CHANNEL_CANNOT_UNLATCH; return; } /* Unlatch to ASCII and increment progress */ if(unlatchType == DMTX_UNLATCH_EXPLICIT) { PushInputWord(channel, DMTX_CHAR_TRIPLET_UNLATCH); IncrementProgress(channel, 12); } break; case DmtxSchemeEncodeEdifact: /* 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 */ assert(channel->currentLength % 3 == 0); if(unlatchType == DMTX_UNLATCH_EXPLICIT) { PushInputWord(channel, DMTX_CHAR_EDIFACT_UNLATCH); 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 DmtxSchemeEncodeBase256: /* 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 = DmtxSchemeEncodeAscii; /* Latch to new encodation scheme */ switch(targetScheme) { case DmtxSchemeEncodeAscii: /* Nothing to do */ break; case DmtxSchemeEncodeC40: PushInputWord(channel, DMTX_CHAR_C40_LATCH); IncrementProgress(channel, 12); break; case DmtxSchemeEncodeText: PushInputWord(channel, DMTX_CHAR_TEXT_LATCH); IncrementProgress(channel, 12); break; case DmtxSchemeEncodeX12: PushInputWord(channel, DMTX_CHAR_X12_LATCH); IncrementProgress(channel, 12); break; case DmtxSchemeEncodeEdifact: PushInputWord(channel, DMTX_CHAR_EDIFACT_LATCH); IncrementProgress(channel, 12); break; case DmtxSchemeEncodeBase256: PushInputWord(channel, DMTX_CHAR_BASE256_LATCH); 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; assert(channel->firstCodeWord % 12 == 0);}/** * @brief Push codeword onto channel and increment length * @param channel * @param codeword * @return void */static voidPushInputWord(DmtxChannel *channel, unsigned char codeword){ int i; int startByte, pos; DmtxQuadruplet quad; /* XXX should this assertion actually be a legit runtime test? */ assert(channel->encodedLength/12 <= 3*1558); /* 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 DmtxSchemeEncodeAscii: channel->encodedWords[channel->currentLength/12] = codeword; channel->encodedLength += 12; break; case DmtxSchemeEncodeC40: case DmtxSchemeEncodeText: case DmtxSchemeEncodeX12: channel->encodedWords[channel->encodedLength/12] = codeword; channel->encodedLength += 12; break; case DmtxSchemeEncodeEdifact: /* 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: case 2: channel->encodedWords[startByte+2] = ((quad.value[2] & 0x03) << 6) | quad.value[3]; case 1: channel->encodedWords[startByte+1] = ((quad.value[1] & 0x0f) << 4) | (quad.value[2] >> 2); case 0: channel->encodedWords[startByte] = (quad.value[0] << 2) | (quad.value[1] >> 4); } channel->encodedLength += 9; break; case DmtxSchemeEncodeBase256: channel->encodedWords[channel->currentLength/12] = codeword; channel->encodedLength += 12; break; default: break; }}/** * @brief Push triplet codeword onto channel * @param channel * @param triplet * @return void */static voidPushTriplet(DmtxChannel *channel, DmtxTriplet *triplet){ int tripletValue; tripletValue = (1600 * triplet->value[0]) + (40 * triplet->value[1]) + triplet->value[2] + 1; PushInputWord(channel, tripletValue / 256); PushInputWord(channel, tripletValue % 256);}/** * @brief Increment encoding progress tracking variables * @param channel * @param encodedUnits * @return void */static voidIncrementProgress(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -