Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zint/backend/filemem.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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zint/backend/filemem.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,464 @@ +/* filemem.c - write to file/memory abstraction */ +/* + libzint - the open source barcode library + Copyright (C) 2023-2024 Robin Stuart <rstuart114@gmail.com> + + 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. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + 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 THE COPYRIGHT OWNER OR 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#ifdef _MSC_VER +#include <io.h> +#include <fcntl.h> +#endif + +#include "filemem.h" +#include "output.h" + +#define FM_PAGE_SIZE 0x8000 /* 32k */ + +#ifndef EOVERFLOW +#define EOVERFLOW EINVAL +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 /* `va_copy()` not before MSVC 2013 (C++ 12.0) */ +# define va_copy(dest, src) (dest = src) +#else +# if defined(ZINT_IS_C89) && !defined(va_copy) +# ifdef __GNUC__ +# define va_copy __va_copy /* Available with clang as well */ +# else +# define va_copy(dest, src) (dest = src) /* Will fail if array (need `*dest = *src`) or something else */ +# endif +# endif +#endif + +/* Helper to set `err` only if not already set, returning 0 always for convenience */ +static int fm_seterr(struct filemem *restrict const fmp, const int err) { + if (fmp->err == 0) { + fmp->err = err; + } + return 0; +} + +/* Helper to set position, syncing end marker */ +static void fm_setpos(struct filemem *restrict const fmp, const size_t pos) { + assert(pos <= fmp->memsize); + fmp->mempos = pos; + if (fmp->mempos > fmp->memend) { + fmp->memend = fmp->mempos; + } +} + +/* Helper to clear memory buffer and associates */ +static void fm_clear_mem(struct filemem *restrict const fmp) { + if (fmp->mem) { + free(fmp->mem); + fmp->mem = NULL; + } + fmp->memsize = fmp->mempos = fmp->memend = 0; +#ifdef FM_NO_VSNPRINTF + if (fmp->fp_null) { + (void) fclose(fmp->fp_null); + fmp->fp_null = NULL; + } +#endif +} + +/* `fopen()` if file, setup memory buffer if BARCODE_MEMORY_FILE, returning 1 on success, 0 on failure */ +INTERNAL int fm_open(struct filemem *restrict const fmp, struct zint_symbol *symbol, const char *mode) { + assert(fmp && symbol && mode); + fmp->fp = NULL; + fmp->mem = NULL; + fmp->memsize = fmp->mempos = fmp->memend = 0; + fmp->flags = symbol->output_options & (BARCODE_STDOUT | BARCODE_MEMORY_FILE); + fmp->err = 0; +#ifdef FM_NO_VSNPRINTF + fmp->fp_null = NULL; +#endif + + if (fmp->flags & BARCODE_MEMORY_FILE) { + if (!(fmp->mem = (unsigned char *) malloc(FM_PAGE_SIZE))) { + return fm_seterr(fmp, ENOMEM); + } + fmp->memsize = FM_PAGE_SIZE; + if (symbol->memfile) { + free(symbol->memfile); + symbol->memfile = NULL; + } + symbol->memfile_size = 0; + return 1; + } + if (fmp->flags & BARCODE_STDOUT) { +#ifdef _MSC_VER + if (strchr(mode, 'b') != NULL && _setmode(_fileno(stdout), _O_BINARY) == -1) { + return fm_seterr(fmp, errno); + } +#endif + fmp->fp = stdout; + return 1; + } + if (!(fmp->fp = out_fopen(symbol->outfile, mode))) { + return fm_seterr(fmp, errno); + } + return 1; +} + +/* Expand memory buffer, returning 1 on success, 0 on failure */ +static int fm_mem_expand(struct filemem *restrict const fmp, const size_t size) { + unsigned char *new_mem; + size_t new_size; + + assert(fmp); + if (!fmp->mem) { + return fm_seterr(fmp, EINVAL); + } + if (size == 0) { + return 1; + } + if (fmp->mempos + size < fmp->memsize) { /* Fits? */ + if (fmp->mempos + size <= fmp->mempos) { /* Check for overflow */ + fm_clear_mem(fmp); + return fm_seterr(fmp, EOVERFLOW); + } + return 1; + } + new_size = fmp->memsize + (size < FM_PAGE_SIZE ? FM_PAGE_SIZE : size); + if (new_size <= fmp->memsize) { /* Check for overflow */ + fm_clear_mem(fmp); + return fm_seterr(fmp, EOVERFLOW); + } + /* Protect against very large files & (Linux) OOM killer - cf `raster_malloc()` in "raster.c" */ + if (new_size > 0x40000000 /*1GB*/ || !(new_mem = (unsigned char *) realloc(fmp->mem, new_size))) { + fm_clear_mem(fmp); + return fm_seterr(fmp, new_size > 0x40000000 ? EINVAL : ENOMEM); + } + fmp->mem = new_mem; + fmp->memsize = new_size; + return 1; +} + +/* `fwrite()` to file or memory, returning 1 on success, 0 on failure */ +INTERNAL int fm_write(const void *restrict ptr, const size_t size, const size_t nitems, + struct filemem *restrict const fmp) { + assert(fmp && ptr); + if (fmp->err) { + return 0; + } + if (size == 0 || nitems == 0) { + return 1; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + const size_t tot_size = size * nitems; + if (tot_size / size != nitems) { + return fm_seterr(fmp, EOVERFLOW); + } + if (!fm_mem_expand(fmp, tot_size)) { + return 0; + } + memcpy(fmp->mem + fmp->mempos, ptr, tot_size); + fm_setpos(fmp, fmp->mempos + tot_size); + return 1; + } + if (fwrite(ptr, size, nitems, fmp->fp) != nitems) { + return fm_seterr(fmp, errno); + } + return 1; +} + +/* `fputc()` to file or memory, returning 1 on success, 0 on failure */ +INTERNAL int fm_putc(const int ch, struct filemem *restrict const fmp) { + assert(fmp); + if (fmp->err) { + return 0; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + if (!fm_mem_expand(fmp, 1)) { + return 0; + } + fmp->mem[fmp->mempos] = (unsigned char) ch; + fm_setpos(fmp, fmp->mempos + 1); + return 1; + } + if (fputc(ch, fmp->fp) == EOF) { + return fm_seterr(fmp, errno); + } + return 1; +} + +/* `fputs()` to file or memory, returning 1 on success, 0 on failure */ +INTERNAL int fm_puts(const char *str, struct filemem *restrict const fmp) { + assert(fmp); + if (fmp->err) { + return 0; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + const size_t len = strlen(str); + if (!fm_mem_expand(fmp, len)) { + return 0; + } + memcpy(fmp->mem + fmp->mempos, str, len); + fm_setpos(fmp, fmp->mempos + len); + return 1; + } + if (fputs(str, fmp->fp) == EOF) { + return fm_seterr(fmp, errno); + } + return 1; +} + +#ifdef FM_NO_VSNPRINTF +# ifdef _WIN32 +# define DEV_NULL "NUL" +# else +# define DEV_NULL "/dev/null" +# endif +#endif + +/* Helper to `printf()` into mem buffer */ +static int fm_vprintf(struct filemem *restrict const fmp, const char *fmt, va_list ap) { + va_list cpy; + int size, check; + + /* Adapted from https://stackoverflow.com/a/52558247/664741 */ +#ifdef FM_NO_VSNPRINTF + if (!fmp->fp_null && !(fmp->fp_null = fopen(DEV_NULL, "wb"))) { + return fm_seterr(fmp, errno); + } +#endif + + va_copy(cpy, ap); + /* The clang-tidy warning is a bug https://github.com/llvm/llvm-project/issues/40656 */ +#ifdef FM_NO_VSNPRINTF + size = vfprintf(fmp->fp_null, fmt, cpy); /* NOLINT(clang-analyzer-valist.Uninitialized) */ +#else + size = vsnprintf(NULL, 0, fmt, cpy); /* NOLINT(clang-analyzer-valist.Uninitialized) */ +#endif + va_end(cpy); + + if (size < 0) { + return fm_seterr(fmp, errno); + } + + if (!fm_mem_expand(fmp, size + 1)) { + return 0; + } + +#ifdef FM_NO_VSNPRINTF + /* NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized) - see above */ + check = vsprintf((char *) fmp->mem + fmp->mempos, fmt, ap); +#else + /* NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized) - see above */ + check = vsnprintf((char *) fmp->mem + fmp->mempos, size + 1, fmt, ap); +#endif + + (void)check; + assert(check == size); + + fm_setpos(fmp, fmp->mempos + size); + + return 1; +} + +/* `fprintf()` to file or memory, returning 1 on success, 0 on failure */ +INTERNAL int fm_printf(struct filemem *restrict const fmp, const char *fmt, ...) { + va_list ap; + int ret; + + assert(fmp && fmt); + if (fmp->err) { + return 0; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + va_start(ap, fmt); + ret = fm_vprintf(fmp, fmt, ap); + va_end(ap); + return ret; + } + va_start(ap, fmt); + ret = vfprintf(fmp->fp, fmt, ap) >= 0; /* NOLINT(clang-analyzer-valist.Uninitialized) - see above */ + va_end(ap); + return ret ? 1 : fm_seterr(fmp, errno); +} + +/* Output float without trailing zeroes to `fmp` with decimal pts `dp` (precision), returning 1 on success, 0 on + failure */ +INTERNAL int fm_putsf(const char *prefix, const int dp, const float arg, struct filemem *restrict const fmp) { + int i, end; + char buf[256]; /* Assuming `dp` reasonable */ + const int len = sprintf(buf, "%.*f", dp, arg); + + assert(fmp); + if (fmp->err) { + return 0; + } + if (prefix && *prefix) { + if (!fm_puts(prefix, fmp)) { + return 0; + } + } + + /* Adapted from https://stackoverflow.com/a/36202854/664741 */ + for (i = len - 1, end = len; i >= 0; i--) { + if (buf[i] == '0') { + if (end == i + 1) { + end = i; + } + } else if (!z_isdigit(buf[i]) && buf[i] != '-') { /* If not digit or minus then decimal point */ + if (end == i + 1) { + end = i; + } else { + buf[i] = '.'; /* Overwrite any locale-specific setting for decimal point */ + } + buf[end] = '\0'; + break; + } + } + + return fm_puts(buf, fmp); +} + +/* `fclose()` if file, set `symbol->memfile` & `symbol->memfile_size` if memory, returning 1 on success, 0 on + failure */ +INTERNAL int fm_close(struct filemem *restrict const fmp, struct zint_symbol *symbol) { + assert(fmp && symbol); + if (fmp->flags & BARCODE_MEMORY_FILE) { + if (fmp->err || !fmp->mem) { + fm_clear_mem(fmp); + return fm_seterr(fmp, EINVAL); + } + symbol->memfile_size = (int) fmp->mempos; + if ((size_t) symbol->memfile_size != fmp->mempos) { + fm_clear_mem(fmp); + symbol->memfile_size = 0; + return fm_seterr(fmp, EINVAL); + } + symbol->memfile = fmp->mem; + fmp->mem = NULL; /* Now belongs to `symbol` */ + fm_clear_mem(fmp); + return 1; + } + if (fmp->err || !fmp->fp) { + if (!(fmp->flags & BARCODE_STDOUT) && fmp->fp) { + (void) fclose(fmp->fp); + } + return fm_seterr(fmp, EINVAL); + } + if (fmp->flags & BARCODE_STDOUT) { + if (fflush(fmp->fp) != 0) { + fmp->fp = NULL; + return fm_seterr(fmp, errno); + } + } else { + if (fclose(fmp->fp) != 0) { + fmp->fp = NULL; + return fm_seterr(fmp, errno); + } + } + fmp->fp = NULL; + return 1; +} + +/* `fseek()` to file/memory offset, returning 1 if successful, 0 on failure */ +INTERNAL int fm_seek(struct filemem *restrict const fmp, const long offset, const int whence) { + assert(fmp); + if (fmp->err) { + return 0; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + const size_t start = whence == SEEK_SET ? 0 : whence == SEEK_CUR ? fmp->mempos : fmp->memend; + const size_t new_pos = start + offset; + if ((offset > 0 && new_pos <= start) || (offset < 0 && new_pos >= start)) { /* Check for over/underflow */ + return fm_seterr(fmp, EINVAL); + } + if (!fm_mem_expand(fmp, new_pos)) { + return 0; + } + fm_setpos(fmp, new_pos); + return 1; + } + if (fseek(fmp->fp, offset, whence) != 0) { + return fm_seterr(fmp, errno); + } + return 1; +} + +/* `ftell()` returns current file/memory offset if successful, -1 on failure */ +INTERNAL long fm_tell(struct filemem *restrict const fmp) { + long ret; + assert(fmp); + if (fmp->err) { + return -1; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + if (!fmp->mem) { + (void) fm_seterr(fmp, ENOMEM); + return -1; + } + return (long) fmp->mempos; + } + ret = ftell(fmp->fp); + /* On many Linux distros `ftell()` returns LONG_MAX not -1 on error */ + if (ret < 0 || ret == LONG_MAX) { + (void) fm_seterr(fmp, errno); + return -1; + } + return ret; +} + +/* Return `err`, which uses `errno` values; if file and `err` not set, test `ferror()` also */ +INTERNAL int fm_error(struct filemem *restrict const fmp) { + assert(fmp); + if (fmp->err == 0 && !(fmp->flags & BARCODE_MEMORY_FILE) && ferror(fmp->fp)) { + (void) fm_seterr(fmp, EIO); + } + return fmp->err; +} + +/* `fflush()` if file, no-op (apart from error checking) if memory, returning 1 on success, 0 on failure + NOTE: don't use, included only for libpng compatibility */ +INTERNAL int fm_flush(struct filemem *restrict const fmp) { + assert(fmp); + if (fmp->err) { + return 0; + } + if (fmp->flags & BARCODE_MEMORY_FILE) { + if (!fmp->mem) { + return fm_seterr(fmp, EINVAL); + } + return 1; + } + if (fflush(fmp->fp) == EOF) { + return fm_seterr(fmp, errno); + } + return 1; +} + +/* vim: set ts=4 sw=4 et : */
