Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
