Coverage Report

Created: 2024-02-28 06:46

/src/leptonica/src/ptabasic.c
Line
Count
Source (jump to first uncovered line)
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  ptabasic.c
29
 * <pre>
30
 *
31
 *      Pta creation, destruction, copy, clone, empty
32
 *           PTA            *ptaCreate()
33
 *           PTA            *ptaCreateFromNuma()
34
 *           void            ptaDestroy()
35
 *           PTA            *ptaCopy()
36
 *           PTA            *ptaCopyRange()
37
 *           PTA            *ptaClone()
38
 *           l_int32         ptaEmpty()
39
 *
40
 *      Pta array extension
41
 *           l_int32         ptaAddPt()
42
 *           static l_int32  ptaExtendArrays()
43
 *
44
 *      Pta insertion and removal
45
 *           l_int32         ptaInsertPt()
46
 *           l_int32         ptaRemovePt()
47
 *
48
 *      Pta accessors
49
 *           l_int32         ptaGetCount()
50
 *           l_int32         ptaGetPt()
51
 *           l_int32         ptaGetIPt()
52
 *           l_int32         ptaSetPt()
53
 *           l_int32         ptaGetArrays()
54
 *
55
 *      Pta serialized for I/O
56
 *           PTA            *ptaRead()
57
 *           PTA            *ptaReadStream()
58
 *           PTA            *ptaReadMem()
59
 *           l_int32         ptaWriteDebug()
60
 *           l_int32         ptaWrite()
61
 *           l_int32         ptaWriteStream()
62
 *           l_int32         ptaWriteMem()
63
 *
64
 *      Ptaa creation, destruction
65
 *           PTAA           *ptaaCreate()
66
 *           void            ptaaDestroy()
67
 *
68
 *      Ptaa array extension
69
 *           l_int32         ptaaAddPta()
70
 *           static l_int32  ptaaExtendArray()
71
 *
72
 *      Ptaa accessors
73
 *           l_int32         ptaaGetCount()
74
 *           l_int32         ptaaGetPta()
75
 *           l_int32         ptaaGetPt()
76
 *
77
 *      Ptaa array modifiers
78
 *           l_int32         ptaaInitFull()
79
 *           l_int32         ptaaReplacePta()
80
 *           l_int32         ptaaAddPt()
81
 *           l_int32         ptaaTruncate()
82
 *
83
 *      Ptaa serialized for I/O
84
 *           PTAA           *ptaaRead()
85
 *           PTAA           *ptaaReadStream()
86
 *           PTAA           *ptaaReadMem()
87
 *           l_int32         ptaaWrite()
88
 *           l_int32         ptaaWriteStream()
89
 *           l_int32         ptaaWriteMem()
90
 * </pre>
91
 */
92
93
#ifdef HAVE_CONFIG_H
94
#include <config_auto.h>
95
#endif  /* HAVE_CONFIG_H */
96
97
#include <string.h>
98
#include "allheaders.h"
99
#include "array_internal.h"
100
#include "pix_internal.h"
101
102
static const l_uint32  MaxArraySize = 100000000;  /* 100 million */
103
static const l_uint32  MaxPtrArraySize = 10000000;  /* 10 million */
104
static const l_int32 InitialArraySize = 50;      /*!< n'importe quoi */
105
106
    /* Static functions */
107
static l_int32 ptaExtendArrays(PTA *pta);
108
static l_int32 ptaaExtendArray(PTAA *ptaa);
109
110
/*---------------------------------------------------------------------*
111
 *                Pta creation, destruction, copy, clone               *
112
 *---------------------------------------------------------------------*/
113
/*!
114
 * \brief   ptaCreate()
115
 *
116
 * \param[in]    n    initial array sizes
117
 * \return  pta, or NULL on error.
118
 */
119
PTA *
120
ptaCreate(l_int32  n)
121
0
{
122
0
PTA  *pta;
123
124
0
    if (n <= 0 || n > (l_int32)MaxArraySize)
125
0
        n = InitialArraySize;
126
127
0
    pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA));
128
0
    pta->n = 0;
129
0
    pta->nalloc = n;
130
0
    pta->refcount = 1;
131
0
    pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
132
0
    pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
133
0
    if (!pta->x || !pta->y) {
134
0
        ptaDestroy(&pta);
135
0
        return (PTA *)ERROR_PTR("x and y arrays not both made", __func__, NULL);
136
0
    }
137
138
0
    return pta;
139
0
}
140
141
142
/*!
143
 * \brief   ptaCreateFromNuma()
144
 *
145
 * \param[in]    nax   [optional] can be null
146
 * \param[in]    nay
147
 * \return  pta, or NULL on error.
148
 */
149
PTA *
150
ptaCreateFromNuma(NUMA  *nax,
151
                  NUMA  *nay)
152
0
{
153
0
l_int32    i, n;
154
0
l_float32  startx, delx, xval, yval;
155
0
PTA       *pta;
156
157
0
    if (!nay)
158
0
        return (PTA *)ERROR_PTR("nay not defined", __func__, NULL);
159
0
    n = numaGetCount(nay);
160
0
    if (nax && numaGetCount(nax) != n)
161
0
        return (PTA *)ERROR_PTR("nax and nay sizes differ", __func__, NULL);
162
163
0
    pta = ptaCreate(n);
164
0
    numaGetParameters(nay, &startx, &delx);
165
0
    for (i = 0; i < n; i++) {
166
0
        if (nax)
167
0
            numaGetFValue(nax, i, &xval);
168
0
        else  /* use implicit x values from nay */
169
0
            xval = startx + i * delx;
170
0
        numaGetFValue(nay, i, &yval);
171
0
        ptaAddPt(pta, xval, yval);
172
0
    }
173
174
0
    return pta;
175
0
}
176
177
178
/*!
179
 * \brief   ptaDestroy()
180
 *
181
 * \param[in,out]   ppta   will be set to null before returning
182
 * \return  void
183
 *
184
 * <pre>
185
 * Notes:
186
 *      (1) Decrements the ref count and, if 0, destroys the pta.
187
 *      (2) Always nulls the input ptr.
188
 * </pre>
189
 */
190
void
191
ptaDestroy(PTA  **ppta)
192
0
{
193
0
PTA  *pta;
194
195
0
    if (ppta == NULL) {
196
0
        L_WARNING("ptr address is NULL!\n", __func__);
197
0
        return;
198
0
    }
199
200
0
    if ((pta = *ppta) == NULL)
201
0
        return;
202
203
0
    if (--pta->refcount == 0) {
204
0
        LEPT_FREE(pta->x);
205
0
        LEPT_FREE(pta->y);
206
0
        LEPT_FREE(pta);
207
0
    }
208
0
    *ppta = NULL;
209
0
}
210
211
212
/*!
213
 * \brief   ptaCopy()
214
 *
215
 * \param[in]    pta
216
 * \return  copy of pta, or NULL on error
217
 */
