twain3.0/3rdparty/hgOCR/leptonica/numabasic.c

2024 lines
51 KiB
C
Raw Permalink Normal View History

2021-11-20 06:24:33 +00:00
/*====================================================================*
- 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 numabasic.c
* <pre>
*
* Numa creation, destruction, copy, clone, etc.
* NUMA *numaCreate()
* NUMA *numaCreateFromIArray()
* NUMA *numaCreateFromFArray()
* NUMA *numaCreateFromString()
* void *numaDestroy()
* NUMA *numaCopy()
* NUMA *numaClone()
* l_int32 numaEmpty()
*
* Add/remove number (float or integer)
* l_int32 numaAddNumber()
* static l_int32 numaExtendArray()
* l_int32 numaInsertNumber()
* l_int32 numaRemoveNumber()
* l_int32 numaReplaceNumber()
*
* Numa accessors
* l_int32 numaGetCount()
* l_int32 numaSetCount()
* l_int32 numaGetIValue()
* l_int32 numaGetFValue()
* l_int32 numaSetValue()
* l_int32 numaShiftValue()
* l_int32 *numaGetIArray()
* l_float32 *numaGetFArray()
* l_int32 numaGetRefcount()
* l_int32 numaChangeRefcount()
* l_int32 numaGetParameters()
* l_int32 numaSetParameters()
* l_int32 numaCopyParameters()
*
* Convert to string array
* SARRAY *numaConvertToSarray()
*
* Serialize numa for I/O
* NUMA *numaRead()
* NUMA *numaReadStream()
* NUMA *numaReadMem()
* l_int32 numaWriteDebug()
* l_int32 numaWrite()
* l_int32 numaWriteStream()
* l_int32 numaWriteMem()
*
* Numaa creation, destruction, truncation
* NUMAA *numaaCreate()
* NUMAA *numaaCreateFull()
* NUMAA *numaaTruncate()
* void *numaaDestroy()
*
* Add Numa to Numaa
* l_int32 numaaAddNuma()
* static l_int32 numaaExtendArray()
*
* Numaa accessors
* l_int32 numaaGetCount()
* l_int32 numaaGetNumaCount()
* l_int32 numaaGetNumberCount()
* NUMA **numaaGetPtrArray()
* NUMA *numaaGetNuma()
* NUMA *numaaReplaceNuma()
* l_int32 numaaGetValue()
* l_int32 numaaAddNumber()
*
* Serialize numaa for I/O
* NUMAA *numaaRead()
* NUMAA *numaaReadStream()
* NUMAA *numaaReadMem()
* l_int32 numaaWrite()
* l_int32 numaaWriteStream()
* l_int32 numaaWriteMem()
*
* (1) The Numa is a struct holding an array of floats. It can also
* be used to store l_int32 values, with some loss of precision
* for floats larger than about 10 million. Use the L_Dna instead
* if integers larger than a few million need to be stored.
*
* (2) Always use the accessors in this file, never the fields directly.
*
* (3) Storing and retrieving numbers:
*
* * to append a new number to the array, use numaAddNumber(). If
* the number is an int, it will will automatically be converted
* to l_float32 and stored.
*
* * to reset a value stored in the array, use numaSetValue().
*
* * to increment or decrement a value stored in the array,
* use numaShiftValue().
*
* * to obtain a value from the array, use either numaGetIValue()
* or numaGetFValue(), depending on whether you are retrieving
* an integer or a float. This avoids doing an explicit cast,
* such as
* (a) return a l_float32 and cast it to an l_int32
* (b) cast the return directly to (l_float32 *) to
* satisfy the function prototype, as in
* numaGetFValue(na, index, (l_float32 *)&ival); [ugly!]
*
* (4) int <--> float conversions:
*
* Tradition dictates that type conversions go automatically from
* l_int32 --> l_float32, even though it is possible to lose
* precision for large integers, whereas you must cast (l_int32)
* to go from l_float32 --> l_int32 because you're truncating
* to the integer value.
*
* (5) As with other arrays in leptonica, the numa has both an allocated
* size and a count of the stored numbers. When you add a number, it
* goes on the end of the array, and causes a realloc if the array
* is already filled. However, in situations where you want to
* add numbers randomly into an array, such as when you build a
* histogram, you must set the count of stored numbers in advance.
* This is done with numaSetCount(). If you set a count larger
* than the allocated array, it does a realloc to the size requested.
*
* (6) In situations where the data in a numa correspond to a function
* y(x), the values can be either at equal spacings in x or at
* arbitrary spacings. For the former, we can represent all x values
* by two parameters: startx (corresponding to y[0]) and delx
* for the change in x for adjacent values y[i] and y[i+1].
* startx and delx are initialized to 0.0 and 1.0, rsp.
* For arbitrary spacings, we use a second numa, and the two
* numas are typically denoted nay and nax.
*
* (7) The numa is also the basic struct used for histograms. Every numa
* has startx and delx fields, initialized to 0.0 and 1.0, that can
* be used to represent the "x" value for the location of the
* first bin and the bin width, respectively. Accessors are the
* numa*Parameters() functions. All functions that make numa
* histograms must set these fields properly, and many functions
* that use numa histograms rely on the correctness of these values.
* </pre>
*/
#include <string.h>
#include <math.h>
#include "allheaders.h"
/* Bounds on initial array size */
static const l_uint32 MaxArraySize = 100000000; /* for numa */
static const l_uint32 MaxPtrArraySize = 10000; /* for numaa */
static const l_int32 InitialArraySize = 50; /*!< n'importe quoi */
/* Static functions */
static l_int32 numaExtendArray(NUMA *na);
static l_int32 numaaExtendArray(NUMAA *naa);
/*--------------------------------------------------------------------------*
* Numa creation, destruction, copy, clone, etc. *
*--------------------------------------------------------------------------*/
/*!
* \brief numaCreate()
*
* \param[in] n size of number array to be alloc'd 0 for default
* \return na, or NULL on error
*/
NUMA *
numaCreate(l_int32 n)
{
NUMA *na;
PROCNAME("numaCreate");
if (n <= 0 || n > MaxArraySize)
n = InitialArraySize;
na = (NUMA *)LEPT_CALLOC(1, sizeof(NUMA));
if ((na->array = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL) {
numaDestroy(&na);
return (NUMA *)ERROR_PTR("number array not made", procName, NULL);
}
na->nalloc = n;
na->n = 0;
na->refcount = 1;
na->startx = 0.0;
na->delx = 1.0;
return na;
}
/*!
* \brief numaCreateFromIArray()
*
* \param[in] iarray integer array
* \param[in] size of the array
* \return na, or NULL on error
*
* <pre>
* Notes:
* (1) We can't insert this int array into the numa, because a numa
* takes a float array. So this just copies the data from the
* input array into the numa. The input array continues to be
* owned by the caller.
* </pre>
*/
NUMA *
numaCreateFromIArray(l_int32 *iarray,
l_int32 size)
{
l_int32 i;
NUMA *na;
PROCNAME("numaCreateFromIArray");
if (!iarray)
return (NUMA *)ERROR_PTR("iarray not defined", procName, NULL);
if (size <= 0)
return (NUMA *)ERROR_PTR("size must be > 0", procName, NULL);
na = numaCreate(size);
for (i = 0; i < size; i++)
numaAddNumber(na, iarray[i]);
return na;
}
/*!
* \brief numaCreateFromFArray()
*
* \param[in] farray float array
* \param[in] size of the array
* \param[in] copyflag L_INSERT or L_COPY
* \return na, or NULL on error
*
* <pre>
* Notes:
* (1) With L_INSERT, ownership of the input array is transferred
* to the returned numa, and all %size elements are considered
* to be valid.
* </pre>
*/
NUMA *
numaCreateFromFArray(l_float32 *farray,
l_int32 size,
l_int32 copyflag)
{
l_int32 i;
NUMA *na;
PROCNAME("numaCreateFromFArray");
if (!farray)
return (NUMA *)ERROR_PTR("farray not defined", procName, NULL);
if (size <= 0)
return (NUMA *)ERROR_PTR("size must be > 0", procName, NULL);
if (copyflag != L_INSERT && copyflag != L_COPY)
return (NUMA *)ERROR_PTR("invalid copyflag", procName, NULL);
na = numaCreate(size);
if (copyflag == L_INSERT) {
if (na->array) LEPT_FREE(na->array);
na->array = farray;
na->n = size;
} else { /* just copy the contents */
for (i = 0; i < size; i++)
numaAddNumber(na, farray[i]);
}
return na;
}
/*!
* \brief numaCreateFromString()
*
* \param[in] str string of comma-separated numbers
* \return na, or NULL on error
*
* <pre>
* Notes:
* (1) The numbers can be ints or floats; they will be interpreted
* and stored as floats. To use them as integers (e.g., for
* indexing into arrays), use numaGetIValue(...).
* </pre>
*/
NUMA *
numaCreateFromString(const char *str)
{
char *substr;
l_int32 i, n, nerrors;
l_float32 val;
NUMA *na;
SARRAY *sa;
PROCNAME("numaCreateFromString");
if (!str || (strlen(str) == 0))
return (NUMA *)ERROR_PTR("str not defined or empty", procName, NULL);
sa = sarrayCreate(0);
sarraySplitString(sa, str, ",");
n = sarrayGetCount(sa);
na = numaCreate(n);
nerrors = 0;
for (i = 0; i < n; i++) {
substr = sarrayGetString(sa, i, L_NOCOPY);
if (sscanf(substr, "%f", &val) != 1) {
L_ERROR("substr %d not float\n", procName, i);
nerrors++;
} else {
numaAddNumber(na, val);
}
}
sarrayDestroy(&sa);
if (nerrors > 0) {
numaDestroy(&na);
return (NUMA *)ERROR_PTR("non-floats in string", procName, NULL);
}
return na;
}
/*!
* \brief numaDestroy()
*
* \param[in,out] pna numa to be destroyed and nulled if it exists
* \return void
*
* <pre>
* Notes:
* (1) Decrements the ref count and, if 0, destroys the numa.
* (2) Always nulls the input ptr.
* </pre>
*/
void
numaDestroy(NUMA **pna)
{
NUMA *na;
PROCNAME("numaDestroy");
if (pna == NULL) {
L_WARNING("ptr address is NULL\n", procName);
return;
}
if ((na = *pna) == NULL)
return;
/* Decrement the ref count. If it is 0, destroy the numa. */
numaChangeRefcount(na, -1);
if (numaGetRefcount(na) <= 0) {
if (na->array)
LEPT_FREE(na->array);
LEPT_FREE(na);
}
*pna = NULL;
return;
}
/*!
* \brief numaCopy()
*
* \param[in] na
* \return copy of numa, or NULL on error
*/
NUMA *
numaCopy(NUMA *na)
{
l_int32 i;
NUMA *cna;
PROCNAME("numaCopy");
if (!na)
return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
if ((cna = numaCreate(na->nalloc)) == NULL)
return (NUMA *)ERROR_PTR("cna not made", procName, NULL);
cna->startx = na->startx;
cna->delx = na->delx;
for (i = 0; i < na->n; i++)
numaAddNumber(cna, na->array[i]);
return cna;
}
/*!
* \brief numaClone()
*
* \param[in] na
* \return ptr to same numa, or NULL on error
*/
NUMA *
numaClone(NUMA *na)
{
PROCNAME("numaClone");
if (!na)
return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
numaChangeRefcount(na, 1);
return na;
}
/*!
* \brief numaEmpty()
*
* \param[in] na
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* (1) This does not change the allocation of the array.
* It just clears the number of stored numbers, so that
* the array appears to be empty.
* </pre>
*/
l_ok
numaEmpty(NUMA *na)
{
PROCNAME("numaEmpty");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->n = 0;
return 0;
}
/*--------------------------------------------------------------------------*
* Number array: add number and extend array *
*--------------------------------------------------------------------------*/
/*!
* \brief numaAddNumber()
*
* \param[in] na
* \param[in] val float or int to be added; stored as a float
* \return 0 if OK, 1 on error
*/
l_ok
numaAddNumber(NUMA *na,
l_float32 val)
{
l_int32 n;
PROCNAME("numaAddNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (n >= na->nalloc)
numaExtendArray(na);
na->array[n] = val;
na->n++;
return 0;
}
/*!
* \brief numaExtendArray()
*
* \param[in] na
* \return 0 if OK, 1 on error
*/
static l_int32
numaExtendArray(NUMA *na)
{
PROCNAME("numaExtendArray");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
sizeof(l_float32) * na->nalloc,
2 * sizeof(l_float32) * na->nalloc)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
na->nalloc *= 2;
return 0;
}
/*!
* \brief numaInsertNumber()
*
* \param[in] na
* \param[in] index location in na to insert new value
* \param[in] val float32 or integer to be added
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This shifts na[i] --> na[i + 1] for all i >= index,
* and then inserts val as na[index].
* (2) It should not be used repeatedly on large arrays,
* because the function is O(n).
*
* </pre>
*/
l_ok
numaInsertNumber(NUMA *na,
l_int32 index,
l_float32 val)
{
l_int32 i, n;
PROCNAME("numaInsertNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index > n)
return ERROR_INT("index not in {0...n}", procName, 1);
if (n >= na->nalloc)
numaExtendArray(na);
for (i = n; i > index; i--)
na->array[i] = na->array[i - 1];
na->array[index] = val;
na->n++;
return 0;
}
/*!
* \brief numaRemoveNumber()
*
* \param[in] na
* \param[in] index element to be removed
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This shifts na[i] --> na[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
numaRemoveNumber(NUMA *na,
l_int32 index)
{
l_int32 i, n;
PROCNAME("numaRemoveNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index >= n)
return ERROR_INT("index not in {0...n - 1}", procName, 1);
for (i = index + 1; i < n; i++)
na->array[i - 1] = na->array[i];
na->n--;
return 0;
}
/*!
* \brief numaReplaceNumber()
*
* \param[in] na
* \param[in] index element to be replaced
* \param[in] val new value to replace old one
* \return 0 if OK, 1 on error
*/
l_ok
numaReplaceNumber(NUMA *na,
l_int32 index,
l_float32 val)
{
l_int32 n;
PROCNAME("numaReplaceNumber");
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
if (index < 0 || index >= n)
return ERROR_INT("index not in {0...n - 1}", procName, 1);
na->array[index] = val;
return 0;
}
/*----------------------------------------------------------------------*
* Numa accessors *
*----------------------------------------------------------------------*/
/*!
* \brief numaGetCount()
*
* \param[in] na
* \return count, or 0 if no numbers or on error
*/
l_int32
numaGetCount(NUMA *na)
{
PROCNAME("numaGetCount");
if (!na)
return ERROR_INT("na not defined", procName, 0);
return na->n;
}
/*!
* \brief numaSetCount()
*
* \param[in] na
* \param[in] newcount
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) If newcount <= na->nalloc, this resets na->n.
* Using newcount = 0 is equivalent to numaEmpty().
* (2) If newcount > na->nalloc, this causes a realloc
* to a size na->nalloc = newcount.
* (3) All the previously unused values in na are set to 0.0.
* </pre>
*/
l_ok
numaSetCount(NUMA *na,
l_int32 newcount)
{
PROCNAME("numaSetCount");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (newcount > na->nalloc) {
if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
sizeof(l_float32) * na->nalloc,
sizeof(l_float32) * newcount)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
na->nalloc = newcount;
}
na->n = newcount;
return 0;
}
/*!
* \brief numaGetFValue()
*
* \param[in] na
* \param[in] index into numa
* \param[out] pval float value; set to 0.0 on error
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* (1) Caller may need to check the function return value to
* decide if a 0.0 in the returned ival is valid.
* </pre>
*/
l_ok
numaGetFValue(NUMA *na,
l_int32 index,
l_float32 *pval)
{
PROCNAME("numaGetFValue");
if (!pval)
return ERROR_INT("&val not defined", procName, 1);
*pval = 0.0;
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
*pval = na->array[index];
return 0;
}
/*!
* \brief numaGetIValue()
*
* \param[in] na
* \param[in] index into numa
* \param[out] pival integer value; set to 0 on error
* \return 0 if OK; 1 on error
*
* <pre>
* Notes:
* (1) Caller may need to check the function return value to
* decide if a 0 in the returned ival is valid.
* </pre>
*/
l_ok
numaGetIValue(NUMA *na,
l_int32 index,
l_int32 *pival)
{
l_float32 val;
PROCNAME("numaGetIValue");
if (!pival)
return ERROR_INT("&ival not defined", procName, 1);
*pival = 0;
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
val = na->array[index];
*pival = (l_int32)(val + L_SIGN(val) * 0.5);
return 0;
}
/*!
* \brief numaSetValue()
*
* \param[in] na
* \param[in] index to element to be set
* \param[in] val to set
* \return 0 if OK; 1 on error
*/
l_ok
numaSetValue(NUMA *na,
l_int32 index,
l_float32 val)
{
PROCNAME("numaSetValue");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
na->array[index] = val;
return 0;
}
/*!
* \brief numaShiftValue()
*
* \param[in] na
* \param[in] index to element to change relative to the current value
* \param[in] diff increment if diff > 0 or decrement if diff < 0
* \return 0 if OK; 1 on error
*/
l_ok
numaShiftValue(NUMA *na,
l_int32 index,
l_float32 diff)
{
PROCNAME("numaShiftValue");
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (index < 0 || index >= na->n)
return ERROR_INT("index not valid", procName, 1);
na->array[index] += diff;
return 0;
}
/*!
* \brief numaGetIArray()
*
* \param[in] na
* \return a copy of the bare internal array, integerized
* by rounding, or NULL on error
* <pre>
* Notes:
* (1) A copy of the array is always made, because we need to
* generate an integer array from the bare float array.
* The caller is responsible for freeing the array.
* (2) The array size is determined by the number of stored numbers,
* not by the size of the allocated array in the Numa.
* (3) This function is provided to simplify calculations
* using the bare internal array, rather than continually
* calling accessors on the numa. It is typically used
* on an array of size 256.
* </pre>
*/
l_int32 *
numaGetIArray(NUMA *na)
{
l_int32 i, n, ival;
l_int32 *array;
PROCNAME("numaGetIArray");
if (!na)
return (l_int32 *)ERROR_PTR("na not defined", procName, NULL);
n = numaGetCount(na);
if ((array = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL)
return (l_int32 *)ERROR_PTR("array not made", procName, NULL);
for (i = 0; i < n; i++) {
numaGetIValue(na, i, &ival);
array[i] = ival;
}
return array;
}
/*!
* \brief numaGetFArray()
*
* \param[in] na
* \param[in] copyflag L_NOCOPY or L_COPY
* \return either the bare internal array or a copy of it,
* or NULL on error
*
* <pre>
* Notes:
* (1) If copyflag == L_COPY, it makes a copy which the caller
* is responsible for freeing. Otherwise, it operates
* directly on the bare array of the numa.
* (2) Very important: for L_NOCOPY, any writes to the array
* will be in the numa. Do not write beyond the size of
* the count field, because it will not be accessible
* from the numa! If necessary, be sure to set the count
* field to a larger number (such as the alloc size)
* BEFORE calling this function. Creating with numaMakeConstant()
* is another way to insure full initialization.
* </pre>
*/
l_float32 *
numaGetFArray(NUMA *na,
l_int32 copyflag)
{
l_int32 i, n;
l_float32 *array;
PROCNAME("numaGetFArray");
if (!na)
return (l_float32 *)ERROR_PTR("na not defined", procName, NULL);
if (copyflag == L_NOCOPY) {
array = na->array;
} else { /* copyflag == L_COPY */
n = numaGetCount(na);
if ((array = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL)
return (l_float32 *)ERROR_PTR("array not made", procName, NULL);
for (i = 0; i < n; i++)
array[i] = na->array[i];
}
return array;
}
/*!
* \brief numaGetRefCount()
*
* \param[in] na
* \return refcount, or UNDEF on error
*/
l_int32
numaGetRefcount(NUMA *na)
{
PROCNAME("numaGetRefcount");
if (!na)
return ERROR_INT("na not defined", procName, UNDEF);
return na->refcount;
}
/*!
* \brief numaChangeRefCount()
*
* \param[in] na
* \param[in] delta change to be applied
* \return 0 if OK, 1 on error
*/
l_ok
numaChangeRefcount(NUMA *na,
l_int32 delta)
{
PROCNAME("numaChangeRefcount");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->refcount += delta;
return 0;
}
/*!
* \brief numaGetParameters()
*
* \param[in] na
* \param[out] pstartx [optional] startx
* \param[out] pdelx [optional] delx
* \return 0 if OK, 1 on error
*/
l_ok
numaGetParameters(NUMA *na,
l_float32 *pstartx,
l_float32 *pdelx)
{
PROCNAME("numaGetParameters");
if (!pdelx && !pstartx)
return ERROR_INT("no return val requested", procName, 1);
if (pstartx) *pstartx = 0.0;
if (pdelx) *pdelx = 1.0;
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (pstartx) *pstartx = na->startx;
if (pdelx) *pdelx = na->delx;
return 0;
}
/*!
* \brief numaSetParameters()
*
* \param[in] na
* \param[in] startx x value corresponding to na[0]
* \param[in] delx difference in x values for the situation where the
* elements of na correspond to the evaulation of a
* function at equal intervals of size %delx
* \return 0 if OK, 1 on error
*/
l_ok
numaSetParameters(NUMA *na,
l_float32 startx,
l_float32 delx)
{
PROCNAME("numaSetParameters");
if (!na)
return ERROR_INT("na not defined", procName, 1);
na->startx = startx;
na->delx = delx;
return 0;
}
/*!
* \brief numaCopyParameters()
*
* \param[in] nad destination Numa
* \param[in] nas source Numa
* \return 0 if OK, 1 on error
*/
l_ok
numaCopyParameters(NUMA *nad,
NUMA *nas)
{
l_float32 start, binsize;
PROCNAME("numaCopyParameters");
if (!nas || !nad)
return ERROR_INT("nas and nad not both defined", procName, 1);
numaGetParameters(nas, &start, &binsize);
numaSetParameters(nad, start, binsize);
return 0;
}
/*----------------------------------------------------------------------*
* Convert to string array *
*----------------------------------------------------------------------*/
/*!
* \brief numaConvertToSarray()
*
* \param[in] na
* \param[in] size1 size of conversion field
* \param[in] size2 for float conversion: size of field to the right
* of the decimal point
* \param[in] addzeros for integer conversion: to add lead zeros
* \param[in] type L_INTEGER_VALUE, L_FLOAT_VALUE
* \return a sarray of the float values converted to strings
* representing either integer or float values; or NULL on error.
*
* <pre>
* Notes:
* (1) For integer conversion, size2 is ignored.
* For float conversion, addzeroes is ignored.
* </pre>
*/
SARRAY *
numaConvertToSarray(NUMA *na,
l_int32 size1,
l_int32 size2,
l_int32 addzeros,
l_int32 type)
{
char fmt[32], strbuf[64];
l_int32 i, n, ival;
l_float32 fval;
SARRAY *sa;
PROCNAME("numaConvertToSarray");
if (!na)
return (SARRAY *)ERROR_PTR("na not defined", procName, NULL);
if (type != L_INTEGER_VALUE && type != L_FLOAT_VALUE)
return (SARRAY *)ERROR_PTR("invalid type", procName, NULL);
if (type == L_INTEGER_VALUE) {
if (addzeros)
snprintf(fmt, sizeof(fmt), "%%0%dd", size1);
else
snprintf(fmt, sizeof(fmt), "%%%dd", size1);
} else { /* L_FLOAT_VALUE */
snprintf(fmt, sizeof(fmt), "%%%d.%df", size1, size2);
}
n = numaGetCount(na);
if ((sa = sarrayCreate(n)) == NULL)
return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
for (i = 0; i < n; i++) {
if (type == L_INTEGER_VALUE) {
numaGetIValue(na, i, &ival);
snprintf(strbuf, sizeof(strbuf), fmt, ival);
} else { /* L_FLOAT_VALUE */
numaGetFValue(na, i, &fval);
snprintf(strbuf, sizeof(strbuf), fmt, fval);
}
sarrayAddString(sa, strbuf, L_COPY);
}
return sa;
}
/*----------------------------------------------------------------------*
* Serialize numa for I/O *
*----------------------------------------------------------------------*/
/*!
* \brief numaRead()
*
* \param[in] filename
* \return na, or NULL on error
*/
NUMA *
numaRead(const char *filename)
{
FILE *fp;
NUMA *na;
PROCNAME("numaRead");
if (!filename)
return (NUMA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
na = numaReadStream(fp);
fclose(fp);
if (!na)
return (NUMA *)ERROR_PTR("na not read", procName, NULL);
return na;
}
/*!
* \brief numaReadStream()
*
* \param[in] fp file stream
* \return numa, or NULL on error
*/
NUMA *
numaReadStream(FILE *fp)
{
l_int32 i, n, index, ret, version;
l_float32 val, startx, delx;
NUMA *na;
PROCNAME("numaReadStream");
if (!fp)
return (NUMA *)ERROR_PTR("stream not defined", procName, NULL);
ret = fscanf(fp, "\nNuma Version %d\n", &version);
if (ret != 1)
return (NUMA *)ERROR_PTR("not a numa file", procName, NULL);
if (version != NUMA_VERSION_NUMBER)
return (NUMA *)ERROR_PTR("invalid numa version", procName, NULL);
if (fscanf(fp, "Number of numbers = %d\n", &n) != 1)
return (NUMA *)ERROR_PTR("invalid number of numbers", procName, NULL);
if (n > MaxArraySize) {
L_ERROR("n = %d > %d\n", procName, n, MaxArraySize);
return NULL;
}
if ((na = numaCreate(n)) == NULL)
return (NUMA *)ERROR_PTR("na not made", procName, NULL);
for (i = 0; i < n; i++) {
if (fscanf(fp, " [%d] = %f\n", &index, &val) != 2) {
numaDestroy(&na);
return (NUMA *)ERROR_PTR("bad input data", procName, NULL);
}
numaAddNumber(na, val);
}
/* Optional data */
if (fscanf(fp, "startx = %f, delx = %f\n", &startx, &delx) == 2)
numaSetParameters(na, startx, delx);
return na;
}
/*!
* \brief numaReadMem()
*
* \param[in] data numa serialization; in ascii
* \param[in] size of data; can use strlen to get it
* \return na, or NULL on error
*/
NUMA *
numaReadMem(const l_uint8 *data,
size_t size)
{
FILE *fp;
NUMA *na;
PROCNAME("numaReadMem");
if (!data)
return (NUMA *)ERROR_PTR("data not defined", procName, NULL);
if ((fp = fopenReadFromMemory(data, size)) == NULL)
return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
na = numaReadStream(fp);
fclose(fp);
if (!na) L_ERROR("numa not read\n", procName);
return na;
}
/*!
* \brief numaWriteDebug()
*
* \param[in] filename
* \param[in] na
* \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 numaWrite() 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
numaWriteDebug(const char *filename,
NUMA *na)
{
PROCNAME("numaWriteDebug");
if (LeptDebugOK) {
return numaWrite(filename, na);
} else {
L_INFO("write to named temp file %s is disabled\n", procName, filename);
return 0;
}
}
/*!
* \brief numaWrite()
*
* \param[in] filename
* \param[in] na
* \return 0 if OK, 1 on error
*/
l_ok
numaWrite(const char *filename,
NUMA *na)
{
l_int32 ret;
FILE *fp;
PROCNAME("numaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
if ((fp = fopenWriteStream(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = numaWriteStream(fp, na);
fclose(fp);
if (ret)
return ERROR_INT("na not written to stream", procName, 1);
return 0;
}
/*!
* \brief numaWriteStream()
*
* \param[in] fp file stream
* \param[in] na
* \return 0 if OK, 1 on error
*/
l_ok
numaWriteStream(FILE *fp,
NUMA *na)
{
l_int32 i, n;
l_float32 startx, delx;
PROCNAME("numaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaGetCount(na);
fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER);
fprintf(fp, "Number of numbers = %d\n", n);
for (i = 0; i < n; i++)
fprintf(fp, " [%d] = %f\n", i, na->array[i]);
fprintf(fp, "\n");
/* Optional data */
numaGetParameters(na, &startx, &delx);
if (startx != 0.0 || delx != 1.0)
fprintf(fp, "startx = %f, delx = %f\n", startx, delx);
return 0;
}
/*!
* \brief numaWriteMem()
*
* \param[out] pdata data of serialized numa; ascii
* \param[out] psize size of returned data
* \param[in] na
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Serializes a numa in memory and puts the result in a buffer.
* </pre>
*/
l_ok
numaWriteMem(l_uint8 **pdata,
size_t *psize,
NUMA *na)
{
l_int32 ret;
FILE *fp;
PROCNAME("numaWriteMem");
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 (!na)
return ERROR_INT("na not defined", procName, 1);
#if HAVE_FMEMOPEN
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = numaWriteStream(fp, na);
#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 = numaWriteStream(fp, na);
rewind(fp);
*pdata = l_binaryReadStream(fp, psize);
#endif /* HAVE_FMEMOPEN */
fclose(fp);
return ret;
}
/*--------------------------------------------------------------------------*
* Numaa creation, destruction *
*--------------------------------------------------------------------------*/
/*!
* \brief numaaCreate()
*
* \param[in] n size of numa ptr array to be alloc'd 0 for default
* \return naa, or NULL on error
*
*/
NUMAA *
numaaCreate(l_int32 n)
{
NUMAA *naa;
PROCNAME("numaaCreate");
if (n <= 0 || n > MaxPtrArraySize)
n = InitialArraySize;
naa = (NUMAA *)LEPT_CALLOC(1, sizeof(NUMAA));
if ((naa->numa = (NUMA **)LEPT_CALLOC(n, sizeof(NUMA *))) == NULL) {
numaaDestroy(&naa);
return (NUMAA *)ERROR_PTR("numa ptr array not made", procName, NULL);
}
naa->nalloc = n;
naa->n = 0;
return naa;
}
/*!
* \brief numaaCreateFull()
*
* \param[in] nptr size of numa ptr array to be alloc'd
* \param[in] n size of individual numa arrays to be allocated
* to 0 for default
* \return naa, or NULL on error
*
* <pre>
* Notes:
* (1) This allocates numaa and fills the array with allocated numas.
* In use, after calling this function, use
* numaaAddNumber(naa, index, val);
* to add val to the index-th numa in naa.
* </pre>
*/
NUMAA *
numaaCreateFull(l_int32 nptr,
l_int32 n)
{
l_int32 i;
NUMAA *naa;
NUMA *na;
naa = numaaCreate(nptr);
for (i = 0; i < nptr; i++) {
na = numaCreate(n);
numaaAddNuma(naa, na, L_INSERT);
}
return naa;
}
/*!
* \brief numaaTruncate()
*
* \param[in] naa
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This identifies the largest index containing a numa that
* has any numbers within it, destroys all numa beyond that
* index, and resets the count.
* </pre>
*/
l_ok
numaaTruncate(NUMAA *naa)
{
l_int32 i, n, nn;
NUMA *na;
PROCNAME("numaaTruncate");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
for (i = n - 1; i >= 0; i--) {
na = numaaGetNuma(naa, i, L_CLONE);
if (!na)
continue;
nn = numaGetCount(na);
numaDestroy(&na);
if (nn == 0)
numaDestroy(&naa->numa[i]);
else
break;
}
naa->n = i + 1;
return 0;
}
/*!
* \brief numaaDestroy()
*
* \param[in,out] pnaa to be destroyed and nulled, if it exists
* \return void
*/
void
numaaDestroy(NUMAA **pnaa)
{
l_int32 i;
NUMAA *naa;
PROCNAME("numaaDestroy");
if (pnaa == NULL) {
L_WARNING("ptr address is NULL!\n", procName);
return;
}
if ((naa = *pnaa) == NULL)
return;
for (i = 0; i < naa->n; i++)
numaDestroy(&naa->numa[i]);
LEPT_FREE(naa->numa);
LEPT_FREE(naa);
*pnaa = NULL;
return;
}
/*--------------------------------------------------------------------------*
* Add Numa to Numaa *
*--------------------------------------------------------------------------*/
/*!
* \brief numaaAddNuma()
*
* \param[in] naa
* \param[in] na to be added
* \param[in] copyflag L_INSERT, L_COPY, L_CLONE
* \return 0 if OK, 1 on error
*/
l_ok
numaaAddNuma(NUMAA *naa,
NUMA *na,
l_int32 copyflag)
{
l_int32 n;
NUMA *nac;
PROCNAME("numaaAddNuma");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
if (copyflag == L_INSERT) {
nac = na;
} else if (copyflag == L_COPY) {
if ((nac = numaCopy(na)) == NULL)
return ERROR_INT("nac not made", procName, 1);
} else if (copyflag == L_CLONE) {
nac = numaClone(na);
} else {
return ERROR_INT("invalid copyflag", procName, 1);
}
n = numaaGetCount(naa);
if (n >= naa->nalloc)
numaaExtendArray(naa);
naa->numa[n] = nac;
naa->n++;
return 0;
}
/*!
* \brief numaaExtendArray()
*
* \param[in] naa
* \return 0 if OK, 1 on error
*/
static l_int32
numaaExtendArray(NUMAA *naa)
{
PROCNAME("numaaExtendArray");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if ((naa->numa = (NUMA **)reallocNew((void **)&naa->numa,
sizeof(NUMA *) * naa->nalloc,
2 * sizeof(NUMA *) * naa->nalloc)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
naa->nalloc *= 2;
return 0;
}
/*----------------------------------------------------------------------*
* Numaa accessors *
*----------------------------------------------------------------------*/
/*!
* \brief numaaGetCount()
*
* \param[in] naa
* \return count number of numa, or 0 if no numa or on error
*/
l_int32
numaaGetCount(NUMAA *naa)
{
PROCNAME("numaaGetCount");
if (!naa)
return ERROR_INT("naa not defined", procName, 0);
return naa->n;
}
/*!
* \brief numaaGetNumaCount()
*
* \param[in] naa
* \param[in] index of numa in naa
* \return count of numbers in the referenced numa, or 0 on error.
*/
l_int32
numaaGetNumaCount(NUMAA *naa,
l_int32 index)
{
PROCNAME("numaaGetNumaCount");
if (!naa)
return ERROR_INT("naa not defined", procName, 0);
if (index < 0 || index >= naa->n)
return ERROR_INT("invalid index into naa", procName, 0);
return numaGetCount(naa->numa[index]);
}
/*!
* \brief numaaGetNumberCount()
*
* \param[in] naa
* \return count total number of numbers in the numaa,
* or 0 if no numbers or on error
*/
l_int32
numaaGetNumberCount(NUMAA *naa)
{
NUMA *na;
l_int32 n, sum, i;
PROCNAME("numaaGetNumberCount");
if (!naa)
return ERROR_INT("naa not defined", procName, 0);
n = numaaGetCount(naa);
for (sum = 0, i = 0; i < n; i++) {
na = numaaGetNuma(naa, i, L_CLONE);
sum += numaGetCount(na);
numaDestroy(&na);
}
return sum;
}
/*!
* \brief numaaGetPtrArray()
*
* \param[in] naa
* \return the internal array of ptrs to Numa, or NULL on error
*
* <pre>
* Notes:
* (1) This function is convenient for doing direct manipulation on
* a fixed size array of Numas. To do this, it sets the count
* to the full size of the allocated array of Numa ptrs.
* The originating Numaa owns this array: DO NOT free it!
* (2) Intended usage:
* Numaa *naa = numaaCreate(n);
* Numa **array = numaaGetPtrArray(naa);
* ... [manipulate Numas directly on the array]
* numaaDestroy(&naa);
* (3) Cautions:
* ~ Do not free this array; it is owned by tne Numaa.
* ~ Do not call any functions on the Numaa, other than
* numaaDestroy() when you're finished with the array.
* Adding a Numa will force a resize, destroying the ptr array.
* ~ Do not address the array outside its allocated size.
* With the bare array, there are no protections. If the
* allocated size is n, array[n] is an error.
* </pre>
*/
NUMA **
numaaGetPtrArray(NUMAA *naa)
{
PROCNAME("numaaGetPtrArray");
if (!naa)
return (NUMA **)ERROR_PTR("naa not defined", procName, NULL);
naa->n = naa->nalloc;
return naa->numa;
}
/*!
* \brief numaaGetNuma()
*
* \param[in] naa
* \param[in] index to the index-th numa
* \param[in] accessflag L_COPY or L_CLONE
* \return numa, or NULL on error
*/
NUMA *
numaaGetNuma(NUMAA *naa,
l_int32 index,
l_int32 accessflag)
{
PROCNAME("numaaGetNuma");
if (!naa)
return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
if (index < 0 || index >= naa->n)
return (NUMA *)ERROR_PTR("index not valid", procName, NULL);
if (accessflag == L_COPY)
return numaCopy(naa->numa[index]);
else if (accessflag == L_CLONE)
return numaClone(naa->numa[index]);
else
return (NUMA *)ERROR_PTR("invalid accessflag", procName, NULL);
}
/*!
* \brief numaaReplaceNuma()
*
* \param[in] naa
* \param[in] index to the index-th numa
* \param[in] na insert and replace any existing one
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Any existing numa is destroyed, and the input one
* is inserted in its place.
* (2) If the index is invalid, return 1 (error)
* </pre>
*/
l_ok
numaaReplaceNuma(NUMAA *naa,
l_int32 index,
NUMA *na)
{
l_int32 n;
PROCNAME("numaaReplaceNuma");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if (!na)
return ERROR_INT("na not defined", procName, 1);
n = numaaGetCount(naa);
if (index < 0 || index >= n)
return ERROR_INT("index not valid", procName, 1);
numaDestroy(&naa->numa[index]);
naa->numa[index] = na;
return 0;
}
/*!
* \brief numaaGetValue()
*
* \param[in] naa
* \param[in] i index of numa within numaa
* \param[in] j index into numa
* \param[out] pfval [optional] float value
* \param[out] pival [optional] int value
* \return 0 if OK, 1 on error
*/
l_ok
numaaGetValue(NUMAA *naa,
l_int32 i,
l_int32 j,
l_float32 *pfval,
l_int32 *pival)
{
l_int32 n;
NUMA *na;
PROCNAME("numaaGetValue");
if (!pfval && !pival)
return ERROR_INT("no return val requested", procName, 1);
if (pfval) *pfval = 0.0;
if (pival) *pival = 0;
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
if (i < 0 || i >= n)
return ERROR_INT("invalid index into naa", procName, 1);
na = naa->numa[i];
if (j < 0 || j >= na->n)
return ERROR_INT("invalid index into na", procName, 1);
if (pfval) *pfval = na->array[j];
if (pival) *pival = (l_int32)(na->array[j]);
return 0;
}
/*!
* \brief numaaAddNumber()
*
* \param[in] naa
* \param[in] index of numa within numaa
* \param[in] val float or int to be added; stored as a float
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Adds to an existing numa only.
* </pre>
*/
l_ok
numaaAddNumber(NUMAA *naa,
l_int32 index,
l_float32 val)
{
l_int32 n;
NUMA *na;
PROCNAME("numaaAddNumber");
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
if (index < 0 || index >= n)
return ERROR_INT("invalid index in naa", procName, 1);
na = numaaGetNuma(naa, index, L_CLONE);
numaAddNumber(na, val);
numaDestroy(&na);
return 0;
}
/*----------------------------------------------------------------------*
* Serialize numaa for I/O *
*----------------------------------------------------------------------*/
/*!
* \brief numaaRead()
*
* \param[in] filename
* \return naa, or NULL on error
*/
NUMAA *
numaaRead(const char *filename)
{
FILE *fp;
NUMAA *naa;
PROCNAME("numaaRead");
if (!filename)
return (NUMAA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
naa = numaaReadStream(fp);
fclose(fp);
if (!naa)
return (NUMAA *)ERROR_PTR("naa not read", procName, NULL);
return naa;
}
/*!
* \brief numaaReadStream()
*
* \param[in] fp file stream
* \return naa, or NULL on error
*/
NUMAA *
numaaReadStream(FILE *fp)
{
l_int32 i, n, index, ret, version;
NUMA *na;
NUMAA *naa;
PROCNAME("numaaReadStream");
if (!fp)
return (NUMAA *)ERROR_PTR("stream not defined", procName, NULL);
ret = fscanf(fp, "\nNumaa Version %d\n", &version);
if (ret != 1)
return (NUMAA *)ERROR_PTR("not a numa file", procName, NULL);
if (version != NUMA_VERSION_NUMBER)
return (NUMAA *)ERROR_PTR("invalid numaa version", procName, NULL);
if (fscanf(fp, "Number of numa = %d\n\n", &n) != 1)
return (NUMAA *)ERROR_PTR("invalid number of numa", procName, NULL);
if (n > MaxPtrArraySize) {
L_ERROR("n = %d > %d\n", procName, n, MaxPtrArraySize);
return NULL;
}
if ((naa = numaaCreate(n)) == NULL)
return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
for (i = 0; i < n; i++) {
if (fscanf(fp, "Numa[%d]:", &index) != 1) {
numaaDestroy(&naa);
return (NUMAA *)ERROR_PTR("invalid numa header", procName, NULL);
}
if ((na = numaReadStream(fp)) == NULL) {
numaaDestroy(&naa);
return (NUMAA *)ERROR_PTR("na not made", procName, NULL);
}
numaaAddNuma(naa, na, L_INSERT);
}
return naa;
}
/*!
* \brief numaaReadMem()
*
* \param[in] data numaa serialization; in ascii
* \param[in] size of data; can use strlen to get it
* \return naa, or NULL on error
*/
NUMAA *
numaaReadMem(const l_uint8 *data,
size_t size)
{
FILE *fp;
NUMAA *naa;
PROCNAME("numaaReadMem");
if (!data)
return (NUMAA *)ERROR_PTR("data not defined", procName, NULL);
if ((fp = fopenReadFromMemory(data, size)) == NULL)
return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
naa = numaaReadStream(fp);
fclose(fp);
if (!naa) L_ERROR("naa not read\n", procName);
return naa;
}
/*!
* \brief numaaWrite()
*
* \param[in] filename
* \param[in] naa
* \return 0 if OK, 1 on error
*/
l_ok
numaaWrite(const char *filename,
NUMAA *naa)
{
l_int32 ret;
FILE *fp;
PROCNAME("numaaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
if ((fp = fopenWriteStream(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = numaaWriteStream(fp, naa);
fclose(fp);
if (ret)
return ERROR_INT("naa not written to stream", procName, 1);
return 0;
}
/*!
* \brief numaaWriteStream()
*
* \param[in] fp file stream
* \param[in] naa
* \return 0 if OK, 1 on error
*/
l_ok
numaaWriteStream(FILE *fp,
NUMAA *naa)
{
l_int32 i, n;
NUMA *na;
PROCNAME("numaaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!naa)
return ERROR_INT("naa not defined", procName, 1);
n = numaaGetCount(naa);
fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
fprintf(fp, "Number of numa = %d\n\n", n);
for (i = 0; i < n; i++) {
if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
return ERROR_INT("na not found", procName, 1);
fprintf(fp, "Numa[%d]:", i);
numaWriteStream(fp, na);
numaDestroy(&na);
}
return 0;
}
/*!
* \brief numaaWriteMem()
*
* \param[out] pdata data of serialized numaa; ascii
* \param[out] psize size of returned data
* \param[in] naa
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Serializes a numaa in memory and puts the result in a buffer.
* </pre>
*/
l_ok
numaaWriteMem(l_uint8 **pdata,
size_t *psize,
NUMAA *naa)
{
l_int32 ret;
FILE *fp;
PROCNAME("numaaWriteMem");
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 (!naa)
return ERROR_INT("naa not defined", procName, 1);
#if HAVE_FMEMOPEN
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = numaaWriteStream(fp, naa);
#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 = numaaWriteStream(fp, naa);
rewind(fp);
*pdata = l_binaryReadStream(fp, psize);
#endif /* HAVE_FMEMOPEN */
fclose(fp);
return ret;
}