Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/leptonica/src/bbuffer.c @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | b50eed0cc0ef |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/leptonica/src/bbuffer.c Mon Sep 15 11:44:09 2025 +0200 @@ -0,0 +1,469 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/*! + * \file bbuffer.c + * <pre> + * + * Create/Destroy BBuffer + * L_BBUFFER *bbufferCreate() + * void *bbufferDestroy() + * l_uint8 *bbufferDestroyAndSaveData() + * + * Operations to read data TO a BBuffer + * l_int32 bbufferRead() + * l_int32 bbufferReadStream() + * l_int32 bbufferExtendArray() + * + * Operations to write data FROM a BBuffer + * l_int32 bbufferWrite() + * l_int32 bbufferWriteStream() + * + * The bbuffer is an implementation of a byte queue. + * The bbuffer holds a byte array from which bytes are + * processed in a first-in/first-out fashion. As with + * any queue, bbuffer maintains two "pointers," one to the + * tail of the queue (where you read new bytes onto it) + * and one to the head of the queue (where you start from + * when writing bytes out of it. + * + * The queue can be visualized: + * + * \code + * byte 0 byte (nalloc - 1) + * | | + * -------------------------------------------------- + * H T + * [ aw ][ bytes currently on queue ][ anr ] + * + * ---: all allocated data in bbuffer + * H: queue head (ptr to next byte to be written out) + * T: queue tail (ptr to first byte to be written to) + * aw: already written from queue + * anr: allocated but not yet read to + * \endcode + * The purpose of bbuffer is to allow you to safely read + * bytes in, and to sequentially write them out as well. + * In the process of writing bytes out, you don't actually + * remove the bytes in the array; you just move the pointer + * (nwritten) which points to the head of the queue. In + * the process of reading bytes in, you sometimes need to + * expand the array size. If a read is performed after a + * write, so that the head of the queue is not at the + * beginning of the array, the bytes already written are + * first removed by copying the others over them; then the + * new bytes are read onto the tail of the queue. + * + * Note that the meaning of "read into" and "write from" + * the bbuffer is OPPOSITE to that for a stream, where + * you read "from" a stream and write "into" a stream. + * As a mnemonic for remembering the direction: + * ~ to read bytes from a stream into the bbuffer, + * you call fread on the stream + * ~ to write bytes from the bbuffer into a stream, + * you call fwrite on the stream + * + * See zlibmem.c for an example use of bbuffer, where we + * compress and decompress an array of bytes in memory. + * + * We can also use the bbuffer trivially to read from stdin + * into memory; e.g., to capture bytes piped from the stdout + * of another program. This is equivalent to repeatedly + * calling bbufferReadStream() until the input queue is empty. + * This is implemented in l_binaryReadStream(). + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include "allheaders.h" + + /* Bounds on array size */ +static const l_uint32 MaxArraySize = 1000000000; /* 10^9 bytes */ +static const l_int32 InitialArraySize = 1024; /*!< n'importe quoi */ + +/*--------------------------------------------------------------------------* + * BBuffer create/destroy * + *--------------------------------------------------------------------------*/ +/*! + * \brief bbufferCreate() + * + * \param[in] indata address in memory [optional] + * \param[in] nalloc size of byte array to be alloc'd 0 for default + * \return bbuffer, or NULL on error + * + * <pre> + * Notes: + * (1) If a buffer address is given, you should read all the data in. + * (2) Allocates a bbuffer with associated byte array of + * the given size. If a buffer address is given, + * it then reads the number of bytes into the byte array. + * </pre> + */ +L_BBUFFER * +bbufferCreate(const l_uint8 *indata, + l_int32 nalloc) +{ +L_BBUFFER *bb; + + if (nalloc <= 0 || nalloc > MaxArraySize) + nalloc = InitialArraySize; + + bb = (L_BBUFFER *)LEPT_CALLOC(1, sizeof(L_BBUFFER)); + if ((bb->array = (l_uint8 *)LEPT_CALLOC(nalloc, sizeof(l_uint8))) == NULL) { + LEPT_FREE(bb); + return (L_BBUFFER *)ERROR_PTR("byte array not made", __func__, NULL); + } + bb->nalloc = nalloc; + bb->nwritten = 0; + + if (indata) { + memcpy(bb->array, indata, nalloc); + bb->n = nalloc; + } else { + bb->n = 0; + } + + return bb; +} + + +/*! + * \brief bbufferDestroy() + * + * \param[in,out] pbb will be set to null before returning + * \return void + * + * <pre> + * Notes: + * (1) Destroys the byte array in the bbuffer and then the bbuffer; + * then nulls the contents of the input ptr. + * </pre> + */ +void +bbufferDestroy(L_BBUFFER **pbb) +{ +L_BBUFFER *bb; + + if (pbb == NULL) { + L_WARNING("ptr address is NULL\n", __func__); + return; + } + + if ((bb = *pbb) == NULL) + return; + + if (bb->array) + LEPT_FREE(bb->array); + LEPT_FREE(bb); + *pbb = NULL; +} + + +/*! + * \brief bbufferDestroyAndSaveData() + * + * \param[in,out] pbb input data buffer; will be nulled + * \param[out] pnbytes number of bytes saved in array + * \return barray newly allocated array of data + * + * <pre> + * Notes: + * (1) Copies data to newly allocated array; then destroys the bbuffer. + * </pre> + */ +l_uint8 * +bbufferDestroyAndSaveData(L_BBUFFER **pbb, + size_t *pnbytes) +{ +l_uint8 *array; +size_t nbytes; +L_BBUFFER *bb; + + if (pbb == NULL) { + L_WARNING("ptr address is NULL\n", __func__); + return NULL; + } + if (pnbytes == NULL) { + L_WARNING("&nbytes is NULL\n", __func__); + bbufferDestroy(pbb); + return NULL; + } + + if ((bb = *pbb) == NULL) + return NULL; + + /* write all unwritten bytes out to a new array */ + nbytes = bb->n - bb->nwritten; + *pnbytes = nbytes; + if ((array = (l_uint8 *)LEPT_CALLOC(nbytes, sizeof(l_uint8))) == NULL) { + L_WARNING("calloc failure for array\n", __func__); + return NULL; + } + memcpy(array, bb->array + bb->nwritten, nbytes); + + bbufferDestroy(pbb); + return array; +} + + +/*--------------------------------------------------------------------------* + * Operations to read data INTO a BBuffer * + *--------------------------------------------------------------------------*/ +/*! + * \brief bbufferRead() + * + * \param[in] bb bbuffer + * \param[in] src source memory buffer from which bytes are read + * \param[in] nbytes bytes to be read + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) For a read after write, first remove the written + * bytes by shifting the unwritten bytes in the array, + * then check if there is enough room to add the new bytes. + * If not, realloc with bbufferExpandArray(), resulting + * in a second writing of the unwritten bytes. While less + * efficient, this is simpler than making a special case + * of reallocNew(). + * </pre> + */ +l_ok +bbufferRead(L_BBUFFER *bb, + l_uint8 *src, + l_int32 nbytes) +{ +l_int32 navail, nadd, nwritten; + + if (!bb) + return ERROR_INT("bb not defined", __func__, 1); + if (!src) + return ERROR_INT("src not defined", __func__, 1); + if (nbytes == 0) + return ERROR_INT("no bytes to read", __func__, 1); + + if ((nwritten = bb->nwritten)) { /* move the unwritten bytes over */ + memmove(bb->array, bb->array + nwritten, bb->n - nwritten); + bb->nwritten = 0; + bb->n -= nwritten; + } + + /* If necessary, expand the allocated array. Do so by + * by at least a factor of two. */ + navail = bb->nalloc - bb->n; + if (nbytes > navail) { + nadd = L_MAX(bb->nalloc, nbytes); + if (bbufferExtendArray(bb, nadd)) + return ERROR_INT("extension failed", __func__, 1); + } + + /* Read in the new bytes */ + memcpy(bb->array + bb->n, src, nbytes); + bb->n += nbytes; + return 0; +} + + +/*! + * \brief bbufferReadStream() + * + * \param[in] bb bbuffer + * \param[in] fp source stream from which bytes are read + * \param[in] nbytes bytes to be read + * \return 0 if OK, 1 on error + */ +l_ok +bbufferReadStream(L_BBUFFER *bb, + FILE *fp, + l_int32 nbytes) +{ +l_int32 navail, nadd, nread, nwritten; + + if (!bb) + return ERROR_INT("bb not defined", __func__, 1); + if (!fp) + return ERROR_INT("fp not defined", __func__, 1); + if (nbytes == 0) + return ERROR_INT("no bytes to read", __func__, 1); + + if ((nwritten = bb->nwritten)) { /* move any unwritten bytes over */ + memmove(bb->array, bb->array + nwritten, bb->n - nwritten); + bb->nwritten = 0; + bb->n -= nwritten; + } + + /* If necessary, expand the allocated array. Do so by + * by at least a factor of two. */ + navail = bb->nalloc - bb->n; + if (nbytes > navail) { + nadd = L_MAX(bb->nalloc, nbytes); + if (bbufferExtendArray(bb, nadd)) + return ERROR_INT("extension failed", __func__, 1); + } + + /* Read in the new bytes */ + nread = fread(bb->array + bb->n, 1, nbytes, fp); + bb->n += nread; + + return 0; +} + + +/*! + * \brief bbufferExtendArray() + * + * \param[in] bb bbuffer + * \param[in] nbytes number of bytes to extend array size + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) reallocNew() copies all bb->nalloc bytes, even though + * only bb->n are data. + * </pre> + */ +l_ok +bbufferExtendArray(L_BBUFFER *bb, + l_int32 nbytes) +{ + if (!bb) + return ERROR_INT("bb not defined", __func__, 1); + + if ((bb->array = (l_uint8 *)reallocNew((void **)&bb->array, + bb->nalloc, + bb->nalloc + nbytes)) == NULL) + return ERROR_INT("new ptr array not returned", __func__, 1); + + bb->nalloc += nbytes; + return 0; +} + + +/*--------------------------------------------------------------------------* + * Operations to write data FROM a BBuffer * + *--------------------------------------------------------------------------*/ +/*! + * \brief bbufferWrite() + * + * \param[in] bb bbuffer + * \param[in] dest dest memory buffer to which bytes are written + * \param[in] nbytes bytes requested to be written + * \param[out] pnout bytes actually written + * \return 0 if OK, 1 on error + */ +l_ok +bbufferWrite(L_BBUFFER *bb, + l_uint8 *dest, + size_t nbytes, + size_t *pnout) +{ +size_t nleft, nout; + + if (!bb) + return ERROR_INT("bb not defined", __func__, 1); + if (!dest) + return ERROR_INT("dest not defined", __func__, 1); + if (nbytes <= 0) + return ERROR_INT("no bytes requested to write", __func__, 1); + if (!pnout) + return ERROR_INT("&nout not defined", __func__, 1); + + nleft = bb->n - bb->nwritten; + nout = L_MIN(nleft, nbytes); + *pnout = nout; + + if (nleft == 0) { /* nothing to write; reinitialize the buffer */ + bb->n = 0; + bb->nwritten = 0; + return 0; + } + + /* nout > 0; transfer the data out */ + memcpy(dest, bb->array + bb->nwritten, nout); + bb->nwritten += nout; + + /* If all written; "empty" the buffer */ + if (nout == nleft) { + bb->n = 0; + bb->nwritten = 0; + } + + return 0; +} + + +/*! + * \brief bbufferWriteStream() + * + * \param[in] bb bbuffer + * \param[in] fp dest stream to which bytes are written + * \param[in] nbytes bytes requested to be written + * \param[out] pnout bytes actually written + * \return 0 if OK, 1 on error + */ +l_ok +bbufferWriteStream(L_BBUFFER *bb, + FILE *fp, + size_t nbytes, + size_t *pnout) +{ +size_t nleft, nout; + + if (!bb) + return ERROR_INT("bb not defined", __func__, 1); + if (!fp) + return ERROR_INT("output stream not defined", __func__, 1); + if (nbytes <= 0) + return ERROR_INT("no bytes requested to write", __func__, 1); + if (!pnout) + return ERROR_INT("&nout not defined", __func__, 1); + + nleft = bb->n - bb->nwritten; + nout = L_MIN(nleft, nbytes); + *pnout = nout; + + if (nleft == 0) { /* nothing to write; reinitialize the buffer */ + bb->n = 0; + bb->nwritten = 0; + return 0; + } + + /* nout > 0; transfer the data out */ + fwrite(bb->array + bb->nwritten, 1, nout, fp); + bb->nwritten += nout; + + /* If all written; "empty" the buffer */ + if (nout == nleft) { + bb->n = 0; + bb->nwritten = 0; + } + + return 0; +}