218
PTA *
219
ptaCopy(PTA  *pta)
220
0
{
221
0
l_int32    i;
222
0
l_float32  x, y;
223
0
PTA       *npta;
224
225
0
    if (!pta)
226
0
        return (PTA *)ERROR_PTR("pta not defined", __func__, NULL);
227
228
0
    if ((npta = ptaCreate(pta->nalloc)) == NULL)
229
0
        return (PTA *)ERROR_PTR("npta not made", __func__, NULL);
230
231
0
    for (i = 0; i < pta->n; i++) {
232
0
        ptaGetPt(pta, i, &x, &y);
233
0
        ptaAddPt(npta, x, y);
234
0
    }
235
236
0
    return npta;
237
0
}
238
239
240
/*!
241
 * \brief   ptaCopyRange()
242
 *
243
 * \param[in]    ptas
244
 * \param[in]    istart    starting index in ptas
245
 * \param[in]    iend      ending index in ptas; use 0 to copy to end
246
 * \return  0 if OK, 1 on error
247
 */
248
PTA *
249
ptaCopyRange(PTA     *ptas,
250
             l_int32  istart,
251
             l_int32  iend)
252
0
{
253
0
l_int32  n, i, x, y;
254
0
PTA     *ptad;
255
256
0
    if (!ptas)
257
0
        return (PTA *)ERROR_PTR("ptas not defined", __func__, NULL);
258
0
    n = ptaGetCount(ptas);
259
0
    if (istart < 0)
260
0
        istart = 0;
261
0
    if (istart >= n)
262
0
        return (PTA *)ERROR_PTR("istart out of bounds", __func__, NULL);
263
0
    if (iend <= 0 || iend >= n)
264
0
        iend = n - 1;
265
0
    if (istart > iend)
266
0
        return (PTA *)ERROR_PTR("istart > iend; no pts", __func__, NULL);
267
268
0
    if ((ptad = ptaCreate(iend - istart + 1)) == NULL)
269
0
        return (PTA *)ERROR_PTR("ptad not made", __func__, NULL);
270
0
    for (i = istart; i <= iend; i++) {
271
0
        ptaGetIPt(ptas, i, &x, &y);
272
0
        ptaAddPt(ptad, x, y);
273
0
    }
274
275
0
    return ptad;
276
0
}
277
278
279
/*!
280
 * \brief   ptaClone()
281
 *
282
 * \param[in]    pta
283
 * \return  ptr to same pta, or NULL on error
284
 */
285
PTA *
286
ptaClone(PTA  *pta)
287
0
{
288
0
    if (!pta)
289
0
        return (PTA *)ERROR_PTR("pta not defined", __func__, NULL);
290
291
0
    ++pta->refcount;
292
0
    return pta;
293
0
}
294
295
296
/*!
297
 * \brief   ptaEmpty()
298
 *
299
 * \param[in]    pta
300
 * \return  0 if OK, 1 on error
301
 *
302
 * <pre>
303
 * Notes:
304
 *      This only resets the Pta::n field, for reuse
305
 * </pre>
306
 */
307
l_ok
308
ptaEmpty(PTA  *pta)
309
0
{
310
0
    if (!pta)
311
0
        return ERROR_INT("ptad not defined", __func__, 1);
312
0
    pta->n = 0;
313
0
    return 0;
314
0
}
315
316
317
/*---------------------------------------------------------------------*
318
 *                         Pta array extension                         *
319
 *---------------------------------------------------------------------*/
320
/*!
321
 * \brief   ptaAddPt()
322
 *
323
 * \param[in]    pta
324
 * \param[in]    x, y
325
 * \return  0 if OK, 1 on error
326
 */
327
l_ok
328
ptaAddPt(PTA       *pta,
329
         l_float32  x,
330
         l_float32  y)
331
0
{
332
0
l_int32  n;
333
334
0
    if (!pta)
335
0
        return ERROR_INT("pta not defined", __func__, 1);
336
337
0
    n = pta->n;
338
0
    if (n >= pta->nalloc) {
339
0
        if (ptaExtendArrays(pta))
340
0
            return ERROR_INT("extension failed", __func__, 1);
341
0
    }
342
343
0
    pta->x[n] = x;
344
0
    pta->y[n] = y;
345
0
    pta->n++;
346
0
    return 0;
347
0
}
348
349
350
/*!
351
 * \brief   ptaExtendArrays()
352
 *
353
 * \param[in]    pta
354
 * \return  0 if OK; 1 on error
355
 *
356
 * <pre>
357
 * Notes:
358
 *      (1) Doubles the size of the array.
359
 *      (2) The max number of points is 100M.
360
 * </pre>
361
 */
362
static l_int32
363
ptaExtendArrays(PTA  *pta)
364
0
{
365
0
size_t  oldsize, newsize;
366
367
0
    if (!pta)
368
0
        return ERROR_INT("pta not defined", __func__, 1);
369
0
    if (pta->nalloc > (l_int32)MaxArraySize)  /* belt & suspenders */
370
0
        return ERROR_INT("pta at maximum size; can't extend", __func__, 1);
371
0
    oldsize = 4 * pta->nalloc;
372
0
    if (pta->nalloc > MaxArraySize / 2) {
373
0
        newsize = 4 * MaxArraySize;
374
0
        pta->nalloc = MaxArraySize;
375
0
    } else {
376
0
        newsize = 2 * oldsize;
377
0
        pta->nalloc *= 2;
378
0
    }
379
0
    if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x,
380
0
                                          oldsize, newsize)) == NULL)
381
0
        return ERROR_INT("new x array not returned", __func__, 1);
382
0
    if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y,
383
0
                                          oldsize, newsize)) == NULL)
384
0
        return ERROR_INT("new y array not returned", __func__, 1);
385
386
0
    return 0;
387
0
}
388
389
390
/*---------------------------------------------------------------------*
391
 *                     Pta insertion and removal                       *
392
 *---------------------------------------------------------------------*/
393
/*!
394
 * \brief   ptaInsertPt()
395
 *
396
 * \param[in]    pta
397
 * \param[in]    index   at which pt is to be inserted
398
 * \param[in]    x, y    point values
399
 * \return  0 if OK; 1 on error
400
 */
401
l_ok
402
ptaInsertPt(PTA     *pta,
403
            l_int32  index,
404
            l_int32  x,
405
            l_int32  y)
406
0
{
407
0
l_int32  i, n;
408
409
0
    if (!pta)
410
0
        return ERROR_INT("pta not defined", __func__, 1);
411
0
    n = ptaGetCount(pta);
412
0
    if (index < 0 || index > n) {
413
0
        L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n);
414
0
        return 1;
415
0
    }
