summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'leptonica/src/ptabasic.c')
-rw-r--r--leptonica/src/ptabasic.c1607
1 files changed, 1607 insertions, 0 deletions
diff --git a/leptonica/src/ptabasic.c b/leptonica/src/ptabasic.c
new file mode 100644
index 00000000..25b23a70
--- /dev/null
+++ b/leptonica/src/ptabasic.c
@@ -0,0 +1,1607 @@
+/*====================================================================*
+ - 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 ptabasic.c
+ * <pre>
+ *
+ * Pta creation, destruction, copy, clone, empty
+ * PTA *ptaCreate()
+ * PTA *ptaCreateFromNuma()
+ * void ptaDestroy()
+ * PTA *ptaCopy()
+ * PTA *ptaCopyRange()
+ * PTA *ptaClone()
+ * l_int32 ptaEmpty()
+ *
+ * Pta array extension
+ * l_int32 ptaAddPt()
+ * static l_int32 ptaExtendArrays()
+ *
+ * Pta insertion and removal
+ * l_int32 ptaInsertPt()
+ * l_int32 ptaRemovePt()
+ *
+ * Pta accessors
+ * l_int32 ptaGetRefcount()
+ * l_int32 ptaChangeRefcount()
+ * l_int32 ptaGetCount()
+ * l_int32 ptaGetPt()
+ * l_int32 ptaGetIPt()
+ * l_int32 ptaSetPt()
+ * l_int32 ptaGetArrays()
+ *
+ * Pta serialized for I/O
+ * PTA *ptaRead()
+ * PTA *ptaReadStream()
+ * PTA *ptaReadMem()
+ * l_int32 ptaWriteDebug()
+ * l_int32 ptaWrite()
+ * l_int32 ptaWriteStream()
+ * l_int32 ptaWriteMem()
+ *
+ * Ptaa creation, destruction
+ * PTAA *ptaaCreate()
+ * void ptaaDestroy()
+ *
+ * Ptaa array extension
+ * l_int32 ptaaAddPta()
+ * static l_int32 ptaaExtendArray()
+ *
+ * Ptaa accessors
+ * l_int32 ptaaGetCount()
+ * l_int32 ptaaGetPta()
+ * l_int32 ptaaGetPt()
+ *
+ * Ptaa array modifiers
+ * l_int32 ptaaInitFull()
+ * l_int32 ptaaReplacePta()
+ * l_int32 ptaaAddPt()
+ * l_int32 ptaaTruncate()
+ *
+ * Ptaa serialized for I/O
+ * PTAA *ptaaRead()
+ * PTAA *ptaaReadStream()
+ * PTAA *ptaaReadMem()
+ * l_int32 ptaaWrite()
+ * l_int32 ptaaWriteStream()
+ * l_int32 ptaaWriteMem()
+ * </pre>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config_auto.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include "allheaders.h"
+
+static const l_uint32 MaxArraySize = 100000000; /* 100 million */
+static const l_uint32 MaxPtrArraySize = 10000000; /* 10 million */
+static const l_int32 InitialArraySize = 50; /*!< n'importe quoi */
+
+ /* Static functions */
+static l_int32 ptaExtendArrays(PTA *pta);
+static l_int32 ptaaExtendArray(PTAA *ptaa);
+
+/*---------------------------------------------------------------------*
+ * Pta creation, destruction, copy, clone *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaCreate()
+ *
+ * \param[in] n initial array sizes
+ * \return pta, or NULL on error.
+ */
+PTA *
+ptaCreate(l_int32 n)
+{
+PTA *pta;
+
+ PROCNAME("ptaCreate");
+
+ if (n <= 0 || n > MaxArraySize)
+ n = InitialArraySize;
+
+ pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA));
+ pta->n = 0;
+ pta->nalloc = n;
+ ptaChangeRefcount(pta, 1); /* sets to 1 */
+ pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
+ pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
+ if (!pta->x || !pta->y) {
+ ptaDestroy(&pta);
+ return (PTA *)ERROR_PTR("x and y arrays not both made", procName, NULL);
+ }
+
+ return pta;
+}
+
+
+/*!
+ * \brief ptaCreateFromNuma()
+ *
+ * \param[in] nax [optional] can be null
+ * \param[in] nay
+ * \return pta, or NULL on error.
+ */
+PTA *
+ptaCreateFromNuma(NUMA *nax,
+ NUMA *nay)
+{
+l_int32 i, n;
+l_float32 startx, delx, xval, yval;
+PTA *pta;
+
+ PROCNAME("ptaCreateFromNuma");
+
+ if (!nay)
+ return (PTA *)ERROR_PTR("nay not defined", procName, NULL);
+ n = numaGetCount(nay);
+ if (nax && numaGetCount(nax) != n)
+ return (PTA *)ERROR_PTR("nax and nay sizes differ", procName, NULL);
+
+ pta = ptaCreate(n);
+ numaGetParameters(nay, &startx, &delx);
+ for (i = 0; i < n; i++) {
+ if (nax)
+ numaGetFValue(nax, i, &xval);
+ else /* use implicit x values from nay */
+ xval = startx + i * delx;
+ numaGetFValue(nay, i, &yval);
+ ptaAddPt(pta, xval, yval);
+ }
+
+ return pta;
+}
+
+
+/*!
+ * \brief ptaDestroy()
+ *
+ * \param[in,out] ppta will be set to null before returning
+ * \return void
+ *
+ * <pre>
+ * Notes:
+ * (1) Decrements the ref count and, if 0, destroys the pta.
+ * (2) Always nulls the input ptr.
+ * </pre>
+ */
+void
+ptaDestroy(PTA **ppta)
+{
+PTA *pta;
+
+ PROCNAME("ptaDestroy");
+
+ if (ppta == NULL) {
+ L_WARNING("ptr address is NULL!\n", procName);
+ return;
+ }
+
+ if ((pta = *ppta) == NULL)
+ return;
+
+ ptaChangeRefcount(pta, -1);
+ if (ptaGetRefcount(pta) <= 0) {
+ LEPT_FREE(pta->x);
+ LEPT_FREE(pta->y);
+ LEPT_FREE(pta);
+ }
+ *ppta = NULL;
+}
+
+
+/*!
+ * \brief ptaCopy()
+ *
+ * \param[in] pta
+ * \return copy of pta, or NULL on error
+ */
+PTA *
+ptaCopy(PTA *pta)
+{
+l_int32 i;
+l_float32 x, y;
+PTA *npta;
+
+ PROCNAME("ptaCopy");
+
+ if (!pta)
+ return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
+
+ if ((npta = ptaCreate(pta->nalloc)) == NULL)
+ return (PTA *)ERROR_PTR("npta not made", procName, NULL);
+
+ for (i = 0; i < pta->n; i++) {
+ ptaGetPt(pta, i, &x, &y);
+ ptaAddPt(npta, x, y);
+ }
+
+ return npta;
+}
+
+
+/*!
+ * \brief ptaCopyRange()
+ *
+ * \param[in] ptas
+ * \param[in] istart starting index in ptas
+ * \param[in] iend ending index in ptas; use 0 to copy to end
+ * \return 0 if OK, 1 on error
+ */
+PTA *
+ptaCopyRange(PTA *ptas,
+ l_int32 istart,
+ l_int32 iend)
+{
+l_int32 n, i, x, y;
+PTA *ptad;
+
+ PROCNAME("ptaCopyRange");
+
+ if (!ptas)
+ return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
+ n = ptaGetCount(ptas);
+ if (istart < 0)
+ istart = 0;
+ if (istart >= n)
+ return (PTA *)ERROR_PTR("istart out of bounds", procName, NULL);
+ if (iend <= 0 || iend >= n)
+ iend = n - 1;
+ if (istart > iend)
+ return (PTA *)ERROR_PTR("istart > iend; no pts", procName, NULL);
+
+ if ((ptad = ptaCreate(iend - istart + 1)) == NULL)
+ return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
+ for (i = istart; i <= iend; i++) {
+ ptaGetIPt(ptas, i, &x, &y);
+ ptaAddPt(ptad, x, y);
+ }
+
+ return ptad;
+}
+
+
+/*!
+ * \brief ptaClone()
+ *
+ * \param[in] pta
+ * \return ptr to same pta, or NULL on error
+ */
+PTA *
+ptaClone(PTA *pta)
+{
+ PROCNAME("ptaClone");
+
+ if (!pta)
+ return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
+
+ ptaChangeRefcount(pta, 1);
+ return pta;
+}
+
+
+/*!
+ * \brief ptaEmpty()
+ *
+ * \param[in] pta
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * This only resets the Pta::n field, for reuse
+ * </pre>
+ */
+l_ok
+ptaEmpty(PTA *pta)
+{
+ PROCNAME("ptaEmpty");
+
+ if (!pta)
+ return ERROR_INT("ptad not defined", procName, 1);
+ pta->n = 0;
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Pta array extension *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaAddPt()
+ *
+ * \param[in] pta
+ * \param[in] x, y
+ * \return 0 if OK, 1 on error
+ */
+l_ok
+ptaAddPt(PTA *pta,
+ l_float32 x,
+ l_float32 y)
+{
+l_int32 n;
+
+ PROCNAME("ptaAddPt");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+ n = pta->n;
+ if (n >= pta->nalloc) {
+ if (ptaExtendArrays(pta))
+ return ERROR_INT("extension failed", procName, 1);
+ }
+
+ pta->x[n] = x;
+ pta->y[n] = y;
+ pta->n++;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaExtendArrays()
+ *
+ * \param[in] pta
+ * \return 0 if OK; 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) The max number of points is 100M.
+ * </pre>
+ */
+static l_int32
+ptaExtendArrays(PTA *pta)
+{
+size_t oldsize, newsize;
+
+ PROCNAME("ptaExtendArrays");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ if (pta->nalloc > MaxArraySize) /* belt & suspenders */
+ return ERROR_INT("pta has too many ptrs", procName, 1);
+ oldsize = pta->nalloc * sizeof(l_float32);
+ newsize = 2 * oldsize;
+ if (newsize > 4 * MaxArraySize) /* array of 100M floats */
+ return ERROR_INT("newsize > 400 MB; too large", procName, 1);
+
+ if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x,
+ oldsize, newsize)) == NULL)
+ return ERROR_INT("new x array not returned", procName, 1);
+ if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y,
+ oldsize, newsize)) == NULL)
+ return ERROR_INT("new y array not returned", procName, 1);
+
+ pta->nalloc *= 2;
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Pta insertion and removal *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaInsertPt()
+ *
+ * \param[in] pta
+ * \param[in] index at which pt is to be inserted
+ * \param[in] x, y point values
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaInsertPt(PTA *pta,
+ l_int32 index,
+ l_int32 x,
+ l_int32 y)
+{
+l_int32 i, n;
+
+ PROCNAME("ptaInsertPt");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ n = ptaGetCount(pta);
+ if (index < 0 || index > n) {
+ L_ERROR("index %d not in [0,...,%d]\n", procName, index, n);
+ return 1;
+ }
+
+ if (n > pta->nalloc) {
+ if (ptaExtendArrays(pta))
+ return ERROR_INT("extension failed", procName, 1);
+ }
+ pta->n++;
+ for (i = n; i > index; i--) {
+ pta->x[i] = pta->x[i - 1];
+ pta->y[i] = pta->y[i - 1];
+ }
+ pta->x[index] = x;
+ pta->y[index] = y;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaRemovePt()
+ *
+ * \param[in] pta
+ * \param[in] index of point to be removed
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) This shifts pta[i] --> pta[i - 1] for all i > index.
+ * (2) It should not be used repeatedly on large arrays,
+ * because the function is O(n).
+ * </pre>
+ */
+l_ok
+ptaRemovePt(PTA *pta,
+ l_int32 index)
+{
+l_int32 i, n;
+
+ PROCNAME("ptaRemovePt");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ n = ptaGetCount(pta);
+ if (index < 0 || index >= n) {
+ L_ERROR("index %d not in [0,...,%d]\n", procName, index, n - 1);
+ return 1;
+ }
+
+ /* Remove the point */
+ for (i = index + 1; i < n; i++) {
+ pta->x[i - 1] = pta->x[i];
+ pta->y[i - 1] = pta->y[i];
+ }
+ pta->n--;
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Pta accessors *
+ *---------------------------------------------------------------------*/
+l_int32
+ptaGetRefcount(PTA *pta)
+{
+ PROCNAME("ptaGetRefcount");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ return pta->refcount;
+}
+
+
+l_int32
+ptaChangeRefcount(PTA *pta,
+ l_int32 delta)
+{
+ PROCNAME("ptaChangeRefcount");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ pta->refcount += delta;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaGetCount()
+ *
+ * \param[in] pta
+ * \return count, or 0 if no pta
+ */
+l_int32
+ptaGetCount(PTA *pta)
+{
+ PROCNAME("ptaGetCount");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 0);
+
+ return pta->n;
+}
+
+
+/*!
+ * \brief ptaGetPt()
+ *
+ * \param[in] pta
+ * \param[in] index into arrays
+ * \param[out] px [optional] float x value
+ * \param[out] py [optional] float y value
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaGetPt(PTA *pta,
+ l_int32 index,
+ l_float32 *px,
+ l_float32 *py)
+{
+ PROCNAME("ptaGetPt");
+
+ if (px) *px = 0;
+ if (py) *py = 0;
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ if (index < 0 || index >= pta->n)
+ return ERROR_INT("invalid index", procName, 1);
+
+ if (px) *px = pta->x[index];
+ if (py) *py = pta->y[index];
+ return 0;
+}
+
+
+/*!
+ * \brief ptaGetIPt()
+ *
+ * \param[in] pta
+ * \param[in] index into arrays
+ * \param[out] px [optional] integer x value
+ * \param[out] py [optional] integer y value
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaGetIPt(PTA *pta,
+ l_int32 index,
+ l_int32 *px,
+ l_int32 *py)
+{
+ PROCNAME("ptaGetIPt");
+
+ if (px) *px = 0;
+ if (py) *py = 0;
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ if (index < 0 || index >= pta->n)
+ return ERROR_INT("invalid index", procName, 1);
+
+ if (px) *px = (l_int32)(pta->x[index] + 0.5);
+ if (py) *py = (l_int32)(pta->y[index] + 0.5);
+ return 0;
+}
+
+
+/*!
+ * \brief ptaSetPt()
+ *
+ * \param[in] pta
+ * \param[in] index into arrays
+ * \param[in] x, y
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaSetPt(PTA *pta,
+ l_int32 index,
+ l_float32 x,
+ l_float32 y)
+{
+ PROCNAME("ptaSetPt");
+
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ if (index < 0 || index >= pta->n)
+ return ERROR_INT("invalid index", procName, 1);
+
+ pta->x[index] = x;
+ pta->y[index] = y;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaGetArrays()
+ *
+ * \param[in] pta
+ * \param[out] pnax [optional] numa of x array
+ * \param[out] pnay [optional] numa of y array
+ * \return 0 if OK; 1 on error or if pta is empty
+ *
+ * <pre>
+ * Notes:
+ * (1) This copies the internal arrays into new Numas.
+ * </pre>
+ */
+l_ok
+ptaGetArrays(PTA *pta,
+ NUMA **pnax,
+ NUMA **pnay)
+{
+l_int32 i, n;
+NUMA *nax, *nay;
+
+ PROCNAME("ptaGetArrays");
+
+ if (!pnax && !pnay)
+ return ERROR_INT("no output requested", procName, 1);
+ if (pnax) *pnax = NULL;
+ if (pnay) *pnay = NULL;
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ if ((n = ptaGetCount(pta)) == 0)
+ return ERROR_INT("pta is empty", procName, 1);
+
+ if (pnax) {
+ if ((nax = numaCreate(n)) == NULL)
+ return ERROR_INT("nax not made", procName, 1);
+ *pnax = nax;
+ for (i = 0; i < n; i++)
+ nax->array[i] = pta->x[i];
+ nax->n = n;
+ }
+ if (pnay) {
+ if ((nay = numaCreate(n)) == NULL)
+ return ERROR_INT("nay not made", procName, 1);
+ *pnay = nay;
+ for (i = 0; i < n; i++)
+ nay->array[i] = pta->y[i];
+ nay->n = n;
+ }
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Pta serialized for I/O *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaRead()
+ *
+ * \param[in] filename
+ * \return pta, or NULL on error
+ */
+PTA *
+ptaRead(const char *filename)
+{
+FILE *fp;
+PTA *pta;
+
+ PROCNAME("ptaRead");
+
+ if (!filename)
+ return (PTA *)ERROR_PTR("filename not defined", procName, NULL);
+
+ if ((fp = fopenReadStream(filename)) == NULL)
+ return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
+ pta = ptaReadStream(fp);
+ fclose(fp);
+ if (!pta)
+ return (PTA *)ERROR_PTR("pta not read", procName, NULL);
+ return pta;
+}
+
+
+/*!
+ * \brief ptaReadStream()
+ *
+ * \param[in] fp file stream
+ * \return pta, or NULL on error
+ *
+ * <pre>
+ * Notes:
+ * (1) It is OK for the pta to be empty (n == 0).
+ * </pre>
+
+ */
+PTA *
+ptaReadStream(FILE *fp)
+{
+char typestr[128]; /* hardcoded below in fscanf */
+l_int32 i, n, ix, iy, type, version;
+l_float32 x, y;
+PTA *pta;
+
+ PROCNAME("ptaReadStream");
+
+ if (!fp)
+ return (PTA *)ERROR_PTR("stream not defined", procName, NULL);
+
+ if (fscanf(fp, "\n Pta Version %d\n", &version) != 1)
+ return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
+ if (version != PTA_VERSION_NUMBER)
+ return (PTA *)ERROR_PTR("invalid pta version", procName, NULL);
+ if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2)
+ return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
+ if (n < 0)
+ return (PTA *)ERROR_PTR("num pts <= 0", procName, NULL);
+ if (n > MaxArraySize)
+ return (PTA *)ERROR_PTR("too many pts", procName, NULL);
+ if (n == 0) L_INFO("the pta is empty\n", procName);
+
+ if (!strcmp(typestr, "float"))
+ type = 0;
+ else /* typestr is "integer" */
+ type = 1;
+ if ((pta = ptaCreate(n)) == NULL)
+ return (PTA *)ERROR_PTR("pta not made", procName, NULL);
+ for (i = 0; i < n; i++) {
+ if (type == 0) { /* data is float */
+ if (fscanf(fp, " (%f, %f)\n", &x, &y) != 2) {
+ ptaDestroy(&pta);
+ return (PTA *)ERROR_PTR("error reading floats", procName, NULL);
+ }
+ ptaAddPt(pta, x, y);
+ } else { /* data is integer */
+ if (fscanf(fp, " (%d, %d)\n", &ix, &iy) != 2) {
+ ptaDestroy(&pta);
+ return (PTA *)ERROR_PTR("error reading ints", procName, NULL);
+ }
+ ptaAddPt(pta, ix, iy);
+ }
+ }
+
+ return pta;
+}
+
+
+/*!
+ * \brief ptaReadMem()
+ *
+ * \param[in] data serialization in ascii
+ * \param[in] size of data in bytes; can use strlen to get it
+ * \return pta, or NULL on error
+ */
+PTA *
+ptaReadMem(const l_uint8 *data,
+ size_t size)
+{
+FILE *fp;
+PTA *pta;
+
+ PROCNAME("ptaReadMem");
+
+ if (!data)
+ return (PTA *)ERROR_PTR("data not defined", procName, NULL);
+ if ((fp = fopenReadFromMemory(data, size)) == NULL)
+ return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
+
+ pta = ptaReadStream(fp);
+ fclose(fp);
+ if (!pta) L_ERROR("pta not read\n", procName);
+ return pta;
+}
+
+
+/*!
+ * \brief ptaWriteDebug()
+ *
+ * \param[in] filename
+ * \param[in] pta
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) Debug version, intended for use in the library when writing
+ * to files in a temp directory with names that are compiled in.
+ * This is used instead of ptaWrite() for all such library calls.
+ * (2) The global variable LeptDebugOK defaults to 0, and can be set
+ * or cleared by the function setLeptDebugOK().
+ * </pre>
+ */
+l_ok
+ptaWriteDebug(const char *filename,
+ PTA *pta,
+ l_int32 type)
+{
+ PROCNAME("ptaWriteDebug");
+
+ if (LeptDebugOK) {
+ return ptaWrite(filename, pta, type);
+ } else {
+ L_INFO("write to named temp file %s is disabled\n", procName, filename);
+ return 0;
+ }
+}
+
+
+/*!
+ * \brief ptaWrite()
+ *
+ * \param[in] filename
+ * \param[in] pta
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ */
+l_ok
+ptaWrite(const char *filename,
+ PTA *pta,
+ l_int32 type)
+{
+l_int32 ret;
+FILE *fp;
+
+ PROCNAME("ptaWrite");
+
+ if (!filename)
+ return ERROR_INT("filename not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+ if ((fp = fopenWriteStream(filename, "w")) == NULL)
+ return ERROR_INT("stream not opened", procName, 1);
+ ret = ptaWriteStream(fp, pta, type);
+ fclose(fp);
+ if (ret)
+ return ERROR_INT("pta not written to stream", procName, 1);
+ return 0;
+}
+
+
+/*!
+ * \brief ptaWriteStream()
+ *
+ * \param[in] fp file stream
+ * \param[in] pta
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaWriteStream(FILE *fp,
+ PTA *pta,
+ l_int32 type)
+{
+l_int32 i, n, ix, iy;
+l_float32 x, y;
+
+ PROCNAME("ptaWriteStream");
+
+ if (!fp)
+ return ERROR_INT("stream not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+ n = ptaGetCount(pta);
+ fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER);
+ if (type == 0)
+ fprintf(fp, " Number of pts = %d; format = float\n", n);
+ else /* type == 1 */
+ fprintf(fp, " Number of pts = %d; format = integer\n", n);
+ for (i = 0; i < n; i++) {
+ if (type == 0) { /* data is float */
+ ptaGetPt(pta, i, &x, &y);
+ fprintf(fp, " (%f, %f)\n", x, y);
+ } else { /* data is integer */
+ ptaGetIPt(pta, i, &ix, &iy);
+ fprintf(fp, " (%d, %d)\n", ix, iy);
+ }
+ }
+
+ return 0;
+}
+
+
+/*!
+ * \brief ptaWriteMem()
+ *
+ * \param[out] pdata data of serialized pta; ascii
+ * \param[out] psize size of returned data
+ * \param[in] pta
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) Serializes a pta in memory and puts the result in a buffer.
+ * </pre>
+ */
+l_ok
+ptaWriteMem(l_uint8 **pdata,
+ size_t *psize,
+ PTA *pta,
+ l_int32 type)
+{
+l_int32 ret;
+FILE *fp;
+
+ PROCNAME("ptaWriteMem");
+
+ if (pdata) *pdata = NULL;
+ if (psize) *psize = 0;
+ if (!pdata)
+ return ERROR_INT("&data not defined", procName, 1);
+ if (!psize)
+ return ERROR_INT("&size not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+#if HAVE_FMEMOPEN
+ if ((fp = open_memstream((char **)pdata, psize)) == NULL)
+ return ERROR_INT("stream not opened", procName, 1);
+ ret = ptaWriteStream(fp, pta, type);
+#else
+ L_INFO("work-around: writing to a temp file\n", procName);
+ #ifdef _WIN32
+ if ((fp = fopenWriteWinTempfile()) == NULL)
+ return ERROR_INT("tmpfile stream not opened", procName, 1);
+ #else
+ if ((fp = tmpfile()) == NULL)
+ return ERROR_INT("tmpfile stream not opened", procName, 1);
+ #endif /* _WIN32 */
+ ret = ptaWriteStream(fp, pta, type);
+ rewind(fp);
+ *pdata = l_binaryReadStream(fp, psize);
+#endif /* HAVE_FMEMOPEN */
+ fclose(fp);
+ return ret;
+}
+
+
+/*---------------------------------------------------------------------*
+ * PTAA creation, destruction *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaaCreate()
+ *
+ * \param[in] n initial number of ptrs
+ * \return ptaa, or NULL on error
+ */
+PTAA *
+ptaaCreate(l_int32 n)
+{
+PTAA *ptaa;
+
+ PROCNAME("ptaaCreate");
+
+ if (n <= 0 || n > MaxPtrArraySize)
+ n = InitialArraySize;
+
+ ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA));
+ ptaa->n = 0;
+ ptaa->nalloc = n;
+ if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) {
+ ptaaDestroy(&ptaa);
+ return (PTAA *)ERROR_PTR("pta ptrs not made", procName, NULL);
+ }
+ return ptaa;
+}
+
+
+/*!
+ * \brief ptaaDestroy()
+ *
+ * \param[in,out] pptaa will be set to null before returning
+ * \return void
+ */
+void
+ptaaDestroy(PTAA **pptaa)
+{
+l_int32 i;
+PTAA *ptaa;
+
+ PROCNAME("ptaaDestroy");
+
+ if (pptaa == NULL) {
+ L_WARNING("ptr address is NULL!\n", procName);
+ return;
+ }
+
+ if ((ptaa = *pptaa) == NULL)
+ return;
+
+ for (i = 0; i < ptaa->n; i++)
+ ptaDestroy(&ptaa->pta[i]);
+ LEPT_FREE(ptaa->pta);
+ LEPT_FREE(ptaa);
+ *pptaa = NULL;
+}
+
+
+/*---------------------------------------------------------------------*
+ * PTAA array extension *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaaAddPta()
+ *
+ * \param[in] ptaa
+ * \param[in] pta to be added
+ * \param[in] copyflag L_INSERT, L_COPY, L_CLONE
+ * \return 0 if OK, 1 on error
+ */
+l_ok
+ptaaAddPta(PTAA *ptaa,
+ PTA *pta,
+ l_int32 copyflag)
+{
+l_int32 n;
+PTA *ptac;
+
+ PROCNAME("ptaaAddPta");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+ if (copyflag == L_INSERT) {
+ ptac = pta;
+ } else if (copyflag == L_COPY) {
+ if ((ptac = ptaCopy(pta)) == NULL)
+ return ERROR_INT("ptac not made", procName, 1);
+ } else if (copyflag == L_CLONE) {
+ if ((ptac = ptaClone(pta)) == NULL)
+ return ERROR_INT("pta clone not made", procName, 1);
+ } else {
+ return ERROR_INT("invalid copyflag", procName, 1);
+ }
+
+ n = ptaaGetCount(ptaa);
+ if (n >= ptaa->nalloc) {
+ if (ptaaExtendArray(ptaa)) {
+ if (copyflag != L_INSERT)
+ ptaDestroy(&ptac);
+ return ERROR_INT("extension failed", procName, 1);
+ }
+ }
+
+ ptaa->pta[n] = ptac;
+ ptaa->n++;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaExtendArray()
+ *
+ * \param[in] ptaa
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) This doubles the pta ptr array size.
+ * (2) The max number of pta ptrs is 10M.
+ * </pre>
+ *
+ */
+static l_int32
+ptaaExtendArray(PTAA *ptaa)
+{
+size_t oldsize, newsize;
+
+ PROCNAME("ptaaExtendArray");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ oldsize = ptaa->nalloc * sizeof(PTA *);
+ newsize = 2 * oldsize;
+ if (newsize > 8 * MaxPtrArraySize)
+ return ERROR_INT("newsize > 80 MB; too large", procName, 1);
+
+ if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta,
+ oldsize, newsize)) == NULL)
+ return ERROR_INT("new ptr array not returned", procName, 1);
+
+ ptaa->nalloc *= 2;
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Ptaa accessors *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaaGetCount()
+ *
+ * \param[in] ptaa
+ * \return count, or 0 if no ptaa
+ */
+l_int32
+ptaaGetCount(PTAA *ptaa)
+{
+ PROCNAME("ptaaGetCount");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 0);
+
+ return ptaa->n;
+}
+
+
+/*!
+ * \brief ptaaGetPta()
+ *
+ * \param[in] ptaa
+ * \param[in] index to the i-th pta
+ * \param[in] accessflag L_COPY or L_CLONE
+ * \return pta, or NULL on error
+ */
+PTA *
+ptaaGetPta(PTAA *ptaa,
+ l_int32 index,
+ l_int32 accessflag)
+{
+ PROCNAME("ptaaGetPta");
+
+ if (!ptaa)
+ return (PTA *)ERROR_PTR("ptaa not defined", procName, NULL);
+ if (index < 0 || index >= ptaa->n)
+ return (PTA *)ERROR_PTR("index not valid", procName, NULL);
+
+ if (accessflag == L_COPY)
+ return ptaCopy(ptaa->pta[index]);
+ else if (accessflag == L_CLONE)
+ return ptaClone(ptaa->pta[index]);
+ else
+ return (PTA *)ERROR_PTR("invalid accessflag", procName, NULL);
+}
+
+
+/*!
+ * \brief ptaaGetPt()
+ *
+ * \param[in] ptaa
+ * \param[in] ipta to the i-th pta
+ * \param[in] jpt index to the j-th pt in the pta
+ * \param[out] px [optional] float x value
+ * \param[out] py [optional] float y value
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaaGetPt(PTAA *ptaa,
+ l_int32 ipta,
+ l_int32 jpt,
+ l_float32 *px,
+ l_float32 *py)
+{
+PTA *pta;
+
+ PROCNAME("ptaaGetPt");
+
+ if (px) *px = 0;
+ if (py) *py = 0;
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ if (ipta < 0 || ipta >= ptaa->n)
+ return ERROR_INT("index ipta not valid", procName, 1);
+
+ pta = ptaaGetPta(ptaa, ipta, L_CLONE);
+ if (jpt < 0 || jpt >= pta->n) {
+ ptaDestroy(&pta);
+ return ERROR_INT("index jpt not valid", procName, 1);
+ }
+
+ ptaGetPt(pta, jpt, px, py);
+ ptaDestroy(&pta);
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Ptaa array modifiers *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaaInitFull()
+ *
+ * \param[in] ptaa can have non-null ptrs in the ptr array
+ * \param[in] pta to be replicated into the entire ptr array
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaaInitFull(PTAA *ptaa,
+ PTA *pta)
+{
+l_int32 n, i;
+PTA *ptat;
+
+ PROCNAME("ptaaInitFull");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+
+ n = ptaa->nalloc;
+ ptaa->n = n;
+ for (i = 0; i < n; i++) {
+ ptat = ptaCopy(pta);
+ ptaaReplacePta(ptaa, i, ptat);
+ }
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaReplacePta()
+ *
+ * \param[in] ptaa
+ * \param[in] index to the index-th pta
+ * \param[in] pta insert and replace any existing one
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) Any existing pta is destroyed, and the input one
+ * is inserted in its place.
+ * (2) If %index is invalid, return 1 (error)
+ * </pre>
+ */
+l_ok
+ptaaReplacePta(PTAA *ptaa,
+ l_int32 index,
+ PTA *pta)
+{
+l_int32 n;
+
+ PROCNAME("ptaaReplacePta");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ if (!pta)
+ return ERROR_INT("pta not defined", procName, 1);
+ n = ptaaGetCount(ptaa);
+ if (index < 0 || index >= n)
+ return ERROR_INT("index not valid", procName, 1);
+
+ ptaDestroy(&ptaa->pta[index]);
+ ptaa->pta[index] = pta;
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaAddPt()
+ *
+ * \param[in] ptaa
+ * \param[in] ipta to the i-th pta
+ * \param[in] x,y point coordinates
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaaAddPt(PTAA *ptaa,
+ l_int32 ipta,
+ l_float32 x,
+ l_float32 y)
+{
+PTA *pta;
+
+ PROCNAME("ptaaAddPt");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+ if (ipta < 0 || ipta >= ptaa->n)
+ return ERROR_INT("index ipta not valid", procName, 1);
+
+ pta = ptaaGetPta(ptaa, ipta, L_CLONE);
+ ptaAddPt(pta, x, y);
+ ptaDestroy(&pta);
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaTruncate()
+ *
+ * \param[in] ptaa
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) This identifies the largest index containing a pta that
+ * has any points within it, destroys all pta above that index,
+ * and resets the count.
+ * </pre>
+ */
+l_ok
+ptaaTruncate(PTAA *ptaa)
+{
+l_int32 i, n, np;
+PTA *pta;
+
+ PROCNAME("ptaaTruncate");
+
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+
+ n = ptaaGetCount(ptaa);
+ for (i = n - 1; i >= 0; i--) {
+ pta = ptaaGetPta(ptaa, i, L_CLONE);
+ if (!pta) {
+ ptaa->n--;
+ continue;
+ }
+ np = ptaGetCount(pta);
+ ptaDestroy(&pta);
+ if (np == 0) {
+ ptaDestroy(&ptaa->pta[i]);
+ ptaa->n--;
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*
+ * Ptaa serialized for I/O *
+ *---------------------------------------------------------------------*/
+/*!
+ * \brief ptaaRead()
+ *
+ * \param[in] filename
+ * \return ptaa, or NULL on error
+ */
+PTAA *
+ptaaRead(const char *filename)
+{
+FILE *fp;
+PTAA *ptaa;
+
+ PROCNAME("ptaaRead");
+
+ if (!filename)
+ return (PTAA *)ERROR_PTR("filename not defined", procName, NULL);
+
+ if ((fp = fopenReadStream(filename)) == NULL)
+ return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
+ ptaa = ptaaReadStream(fp);
+ fclose(fp);
+ if (!ptaa)
+ return (PTAA *)ERROR_PTR("ptaa not read", procName, NULL);
+ return ptaa;
+}
+
+
+/*!
+ * \brief ptaaReadStream()
+ *
+ * \param[in] fp file stream
+ * \return ptaa, or NULL on error
+ *
+ * <pre>
+ * Notes:
+ * (1) It is OK for the ptaa to be empty (n == 0).
+ * </pre>
+ */
+PTAA *
+ptaaReadStream(FILE *fp)
+{
+l_int32 i, n, version;
+PTA *pta;
+PTAA *ptaa;
+
+ PROCNAME("ptaaReadStream");
+
+ if (!fp)
+ return (PTAA *)ERROR_PTR("stream not defined", procName, NULL);
+
+ if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1)
+ return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
+ if (version != PTA_VERSION_NUMBER)
+ return (PTAA *)ERROR_PTR("invalid ptaa version", procName, NULL);
+ if (fscanf(fp, "Number of Pta = %d\n", &n) != 1)
+ return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
+ if (n < 0)
+ return (PTAA *)ERROR_PTR("num pta ptrs <= 0", procName, NULL);
+ if (n > MaxPtrArraySize)
+ return (PTAA *)ERROR_PTR("too many pta ptrs", procName, NULL);
+ if (n == 0) L_INFO("the ptaa is empty\n", procName);
+
+ if ((ptaa = ptaaCreate(n)) == NULL)
+ return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
+ for (i = 0; i < n; i++) {
+ if ((pta = ptaReadStream(fp)) == NULL) {
+ ptaaDestroy(&ptaa);
+ return (PTAA *)ERROR_PTR("error reading pta", procName, NULL);
+ }
+ ptaaAddPta(ptaa, pta, L_INSERT);
+ }
+
+ return ptaa;
+}
+
+
+/*!
+ * \brief ptaaReadMem()
+ *
+ * \param[in] data serialization in ascii
+ * \param[in] size of data in bytes; can use strlen to get it
+ * \return ptaa, or NULL on error
+ */
+PTAA *
+ptaaReadMem(const l_uint8 *data,
+ size_t size)
+{
+FILE *fp;
+PTAA *ptaa;
+
+ PROCNAME("ptaaReadMem");
+
+ if (!data)
+ return (PTAA *)ERROR_PTR("data not defined", procName, NULL);
+ if ((fp = fopenReadFromMemory(data, size)) == NULL)
+ return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
+
+ ptaa = ptaaReadStream(fp);
+ fclose(fp);
+ if (!ptaa) L_ERROR("ptaa not read\n", procName);
+ return ptaa;
+}
+
+
+/*!
+ * \brief ptaaWriteDebug()
+ *
+ * \param[in] filename
+ * \param[in] ptaa
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) Debug version, intended for use in the library when writing
+ * to files in a temp directory with names that are compiled in.
+ * This is used instead of ptaaWrite() for all such library calls.
+ * (2) The global variable LeptDebugOK defaults to 0, and can be set
+ * or cleared by the function setLeptDebugOK().
+ * </pre>
+ */
+l_ok
+ptaaWriteDebug(const char *filename,
+ PTAA *ptaa,
+ l_int32 type)
+{
+ PROCNAME("ptaaWriteDebug");
+
+ if (LeptDebugOK) {
+ return ptaaWrite(filename, ptaa, type);
+ } else {
+ L_INFO("write to named temp file %s is disabled\n", procName, filename);
+ return 0;
+ }
+}
+
+
+/*!
+ * \brief ptaaWrite()
+ *
+ * \param[in] filename
+ * \param[in] ptaa
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ */
+l_ok
+ptaaWrite(const char *filename,
+ PTAA *ptaa,
+ l_int32 type)
+{
+l_int32 ret;
+FILE *fp;
+
+ PROCNAME("ptaaWrite");
+
+ if (!filename)
+ return ERROR_INT("filename not defined", procName, 1);
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+
+ if ((fp = fopenWriteStream(filename, "w")) == NULL)
+ return ERROR_INT("stream not opened", procName, 1);
+ ret = ptaaWriteStream(fp, ptaa, type);
+ fclose(fp);
+ if (ret)
+ return ERROR_INT("ptaa not written to stream", procName, 1);
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaWriteStream()
+ *
+ * \param[in] fp file stream
+ * \param[in] ptaa
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK; 1 on error
+ */
+l_ok
+ptaaWriteStream(FILE *fp,
+ PTAA *ptaa,
+ l_int32 type)
+{
+l_int32 i, n;
+PTA *pta;
+
+ PROCNAME("ptaaWriteStream");
+
+ if (!fp)
+ return ERROR_INT("stream not defined", procName, 1);
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+
+ n = ptaaGetCount(ptaa);
+ fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER);
+ fprintf(fp, "Number of Pta = %d\n", n);
+ for (i = 0; i < n; i++) {
+ pta = ptaaGetPta(ptaa, i, L_CLONE);
+ ptaWriteStream(fp, pta, type);
+ ptaDestroy(&pta);
+ }
+
+ return 0;
+}
+
+
+/*!
+ * \brief ptaaWriteMem()
+ *
+ * \param[out] pdata data of serialized ptaa; ascii
+ * \param[out] psize size of returned data
+ * \param[in] ptaa
+ * \param[in] type 0 for float values; 1 for integer values
+ * \return 0 if OK, 1 on error
+ *
+ * <pre>
+ * Notes:
+ * (1) Serializes %ptaa in memory and puts the result in a buffer.
+ * </pre>
+ */
+l_ok
+ptaaWriteMem(l_uint8 **pdata,
+ size_t *psize,
+ PTAA *ptaa,
+ l_int32 type)
+{
+l_int32 ret;
+FILE *fp;
+
+ PROCNAME("ptaaWriteMem");
+
+ if (pdata) *pdata = NULL;
+ if (psize) *psize = 0;
+ if (!pdata)
+ return ERROR_INT("&data not defined", procName, 1);
+ if (!psize)
+ return ERROR_INT("&size not defined", procName, 1);
+ if (!ptaa)
+ return ERROR_INT("ptaa not defined", procName, 1);
+
+#if HAVE_FMEMOPEN
+ if ((fp = open_memstream((char **)pdata, psize)) == NULL)
+ return ERROR_INT("stream not opened", procName, 1);
+ ret = ptaaWriteStream(fp, ptaa, type);
+#else
+ L_INFO("work-around: writing to a temp file\n", procName);
+ #ifdef _WIN32
+ if ((fp = fopenWriteWinTempfile()) == NULL)
+ return ERROR_INT("tmpfile stream not opened", procName, 1);
+ #else
+ if ((fp = tmpfile()) == NULL)
+ return ERROR_INT("tmpfile stream not opened", procName, 1);
+ #endif /* _WIN32 */
+ ret = ptaaWriteStream(fp, ptaa, type);
+ rewind(fp);
+ *pdata = l_binaryReadStream(fp, psize);
+#endif /* HAVE_FMEMOPEN */
+ fclose(fp);
+ return ret;
+}