comparison mupdf-source/thirdparty/zxing-cpp/core/src/HRI.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
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * Copyright 2016 Nu-book Inc.
3 * Copyright 2016 ZXing authors
4 * Copyright 2022 Axel Waggershauser
5 */
6 // SPDX-License-Identifier: Apache-2.0
7
8 #include "HRI.h"
9
10 #include "ZXAlgorithms.h"
11
12 #include <cmath>
13 #include <cstring>
14 #include <string_view>
15
16 namespace ZXing {
17
18 struct AiInfo
19 {
20 const char aiPrefix[5];
21 int8_t _fieldSize; // if negative, the length is variable and abs(length) give the max size
22
23 bool isVariableLength() const noexcept { return _fieldSize < 0; }
24 int fieldSize() const noexcept { return std::abs(_fieldSize); }
25 int aiSize() const
26 {
27 using namespace std::literals;
28 if ((aiPrefix[0] == '3' && Contains("1234569", aiPrefix[1])) || aiPrefix == "703"sv || aiPrefix == "723"sv)
29 return 4;
30 else
31 return strlen(aiPrefix);
32 }
33 };
34
35 // https://github.com/gs1/gs1-syntax-dictionary 2024-06-10
36 static const AiInfo aiInfos[] = {
37 //TWO_DIGIT_DATA_LENGTH
38 { "00", 18 },
39 { "01", 14 },
40 { "02", 14 },
41
42 { "10", -20 },
43 { "11", 6 },
44 { "12", 6 },
45 { "13", 6 },
46 { "15", 6 },
47 { "16", 6 },
48 { "17", 6 },
49
50 { "20", 2 },
51 { "21", -20 },
52 { "22", -20 },
53
54 { "30", -8 },
55 { "37", -8 },
56
57 { "90", -30 },
58 { "91", -90 },
59 { "92", -90 },
60 { "93", -90 },
61 { "94", -90 },
62 { "95", -90 },
63 { "96", -90 },
64 { "97", -90 },
65 { "98", -90 },
66 { "99", -90 },
67
68 //THREE_DIGIT_DATA_LENGTH
69 { "235", -28 },
70 { "240", -30 },
71 { "241", -30 },
72 { "242", -6 },
73 { "243", -20 },
74 { "250", -30 },
75 { "251", -30 },
76 { "253", -30 },
77 { "254", -20 },
78 { "255", -25 },
79
80 { "400", -30 },
81 { "401", -30 },
82 { "402", 17 },
83 { "403", -30 },
84 { "410", 13 },
85 { "411", 13 },
86 { "412", 13 },
87 { "413", 13 },
88 { "414", 13 },
89 { "415", 13 },
90 { "416", 13 },
91 { "417", 13 },
92 { "420", -20 },
93 { "421", -12 },
94 { "422", 3 },
95 { "423", -15 },
96 { "424", 3 },
97 { "425", -15 },
98 { "426", 3 },
99 { "427", -3 },
100
101 { "710", -20 },
102 { "711", -20 },
103 { "712", -20 },
104 { "713", -20 },
105 { "714", -20 },
106 { "715", -20 },
107
108 //THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH
109 { "310", 6 },
110 { "311", 6 },
111 { "312", 6 },
112 { "313", 6 },
113 { "314", 6 },
114 { "315", 6 },
115 { "316", 6 },
116 { "320", 6 },
117 { "321", 6 },
118 { "322", 6 },
119 { "323", 6 },
120 { "324", 6 },
121 { "325", 6 },
122 { "326", 6 },
123 { "327", 6 },
124 { "328", 6 },
125 { "329", 6 },
126 { "330", 6 },
127 { "331", 6 },
128 { "332", 6 },
129 { "333", 6 },
130 { "334", 6 },
131 { "335", 6 },
132 { "336", 6 },
133 { "337", 6 },
134 { "340", 6 },
135 { "341", 6 },
136 { "342", 6 },
137 { "343", 6 },
138 { "344", 6 },
139 { "345", 6 },
140 { "346", 6 },
141 { "347", 6 },
142 { "348", 6 },
143 { "349", 6 },
144 { "350", 6 },
145 { "351", 6 },
146 { "352", 6 },
147 { "353", 6 },
148 { "354", 6 },
149 { "355", 6 },
150 { "356", 6 },
151 { "357", 6 },
152 { "360", 6 },
153 { "361", 6 },
154 { "362", 6 },
155 { "363", 6 },
156 { "364", 6 },
157 { "365", 6 },
158 { "366", 6 },
159 { "367", 6 },
160 { "368", 6 },
161 { "369", 6 },
162 { "390", -15 },
163 { "391", -18 },
164 { "392", -15 },
165 { "393", -18 },
166 { "394", 4 },
167 { "395", 6 },
168 { "703", -30 },
169 { "723", -30 },
170
171 //FOUR_DIGIT_DATA_LENGTH
172 { "4300", -35 },
173 { "4301", -35 },
174 { "4302", -70 },
175 { "4303", -70 },
176 { "4304", -70 },
177 { "4305", -70 },
178 { "4306", -70 },
179 { "4307", 2 },
180 { "4308", -30 },
181 { "4309", 20 },
182 { "4310", -35 },
183 { "4311", -35 },
184 { "4312", -70 },
185 { "4313", -70 },
186 { "4314", -70 },
187 { "4315", -70 },
188 { "4316", -70 },
189 { "4317", 2 },
190 { "4318", -20 },
191 { "4319", -30 },
192 { "4320", -35 },
193 { "4321", 1 },
194 { "4322", 1 },
195 { "4323", 1 },
196 { "4324", 10 },
197 { "4325", 10 },
198 { "4326", 6 },
199 { "4330", -7 },
200 { "4331", -7 },
201 { "4332", -7 },
202 { "4333", -7 },
203
204 { "7001", 13 },
205 { "7002", -30 },
206 { "7003", 10 },
207 { "7004", -4 },
208 { "7005", -12 },
209 { "7006", 6 },
210 { "7007", -12 },
211 { "7008", -3 },
212 { "7009", -10 },
213 { "7010", -2 },
214 { "7011", -10 },
215 { "7020", -20 },
216 { "7021", -20 },
217 { "7022", -20 },
218 { "7023", -30 },
219 { "7040", 4 },
220 { "7240", -20 },
221 { "7241", 2 },
222 { "7242", -25 },
223 { "7250", 8 },
224 { "7251", 12 },
225 { "7252", 1 },
226 { "7253", -40 },
227 { "7254", -40 },
228 { "7255", -10 },
229 { "7256", -90 },
230 { "7257", -70 },
231 { "7258", 3 },
232 { "7259", -40 },
233
234 { "8001", 14 },
235 { "8002", -20 },
236 { "8003", -30 },
237 { "8004", -30 },
238 { "8005", 6 },
239 { "8006", 18 },
240 { "8007", -34 },
241 { "8008", -12 },
242 { "8009", -50 },
243 { "8010", -30 },
244 { "8011", -12 },
245 { "8012", -20 },
246 { "8013", -25 },
247 { "8017", 18 },
248 { "8018", 18 },
249 { "8019", -10 },
250 { "8020", -25 },
251 { "8026", 18 },
252 { "8030", -90 },
253 { "8110", -70 },
254 { "8111", 4 },
255 { "8112", -70 },
256 { "8200", -70 },
257 };
258
259 std::string HRIFromGS1(std::string_view gs1)
260 {
261 //TODO: c++20
262 auto starts_with = [](std::string_view str, std::string_view pre) { return str.substr(0, pre.size()) == pre; };
263 constexpr char GS = 29; // GS character (29 / 0x1D)
264
265 std::string_view rem = gs1;
266 std::string res;
267
268 while (rem.size()) {
269 const AiInfo* i = FindIf(aiInfos, [&](const AiInfo& i) { return starts_with(rem, i.aiPrefix); });
270 if (i == std::end(aiInfos))
271 return {};
272
273 int aiSize = i->aiSize();
274 if (Size(rem) < aiSize)
275 return {};
276
277 res += '(';
278 res += rem.substr(0, aiSize);
279 res += ')';
280 rem.remove_prefix(aiSize);
281
282 int fieldSize = i->fieldSize();
283 if (i->isVariableLength()) {
284 auto gsPos = rem.find(GS);
285 #if 1
286 fieldSize = std::min(gsPos == std::string_view::npos ? Size(rem) : narrow_cast<int>(gsPos), fieldSize);
287 #else
288 // TODO: ignore the 'max field size' part for now as it breaks rssexpanded-3/13.png?
289 fieldSize = gsPos == std::string_view::npos ? Size(rem) : narrow_cast<int>(gsPos);
290 #endif
291 }
292 if (fieldSize == 0 || Size(rem) < fieldSize)
293 return {};
294
295 res += rem.substr(0, fieldSize);
296 rem.remove_prefix(fieldSize);
297
298 // See General Specification v22.0 Section 7.8.6.3: "...the processing routine SHALL tolerate a single separator character
299 // immediately following any element string, whether necessary or not..."
300 if (Size(rem) && rem.front() == GS)
301 rem.remove_prefix(1);
302 }
303
304 return res;
305 }
306
307 std::string HRIFromISO15434(std::string_view str)
308 {
309 // Use available unicode symbols to simulate sub- and superscript letters as specified in
310 // ISO/IEC 15434:2019(E) 6. Human readable representation
311
312 std::string res;
313 res.reserve(str.size());
314
315 for (char c : str) {
316 #if 1
317 if (0 <= c && c <= 0x20)
318 (res += "\xe2\x90") += char(0x80 + c); // Unicode Block “Control Pictures”: 0x2400
319 else
320 res += c;
321 #else
322 switch (c) {
323 case 4: oss << u8"\u1d31\u1d52\u209c"; break; // EOT
324 case 28: oss << u8"\ua7f3\u209b"; break; // FS
325 case 29: oss << u8"\u1d33\u209b"; break; // GS
326 case 30: oss << u8"\u1d3f\u209b"; break; // RS
327 case 31: oss << u8"\u1d41\u209b"; break; // US
328 default: oss << c;
329 }
330 #endif
331 }
332
333 return res;
334 }
335
336 } // namespace ZXing