416
417
0
    if (n > pta->nalloc) {
418
0
        if (ptaExtendArrays(pta))
419
0
            return ERROR_INT("extension failed", __func__, 1);
420
0
    }
421
0
    pta->n++;
422
0
    for (i = n; i > index; i--) {
423
0
        pta->x[i] = pta->x[i - 1];
424
0
        pta->y[i] = pta->y[i - 1];
425
0
    }
426
0
    pta->x[index] = x;
427
0
    pta->y[index] = y;
428
0
    return 0;
429
0
}
430
431
432
/*!
433
 * \brief   ptaRemovePt()
434
 *
435
 * \param[in]    pta
436
 * \param[in]    index    of point to be removed
437
 * \return  0 if OK, 1 on error
438
 *
439
 * <pre>
440
 * Notes:
441
 *      (1) This shifts pta[i] --> pta[i - 1] for all i > index.
442
 *      (2) It should not be used repeatedly on large arrays,
443
 *          because the function is O(n).
444
 * </pre>
445
 */
446
l_ok
447
ptaRemovePt(PTA     *pta,
448
            l_int32  index)
449
0
{
450
0
l_int32  i, n;
451
452
0
    if (!pta)
453
0
        return ERROR_INT("pta not defined", __func__, 1);
454
0
    n = ptaGetCount(pta);
455
0
    if (index < 0 || index >= n) {
456
0
        L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n - 1);
457
0
        return 1;
458
0
    }
459
460
        /* Remove the point */
461
0
    for (i = index + 1; i < n; i++) {
462
0
        pta->x[i - 1] = pta->x[i];
463
0
        pta->y[i - 1] = pta->y[i];
464
0
    }
465
0
    pta->n--;
466
0
    return 0;
467
0
}
468
469
470
/*---------------------------------------------------------------------*
471
 *                           Pta accessors                             *
472
 *---------------------------------------------------------------------*/
473
/*!
474
 * \brief   ptaGetCount()
475
 *
476
 * \param[in]    pta
477
 * \return  count, or 0 if no pta
478
 */
479
l_int32
480
ptaGetCount(PTA  *pta)
481
0
{
482
0
    if (!pta)
483
0
        return ERROR_INT("pta not defined", __func__, 0);
484
485
0
    return pta->n;
486
0
}
487
488
489
/*!
490
 * \brief   ptaGetPt()
491
 *
492
 * \param[in]    pta
493
 * \param[in]    index    into arrays
494
 * \param[out]   px       [optional] float x value
495
 * \param[out]   py       [optional] float y value
496
 * \return  0 if OK; 1 on error
497
 */
498
l_ok
499
ptaGetPt(PTA        *pta,
500
         l_int32     index,
501
         l_float32  *px,
502
         l_float32  *py)
503
0
{
504
0
    if (px) *px = 0;
505
0
    if (py) *py = 0;
506
0
    if (!pta)
507
0
        return ERROR_INT("pta not defined", __func__, 1);
508
0
    if (index < 0 || index >= pta->n)
509
0
        return ERROR_INT("invalid index", __func__, 1);
510
511
0
    if (px) *px = pta->x[index];
512
0
    if (py) *py = pta->y[index];
513
0
    return 0;
514
0
}
515
516
517
/*!
518
 * \brief   ptaGetIPt()
519
 *
520
 * \param[in]    pta
521
 * \param[in]    index    into arrays
522
 * \param[out]   px       [optional] integer x value
523
 * \param[out]   py       [optional] integer y value
524
 * \return  0 if OK; 1 on error
525
 */
526
l_ok
527
ptaGetIPt(PTA      *pta,
528
          l_int32   index,
529
          l_int32  *px,
530
          l_int32  *py)
531
0
{
532
0
    if (px) *px = 0;
533
0
    if (py) *py = 0;
534
0
    if (!pta)
535
0
        return ERROR_INT("pta not defined", __func__, 1);
536
0
    if (index < 0 || index >= pta->n)
537
0
        return ERROR_INT("invalid index", __func__, 1);
538
539
0
    if (px) *px = (l_int32)(pta->x[index] + 0.5);
540
0
    if (py) *py = (l_int32)(pta->y[index] + 0.5);
541
0
    return 0;
542
0
}
543
544
545
/*!
546
 * \brief   ptaSetPt()
547
 *
548
 * \param[in]    pta
549
 * \param[in]    index    into arrays
550
 * \param[in]    x, y
551
 * \return  0 if OK; 1 on error
552
 */
553
l_ok
554
ptaSetPt(PTA       *pta,
555
         l_int32    index,
556
         l_float32  x,
557
         l_float32  y)
558
0
{
559
0
    if (!pta)
560
0
        return ERROR_INT("pta not defined", __func__, 1);
561
0
    if (index < 0 || index >= pta->n)
562
0
        return ERROR_INT("invalid index", __func__, 1);
563
564
0
    pta->x[index] = x;
565
0
    pta->y[index] = y;
566
0
    return 0;
567
0
}
568
569
570
/*!
571
 * \brief   ptaGetArrays()
572
 *
573
 * \param[in]    pta
574
 * \param[out]   pnax    [optional] numa of x array
575
 * \param[out]   pnay    [optional] numa of y array
576
 * \return  0 if OK; 1 on error or if pta is empty
577
 *
578
 * <pre>
579
 * Notes:
580
 *      (1) This copies the internal arrays into new Numas.
581
 * </pre>
582
 */
583
l_ok
584
ptaGetArrays(PTA    *pta,
585
             NUMA  **pnax,
586
             NUMA  **pnay)
587
0
{
588
0
l_int32  i, n;
589
0
NUMA    *nax, *nay;
590
591
0
    if (!pnax && !pnay)
592
0
        return ERROR_INT("no output requested", __func__, 1);
593
0
    if (pnax) *pnax = NULL;
594
0
    if (pnay) *pnay = NULL;
595
0
    if (!pta)
596
0
        return ERROR_INT("pta not defined", __func__, 1);
597
0
    if ((n = ptaGetCount(pta)) == 0)
598
0
        return ERROR_INT("pta is empty", __func__, 1);
599
600
0
    if (pnax) {
601
0
        if ((nax = numaCreate(n)) == NULL)
602
0
            return ERROR_INT("nax not made", __func__, 1);
603
0
        *pnax = nax;
604
0
        for (i = 0; i < n; i++)
605
0
            nax->array[i] = pta->x[i];
606
0
        nax->n = n;
607
0
    }
608
0
    if (pnay) {
609
0
        if ((nay = numaCreate(n)) == NULL)
610
0
            return ERROR_INT("nay not made", __func__, 1);
611
0
        *pnay = nay;
612
0
        for (i = 0; i < n; i++)
613
0
            nay->array[i] = pta->y[i];
614
0
        nay->n = n;
615
0
    }
616
0
    return 0;
617
0
}
618
619
620
/*---------------------------------------------------------------------*
621
 *                       Pta serialized for I/O                        *
622
 *---------------------------------------------------------------------*/
