diff mupdf-source/thirdparty/zxing-cpp/core/src/GTIN.cpp @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/zxing-cpp/core/src/GTIN.cpp	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,253 @@
+/*
+* Copyright 2016 Nu-book Inc.
+* Copyright 2016 ZXing authors
+*/
+// SPDX-License-Identifier: Apache-2.0
+
+#include "GTIN.h"
+
+#include "Barcode.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+#include <string>
+
+namespace ZXing::GTIN {
+
+struct CountryId
+{
+	uint16_t first;
+	uint16_t last;
+	const char id[3];
+};
+
+bool operator<(const CountryId& lhs, const CountryId& rhs)
+{
+	return lhs.last < rhs.last;
+}
+
+// https://www.gs1.org/standards/id-keys/company-prefix (as of 7 Feb 2022)
+// and https://en.wikipedia.org/wiki/List_of_GS1_country_codes
+static const CountryId COUNTRIES[] = {
+	// clang-format off
+	{1, 19, "US"},
+	{30, 39, "US"},
+	{60, 99, "US"}, // Note 99 coupon identification
+	{100, 139, "US"},
+	{300, 379, "FR"}, // France (and Monaco according to Wikipedia)
+	{380, 380, "BG"}, // Bulgaria
+	{383, 383, "SI"}, // Slovenia
+	{385, 385, "HR"}, // Croatia
+	{387, 387, "BA"}, // Bosnia and Herzegovina
+	{389, 389, "ME"}, // Montenegro
+	//{390, 390, "XK"}, // (Kosovo according to Wikipedia, unsourced)
+	{400, 440, "DE"}, // Germany
+	{450, 459, "JP"}, // Japan
+	{460, 469, "RU"}, // Russia
+	{470, 470, "KG"}, // Kyrgyzstan
+	{471, 471, "TW"}, // Taiwan
+	{474, 474, "EE"}, // Estonia
+	{475, 475, "LV"}, // Latvia
+	{476, 476, "AZ"}, // Azerbaijan
+	{477, 477, "LT"}, // Lithuania
+	{478, 478, "UZ"}, // Uzbekistan
+	{479, 479, "LK"}, // Sri Lanka
+	{480, 480, "PH"}, // Philippines
+	{481, 481, "BY"}, // Belarus
+	{482, 482, "UA"}, // Ukraine
+	{483, 483, "TM"}, // Turkmenistan
+	{484, 484, "MD"}, // Moldova
+	{485, 485, "AM"}, // Armenia
+	{486, 486, "GE"}, // Georgia
+	{487, 487, "KZ"}, // Kazakhstan
+	{488, 488, "TJ"}, // Tajikistan
+	{489, 489, "HK"}, // Hong Kong
+	{490, 499, "JP"}, // Japan
+	{500, 509, "GB"}, // UK
+	{520, 521, "GR"}, // Greece
+	{528, 528, "LB"}, // Lebanon
+	{529, 529, "CY"}, // Cyprus
+	{530, 530, "AL"}, // Albania
+	{531, 531, "MK"}, // North Macedonia
+	{535, 535, "MT"}, // Malta
+	{539, 539, "IE"}, // Ireland
+	{540, 549, "BE"}, // Belgium & Luxembourg
+	{560, 560, "PT"}, // Portugal
+	{569, 569, "IS"}, // Iceland
+	{570, 579, "DK"}, // Denmark (and Faroe Islands and Greenland according to Wikipedia)
+	{590, 590, "PL"}, // Poland
+	{594, 594, "RO"}, // Romania
+	{599, 599, "HU"}, // Hungary
+	{600, 601, "ZA"}, // South Africa
+	{603, 603, "GH"}, // Ghana
+	{604, 604, "SN"}, // Senegal
+	{608, 608, "BH"}, // Bahrain
+	{609, 609, "MU"}, // Mauritius
+	{611, 611, "MA"}, // Morocco
+	{613, 613, "DZ"}, // Algeria
+	{615, 615, "NG"}, // Nigeria
+	{616, 616, "KE"}, // Kenya
+	{617, 617, "CM"}, // Cameroon
+	{618, 618, "CI"}, // Côte d'Ivoire
+	{619, 619, "TN"}, // Tunisia
+	{620, 620, "TZ"}, // Tanzania
+	{621, 621, "SY"}, // Syria
+	{622, 622, "EG"}, // Egypt
+	{623, 623, "BN"}, // Brunei
+	{624, 624, "LY"}, // Libya
+	{625, 625, "JO"}, // Jordan
+	{626, 626, "IR"}, // Iran
+	{627, 627, "KW"}, // Kuwait
+	{628, 628, "SA"}, // Saudi Arabia
+	{629, 629, "AE"}, // United Arab Emirates
+	{630, 630, "QA"}, // Qatar
+	{631, 631, "NA"}, // Namibia
+	{640, 649, "FI"}, // Finland
+	{690, 699, "CN"}, // China
+	{700, 709, "NO"}, // Norway
+	{729, 729, "IL"}, // Israel
+	{730, 739, "SE"}, // Sweden
+	{740, 740, "GT"}, // Guatemala
+	{741, 741, "SV"}, // El Salvador
+	{742, 742, "HN"}, // Honduras
+	{743, 743, "NI"}, // Nicaragua
+	{744, 744, "CR"}, // Costa Rica
+	{745, 745, "PA"}, // Panama
+	{746, 746, "DO"}, // Dominican Republic
+	{750, 750, "MX"}, // Mexico
+	{754, 755, "CA"}, // Canada
+	{759, 759, "VE"}, // Venezuela
+	{760, 769, "CH"}, // Switzerland (and Liechtenstein according to Wikipedia)
+	{770, 771, "CO"}, // Colombia
+	{773, 773, "UY"}, // Uruguay
+	{775, 775, "PE"}, // Peru
+	{777, 777, "BO"}, // Bolivia
+	{778, 779, "AR"}, // Argentina
+	{780, 780, "CL"}, // Chile
+	{784, 784, "PY"}, // Paraguay
+	{786, 786, "EC"}, // Ecuador
+	{789, 790, "BR"}, // Brazil
+	{800, 839, "IT"}, // Italy (and San Marino and Vatican City according to Wikipedia)
+	{840, 849, "ES"}, // Spain (and Andorra according to Wikipedia)
+	{850, 850, "CU"}, // Cuba
+	{858, 858, "SK"}, // Slovakia
+	{859, 859, "CZ"}, // Czechia
+	{860, 860, "RS"}, // Serbia
+	{865, 865, "MN"}, // Mongolia
+	{867, 867, "KP"}, // North Korea
+	{868, 869, "TR"}, // Turkey
+	{870, 879, "NL"}, // Netherlands
+	{880, 880, "KR"}, // South Korea
+	{883, 883, "MM"}, // Myanmar
+	{884, 884, "KH"}, // Cambodia
+	{885, 885, "TH"}, // Thailand
+	{888, 888, "SG"}, // Singapore
+	{890, 890, "IN"}, // India
+	{893, 893, "VN"}, // Vietnam
+	{896, 896, "PK"}, // Pakistan
+	{899, 899, "ID"}, // Indonesia
+	{900, 919, "AT"}, // Austria
+	{930, 939, "AU"}, // Australia
+	{940, 949, "NZ"}, // New Zealand
+	{955, 955, "MY"}, // Malaysia
+	{958, 958, "MO"}, // Macao
+	//{960, 961, "GB"}, // Global Office - assigned to GS1 UK for GTIN-8 allocations (also 9620-9624999)
+	// clang-format on
+};
+
+std::string LookupCountryIdentifier(const std::string& GTIN, const BarcodeFormat format)
+{
+	// Ignore add-on if any
+	const auto space = GTIN.find(' ');
+	const std::string::size_type size = space != std::string::npos ? space : GTIN.size();
+
+	if (size != 14 && size != 13 && size != 12 && size != 8)
+		return {};
+
+	// GTIN-14 leading packaging level indicator
+	const int first = size == 14 ? 1 : 0;
+	// UPC-A/E implicit leading 0
+	const int implicitZero = size == 12 || (size == 8 && format != BarcodeFormat::EAN8) ? 1 : 0;
+
+	if (size != 8 || format != BarcodeFormat::EAN8) { // Assuming following doesn't apply to EAN-8
+		// 0000000 Restricted Circulation Numbers; 0000001-0000099 unused to avoid collision with GTIN-8
+		int prefix = std::stoi(GTIN.substr(first, 7 - implicitZero));
+		if (prefix >= 0 && prefix <= 99)
+			return {};
+
+		// 00001-00009 US
+		prefix = std::stoi(GTIN.substr(first, 5 - implicitZero));
+		if (prefix >= 1 && prefix <= 9)
+			return "US";
+
+		// 0001-0009 US
+		prefix = std::stoi(GTIN.substr(first, 4 - implicitZero));
+		if (prefix >= 1 && prefix <= 9)
+			return "US";
+	}
+
+	const int prefix = std::stoi(GTIN.substr(first, 3 - implicitZero));
+
+	// Special case EAN-8 for prefix < 100 (GS1 General Specifications Figure 1.4.3-1)
+	if (size == 8 && format == BarcodeFormat::EAN8 && prefix <= 99) // Restricted Circulation Numbers
+		return {};
+
+	const auto it = std::lower_bound(std::begin(COUNTRIES), std::end(COUNTRIES), CountryId{0, narrow_cast<uint16_t>(prefix), ""});
+
+	return it != std::end(COUNTRIES) && prefix >= it->first && prefix <= it->last ? it->id : std::string();
+}
+
+std::string EanAddOn(const Barcode& barcode)
+{
+	if (!(BarcodeFormat::EAN13 | BarcodeFormat::UPCA | BarcodeFormat::UPCE | BarcodeFormat::EAN8).testFlag(barcode.format()))
+		return {};
+	auto txt = barcode.bytes().asString();
+	auto pos = txt.find(' ');
+	return pos != std::string::npos ? std::string(txt.substr(pos + 1)) : std::string();
+}
+
+std::string IssueNr(const std::string& ean2AddOn)
+{
+	if (ean2AddOn.size() != 2)
+		return {};
+
+	return std::to_string(std::stoi(ean2AddOn));
+}
+
+std::string Price(const std::string& ean5AddOn)
+{
+	if (ean5AddOn.size() != 5)
+		return {};
+
+	std::string currency;
+	switch (ean5AddOn.front()) {
+	case '0': [[fallthrough]];
+	case '1': currency = "GBP £"; break; // UK
+	case '3': currency = "AUD $"; break; // AUS
+	case '4': currency = "NZD $"; break; // NZ
+	case '5': currency = "USD $"; break; // US
+	case '6': currency = "CAD $"; break; // CA
+	case '9':
+		// Reference: http://www.jollytech.com
+		if (ean5AddOn == "90000") // No suggested retail price
+			return {};
+		if (ean5AddOn == "99991") // Complementary
+			return "0.00";
+		if (ean5AddOn == "99990")
+			return "Used";
+
+		// Otherwise... unknown currency?
+		currency = "";
+		break;
+	default: currency = ""; break;
+	}
+
+	int rawAmount = std::stoi(ean5AddOn.substr(1));
+	std::stringstream buf;
+	buf << currency << std::fixed << std::setprecision(2) << (float(rawAmount) / 100);
+	return buf.str();
+}
+
+} // namespace ZXing::GTIN