summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2021-03-30 10:59:39 +0200
committerThomas Deutschmann <whissi@gentoo.org>2021-04-01 00:04:14 +0200
commit5ff1d6955496b3cf9a35042c9ac35db43bc336b1 (patch)
tree6d470f7eb448f59f53e8df1010aec9dad8ce1f72 /leptonica/src/spixio.c
parentImport Ghostscript 9.53.1 (diff)
downloadghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.tar.gz
ghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.tar.bz2
ghostscript-gpl-patches-5ff1d6955496b3cf9a35042c9ac35db43bc336b1.zip
Import Ghostscript 9.54ghostscript-9.54
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'leptonica/src/spixio.c')
-rw-r--r--leptonica/src/spixio.c518
1 files changed, 518 insertions, 0 deletions
diff --git a/leptonica/src/spixio.c b/leptonica/src/spixio.c
new file mode 100644
index 00000000..229f4f46
--- /dev/null
+++ b/leptonica/src/spixio.c
@@ -0,0 +1,518 @@
+/*====================================================================*
+ - 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 spixio.c
+ * <pre>
+ *
+ * This does fast serialization of a pix in memory to file,
+ * copying the raw data for maximum speed. The underlying
+ * function serializes it to memory, and it is wrapped to be
+ * callable from standard pixRead() and pixWrite() file functions.
+ *
+ * Reading spix from file
+ * PIX *pixReadStreamSpix()
+ * l_int32 readHeaderSpix()
+ * l_int32 freadHeaderSpix()
+ * l_int32 sreadHeaderSpix()
+ *
+ * Writing spix to file
+ * l_int32 pixWriteStreamSpix()
+ *
+ * Low-level serialization of pix to/from memory (uncompressed)
+ * PIX *pixReadMemSpix()
+ * l_int32 pixWriteMemSpix()
+ * l_int32 pixSerializeToMemory()
+ * PIX *pixDeserializeFromMemory()
+ *
+ * Note: these functions have not been extensively tested for fuzzing
+ * (bad input data that can result in, e.g., memory faults).
+ * The spix serialization format is only defined here, in leptonica.
+ * The image data is uncompressed and the serialization is not intended
+ * to be a secure file format from untrusted sources.
+ * </pre>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config_auto.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include "allheaders.h"
+
+ /* Image dimension limits */
+static const l_int32 MaxAllowedWidth = 1000000;
+static const l_int32 MaxAllowedHeight = 1000000;
+static const l_int64 MaxAllowedArea = 400000000LL;
+
+#ifndef NO_CONSOLE_IO
+#define DEBUG_SERIALIZE 0
+#endif /* ~NO_CONSOLE_IO */
+
+
+/*-----------------------------------------------------------------------*
+ * Reading spix from file *
+ *-----------------------------------------------------------------------*/
+/*!
+ * \brief pixReadStreamSpix()
+ *
+ * \param[in] fp file stream
+ * \return pix, or NULL on error.
+ *
+ * <pre>
+ * Notes:
+ * (1) If called from pixReadStream(), the stream is positioned
+ * at the beginning of the file.
+ * </pre>
+ */
+PIX *
+pixReadStreamSpix(FILE *fp)
+{
+size_t nbytes;
+l_uint8 *data;
+PIX *pix;
+
+ PROCNAME("pixReadStreamSpix");
+
+ if (!fp)
+ return (PIX *)ERROR_PTR("stream not defined", procName, NULL);
+
+ if ((data = l_binaryReadStream(fp, &nbytes)) == NULL)
+ return (PIX *)ERROR_PTR("data not read", procName, NULL);
+ pix = pixReadMemSpix(data, nbytes);
+ LEPT_FREE(data);
+ if (!pix)
+ return (PIX *)ERROR_PTR("pix not made", procName, NULL);
+ return pix;
+}
+
+
+/*!
+ * \brief readHeaderSpix()
+ *
+ * \param[in] filename
+ * \param[out] pwidth width
+ * \param[out] pheight height
+ * \param[out] pbps bits/sample
+ * \param[out] pspp samples/pixel
+ * \param[out] piscmap [optional] input NULL to ignore
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) If there is a colormap, iscmap is returned as 1; else 0.
+ * </pre>
+ */
+l_ok
+readHeaderSpix(const char *filename,
+ l_int32 *pwidth,
+ l_int32 *pheight,
+ l_int32 *pbps,
+ l_int32 *pspp,
+ l_int32 *piscmap)
+{
+l_int32 ret;
+FILE *fp;
+
+ PROCNAME("readHeaderSpix");
+
+ if (!filename)
+ return ERROR_INT("filename not defined", procName, 1);
+ if (!pwidth || !pheight || !pbps || !pspp)
+ return ERROR_INT("input ptr(s) not defined", procName, 1);
+ if ((fp = fopenReadStream(filename)) == NULL)
+ return ERROR_INT("image file not found", procName, 1);
+ ret = freadHeaderSpix(fp, pwidth, pheight, pbps, pspp, piscmap);
+ fclose(fp);
+ return ret;
+}
+
+
+/*!
+ * \brief freadHeaderSpix()
+ *
+ * \param[in] fp file stream
+ * \param[out] pwidth width
+ * \param[out] pheight height
+ * \param[out] pbps bits/sample
+ * \param[out] pspp samples/pixel
+ * \param[out] piscmap [optional] input NULL to ignore
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) If there is a colormap, iscmap is returned as 1; else 0.
+ * </pre>
+ */
+l_ok
+freadHeaderSpix(FILE *fp,
+ l_int32 *pwidth,
+ l_int32 *pheight,
+ l_int32 *pbps,
+ l_int32 *pspp,
+ l_int32 *piscmap)
+{
+l_int32 nbytes, ret;
+l_uint32 data[6];
+
+ PROCNAME("freadHeaderSpix");
+
+ if (!fp)
+ return ERROR_INT("stream not defined", procName, 1);
+ if (!pwidth || !pheight || !pbps || !pspp)
+ return ERROR_INT("input ptr(s) not defined", procName, 1);
+
+ nbytes = fnbytesInFile(fp);
+ if (nbytes < 32)
+ return ERROR_INT("file too small to be spix", procName, 1);
+ if (fread(data, 4, 6, fp) != 6)
+ return ERROR_INT("error reading data", procName, 1);
+ ret = sreadHeaderSpix(data, nbytes, pwidth, pheight, pbps, pspp, piscmap);
+ return ret;
+}
+
+
+/*!
+ * \brief sreadHeaderSpix()
+ *
+ * \param[in] data
+ * \param[in] size of data
+ * \param[out] pwidth width
+ * \param[out] pheight height
+ * \param[out] pbps bits/sample
+ * \param[out] pspp samples/pixel
+ * \param[out] piscmap [optional] input NULL to ignore
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) If there is a colormap, iscmap is returned as 1; else 0.
+ * </pre>
+ */
+l_ok
+sreadHeaderSpix(const l_uint32 *data,
+ size_t size,
+ l_int32 *pwidth,
+ l_int32 *pheight,
+ l_int32 *pbps,
+ l_int32 *pspp,
+ l_int32 *piscmap)
+{
+char *id;
+l_int32 d, ncolors;
+
+ PROCNAME("sreadHeaderSpix");
+
+ if (!data)
+ return ERROR_INT("data not defined", procName, 1);
+ if (!pwidth || !pheight || !pbps || !pspp)
+ return ERROR_INT("input ptr(s) not defined", procName, 1);
+ *pwidth = *pheight = *pbps = *pspp = 0;
+ if (piscmap)
+ *piscmap = 0;
+ if (size < 28)
+ return ERROR_INT("size too small", procName, 1);
+
+ /* Check file id */
+ id = (char *)data;
+ if (id[0] != 's' || id[1] != 'p' || id[2] != 'i' || id[3] != 'x')
+ return ERROR_INT("not a valid spix file", procName, 1);
+
+ *pwidth = data[1];
+ *pheight = data[2];
+ d = data[3];
+ if (d <= 16) {
+ *pbps = d;
+ *pspp = 1;
+ } else {
+ *pbps = 8;
+ *pspp = d / 8; /* if the pix is 32 bpp, call it 4 samples */
+ }
+ ncolors = data[5];
+ if (piscmap)
+ *piscmap = (ncolors == 0) ? 0 : 1;
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------*
+ * Writing spix to file *
+ *-----------------------------------------------------------------------*/
+/*!
+ * \brief pixWriteStreamSpix()
+ *
+ * \param[in] fp file stream
+ * \param[in] pix
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+pixWriteStreamSpix(FILE *fp,
+ PIX *pix)
+{
+l_uint8 *data;
+size_t size;
+
+ PROCNAME("pixWriteStreamSpix");
+
+ if (!fp)
+ return ERROR_INT("stream not defined", procName, 1);
+ if (!pix)
+ return ERROR_INT("pix not defined", procName, 1);
+
+ if (pixWriteMemSpix(&data, &size, pix))
+ return ERROR_INT("failure to write pix to memory", procName, 1);
+ fwrite(data, 1, size, fp);
+ LEPT_FREE(data);
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------*
+ * Low-level serialization of pix to/from memory (uncompressed) *
+ *-----------------------------------------------------------------------*/
+/*!
+ * \brief pixReadMemSpix()
+ *
+ * \param[in] data const; uncompressed
+ * \param[in] size bytes of data
+ * \return pix, or NULL on error
+ */
+PIX *
+pixReadMemSpix(const l_uint8 *data,
+ size_t size)
+{
+ return pixDeserializeFromMemory((l_uint32 *)data, size);
+}
+
+
+/*!
+ * \brief pixWriteMemSpix()
+ *
+ * \param[out] pdata data of serialized, uncompressed pix
+ * \param[out] psize size of returned data
+ * \param[in] pix all depths; colormap OK
+ * \return 0 if OK, 1 on error
+ */
+l_ok
+pixWriteMemSpix(l_uint8 **pdata,
+ size_t *psize,
+ PIX *pix)
+{
+ return pixSerializeToMemory(pix, (l_uint32 **)pdata, psize);
+}
+
+
+/*!
+ * \brief pixSerializeToMemory()
+ *
+ * \param[in] pixs all depths, colormap OK
+ * \param[out] pdata serialized data in memory
+ * \param[out] pnbytes number of bytes in data string
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) This does a fast serialization of the principal elements
+ * of the pix, as follows:
+ * "spix" (4 bytes) -- ID for file type
+ * w (4 bytes)
+ * h (4 bytes)
+ * d (4 bytes)
+ * wpl (4 bytes)
+ * ncolors (4 bytes) -- in colormap; 0 if there is no colormap
+ * cdata (4 * ncolors) -- size of serialized colormap array
+ * rdatasize (4 bytes) -- size of serialized raster data
+ * = 4 * wpl * h
+ * rdata (rdatasize)
+ * </pre>
+ */
+l_ok
+pixSerializeToMemory(PIX *pixs,
+ l_uint32 **pdata,
+ size_t *pnbytes)
+{
+char *id;
+l_int32 w, h, d, wpl, rdatasize, ncolors, nbytes, index, valid;
+l_uint8 *cdata; /* data in colormap array (4 bytes/color table entry) */
+l_uint32 *data;
+l_uint32 *rdata; /* data in pix raster */
+PIXCMAP *cmap;
+
+ PROCNAME("pixSerializeToMemory");
+
+ if (!pdata || !pnbytes)
+ return ERROR_INT("&data and &nbytes not both defined", procName, 1);
+ *pdata = NULL;
+ *pnbytes = 0;
+ if (!pixs)
+ return ERROR_INT("pixs not defined", procName, 1);
+
+ pixGetDimensions(pixs, &w, &h, &d);
+ wpl = pixGetWpl(pixs);
+ rdata = pixGetData(pixs);
+ rdatasize = 4 * wpl * h;
+ ncolors = 0;
+ cdata = NULL;
+ if ((cmap = pixGetColormap(pixs)) != NULL) {
+ pixcmapIsValid(cmap, pixs, &valid);
+ if (!valid)
+ return ERROR_INT("colormap not valid", procName, 1);
+ pixcmapSerializeToMemory(cmap, 4, &ncolors, &cdata);
+ }
+
+ nbytes = 24 + 4 * ncolors + 4 + rdatasize;
+ if ((data = (l_uint32 *)LEPT_CALLOC(nbytes / 4, sizeof(l_uint32)))
+ == NULL) {
+ LEPT_FREE(cdata);
+ return ERROR_INT("data not made", procName, 1);
+ }
+ *pdata = data;
+ *pnbytes = nbytes;
+ id = (char *)data;
+ id[0] = 's';
+ id[1] = 'p';
+ id[2] = 'i';
+ id[3] = 'x';
+ data[1] = w;
+ data[2] = h;
+ data[3] = d;
+ data[4] = wpl;
+ data[5] = ncolors;
+ if (ncolors > 0)
+ memcpy(data + 6, cdata, 4 * ncolors);
+ index = 6 + ncolors;
+ data[index] = rdatasize;
+ memcpy(data + index + 1, rdata, rdatasize);
+
+#if DEBUG_SERIALIZE
+ lept_stderr("Serialize: "
+ "raster size = %d, ncolors in cmap = %d, total bytes = %d\n",
+ rdatasize, ncolors, nbytes);
+#endif /* DEBUG_SERIALIZE */
+
+ LEPT_FREE(cdata);
+ return 0;
+}
+
+
+/*!
+ * \brief pixDeserializeFromMemory()
+ *
+ * \param[in] data serialized data in memory
+ * \param[in] nbytes number of bytes in data string
+ * \return pix, or NULL on error
+ *
+ * <pre>
+ * Notes:
+ * (1) See pixSerializeToMemory() for the binary format.
+ * (2) Note the image size limits.
+ * </pre>
+ */
+PIX *
+pixDeserializeFromMemory(const l_uint32 *data,
+ size_t nbytes)
+{
+char *id;
+l_int32 w, h, d, pixdata_size, memdata_size, imdata_size, ncolors, valid;
+l_uint32 *imdata; /* data in pix raster */
+PIX *pix1, *pixd;
+PIXCMAP *cmap;
+
+ PROCNAME("pixDeserializeFromMemory");
+
+ if (!data)
+ return (PIX *)ERROR_PTR("data not defined", procName, NULL);
+ if (nbytes < 28 || nbytes > ((1LL << 31) - 1)) {
+ L_ERROR("invalid nbytes = %zu\n", procName, nbytes);
+ return NULL;
+ }
+
+ id = (char *)data;
+ if (id[0] != 's' || id[1] != 'p' || id[2] != 'i' || id[3] != 'x')
+ return (PIX *)ERROR_PTR("invalid id string", procName, NULL);
+ w = data[1];
+ h = data[2];
+ d = data[3];
+ ncolors = data[5];
+
+ /* Sanity checks on the amount of image data */
+ if (w < 1 || w > MaxAllowedWidth)
+ return (PIX *)ERROR_PTR("invalid width", procName, NULL);
+ if (h < 1 || h > MaxAllowedHeight)
+ return (PIX *)ERROR_PTR("invalid height", procName, NULL);
+ if (1LL * w * h > MaxAllowedArea)
+ return (PIX *)ERROR_PTR("area too large", procName, NULL);
+ if (ncolors < 0 || ncolors > 256 || ncolors + 7 >= nbytes/sizeof(l_int32))
+ return (PIX *)ERROR_PTR("invalid ncolors", procName, NULL);
+ if ((pix1 = pixCreateHeader(w, h, d)) == NULL) /* just make the header */
+ return (PIX *)ERROR_PTR("failed to make header", procName, NULL);
+ pixdata_size = 4 * h * pixGetWpl(pix1);
+ memdata_size = nbytes - 24 - 4 * ncolors - 4;
+ imdata_size = data[6 + ncolors];
+ pixDestroy(&pix1);
+ if (pixdata_size != memdata_size || pixdata_size != imdata_size) {
+ L_ERROR("pixdata_size = %d, memdata_size = %d, imdata_size = %d "
+ "not all equal!\n", procName, pixdata_size, memdata_size,
+ imdata_size);
+ return NULL;
+ }
+
+ if ((pixd = pixCreate(w, h, d)) == NULL)
+ return (PIX *)ERROR_PTR("pix not made", procName, NULL);
+ if (ncolors > 0) {
+ cmap = pixcmapDeserializeFromMemory((l_uint8 *)(&data[6]), 4, ncolors);
+ if (!cmap) {
+ pixDestroy(&pixd);
+ return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
+ }
+ if (pixSetColormap(pixd, cmap)) {
+ pixDestroy(&pixd);
+ return (PIX *)ERROR_PTR("cmap is not valid", procName, NULL);
+ }
+ }
+
+ /* Read the raster data */
+ imdata = pixGetData(pixd);
+ memcpy(imdata, data + 7 + ncolors, imdata_size);
+
+ /* Verify that the colormap is valid with the pix */
+ if (ncolors > 0) {
+ pixcmapIsValid(cmap, pixd, &valid);
+ if (!valid) {
+ pixDestroy(&pixd);
+ return (PIX *)ERROR_PTR("cmap is invalid with pix", procName, NULL);
+ }
+ }
+
+#if DEBUG_SERIALIZE
+ lept_stderr("Deserialize: "
+ "raster size = %d, ncolors in cmap = %d, total bytes = %zu\n",
+ imdata_size, ncolors, nbytes);
+#endif /* DEBUG_SERIALIZE */
+
+ return pixd;
+}