623
/*!
624
 * \brief   ptaRead()
625
 *
626
 * \param[in]    filename
627
 * \return  pta, or NULL on error
628
 */
629
PTA *
630
ptaRead(const char  *filename)
631
0
{
632
0
FILE  *fp;
633
0
PTA   *pta;
634
635
0
    if (!filename)
636
0
        return (PTA *)ERROR_PTR("filename not defined", __func__, NULL);
637
638
0
    if ((fp = fopenReadStream(filename)) == NULL)
639
0
        return (PTA *)ERROR_PTR_1("stream not opened",
640
0
                                  filename, __func__, NULL);
641
0
    pta = ptaReadStream(fp);
642
0
    fclose(fp);
643
0
    if (!pta)
644
0
        return (PTA *)ERROR_PTR_1("pta not read", filename, __func__, NULL);
645
0
    return pta;
646
0
}
647
648
649
/*!
650
 * \brief   ptaReadStream()
651
 *
652
 * \param[in]    fp    file stream
653
 * \return  pta, or NULL on error
654
 *
655
 * <pre>
656
 * Notes:
657
 *      (1) It is OK for the pta to be empty (n == 0).
658
 * </pre>
659
660
 */
661
PTA *
662
ptaReadStream(FILE  *fp)
663
0
{
664
0
char       typestr[128];  /* hardcoded below in fscanf */
665
0
l_int32    i, n, ix, iy, type, version;
666
0
l_float32  x, y;
667
0
PTA       *pta;
668
669
0
    if (!fp)
670
0
        return (PTA *)ERROR_PTR("stream not defined", __func__, NULL);
671
672
0
    if (fscanf(fp, "\n Pta Version %d\n", &version) != 1)
673
0
        return (PTA *)ERROR_PTR("not a pta file", __func__, NULL);
674
0
    if (version != PTA_VERSION_NUMBER)
675
0
        return (PTA *)ERROR_PTR("invalid pta version", __func__, NULL);
676
0
    if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2)
677
0
        return (PTA *)ERROR_PTR("not a pta file", __func__, NULL);
678
0
    if (n < 0)
679
0
        return (PTA *)ERROR_PTR("num pts <= 0", __func__, NULL);
680
0
    if (n > (l_int32)MaxArraySize)
681
0
        return (PTA *)ERROR_PTR("too many pts", __func__, NULL);
682
0
    if (n == 0) L_INFO("the pta is empty\n", __func__);
683
684
0
    if (!strcmp(typestr, "float"))
685
0
        type = 0;
686
0
    else  /* typestr is "integer" */
687
0
        type = 1;
688
0
    if ((pta = ptaCreate(n)) == NULL)
689
0
        return (PTA *)ERROR_PTR("pta not made", __func__, NULL);
690
0
    for (i = 0; i < n; i++) {
691
0
        if (type == 0) {  /* data is float */
692
0
            if (fscanf(fp, "   (%f, %f)\n", &x, &y) != 2) {
693
0
                ptaDestroy(&pta);
694
0
                return (PTA *)ERROR_PTR("error reading floats", __func__, NULL);
695
0
            }
696
0
            ptaAddPt(pta, x, y);
697
0
        } else {   /* data is integer */
698
0
            if (fscanf(fp, "   (%d, %d)\n", &ix, &iy) != 2) {
699
0
                ptaDestroy(&pta);
700
0
                return (PTA *)ERROR_PTR("error reading ints", __func__, NULL);
701
0
            }
702
0
            ptaAddPt(pta, ix, iy);
703
0
        }
704
0
    }
705
706
0
    return pta;
707
0
}
708
709
710
/*!
711
 * \brief   ptaReadMem()
712
 *
713
 * \param[in]    data    serialization in ascii
714
 * \param[in]    size    of data in bytes; can use strlen to get it
715
 * \return  pta, or NULL on error
716
 */
717
PTA *
718
ptaReadMem(const l_uint8  *data,
719
           size_t          size)
720
0
{
721
0
FILE  *fp;
722
0
PTA   *pta;
723
724
0
    if (!data)
725
0
        return (PTA *)ERROR_PTR("data not defined", __func__, NULL);
726
0
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
727
0
        return (PTA *)ERROR_PTR("stream not opened", __func__, NULL);
728
729
0
    pta = ptaReadStream(fp);
730
0
    fclose(fp);
731
0
    if (!pta) L_ERROR("pta not read\n", __func__);
732
0
    return pta;
733
0
}
734
735
736
/*!
737
 * \brief   ptaWriteDebug()
738
 *
739
 * \param[in]    filename
740
 * \param[in]    pta
741
 * \param[in]    type       0 for float values; 1 for integer values
742
 * \return  0 if OK, 1 on error
743
 *
744
 * <pre>
745
 * Notes:
746
 *      (1) Debug version, intended for use in the library when writing
747
 *          to files in a temp directory with names that are compiled in.
748
 *          This is used instead of ptaWrite() for all such library calls.
749
 *      (2) The global variable LeptDebugOK defaults to 0, and can be set
750
 *          or cleared by the function setLeptDebugOK().
751
 * </pre>
752
 */
753
l_ok
754
ptaWriteDebug(const char  *filename,
755
              PTA         *pta,
756
              l_int32      type)
757
0
{
758
0
    if (LeptDebugOK) {
759
0
        return ptaWrite(filename, pta, type);
760
0
    } else {
761
0
        L_INFO("write to named temp file %s is disabled\n", __func__, filename);
762
0
        return 0;
763
0
    }
764
0
}
765
766
767
/*!
768
 * \brief   ptaWrite()
769
 *
770
 * \param[in]    filename
771
 * \param[in]    pta
772
 * \param[in]    type       0 for float values; 1 for integer values
773
 * \return  0 if OK, 1 on error
774
 */
775
l_ok
776
ptaWrite(const char  *filename,
777
         PTA         *pta,
778
         l_int32      type)
779
0
{
780
0
l_int32  ret;
781
0
FILE    *fp;
782
783
0
    if (!filename)
784
0
        return ERROR_INT("filename not defined", __func__, 1);
785
0
    if (!pta)
786
0
        return ERROR_INT("pta not defined", __func__, 1);
787
788
0
    if ((fp = fopenWriteStream(filename, "w")) == NULL)
789
0
        return ERROR_INT_1("stream not opened", filename, __func__, 1);
790
0
    ret = ptaWriteStream(fp, pta, type);
791
0
    fclose(fp);
792
0
    if (ret)
793
0
        return ERROR_INT_1("pta not written to stream", filename, __func__, 1);
794
0
    return 0;
795
0
}
796
797
798
/*!
799
 * \brief   ptaWriteStream()
800
 *
801
 * \param[in]    fp      file stream
802
 * \param[in]    pta
803
 * \param[in]    type    0 for float values; 1 for integer values
804
 * \return  0 if OK; 1 on error
805
 */
