Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/leptonica/src/dnabasic.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/leptonica/src/dnabasic.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,1807 @@ +/*====================================================================* + - 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 dnabasic.c + * <pre> + * + * Dna creation, destruction, copy, clone, etc. + * L_DNA *l_dnaCreate() + * L_DNA *l_dnaCreateFromIArray() + * L_DNA *l_dnaCreateFromDArray() + * L_DNA *l_dnaMakeSequence() + * void *l_dnaDestroy() + * L_DNA *l_dnaCopy() + * L_DNA *l_dnaClone() + * l_int32 l_dnaEmpty() + * + * Dna: add/remove number and extend array + * l_int32 l_dnaAddNumber() + * static l_int32 l_dnaExtendArray() + * l_int32 l_dnaInsertNumber() + * l_int32 l_dnaRemoveNumber() + * l_int32 l_dnaReplaceNumber() + * + * Dna accessors + * l_int32 l_dnaGetCount() + * l_int32 l_dnaSetCount() + * l_int32 l_dnaGetIValue() + * l_int32 l_dnaGetDValue() + * l_int32 l_dnaSetValue() + * l_int32 l_dnaShiftValue() + * l_int32 *l_dnaGetIArray() + * l_float64 *l_dnaGetDArray() + * l_int32 l_dnaGetParameters() + * l_int32 l_dnaSetParameters() + * l_int32 l_dnaCopyParameters() + * + * Serialize Dna for I/O + * L_DNA *l_dnaRead() + * L_DNA *l_dnaReadStream() + * L_DNA *l_dnaReadMem() + * l_int32 l_dnaWrite() + * l_int32 l_dnaWriteStream() + * l_int32 l_dnaWriteStderr() + * l_int32 l_dnaWriteMem() + * + * Dnaa creation, destruction + * L_DNAA *l_dnaaCreate() + * L_DNAA *l_dnaaCreateFull() + * l_int32 l_dnaaTruncate() + * void *l_dnaaDestroy() + * + * Add Dna to Dnaa + * l_int32 l_dnaaAddDna() + * static l_int32 l_dnaaExtendArray() + * + * Dnaa accessors + * l_int32 l_dnaaGetCount() + * l_int32 l_dnaaGetDnaCount() + * l_int32 l_dnaaGetNumberCount() + * L_DNA *l_dnaaGetDna() + * L_DNA *l_dnaaReplaceDna() + * l_int32 l_dnaaGetValue() + * l_int32 l_dnaaAddNumber() + * + * Serialize Dnaa for I/O + * L_DNAA *l_dnaaRead() + * L_DNAA *l_dnaaReadStream() + * L_DNAA *l_dnaaReadMem() + * l_int32 l_dnaaWrite() + * l_int32 l_dnaaWriteStream() + * l_int32 l_dnaaWriteMem() + * + * (1) The Dna is a struct holding an array of doubles. It can also + * be used to store l_int32 values, up to the full precision + * of int32. Always use it whenever 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 l_dnaAddNumber(). If + * the number is an int, it will will automatically be converted + * to l_float64 and stored. + * + * * to reset a value stored in the array, use l_dnaSetValue(). + * + * * to increment or decrement a value stored in the array, + * use l_dnaShiftValue(). + * + * * to obtain a value from the array, use either l_dnaGetIValue() + * or l_dnaGetDValue(), depending on whether you are retrieving + * an integer or a float64. This avoids doing an explicit cast, + * such as + * (a) return a l_float64 and cast it to an l_int32 + * (b) cast the return directly to (l_float64 *) to + * satisfy the function prototype, as in + * l_dnaGetDValue(da, index, (l_float64 *)&ival); [ugly!] + * + * (4) int <--> double conversions: + * + * Conversions go automatically from l_int32 --> l_float64, + * without loss of precision. You must cast (l_int32) + * to go from l_float64 --> l_int32 because you're truncating + * to the integer value. + * + * (5) As with other arrays in leptonica, the l_dna 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 l_dnaSetCount(). 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 l_dna 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 l_dna, and the two + * l_dnas are typically denoted dnay and dnax. + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <math.h> +#include "allheaders.h" +#include "array_internal.h" + + /* Bounds on initial array size */ +static const l_uint32 MaxDoubleArraySize = 100000000; /* for dna */ +static const l_uint32 MaxPtrArraySize = 1000000; /* for dnaa */ +static const l_int32 InitialArraySize = 50; /*!< n'importe quoi */ + + /* Static functions */ +static l_int32 l_dnaExtendArray(L_DNA *da); +static l_int32 l_dnaaExtendArray(L_DNAA *daa); + +/*--------------------------------------------------------------------------* + * Dna creation, destruction, copy, clone, etc. * + *--------------------------------------------------------------------------*/ +/*! + * \brief l_dnaCreate() + * + * \param[in] n size of number array to be alloc'd; 0 for default + * \return da, or NULL on error + */ +L_DNA * +l_dnaCreate(l_int32 n) +{ +L_DNA *da; + + if (n <= 0 || n > MaxDoubleArraySize) + n = InitialArraySize; + + da = (L_DNA *)LEPT_CALLOC(1, sizeof(L_DNA)); + if ((da->array = (l_float64 *)LEPT_CALLOC(n, sizeof(l_float64))) == NULL) { + l_dnaDestroy(&da); + return (L_DNA *)ERROR_PTR("double array not made", __func__, NULL); + } + + da->nalloc = n; + da->n = 0; + da->refcount = 1; + da->startx = 0.0; + da->delx = 1.0; + + return da; +} + + +/*! + * \brief l_dnaCreateFromIArray() + * + * \param[in] iarray integer array + * \param[in] size of the array + * \return da, or NULL on error + * + * <pre> + * Notes: + * (1) We can't insert this int array into the l_dna, because a l_dna + * takes a double array. So this just copies the data from the + * input array into the l_dna. The input array continues to be + * owned by the caller. + * </pre> + */ +L_DNA * +l_dnaCreateFromIArray(l_int32 *iarray, + l_int32 size) +{ +l_int32 i; +L_DNA *da; + + if (!iarray) + return (L_DNA *)ERROR_PTR("iarray not defined", __func__, NULL); + if (size <= 0) + return (L_DNA *)ERROR_PTR("size must be > 0", __func__, NULL); + + da = l_dnaCreate(size); + for (i = 0; i < size; i++) + l_dnaAddNumber(da, iarray[i]); + + return da; +} + + +/*! + * \brief l_dnaCreateFromDArray() + * + * \param[in] darray float + * \param[in] size of the array + * \param[in] copyflag L_INSERT or L_COPY + * \return da, or NULL on error + * + * <pre> + * Notes: + * (1) With L_INSERT, ownership of the input array is transferred + * to the returned l_dna, and all %size elements are considered + * to be valid. + * </pre> + */ +L_DNA * +l_dnaCreateFromDArray(l_float64 *darray, + l_int32 size, + l_int32 copyflag) +{ +l_int32 i; +L_DNA *da; + + if (!darray) + return (L_DNA *)ERROR_PTR("darray not defined", __func__, NULL); + if (size <= 0) + return (L_DNA *)ERROR_PTR("size must be > 0", __func__, NULL); + if (copyflag != L_INSERT && copyflag != L_COPY) + return (L_DNA *)ERROR_PTR("invalid copyflag", __func__, NULL); + + da = l_dnaCreate(size); + if (copyflag == L_INSERT) { + if (da->array) LEPT_FREE(da->array); + da->array = darray; + da->n = size; + } else { /* just copy the contents */ + for (i = 0; i < size; i++) + l_dnaAddNumber(da, darray[i]); + } + + return da; +} + + +/*! + * \brief l_dnaMakeSequence() + * + * \param[in] startval + * \param[in] increment + * \param[in] size of sequence + * \return l_dna of sequence of evenly spaced values, or NULL on error + */ +L_DNA * +l_dnaMakeSequence(l_float64 startval, + l_float64 increment, + l_int32 size) +{ +l_int32 i; +l_float64 val; +L_DNA *da; + + if ((da = l_dnaCreate(size)) == NULL) + return (L_DNA *)ERROR_PTR("da not made", __func__, NULL); + + for (i = 0; i < size; i++) { + val = startval + i * increment; + l_dnaAddNumber(da, val); + } + + return da; +} + + +/*! + * \brief l_dnaDestroy() + * + * \param[in,out] pda will be set to null before returning + * \return void + * + * <pre> + * Notes: + * (1) Decrements the ref count and, if 0, destroys the l_dna. + * (2) Always nulls the input ptr. + * </pre> + */ +void +l_dnaDestroy(L_DNA **pda) +{ +L_DNA *da; + + if (pda == NULL) { + L_WARNING("ptr address is NULL\n", __func__); + return; + } + + if ((da = *pda) == NULL) + return; + + /* Decrement the ref count. If it is 0, destroy the l_dna. */ + if (--da->refcount == 0) { + if (da->array) + LEPT_FREE(da->array); + LEPT_FREE(da); + } + *pda = NULL; +} + + +/*! + * \brief l_dnaCopy() + * + * \param[in] da + * \return copy of da, or NULL on error + * + * <pre> + * Notes: + * (1) This removes unused ptrs above da->n. + * </pre> + */ +L_DNA * +l_dnaCopy(L_DNA *da) +{ +l_int32 i; +L_DNA *dac; + + if (!da) + return (L_DNA *)ERROR_PTR("da not defined", __func__, NULL); + + if ((dac = l_dnaCreate(da->n)) == NULL) + return (L_DNA *)ERROR_PTR("dac not made", __func__, NULL); + dac->startx = da->startx; + dac->delx = da->delx; + + for (i = 0; i < da->n; i++) + l_dnaAddNumber(dac, da->array[i]); + + return dac; +} + + +/*! + * \brief l_dnaClone() + * + * \param[in] da + * \return ptr to same da, or NULL on error + */ +L_DNA * +l_dnaClone(L_DNA *da) +{ + if (!da) + return (L_DNA *)ERROR_PTR("da not defined", __func__, NULL); + + ++da->refcount; + return da; +} + + +/*! + * \brief l_dnaEmpty() + * + * \param[in] da + * \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 +l_dnaEmpty(L_DNA *da) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + da->n = 0; + return 0; +} + + + +/*--------------------------------------------------------------------------* + * Dna: add/remove number and extend array * + *--------------------------------------------------------------------------*/ +/*! + * \brief l_dnaAddNumber() + * + * \param[in] da + * \param[in] val float or int to be added; stored as a float + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaAddNumber(L_DNA *da, + l_float64 val) +{ +l_int32 n; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + n = l_dnaGetCount(da); + if (n >= da->nalloc) { + if (l_dnaExtendArray(da)) + return ERROR_INT("extension failed", __func__, 1); + } + da->array[n] = val; + da->n++; + return 0; +} + + +/*! + * \brief l_dnaExtendArray() + * + * \param[in] da + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Doubles the size of the array. + * (2) The max number of doubles is 100M. + * </pre> + */ +static l_int32 +l_dnaExtendArray(L_DNA *da) +{ +size_t oldsize, newsize; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + if (da->nalloc > MaxDoubleArraySize) + return ERROR_INT("da at maximum size; can't extend", __func__, 1); + oldsize = da->nalloc * sizeof(l_float64); + if (da->nalloc > MaxDoubleArraySize / 2) { + newsize = MaxDoubleArraySize * sizeof(l_float64); + da->nalloc = MaxDoubleArraySize; + } else { + newsize = 2 * oldsize; + da->nalloc *= 2; + } + if ((da->array = (l_float64 *)reallocNew((void **)&da->array, + oldsize, newsize)) == NULL) + return ERROR_INT("new ptr array not returned", __func__, 1); + + return 0; +} + + +/*! + * \brief l_dnaInsertNumber() + * + * \param[in] da + * \param[in] index location in da to insert new value + * \param[in] val float64 or integer to be added + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This shifts da[i] --> da[i + 1] for all i >= %index, + * and then inserts %val as da[%index]. + * (2) It should not be used repeatedly on large arrays, + * because the function is O(n). + * + * </pre> + */ +l_ok +l_dnaInsertNumber(L_DNA *da, + l_int32 index, + l_float64 val) +{ +l_int32 i, n; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + n = l_dnaGetCount(da); + if (index < 0 || index > n) { + L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n); + return 1; + } + + if (n >= da->nalloc) { + if (l_dnaExtendArray(da)) + return ERROR_INT("extension failed", __func__, 1); + } + for (i = n; i > index; i--) + da->array[i] = da->array[i - 1]; + da->array[index] = val; + da->n++; + return 0; +} + + +/*! + * \brief l_dnaRemoveNumber() + * + * \param[in] da + * \param[in] index element to be removed + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This shifts da[i] --> da[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 +l_dnaRemoveNumber(L_DNA *da, + l_int32 index) +{ +l_int32 i, n; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + n = l_dnaGetCount(da); + if (index < 0 || index >= n) { + L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n - 1); + return 1; + } + + for (i = index + 1; i < n; i++) + da->array[i - 1] = da->array[i]; + da->n--; + return 0; +} + + +/*! + * \brief l_dnaReplaceNumber() + * + * \param[in] da + * \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 +l_dnaReplaceNumber(L_DNA *da, + l_int32 index, + l_float64 val) +{ +l_int32 n; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + n = l_dnaGetCount(da); + if (index < 0 || index >= n) { + L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n - 1); + return 1; + } + + da->array[index] = val; + return 0; +} + + +/*----------------------------------------------------------------------* + * Dna accessors * + *----------------------------------------------------------------------*/ +/*! + * \brief l_dnaGetCount() + * + * \param[in] da + * \return count, or 0 if no numbers or on error + */ +l_int32 +l_dnaGetCount(L_DNA *da) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 0); + return da->n; +} + + +/*! + * \brief l_dnaSetCount() + * + * \param[in] da + * \param[in] newcount + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) If %newcount <= da->nalloc, this resets da->n. + * Using %newcount = 0 is equivalent to l_dnaEmpty(). + * (2) If %newcount > da->nalloc, this causes a realloc + * to a size da->nalloc = %newcount. + * (3) All the previously unused values in da are set to 0.0. + * </pre> + */ +l_ok +l_dnaSetCount(L_DNA *da, + l_int32 newcount) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 1); + if (newcount > da->nalloc) { + if ((da->array = (l_float64 *)reallocNew((void **)&da->array, + sizeof(l_float64) * da->nalloc, + sizeof(l_float64) * newcount)) == NULL) + return ERROR_INT("new ptr array not returned", __func__, 1); + da->nalloc = newcount; + } + da->n = newcount; + return 0; +} + + +/*! + * \brief l_dnaGetDValue() + * + * \param[in] da + * \param[in] index into l_dna + * \param[out] pval double value; 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 +l_dnaGetDValue(L_DNA *da, + l_int32 index, + l_float64 *pval) +{ + if (!pval) + return ERROR_INT("&val not defined", __func__, 1); + *pval = 0.0; + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + if (index < 0 || index >= da->n) + return ERROR_INT("index not valid", __func__, 1); + + *pval = da->array[index]; + return 0; +} + + +/*! + * \brief l_dnaGetIValue() + * + * \param[in] da + * \param[in] index into l_dna + * \param[out] pival integer value; 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 +l_dnaGetIValue(L_DNA *da, + l_int32 index, + l_int32 *pival) +{ +l_float64 val; + + if (!pival) + return ERROR_INT("&ival not defined", __func__, 1); + *pival = 0; + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + if (index < 0 || index >= da->n) + return ERROR_INT("index not valid", __func__, 1); + + val = da->array[index]; + *pival = (l_int32)(val + L_SIGN(val) * 0.5); + return 0; +} + + +/*! + * \brief l_dnaSetValue() + * + * \param[in] da + * \param[in] index to element to be set + * \param[in] val to set element + * \return 0 if OK; 1 on error + */ +l_ok +l_dnaSetValue(L_DNA *da, + l_int32 index, + l_float64 val) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 1); + if (index < 0 || index >= da->n) + return ERROR_INT("index not valid", __func__, 1); + + da->array[index] = val; + return 0; +} + + +/*! + * \brief l_dnaShiftValue() + * + * \param[in] da + * \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 +l_dnaShiftValue(L_DNA *da, + l_int32 index, + l_float64 diff) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 1); + if (index < 0 || index >= da->n) + return ERROR_INT("index not valid", __func__, 1); + + da->array[index] += diff; + return 0; +} + + +/*! + * \brief l_dnaGetIArray() + * + * \param[in] da + * \return a copy of the bare internal array, integerized + * by rounding, or NULL on error + * <pre> + * Notes: + * (1) A copy of the array is made, because we need to + * generate an integer array from the bare double 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 l_dna. + * (3) This function is provided to simplify calculations + * using the bare internal array, rather than continually + * calling accessors on the l_dna. It is typically used + * on an array of size 256. + * </pre> + */ +l_int32 * +l_dnaGetIArray(L_DNA *da) +{ +l_int32 i, n, ival; +l_int32 *array; + + if (!da) + return (l_int32 *)ERROR_PTR("da not defined", __func__, NULL); + + n = l_dnaGetCount(da); + if ((array = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL) + return (l_int32 *)ERROR_PTR("array not made", __func__, NULL); + for (i = 0; i < n; i++) { + l_dnaGetIValue(da, i, &ival); + array[i] = ival; + } + + return array; +} + + +/*! + * \brief l_dnaGetDArray() + * + * \param[in] da + * \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 l_dna. + * (2) Very important: for L_NOCOPY, any writes to the array + * will be in the l_dna. Do not write beyond the size of + * the count field, because it will not be accessible + * from the l_dna! If necessary, be sure to set the count + * field to a larger number (such as the alloc size) + * BEFORE calling this function. Creating with l_dnaMakeConstant() + * is another way to insure full initialization. + * </pre> + */ +l_float64 * +l_dnaGetDArray(L_DNA *da, + l_int32 copyflag) +{ +l_int32 i, n; +l_float64 *array; + + if (!da) + return (l_float64 *)ERROR_PTR("da not defined", __func__, NULL); + + if (copyflag == L_NOCOPY) { + array = da->array; + } else { /* copyflag == L_COPY */ + n = l_dnaGetCount(da); + if ((array = (l_float64 *)LEPT_CALLOC(n, sizeof(l_float64))) == NULL) + return (l_float64 *)ERROR_PTR("array not made", __func__, NULL); + for (i = 0; i < n; i++) + array[i] = da->array[i]; + } + + return array; +} + + +/*! + * \brief l_dnaGetParameters() + * + * \param[in] da + * \param[out] pstartx [optional] startx + * \param[out] pdelx [optional] delx + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaGetParameters(L_DNA *da, + l_float64 *pstartx, + l_float64 *pdelx) +{ + if (pstartx) *pstartx = 0.0; + if (pdelx) *pdelx = 1.0; + if (!pstartx && !pdelx) + return ERROR_INT("neither &startx nor &delx are defined", __func__, 1); + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + if (pstartx) *pstartx = da->startx; + if (pdelx) *pdelx = da->delx; + return 0; +} + + +/*! + * \brief l_dnaSetParameters() + * + * \param[in] da + * \param[in] startx x value corresponding to da[0] + * \param[in] delx difference in x values for the situation where the + * elements of da correspond to the evaluation of a + * function at equal intervals of size %delx + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaSetParameters(L_DNA *da, + l_float64 startx, + l_float64 delx) +{ + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + da->startx = startx; + da->delx = delx; + return 0; +} + + +/*! + * \brief l_dnaCopyParameters() + * + * \param[in] dad destination DNuma + * \param[in] das source DNuma + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaCopyParameters(L_DNA *dad, + L_DNA *das) +{ +l_float64 start, binsize; + + if (!das || !dad) + return ERROR_INT("das and dad not both defined", __func__, 1); + + l_dnaGetParameters(das, &start, &binsize); + l_dnaSetParameters(dad, start, binsize); + return 0; +} + + +/*----------------------------------------------------------------------* + * Serialize Dna for I/O * + *----------------------------------------------------------------------*/ +/*! + * \brief l_dnaRead() + * + * \param[in] filename + * \return da, or NULL on error + */ +L_DNA * +l_dnaRead(const char *filename) +{ +FILE *fp; +L_DNA *da; + + if (!filename) + return (L_DNA *)ERROR_PTR("filename not defined", __func__, NULL); + + if ((fp = fopenReadStream(filename)) == NULL) + return (L_DNA *)ERROR_PTR_1("stream not opened", + filename, __func__, NULL); + da = l_dnaReadStream(fp); + fclose(fp); + if (!da) + return (L_DNA *)ERROR_PTR_1("da not read", + filename, __func__, NULL); + return da; +} + + +/*! + * \brief l_dnaReadStream() + * + * \param[in] fp file stream + * \return da, or NULL on error + * + * <pre> + * Notes: + * (1) fscanf takes %lf to read a double; fprintf takes %f to write it. + * (2) It is OK for the dna to be empty. + * </pre> + */ +L_DNA * +l_dnaReadStream(FILE *fp) +{ +l_int32 i, n, index, ret, version; +l_float64 val, startx, delx; +L_DNA *da; + + if (!fp) + return (L_DNA *)ERROR_PTR("stream not defined", __func__, NULL); + + ret = fscanf(fp, "\nL_Dna Version %d\n", &version); + if (ret != 1) + return (L_DNA *)ERROR_PTR("not a l_dna file", __func__, NULL); + if (version != DNA_VERSION_NUMBER) + return (L_DNA *)ERROR_PTR("invalid l_dna version", __func__, NULL); + if (fscanf(fp, "Number of numbers = %d\n", &n) != 1) + return (L_DNA *)ERROR_PTR("invalid number of numbers", __func__, NULL); + if (n < 0) + return (L_DNA *)ERROR_PTR("num doubles < 0", __func__, NULL); + if (n > MaxDoubleArraySize) + return (L_DNA *)ERROR_PTR("too many doubles", __func__, NULL); + if (n == 0) L_INFO("the dna is empty\n", __func__); + + if ((da = l_dnaCreate(n)) == NULL) + return (L_DNA *)ERROR_PTR("da not made", __func__, NULL); + for (i = 0; i < n; i++) { + if (fscanf(fp, " [%d] = %lf\n", &index, &val) != 2) { + l_dnaDestroy(&da); + return (L_DNA *)ERROR_PTR("bad input data", __func__, NULL); + } + l_dnaAddNumber(da, val); + } + + /* Optional data */ + if (fscanf(fp, "startx = %lf, delx = %lf\n", &startx, &delx) == 2) + l_dnaSetParameters(da, startx, delx); + return da; +} + + +/*! + * \brief l_dnaReadMem() + * + * \param[in] data dna serialization; in ascii + * \param[in] size of data; can use strlen to get it + * \return da, or NULL on error + */ +L_DNA * +l_dnaReadMem(const l_uint8 *data, + size_t size) +{ +FILE *fp; +L_DNA *da; + + if (!data) + return (L_DNA *)ERROR_PTR("data not defined", __func__, NULL); + if ((fp = fopenReadFromMemory(data, size)) == NULL) + return (L_DNA *)ERROR_PTR("stream not opened", __func__, NULL); + + da = l_dnaReadStream(fp); + fclose(fp); + if (!da) L_ERROR("dna not read\n", __func__); + return da; +} + + +/*! + * \brief l_dnaWrite() + * + * \param[in] filename + * \param[in] da + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaWrite(const char *filename, + L_DNA *da) +{ +l_int32 ret; +FILE *fp; + + if (!filename) + return ERROR_INT("filename not defined", __func__, 1); + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + if ((fp = fopenWriteStream(filename, "w")) == NULL) + return ERROR_INT_1("stream not opened", filename, __func__, 1); + ret = l_dnaWriteStream(fp, da); + fclose(fp); + if (ret) + return ERROR_INT_1("da not written to stream", filename, __func__, 1); + return 0; +} + + +/*! + * \brief l_dnaWriteStream() + * + * \param[in] fp file stream; use NULL to write to stderr + * \param[in] da + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaWriteStream(FILE *fp, + L_DNA *da) +{ +l_int32 i, n; +l_float64 startx, delx; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + if (!fp) + return l_dnaWriteStderr(da); + + n = l_dnaGetCount(da); + fprintf(fp, "\nL_Dna Version %d\n", DNA_VERSION_NUMBER); + fprintf(fp, "Number of numbers = %d\n", n); + for (i = 0; i < n; i++) + fprintf(fp, " [%d] = %f\n", i, da->array[i]); + fprintf(fp, "\n"); + + /* Optional data */ + l_dnaGetParameters(da, &startx, &delx); + if (startx != 0.0 || delx != 1.0) + fprintf(fp, "startx = %f, delx = %f\n", startx, delx); + + return 0; +} + + +/*! + * \brief l_dnaWriteStrderr() + * + * \param[in] da + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaWriteStderr(L_DNA *da) +{ +l_int32 i, n; +l_float64 startx, delx; + + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + n = l_dnaGetCount(da); + lept_stderr("\nL_Dna Version %d\n", DNA_VERSION_NUMBER); + lept_stderr("Number of numbers = %d\n", n); + for (i = 0; i < n; i++) + lept_stderr(" [%d] = %f\n", i, da->array[i]); + lept_stderr("\n"); + + /* Optional data */ + l_dnaGetParameters(da, &startx, &delx); + if (startx != 0.0 || delx != 1.0) + lept_stderr("startx = %f, delx = %f\n", startx, delx); + + return 0; +} + + +/*! + * \brief l_dnaWriteMem() + * + * \param[out] pdata data of serialized dna; ascii + * \param[out] psize size of returned data + * \param[in] da + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Serializes a dna in memory and puts the result in a buffer. + * </pre> + */ +l_ok +l_dnaWriteMem(l_uint8 **pdata, + size_t *psize, + L_DNA *da) +{ +l_int32 ret; +FILE *fp; + + if (pdata) *pdata = NULL; + if (psize) *psize = 0; + if (!pdata) + return ERROR_INT("&data not defined", __func__, 1); + if (!psize) + return ERROR_INT("&size not defined", __func__, 1); + if (!da) + return ERROR_INT("da not defined", __func__, 1); + +#if HAVE_FMEMOPEN + if ((fp = open_memstream((char **)pdata, psize)) == NULL) + return ERROR_INT("stream not opened", __func__, 1); + ret = l_dnaWriteStream(fp, da); + fputc('\0', fp); + fclose(fp); + if (*psize > 0) *psize = *psize - 1; +#else + L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); + #ifdef _WIN32 + if ((fp = fopenWriteWinTempfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", __func__, 1); + #else + if ((fp = tmpfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", __func__, 1); + #endif /* _WIN32 */ + ret = l_dnaWriteStream(fp, da); + rewind(fp); + *pdata = l_binaryReadStream(fp, psize); + fclose(fp); +#endif /* HAVE_FMEMOPEN */ + return ret; +} + + +/*--------------------------------------------------------------------------* + * Dnaa creation, destruction * + *--------------------------------------------------------------------------*/ +/*! + * \brief l_dnaaCreate() + * + * \param[in] n size of l_dna ptr array to be alloc'd 0 for default + * \return daa, or NULL on error + * + */ +L_DNAA * +l_dnaaCreate(l_int32 n) +{ +L_DNAA *daa; + + if (n <= 0 || n > MaxPtrArraySize) + n = InitialArraySize; + + daa = (L_DNAA *)LEPT_CALLOC(1, sizeof(L_DNAA)); + if ((daa->dna = (L_DNA **)LEPT_CALLOC(n, sizeof(L_DNA *))) == NULL) { + l_dnaaDestroy(&daa); + return (L_DNAA *)ERROR_PTR("l_dna ptr array not made", __func__, NULL); + } + daa->nalloc = n; + daa->n = 0; + return daa; +} + + +/*! + * \brief l_dnaaCreateFull() + * + * \param[in] nptr size of dna ptr array to be alloc'd + * \param[in] n size of individual dna arrays to be alloc'd 0 for default + * \return daa, or NULL on error + * + * <pre> + * Notes: + * (1) This allocates a dnaa and fills the array with allocated dnas. + * In use, after calling this function, use + * l_dnaaAddNumber(dnaa, index, val); + * to add val to the index-th dna in dnaa. + * </pre> + */ +L_DNAA * +l_dnaaCreateFull(l_int32 nptr, + l_int32 n) +{ +l_int32 i; +L_DNAA *daa; +L_DNA *da; + + daa = l_dnaaCreate(nptr); + for (i = 0; i < nptr; i++) { + da = l_dnaCreate(n); + l_dnaaAddDna(daa, da, L_INSERT); + } + + return daa; +} + + +/*! + * \brief l_dnaaTruncate() + * + * \param[in] daa + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This identifies the largest index containing a dna that + * has any numbers within it, destroys all dna beyond that + * index, and resets the count. + * </pre> + */ +l_ok +l_dnaaTruncate(L_DNAA *daa) +{ +l_int32 i, n, nn; +L_DNA *da; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + + n = l_dnaaGetCount(daa); + for (i = n - 1; i >= 0; i--) { + da = l_dnaaGetDna(daa, i, L_CLONE); + if (!da) + continue; + nn = l_dnaGetCount(da); + l_dnaDestroy(&da); /* the clone */ + if (nn == 0) + l_dnaDestroy(&daa->dna[i]); + else + break; + } + daa->n = i + 1; + return 0; +} + + +/*! + * \brief l_dnaaDestroy() + * + * \param[in,out] pdaa will be set to null before returning + * \return void + */ +void +l_dnaaDestroy(L_DNAA **pdaa) +{ +l_int32 i; +L_DNAA *daa; + + if (pdaa == NULL) { + L_WARNING("ptr address is NULL!\n", __func__); + return; + } + + if ((daa = *pdaa) == NULL) + return; + + for (i = 0; i < daa->n; i++) + l_dnaDestroy(&daa->dna[i]); + LEPT_FREE(daa->dna); + LEPT_FREE(daa); + *pdaa = NULL; +} + + +/*--------------------------------------------------------------------------* + * Add Dna to Dnaa * + *--------------------------------------------------------------------------*/ +/*! + * \brief l_dnaaAddDna() + * + * \param[in] daa + * \param[in] da to be added + * \param[in] copyflag L_INSERT, L_COPY, L_CLONE + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaaAddDna(L_DNAA *daa, + L_DNA *da, + l_int32 copyflag) +{ +l_int32 n; +L_DNA *dac; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + if (!da) + return ERROR_INT("da not defined", __func__, 1); + + if (copyflag == L_INSERT) { + dac = da; + } else if (copyflag == L_COPY) { + if ((dac = l_dnaCopy(da)) == NULL) + return ERROR_INT("dac not made", __func__, 1); + } else if (copyflag == L_CLONE) { + dac = l_dnaClone(da); + } else { + return ERROR_INT("invalid copyflag", __func__, 1); + } + + n = l_dnaaGetCount(daa); + if (n >= daa->nalloc) { + if (l_dnaaExtendArray(daa)) { + if (copyflag != L_INSERT) + l_dnaDestroy(&dac); + return ERROR_INT("extension failed", __func__, 1); + } + } + daa->dna[n] = dac; + daa->n++; + return 0; +} + + +/*! + * \brief l_dnaaExtendArray() + * + * \param[in] daa + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Doubles the number of dna ptrs. + * (2) The max size of the dna array is 1M ptrs. + * </pre> + */ +static l_int32 +l_dnaaExtendArray(L_DNAA *daa) +{ +size_t oldsize, newsize; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + if (daa->nalloc > MaxPtrArraySize) /* belt & suspenders */ + return ERROR_INT("daa has too many ptrs", __func__, 1); + oldsize = daa->nalloc * sizeof(L_DNA *); + newsize = 2 * oldsize; + if (newsize > 8 * MaxPtrArraySize) + return ERROR_INT("newsize > 8 MB; too large", __func__, 1); + + if ((daa->dna = (L_DNA **)reallocNew((void **)&daa->dna, + oldsize, newsize)) == NULL) + return ERROR_INT("new ptr array not returned", __func__, 1); + + daa->nalloc *= 2; + return 0; +} + + +/*----------------------------------------------------------------------* + * DNumaa accessors * + *----------------------------------------------------------------------*/ +/*! + * \brief l_dnaaGetCount() + * + * \param[in] daa + * \return count number of l_dna, or 0 if no l_dna or on error + */ +l_int32 +l_dnaaGetCount(L_DNAA *daa) +{ + if (!daa) + return ERROR_INT("daa not defined", __func__, 0); + return daa->n; +} + + +/*! + * \brief l_dnaaGetDnaCount() + * + * \param[in] daa + * \param[in] index of l_dna in daa + * \return count of numbers in the referenced l_dna, or 0 on error. + */ +l_int32 +l_dnaaGetDnaCount(L_DNAA *daa, + l_int32 index) +{ + if (!daa) + return ERROR_INT("daa not defined", __func__, 0); + if (index < 0 || index >= daa->n) + return ERROR_INT("invalid index into daa", __func__, 0); + return l_dnaGetCount(daa->dna[index]); +} + + +/*! + * \brief l_dnaaGetNumberCount() + * + * \param[in] daa + * \return count total number of numbers in the l_dnaa, + * or 0 if no numbers or on error + */ +l_int32 +l_dnaaGetNumberCount(L_DNAA *daa) +{ +L_DNA *da; +l_int32 n, sum, i; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 0); + + n = l_dnaaGetCount(daa); + for (sum = 0, i = 0; i < n; i++) { + da = l_dnaaGetDna(daa, i, L_CLONE); + sum += l_dnaGetCount(da); + l_dnaDestroy(&da); + } + + return sum; +} + + +/*! + * \brief l_dnaaGetDna() + * + * \param[in] daa + * \param[in] index to the index-th l_dna + * \param[in] accessflag L_COPY or L_CLONE + * \return l_dna, or NULL on error + */ +L_DNA * +l_dnaaGetDna(L_DNAA *daa, + l_int32 index, + l_int32 accessflag) +{ + if (!daa) + return (L_DNA *)ERROR_PTR("daa not defined", __func__, NULL); + if (index < 0 || index >= daa->n) + return (L_DNA *)ERROR_PTR("index not valid", __func__, NULL); + + if (accessflag == L_COPY) + return l_dnaCopy(daa->dna[index]); + else if (accessflag == L_CLONE) + return l_dnaClone(daa->dna[index]); + else + return (L_DNA *)ERROR_PTR("invalid accessflag", __func__, NULL); +} + + +/*! + * \brief l_dnaaReplaceDna() + * + * \param[in] daa + * \param[in] index to the index-th l_dna + * \param[in] da insert and replace any existing one + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Any existing l_dna is destroyed, and the input one + * is inserted in its place. + * (2) If %index is invalid, return 1 (error) + * </pre> + */ +l_ok +l_dnaaReplaceDna(L_DNAA *daa, + l_int32 index, + L_DNA *da) +{ +l_int32 n; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + if (!da) + return ERROR_INT("da not defined", __func__, 1); + n = l_dnaaGetCount(daa); + if (index < 0 || index >= n) + return ERROR_INT("index not valid", __func__, 1); + + l_dnaDestroy(&daa->dna[index]); + daa->dna[index] = da; + return 0; +} + + +/*! + * \brief l_dnaaGetValue() + * + * \param[in] daa + * \param[in] i index of l_dna within l_dnaa + * \param[in] j index into l_dna + * \param[out] pval double value + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaaGetValue(L_DNAA *daa, + l_int32 i, + l_int32 j, + l_float64 *pval) +{ +l_int32 n; +L_DNA *da; + + if (!pval) + return ERROR_INT("&val not defined", __func__, 1); + *pval = 0.0; + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + n = l_dnaaGetCount(daa); + if (i < 0 || i >= n) + return ERROR_INT("invalid index into daa", __func__, 1); + da = daa->dna[i]; + if (j < 0 || j >= da->n) + return ERROR_INT("invalid index into da", __func__, 1); + *pval = da->array[j]; + return 0; +} + + +/*! + * \brief l_dnaaAddNumber() + * + * \param[in] daa + * \param[in] index of l_dna within l_dnaa + * \param[in] val number to be added; stored as a double + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Adds to an existing l_dna only. + * </pre> + */ +l_ok +l_dnaaAddNumber(L_DNAA *daa, + l_int32 index, + l_float64 val) +{ +l_int32 n; +L_DNA *da; + + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + n = l_dnaaGetCount(daa); + if (index < 0 || index >= n) + return ERROR_INT("invalid index in daa", __func__, 1); + + da = l_dnaaGetDna(daa, index, L_CLONE); + l_dnaAddNumber(da, val); + l_dnaDestroy(&da); + return 0; +} + + +/*----------------------------------------------------------------------* + * Serialize Dna for I/O * + *----------------------------------------------------------------------*/ +/*! + * \brief l_dnaaRead() + * + * \param[in] filename + * \return daa, or NULL on error + */ +L_DNAA * +l_dnaaRead(const char *filename) +{ +FILE *fp; +L_DNAA *daa; + + if (!filename) + return (L_DNAA *)ERROR_PTR("filename not defined", __func__, NULL); + + if ((fp = fopenReadStream(filename)) == NULL) + return (L_DNAA *)ERROR_PTR_1("stream not opened", + filename, __func__, NULL); + daa = l_dnaaReadStream(fp); + fclose(fp); + if (!daa) + return (L_DNAA *)ERROR_PTR_1("daa not read", + filename, __func__, NULL); + return daa; +} + + +/*! + * \brief l_dnaaReadStream() + * + * \param[in] fp file stream + * \return daa, or NULL on error + * + * <pre> + * Notes: + * (1) It is OK for the dnaa to be empty. + * </pre> + */ +L_DNAA * +l_dnaaReadStream(FILE *fp) +{ +l_int32 i, n, index, ret, version; +L_DNA *da; +L_DNAA *daa; + + if (!fp) + return (L_DNAA *)ERROR_PTR("stream not defined", __func__, NULL); + + ret = fscanf(fp, "\nL_Dnaa Version %d\n", &version); + if (ret != 1) + return (L_DNAA *)ERROR_PTR("not a l_dna file", __func__, NULL); + if (version != DNA_VERSION_NUMBER) + return (L_DNAA *)ERROR_PTR("invalid l_dnaa version", __func__, NULL); + if (fscanf(fp, "Number of L_Dna = %d\n\n", &n) != 1) + return (L_DNAA *)ERROR_PTR("invalid number of l_dna", __func__, NULL); + if (n < 0) + return (L_DNAA *)ERROR_PTR("num l_dna <= 0", __func__, NULL); + if (n > MaxPtrArraySize) + return (L_DNAA *)ERROR_PTR("too many l_dna", __func__, NULL); + if (n == 0) L_INFO("the dnaa is empty\n", __func__); + + if ((daa = l_dnaaCreate(n)) == NULL) + return (L_DNAA *)ERROR_PTR("daa not made", __func__, NULL); + for (i = 0; i < n; i++) { + if (fscanf(fp, "L_Dna[%d]:", &index) != 1) { + l_dnaaDestroy(&daa); + return (L_DNAA *)ERROR_PTR("invalid l_dna header", __func__, NULL); + } + if ((da = l_dnaReadStream(fp)) == NULL) { + l_dnaaDestroy(&daa); + return (L_DNAA *)ERROR_PTR("da not made", __func__, NULL); + } + l_dnaaAddDna(daa, da, L_INSERT); + } + + return daa; +} + + +/*! + * \brief l_dnaaReadMem() + * + * \param[in] data dnaa serialization; in ascii + * \param[in] size of data; can use strlen to get it + * \return daa, or NULL on error + */ +L_DNAA * +l_dnaaReadMem(const l_uint8 *data, + size_t size) +{ +FILE *fp; +L_DNAA *daa; + + if (!data) + return (L_DNAA *)ERROR_PTR("data not defined", __func__, NULL); + if ((fp = fopenReadFromMemory(data, size)) == NULL) + return (L_DNAA *)ERROR_PTR("stream not opened", __func__, NULL); + + daa = l_dnaaReadStream(fp); + fclose(fp); + if (!daa) L_ERROR("daa not read\n", __func__); + return daa; +} + + +/*! + * \brief l_dnaaWrite() + * + * \param[in] filename + * \param[in] daa + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaaWrite(const char *filename, + L_DNAA *daa) +{ +l_int32 ret; +FILE *fp; + + if (!filename) + return ERROR_INT("filename not defined", __func__, 1); + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + + if ((fp = fopenWriteStream(filename, "w")) == NULL) + return ERROR_INT_1("stream not opened", filename, __func__, 1); + ret = l_dnaaWriteStream(fp, daa); + fclose(fp); + if (ret) + return ERROR_INT_1("daa not written to stream", filename, __func__, 1); + return 0; +} + + +/*! + * \brief l_dnaaWriteStream() + * + * \param[in] fp file stream + * \param[in] daa + * \return 0 if OK, 1 on error + */ +l_ok +l_dnaaWriteStream(FILE *fp, + L_DNAA *daa) +{ +l_int32 i, n; +L_DNA *da; + + if (!fp) + return ERROR_INT("stream not defined", __func__, 1); + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + + n = l_dnaaGetCount(daa); + fprintf(fp, "\nL_Dnaa Version %d\n", DNA_VERSION_NUMBER); + fprintf(fp, "Number of L_Dna = %d\n\n", n); + for (i = 0; i < n; i++) { + if ((da = l_dnaaGetDna(daa, i, L_CLONE)) == NULL) + return ERROR_INT("da not found", __func__, 1); + fprintf(fp, "L_Dna[%d]:", i); + l_dnaWriteStream(fp, da); + l_dnaDestroy(&da); + } + + return 0; +} + + +/*! + * \brief l_dnaaWriteMem() + * + * \param[out] pdata data of serialized dnaa; ascii + * \param[out] psize size of returned data + * \param[in] daa + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Serializes a dnaa in memory and puts the result in a buffer. + * </pre> + */ +l_ok +l_dnaaWriteMem(l_uint8 **pdata, + size_t *psize, + L_DNAA *daa) +{ +l_int32 ret; +FILE *fp; + + if (pdata) *pdata = NULL; + if (psize) *psize = 0; + if (!pdata) + return ERROR_INT("&data not defined", __func__, 1); + if (!psize) + return ERROR_INT("&size not defined", __func__, 1); + if (!daa) + return ERROR_INT("daa not defined", __func__, 1); + +#if HAVE_FMEMOPEN + if ((fp = open_memstream((char **)pdata, psize)) == NULL) + return ERROR_INT("stream not opened", __func__, 1); + ret = l_dnaaWriteStream(fp, daa); + fputc('\0', fp); + fclose(fp); + if (*psize > 0) *psize = *psize - 1; +#else + L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); + #ifdef _WIN32 + if ((fp = fopenWriteWinTempfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", __func__, 1); + #else + if ((fp = tmpfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", __func__, 1); + #endif /* _WIN32 */ + ret = l_dnaaWriteStream(fp, daa); + rewind(fp); + *pdata = l_binaryReadStream(fp, psize); + fclose(fp); +#endif /* HAVE_FMEMOPEN */ + return ret; +} +
