1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -
4  -  Redistribution and use in source and binary forms, with or without
5  -  modification, are permitted provided that the following conditions
6  -  are met:
7  -  1. Redistributions of source code must retain the above copyright
8  -     notice, this list of conditions and the following disclaimer.
9  -  2. Redistributions in binary form must reproduce the above
10  -     copyright notice, this list of conditions and the following
11  -     disclaimer in the documentation and/or other materials
12  -     provided with the distribution.
13  -
14  -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18  -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 /*!
28  * \file  numabasic.c
29  * <pre>
30  *
31  *      Numa creation, destruction, copy, clone, etc.
32  *          NUMA        *numaCreate()
33  *          NUMA        *numaCreateFromIArray()
34  *          NUMA        *numaCreateFromFArray()
35  *          NUMA        *numaCreateFromString()
36  *          void        *numaDestroy()
37  *          NUMA        *numaCopy()
38  *          NUMA        *numaClone()
39  *          l_int32      numaEmpty()
40  *
41  *      Add/remove number (float or integer)
42  *          l_int32      numaAddNumber()
43  *          static l_int32  numaExtendArray()
44  *          l_int32      numaInsertNumber()
45  *          l_int32      numaRemoveNumber()
46  *          l_int32      numaReplaceNumber()
47  *
48  *      Numa accessors
49  *          l_int32      numaGetCount()
50  *          l_int32      numaSetCount()
51  *          l_int32      numaGetIValue()
52  *          l_int32      numaGetFValue()
53  *          l_int32      numaSetValue()
54  *          l_int32      numaShiftValue()
55  *          l_int32     *numaGetIArray()
56  *          l_float32   *numaGetFArray()
57  *          l_int32      numaGetRefcount()
58  *          l_int32      numaChangeRefcount()
59  *          l_int32      numaGetParameters()
60  *          l_int32      numaSetParameters()
61  *          l_int32      numaCopyParameters()
62  *
63  *      Convert to string array
64  *          SARRAY      *numaConvertToSarray()
65  *
66  *      Serialize numa for I/O
67  *          NUMA        *numaRead()
68  *          NUMA        *numaReadStream()
69  *          NUMA        *numaReadMem()
70  *          l_int32      numaWriteDebug()
71  *          l_int32      numaWrite()
72  *          l_int32      numaWriteStream()
73  *          l_int32      numaWriteMem()
74  *
75  *      Numaa creation, destruction, truncation
76  *          NUMAA       *numaaCreate()
77  *          NUMAA       *numaaCreateFull()
78  *          NUMAA       *numaaTruncate()
79  *          void        *numaaDestroy()
80  *
81  *      Add Numa to Numaa
82  *          l_int32      numaaAddNuma()
83  *          static l_int32   numaaExtendArray()
84  *
85  *      Numaa accessors
86  *          l_int32      numaaGetCount()
87  *          l_int32      numaaGetNumaCount()
88  *          l_int32      numaaGetNumberCount()
89  *          NUMA       **numaaGetPtrArray()
90  *          NUMA        *numaaGetNuma()
91  *          NUMA        *numaaReplaceNuma()
92  *          l_int32      numaaGetValue()
93  *          l_int32      numaaAddNumber()
94  *
95  *      Serialize numaa for I/O
96  *          NUMAA       *numaaRead()
97  *          NUMAA       *numaaReadStream()
98  *          NUMAA       *numaaReadMem()
99  *          l_int32      numaaWrite()
100  *          l_int32      numaaWriteStream()
101  *          l_int32      numaaWriteMem()
102  *
103  *    (1) The Numa is a struct holding an array of floats.  It can also
104  *        be used to store l_int32 values, with some loss of precision
105  *        for floats larger than about 10 million.  Use the L_Dna instead
106  *        if integers larger than a few million need to be stored.
107  *
108  *    (2) Always use the accessors in this file, never the fields directly.
109  *
110  *    (3) Storing and retrieving numbers:
111  *
112  *       * to append a new number to the array, use numaAddNumber().  If
113  *         the number is an int, it will will automatically be converted
114  *         to l_float32 and stored.
115  *
116  *       * to reset a value stored in the array, use numaSetValue().
117  *
118  *       * to increment or decrement a value stored in the array,
119  *         use numaShiftValue().
120  *
121  *       * to obtain a value from the array, use either numaGetIValue()
122  *         or numaGetFValue(), depending on whether you are retrieving
123  *         an integer or a float.  This avoids doing an explicit cast,
124  *         such as
125  *           (a) return a l_float32 and cast it to an l_int32
126  *           (b) cast the return directly to (l_float32 *) to
127  *               satisfy the function prototype, as in
128  *                 numaGetFValue(na, index, (l_float32 *)&ival);   [ugly!]
129  *
130  *    (4) int <--> float conversions:
131  *
132  *        Tradition dictates that type conversions go automatically from
133  *        l_int32 --> l_float32, even though it is possible to lose
134  *        precision for large integers, whereas you must cast (l_int32)
135  *        to go from l_float32 --> l_int32 because you're truncating
136  *        to the integer value.
137  *
138  *    (5) As with other arrays in leptonica, the numa has both an allocated
139  *        size and a count of the stored numbers.  When you add a number, it
140  *        goes on the end of the array, and causes a realloc if the array
141  *        is already filled.  However, in situations where you want to
142  *        add numbers randomly into an array, such as when you build a
143  *        histogram, you must set the count of stored numbers in advance.
144  *        This is done with numaSetCount().  If you set a count larger
145  *        than the allocated array, it does a realloc to the size requested.
146  *
147  *    (6) In situations where the data in a numa correspond to a function
148  *        y(x), the values can be either at equal spacings in x or at
149  *        arbitrary spacings.  For the former, we can represent all x values
150  *        by two parameters: startx (corresponding to y[0]) and delx
151  *        for the change in x for adjacent values y[i] and y[i+1].
152  *        startx and delx are initialized to 0.0 and 1.0, rsp.
153  *        For arbitrary spacings, we use a second numa, and the two
154  *        numas are typically denoted nay and nax.
155  *
156  *    (7) The numa is also the basic struct used for histograms.  Every numa
157  *        has startx and delx fields, initialized to 0.0 and 1.0, that can
158  *        be used to represent the "x" value for the location of the
159  *        first bin and the bin width, respectively.  Accessors are the
160  *        numa*Parameters() functions.  All functions that make numa
161  *        histograms must set these fields properly, and many functions
162  *        that use numa histograms rely on the correctness of these values.
163  * </pre>
164  */
165 
166 #include <string.h>
167 #include <math.h>
168 #include "allheaders.h"
169 
170 static const l_int32 INITIAL_PTR_ARRAYSIZE = 50;      /* n'importe quoi */
171 
172     /* Static functions */
173 static l_int32 numaExtendArray(NUMA  *na);
174 static l_int32 numaaExtendArray(NUMAA  *naa);
175 
176 
177 /*--------------------------------------------------------------------------*
178  *               Numa creation, destruction, copy, clone, etc.              *
179  *--------------------------------------------------------------------------*/
180 /*!
181  * \brief   numaCreate()
182  *
183  * \param[in]    n size of number array to be alloc'd 0 for default
184  * \return  na, or NULL on error
185  */
186 NUMA *
numaCreate(l_int32 n)187 numaCreate(l_int32  n)
188 {
189 NUMA  *na;
190 
191     PROCNAME("numaCreate");
192 
193     if (n <= 0)
194         n = INITIAL_PTR_ARRAYSIZE;
195 
196     if ((na = (NUMA *)LEPT_CALLOC(1, sizeof(NUMA))) == NULL)
197         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
198     if ((na->array = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL) {
199         numaDestroy(&na);
200         return (NUMA *)ERROR_PTR("number array not made", procName, NULL);
201     }
202 
203     na->nalloc = n;
204     na->n = 0;
205     na->refcount = 1;
206     na->startx = 0.0;
207     na->delx = 1.0;
208     return na;
209 }
210 
211 
212 /*!
213  * \brief   numaCreateFromIArray()
214  *
215  * \param[in]    iarray integer
216  * \param[in]    size of the array
217  * \return  na, or NULL on error
218  *
219  * <pre>
220  * Notes:
221  *      (1) We can't insert this int array into the numa, because a numa
222  *          takes a float array.  So this just copies the data from the
223  *          input array into the numa.  The input array continues to be
224  *          owned by the caller.
225  * </pre>
226  */
227 NUMA *
numaCreateFromIArray(l_int32 * iarray,l_int32 size)228 numaCreateFromIArray(l_int32  *iarray,
229                      l_int32   size)
230 {
231 l_int32  i;
232 NUMA    *na;
233 
234     PROCNAME("numaCreateFromIArray");
235 
236     if (!iarray)
237         return (NUMA *)ERROR_PTR("iarray not defined", procName, NULL);
238     if (size <= 0)
239         return (NUMA *)ERROR_PTR("size must be > 0", procName, NULL);
240 
241     na = numaCreate(size);
242     for (i = 0; i < size; i++)
243         numaAddNumber(na, iarray[i]);
244 
245     return na;
246 }
247 
248 
249 /*!
250  * \brief   numaCreateFromFArray()
251  *
252  * \param[in]    farray float
253  * \param[in]    size of the array
254  * \param[in]    copyflag L_INSERT or L_COPY
255  * \return  na, or NULL on error
256  *
257  * <pre>
258  * Notes:
259  *      (1) With L_INSERT, ownership of the input array is transferred
260  *          to the returned numa, and all %size elements are considered
261  *          to be valid.
262  * </pre>
263  */
264 NUMA *
numaCreateFromFArray(l_float32 * farray,l_int32 size,l_int32 copyflag)265 numaCreateFromFArray(l_float32  *farray,
266                      l_int32     size,
267                      l_int32     copyflag)
268 {
269 l_int32  i;
270 NUMA    *na;
271 
272     PROCNAME("numaCreateFromFArray");
273 
274     if (!farray)
275         return (NUMA *)ERROR_PTR("farray not defined", procName, NULL);
276     if (size <= 0)
277         return (NUMA *)ERROR_PTR("size must be > 0", procName, NULL);
278     if (copyflag != L_INSERT && copyflag != L_COPY)
279         return (NUMA *)ERROR_PTR("invalid copyflag", procName, NULL);
280 
281     na = numaCreate(size);
282     if (copyflag == L_INSERT) {
283         if (na->array) LEPT_FREE(na->array);
284         na->array = farray;
285         na->n = size;
286     } else {  /* just copy the contents */
287         for (i = 0; i < size; i++)
288             numaAddNumber(na, farray[i]);
289     }
290 
291     return na;
292 }
293 
294 
295 /*!
296  * \brief   numaCreateFromString()
297  *
298  * \param[in]    str string of comma-separated numbers
299  * \return  na, or NULL on error
300  *
301  * <pre>
302  * Notes:
303  *      (1) The numbers can be ints or floats; they will be interpreted
304  *          and stored as floats.  To use them as integers (e.g., for
305  *          indexing into arrays), use numaGetIValue(...).
306  * </pre>
307  */
308 NUMA *
numaCreateFromString(const char * str)309 numaCreateFromString(const char  *str)
310 {
311 char      *substr;
312 l_int32    i, n, nerrors;
313 l_float32  val;
314 NUMA      *na;
315 SARRAY    *sa;
316 
317     PROCNAME("numaCreateFromString");
318 
319     if (!str || (strlen(str) == 0))
320         return (NUMA *)ERROR_PTR("str not defined or empty", procName, NULL);
321 
322     sa = sarrayCreate(0);
323     sarraySplitString(sa, str, ",");
324     n = sarrayGetCount(sa);
325     na = numaCreate(n);
326     nerrors = 0;
327     for (i = 0; i < n; i++) {
328         substr = sarrayGetString(sa, i, L_NOCOPY);
329         if (sscanf(substr, "%f", &val) != 1) {
330             L_ERROR("substr %d not float\n", procName, i);
331             nerrors++;
332         } else {
333             numaAddNumber(na, val);
334         }
335     }
336 
337     sarrayDestroy(&sa);
338     if (nerrors > 0) {
339         numaDestroy(&na);
340         return (NUMA *)ERROR_PTR("non-floats in string", procName, NULL);
341     }
342 
343     return na;
344 }
345 
346 
347 /*!
348  * \brief   numaDestroy()
349  *
350  * \param[in,out] pna to be nulled if it exists
351  * \return  void
352  *
353  * <pre>
354  * Notes:
355  *      (1) Decrements the ref count and, if 0, destroys the numa.
356  *      (2) Always nulls the input ptr.
357  * </pre>
358  */
359 void
numaDestroy(NUMA ** pna)360 numaDestroy(NUMA  **pna)
361 {
362 NUMA  *na;
363 
364     PROCNAME("numaDestroy");
365 
366     if (pna == NULL) {
367         L_WARNING("ptr address is NULL\n", procName);
368         return;
369     }
370 
371     if ((na = *pna) == NULL)
372         return;
373 
374         /* Decrement the ref count.  If it is 0, destroy the numa. */
375     numaChangeRefcount(na, -1);
376     if (numaGetRefcount(na) <= 0) {
377         if (na->array)
378             LEPT_FREE(na->array);
379         LEPT_FREE(na);
380     }
381 
382     *pna = NULL;
383     return;
384 }
385 
386 
387 /*!
388  * \brief   numaCopy()
389  *
390  * \param[in]    na
391  * \return  copy of numa, or NULL on error
392  */
393 NUMA *
numaCopy(NUMA * na)394 numaCopy(NUMA  *na)
395 {
396 l_int32  i;
397 NUMA    *cna;
398 
399     PROCNAME("numaCopy");
400 
401     if (!na)
402         return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
403 
404     if ((cna = numaCreate(na->nalloc)) == NULL)
405         return (NUMA *)ERROR_PTR("cna not made", procName, NULL);
406     cna->startx = na->startx;
407     cna->delx = na->delx;
408 
409     for (i = 0; i < na->n; i++)
410         numaAddNumber(cna, na->array[i]);
411 
412     return cna;
413 }
414 
415 
416 /*!
417  * \brief   numaClone()
418  *
419  * \param[in]    na
420  * \return  ptr to same numa, or NULL on error
421  */
422 NUMA *
numaClone(NUMA * na)423 numaClone(NUMA  *na)
424 {
425     PROCNAME("numaClone");
426 
427     if (!na)
428         return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
429 
430     numaChangeRefcount(na, 1);
431     return na;
432 }
433 
434 
435 /*!
436  * \brief   numaEmpty()
437  *
438  * \param[in]    na
439  * \return  0 if OK; 1 on error
440  *
441  * <pre>
442  * Notes:
443  *      (1) This does not change the allocation of the array.
444  *          It just clears the number of stored numbers, so that
445  *          the array appears to be empty.
446  * </pre>
447  */
448 l_int32
numaEmpty(NUMA * na)449 numaEmpty(NUMA  *na)
450 {
451     PROCNAME("numaEmpty");
452 
453     if (!na)
454         return ERROR_INT("na not defined", procName, 1);
455 
456     na->n = 0;
457     return 0;
458 }
459 
460 
461 
462 /*--------------------------------------------------------------------------*
463  *                 Number array: add number and extend array                *
464  *--------------------------------------------------------------------------*/
465 /*!
466  * \brief   numaAddNumber()
467  *
468  * \param[in]    na
469  * \param[in]    val  float or int to be added; stored as a float
470  * \return  0 if OK, 1 on error
471  */
472 l_int32
numaAddNumber(NUMA * na,l_float32 val)473 numaAddNumber(NUMA      *na,
474               l_float32  val)
475 {
476 l_int32  n;
477 
478     PROCNAME("numaAddNumber");
479 
480     if (!na)
481         return ERROR_INT("na not defined", procName, 1);
482 
483     n = numaGetCount(na);
484     if (n >= na->nalloc)
485         numaExtendArray(na);
486     na->array[n] = val;
487     na->n++;
488     return 0;
489 }
490 
491 
492 /*!
493  * \brief   numaExtendArray()
494  *
495  * \param[in]    na
496  * \return  0 if OK, 1 on error
497  */
498 static l_int32
numaExtendArray(NUMA * na)499 numaExtendArray(NUMA  *na)
500 {
501     PROCNAME("numaExtendArray");
502 
503     if (!na)
504         return ERROR_INT("na not defined", procName, 1);
505 
506     if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
507                                 sizeof(l_float32) * na->nalloc,
508                                 2 * sizeof(l_float32) * na->nalloc)) == NULL)
509             return ERROR_INT("new ptr array not returned", procName, 1);
510 
511     na->nalloc *= 2;
512     return 0;
513 }
514 
515 
516 /*!
517  * \brief   numaInsertNumber()
518  *
519  * \param[in]    na
520  * \param[in]    index location in na to insert new value
521  * \param[in]    val  float32 or integer to be added
522  * \return  0 if OK, 1 on error
523  *
524  * <pre>
525  * Notes:
526  *      (1) This shifts na[i] --> na[i + 1] for all i >= index,
527  *          and then inserts val as na[index].
528  *      (2) It should not be used repeatedly on large arrays,
529  *          because the function is O(n).
530  *
531  * </pre>
532  */
533 l_int32
numaInsertNumber(NUMA * na,l_int32 index,l_float32 val)534 numaInsertNumber(NUMA      *na,
535                  l_int32    index,
536                  l_float32  val)
537 {
538 l_int32  i, n;
539 
540     PROCNAME("numaInsertNumber");
541 
542     if (!na)
543         return ERROR_INT("na not defined", procName, 1);
544     n = numaGetCount(na);
545     if (index < 0 || index > n)
546         return ERROR_INT("index not in {0...n}", procName, 1);
547 
548     if (n >= na->nalloc)
549         numaExtendArray(na);
550     for (i = n; i > index; i--)
551         na->array[i] = na->array[i - 1];
552     na->array[index] = val;
553     na->n++;
554     return 0;
555 }
556 
557 
558 /*!
559  * \brief   numaRemoveNumber()
560  *
561  * \param[in]    na
562  * \param[in]    index element to be removed
563  * \return  0 if OK, 1 on error
564  *
565  * <pre>
566  * Notes:
567  *      (1) This shifts na[i] --> na[i - 1] for all i > index.
568  *      (2) It should not be used repeatedly on large arrays,
569  *          because the function is O(n).
570  * </pre>
571  */
572 l_int32
numaRemoveNumber(NUMA * na,l_int32 index)573 numaRemoveNumber(NUMA    *na,
574                  l_int32  index)
575 {
576 l_int32  i, n;
577 
578     PROCNAME("numaRemoveNumber");
579 
580     if (!na)
581         return ERROR_INT("na not defined", procName, 1);
582     n = numaGetCount(na);
583     if (index < 0 || index >= n)
584         return ERROR_INT("index not in {0...n - 1}", procName, 1);
585 
586     for (i = index + 1; i < n; i++)
587         na->array[i - 1] = na->array[i];
588     na->n--;
589     return 0;
590 }
591 
592 
593 /*!
594  * \brief   numaReplaceNumber()
595  *
596  * \param[in]    na
597  * \param[in]    index element to be replaced
598  * \param[in]    val new value to replace old one
599  * \return  0 if OK, 1 on error
600  */
601 l_int32
numaReplaceNumber(NUMA * na,l_int32 index,l_float32 val)602 numaReplaceNumber(NUMA      *na,
603                   l_int32    index,
604                   l_float32  val)
605 {
606 l_int32  n;
607 
608     PROCNAME("numaReplaceNumber");
609 
610     if (!na)
611         return ERROR_INT("na not defined", procName, 1);
612     n = numaGetCount(na);
613     if (index < 0 || index >= n)
614         return ERROR_INT("index not in {0...n - 1}", procName, 1);
615 
616     na->array[index] = val;
617     return 0;
618 }
619 
620 
621 /*----------------------------------------------------------------------*
622  *                            Numa accessors                            *
623  *----------------------------------------------------------------------*/
624 /*!
625  * \brief   numaGetCount()
626  *
627  * \param[in]    na
628  * \return  count, or 0 if no numbers or on error
629  */
630 l_int32
numaGetCount(NUMA * na)631 numaGetCount(NUMA  *na)
632 {
633     PROCNAME("numaGetCount");
634 
635     if (!na)
636         return ERROR_INT("na not defined", procName, 0);
637     return na->n;
638 }
639 
640 
641 /*!
642  * \brief   numaSetCount()
643  *
644  * \param[in]    na
645  * \param[in]    newcount
646  * \return  0 if OK, 1 on error
647  *
648  * <pre>
649  * Notes:
650  *      (1) If newcount <= na->nalloc, this resets na->n.
651  *          Using newcount = 0 is equivalent to numaEmpty().
652  *      (2) If newcount > na->nalloc, this causes a realloc
653  *          to a size na->nalloc = newcount.
654  *      (3) All the previously unused values in na are set to 0.0.
655  * </pre>
656  */
657 l_int32
numaSetCount(NUMA * na,l_int32 newcount)658 numaSetCount(NUMA    *na,
659              l_int32  newcount)
660 {
661     PROCNAME("numaSetCount");
662 
663     if (!na)
664         return ERROR_INT("na not defined", procName, 1);
665     if (newcount > na->nalloc) {
666         if ((na->array = (l_float32 *)reallocNew((void **)&na->array,
667                          sizeof(l_float32) * na->nalloc,
668                          sizeof(l_float32) * newcount)) == NULL)
669             return ERROR_INT("new ptr array not returned", procName, 1);
670         na->nalloc = newcount;
671     }
672     na->n = newcount;
673     return 0;
674 }
675 
676 
677 /*!
678  * \brief   numaGetFValue()
679  *
680  * \param[in]    na
681  * \param[in]    index into numa
682  * \param[out]   pval  float value; 0.0 on error
683  * \return  0 if OK; 1 on error
684  *
685  * <pre>
686  * Notes:
687  *      (1) Caller may need to check the function return value to
688  *          decide if a 0.0 in the returned ival is valid.
689  * </pre>
690  */
691 l_int32
numaGetFValue(NUMA * na,l_int32 index,l_float32 * pval)692 numaGetFValue(NUMA       *na,
693               l_int32     index,
694               l_float32  *pval)
695 {
696     PROCNAME("numaGetFValue");
697 
698     if (!pval)
699         return ERROR_INT("&val not defined", procName, 1);
700     *pval = 0.0;
701     if (!na)
702         return ERROR_INT("na not defined", procName, 1);
703 
704     if (index < 0 || index >= na->n)
705         return ERROR_INT("index not valid", procName, 1);
706 
707     *pval = na->array[index];
708     return 0;
709 }
710 
711 
712 /*!
713  * \brief   numaGetIValue()
714  *
715  * \param[in]    na
716  * \param[in]    index into numa
717  * \param[out]   pival  integer value; 0 on error
718  * \return  0 if OK; 1 on error
719  *
720  * <pre>
721  * Notes:
722  *      (1) Caller may need to check the function return value to
723  *          decide if a 0 in the returned ival is valid.
724  * </pre>
725  */
726 l_int32
numaGetIValue(NUMA * na,l_int32 index,l_int32 * pival)727 numaGetIValue(NUMA     *na,
728               l_int32   index,
729               l_int32  *pival)
730 {
731 l_float32  val;
732 
733     PROCNAME("numaGetIValue");
734 
735     if (!pival)
736         return ERROR_INT("&ival not defined", procName, 1);
737     *pival = 0;
738     if (!na)
739         return ERROR_INT("na not defined", procName, 1);
740 
741     if (index < 0 || index >= na->n)
742         return ERROR_INT("index not valid", procName, 1);
743 
744     val = na->array[index];
745     *pival = (l_int32)(val + L_SIGN(val) * 0.5);
746     return 0;
747 }
748 
749 
750 /*!
751  * \brief   numaSetValue()
752  *
753  * \param[in]    na
754  * \param[in]    index   to element to be set
755  * \param[in]    val  to set element
756  * \return  0 if OK; 1 on error
757  */
758 l_int32
numaSetValue(NUMA * na,l_int32 index,l_float32 val)759 numaSetValue(NUMA      *na,
760              l_int32    index,
761              l_float32  val)
762 {
763     PROCNAME("numaSetValue");
764 
765     if (!na)
766         return ERROR_INT("na not defined", procName, 1);
767     if (index < 0 || index >= na->n)
768         return ERROR_INT("index not valid", procName, 1);
769 
770     na->array[index] = val;
771     return 0;
772 }
773 
774 
775 /*!
776  * \brief   numaShiftValue()
777  *
778  * \param[in]    na
779  * \param[in]    index to element to change relative to the current value
780  * \param[in]    diff  increment if diff > 0 or decrement if diff < 0
781  * \return  0 if OK; 1 on error
782  */
783 l_int32
numaShiftValue(NUMA * na,l_int32 index,l_float32 diff)784 numaShiftValue(NUMA      *na,
785                l_int32    index,
786                l_float32  diff)
787 {
788     PROCNAME("numaShiftValue");
789 
790     if (!na)
791         return ERROR_INT("na not defined", procName, 1);
792     if (index < 0 || index >= na->n)
793         return ERROR_INT("index not valid", procName, 1);
794 
795     na->array[index] += diff;
796     return 0;
797 }
798 
799 
800 /*!
801  * \brief   numaGetIArray()
802  *
803  * \param[in]    na
804  * \return  a copy of the bare internal array, integerized
805  *              by rounding, or NULL on error
806  * <pre>
807  * Notes:
808  *      (1) A copy of the array is always made, because we need to
809  *          generate an integer array from the bare float array.
810  *          The caller is responsible for freeing the array.
811  *      (2) The array size is determined by the number of stored numbers,
812  *          not by the size of the allocated array in the Numa.
813  *      (3) This function is provided to simplify calculations
814  *          using the bare internal array, rather than continually
815  *          calling accessors on the numa.  It is typically used
816  *          on an array of size 256.
817  * </pre>
818  */
819 l_int32 *
numaGetIArray(NUMA * na)820 numaGetIArray(NUMA  *na)
821 {
822 l_int32   i, n, ival;
823 l_int32  *array;
824 
825     PROCNAME("numaGetIArray");
826 
827     if (!na)
828         return (l_int32 *)ERROR_PTR("na not defined", procName, NULL);
829 
830     n = numaGetCount(na);
831     if ((array = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL)
832         return (l_int32 *)ERROR_PTR("array not made", procName, NULL);
833     for (i = 0; i < n; i++) {
834         numaGetIValue(na, i, &ival);
835         array[i] = ival;
836     }
837 
838     return array;
839 }
840 
841 
842 /*!
843  * \brief   numaGetFArray()
844  *
845  * \param[in]    na
846  * \param[in]    copyflag L_NOCOPY or L_COPY
847  * \return  either the bare internal array or a copy of it,
848  *              or NULL on error
849  *
850  * <pre>
851  * Notes:
852  *      (1) If copyflag == L_COPY, it makes a copy which the caller
853  *          is responsible for freeing.  Otherwise, it operates
854  *          directly on the bare array of the numa.
855  *      (2) Very important: for L_NOCOPY, any writes to the array
856  *          will be in the numa.  Do not write beyond the size of
857  *          the count field, because it will not be accessible
858  *          from the numa!  If necessary, be sure to set the count
859  *          field to a larger number (such as the alloc size)
860  *          BEFORE calling this function.  Creating with numaMakeConstant()
861  *          is another way to insure full initialization.
862  * </pre>
863  */
864 l_float32 *
numaGetFArray(NUMA * na,l_int32 copyflag)865 numaGetFArray(NUMA    *na,
866               l_int32  copyflag)
867 {
868 l_int32     i, n;
869 l_float32  *array;
870 
871     PROCNAME("numaGetFArray");
872 
873     if (!na)
874         return (l_float32 *)ERROR_PTR("na not defined", procName, NULL);
875 
876     if (copyflag == L_NOCOPY) {
877         array = na->array;
878     } else {  /* copyflag == L_COPY */
879         n = numaGetCount(na);
880         if ((array = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL)
881             return (l_float32 *)ERROR_PTR("array not made", procName, NULL);
882         for (i = 0; i < n; i++)
883             array[i] = na->array[i];
884     }
885 
886     return array;
887 }
888 
889 
890 /*!
891  * \brief   numaGetRefCount()
892  *
893  * \param[in]    na
894  * \return  refcount, or UNDEF on error
895  */
896 l_int32
numaGetRefcount(NUMA * na)897 numaGetRefcount(NUMA  *na)
898 {
899     PROCNAME("numaGetRefcount");
900 
901     if (!na)
902         return ERROR_INT("na not defined", procName, UNDEF);
903     return na->refcount;
904 }
905 
906 
907 /*!
908  * \brief   numaChangeRefCount()
909  *
910  * \param[in]    na
911  * \param[in]    delta change to be applied
912  * \return  0 if OK, 1 on error
913  */
914 l_int32
numaChangeRefcount(NUMA * na,l_int32 delta)915 numaChangeRefcount(NUMA    *na,
916                    l_int32  delta)
917 {
918     PROCNAME("numaChangeRefcount");
919 
920     if (!na)
921         return ERROR_INT("na not defined", procName, 1);
922     na->refcount += delta;
923     return 0;
924 }
925 
926 
927 /*!
928  * \brief   numaGetParameters()
929  *
930  * \param[in]    na
931  * \param[out]   pstartx [optional] startx
932  * \param[out]   pdelx [optional] delx
933  * \return  0 if OK, 1 on error
934  */
935 l_int32
numaGetParameters(NUMA * na,l_float32 * pstartx,l_float32 * pdelx)936 numaGetParameters(NUMA       *na,
937                   l_float32  *pstartx,
938                   l_float32  *pdelx)
939 {
940     PROCNAME("numaGetParameters");
941 
942     if (!pdelx && !pstartx)
943         return ERROR_INT("no return val requested", procName, 1);
944     if (pstartx) *pstartx = 0.0;
945     if (pdelx) *pdelx = 1.0;
946     if (!na)
947         return ERROR_INT("na not defined", procName, 1);
948 
949     if (pstartx) *pstartx = na->startx;
950     if (pdelx) *pdelx = na->delx;
951     return 0;
952 }
953 
954 
955 /*!
956  * \brief   numaSetParameters()
957  *
958  * \param[in]    na
959  * \param[in]    startx x value corresponding to na[0]
960  * \param[in]    delx difference in x values for the situation where the
961  *                    elements of na correspond to the evaulation of a
962  *                    function at equal intervals of size %delx
963  * \return  0 if OK, 1 on error
964  */
965 l_int32
numaSetParameters(NUMA * na,l_float32 startx,l_float32 delx)966 numaSetParameters(NUMA      *na,
967                   l_float32  startx,
968                   l_float32  delx)
969 {
970     PROCNAME("numaSetParameters");
971 
972     if (!na)
973         return ERROR_INT("na not defined", procName, 1);
974 
975     na->startx = startx;
976     na->delx = delx;
977     return 0;
978 }
979 
980 
981 /*!
982  * \brief   numaCopyParameters()
983  *
984  * \param[in]    nad destination Numa
985  * \param[in]    nas source Numa
986  * \return  0 if OK, 1 on error
987  */
988 l_int32
numaCopyParameters(NUMA * nad,NUMA * nas)989 numaCopyParameters(NUMA  *nad,
990                    NUMA  *nas)
991 {
992 l_float32  start, binsize;
993 
994     PROCNAME("numaCopyParameters");
995 
996     if (!nas || !nad)
997         return ERROR_INT("nas and nad not both defined", procName, 1);
998 
999     numaGetParameters(nas, &start, &binsize);
1000     numaSetParameters(nad, start, binsize);
1001     return 0;
1002 }
1003 
1004 
1005 /*----------------------------------------------------------------------*
1006  *                      Convert to string array                         *
1007  *----------------------------------------------------------------------*/
1008 /*!
1009  * \brief   numaConvertToSarray()
1010  *
1011  * \param[in]    na
1012  * \param[in]    size1 size of conversion field
1013  * \param[in]    size2 for float conversion: size of field to the right
1014  *                     of the decimal point
1015  * \param[in]    addzeros for integer conversion: to add lead zeros
1016  * \param[in]    type L_INTEGER_VALUE, L_FLOAT_VALUE
1017  * \return  a sarray of the float values converted to strings
1018  *              representing either integer or float values; or NULL on error.
1019  *
1020  * <pre>
1021  * Notes:
1022  *      (1) For integer conversion, size2 is ignored.
1023  *          For float conversion, addzeroes is ignored.
1024  * </pre>
1025  */
1026 SARRAY *
numaConvertToSarray(NUMA * na,l_int32 size1,l_int32 size2,l_int32 addzeros,l_int32 type)1027 numaConvertToSarray(NUMA    *na,
1028                     l_int32  size1,
1029                     l_int32  size2,
1030                     l_int32  addzeros,
1031                     l_int32  type)
1032 {
1033 char       fmt[32], strbuf[64];
1034 l_int32    i, n, ival;
1035 l_float32  fval;
1036 SARRAY    *sa;
1037 
1038     PROCNAME("numaConvertToSarray");
1039 
1040     if (!na)
1041         return (SARRAY *)ERROR_PTR("na not defined", procName, NULL);
1042     if (type != L_INTEGER_VALUE && type != L_FLOAT_VALUE)
1043         return (SARRAY *)ERROR_PTR("invalid type", procName, NULL);
1044 
1045     if (type == L_INTEGER_VALUE) {
1046         if (addzeros)
1047             snprintf(fmt, sizeof(fmt), "%%0%dd", size1);
1048         else
1049             snprintf(fmt, sizeof(fmt), "%%%dd", size1);
1050     } else {  /* L_FLOAT_VALUE */
1051         snprintf(fmt, sizeof(fmt), "%%%d.%df", size1, size2);
1052     }
1053 
1054     n = numaGetCount(na);
1055     if ((sa = sarrayCreate(n)) == NULL)
1056         return (SARRAY *)ERROR_PTR("sa not made", procName, NULL);
1057 
1058     for (i = 0; i < n; i++) {
1059         if (type == L_INTEGER_VALUE) {
1060             numaGetIValue(na, i, &ival);
1061             snprintf(strbuf, sizeof(strbuf), fmt, ival);
1062         } else {  /* L_FLOAT_VALUE */
1063             numaGetFValue(na, i, &fval);
1064             snprintf(strbuf, sizeof(strbuf), fmt, fval);
1065         }
1066         sarrayAddString(sa, strbuf, L_COPY);
1067     }
1068 
1069     return sa;
1070 }
1071 
1072 
1073 /*----------------------------------------------------------------------*
1074  *                       Serialize numa for I/O                         *
1075  *----------------------------------------------------------------------*/
1076 /*!
1077  * \brief   numaRead()
1078  *
1079  * \param[in]    filename
1080  * \return  na, or NULL on error
1081  */
1082 NUMA *
numaRead(const char * filename)1083 numaRead(const char  *filename)
1084 {
1085 FILE  *fp;
1086 NUMA  *na;
1087 
1088     PROCNAME("numaRead");
1089 
1090     if (!filename)
1091         return (NUMA *)ERROR_PTR("filename not defined", procName, NULL);
1092 
1093     if ((fp = fopenReadStream(filename)) == NULL)
1094         return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
1095     na = numaReadStream(fp);
1096     fclose(fp);
1097     if (!na)
1098         return (NUMA *)ERROR_PTR("na not read", procName, NULL);
1099     return na;
1100 }
1101 
1102 
1103 /*!
1104  * \brief   numaReadStream()
1105  *
1106  * \param[in]    fp file stream
1107  * \return  numa, or NULL on error
1108  */
1109 NUMA *
numaReadStream(FILE * fp)1110 numaReadStream(FILE  *fp)
1111 {
1112 l_int32    i, n, index, ret, version;
1113 l_float32  val, startx, delx;
1114 NUMA      *na;
1115 
1116     PROCNAME("numaReadStream");
1117 
1118     if (!fp)
1119         return (NUMA *)ERROR_PTR("stream not defined", procName, NULL);
1120 
1121     ret = fscanf(fp, "\nNuma Version %d\n", &version);
1122     if (ret != 1)
1123         return (NUMA *)ERROR_PTR("not a numa file", procName, NULL);
1124     if (version != NUMA_VERSION_NUMBER)
1125         return (NUMA *)ERROR_PTR("invalid numa version", procName, NULL);
1126     if (fscanf(fp, "Number of numbers = %d\n", &n) != 1)
1127         return (NUMA *)ERROR_PTR("invalid number of numbers", procName, NULL);
1128 
1129     if ((na = numaCreate(n)) == NULL)
1130         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
1131 
1132     for (i = 0; i < n; i++) {
1133         if (fscanf(fp, "  [%d] = %f\n", &index, &val) != 2) {
1134             numaDestroy(&na);
1135             return (NUMA *)ERROR_PTR("bad input data", procName, NULL);
1136         }
1137         numaAddNumber(na, val);
1138     }
1139 
1140         /* Optional data */
1141     if (fscanf(fp, "startx = %f, delx = %f\n", &startx, &delx) == 2)
1142         numaSetParameters(na, startx, delx);
1143 
1144     return na;
1145 }
1146 
1147 
1148 /*!
1149  * \brief   numaReadMem()
1150  *
1151  * \param[in]    data  numa serialization; in ascii
1152  * \param[in]    size  of data; can use strlen to get it
1153  * \return  na, or NULL on error
1154  */
1155 NUMA *
numaReadMem(const l_uint8 * data,size_t size)1156 numaReadMem(const l_uint8  *data,
1157             size_t          size)
1158 {
1159 FILE  *fp;
1160 NUMA  *na;
1161 
1162     PROCNAME("numaReadMem");
1163 
1164     if (!data)
1165         return (NUMA *)ERROR_PTR("data not defined", procName, NULL);
1166     if ((fp = fopenReadFromMemory(data, size)) == NULL)
1167         return (NUMA *)ERROR_PTR("stream not opened", procName, NULL);
1168 
1169     na = numaReadStream(fp);
1170     fclose(fp);
1171     if (!na) L_ERROR("numa not read\n", procName);
1172     return na;
1173 }
1174 
1175 
1176 /*!
1177  * \brief   numaWriteDebug()
1178  *
1179  * \param[in]    filename
1180  * \param[in]    na
1181  * \return  0 if OK; 1 on error
1182  *
1183  * <pre>
1184  * Notes:
1185  *      (1) Debug version, intended for use in the library when writing
1186  *          to files in a temp directory with names that are compiled in.
1187  *          This is used instead of numaWrite() for all such library calls.
1188  *      (2) The global variable LeptDebugOK defaults to 0, and can be set
1189  *          or cleared by the function setLeptDebugOK().
1190  * </pre>
1191  */
1192 l_int32
numaWriteDebug(const char * filename,NUMA * na)1193 numaWriteDebug(const char  *filename,
1194                NUMA        *na)
1195 {
1196     PROCNAME("numaWriteDebug");
1197 
1198     if (LeptDebugOK) {
1199         return numaWrite(filename, na);
1200     } else {
1201         L_INFO("write to named temp file %s is disabled\n", procName, filename);
1202         return 0;
1203     }
1204 }
1205 
1206 
1207 /*!
1208  * \brief   numaWrite()
1209  *
1210  * \param[in]    filename, na
1211  * \return  0 if OK, 1 on error
1212  */
1213 l_int32
numaWrite(const char * filename,NUMA * na)1214 numaWrite(const char  *filename,
1215           NUMA        *na)
1216 {
1217 l_int32  ret;
1218 FILE    *fp;
1219 
1220     PROCNAME("numaWrite");
1221 
1222     if (!filename)
1223         return ERROR_INT("filename not defined", procName, 1);
1224     if (!na)
1225         return ERROR_INT("na not defined", procName, 1);
1226 
1227     if ((fp = fopenWriteStream(filename, "w")) == NULL)
1228         return ERROR_INT("stream not opened", procName, 1);
1229     ret = numaWriteStream(fp, na);
1230     fclose(fp);
1231     if (ret)
1232         return ERROR_INT("na not written to stream", procName, 1);
1233     return 0;
1234 }
1235 
1236 
1237 /*!
1238  * \brief   numaWriteStream()
1239  *
1240  * \param[in]    fp file stream
1241  * \param[in]    na
1242  * \return  0 if OK, 1 on error
1243  */
1244 l_int32
numaWriteStream(FILE * fp,NUMA * na)1245 numaWriteStream(FILE  *fp,
1246                 NUMA  *na)
1247 {
1248 l_int32    i, n;
1249 l_float32  startx, delx;
1250 
1251     PROCNAME("numaWriteStream");
1252 
1253     if (!fp)
1254         return ERROR_INT("stream not defined", procName, 1);
1255     if (!na)
1256         return ERROR_INT("na not defined", procName, 1);
1257 
1258     n = numaGetCount(na);
1259     fprintf(fp, "\nNuma Version %d\n", NUMA_VERSION_NUMBER);
1260     fprintf(fp, "Number of numbers = %d\n", n);
1261     for (i = 0; i < n; i++)
1262         fprintf(fp, "  [%d] = %f\n", i, na->array[i]);
1263     fprintf(fp, "\n");
1264 
1265         /* Optional data */
1266     numaGetParameters(na, &startx, &delx);
1267     if (startx != 0.0 || delx != 1.0)
1268         fprintf(fp, "startx = %f, delx = %f\n", startx, delx);
1269 
1270     return 0;
1271 }
1272 
1273 
1274 /*!
1275  * \brief   numaWriteMem()
1276  *
1277  * \param[out]   pdata data of serialized numa; ascii
1278  * \param[out]   psize size of returned data
1279  * \param[in]    na
1280  * \return  0 if OK, 1 on error
1281  *
1282  * <pre>
1283  * Notes:
1284  *      (1) Serializes a numa in memory and puts the result in a buffer.
1285  * </pre>
1286  */
1287 l_int32
numaWriteMem(l_uint8 ** pdata,size_t * psize,NUMA * na)1288 numaWriteMem(l_uint8  **pdata,
1289              size_t    *psize,
1290              NUMA      *na)
1291 {
1292 l_int32  ret;
1293 FILE    *fp;
1294 
1295     PROCNAME("numaWriteMem");
1296 
1297     if (pdata) *pdata = NULL;
1298     if (psize) *psize = 0;
1299     if (!pdata)
1300         return ERROR_INT("&data not defined", procName, 1);
1301     if (!psize)
1302         return ERROR_INT("&size not defined", procName, 1);
1303     if (!na)
1304         return ERROR_INT("na not defined", procName, 1);
1305 
1306 #if HAVE_FMEMOPEN
1307     if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1308         return ERROR_INT("stream not opened", procName, 1);
1309     ret = numaWriteStream(fp, na);
1310 #else
1311     L_INFO("work-around: writing to a temp file\n", procName);
1312   #ifdef _WIN32
1313     if ((fp = fopenWriteWinTempfile()) == NULL)
1314         return ERROR_INT("tmpfile stream not opened", procName, 1);
1315   #else
1316     if ((fp = tmpfile()) == NULL)
1317         return ERROR_INT("tmpfile stream not opened", procName, 1);
1318   #endif  /* _WIN32 */
1319     ret = numaWriteStream(fp, na);
1320     rewind(fp);
1321     *pdata = l_binaryReadStream(fp, psize);
1322 #endif  /* HAVE_FMEMOPEN */
1323     fclose(fp);
1324     return ret;
1325 }
1326 
1327 
1328 /*--------------------------------------------------------------------------*
1329  *                     Numaa creation, destruction                          *
1330  *--------------------------------------------------------------------------*/
1331 /*!
1332  * \brief   numaaCreate()
1333  *
1334  * \param[in]    n size of numa ptr array to be alloc'd 0 for default
1335  * \return  naa, or NULL on error
1336  *
1337  */
1338 NUMAA *
numaaCreate(l_int32 n)1339 numaaCreate(l_int32  n)
1340 {
1341 NUMAA  *naa;
1342 
1343     PROCNAME("numaaCreate");
1344 
1345     if (n <= 0)
1346         n = INITIAL_PTR_ARRAYSIZE;
1347 
1348     if ((naa = (NUMAA *)LEPT_CALLOC(1, sizeof(NUMAA))) == NULL)
1349         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1350     if ((naa->numa = (NUMA **)LEPT_CALLOC(n, sizeof(NUMA *))) == NULL) {
1351         numaaDestroy(&naa);
1352         return (NUMAA *)ERROR_PTR("numa ptr array not made", procName, NULL);
1353     }
1354 
1355     naa->nalloc = n;
1356     naa->n = 0;
1357     return naa;
1358 }
1359 
1360 
1361 /*!
1362  * \brief   numaaCreateFull()
1363  *
1364  * \param[in]    nptr: size of numa ptr array to be alloc'd
1365  * \param[in]    n: size of individual numa arrays to be alloc'd 0 for default
1366  * \return  naa, or NULL on error
1367  *
1368  * <pre>
1369  * Notes:
1370  *      (1) This allocates numaa and fills the array with allocated numas.
1371  *          In use, after calling this function, use
1372  *              numaaAddNumber(naa, index, val);
1373  *          to add val to the index-th numa in naa.
1374  * </pre>
1375  */
1376 NUMAA *
numaaCreateFull(l_int32 nptr,l_int32 n)1377 numaaCreateFull(l_int32  nptr,
1378                 l_int32  n)
1379 {
1380 l_int32  i;
1381 NUMAA   *naa;
1382 NUMA    *na;
1383 
1384     naa = numaaCreate(nptr);
1385     for (i = 0; i < nptr; i++) {
1386         na = numaCreate(n);
1387         numaaAddNuma(naa, na, L_INSERT);
1388     }
1389 
1390     return naa;
1391 }
1392 
1393 
1394 /*!
1395  * \brief   numaaTruncate()
1396  *
1397  * \param[in]    naa
1398  * \return  0 if OK, 1 on error
1399  *
1400  * <pre>
1401  * Notes:
1402  *      (1) This identifies the largest index containing a numa that
1403  *          has any numbers within it, destroys all numa beyond that
1404  *          index, and resets the count.
1405  * </pre>
1406  */
1407 l_int32
numaaTruncate(NUMAA * naa)1408 numaaTruncate(NUMAA  *naa)
1409 {
1410 l_int32  i, n, nn;
1411 NUMA    *na;
1412 
1413     PROCNAME("numaaTruncate");
1414 
1415     if (!naa)
1416         return ERROR_INT("naa not defined", procName, 1);
1417 
1418     n = numaaGetCount(naa);
1419     for (i = n - 1; i >= 0; i--) {
1420         na = numaaGetNuma(naa, i, L_CLONE);
1421         if (!na)
1422             continue;
1423         nn = numaGetCount(na);
1424         numaDestroy(&na);
1425         if (nn == 0)
1426             numaDestroy(&naa->numa[i]);
1427         else
1428             break;
1429     }
1430     naa->n = i + 1;
1431     return 0;
1432 }
1433 
1434 
1435 /*!
1436  * \brief   numaaDestroy()
1437  *
1438  * \param[in,out]  pnaa to be nulled if it exists
1439  * \return  void
1440  */
1441 void
numaaDestroy(NUMAA ** pnaa)1442 numaaDestroy(NUMAA  **pnaa)
1443 {
1444 l_int32  i;
1445 NUMAA   *naa;
1446 
1447     PROCNAME("numaaDestroy");
1448 
1449     if (pnaa == NULL) {
1450         L_WARNING("ptr address is NULL!\n", procName);
1451         return;
1452     }
1453 
1454     if ((naa = *pnaa) == NULL)
1455         return;
1456 
1457     for (i = 0; i < naa->n; i++)
1458         numaDestroy(&naa->numa[i]);
1459     LEPT_FREE(naa->numa);
1460     LEPT_FREE(naa);
1461     *pnaa = NULL;
1462 
1463     return;
1464 }
1465 
1466 
1467 
1468 /*--------------------------------------------------------------------------*
1469  *                              Add Numa to Numaa                           *
1470  *--------------------------------------------------------------------------*/
1471 /*!
1472  * \brief   numaaAddNuma()
1473  *
1474  * \param[in]    naa
1475  * \param[in]    na   to be added
1476  * \param[in]    copyflag  L_INSERT, L_COPY, L_CLONE
1477  * \return  0 if OK, 1 on error
1478  */
1479 l_int32
numaaAddNuma(NUMAA * naa,NUMA * na,l_int32 copyflag)1480 numaaAddNuma(NUMAA   *naa,
1481              NUMA    *na,
1482              l_int32  copyflag)
1483 {
1484 l_int32  n;
1485 NUMA    *nac;
1486 
1487     PROCNAME("numaaAddNuma");
1488 
1489     if (!naa)
1490         return ERROR_INT("naa not defined", procName, 1);
1491     if (!na)
1492         return ERROR_INT("na not defined", procName, 1);
1493 
1494     if (copyflag == L_INSERT) {
1495         nac = na;
1496     } else if (copyflag == L_COPY) {
1497         if ((nac = numaCopy(na)) == NULL)
1498             return ERROR_INT("nac not made", procName, 1);
1499     } else if (copyflag == L_CLONE) {
1500         nac = numaClone(na);
1501     } else {
1502         return ERROR_INT("invalid copyflag", procName, 1);
1503     }
1504 
1505     n = numaaGetCount(naa);
1506     if (n >= naa->nalloc)
1507         numaaExtendArray(naa);
1508     naa->numa[n] = nac;
1509     naa->n++;
1510     return 0;
1511 }
1512 
1513 
1514 /*!
1515  * \brief   numaaExtendArray()
1516  *
1517  * \param[in]    naa
1518  * \return  0 if OK, 1 on error
1519  */
1520 static l_int32
numaaExtendArray(NUMAA * naa)1521 numaaExtendArray(NUMAA  *naa)
1522 {
1523     PROCNAME("numaaExtendArray");
1524 
1525     if (!naa)
1526         return ERROR_INT("naa not defined", procName, 1);
1527 
1528     if ((naa->numa = (NUMA **)reallocNew((void **)&naa->numa,
1529                               sizeof(NUMA *) * naa->nalloc,
1530                               2 * sizeof(NUMA *) * naa->nalloc)) == NULL)
1531             return ERROR_INT("new ptr array not returned", procName, 1);
1532 
1533     naa->nalloc *= 2;
1534     return 0;
1535 }
1536 
1537 
1538 /*----------------------------------------------------------------------*
1539  *                           Numaa accessors                            *
1540  *----------------------------------------------------------------------*/
1541 /*!
1542  * \brief   numaaGetCount()
1543  *
1544  * \param[in]    naa
1545  * \return  count number of numa, or 0 if no numa or on error
1546  */
1547 l_int32
numaaGetCount(NUMAA * naa)1548 numaaGetCount(NUMAA  *naa)
1549 {
1550     PROCNAME("numaaGetCount");
1551 
1552     if (!naa)
1553         return ERROR_INT("naa not defined", procName, 0);
1554     return naa->n;
1555 }
1556 
1557 
1558 /*!
1559  * \brief   numaaGetNumaCount()
1560  *
1561  * \param[in]    naa
1562  * \param[in]    index of numa in naa
1563  * \return  count of numbers in the referenced numa, or 0 on error.
1564  */
1565 l_int32
numaaGetNumaCount(NUMAA * naa,l_int32 index)1566 numaaGetNumaCount(NUMAA   *naa,
1567                   l_int32  index)
1568 {
1569     PROCNAME("numaaGetNumaCount");
1570 
1571     if (!naa)
1572         return ERROR_INT("naa not defined", procName, 0);
1573     if (index < 0 || index >= naa->n)
1574         return ERROR_INT("invalid index into naa", procName, 0);
1575     return numaGetCount(naa->numa[index]);
1576 }
1577 
1578 
1579 /*!
1580  * \brief   numaaGetNumberCount()
1581  *
1582  * \param[in]    naa
1583  * \return  count total number of numbers in the numaa,
1584  *                     or 0 if no numbers or on error
1585  */
1586 l_int32
numaaGetNumberCount(NUMAA * naa)1587 numaaGetNumberCount(NUMAA  *naa)
1588 {
1589 NUMA    *na;
1590 l_int32  n, sum, i;
1591 
1592     PROCNAME("numaaGetNumberCount");
1593 
1594     if (!naa)
1595         return ERROR_INT("naa not defined", procName, 0);
1596 
1597     n = numaaGetCount(naa);
1598     for (sum = 0, i = 0; i < n; i++) {
1599         na = numaaGetNuma(naa, i, L_CLONE);
1600         sum += numaGetCount(na);
1601         numaDestroy(&na);
1602     }
1603 
1604     return sum;
1605 }
1606 
1607 
1608 /*!
1609  * \brief   numaaGetPtrArray()
1610  *
1611  * \param[in]    naa
1612  * \return  the internal array of ptrs to Numa, or NULL on error
1613  *
1614  * <pre>
1615  * Notes:
1616  *      (1) This function is convenient for doing direct manipulation on
1617  *          a fixed size array of Numas.  To do this, it sets the count
1618  *          to the full size of the allocated array of Numa ptrs.
1619  *          The originating Numaa owns this array: DO NOT free it!
1620  *      (2) Intended usage:
1621  *            Numaa *naa = numaaCreate(n);
1622  *            Numa **array = numaaGetPtrArray(naa);
1623  *             ...  [manipulate Numas directly on the array]
1624  *            numaaDestroy(&naa);
1625  *      (3) Cautions:
1626  *           ~ Do not free this array; it is owned by tne Numaa.
1627  *           ~ Do not call any functions on the Numaa, other than
1628  *             numaaDestroy() when you're finished with the array.
1629  *             Adding a Numa will force a resize, destroying the ptr array.
1630  *           ~ Do not address the array outside its allocated size.
1631  *             With the bare array, there are no protections.  If the
1632  *             allocated size is n, array[n] is an error.
1633  * </pre>
1634  */
1635 NUMA **
numaaGetPtrArray(NUMAA * naa)1636 numaaGetPtrArray(NUMAA  *naa)
1637 {
1638     PROCNAME("numaaGetPtrArray");
1639 
1640     if (!naa)
1641         return (NUMA **)ERROR_PTR("naa not defined", procName, NULL);
1642 
1643     naa->n = naa->nalloc;
1644     return naa->numa;
1645 }
1646 
1647 
1648 /*!
1649  * \brief   numaaGetNuma()
1650  *
1651  * \param[in]    naa
1652  * \param[in]    index  to the index-th numa
1653  * \param[in]    accessflag   L_COPY or L_CLONE
1654  * \return  numa, or NULL on error
1655  */
1656 NUMA *
numaaGetNuma(NUMAA * naa,l_int32 index,l_int32 accessflag)1657 numaaGetNuma(NUMAA   *naa,
1658              l_int32  index,
1659              l_int32  accessflag)
1660 {
1661     PROCNAME("numaaGetNuma");
1662 
1663     if (!naa)
1664         return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
1665     if (index < 0 || index >= naa->n)
1666         return (NUMA *)ERROR_PTR("index not valid", procName, NULL);
1667 
1668     if (accessflag == L_COPY)
1669         return numaCopy(naa->numa[index]);
1670     else if (accessflag == L_CLONE)
1671         return numaClone(naa->numa[index]);
1672     else
1673         return (NUMA *)ERROR_PTR("invalid accessflag", procName, NULL);
1674 }
1675 
1676 
1677 /*!
1678  * \brief   numaaReplaceNuma()
1679  *
1680  * \param[in]    naa
1681  * \param[in]    index  to the index-th numa
1682  * \param[in]    na insert and replace any existing one
1683  * \return  0 if OK, 1 on error
1684  *
1685  * <pre>
1686  * Notes:
1687  *      (1) Any existing numa is destroyed, and the input one
1688  *          is inserted in its place.
1689  *      (2) If the index is invalid, return 1 (error)
1690  * </pre>
1691  */
1692 l_int32
numaaReplaceNuma(NUMAA * naa,l_int32 index,NUMA * na)1693 numaaReplaceNuma(NUMAA   *naa,
1694                  l_int32  index,
1695                  NUMA    *na)
1696 {
1697 l_int32  n;
1698 
1699     PROCNAME("numaaReplaceNuma");
1700 
1701     if (!naa)
1702         return ERROR_INT("naa not defined", procName, 1);
1703     if (!na)
1704         return ERROR_INT("na not defined", procName, 1);
1705     n = numaaGetCount(naa);
1706     if (index < 0 || index >= n)
1707         return ERROR_INT("index not valid", procName, 1);
1708 
1709     numaDestroy(&naa->numa[index]);
1710     naa->numa[index] = na;
1711     return 0;
1712 }
1713 
1714 
1715 /*!
1716  * \brief   numaaGetValue()
1717  *
1718  * \param[in]    naa
1719  * \param[in]    i index of numa within numaa
1720  * \param[in]    j index into numa
1721  * \param[out]   pfval [optional] float value
1722  * \param[out]   pival [optional] int value
1723  * \return  0 if OK, 1 on error
1724  */
1725 l_int32
numaaGetValue(NUMAA * naa,l_int32 i,l_int32 j,l_float32 * pfval,l_int32 * pival)1726 numaaGetValue(NUMAA      *naa,
1727               l_int32     i,
1728               l_int32     j,
1729               l_float32  *pfval,
1730               l_int32    *pival)
1731 {
1732 l_int32  n;
1733 NUMA    *na;
1734 
1735     PROCNAME("numaaGetValue");
1736 
1737     if (!pfval && !pival)
1738         return ERROR_INT("no return val requested", procName, 1);
1739     if (pfval) *pfval = 0.0;
1740     if (pival) *pival = 0;
1741     if (!naa)
1742         return ERROR_INT("naa not defined", procName, 1);
1743     n = numaaGetCount(naa);
1744     if (i < 0 || i >= n)
1745         return ERROR_INT("invalid index into naa", procName, 1);
1746     na = naa->numa[i];
1747     if (j < 0 || j >= na->n)
1748         return ERROR_INT("invalid index into na", procName, 1);
1749     if (pfval) *pfval = na->array[j];
1750     if (pival) *pival = (l_int32)(na->array[j]);
1751     return 0;
1752 }
1753 
1754 
1755 /*!
1756  * \brief   numaaAddNumber()
1757  *
1758  * \param[in]    naa
1759  * \param[in]    index of numa within numaa
1760  * \param[in]    val  float or int to be added; stored as a float
1761  * \return  0 if OK, 1 on error
1762  *
1763  * <pre>
1764  * Notes:
1765  *      (1) Adds to an existing numa only.
1766  * </pre>
1767  */
1768 l_int32
numaaAddNumber(NUMAA * naa,l_int32 index,l_float32 val)1769 numaaAddNumber(NUMAA     *naa,
1770                l_int32    index,
1771                l_float32  val)
1772 {
1773 l_int32  n;
1774 NUMA    *na;
1775 
1776     PROCNAME("numaaAddNumber");
1777 
1778     if (!naa)
1779         return ERROR_INT("naa not defined", procName, 1);
1780     n = numaaGetCount(naa);
1781     if (index < 0 || index >= n)
1782         return ERROR_INT("invalid index in naa", procName, 1);
1783 
1784     na = numaaGetNuma(naa, index, L_CLONE);
1785     numaAddNumber(na, val);
1786     numaDestroy(&na);
1787     return 0;
1788 }
1789 
1790 
1791 /*----------------------------------------------------------------------*
1792  *                      Serialize numaa for I/O                         *
1793  *----------------------------------------------------------------------*/
1794 /*!
1795  * \brief   numaaRead()
1796  *
1797  * \param[in]    filename
1798  * \return  naa, or NULL on error
1799  */
1800 NUMAA *
numaaRead(const char * filename)1801 numaaRead(const char  *filename)
1802 {
1803 FILE   *fp;
1804 NUMAA  *naa;
1805 
1806     PROCNAME("numaaRead");
1807 
1808     if (!filename)
1809         return (NUMAA *)ERROR_PTR("filename not defined", procName, NULL);
1810 
1811     if ((fp = fopenReadStream(filename)) == NULL)
1812         return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
1813     naa = numaaReadStream(fp);
1814     fclose(fp);
1815     if (!naa)
1816         return (NUMAA *)ERROR_PTR("naa not read", procName, NULL);
1817     return naa;
1818 }
1819 
1820 
1821 /*!
1822  * \brief   numaaReadStream()
1823  *
1824  * \param[in]    fp file stream
1825  * \return  naa, or NULL on error
1826  */
1827 NUMAA *
numaaReadStream(FILE * fp)1828 numaaReadStream(FILE  *fp)
1829 {
1830 l_int32    i, n, index, ret, version;
1831 NUMA      *na;
1832 NUMAA     *naa;
1833 
1834     PROCNAME("numaaReadStream");
1835 
1836     if (!fp)
1837         return (NUMAA *)ERROR_PTR("stream not defined", procName, NULL);
1838 
1839     ret = fscanf(fp, "\nNumaa Version %d\n", &version);
1840     if (ret != 1)
1841         return (NUMAA *)ERROR_PTR("not a numa file", procName, NULL);
1842     if (version != NUMA_VERSION_NUMBER)
1843         return (NUMAA *)ERROR_PTR("invalid numaa version", procName, NULL);
1844     if (fscanf(fp, "Number of numa = %d\n\n", &n) != 1)
1845         return (NUMAA *)ERROR_PTR("invalid number of numa", procName, NULL);
1846     if ((naa = numaaCreate(n)) == NULL)
1847         return (NUMAA *)ERROR_PTR("naa not made", procName, NULL);
1848 
1849     for (i = 0; i < n; i++) {
1850         if (fscanf(fp, "Numa[%d]:", &index) != 1) {
1851             numaaDestroy(&naa);
1852             return (NUMAA *)ERROR_PTR("invalid numa header", procName, NULL);
1853         }
1854         if ((na = numaReadStream(fp)) == NULL) {
1855             numaaDestroy(&naa);
1856             return (NUMAA *)ERROR_PTR("na not made", procName, NULL);
1857         }
1858         numaaAddNuma(naa, na, L_INSERT);
1859     }
1860 
1861     return naa;
1862 }
1863 
1864 
1865 /*!
1866  * \brief   numaaReadMem()
1867  *
1868  * \param[in]    data  numaa serialization; in ascii
1869  * \param[in]    size  of data; can use strlen to get it
1870  * \return  naa, or NULL on error
1871  */
1872 NUMAA *
numaaReadMem(const l_uint8 * data,size_t size)1873 numaaReadMem(const l_uint8  *data,
1874              size_t          size)
1875 {
1876 FILE   *fp;
1877 NUMAA  *naa;
1878 
1879     PROCNAME("numaaReadMem");
1880 
1881     if (!data)
1882         return (NUMAA *)ERROR_PTR("data not defined", procName, NULL);
1883     if ((fp = fopenReadFromMemory(data, size)) == NULL)
1884         return (NUMAA *)ERROR_PTR("stream not opened", procName, NULL);
1885 
1886     naa = numaaReadStream(fp);
1887     fclose(fp);
1888     if (!naa) L_ERROR("naa not read\n", procName);
1889     return naa;
1890 }
1891 
1892 
1893 /*!
1894  * \brief   numaaWrite()
1895  *
1896  * \param[in]    filename, naa
1897  * \return  0 if OK, 1 on error
1898  */
1899 l_int32
numaaWrite(const char * filename,NUMAA * naa)1900 numaaWrite(const char  *filename,
1901            NUMAA       *naa)
1902 {
1903 l_int32  ret;
1904 FILE    *fp;
1905 
1906     PROCNAME("numaaWrite");
1907 
1908     if (!filename)
1909         return ERROR_INT("filename not defined", procName, 1);
1910     if (!naa)
1911         return ERROR_INT("naa not defined", procName, 1);
1912 
1913     if ((fp = fopenWriteStream(filename, "w")) == NULL)
1914         return ERROR_INT("stream not opened", procName, 1);
1915     ret = numaaWriteStream(fp, naa);
1916     fclose(fp);
1917     if (ret)
1918         return ERROR_INT("naa not written to stream", procName, 1);
1919     return 0;
1920 }
1921 
1922 
1923 /*!
1924  * \brief   numaaWriteStream()
1925  *
1926  * \param[in]    fp file stream
1927  * \param[in]    naa
1928  * \return  0 if OK, 1 on error
1929  */
1930 l_int32
numaaWriteStream(FILE * fp,NUMAA * naa)1931 numaaWriteStream(FILE   *fp,
1932                  NUMAA  *naa)
1933 {
1934 l_int32  i, n;
1935 NUMA    *na;
1936 
1937     PROCNAME("numaaWriteStream");
1938 
1939     if (!fp)
1940         return ERROR_INT("stream not defined", procName, 1);
1941     if (!naa)
1942         return ERROR_INT("naa not defined", procName, 1);
1943 
1944     n = numaaGetCount(naa);
1945     fprintf(fp, "\nNumaa Version %d\n", NUMA_VERSION_NUMBER);
1946     fprintf(fp, "Number of numa = %d\n\n", n);
1947     for (i = 0; i < n; i++) {
1948         if ((na = numaaGetNuma(naa, i, L_CLONE)) == NULL)
1949             return ERROR_INT("na not found", procName, 1);
1950         fprintf(fp, "Numa[%d]:", i);
1951         numaWriteStream(fp, na);
1952         numaDestroy(&na);
1953     }
1954 
1955     return 0;
1956 }
1957 
1958 
1959 /*!
1960  * \brief   numaaWriteMem()
1961  *
1962  * \param[out]   pdata  data of serialized numaa; ascii
1963  * \param[out]   psize  size of returned data
1964  * \param[in]    naa
1965  * \return  0 if OK, 1 on error
1966  *
1967  * <pre>
1968  * Notes:
1969  *      (1) Serializes a numaa in memory and puts the result in a buffer.
1970  * </pre>
1971  */
1972 l_int32
numaaWriteMem(l_uint8 ** pdata,size_t * psize,NUMAA * naa)1973 numaaWriteMem(l_uint8  **pdata,
1974               size_t    *psize,
1975               NUMAA     *naa)
1976 {
1977 l_int32  ret;
1978 FILE    *fp;
1979 
1980     PROCNAME("numaaWriteMem");
1981 
1982     if (pdata) *pdata = NULL;
1983     if (psize) *psize = 0;
1984     if (!pdata)
1985         return ERROR_INT("&data not defined", procName, 1);
1986     if (!psize)
1987         return ERROR_INT("&size not defined", procName, 1);
1988     if (!naa)
1989         return ERROR_INT("naa not defined", procName, 1);
1990 
1991 #if HAVE_FMEMOPEN
1992     if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1993         return ERROR_INT("stream not opened", procName, 1);
1994     ret = numaaWriteStream(fp, naa);
1995 #else
1996     L_INFO("work-around: writing to a temp file\n", procName);
1997   #ifdef _WIN32
1998     if ((fp = fopenWriteWinTempfile()) == NULL)
1999         return ERROR_INT("tmpfile stream not opened", procName, 1);
2000   #else
2001     if ((fp = tmpfile()) == NULL)
2002         return ERROR_INT("tmpfile stream not opened", procName, 1);
2003   #endif  /* _WIN32 */
2004     ret = numaaWriteStream(fp, naa);
2005     rewind(fp);
2006     *pdata = l_binaryReadStream(fp, psize);
2007 #endif  /* HAVE_FMEMOPEN */
2008     fclose(fp);
2009     return ret;
2010 }
2011 
2012