806
l_ok
807
ptaWriteStream(FILE    *fp,
808
               PTA     *pta,
809
               l_int32  type)
810
0
{
811
0
l_int32    i, n, ix, iy;
812
0
l_float32  x, y;
813
814
0
    if (!fp)
815
0
        return ERROR_INT("stream not defined", __func__, 1);
816
0
    if (!pta)
817
0
        return ERROR_INT("pta not defined", __func__, 1);
818
819
0
    n = ptaGetCount(pta);
820
0
    fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER);
821
0
    if (type == 0)
822
0
        fprintf(fp, " Number of pts = %d; format = float\n", n);
823
0
    else  /* type == 1 */
824
0
        fprintf(fp, " Number of pts = %d; format = integer\n", n);
825
0
    for (i = 0; i < n; i++) {
826
0
        if (type == 0) {  /* data is float */
827
0
            ptaGetPt(pta, i, &x, &y);
828
0
            fprintf(fp, "   (%f, %f)\n", x, y);
829
0
        } else {   /* data is integer */
830
0
            ptaGetIPt(pta, i, &ix, &iy);
831
0
            fprintf(fp, "   (%d, %d)\n", ix, iy);
832
0
        }
833
0
    }
834
835
0
    return 0;
836
0
}
837
838
839
/*!
840
 * \brief   ptaWriteMem()
841
 *
842
 * \param[out]   pdata    data of serialized pta; ascii
843
 * \param[out]   psize    size of returned data
844
 * \param[in]    pta
845
 * \param[in]    type     0 for float values; 1 for integer values
846
 * \return  0 if OK, 1 on error
847
 *
848
 * <pre>
849
 * Notes:
850
 *      (1) Serializes a pta in memory and puts the result in a buffer.
851
 * </pre>
852
 */
853
l_ok
854
ptaWriteMem(l_uint8  **pdata,
855
            size_t    *psize,
856
            PTA       *pta,
857
            l_int32    type)
858
0
{
859
0
l_int32  ret;
860
0
FILE    *fp;
861
862
0
    if (pdata) *pdata = NULL;
863
0
    if (psize) *psize = 0;
864
0
    if (!pdata)
865
0
        return ERROR_INT("&data not defined", __func__, 1);
866
0
    if (!psize)
867
0
        return ERROR_INT("&size not defined", __func__, 1);
868
0
    if (!pta)
869
0
        return ERROR_INT("pta not defined", __func__, 1);
870
871
0
#if HAVE_FMEMOPEN
872
0
    if ((fp = open_memstream((char **)pdata, psize)) == NULL)
873
0
        return ERROR_INT("stream not opened", __func__, 1);
874
0
    ret = ptaWriteStream(fp, pta, type);
875
0
    fputc('\0', fp);
876
0
    fclose(fp);
877
0
    *psize = *psize - 1;
878
#else
879
    L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
880
  #ifdef _WIN32
881
    if ((fp = fopenWriteWinTempfile()) == NULL)
882
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
883
  #else
884
    if ((fp = tmpfile()) == NULL)
885
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
886
  #endif  /* _WIN32 */
887
    ret = ptaWriteStream(fp, pta, type);
888
    rewind(fp);
889
    *pdata = l_binaryReadStream(fp, psize);
890
    fclose(fp);
891
#endif  /* HAVE_FMEMOPEN */
892
0
    return ret;
893
0
}
894
895
896
/*---------------------------------------------------------------------*
897
 *                     PTAA creation, destruction                      *
898
 *---------------------------------------------------------------------*/
899
/*!
900
 * \brief   ptaaCreate()
901
 *
902
 * \param[in]    n    initial number of ptrs
903
 * \return  ptaa, or NULL on error
904
 */
905
PTAA *
906
ptaaCreate(l_int32  n)
907
0
{
908
0
PTAA  *ptaa;
909
910
0
    if (n <= 0 || n > (l_int32)MaxPtrArraySize)
911
0
        n = InitialArraySize;
912
913
0
    ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA));
914
0
    ptaa->n = 0;
915
0
    ptaa->nalloc = n;
916
0
    if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) {
917
0
        ptaaDestroy(&ptaa);
918
0
        return (PTAA *)ERROR_PTR("pta ptrs not made", __func__, NULL);
919
0
    }
920
0
    return ptaa;
921
0
}
922
923
924
/*!
925
 * \brief   ptaaDestroy()
926
 *
927
 * \param[in,out]   pptaa   will be set to null before returning
928
 * \return  void
929
 */
930
void
931
ptaaDestroy(PTAA  **pptaa)
932
0
{
933
0
l_int32  i;
934
0
PTAA    *ptaa;
935
936
0
    if (pptaa == NULL) {
937
0
        L_WARNING("ptr address is NULL!\n", __func__);
938
0
        return;
939
0
    }
940
941
0
    if ((ptaa = *pptaa) == NULL)
942
0
        return;
943
944
0
    for (i = 0; i < ptaa->n; i++)
945
0
        ptaDestroy(&ptaa->pta[i]);
946
0
    LEPT_FREE(ptaa->pta);
947
0
    LEPT_FREE(ptaa);
948
0
    *pptaa = NULL;
949
0
}
950
951
952
/*---------------------------------------------------------------------*
953
 *                          PTAA array extension                       *
954
 *---------------------------------------------------------------------*/
955
/*!
956
 * \brief   ptaaAddPta()
957
 *
958
 * \param[in]    ptaa
959
 * \param[in]    pta         to be added
960
 * \param[in]    copyflag    L_INSERT, L_COPY, L_CLONE
961
 * \return  0 if OK, 1 on error
962
 */
963
l_ok
964
ptaaAddPta(PTAA    *ptaa,
965
           PTA     *pta,
966
           l_int32  copyflag)
