comparison mupdf-source/thirdparty/leptonica/src/bbuffer.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 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file bbuffer.c
29 * <pre>
30 *
31 * Create/Destroy BBuffer
32 * L_BBUFFER *bbufferCreate()
33 * void *bbufferDestroy()
34 * l_uint8 *bbufferDestroyAndSaveData()
35 *
36 * Operations to read data TO a BBuffer
37 * l_int32 bbufferRead()
38 * l_int32 bbufferReadStream()
39 * l_int32 bbufferExtendArray()
40 *
41 * Operations to write data FROM a BBuffer
42 * l_int32 bbufferWrite()
43 * l_int32 bbufferWriteStream()
44 *
45 * The bbuffer is an implementation of a byte queue.
46 * The bbuffer holds a byte array from which bytes are
47 * processed in a first-in/first-out fashion. As with
48 * any queue, bbuffer maintains two "pointers," one to the
49 * tail of the queue (where you read new bytes onto it)
50 * and one to the head of the queue (where you start from
51 * when writing bytes out of it.
52 *
53 * The queue can be visualized:
54 *
55 * \code
56 * byte 0 byte (nalloc - 1)
57 * | |
58 * --------------------------------------------------
59 * H T
60 * [ aw ][ bytes currently on queue ][ anr ]
61 *
62 * ---: all allocated data in bbuffer
63 * H: queue head (ptr to next byte to be written out)
64 * T: queue tail (ptr to first byte to be written to)
65 * aw: already written from queue
66 * anr: allocated but not yet read to
67 * \endcode
68 * The purpose of bbuffer is to allow you to safely read
69 * bytes in, and to sequentially write them out as well.
70 * In the process of writing bytes out, you don't actually
71 * remove the bytes in the array; you just move the pointer
72 * (nwritten) which points to the head of the queue. In
73 * the process of reading bytes in, you sometimes need to
74 * expand the array size. If a read is performed after a
75 * write, so that the head of the queue is not at the
76 * beginning of the array, the bytes already written are
77 * first removed by copying the others over them; then the
78 * new bytes are read onto the tail of the queue.
79 *
80 * Note that the meaning of "read into" and "write from"
81 * the bbuffer is OPPOSITE to that for a stream, where
82 * you read "from" a stream and write "into" a stream.
83 * As a mnemonic for remembering the direction:
84 * ~ to read bytes from a stream into the bbuffer,
85 * you call fread on the stream
86 * ~ to write bytes from the bbuffer into a stream,
87 * you call fwrite on the stream
88 *
89 * See zlibmem.c for an example use of bbuffer, where we
90 * compress and decompress an array of bytes in memory.
91 *
92 * We can also use the bbuffer trivially to read from stdin
93 * into memory; e.g., to capture bytes piped from the stdout
94 * of another program. This is equivalent to repeatedly
95 * calling bbufferReadStream() until the input queue is empty.
96 * This is implemented in l_binaryReadStream().
97 * </pre>
98 */
99
100 #ifdef HAVE_CONFIG_H
101 #include <config_auto.h>
102 #endif /* HAVE_CONFIG_H */
103
104 #include <string.h>
105 #include "allheaders.h"
106
107 /* Bounds on array size */
108 static const l_uint32 MaxArraySize = 1000000000; /* 10^9 bytes */
109 static const l_int32 InitialArraySize = 1024; /*!< n'importe quoi */
110
111 /*--------------------------------------------------------------------------*
112 * BBuffer create/destroy *
113 *--------------------------------------------------------------------------*/
114 /*!
115 * \brief bbufferCreate()
116 *
117 * \param[in] indata address in memory [optional]
118 * \param[in] nalloc size of byte array to be alloc'd 0 for default
119 * \return bbuffer, or NULL on error
120 *
121 * <pre>
122 * Notes:
123 * (1) If a buffer address is given, you should read all the data in.
124 * (2) Allocates a bbuffer with associated byte array of
125 * the given size. If a buffer address is given,
126 * it then reads the number of bytes into the byte array.
127 * </pre>
128 */
129 L_BBUFFER *
130 bbufferCreate(const l_uint8 *indata,
131 l_int32 nalloc)
132 {
133 L_BBUFFER *bb;
134
135 if (nalloc <= 0 || nalloc > MaxArraySize)
136 nalloc = InitialArraySize;
137
138 bb = (L_BBUFFER *)LEPT_CALLOC(1, sizeof(L_BBUFFER));
139 if ((bb->array = (l_uint8 *)LEPT_CALLOC(nalloc, sizeof(l_uint8))) == NULL) {
140 LEPT_FREE(bb);
141 return (L_BBUFFER *)ERROR_PTR("byte array not made", __func__, NULL);
142 }
143 bb->nalloc = nalloc;
144 bb->nwritten = 0;
145
146 if (indata) {
147 memcpy(bb->array, indata, nalloc);
148 bb->n = nalloc;
149 } else {
150 bb->n = 0;
151 }
152
153 return bb;
154 }
155
156
157 /*!
158 * \brief bbufferDestroy()
159 *
160 * \param[in,out] pbb will be set to null before returning
161 * \return void
162 *
163 * <pre>
164 * Notes:
165 * (1) Destroys the byte array in the bbuffer and then the bbuffer;
166 * then nulls the contents of the input ptr.
167 * </pre>
168 */
169 void
170 bbufferDestroy(L_BBUFFER **pbb)
171 {
172 L_BBUFFER *bb;
173
174 if (pbb == NULL) {
175 L_WARNING("ptr address is NULL\n", __func__);
176 return;
177 }
178
179 if ((bb = *pbb) == NULL)
180 return;
181
182 if (bb->array)
183 LEPT_FREE(bb->array);
184 LEPT_FREE(bb);
185 *pbb = NULL;
186 }
187
188
189 /*!
190 * \brief bbufferDestroyAndSaveData()
191 *
192 * \param[in,out] pbb input data buffer; will be nulled
193 * \param[out] pnbytes number of bytes saved in array
194 * \return barray newly allocated array of data
195 *
196 * <pre>
197 * Notes:
198 * (1) Copies data to newly allocated array; then destroys the bbuffer.
199 * </pre>
200 */
201 l_uint8 *
202 bbufferDestroyAndSaveData(L_BBUFFER **pbb,
203 size_t *pnbytes)
204 {
205 l_uint8 *array;
206 size_t nbytes;
207 L_BBUFFER *bb;
208
209 if (pbb == NULL) {
210 L_WARNING("ptr address is NULL\n", __func__);
211 return NULL;
212 }
213 if (pnbytes == NULL) {
214 L_WARNING("&nbytes is NULL\n", __func__);
215 bbufferDestroy(pbb);
216 return NULL;
217 }
218
219 if ((bb = *pbb) == NULL)
220 return NULL;
221
222 /* write all unwritten bytes out to a new array */
223 nbytes = bb->n - bb->nwritten;
224 *pnbytes = nbytes;
225 if ((array = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
226 L_WARNING("calloc failure for array\n", __func__);
227 return NULL;
228 }
229 memcpy(array, bb->array + bb->nwritten, nbytes);
230
231 bbufferDestroy(pbb);
232 return array;
233 }
234
235
236 /*--------------------------------------------------------------------------*
237 * Operations to read data INTO a BBuffer *
238 *--------------------------------------------------------------------------*/
239 /*!
240 * \brief bbufferRead()
241 *
242 * \param[in] bb bbuffer
243 * \param[in] src source memory buffer from which bytes are read
244 * \param[in] nbytes bytes to be read
245 * \return 0 if OK, 1 on error
246 *
247 * <pre>
248 * Notes:
249 * (1) For a read after write, first remove the written
250 * bytes by shifting the unwritten bytes in the array,
251 * then check if there is enough room to add the new bytes.
252 * If not, realloc with bbufferExpandArray(), resulting
253 * in a second writing of the unwritten bytes. While less
254 * efficient, this is simpler than making a special case
255 * of reallocNew().
256 * </pre>
257 */
258 l_ok
259 bbufferRead(L_BBUFFER *bb,
260 l_uint8 *src,
261 l_int32 nbytes)
262 {
263 l_int32 navail, nadd, nwritten;
264
265 if (!bb)
266 return ERROR_INT("bb not defined", __func__, 1);
267 if (!src)
268 return ERROR_INT("src not defined", __func__, 1);
269 if (nbytes == 0)
270 return ERROR_INT("no bytes to read", __func__, 1);
271
272 if ((nwritten = bb->nwritten)) { /* move the unwritten bytes over */
273 memmove(bb->array, bb->array + nwritten, bb->n - nwritten);
274 bb->nwritten = 0;
275 bb->n -= nwritten;
276 }
277
278 /* If necessary, expand the allocated array. Do so by
279 * by at least a factor of two. */
280 navail = bb->nalloc - bb->n;
281 if (nbytes > navail) {
282 nadd = L_MAX(bb->nalloc, nbytes);
283 if (bbufferExtendArray(bb, nadd))
284 return ERROR_INT("extension failed", __func__, 1);
285 }
286
287 /* Read in the new bytes */
288 memcpy(bb->array + bb->n, src, nbytes);
289 bb->n += nbytes;
290 return 0;
291 }
292
293
294 /*!
295 * \brief bbufferReadStream()
296 *
297 * \param[in] bb bbuffer
298 * \param[in] fp source stream from which bytes are read
299 * \param[in] nbytes bytes to be read
300 * \return 0 if OK, 1 on error
301 */
302 l_ok
303 bbufferReadStream(L_BBUFFER *bb,
304 FILE *fp,
305 l_int32 nbytes)
306 {
307 l_int32 navail, nadd, nread, nwritten;
308
309 if (!bb)
310 return ERROR_INT("bb not defined", __func__, 1);
311 if (!fp)
312 return ERROR_INT("fp not defined", __func__, 1);
313 if (nbytes == 0)
314 return ERROR_INT("no bytes to read", __func__, 1);
315
316 if ((nwritten = bb->nwritten)) { /* move any unwritten bytes over */
317 memmove(bb->array, bb->array + nwritten, bb->n - nwritten);
318 bb->nwritten = 0;
319 bb->n -= nwritten;
320 }
321
322 /* If necessary, expand the allocated array. Do so by
323 * by at least a factor of two. */
324 navail = bb->nalloc - bb->n;
325 if (nbytes > navail) {
326 nadd = L_MAX(bb->nalloc, nbytes);
327 if (bbufferExtendArray(bb, nadd))
328 return ERROR_INT("extension failed", __func__, 1);
329 }
330
331 /* Read in the new bytes */
332 nread = fread(bb->array + bb->n, 1, nbytes, fp);
333 bb->n += nread;
334
335 return 0;
336 }
337
338
339 /*!
340 * \brief bbufferExtendArray()
341 *
342 * \param[in] bb bbuffer
343 * \param[in] nbytes number of bytes to extend array size
344 * \return 0 if OK, 1 on error
345 *
346 * <pre>
347 * Notes:
348 * (1) reallocNew() copies all bb->nalloc bytes, even though
349 * only bb->n are data.
350 * </pre>
351 */
352 l_ok
353 bbufferExtendArray(L_BBUFFER *bb,
354 l_int32 nbytes)
355 {
356 if (!bb)
357 return ERROR_INT("bb not defined", __func__, 1);
358
359 if ((bb->array = (l_uint8 *)reallocNew((void **)&bb->array,
360 bb->nalloc,
361 bb->nalloc + nbytes)) == NULL)
362 return ERROR_INT("new ptr array not returned", __func__, 1);
363
364 bb->nalloc += nbytes;
365 return 0;
366 }
367
368
369 /*--------------------------------------------------------------------------*
370 * Operations to write data FROM a BBuffer *
371 *--------------------------------------------------------------------------*/
372 /*!
373 * \brief bbufferWrite()
374 *
375 * \param[in] bb bbuffer
376 * \param[in] dest dest memory buffer to which bytes are written
377 * \param[in] nbytes bytes requested to be written
378 * \param[out] pnout bytes actually written
379 * \return 0 if OK, 1 on error
380 */
381 l_ok
382 bbufferWrite(L_BBUFFER *bb,
383 l_uint8 *dest,
384 size_t nbytes,
385 size_t *pnout)
386 {
387 size_t nleft, nout;
388
389 if (!bb)
390 return ERROR_INT("bb not defined", __func__, 1);
391 if (!dest)
392 return ERROR_INT("dest not defined", __func__, 1);
393 if (nbytes <= 0)
394 return ERROR_INT("no bytes requested to write", __func__, 1);
395 if (!pnout)
396 return ERROR_INT("&nout not defined", __func__, 1);
397
398 nleft = bb->n - bb->nwritten;
399 nout = L_MIN(nleft, nbytes);
400 *pnout = nout;
401
402 if (nleft == 0) { /* nothing to write; reinitialize the buffer */
403 bb->n = 0;
404 bb->nwritten = 0;
405 return 0;
406 }
407
408 /* nout > 0; transfer the data out */
409 memcpy(dest, bb->array + bb->nwritten, nout);
410 bb->nwritten += nout;
411
412 /* If all written; "empty" the buffer */
413 if (nout == nleft) {
414 bb->n = 0;
415 bb->nwritten = 0;
416 }
417
418 return 0;
419 }
420
421
422 /*!
423 * \brief bbufferWriteStream()
424 *
425 * \param[in] bb bbuffer
426 * \param[in] fp dest stream to which bytes are written
427 * \param[in] nbytes bytes requested to be written
428 * \param[out] pnout bytes actually written
429 * \return 0 if OK, 1 on error
430 */
431 l_ok
432 bbufferWriteStream(L_BBUFFER *bb,
433 FILE *fp,
434 size_t nbytes,
435 size_t *pnout)
436 {
437 size_t nleft, nout;
438
439 if (!bb)
440 return ERROR_INT("bb not defined", __func__, 1);
441 if (!fp)
442 return ERROR_INT("output stream not defined", __func__, 1);
443 if (nbytes <= 0)
444 return ERROR_INT("no bytes requested to write", __func__, 1);
445 if (!pnout)
446 return ERROR_INT("&nout not defined", __func__, 1);
447
448 nleft = bb->n - bb->nwritten;
449 nout = L_MIN(nleft, nbytes);
450 *pnout = nout;
451
452 if (nleft == 0) { /* nothing to write; reinitialize the buffer */
453 bb->n = 0;
454 bb->nwritten = 0;
455 return 0;
456 }
457
458 /* nout > 0; transfer the data out */
459 fwrite(bb->array + bb->nwritten, 1, nout, fp);
460 bb->nwritten += nout;
461
462 /* If all written; "empty" the buffer */
463 if (nout == nleft) {
464 bb->n = 0;
465 bb->nwritten = 0;
466 }
467
468 return 0;
469 }