blob: 5b46612d623e40819e688b5d123f5ab3d106dcf5 [file] [log] [blame]
// 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;
}