967
0
{
968
0
l_int32  n;
969
0
PTA     *ptac;
970
971
0
    if (!ptaa)
972
0
        return ERROR_INT("ptaa not defined", __func__, 1);
973
0
    if (!pta)
974
0
        return ERROR_INT("pta not defined", __func__, 1);
975
976
0
    if (copyflag == L_INSERT) {
977
0
        ptac = pta;
978
0
    } else if (copyflag == L_COPY) {
979
0
        if ((ptac = ptaCopy(pta)) == NULL)
980
0
            return ERROR_INT("ptac not made", __func__, 1);
981
0
    } else if (copyflag == L_CLONE) {
982
0
        if ((ptac = ptaClone(pta)) == NULL)
983
0
            return ERROR_INT("pta clone not made", __func__, 1);
984
0
    } else {
985
0
        return ERROR_INT("invalid copyflag", __func__, 1);
986
0
    }
987
988
0
    n = ptaaGetCount(ptaa);
989
0
    if (n >= ptaa->nalloc) {
990
0
        if (ptaaExtendArray(ptaa)) {
991
0
            if (copyflag != L_INSERT)
992
0
                ptaDestroy(&ptac);
993
0
            return ERROR_INT("extension failed", __func__, 1);
994
0
        }
995
0
    }
996
997
0
    ptaa->pta[n] = ptac;
998
0
    ptaa->n++;
999
0
    return 0;
1000
0
}
1001
1002
1003
/*!
1004
 * \brief   ptaaExtendArray()
1005
 *
1006
 * \param[in]    ptaa
1007
 * \return  0 if OK, 1 on error
1008
 *
1009
 * <pre>
1010
 * Notes:
1011
 *      (1) This doubles the pta ptr array size.
1012
 *      (2) The max number of pta ptrs is 10M.
1013
 * </pre>
1014
 *
1015
 */
1016
static l_int32
1017
ptaaExtendArray(PTAA  *ptaa)
1018
0
{
1019
0
size_t  oldsize, newsize;
1020
1021
0
    if (!ptaa)
1022
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1023
0
    oldsize = ptaa->nalloc * sizeof(PTA *);
1024
0
    newsize = 2 * oldsize;
1025
0
    if (newsize > 8 * MaxPtrArraySize)
1026
0
        return ERROR_INT("newsize > 80 MB; too large", __func__, 1);
1027
1028
0
    if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta,
1029
0
                                        oldsize, newsize)) == NULL)
1030
0
        return ERROR_INT("new ptr array not returned", __func__, 1);
1031
1032
0
    ptaa->nalloc *= 2;
1033
0
    return 0;
1034
0
}
1035
1036
1037
/*---------------------------------------------------------------------*
1038
 *                          Ptaa accessors                             *
1039
 *---------------------------------------------------------------------*/
1040
/*!
1041
 * \brief   ptaaGetCount()
1042
 *
1043
 * \param[in]    ptaa
1044
 * \return  count, or 0 if no ptaa
1045
 */
1046
l_int32
1047
ptaaGetCount(PTAA  *ptaa)
1048
0
{
1049
0
    if (!ptaa)
1050
0
        return ERROR_INT("ptaa not defined", __func__, 0);
1051
1052
0
    return ptaa->n;
1053
0
}
1054
1055
1056
/*!
1057
 * \brief   ptaaGetPta()
1058
 *
1059
 * \param[in]    ptaa
1060
 * \param[in]    index         to the i-th pta
1061
 * \param[in]    accessflag    L_COPY or L_CLONE
1062
 * \return  pta, or NULL on error
1063
 */
1064
PTA *
1065
ptaaGetPta(PTAA    *ptaa,
1066
           l_int32  index,
1067
           l_int32  accessflag)
1068
0
{
1069
0
    if (!ptaa)
1070
0
        return (PTA *)ERROR_PTR("ptaa not defined", __func__, NULL);
1071
0
    if (index < 0 || index >= ptaa->n)
1072
0
        return (PTA *)ERROR_PTR("index not valid", __func__, NULL);
1073
1074
0
    if (accessflag == L_COPY)
1075
0
        return ptaCopy(ptaa->pta[index]);
1076
0
    else if (accessflag == L_CLONE)
1077
0
        return ptaClone(ptaa->pta[index]);
1078
0
    else
1079
0
        return (PTA *)ERROR_PTR("invalid accessflag", __func__, NULL);
1080
0
}
1081
1082
1083
/*!
1084
 * \brief   ptaaGetPt()
1085
 *
1086
 * \param[in]    ptaa
1087
 * \param[in]    ipta   to the i-th pta
1088
 * \param[in]    jpt    index to the j-th pt in the pta
1089
 * \param[out]   px     [optional] float x value
1090
 * \param[out]   py     [optional] float y value
1091
 * \return  0 if OK; 1 on error
1092
 */
1093
l_ok
1094
ptaaGetPt(PTAA       *ptaa,
1095
           l_int32     ipta,
1096
           l_int32     jpt,
1097
           l_float32  *px,
1098
           l_float32  *py)
1099
0
{
1100
0
PTA  *pta;
1101
1102
0
    if (px) *px = 0;
1103
0
    if (py) *py = 0;
1104
0
    if (!ptaa)
1105
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1106
0
    if (ipta < 0 || ipta >= ptaa->n)
1107
0
        return ERROR_INT("index ipta not valid", __func__, 1);
1108
1109
0
    pta = ptaaGetPta(ptaa, ipta, L_CLONE);
1110
0
    if (jpt < 0 || jpt >= pta->n) {
1111
0
        ptaDestroy(&pta);
1112
0
        return ERROR_INT("index jpt not valid", __func__, 1);
1113
0
    }
1114
1115
0
    ptaGetPt(pta, jpt, px, py);
1116
0
    ptaDestroy(&pta);
1117
0
    return 0;
1118
0
}
1119
1120
1121
/*---------------------------------------------------------------------*
1122
 *                        Ptaa array modifiers                         *
1123
 *---------------------------------------------------------------------*/
1124
/*!
1125
 * \brief   ptaaInitFull()
1126
 *
1127
 * \param[in]    ptaa    can have non-null ptrs in the ptr array
1128
 * \param[in]    pta     to be replicated into the entire ptr array
1129
 * \return  0 if OK; 1 on error
1130
 */
1131
l_ok
1132
ptaaInitFull(PTAA  *ptaa,
1133
             PTA   *pta)
1134
0
{
1135
0
l_int32  n, i;
1136
0
PTA     *ptat;
1137
1138
0
    if (!ptaa)
1139
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1140
0
    if (!pta)
1141
0
        return ERROR_INT("pta not defined", __func__, 1);
1142
1143
0
    n = ptaa->nalloc;
1144
0
    ptaa->n = n;
1145
0
    for (i = 0; i < n; i++) {
1146
0
        ptat = ptaCopy(pta);
1147
0
        ptaaReplacePta(ptaa, i, ptat);
1148
0
    }
1149
0
    return 0;
1150
0
}
1151
1152
1153
/*!
1154
 * \brief   ptaaReplacePta()
1155
 *
1156
 * \param[in]    ptaa
1157
 * \param[in]    index   to the index-th pta
1158
 * \param[in]    pta     insert and replace any existing one
1159
 * \return  0 if OK, 1 on error
1160
 *
1161
 * <pre>
1162
 * Notes:
1163
 *      (1) Any existing pta is destroyed, and the input one
1164
 *          is inserted in its place.
1165
 *      (2) If %index is invalid, return 1 (error)
1166
 * </pre>
1167
 */
