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