| // Copyright 2014 PDFium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| // Original code is licensed as follows: | |
| /* | |
| * Copyright 2006-2007 Jeremias Maerki. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "../barcode.h" | |
| #include "../BC_Dimension.h" | |
| #include "../BC_UtilCodingConvert.h" | |
| #include "../common/BC_CommonBitMatrix.h" | |
| #include "BC_Encoder.h" | |
| #include "BC_SymbolShapeHint.h" | |
| #include "BC_SymbolInfo.h" | |
| #include "BC_EncoderContext.h" | |
| #include "BC_C40Encoder.h" | |
| #include "BC_TextEncoder.h" | |
| #include "BC_X12Encoder.h" | |
| #include "BC_EdifactEncoder.h" | |
| #include "BC_Base256Encoder.h" | |
| #include "BC_ASCIIEncoder.h" | |
| #include "BC_HighLevelEncoder.h" | |
| #define Integer_MAX_VALUE 2147483647 | |
| FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_C40 = 230; | |
| FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_BASE256 = 231; | |
| FX_WCHAR CBC_HighLevelEncoder::UPPER_SHIFT = 235; | |
| FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_ANSIX12 = 238; | |
| FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_TEXT = 239; | |
| FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_EDIFACT = 240; | |
| FX_WCHAR CBC_HighLevelEncoder::C40_UNLATCH = 254; | |
| FX_WCHAR CBC_HighLevelEncoder::X12_UNLATCH = 254; | |
| FX_WCHAR CBC_HighLevelEncoder::PAD = 129; | |
| FX_WCHAR CBC_HighLevelEncoder::MACRO_05 = 236; | |
| FX_WCHAR CBC_HighLevelEncoder::MACRO_06 = 237; | |
| const wchar_t* CBC_HighLevelEncoder::MACRO_05_HEADER = L"[)>05"; | |
| const wchar_t* CBC_HighLevelEncoder::MACRO_06_HEADER = L"[)>06"; | |
| const wchar_t CBC_HighLevelEncoder::MACRO_TRAILER = 0x0004; | |
| CBC_HighLevelEncoder::CBC_HighLevelEncoder() | |
| { | |
| } | |
| CBC_HighLevelEncoder::~CBC_HighLevelEncoder() | |
| { | |
| } | |
| CFX_ByteArray& CBC_HighLevelEncoder::getBytesForMessage(CFX_WideString msg) | |
| { | |
| CFX_ByteString bytestr; | |
| CBC_UtilCodingConvert::UnicodeToUTF8(msg, bytestr); | |
| for (FX_INT32 i = 0; i < bytestr.GetLength(); i++) { | |
| m_bytearray.Add(bytestr.GetAt(i)); | |
| } | |
| return m_bytearray; | |
| } | |
| CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg, CFX_WideString ecLevel, FX_INT32 &e) | |
| { | |
| return encodeHighLevel(msg, ecLevel, FORCE_NONE, NULL, NULL, e); | |
| } | |
| CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg, CFX_WideString ecLevel, SymbolShapeHint shape, CBC_Dimension* minSize, CBC_Dimension* maxSize, FX_INT32 &e) | |
| { | |
| CBC_EncoderContext context(msg, ecLevel, e); | |
| BC_EXCEPTION_CHECK_ReturnValue(e, (FX_LPWSTR)""); | |
| context.setSymbolShape(shape); | |
| context.setSizeConstraints(minSize, maxSize); | |
| if ((msg.Mid(0, 6) == MACRO_05_HEADER) && (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) { | |
| context.writeCodeword(MACRO_05); | |
| context.setSkipAtEnd(2); | |
| context.m_pos += 6; | |
| } else if ((msg.Mid(0, 6) == MACRO_06_HEADER) && (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) { | |
| context.writeCodeword(MACRO_06); | |
| context.setSkipAtEnd(2); | |
| context.m_pos += 6; | |
| } | |
| CFX_PtrArray encoders; | |
| encoders.Add(FX_NEW CBC_ASCIIEncoder()); | |
| encoders.Add(FX_NEW CBC_C40Encoder()); | |
| encoders.Add(FX_NEW CBC_TextEncoder()); | |
| encoders.Add(FX_NEW CBC_X12Encoder()); | |
| encoders.Add(FX_NEW CBC_EdifactEncoder()); | |
| encoders.Add(FX_NEW CBC_Base256Encoder()); | |
| FX_INT32 encodingMode = ASCII_ENCODATION; | |
| while (context.hasMoreCharacters()) { | |
| ((CBC_Encoder*)encoders.GetAt(encodingMode))->Encode(context, e); | |
| if (e != BCExceptionNO) { | |
| for (FX_INT32 i = 0; i < encoders.GetSize(); i++) { | |
| delete (CBC_Encoder*)encoders.GetAt(i); | |
| } | |
| encoders.RemoveAll(); | |
| return (FX_LPWSTR)""; | |
| } | |
| if (context.m_newEncoding >= 0) { | |
| encodingMode = context.m_newEncoding; | |
| context.resetEncoderSignal(); | |
| } | |
| } | |
| FX_INT32 len = context.m_codewords.GetLength(); | |
| context.updateSymbolInfo(e); | |
| if (e != BCExceptionNO) { | |
| for (FX_INT32 i = 0; i < encoders.GetSize(); i++) { | |
| delete (CBC_Encoder*)encoders.GetAt(i); | |
| } | |
| encoders.RemoveAll(); | |
| return (FX_LPWSTR)""; | |
| } | |
| FX_INT32 capacity = context.m_symbolInfo->m_dataCapacity; | |
| if (len < capacity) { | |
| if (encodingMode != ASCII_ENCODATION && encodingMode != BASE256_ENCODATION) { | |
| context.writeCodeword(0x00fe); | |
| } | |
| } | |
| CFX_WideString codewords = context.m_codewords; | |
| if (codewords.GetLength() < capacity) { | |
| codewords += PAD; | |
| } | |
| while (codewords.GetLength() < capacity) { | |
| codewords += (randomize253State(PAD, codewords.GetLength() + 1)); | |
| } | |
| for (FX_INT32 i = 0; i < encoders.GetSize(); i++) { | |
| delete (CBC_Encoder*)encoders.GetAt(i); | |
| } | |
| encoders.RemoveAll(); | |
| return codewords; | |
| } | |
| FX_INT32 CBC_HighLevelEncoder::lookAheadTest(CFX_WideString msg, FX_INT32 startpos, FX_INT32 currentMode) | |
| { | |
| if (startpos >= msg.GetLength()) { | |
| return currentMode; | |
| } | |
| CFX_FloatArray charCounts; | |
| if (currentMode == ASCII_ENCODATION) { | |
| charCounts.Add(0); | |
| charCounts.Add(1); | |
| charCounts.Add(1); | |
| charCounts.Add(1); | |
| charCounts.Add(1); | |
| charCounts.Add(1.25f); | |
| } else { | |
| charCounts.Add(1); | |
| charCounts.Add(2); | |
| charCounts.Add(2); | |
| charCounts.Add(2); | |
| charCounts.Add(2); | |
| charCounts.Add(2.25f); | |
| charCounts[currentMode] = 0; | |
| } | |
| FX_INT32 charsProcessed = 0; | |
| while (TRUE) { | |
| if ((startpos + charsProcessed) == msg.GetLength()) { | |
| FX_DWORD min = Integer_MAX_VALUE; | |
| CFX_ByteArray mins; | |
| mins.SetSize(6); | |
| CFX_Int32Array intCharCounts; | |
| intCharCounts.SetSize(6); | |
| min = findMinimums(charCounts, intCharCounts, min, mins); | |
| FX_INT32 minCount = getMinimumCount(mins); | |
| if (intCharCounts[ASCII_ENCODATION] == min) { | |
| return ASCII_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[BASE256_ENCODATION] > 0) { | |
| return BASE256_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) { | |
| return EDIFACT_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[TEXT_ENCODATION] > 0) { | |
| return TEXT_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[X12_ENCODATION] > 0) { | |
| return X12_ENCODATION; | |
| } | |
| return C40_ENCODATION; | |
| } | |
| FX_WCHAR c = msg.GetAt(startpos + charsProcessed); | |
| charsProcessed++; | |
| if (isDigit(c)) { | |
| charCounts[ASCII_ENCODATION] += 0.5; | |
| } else if (isExtendedASCII(c)) { | |
| charCounts[ASCII_ENCODATION] = (FX_FLOAT) ceil(charCounts[ASCII_ENCODATION]); | |
| charCounts[ASCII_ENCODATION] += 2; | |
| } else { | |
| charCounts[ASCII_ENCODATION] = (FX_FLOAT) ceil(charCounts[ASCII_ENCODATION]); | |
| charCounts[ASCII_ENCODATION]++; | |
| } | |
| if (isNativeC40(c)) { | |
| charCounts[C40_ENCODATION] += 2.0f / 3.0f; | |
| } else if (isExtendedASCII(c)) { | |
| charCounts[C40_ENCODATION] += 8.0f / 3.0f; | |
| } else { | |
| charCounts[C40_ENCODATION] += 4.0f / 3.0f; | |
| } | |
| if (isNativeText(c)) { | |
| charCounts[TEXT_ENCODATION] += 2.0f / 3.0f; | |
| } else if (isExtendedASCII(c)) { | |
| charCounts[TEXT_ENCODATION] += 8.0f / 3.0f; | |
| } else { | |
| charCounts[TEXT_ENCODATION] += 4.0f / 3.0f; | |
| } | |
| if (isNativeX12(c)) { | |
| charCounts[X12_ENCODATION] += 2.0f / 3.0f; | |
| } else if (isExtendedASCII(c)) { | |
| charCounts[X12_ENCODATION] += 13.0f / 3.0f; | |
| } else { | |
| charCounts[X12_ENCODATION] += 10.0f / 3.0f; | |
| } | |
| if (isNativeEDIFACT(c)) { | |
| charCounts[EDIFACT_ENCODATION] += 3.0f / 4.0f; | |
| } else if (isExtendedASCII(c)) { | |
| charCounts[EDIFACT_ENCODATION] += 17.0f / 4.0f; | |
| } else { | |
| charCounts[EDIFACT_ENCODATION] += 13.0f / 4.0f; | |
| } | |
| if (isSpecialB256(c)) { | |
| charCounts[BASE256_ENCODATION] += 4; | |
| } else { | |
| charCounts[BASE256_ENCODATION]++; | |
| } | |
| if (charsProcessed >= 4) { | |
| CFX_Int32Array intCharCounts; | |
| intCharCounts.SetSize(6); | |
| CFX_ByteArray mins; | |
| mins.SetSize(6); | |
| findMinimums(charCounts, intCharCounts, Integer_MAX_VALUE, mins); | |
| FX_INT32 minCount = getMinimumCount(mins); | |
| if (intCharCounts[ASCII_ENCODATION] < intCharCounts[BASE256_ENCODATION] | |
| && intCharCounts[ASCII_ENCODATION] < intCharCounts[C40_ENCODATION] | |
| && intCharCounts[ASCII_ENCODATION] < intCharCounts[TEXT_ENCODATION] | |
| && intCharCounts[ASCII_ENCODATION] < intCharCounts[X12_ENCODATION] | |
| && intCharCounts[ASCII_ENCODATION] < intCharCounts[EDIFACT_ENCODATION]) { | |
| return ASCII_ENCODATION; | |
| } | |
| if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION] | |
| || (mins[C40_ENCODATION] + mins[TEXT_ENCODATION] + mins[X12_ENCODATION] + mins[EDIFACT_ENCODATION]) == 0) { | |
| return BASE256_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) { | |
| return EDIFACT_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[TEXT_ENCODATION] > 0) { | |
| return TEXT_ENCODATION; | |
| } | |
| if (minCount == 1 && mins[X12_ENCODATION] > 0) { | |
| return X12_ENCODATION; | |
| } | |
| if (intCharCounts[C40_ENCODATION] + 1 < intCharCounts[ASCII_ENCODATION] | |
| && intCharCounts[C40_ENCODATION] + 1 < intCharCounts[BASE256_ENCODATION] | |
| && intCharCounts[C40_ENCODATION] + 1 < intCharCounts[EDIFACT_ENCODATION] | |
| && intCharCounts[C40_ENCODATION] + 1 < intCharCounts[TEXT_ENCODATION]) { | |
| if (intCharCounts[C40_ENCODATION] < intCharCounts[X12_ENCODATION]) { | |
| return C40_ENCODATION; | |
| } | |
| if (intCharCounts[C40_ENCODATION] == intCharCounts[X12_ENCODATION]) { | |
| FX_INT32 p = startpos + charsProcessed + 1; | |
| while (p < msg.GetLength()) { | |
| FX_WCHAR tc = msg.GetAt(p); | |
| if (isX12TermSep(tc)) { | |
| return X12_ENCODATION; | |
| } | |
| if (!isNativeX12(tc)) { | |
| break; | |
| } | |
| p++; | |
| } | |
| return C40_ENCODATION; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isDigit(FX_WCHAR ch) | |
| { | |
| return ch >= '0' && ch <= '9'; | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isExtendedASCII(FX_WCHAR ch) | |
| { | |
| return ch >= 128 && ch <= 255; | |
| } | |
| FX_INT32 CBC_HighLevelEncoder::determineConsecutiveDigitCount(CFX_WideString msg, FX_INT32 startpos) | |
| { | |
| FX_INT32 count = 0; | |
| FX_INT32 len = msg.GetLength(); | |
| FX_INT32 idx = startpos; | |
| if (idx < len) { | |
| FX_WCHAR ch = msg.GetAt(idx); | |
| while (isDigit(ch) && idx < len) { | |
| count++; | |
| idx++; | |
| if (idx < len) { | |
| ch = msg.GetAt(idx); | |
| } | |
| } | |
| } | |
| return count; | |
| } | |
| void CBC_HighLevelEncoder::illegalCharacter(FX_WCHAR c, FX_INT32 &e) | |
| { | |
| e = BCExceptionIllegalArgument; | |
| } | |
| FX_WCHAR CBC_HighLevelEncoder::randomize253State(FX_WCHAR ch, FX_INT32 codewordPosition) | |
| { | |
| FX_INT32 pseudoRandom = ((149 * codewordPosition) % 253) + 1; | |
| FX_INT32 tempVariable = ch + pseudoRandom; | |
| return tempVariable <= 254 ? (FX_WCHAR) tempVariable : (FX_WCHAR) (tempVariable - 254); | |
| } | |
| FX_INT32 CBC_HighLevelEncoder::findMinimums(CFX_FloatArray &charCounts, CFX_Int32Array &intCharCounts, FX_INT32 min, CFX_ByteArray &mins) | |
| { | |
| for (FX_INT32 l = 0; l < mins.GetSize(); l++) { | |
| mins[l] = (FX_BYTE)0; | |
| } | |
| for (FX_INT32 i = 0; i < 6; i++) { | |
| intCharCounts[i] = (FX_INT32)ceil(charCounts[i]); | |
| FX_INT32 current = intCharCounts[i]; | |
| if (min > current) { | |
| min = current; | |
| for (FX_INT32 j = 0; j < mins.GetSize(); j++) { | |
| mins[j] = (FX_BYTE)0; | |
| } | |
| } | |
| if (min == current) { | |
| mins[i]++; | |
| } | |
| } | |
| return min; | |
| } | |
| FX_INT32 CBC_HighLevelEncoder::getMinimumCount(CFX_ByteArray &mins) | |
| { | |
| FX_INT32 minCount = 0; | |
| for (FX_INT32 i = 0; i < 6; i++) { | |
| minCount += mins[i]; | |
| } | |
| return minCount; | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isNativeC40(FX_WCHAR ch) | |
| { | |
| return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'); | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isNativeText(FX_WCHAR ch) | |
| { | |
| return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z'); | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isNativeX12(FX_WCHAR ch) | |
| { | |
| return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'); | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isX12TermSep(FX_WCHAR ch) | |
| { | |
| return (ch == '\r') || (ch == '*') || (ch == '>'); | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isNativeEDIFACT(FX_WCHAR ch) | |
| { | |
| return ch >= ' ' && ch <= '^'; | |
| } | |
| FX_BOOL CBC_HighLevelEncoder::isSpecialB256(FX_WCHAR ch) | |
| { | |
| return FALSE; | |
| } |