1168
l_ok
1169
ptaaReplacePta(PTAA    *ptaa,
1170
               l_int32  index,
1171
               PTA     *pta)
1172
0
{
1173
0
l_int32  n;
1174
1175
0
    if (!ptaa)
1176
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1177
0
    if (!pta)
1178
0
        return ERROR_INT("pta not defined", __func__, 1);
1179
0
    n = ptaaGetCount(ptaa);
1180
0
    if (index < 0 || index >= n)
1181
0
        return ERROR_INT("index not valid", __func__, 1);
1182
1183
0
    ptaDestroy(&ptaa->pta[index]);
1184
0
    ptaa->pta[index] = pta;
1185
0
    return 0;
1186
0
}
1187
1188
1189
/*!
1190
 * \brief   ptaaAddPt()
1191
 *
1192
 * \param[in]    ptaa
1193
 * \param[in]    ipta   to the i-th pta
1194
 * \param[in]    x,y    point coordinates
1195
 * \return  0 if OK; 1 on error
1196
 */
1197
l_ok
1198
ptaaAddPt(PTAA      *ptaa,
1199
          l_int32    ipta,
1200
          l_float32  x,
1201
          l_float32  y)
1202
0
{
1203
0
PTA  *pta;
1204
1205
0
    if (!ptaa)
1206
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1207
0
    if (ipta < 0 || ipta >= ptaa->n)
1208
0
        return ERROR_INT("index ipta not valid", __func__, 1);
1209
1210
0
    pta = ptaaGetPta(ptaa, ipta, L_CLONE);
1211
0
    ptaAddPt(pta, x, y);
1212
0
    ptaDestroy(&pta);
1213
0
    return 0;
1214
0
}
1215
1216
1217
/*!
1218
 * \brief   ptaaTruncate()
1219
 *
1220
 * \param[in]    ptaa
1221
 * \return  0 if OK, 1 on error
1222
 *
1223
 * <pre>
1224
 * Notes:
1225
 *      (1) This identifies the largest index containing a pta that
1226
 *          has any points within it, destroys all pta above that index,
1227
 *          and resets the count.
1228
 * </pre>
1229
 */
1230
l_ok
1231
ptaaTruncate(PTAA  *ptaa)
1232
0
{
1233
0
l_int32  i, n, np;
1234
0
PTA     *pta;
1235
1236
0
    if (!ptaa)
1237
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1238
1239
0
    n = ptaaGetCount(ptaa);
1240
0
    for (i = n - 1; i >= 0; i--) {
1241
0
        pta = ptaaGetPta(ptaa, i, L_CLONE);
1242
0
        if (!pta) {
1243
0
            ptaa->n--;
1244
0
            continue;
1245
0
        }
1246
0
        np = ptaGetCount(pta);
1247
0
        ptaDestroy(&pta);
1248
0
        if (np == 0) {
1249
0
            ptaDestroy(&ptaa->pta[i]);
1250
0
            ptaa->n--;
1251
0
        } else {
1252
0
            break;
1253
0
        }
1254
0
    }
1255
0
    return 0;
1256
0
}
1257
1258
1259
/*---------------------------------------------------------------------*
1260
 *                       Ptaa serialized for I/O                       *
1261
 *---------------------------------------------------------------------*/
1262
/*!
1263
 * \brief   ptaaRead()
1264
 *
1265
 * \param[in]    filename
1266
 * \return  ptaa, or NULL on error
1267
 */
1268
PTAA *
1269
ptaaRead(const char  *filename)
1270
0
{
1271
0
FILE  *fp;
1272
0
PTAA  *ptaa;
1273
1274
0
    if (!filename)
1275
0
        return (PTAA *)ERROR_PTR("filename not defined", __func__, NULL);
1276
1277
0
    if ((fp = fopenReadStream(filename)) == NULL)
1278
0
        return (PTAA *)ERROR_PTR_1("stream not opened",
1279
0
                                   filename, __func__, NULL);
1280
0
    ptaa = ptaaReadStream(fp);
1281
0
    fclose(fp);
1282
0
    if (!ptaa)
1283
0
        return (PTAA *)ERROR_PTR_1("ptaa not read", filename, __func__, NULL);
1284
0
    return ptaa;
1285
0
}
1286
1287
1288
/*!
1289
 * \brief   ptaaReadStream()
1290
 *
1291
 * \param[in]    fp    file stream
1292
 * \return  ptaa, or NULL on error
1293
 *
1294
 * <pre>
1295
 * Notes:
1296
 *      (1) It is OK for the ptaa to be empty (n == 0).
1297
 * </pre>
1298
 */
1299
PTAA *
1300
ptaaReadStream(FILE  *fp)
1301
0
{
1302
0
l_int32  i, n, version;
1303
0
PTA     *pta;
1304
0
PTAA    *ptaa;
1305
1306
0
    if (!fp)
1307
0
        return (PTAA *)ERROR_PTR("stream not defined", __func__, NULL);
1308
1309
0
    if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1)
1310
0
        return (PTAA *)ERROR_PTR("not a ptaa file", __func__, NULL);
1311
0
    if (version != PTA_VERSION_NUMBER)
1312
0
        return (PTAA *)ERROR_PTR("invalid ptaa version", __func__, NULL);
1313
0
    if (fscanf(fp, "Number of Pta = %d\n", &n) != 1)
1314
0
        return (PTAA *)ERROR_PTR("not a ptaa file", __func__, NULL);
1315
0
    if (n < 0)
1316
0
        return (PTAA *)ERROR_PTR("num pta ptrs <= 0", __func__, NULL);
1317
0
    if (n > (l_int32)MaxPtrArraySize)
1318
0
        return (PTAA *)ERROR_PTR("too many pta ptrs", __func__, NULL);
1319
0
    if (n == 0) L_INFO("the ptaa is empty\n", __func__);
1320
1321
0
    if ((ptaa = ptaaCreate(n)) == NULL)
1322
0
        return (PTAA *)ERROR_PTR("ptaa not made", __func__, NULL);
1323
0
    for (i = 0; i < n; i++) {
1324
0
        if ((pta = ptaReadStream(fp)) == NULL) {
1325
0
            ptaaDestroy(&ptaa);
1326
0
            return (PTAA *)ERROR_PTR("error reading pta", __func__, NULL);
1327
0
        }
1328
0
        ptaaAddPta(ptaa, pta, L_INSERT);
1329
0
    }
1330
1331
0
    return ptaa;
