zxing-cpp: strip to core library only (remove tests/wrappers/examples/docs); .gitignore: fix /core to allow zxing-cpp/core/ dir

This commit is contained in:
Evgeny committed 2026-06-25 09:37:45 +03:00
1 parent 22c24d135e
commit 8051dfe4e5
2506 files changed
+57271 -30087

No files matched your search

@@ -0,0 +1,68 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "MCBitMatrixParser.h"
#include "BitMatrix.h"
#include "ByteArray.h"
#include <array>
namespace ZXing::MaxiCode {
static const std::array<std::array<int, BitMatrixParser::MATRIX_WIDTH>, BitMatrixParser::MATRIX_HEIGHT> BITNR = {
121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2,
123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3,
125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817,
283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3,
285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820,
287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3,
289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823,
291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3,
293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826,
409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3,
411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829,
413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3,
415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832,
417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3,
419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835,
481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3,
483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838,
485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3,
487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841,
489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3,
491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844,
559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3,
561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847,
563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3,
565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850,
567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3,
569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853,
727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3,
729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856,
731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3,
733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859,
735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3,
737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862,
};
ByteArray BitMatrixParser::ReadCodewords(const BitMatrix& image)
{
ByteArray result(144);
int height = image.height();
int width = image.width();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int bit = BITNR[y][x];
if (bit >= 0 && image.get(x, y)) {
result[bit / 6] |= static_cast<uint8_t>(1 << (5 - (bit % 6)));
}
}
}
return result;
}
} // namespace ZXing::MaxiCode
@@ -0,0 +1,30 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#pragma once
namespace ZXing {
class ByteArray;
class BitMatrix;
namespace MaxiCode {
/**
* @author mike32767
* @author Manuel Kasten
*/
class BitMatrixParser
{
public:
static ByteArray ReadCodewords(const BitMatrix& image);
static const int MATRIX_WIDTH = 30;
static const int MATRIX_HEIGHT = 33;
};
} // MaxiCode
} // ZXing
@@ -0,0 +1,329 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "MCDecoder.h"
#include "ByteArray.h"
#include "CharacterSet.h"
#include "DecoderResult.h"
#include "MCBitMatrixParser.h"
#include "ReedSolomon.h"
#include "ZXTestSupport.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
namespace ZXing::MaxiCode {
static const int ALL = 0;
static const int EVEN = 1;
static const int ODD = 2;
static bool CorrectErrors(ByteArray& codewordBytes, int start, int dataCodewords, int ecCodewords, int mode)
{
int codewords = dataCodewords + ecCodewords;
// in EVEN or ODD mode only half the codewords
int divisor = mode == ALL ? 1 : 2;
// First read into an array of ints
std::vector<int> codewordsInts(codewords / divisor, 0);
for (int i = 0; i < codewords; i++) {
if ((mode == ALL) || (i % 2 == (mode - 1)))
codewordsInts[i / divisor] = codewordBytes[i + start];
}
if (!ReedSolomonDecode(RSField::MaxiCode, codewordsInts, ecCodewords / divisor))
return false;
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < dataCodewords; i++) {
if ((mode == ALL) || (i % 2 == (mode - 1)))
codewordBytes[i + start] = narrow_cast<uint8_t>(codewordsInts[i / divisor]);
}
return true;
}
/**
* <p>MaxiCodes can encode text or structured information as bits in one of several modes,
* with multiple character sets in one code. This class decodes the bits back into text.</p>
*
* @author mike32767
* @author Manuel Kasten
*/
namespace DecodedBitStreamParser {
static const short SHI0 = 0x100;
static const short SHI1 = 0x101;
static const short SHI2 = 0x102;
static const short SHI3 = 0x103;
static const short SHI4 = 0x104;
static const short TWSA = 0x105; // two shift A
static const short TRSA = 0x106; // three shift A
static const short LCHA = 0x107; // latch A
static const short LCHB = 0x108; // latch B
static const short LOCK = 0x109;
static const short ECI = 0x10A;
static const short NS = 0x10B;
static const short PAD = 0x10C;
static const char FS = 0x1C;
static const char GS = 0x1D;
static const char RS = 0x1E;
// clang-format off
const static std::array<short, 0x40> CHARSETS[] = {
{ // set 0 (A)
'\r', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ECI, FS, GS, RS, NS,
' ', PAD, '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', SHI1, SHI2, SHI3, SHI4, LCHB,
},
{ // set 1 (B)
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ECI, FS, GS, RS, NS,
'{', PAD, '}', '~', 0x7F, ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', ' ',
',', '.', '/', ':', '@', '!', '|', PAD, TWSA, TRSA, PAD, SHI0, SHI2, SHI3, SHI4, LCHA,
},
{ // set 2 (C)
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, ECI, FS, GS, RS, NS, // Note that in original code in Java, NS is not there, which seems to be a bug
0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xAA, 0xAC, 0xB1, 0xB2, 0xB3, 0xB5, 0xB9, 0xBA, 0xBC, 0xBD, 0xBE,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, LCHA, 0x20, LOCK, SHI3, SHI4, LCHB,
},
{ // set 3 (D)
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, ECI, FS, GS, RS, NS,
0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xA1, 0xA8, 0xAB, 0xAF, 0xB0, 0xB4, 0xB7, 0xB8, 0xBB, 0xBF, 0x8A,
0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, LCHA, 0x20, SHI2, LOCK, SHI4, LCHB,
},
{ // set 4 (E)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, ECI, PAD, PAD, 0x1B, NS,
FS, GS, RS, 0x1F, 0x9F, 0xA0, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA9, 0xAD, 0xAE, 0xB6,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, LCHA, 0x20, SHI2, SHI3, LOCK, LCHB,
},
};
// clang-format on
static int GetBit(int bit, const ByteArray& bytes)
{
bit--;
return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1;
}
static unsigned int GetInt(const ByteArray& bytes, const ByteArray& x)
{
int len = Size(x);
unsigned int val = 0;
for (int i = 0; i < len; i++)
val += GetBit(x[i], bytes) << (len - i - 1);
return val;
}
static unsigned int GetPostCode2Length(const ByteArray& bytes)
{
return std::min(GetInt(bytes, {39, 40, 41, 42, 31, 32}), 9U);
}
static std::string GetPostCode2(const ByteArray& bytes)
{
unsigned int val = GetInt(bytes,
{33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2});
unsigned int len = GetPostCode2Length(bytes);
// Pad or truncate to length
char buf[11]; // 30 bits 0x3FFFFFFF == 1073741823 (10 digits)
snprintf(buf, sizeof(buf), "%0*d", len, val);
buf[len] = '\0';
return buf;
}
static std::string GetPostCode3(const ByteArray& bytes)
{
return {
(char) CHARSETS[0].at(GetInt(bytes, { 39, 40, 41, 42, 31, 32 })),
(char) CHARSETS[0].at(GetInt(bytes, { 33, 34, 35, 36, 25, 26 })),
(char) CHARSETS[0].at(GetInt(bytes, { 27, 28, 29, 30, 19, 20 })),
(char) CHARSETS[0].at(GetInt(bytes, { 21, 22, 23, 24, 13, 14 })),
(char) CHARSETS[0].at(GetInt(bytes, { 15, 16, 17, 18, 7, 8 })),
(char) CHARSETS[0].at(GetInt(bytes, { 9, 10, 11, 12, 1, 2 })),
};
}
static unsigned int GetCountry(const ByteArray& bytes)
{
return std::min(GetInt(bytes, {53, 54, 43, 44, 45, 46, 47, 48, 37, 38}), 999U);
}
static unsigned int GetServiceClass(const ByteArray& bytes)
{
return std::min(GetInt(bytes, {55, 56, 57, 58, 59, 60, 49, 50, 51, 52}), 999U);
}
/**
* See ISO/IEC 16023:2000 Section 4.6 Table 3
*/
static ZXing::ECI ParseECIValue(const ByteArray& bytes, int& i)
{
int firstByte = bytes[++i];
if ((firstByte & 0x20) == 0)
return ZXing::ECI(firstByte);
int secondByte = bytes[++i];
if ((firstByte & 0x10) == 0)
return ZXing::ECI(((firstByte & 0x0F) << 6) | secondByte);
int thirdByte = bytes[++i];
if ((firstByte & 0x08) == 0)
return ZXing::ECI(((firstByte & 0x07) << 12) | (secondByte << 6) | thirdByte);
int fourthByte = bytes[++i];
return ZXing::ECI(((firstByte & 0x03) << 18) | (secondByte << 12) | (thirdByte << 6) | fourthByte);
}
/**
* See ISO/IEC 16023:2000 Section 4.9.1 Table 5
*/
static void ParseStructuredAppend(const ByteArray& bytes, int& i, StructuredAppendInfo& sai)
{
int byte = bytes[++i];
sai.index = (byte >> 3) & 0x07;
sai.count = (byte & 0x07) + 1;
if (sai.count == 1 || sai.count <= sai.index) // If info doesn't make sense
sai.count = 0; // Choose to mark count as unknown
// No id
}
static void GetMessage(const ByteArray& bytes, int start, int len, Content& result, StructuredAppendInfo& sai)
{
int shift = -1;
int set = 0;
int lastset = 0;
for (int i = start; i < start + len; i++) {
int c = CHARSETS[set].at(bytes[i]);
switch (c) {
case LCHA:
set = 0;
shift = -1;
break;
case LCHB:
set = 1;
shift = -1;
break;
case SHI0:
case SHI1:
case SHI2:
case SHI3:
case SHI4:
lastset = set;
set = c - SHI0;
shift = 1;
break;
case TWSA:
lastset = set;
set = 0;
shift = 2;
break;
case TRSA:
lastset = set;
set = 0;
shift = 3;
break;
case NS:
result.append(
ToString((bytes[i + 1] << 24) + (bytes[i + 2] << 18) + (bytes[i + 3] << 12) + (bytes[i + 4] << 6) + bytes[i + 5], 9));
i += 5;
break;
case LOCK: shift = -1; break;
case ECI: result.switchEncoding(ParseECIValue(bytes, i)); break;
case PAD:
if (i == start)
ParseStructuredAppend(bytes, i, sai);
shift = -1;
break;
default: result.push_back(c);
}
if (shift-- == 0)
set = lastset;
}
}
ZXING_EXPORT_TEST_ONLY
DecoderResult Decode(ByteArray&& bytes, const int mode)
{
Content result;
result.symbology = {'U', (mode == 2 || mode == 3) ? '1' : '0', 2}; // TODO: No identifier defined for mode 6?
result.defaultCharset = CharacterSet::ISO8859_1;
StructuredAppendInfo sai;
switch (mode) {
case 2:
case 3: {
auto postcode = mode == 2 ? GetPostCode2(bytes) : GetPostCode3(bytes);
auto country = ToString(GetCountry(bytes), 3);
auto service = ToString(GetServiceClass(bytes), 3);
GetMessage(bytes, 10, 84, result, sai);
result.insert(result.bytes.asString().starts_with("[)>\u001E01\u001D") ? 9 : 0, // "[)>" + RS + "01" + GS
postcode + GS + country + GS + service + GS);
break;
}
case 4:
case 6: GetMessage(bytes, 1, 93, result, sai); break;
case 5: GetMessage(bytes, 1, 77, result, sai); break;
}
return DecoderResult(std::move(result))
.setEcLevel(std::to_string(mode))
.setStructuredAppend(sai)
.setReaderInit(mode == 6);
}
} // DecodedBitStreamParser
DecoderResult Decode(const BitMatrix& bits)
{
ByteArray codewords = BitMatrixParser::ReadCodewords(bits);
if (!CorrectErrors(codewords, 0, 10, 10, ALL))
return ChecksumError();
int mode = codewords[0] & 0x0F;
ByteArray datawords;
switch (mode) {
case 2: // Structured Carrier Message (numeric postcode)
case 3: // Structured Carrier Message (alphanumeric postcode)
case 4: // Standard Symbol
case 6: // Reader Programming
if (CorrectErrors(codewords, 20, 84, 40, EVEN) && CorrectErrors(codewords, 20, 84, 40, ODD))
datawords.resize(94, 0);
else
return ChecksumError();
break;
case 5: // Full ECC
if (CorrectErrors(codewords, 20, 68, 56, EVEN) && CorrectErrors(codewords, 20, 68, 56, ODD))
datawords.resize(78, 0);
else
return ChecksumError();
break;
default: return FormatError("Invalid mode");
}
std::copy_n(codewords.begin(), 10, datawords.begin());
std::copy_n(codewords.begin() + 20, datawords.size() - 10, datawords.begin() + 10);
return DecodedBitStreamParser::Decode(std::move(datawords), mode);
}
} // namespace ZXing::MaxiCode
@@ -0,0 +1,19 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#pragma once
namespace ZXing {
class DecoderResult;
class BitMatrix;
namespace MaxiCode {
DecoderResult Decode(const BitMatrix& bits);
} // MaxiCode
} // ZXing
@@ -0,0 +1,65 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "MCReader.h"
#include "BinaryBitmap.h"
#include "BitMatrix.h"
#include "DecoderResult.h"
#include "DetectorResult.h"
#include "MCBitMatrixParser.h"
#include "MCDecoder.h"
#include "BarcodeData.h"
namespace ZXing::MaxiCode {
/**
* This method detects a code in a "pure" image -- that is, pure monochrome image
* which contains only an unrotated, unskewed, image of a code, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*/
static DetectorResult ExtractPureBits(const BitMatrix& image)
{
int left, top, width, height;
if (!image.findBoundingBox(left, top, width, height, BitMatrixParser::MATRIX_WIDTH))
return {};
// Now just read off the bits
BitMatrix bits(BitMatrixParser::MATRIX_WIDTH, BitMatrixParser::MATRIX_HEIGHT);
for (int y = 0; y < BitMatrixParser::MATRIX_HEIGHT; y++) {
int iy = top + (y * height + height / 2) / BitMatrixParser::MATRIX_HEIGHT;
for (int x = 0; x < BitMatrixParser::MATRIX_WIDTH; x++) {
int ix = left + (x * width + width / 2 + (y & 0x01) * width / 2) / BitMatrixParser::MATRIX_WIDTH;
if (image.get(ix, iy)) {
bits.set(x, y);
}
}
}
return {std::move(bits), Rectangle<PointI>(left, top, width, height)};
}
BarcodesData Reader::read(const BinaryBitmap& image, [[maybe_unused]] int maxSymbols) const
{
auto binImg = image.getBitMatrix();
if (binImg == nullptr)
return {};
//TODO: this only works with effectively 'pure' barcodes. Needs proper detector.
auto detRes = ExtractPureBits(*binImg);
if (!detRes.isValid())
return {};
DecoderResult decRes = Decode(detRes.bits());
// TODO: before we can meaningfully return a ChecksumError result, we need to check the center for the presence of the finder pattern
if (!decRes.isValid())
return {};
return ToVector(MatrixBarcode(std::move(decRes), std::move(detRes), BarcodeFormat::MaxiCode));
}
} // namespace ZXing::MaxiCode
@@ -0,0 +1,21 @@
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "Reader.h"
namespace ZXing::MaxiCode {
class Reader : public ZXing::Reader
{
public:
using ZXing::Reader::Reader;
BarcodesData read(const BinaryBitmap& image, int maxSymbols) const override;
};
} // namespace ZXing::MaxiCode