comparison mupdf-source/thirdparty/zint/backend/large.c @ 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 /* large.c - Handles binary manipulation of large numbers */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2008-2023 Robin Stuart <rstuart114@gmail.com>
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the project nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30 */
31 /* SPDX-License-Identifier: BSD-3-Clause */
32
33 /* `large_mul_u64()` and `large_div_u64()` are adapted from articles by F. W. Jacob
34 * https://www.codeproject.com/Tips/618570/UInt-Multiplication-Squaring
35 * "This article, along with any associated source code and files, is licensed under The BSD License"
36 * http://www.codeproject.com/Tips/785014/UInt-Division-Modulus
37 * "This article, along with any associated source code and files, is licensed under The BSD License"
38 *
39 * These in turn are based on Hacker's Delight (2nd Edition, 2012) by Henry S. Warren, Jr.
40 * "You are free to use, copy, and distribute any of the code on this web site, whether modified by you or not."
41 * https://web.archive.org/web/20190716204559/http://www.hackersdelight.org/permissions.htm
42 *
43 * `clz_u64()` and other bits and pieces are adapted from r128.h by Alan Hickman (fahickman)
44 * https://github.com/fahickman/r128/blob/master/r128.h
45 * "R128 is released into the public domain. See LICENSE for details." LICENSE is The Unlicense.
46 */
47 #include <assert.h>
48 #include <stdio.h>
49 #include "common.h"
50 #include "large.h"
51
52 #define MASK32 0xFFFFFFFF
53
54 /* Convert decimal string `s` of (at most) length `length` to 64-bit and place in 128-bit `t` */
55 INTERNAL void large_load_str_u64(large_uint *t, const unsigned char *s, const int length) {
56 uint64_t val = 0;
57 const unsigned char *const se = s + length;
58 for (; s < se && z_isdigit(*s); s++) {
59 val *= 10;
60 val += *s - '0';
61 }
62 t->lo = val;
63 t->hi = 0;
64 }
65
66 /* Add 128-bit `s` to 128-bit `t` */
67 INTERNAL void large_add(large_uint *t, const large_uint *s) {
68 t->lo += s->lo;
69 t->hi += s->hi + (t->lo < s->lo);
70 }
71
72 /* Add 64-bit `s` to 128-bit `t` */
73 INTERNAL void large_add_u64(large_uint *t, const uint64_t s) {
74 t->lo += s;
75 if (t->lo < s) {
76 t->hi++;
77 }
78 }
79
80 /* Subtract 64-bit `s` from 128-bit `t` */
81 INTERNAL void large_sub_u64(large_uint *t, const uint64_t s) {
82 uint64_t r = t->lo - s;
83 if (r > t->lo) {
84 t->hi--;
85 }
86 t->lo = r;
87 }
88
89 /* Multiply 128-bit `t` by 64-bit `s`
90 * See Jacob `mult64to128()` and Warren Section 8-2
91 * Note '0' denotes low 32-bits, '1' high 32-bits
92 * if p00 == s0 * tlo0
93 * k00 == carry of p00
94 * p01 == s0 * tlo1
95 * k01 == carry of (p01 + k00)
96 * p10 == s1 * tlo0
97 * k10 == carry of p10
98 * p11 == s1 * tlo1 (unmasked, i.e. including unshifted carry if any)
99 * then t->lo == (p01 + p10 + k00) << 32 + p00
100 * and t->hi == p11 + k10 + k01 + thi * s
101 *
102 * (thi) tlo1 tlo0
103 * x s1 s0
104 * -------------------------
105 * p00
106 * k01 p01 + k00
107 * p10
108 * p11 + k10
109 */
110 INTERNAL void large_mul_u64(large_uint *t, const uint64_t s) {
111 uint64_t thi = t->hi;
112 uint64_t tlo0 = t->lo & MASK32;
113 uint64_t tlo1 = t->lo >> 32;
114
115 uint64_t s0 = s & MASK32;
116 uint64_t s1 = s >> 32;
117
118 uint64_t tmp = s0 * tlo0; /* p00 (unmasked) */
119 uint64_t p00 = tmp & MASK32;
120 uint64_t k10;
121
122 tmp = (s1 * tlo0) + (tmp >> 32); /* (p10 + k00) (p10 unmasked) */
123 k10 = tmp >> 32;
124
125 tmp = (s0 * tlo1) + (tmp & MASK32); /* (p01 + p10 + k00) (p01 unmasked) */
126
127 t->lo = (tmp << 32) + p00; /* (p01 + p10 + k00) << 32 + p00 (note any carry from unmasked p01 shifted out) */
128 t->hi = (s1 * tlo1) + k10 + (tmp >> 32) + thi * s; /* p11 + k10 + k01 + thi * s */
129 }
130
131 /* Count leading zeroes. See Hickman `r128__clz64()` */
132 static int clz_u64(uint64_t x) {
133 uint64_t n = 64, y;
134 y = x >> 32; if (y) { n -= 32; x = y; }
135 y = x >> 16; if (y) { n -= 16; x = y; }
136 y = x >> 8; if (y) { n -= 8; x = y; }
137 y = x >> 4; if (y) { n -= 4; x = y; }
138 y = x >> 2; if (y) { n -= 2; x = y; }
139 y = x >> 1; if (y) { n -= 1; x = y; }
140 return (int) (n - x);
141 }
142
143 #ifdef ZINT_TEST /* Wrapper for direct testing */
144 INTERNAL int clz_u64_test(uint64_t x) {
145 return clz_u64(x);
146 }
147 #endif
148
149 /* Divide 128-bit dividend `t` by 64-bit divisor `v`, returning 64-bit remainder
150 * See Jacob `divmod128by128/64()` and Warren Section 9–2 (divmu64.c.txt)
151 * Note digits are 32-bit parts */
152 INTERNAL uint64_t large_div_u64(large_uint *t, uint64_t v) {
153 const uint64_t b = 0x100000000; /* Number base (2**32) */
154 uint64_t qhi = 0; /* High digit of returned quotient */
155
156 uint64_t tnhi, tnlo, tnlo1, tnlo0, vn1, vn0; /* Normalized forms of (parts of) t and v */
157 uint64_t rnhilo1; /* Remainder after dividing 1st 3 digits of t by v */
158 uint64_t qhat1, qhat0; /* Estimated quotient digits */
159 uint64_t rhat; /* Remainder of estimated quotient digit */
160 uint64_t tmp;
161 int norm_shift;
162
163 /* Deal with single-digit (i.e. 32-bit) divisor here */
164 if (v < b) {
165 qhi = t->hi / v;
166 tmp = ((t->hi - qhi * v) << 32) + (t->lo >> 32); /* k * b + tlo1 */
167 qhat1 = tmp / v;
168 tmp = ((tmp - qhat1 * v) << 32) + (t->lo & MASK32); /* k * b + tlo0 */
169 qhat0 = tmp / v;
170 t->lo = (qhat1 << 32) | qhat0;
171 t->hi = qhi;
172 return tmp - qhat0 * v;
173 }
174
175 /* Main algorithm requires t->hi < v */
176 if (t->hi >= v) {
177 qhi = t->hi / v;
178 t->hi %= v;
179 }
180
181 /* Normalize by shifting v left just enough so that its high-order
182 * bit is on, and shift t left the same amount. Note don't need extra
183 * high-end digit for dividend as t->hi < v */
184
185 norm_shift = clz_u64(v);
186 v <<= norm_shift;
187 vn1 = v >> 32;
188 vn0 = v & MASK32;
189
190 if (norm_shift > 0) {
191 tnhi = (t->hi << norm_shift) | (t->lo >> (64 - norm_shift));
192 tnlo = t->lo << norm_shift;
193 } else {
194 tnhi = t->hi;
195 tnlo = t->lo;
196 }
197
198 tnlo1 = tnlo >> 32;
199 tnlo0 = tnlo & MASK32;
200
201 /* Compute qhat1 estimate */
202
203 assert(vn1 != 0); /* Suppress clang-tidy-14 clang-analyzer-core.DivideZero */
204 qhat1 = tnhi / vn1; /* Divide first digit of v into first 2 digits of t */
205 rhat = tnhi % vn1;
206
207 /* Loop until qhat1 one digit and <= (rhat * b + 3rd digit of t) / vn0 */
208 for (tmp = qhat1 * vn0; qhat1 >= b || tmp > (rhat << 32) + tnlo1; tmp -= vn0) {
209 --qhat1;
210 rhat += vn1;
211 if (rhat >= b) { /* Must check here as (rhat << 32) would overflow */
212 break; /* qhat1 * vn0 < b * b (since vn0 < b) */
213 }
214 }
215 /* Note qhat1 will be exact as have fully divided by 2-digit divisor
216 * (can only be too high by 1 (and require "add back" step) if divisor at least 3 digits) */
217
218 /* Note high digit (if any) of both tnhi and (qhat1 * v) shifted out */
219 rnhilo1 = (tnhi << 32) + tnlo1 - (qhat1 * v);
220
221 /* Compute qhat0 estimate */
222
223 qhat0 = rnhilo1 / vn1; /* Divide first digit of v into 2-digit remains of first 3 digits of t */
224 rhat = rnhilo1 % vn1;
225
226 /* Loop until qhat0 one digit and <= (rhat * b + 4th digit of t) / vn0 */
227 for (tmp = qhat0 * vn0; qhat0 >= b || tmp > (rhat << 32) + tnlo0; tmp -= vn0) {
228 --qhat0;
229 rhat += vn1;
230 if (rhat >= b) {
231 break;
232 }
233 }
234 /* Similarly qhat0 will be exact */
235
236 t->lo = (qhat1 << 32) | qhat0;
237 t->hi = qhi;
238
239 /* Unnormalize remainder */
240 return ((rnhilo1 << 32) + tnlo0 - (qhat0 * v)) >> norm_shift;
241 }
242
243 /* Unset a bit (zero-based) */
244 INTERNAL void large_unset_bit(large_uint *t, const int bit) {
245 if (bit < 64) {
246 t->lo &= ~(((uint64_t) 1) << bit);
247 } else if (bit < 128) {
248 t->hi &= ~(((uint64_t) 1) << (bit - 64));
249 }
250 }
251
252 /* Output large_uint into an unsigned int array of size `size`, each element containing `bits` bits */
253 INTERNAL void large_uint_array(const large_uint *t, unsigned int *uint_array, const int size, int bits) {
254 int i, j;
255 uint64_t mask;
256 if (bits <= 0) {
257 bits = 8;
258 } else if (bits > 32) {
259 bits = 32;
260 }
261 mask = ~(((uint64_t) -1) << bits);
262 for (i = 0, j = 0; i < size && j < 64; i++, j += bits) {
263 uint_array[size - 1 - i] = (unsigned int) ((t->lo >> j) & mask); /* Little-endian order */
264 }
265 if (i < size) {
266 if (j != 64) {
267 j -= 64;
268 /* (first j bits of t->hi) << (bits - j) | (last (bits - j) bits of t->lo) */
269 uint_array[size - i] = (unsigned int) (((t->hi & ~((((uint64_t) -1) << j))) << (bits - j))
270 | (t->lo >> (64 - (bits - j)) & mask));
271 } else {
272 j = 0;
273 }
274 for (; i < size && j < 64; i++, j += bits) {
275 uint_array[size - 1 - i] = (unsigned int) ((t->hi >> j) & mask);
276 }
277 if (i < size) {
278 memset(uint_array, 0, sizeof(unsigned int) * (size - i));
279 }
280 }
281 }
282
283 /* As `large_uint_array()` above, except output to unsigned char array */
284 INTERNAL void large_uchar_array(const large_uint *t, unsigned char *uchar_array, const int size, int bits) {
285 int i;
286 unsigned int *uint_array = (unsigned int *) z_alloca(sizeof(unsigned int) * (size ? size : 1));
287
288 large_uint_array(t, uint_array, size, bits);
289
290 for (i = 0; i < size; i++) {
291 uchar_array[i] = (unsigned char) uint_array[i];
292 }
293 }
294
295 /* Format large_uint into buffer, which should be at least 35 chars in size */
296 INTERNAL char *large_dump(const large_uint *t, char *buf) {
297 unsigned int tlo1 = (unsigned int) (large_lo(t) >> 32);
298 unsigned int tlo0 = (unsigned int) (large_lo(t) & MASK32);
299 unsigned int thi1 = (unsigned int) (large_hi(t) >> 32);
300 unsigned int thi0 = (unsigned int) (large_hi(t) & MASK32);
301
302 if (thi1) {
303 sprintf(buf, "0x%X%08X%08X%08X", thi1, thi0, tlo1, tlo0);
304 } else if (thi0) {
305 sprintf(buf, "0x%X%08X%08X", thi0, tlo1, tlo0);
306 } else if (tlo1) {
307 sprintf(buf, "0x%X%08X", tlo1, tlo0);
308 } else {
309 sprintf(buf, "0x%X", tlo0);
310 }
311 return buf;
312 }
313
314 /* Output formatted large_uint to stdout */
315 INTERNAL void large_print(const large_uint *t) {
316 char buf[35]; /* 2 (0x) + 32 (hex) + 1 */
317
318 puts(large_dump(t, buf));
319 }
320
321 /* vim: set ts=4 sw=4 et : */