1332
0
}
1333
1334
1335
/*!
1336
 * \brief   ptaaReadMem()
1337
 *
1338
 * \param[in]    data    serialization in ascii
1339
 * \param[in]    size    of data in bytes; can use strlen to get it
1340
 * \return  ptaa, or NULL on error
1341
 */
1342
PTAA *
1343
ptaaReadMem(const l_uint8  *data,
1344
            size_t          size)
1345
0
{
1346
0
FILE  *fp;
1347
0
PTAA  *ptaa;
1348
1349
0
    if (!data)
1350
0
        return (PTAA *)ERROR_PTR("data not defined", __func__, NULL);
1351
0
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
1352
0
        return (PTAA *)ERROR_PTR("stream not opened", __func__, NULL);
1353
1354
0
    ptaa = ptaaReadStream(fp);
1355
0
    fclose(fp);
1356
0
    if (!ptaa) L_ERROR("ptaa not read\n", __func__);
1357
0
    return ptaa;
1358
0
}
1359
1360
1361
/*!
1362
 * \brief   ptaaWriteDebug()
1363
 *
1364
 * \param[in]    filename
1365
 * \param[in]    ptaa
1366
 * \param[in]    type      0 for float values; 1 for integer values
1367
 * \return  0 if OK, 1 on error
1368
 *
1369
 * <pre>
1370
 * Notes:
1371
 *      (1) Debug version, intended for use in the library when writing
1372
 *          to files in a temp directory with names that are compiled in.
1373
 *          This is used instead of ptaaWrite() for all such library calls.
1374
 *      (2) The global variable LeptDebugOK defaults to 0, and can be set
1375
 *          or cleared by the function setLeptDebugOK().
1376
 * </pre>
1377
 */
1378
l_ok
1379
ptaaWriteDebug(const char  *filename,
1380
               PTAA        *ptaa,
1381
               l_int32      type)
1382
0
{
1383
0
    if (LeptDebugOK) {
1384
0
        return ptaaWrite(filename, ptaa, type);
1385
0
    } else {
1386
0
        L_INFO("write to named temp file %s is disabled\n", __func__, filename);
1387
0
        return 0;
1388
0
    }
1389
0
}
1390
1391
1392
/*!
1393
 * \brief   ptaaWrite()
1394
 *
1395
 * \param[in]    filename
1396
 * \param[in]    ptaa
1397
 * \param[in]    type      0 for float values; 1 for integer values
1398
 * \return  0 if OK, 1 on error
1399
 */
1400
l_ok
1401
ptaaWrite(const char  *filename,
1402
          PTAA        *ptaa,
1403
          l_int32      type)
1404
0
{
1405
0
l_int32  ret;
1406
0
FILE    *fp;
1407
1408
0
    if (!filename)
1409
0
        return ERROR_INT("filename not defined", __func__, 1);
1410
0
    if (!ptaa)
1411
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1412
1413
0
    if ((fp = fopenWriteStream(filename, "w")) == NULL)
1414
0
        return ERROR_INT_1("stream not opened", filename, __func__, 1);
1415
0
    ret = ptaaWriteStream(fp, ptaa, type);
1416
0
    fclose(fp);
1417
0
    if (ret)
1418
0
        return ERROR_INT_1("ptaa not written to stream", filename, __func__, 1);
1419
0
    return 0;
1420
0
}
1421
1422
1423
/*!
1424
 * \brief   ptaaWriteStream()
1425
 *
1426
 * \param[in]    fp      file stream
1427
 * \param[in]    ptaa
1428
 * \param[in]    type    0 for float values; 1 for integer values
1429
 * \return  0 if OK; 1 on error
1430
 */
1431
l_ok
1432
ptaaWriteStream(FILE    *fp,
1433
                PTAA    *ptaa,
1434
                l_int32  type)
1435
0
{
1436
0
l_int32  i, n;
1437
0
PTA     *pta;
1438
1439
0
    if (!fp)
1440
0
        return ERROR_INT("stream not defined", __func__, 1);
1441
0
    if (!ptaa)
1442
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1443
1444
0
    n = ptaaGetCount(ptaa);
1445
0
    fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER);
1446
0
    fprintf(fp, "Number of Pta = %d\n", n);
1447
0
    for (i = 0; i < n; i++) {
1448
0
        pta = ptaaGetPta(ptaa, i, L_CLONE);
1449
0
        ptaWriteStream(fp, pta, type);
1450
0
        ptaDestroy(&pta);
1451
0
    }
1452
1453
0
    return 0;
1454
0
}
1455
1456
1457
/*!
1458
 * \brief   ptaaWriteMem()
1459
 *
1460
 * \param[out]   pdata    data of serialized ptaa; ascii
1461
 * \param[out]   psize    size of returned data
1462
 * \param[in]    ptaa
1463
 * \param[in]    type     0 for float values; 1 for integer values
1464
 * \return  0 if OK, 1 on error
1465
 *
1466
 * <pre>
1467
 * Notes:
1468
 *      (1) Serializes %ptaa in memory and puts the result in a buffer.
1469
 * </pre>
1470
 */
1471
l_ok
1472
ptaaWriteMem(l_uint8  **pdata,
1473
             size_t    *psize,
1474
             PTAA      *ptaa,
1475
             l_int32    type)
1476
0
{
1477
0
l_int32  ret;
1478
0
FILE    *fp;
1479
1480
0
    if (pdata) *pdata = NULL;
1481
0
    if (psize) *psize = 0;
1482
0
    if (!pdata)
1483
0
        return ERROR_INT("&data not defined", __func__, 1);
1484
0
    if (!psize)
1485
0
        return ERROR_INT("&size not defined", __func__, 1);
1486
0
    if (!ptaa)
1487
0
        return ERROR_INT("ptaa not defined", __func__, 1);
1488
1489
0
#if HAVE_FMEMOPEN
1490
0
    if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1491
0
        return ERROR_INT("stream not opened", __func__, 1);
1492
0
    ret = ptaaWriteStream(fp, ptaa, type);
1493
0
    fputc('\0', fp);
1494
0
    fclose(fp);
1495
0
    *psize = *psize - 1;
1496
#else
1497
    L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1498
  #ifdef _WIN32
1499
    if ((fp = fopenWriteWinTempfile()) == NULL)
1500
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
1501
  #else
1502
    if ((fp = tmpfile()) == NULL)
1503
        return ERROR_INT("tmpfile stream not opened", __func__, 1);
1504
  #endif  /* _WIN32 */
1505
    ret = ptaaWriteStream(fp, ptaa, type);
1506
    rewind(fp);
1507
    *pdata = l_binaryReadStream(fp, psize);
1508
    fclose(fp);
1509
#endif  /* HAVE_FMEMOPEN */
1510
0
    return ret;
1511
0
}