stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
This commit is contained in:
1 parent
a3783b5f55
commit
38c9f229bc
1272 files changed
+968388
-1
No files matched your search
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* Copyright 2024 Axel Waggershauser
|
||||
* Copyright 2025 gitlost
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "CreateBarcode.h"
|
||||
|
||||
#include "BarcodeData.h"
|
||||
#include "BitMatrix.h"
|
||||
#include "ByteArray.h"
|
||||
#include "DecoderResult.h"
|
||||
#include "DetectorResult.h"
|
||||
#include "JSON.h"
|
||||
#include "Version.h"
|
||||
#include "ZXAlgorithms.h"
|
||||
|
||||
#ifdef ZXING_READERS
|
||||
#include "ReadBarcode.h"
|
||||
#endif
|
||||
|
||||
#ifdef ZXING_USE_ZINT
|
||||
#include "ECI.h"
|
||||
#include "TextEncoder.h"
|
||||
#include <zint.h>
|
||||
#else
|
||||
#include "MultiFormatWriter.h"
|
||||
#endif // ZXING_USE_ZINT
|
||||
|
||||
#include <charconv>
|
||||
#include <optional>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ZXing {
|
||||
|
||||
struct CreatorOptions::Data
|
||||
{
|
||||
BarcodeFormat format;
|
||||
std::string options;
|
||||
|
||||
// symbol size (qrcode, datamatrix, etc), map from I, 'WxH'
|
||||
// structured_append (idx, cnt, ID)
|
||||
|
||||
mutable unique_zint_symbol zint;
|
||||
|
||||
#ifndef __cpp_aggregate_paren_init // make XCode 14.x happy
|
||||
Data(BarcodeFormat format, std::string options) : format(format), options(std::move(options)) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
// TODO: check return type
|
||||
#define ZX_PROPERTY(TYPE, NAME) \
|
||||
const TYPE& CreatorOptions::NAME() const noexcept { return d->NAME; } \
|
||||
CreatorOptions& CreatorOptions::NAME(TYPE v)& { return d->NAME = std::move(v), *this; } \
|
||||
CreatorOptions&& CreatorOptions::NAME(TYPE v)&& { return d->NAME = std::move(v), std::move(*this); }
|
||||
|
||||
ZX_PROPERTY(BarcodeFormat, format)
|
||||
ZX_PROPERTY(std::string, options)
|
||||
|
||||
#undef ZX_PROPERTY
|
||||
|
||||
#define ZX_RO_PROPERTY(TYPE, NAME) \
|
||||
std::optional<TYPE> CreatorOptions::NAME() const noexcept { return JsonGet<TYPE>(d->options, #NAME); }
|
||||
|
||||
ZX_RO_PROPERTY(std::string, ecLevel);
|
||||
ZX_RO_PROPERTY(std::string, eci);
|
||||
ZX_RO_PROPERTY(bool, gs1);
|
||||
ZX_RO_PROPERTY(bool, readerInit);
|
||||
ZX_RO_PROPERTY(bool, forceSquare);
|
||||
ZX_RO_PROPERTY(int, columns);
|
||||
ZX_RO_PROPERTY(int, rows);
|
||||
ZX_RO_PROPERTY(int, version);
|
||||
ZX_RO_PROPERTY(int, dataMask);
|
||||
|
||||
#undef ZX_RO_PROPERTY
|
||||
|
||||
CreatorOptions::CreatorOptions(BarcodeFormat format, std::string options) : d(std::make_unique<Data>(format, std::move(options))) {}
|
||||
CreatorOptions::~CreatorOptions() = default;
|
||||
CreatorOptions::CreatorOptions(CreatorOptions&&) noexcept = default;
|
||||
CreatorOptions& CreatorOptions::operator=(CreatorOptions&&) noexcept = default;
|
||||
|
||||
inline bool IsAscii(ByteView bv)
|
||||
{
|
||||
return std::all_of(bv.begin(), bv.end(), [](uint8_t c) { return c <= 127; });
|
||||
}
|
||||
|
||||
#ifdef ZXING_WRITERS
|
||||
#ifdef ZXING_USE_ZINT
|
||||
|
||||
struct String2Int
|
||||
{
|
||||
const char* str;
|
||||
int val;
|
||||
};
|
||||
|
||||
static int ParseECLevel(int symbology, std::string_view s)
|
||||
{
|
||||
constexpr std::string_view EC_LABELS_QR[4] = {"L", "M", "Q", "H"};
|
||||
int res = 0;
|
||||
|
||||
// Convert L/M/Q/H to Zint 1-4
|
||||
if (Contains({BARCODE_QRCODE, BARCODE_MICROQR, BARCODE_RMQR}, symbology))
|
||||
if ((res = IndexOf(EC_LABELS_QR, s)) != -1)
|
||||
return res + 1;
|
||||
|
||||
if (std::from_chars(s.data(), s.data() + s.size() - (s.back() == '%'), res).ec != std::errc{})
|
||||
throw std::invalid_argument(StrCat("Invalid ecLevel: '", s, "'"));
|
||||
|
||||
auto findClosestECLevel = [](const std::vector<int>& list, int val) {
|
||||
int mIdx = -2, mAbs = 100;
|
||||
for (int i = 0; i < Size(list); ++i)
|
||||
if (int abs = std::abs(val - list[i]); abs < mAbs) {
|
||||
mIdx = i;
|
||||
mAbs = abs;
|
||||
}
|
||||
return mIdx + 1;
|
||||
};
|
||||
|
||||
// Convert percentage to Zint
|
||||
if (s.back() == '%') {
|
||||
switch (symbology) {
|
||||
case BARCODE_QRCODE: return findClosestECLevel({20, 37, 55, 65}, res);
|
||||
case BARCODE_MICROQR: return findClosestECLevel({20, 37, 55}, res);
|
||||
case BARCODE_RMQR: return res <= 46 ? 2 : 4;
|
||||
case BARCODE_AZTEC: return findClosestECLevel({10, 23, 36, 50}, res);
|
||||
case BARCODE_PDF417:
|
||||
// TODO: do something sensible with PDF417?
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
static constexpr struct { BarcodeFormat format; SymbologyIdentifier si; } barcodeFormat2SymbologyIdentifier[] = {
|
||||
{BarcodeFormat::Aztec, {'z', '0', 3}}, // '1' GS1, '2' AIM
|
||||
{BarcodeFormat::Codabar, {'F', '0'}}, // if checksum processing were implemented and checksum present and stripped then modifier would be 4
|
||||
// {BarcodeFormat::CodablockF, {'O', '4'}}, // '5' GS1
|
||||
{BarcodeFormat::Code128, {'C', '0'}}, // '1' GS1, '2' AIM
|
||||
// {BarcodeFormat::Code16K, {'K', '0'}}, // '1' GS1, '2' AIM, '4' D1 PAD
|
||||
// {BarcodeFormat::Code39, {'A', '0'}}, // '3' checksum, '4' extended, '7' checksum,extended
|
||||
{BarcodeFormat::Code39Ext, {'A', '4'}}, // '3' checksum, '4' extended, '7' checksum,extended
|
||||
{BarcodeFormat::DataBar, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarOmni, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarStk, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarStkOmni, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarExp, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarExpStk, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataBarLtd, {'e', '0', 0, AIFlag::GS1}},
|
||||
{BarcodeFormat::DataMatrix, {'d', '1', 3}}, // '2' GS1, '3' AIM
|
||||
// {BarcodeFormat::DotCode, {'J', '0', 3}}, // '1' GS1, '2' AIM
|
||||
{BarcodeFormat::DXFilmEdge, {'X', 'F'}},
|
||||
{BarcodeFormat::EAN8, {'E', '4'}},
|
||||
// {BarcodeFormat::HanXin, {'h', '0', 1}}, // '2' GS1
|
||||
// {BarcodeFormat::ITF, {'I', '0'}}, // '1' check digit
|
||||
{BarcodeFormat::MaxiCode, {'U', '0', 2}}, // '1' mode 2 or 3
|
||||
{BarcodeFormat::MicroPDF417, {'L', '2', -1}},
|
||||
{BarcodeFormat::MicroQRCode, {'Q', '1', 1}},
|
||||
{BarcodeFormat::PDF417, {'L', '2', -1}},
|
||||
{BarcodeFormat::QRCode, {'Q', '1', 1}}, // '3' GS1, '5' AIM
|
||||
{BarcodeFormat::RMQRCode, {'Q', '1', 1}}, // '3' GS1, '5' AIM
|
||||
};
|
||||
|
||||
static SymbologyIdentifier SymbologyIdentifierZint2ZXing(const CreatorOptions& opts, const ByteArray& ba)
|
||||
{
|
||||
using enum BarcodeFormat;
|
||||
|
||||
const BarcodeFormat format = opts.format();
|
||||
|
||||
auto i = FindIf(barcodeFormat2SymbologyIdentifier, [format](auto& v) { return v.format == format; });
|
||||
SymbologyIdentifier ret = i != std::end(barcodeFormat2SymbologyIdentifier) ? i->si : SymbologyIdentifier{SymbologyKey(format), '0'};
|
||||
|
||||
if (format & (EAN13 | UPCA | UPCE)) {
|
||||
if (ba.size() > 13) // Have EAN-2/5 add-on?
|
||||
ret.modifier = '3'; // Combined packet, EAN-13, UPC-A, UPC-E, with add-on
|
||||
} else if (opts.gs1() && format & AllGS1) {
|
||||
if (format & (Aztec | Code128))
|
||||
ret.modifier = '1';
|
||||
else if (format == DataMatrix)
|
||||
ret.modifier = '2';
|
||||
else if (format & (QRCode | RMQRCode))
|
||||
ret.modifier = '3';
|
||||
ret.aiFlag = AIFlag::GS1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string ECLevelZint2ZXing(const zint_symbol* zint)
|
||||
{
|
||||
constexpr char EC_LABELS_QR[4] = {'L', 'M', 'Q', 'H'};
|
||||
|
||||
const int symbology = zint->symbology;
|
||||
const int option_1 = zint->option_1;
|
||||
|
||||
switch (symbology) {
|
||||
case BARCODE_AZTEC:
|
||||
if ((option_1 >> 8) >= 0 && (option_1 >> 8) <= 99)
|
||||
return std::to_string(option_1 >> 8) + "%";
|
||||
break;
|
||||
case BARCODE_MAXICODE:
|
||||
// Mode
|
||||
if (option_1 >= 2 && option_1 <= 6)
|
||||
return std::to_string(option_1);
|
||||
break;
|
||||
case BARCODE_PDF417:
|
||||
case BARCODE_PDF417COMP:
|
||||
// Convert to percentage
|
||||
if (option_1 >= 0 && option_1 <= 8) {
|
||||
int overhead = symbology == BARCODE_PDF417COMP ? 35 : 69;
|
||||
int cols = (zint->width - overhead) / 17;
|
||||
int tot_cws = zint->rows * cols;
|
||||
assert(tot_cws);
|
||||
return std::to_string((2 << option_1) * 100 / tot_cws) + "%";
|
||||
}
|
||||
break;
|
||||
// case BARCODE_MICROPDF417:
|
||||
// if ((option_1 >> 8) >= 0 && (option_1 >> 8) <= 99)
|
||||
// return std::to_string(option_1 >> 8) + "%";
|
||||
// break;
|
||||
case BARCODE_QRCODE:
|
||||
case BARCODE_MICROQR:
|
||||
case BARCODE_RMQR:
|
||||
// Convert to L/M/Q/H
|
||||
if (option_1 >= 1 && option_1 <= 4)
|
||||
return {EC_LABELS_QR[option_1 - 1]};
|
||||
break;
|
||||
// case BARCODE_HANXIN:
|
||||
// if (option_1 >= 1 && option_1 <= 4)
|
||||
// return "L" + std::to_string(option_1);
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifndef ZXING_READERS
|
||||
// Convert bytes to UTF-8 code points 0-255
|
||||
static std::string BinaryToUtf8(ByteView ba)
|
||||
{
|
||||
std::string utf8;
|
||||
utf8.reserve(ba.size() * 2);
|
||||
for (auto c : ba)
|
||||
if (c < 0x80) {
|
||||
utf8.push_back(c);
|
||||
} else if (c < 0xC0) {
|
||||
utf8.push_back(0xC2);
|
||||
utf8.push_back(c);
|
||||
} else {
|
||||
utf8.push_back(0xC3);
|
||||
utf8.push_back(c - 0x40);
|
||||
}
|
||||
return utf8;
|
||||
}
|
||||
#endif
|
||||
|
||||
zint_symbol* CreatorOptions::zint() const
|
||||
{
|
||||
using enum BarcodeFormat;
|
||||
|
||||
auto& zint = d->zint;
|
||||
|
||||
if (!zint) {
|
||||
#ifdef PRINT_DEBUG
|
||||
// printf("zint version: %d, sizeof(zint_symbol): %ld, options: %s\n", ZBarcode_Version(), sizeof(zint_symbol), options().c_str());
|
||||
#endif
|
||||
zint.reset(ZBarcode_Create());
|
||||
|
||||
switch (format()) {
|
||||
#define X(NAME, SYM, VAR, FLAGS, ZINT, ENABLED, HRI) \
|
||||
case BarcodeFormat(ZX_BCF_ID(SYM, VAR)): zint->symbology = ZINT; break;
|
||||
ZX_BCF_LIST(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
if (zint->symbology == 0)
|
||||
throw std::invalid_argument(StrCat("Unsupported barcode format for creation: ", ToString(format())));
|
||||
|
||||
if (format() == Code128 && gs1())
|
||||
zint->symbology = BARCODE_GS1_128;
|
||||
|
||||
zint->scale = 0.5f;
|
||||
|
||||
if (auto val = ecLevel(); val)
|
||||
zint->option_1 = ParseECLevel(zint->symbology, *val);
|
||||
|
||||
if (auto val = version(); val && !(format() & AllLinear))
|
||||
zint->option_2 = *val;
|
||||
|
||||
if (auto val = columns(); val && format() & (DataBarExpStk | PDF417 | MicroPDF417 | CompactPDF417))
|
||||
zint->option_2 = *val;
|
||||
|
||||
if (auto val = rows(); val && format() & (DataBarExpStk | PDF417))
|
||||
zint->option_3 = *val;
|
||||
|
||||
if (auto val = dataMask(); val && format() & (QRCode | MicroQRCode))
|
||||
zint->option_3 = (zint->option_3 & 0xFF) | (*val + 1) << 8;
|
||||
|
||||
if (format() == DataMatrix)
|
||||
zint->option_3 = (forceSquare() ? DM_SQUARE : DM_DMRE) | DM_ISO_144;
|
||||
}
|
||||
|
||||
return zint.get();
|
||||
}
|
||||
|
||||
#define CHECK_WARN(ZINT_CALL, WARN) \
|
||||
if (WARN = (ZINT_CALL); WARN >= ZINT_ERROR) \
|
||||
throw std::invalid_argument(StrCat(zint->errtxt, " (retval: ", std::to_string(WARN), ")"));
|
||||
|
||||
Barcode CreateBarcode(const void* data, int size, int mode, const CreatorOptions& opts)
|
||||
{
|
||||
if (!data || size < 1)
|
||||
throw std::invalid_argument("Can not create a barcode from NULL or empty data");
|
||||
|
||||
auto zint = opts.zint();
|
||||
|
||||
zint->input_mode = mode == UNICODE_MODE && opts.gs1() && (opts.format() & BarcodeFormat::AllGS1) ? GS1_MODE : mode;
|
||||
if (mode == UNICODE_MODE && static_cast<const char*>(data)[0] != '[')
|
||||
zint->input_mode |= GS1PARENS_MODE;
|
||||
zint->output_options |= OUT_BUFFER_INTERMEDIATE | BARCODE_NO_QUIET_ZONES | BARCODE_CONTENT_SEGS;
|
||||
if (opts.readerInit())
|
||||
zint->output_options |= READER_INIT;
|
||||
|
||||
if (ZBarcode_Cap(zint->symbology, ZINT_CAP_ECI)) {
|
||||
if (auto eci = opts.eci(); eci) {
|
||||
if (auto cs = CharacterSetFromString(*eci); cs != CharacterSet::Unknown) {
|
||||
zint->eci = static_cast<int>(ToECI(cs));
|
||||
} else if (std::all_of(eci->begin(), eci->end(), IsDigit<char>)) {
|
||||
zint->eci = std::stoi(*eci);
|
||||
}
|
||||
} else if (mode == DATA_MODE) {
|
||||
zint->eci = static_cast<int>(ECI::Binary);
|
||||
}
|
||||
// the following would make sure that non-ASCII text is encoded as UTF-8, hence the GuessTextEncoding for
|
||||
// non-ECI data can't produce a wrong result.
|
||||
// else if (mode == UNICODE_MODE && !IsAscii({data, narrow_cast<size_t>(size)}))
|
||||
// zint->eci = static_cast<int>(ECI::UTF8);
|
||||
}
|
||||
|
||||
if (opts.format() == BarcodeFormat::Telepen && (std::all_of((const char*)data, (const char*)data + size, IsDigit<char>)))
|
||||
zint->symbology = BARCODE_TELEPEN_NUM;
|
||||
|
||||
int warning;
|
||||
CHECK_WARN(ZBarcode_Encode_and_Buffer(zint, (uint8_t*)data, size, 0), warning);
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
printf("create symbol with size: %dx%d\n", zint->width, zint->rows);
|
||||
#endif
|
||||
|
||||
#if 0 // use ReadBarcode to create Barcode object
|
||||
auto buffer = std::vector<uint8_t>(zint->bitmap_width * zint->bitmap_height);
|
||||
std::transform(zint->bitmap, zint->bitmap + zint->bitmap_width * zint->bitmap_height, buffer.data(),
|
||||
[](unsigned char v) { return (v == '0') * 0xff; });
|
||||
|
||||
auto res = ReadBarcode({buffer.data(), zint->bitmap_width, zint->bitmap_height, ImageFormat::Lum},
|
||||
ReaderOptions().formats(opts.format()).isPure(true).binarizer(Binarizer::BoolCast));
|
||||
#else
|
||||
assert(zint->content_seg_count == 1);
|
||||
const auto& content_seg = zint->content_segs[0];
|
||||
const size_t content_seg_len =
|
||||
static_cast<size_t>(content_seg.length - (opts.format() == BarcodeFormat::Code93 && content_seg.length >= 2 ? 2 : 0));
|
||||
|
||||
Content content;
|
||||
|
||||
if (zint->eci || warning == ZINT_WARN_USES_ECI)
|
||||
content.switchEncoding(ECI(content_seg.eci));
|
||||
else
|
||||
content.switchEncoding(ToCharacterSet(ECI(content_seg.eci)));
|
||||
|
||||
if ((zint->input_mode & 0x07) == UNICODE_MODE) {
|
||||
// `content_segs` returned as UTF-8
|
||||
std::string utf8(reinterpret_cast<const char *>(content_seg.source), content_seg_len);
|
||||
content.append(TextEncoder::FromUnicode(utf8, ToCharacterSet(ECI(content_seg.eci))));
|
||||
#ifndef ZXING_READERS
|
||||
content.utf8Cache.push_back(std::move(utf8));
|
||||
#endif
|
||||
} else {
|
||||
content.append({content_seg.source, content_seg_len});
|
||||
#ifndef ZXING_READERS
|
||||
content.utf8Cache.push_back(BinaryToUtf8(content.bytes));
|
||||
#endif
|
||||
}
|
||||
|
||||
content.symbology = SymbologyIdentifierZint2ZXing(opts, content.bytes);
|
||||
|
||||
DecoderResult decRes(std::move(content));
|
||||
decRes.setEcLevel(ECLevelZint2ZXing(zint));
|
||||
decRes.setReaderInit(zint->output_options & READER_INIT);
|
||||
auto bits = BitMatrix(zint->bitmap_width, zint->bitmap_height);
|
||||
std::transform(zint->bitmap, zint->bitmap + zint->bitmap_width * zint->bitmap_height, bits.row(0).begin(),
|
||||
[](unsigned char v) { return (v == '1') * BitMatrix::SET_V; });
|
||||
int left, top, width, height;
|
||||
bits.findBoundingBox(left, top, width, height);
|
||||
|
||||
auto res = MatrixBarcode(std::move(decRes), {std::move(bits), Rectangle<PointI>(left, top, width, height)}, opts.format());
|
||||
#endif
|
||||
|
||||
res.zint = std::move(opts.d->zint);
|
||||
res.zintMutex = std::make_unique<std::mutex>();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& options)
|
||||
{
|
||||
return CreateBarcode(contents.data(), contents.size(), UNICODE_MODE, options);
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& options)
|
||||
{
|
||||
return CreateBarcode(contents.data(), contents.size(), UNICODE_MODE, options);
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& options)
|
||||
{
|
||||
return CreateBarcode(data, size, DATA_MODE, options);
|
||||
}
|
||||
|
||||
#else // ZXING_USE_ZINT
|
||||
|
||||
zint_symbol* CreatorOptions::zint() const { return nullptr; }
|
||||
|
||||
static Barcode CreateBarcode(BitMatrix&& bits, std::string_view contents, const CreatorOptions& opts)
|
||||
{
|
||||
Content content;
|
||||
content.append(contents);
|
||||
|
||||
DecoderResult decRes(std::move(content));
|
||||
DetectorResult detRes(std::move(bits), Rectangle<PointI>(0, 0, bits.width(), bits.height()));
|
||||
return MatrixBarcode(std::move(decRes), std::move(detRes), opts.format());
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& opts)
|
||||
{
|
||||
auto writer = MultiFormatWriter(opts.format()).setMargin(0);
|
||||
if (auto ecLevel = opts.ecLevel(); ecLevel && ecLevel->size() == 1 && strchr("012345678", (*ecLevel)[0]))
|
||||
writer.setEccLevel(std::stoi(*ecLevel));
|
||||
if (!IsAscii({(const uint8_t*)contents.data(), contents.size()}))
|
||||
writer.setEncoding(CharacterSet::UTF8); // write UTF8 (ECI value 26) for maximum compatibility
|
||||
|
||||
return CreateBarcode(writer.encode(std::string(contents), 0, opts.format() & BarcodeFormat::AllLinear ? 50 : 0), contents, opts);
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& opts)
|
||||
{
|
||||
return CreateBarcodeFromText({reinterpret_cast<const char*>(contents.data()), contents.size()}, opts);
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& opts)
|
||||
{
|
||||
std::wstring bytes;
|
||||
for (uint8_t c : ByteView(data, size))
|
||||
bytes.push_back(c);
|
||||
|
||||
auto writer = MultiFormatWriter(opts.format()).setMargin(0);
|
||||
if (auto ecLevel = opts.ecLevel(); ecLevel && ecLevel->size() == 1 && strchr("012345678", (*ecLevel)[0]))
|
||||
writer.setEccLevel(std::stoi(*ecLevel));
|
||||
writer.setEncoding(CharacterSet::BINARY);
|
||||
|
||||
return CreateBarcode(writer.encode(bytes, 0, opts.format() & BarcodeFormat::AllLinear ? 50 : 0), {(const char*)data, (size_t)size}, opts);
|
||||
}
|
||||
|
||||
#endif // ZXING_USE_ZINT
|
||||
|
||||
#else // ZXING_WRITERS
|
||||
|
||||
zint_symbol* CreatorOptions::zint() const { return nullptr; }
|
||||
|
||||
Barcode CreateBarcodeFromText(std::string_view, const CreatorOptions&)
|
||||
{
|
||||
throw std::runtime_error("This build of zxing-cpp does not support creating barcodes.");
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromText(std::u8string_view, const CreatorOptions&)
|
||||
{
|
||||
throw std::runtime_error("This build of zxing-cpp does not support creating barcodes.");
|
||||
}
|
||||
|
||||
Barcode CreateBarcodeFromBytes(const void*, int, const CreatorOptions&)
|
||||
{
|
||||
throw std::runtime_error("This build of zxing-cpp does not support creating barcodes.");
|
||||
}
|
||||
|
||||
#endif // ZXING_WRITERS
|
||||
|
||||
} // namespace ZXing
|
||||
Reference in new issue
Block a user