You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
11 KiB
391 lines
11 KiB
// 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 Jeremias Maerki in part, and ZXing Authors in part
|
|
*
|
|
* 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 "fxbarcode/pdf417/BC_PDF417HighLevelEncoder.h"
|
|
|
|
#include "core/fxcrt/fx_extension.h"
|
|
#include "third_party/bigint/BigIntegerLibrary.hh"
|
|
|
|
namespace {
|
|
|
|
constexpr int16_t kLatchToText = 900;
|
|
constexpr int16_t kLatchToBytePadded = 901;
|
|
constexpr int16_t kLatchToNumeric = 902;
|
|
constexpr int16_t kShiftToByte = 913;
|
|
constexpr int16_t kLatchToByte = 924;
|
|
|
|
constexpr int8_t kMixed[128] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, -1, -1, 11, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, 15, 18, 21,
|
|
10, -1, -1, -1, 22, 20, 13, 16, 17, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8,
|
|
9, 14, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
|
|
|
constexpr int8_t kPunctuation[128] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 15, -1, -1, 11, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 20, -1, 18, -1,
|
|
-1, 28, 23, 24, 22, -1, 13, 16, 17, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, 14, 0, 1, -1, 2, 25, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1,
|
|
7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 21, 27, 9, -1};
|
|
|
|
bool IsAlphaUpperOrSpace(wchar_t ch) {
|
|
return ch == ' ' || (ch >= 'A' && ch <= 'Z');
|
|
}
|
|
|
|
bool IsAlphaLowerOrSpace(wchar_t ch) {
|
|
return ch == ' ' || (ch >= 'a' && ch <= 'z');
|
|
}
|
|
|
|
bool IsMixed(wchar_t ch) {
|
|
// Bounds check avoiding sign mismatch error given questionable signedness.
|
|
return !((ch & ~0x7F) || kMixed[ch] == -1);
|
|
}
|
|
|
|
bool IsPunctuation(wchar_t ch) {
|
|
// Bounds check avoiding sign mismatch error given questionable signedness.
|
|
return !((ch & ~0x7F) || kPunctuation[ch] == -1);
|
|
}
|
|
|
|
bool IsText(wchar_t ch) {
|
|
return (ch >= 32 && ch <= 126) || ch == '\t' || ch == '\n' || ch == '\r';
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
Optional<WideString> CBC_PDF417HighLevelEncoder::EncodeHighLevel(
|
|
WideStringView msg) {
|
|
ByteString bytes = FX_UTF8Encode(msg);
|
|
size_t len = bytes.GetLength();
|
|
WideString result;
|
|
result.Reserve(len);
|
|
for (size_t i = 0; i < len; i++) {
|
|
wchar_t ch = bytes[i] & 0xff;
|
|
if (ch == '?' && bytes[i] != '?')
|
|
return {};
|
|
|
|
result += ch;
|
|
}
|
|
std::vector<uint8_t> byteArr(bytes.begin(), bytes.end());
|
|
len = result.GetLength();
|
|
WideString sb;
|
|
sb.Reserve(len);
|
|
size_t p = 0;
|
|
SubMode textSubMode = SubMode::kAlpha;
|
|
EncodingMode encodingMode = EncodingMode::kUnknown;
|
|
while (p < len) {
|
|
size_t n = DetermineConsecutiveDigitCount(result, p);
|
|
if (n >= 13) {
|
|
sb += kLatchToNumeric;
|
|
encodingMode = EncodingMode::kNumeric;
|
|
textSubMode = SubMode::kAlpha;
|
|
EncodeNumeric(result, p, n, &sb);
|
|
p += n;
|
|
} else {
|
|
size_t t = DetermineConsecutiveTextCount(result, p);
|
|
if (t >= 5 || n == len) {
|
|
if (encodingMode != EncodingMode::kText) {
|
|
sb += kLatchToText;
|
|
encodingMode = EncodingMode::kText;
|
|
textSubMode = SubMode::kAlpha;
|
|
}
|
|
textSubMode = EncodeText(result, p, t, textSubMode, &sb);
|
|
p += t;
|
|
} else {
|
|
Optional<size_t> b =
|
|
DetermineConsecutiveBinaryCount(result, &byteArr, p);
|
|
if (!b)
|
|
return {};
|
|
|
|
size_t b_value = b.value();
|
|
if (b_value == 0)
|
|
b_value = 1;
|
|
if (b_value == 1 && encodingMode == EncodingMode::kText) {
|
|
EncodeBinary(byteArr, p, 1, EncodingMode::kText, &sb);
|
|
} else {
|
|
EncodeBinary(byteArr, p, b_value, encodingMode, &sb);
|
|
encodingMode = EncodingMode::kByte;
|
|
textSubMode = SubMode::kAlpha;
|
|
}
|
|
p += b_value;
|
|
}
|
|
}
|
|
}
|
|
return sb;
|
|
}
|
|
|
|
CBC_PDF417HighLevelEncoder::SubMode CBC_PDF417HighLevelEncoder::EncodeText(
|
|
const WideString& msg,
|
|
size_t startpos,
|
|
size_t count,
|
|
SubMode initialSubmode,
|
|
WideString* sb) {
|
|
WideString tmp;
|
|
tmp.Reserve(count);
|
|
SubMode submode = initialSubmode;
|
|
size_t idx = 0;
|
|
while (idx < count) {
|
|
wchar_t ch = msg[startpos + idx];
|
|
switch (submode) {
|
|
case SubMode::kAlpha:
|
|
if (IsAlphaUpperOrSpace(ch)) {
|
|
if (ch == ' ')
|
|
tmp += 26;
|
|
else
|
|
tmp += ch - 65;
|
|
break;
|
|
}
|
|
if (IsAlphaLowerOrSpace(ch)) {
|
|
submode = SubMode::kLower;
|
|
tmp += 27;
|
|
continue;
|
|
}
|
|
if (IsMixed(ch)) {
|
|
submode = SubMode::kMixed;
|
|
tmp += 28;
|
|
continue;
|
|
}
|
|
if (IsPunctuation(ch)) {
|
|
tmp += 29;
|
|
tmp += kPunctuation[ch];
|
|
}
|
|
break;
|
|
case SubMode::kLower:
|
|
if (IsAlphaLowerOrSpace(ch)) {
|
|
if (ch == ' ')
|
|
tmp += 26;
|
|
else
|
|
tmp += ch - 97;
|
|
break;
|
|
}
|
|
if (IsAlphaUpperOrSpace(ch)) {
|
|
tmp += 27;
|
|
tmp += ch - 65;
|
|
break;
|
|
}
|
|
if (IsMixed(ch)) {
|
|
submode = SubMode::kMixed;
|
|
tmp += 28;
|
|
continue;
|
|
}
|
|
if (IsPunctuation(ch)) {
|
|
tmp += 29;
|
|
tmp += kPunctuation[ch];
|
|
}
|
|
break;
|
|
case SubMode::kMixed:
|
|
if (IsMixed(ch)) {
|
|
tmp += kMixed[ch];
|
|
break;
|
|
}
|
|
if (IsAlphaUpperOrSpace(ch)) {
|
|
submode = SubMode::kAlpha;
|
|
tmp += 28;
|
|
continue;
|
|
}
|
|
if (IsAlphaLowerOrSpace(ch)) {
|
|
submode = SubMode::kLower;
|
|
tmp += 27;
|
|
continue;
|
|
}
|
|
if (startpos + idx + 1 < count) {
|
|
wchar_t next = msg[startpos + idx + 1];
|
|
if (IsPunctuation(next)) {
|
|
submode = SubMode::kPunctuation;
|
|
tmp += 25;
|
|
continue;
|
|
}
|
|
}
|
|
if (IsPunctuation(ch)) {
|
|
tmp += 29;
|
|
tmp += kPunctuation[ch];
|
|
}
|
|
break;
|
|
default:
|
|
if (IsPunctuation(ch)) {
|
|
tmp += kPunctuation[ch];
|
|
break;
|
|
}
|
|
submode = SubMode::kAlpha;
|
|
tmp += 29;
|
|
continue;
|
|
}
|
|
++idx;
|
|
}
|
|
wchar_t h = 0;
|
|
size_t len = tmp.GetLength();
|
|
for (size_t i = 0; i < len; i++) {
|
|
bool odd = (i % 2) != 0;
|
|
if (odd) {
|
|
h = (h * 30) + tmp[i];
|
|
*sb += h;
|
|
} else {
|
|
h = tmp[i];
|
|
}
|
|
}
|
|
if ((len % 2) != 0)
|
|
*sb += (h * 30) + 29;
|
|
return submode;
|
|
}
|
|
|
|
void CBC_PDF417HighLevelEncoder::EncodeBinary(pdfium::span<const uint8_t> bytes,
|
|
size_t startpos,
|
|
size_t count,
|
|
EncodingMode startmode,
|
|
WideString* sb) {
|
|
if (count == 1 && startmode == EncodingMode::kText)
|
|
*sb += kShiftToByte;
|
|
|
|
size_t idx = startpos;
|
|
if (count >= 6) {
|
|
*sb += kLatchToByte;
|
|
wchar_t chars[5];
|
|
while ((startpos + count - idx) >= 6) {
|
|
int64_t t = 0;
|
|
for (size_t i = 0; i < 6; i++) {
|
|
t <<= 8;
|
|
t += bytes[idx + i] & 0xff;
|
|
}
|
|
for (size_t i = 0; i < 5; i++) {
|
|
chars[i] = (t % 900);
|
|
t /= 900;
|
|
}
|
|
for (size_t i = 5; i >= 1; i--)
|
|
*sb += (chars[i - 1]);
|
|
idx += 6;
|
|
}
|
|
}
|
|
if (idx < startpos + count)
|
|
*sb += kLatchToBytePadded;
|
|
for (size_t i = idx; i < startpos + count; i++) {
|
|
int32_t ch = bytes[i] & 0xff;
|
|
*sb += ch;
|
|
}
|
|
}
|
|
|
|
void CBC_PDF417HighLevelEncoder::EncodeNumeric(const WideString& msg,
|
|
size_t startpos,
|
|
size_t count,
|
|
WideString* sb) {
|
|
size_t idx = 0;
|
|
BigInteger num900 = 900;
|
|
while (idx < count) {
|
|
WideString tmp;
|
|
size_t len = 44 < count - idx ? 44 : count - idx;
|
|
ByteString part = (L'1' + msg.Substr(startpos + idx, len)).ToUTF8();
|
|
BigInteger bigint = stringToBigInteger(part.c_str());
|
|
do {
|
|
int32_t c = (bigint % num900).toInt();
|
|
tmp += c;
|
|
bigint = bigint / num900;
|
|
} while (!bigint.isZero());
|
|
for (size_t i = tmp.GetLength(); i >= 1; i--)
|
|
*sb += tmp[i - 1];
|
|
idx += len;
|
|
}
|
|
}
|
|
|
|
size_t CBC_PDF417HighLevelEncoder::DetermineConsecutiveDigitCount(
|
|
WideString msg,
|
|
size_t startpos) {
|
|
size_t count = 0;
|
|
size_t len = msg.GetLength();
|
|
size_t idx = startpos;
|
|
if (idx < len) {
|
|
wchar_t ch = msg[idx];
|
|
while (FXSYS_IsDecimalDigit(ch) && idx < len) {
|
|
count++;
|
|
idx++;
|
|
if (idx < len)
|
|
ch = msg[idx];
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
size_t CBC_PDF417HighLevelEncoder::DetermineConsecutiveTextCount(
|
|
WideString msg,
|
|
size_t startpos) {
|
|
size_t len = msg.GetLength();
|
|
size_t idx = startpos;
|
|
while (idx < len) {
|
|
wchar_t ch = msg[idx];
|
|
size_t numericCount = 0;
|
|
while (numericCount < 13 && FXSYS_IsDecimalDigit(ch) && idx < len) {
|
|
numericCount++;
|
|
idx++;
|
|
if (idx < len)
|
|
ch = msg[idx];
|
|
}
|
|
if (numericCount >= 13)
|
|
return idx - startpos - numericCount;
|
|
if (numericCount > 0)
|
|
continue;
|
|
ch = msg[idx];
|
|
if (!IsText(ch))
|
|
break;
|
|
idx++;
|
|
}
|
|
return idx - startpos;
|
|
}
|
|
|
|
Optional<size_t> CBC_PDF417HighLevelEncoder::DetermineConsecutiveBinaryCount(
|
|
WideString msg,
|
|
std::vector<uint8_t>* bytes,
|
|
size_t startpos) {
|
|
size_t len = msg.GetLength();
|
|
size_t idx = startpos;
|
|
while (idx < len) {
|
|
wchar_t ch = msg[idx];
|
|
size_t numericCount = 0;
|
|
while (numericCount < 13 && FXSYS_IsDecimalDigit(ch)) {
|
|
numericCount++;
|
|
size_t i = idx + numericCount;
|
|
if (i >= len)
|
|
break;
|
|
ch = msg[i];
|
|
}
|
|
if (numericCount >= 13)
|
|
return idx - startpos;
|
|
|
|
size_t textCount = 0;
|
|
while (textCount < 5 && IsText(ch)) {
|
|
textCount++;
|
|
size_t i = idx + textCount;
|
|
if (i >= len)
|
|
break;
|
|
ch = msg[i];
|
|
}
|
|
if (textCount >= 5)
|
|
return idx - startpos;
|
|
ch = msg[idx];
|
|
if ((*bytes)[idx] == 63 && ch != '?')
|
|
return {};
|
|
idx++;
|
|
}
|
|
return idx - startpos;
|
|
}
|