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