Coverage Report

Created: 2026-10-28 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/leptonica/src/bytearray.c
Line
Count
Source
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  bytearray.c
29
 * <pre>
30
 *
31
 *   Functions for handling byte arrays, in analogy with C++ 'strings'
32
 *
33
 *      Creation, copy, clone, destruction
34
 *           L_BYTEA      *l_byteaCreate()
35
 *           L_BYTEA      *l_byteaInitFromMem()
36
 *           L_BYTEA      *l_byteaInitFromFile()
37
 *           L_BYTEA      *l_byteaInitFromStream()
38
 *           L_BYTEA      *l_byteaCopy()
39
 *           void          l_byteaDestroy()
40
 *
41
 *      Accessors
42
 *           size_t        l_byteaGetSize()
43
 *           l_uint8      *l_byteaGetData()
44
 *           l_uint8      *l_byteaCopyData()
45
 *
46
 *      Appending
47
 *           l_int32       l_byteaAppendData()
48
 *           l_int32       l_byteaAppendString()
49
 *           static l_int32  l_byteaExtendArrayToSize()
50
 *
51
 *      Join/Split
52
 *           l_int32       l_byteaJoin()
53
 *           l_int32       l_byteaSplit()
54
 *
55
 *      Search
56
 *           l_int32       l_byteaFindEachSequence()
57
 *
58
 *      Output to file
59
 *           l_int32       l_byteaWrite()
60
 *           l_int32       l_byteaWriteStream()
61
 *
62
 *   The internal data array is always null-terminated, for ease of use
63
 *   in the event that it is an ascii string without null bytes.
64
 * </pre>
65
 */
66
67
#ifdef HAVE_CONFIG_H
68
#include <config_auto.h>
69
#endif  /* HAVE_CONFIG_H */
70
71
#include <string.h>
72
#include "allheaders.h"
73
#include "array_internal.h"
74
75
    /* Bounds on array size */
76
static const l_uint32  MaxArraySize = 1000000000;   /* 10^9 bytes */
77
static const l_int32   InitialArraySize = 200;      /*!< n'importe quoi */
78
79
    /* Static function */
80
static l_int32 l_byteaExtendArrayToSize(L_BYTEA *ba, size_t size);
81
82
/*---------------------------------------------------------------------*
83
 *                  Creation, copy, clone, destruction                 *
84
 *---------------------------------------------------------------------*/
85
/*!
86
 * \brief   l_byteaCreate()
87
 *
88
 * \param[in]    nbytes    determines initial size of data array
89
 * \return  l_bytea, or NULL on error
90
 *
91
 * <pre>
92
 * Notes:
93
 *      (1) The allocated array is n + 1 bytes.  This allows room
94
 *          for null termination.
95
 * </pre>
96
 */
97
L_BYTEA *
98
l_byteaCreate(size_t  nbytes)
99
0
{
100
0
L_BYTEA  *ba;
101
102
0
    if (nbytes <= 0 || nbytes > MaxArraySize)
103
0
        nbytes = InitialArraySize;
104
0
    ba = (L_BYTEA *)LEPT_CALLOC(1, sizeof(L_BYTEA));
105
0
    if (!ba)
106
0
        return (L_BYTEA *)ERROR_PTR("bytea not made", __func__, NULL);
107
0
    ba->data = (l_uint8 *)LEPT_CALLOC(nbytes + 1, sizeof(l_uint8));
108
0
    if (!ba->data) {
109
0
        l_byteaDestroy(&ba);
110
0
        return (L_BYTEA *)ERROR_PTR("ba array not made", __func__, NULL);
111
0
    }
112
0
    ba->nalloc = nbytes + 1;
113
0
    ba->refcount = 1;
114
0
    return ba;
115
0
}
116
117
118
/*!
119
 * \brief   l_byteaInitFromMem()
120
 *
121
 * \param[in]    data    to be copied to the array
122
 * \param[in]    size    amount of data
123
 * \return  l_bytea, or NULL on error
124
 */
125
L_BYTEA *
126
l_byteaInitFromMem(const l_uint8  *data,
127
                   size_t          size)
128
0
{
129
0
L_BYTEA  *ba;
130
131
0
    if (!data)
132
0
        return (L_BYTEA *)ERROR_PTR("data not defined", __func__, NULL);
133
0
    if (size <= 0)
134
0
        return (L_BYTEA *)ERROR_PTR("no bytes to initialize", __func__, NULL);
135
0
    if (size > MaxArraySize)
136
0
        return (L_BYTEA *)ERROR_PTR("size is too big", __func__, NULL);
137
138
0
    if ((ba = l_byteaCreate(size)) == NULL)
139
0
        return (L_BYTEA *)ERROR_PTR("ba not made", __func__, NULL);
140
0
    memcpy(ba->data, data, size);
141
0
    ba->size = size;
142
0
    return ba;
143
0
}
144
145
146
/*!
147
 * \brief   l_byteaInitFromFile()
148
 *
149
 * \param[in]    fname
150
 * \return  l_bytea, or NULL on error
151
 */
152
L_BYTEA *
153
l_byteaInitFromFile(const char  *fname)
154
0
{
155
0
FILE     *fp;
156
0
L_BYTEA  *ba;
157
158
0
    if (!fname)
159
0
        return (L_BYTEA *)ERROR_PTR("fname not defined", __func__, NULL);
160
161
0
    if ((fp = fopenReadStream(fname)) == NULL)
162
0
        return (L_BYTEA *)ERROR_PTR_1("file stream not opened",
163
0
                                      fname, __func__, NULL);
164
0
    ba = l_byteaInitFromStream(fp);
165
0
    fclose(fp);
166
0
    if (!ba)
167
0
        return (L_BYTEA *)ERROR_PTR_1("ba not made", fname, __func__, NULL);
168
0
    return ba;
169
0
}
170
171
172
/*!
173
 * \brief   l_byteaInitFromStream()
174
 *
175
 * \param[in]    fp    file stream
176
 * \return  l_bytea, or NULL on error
177
 */
178
L_BYTEA *
179
l_byteaInitFromStream(FILE  *fp)
180
0
{
181
0
l_uint8  *data;
182
0
size_t    nbytes;
183
0
L_BYTEA  *ba;
184
185
0
    if (!fp)
186
0
        return (L_BYTEA *)ERROR_PTR("stream not defined", __func__, NULL);
187
188
0
    if ((data = l_binaryReadStream(fp, &nbytes)) == NULL)
189
0
        return (L_BYTEA *)ERROR_PTR("data not read", __func__, NULL);
190
0
    if ((ba = l_byteaCreate(nbytes)) == NULL) {
191
0
        LEPT_FREE(data);
192
0
        return (L_BYTEA *)ERROR_PTR("ba not made", __func__, NULL);
193
0
    }
194
0
    memcpy(ba->data, data, nbytes);
195
0
    ba->size = nbytes;
196
0
    LEPT_FREE(data);
197
0
    return ba;
198
0
}
199
200
201
/*!
202
 * \brief   l_byteaCopy()
203
 *
204
 * \param[in]    bas        source lba
205
 * \param[in]    copyflag   L_COPY, L_CLONE
206
 * \return  clone or copy of bas, or NULL on error
207
 *
208
 * <pre>
209
 * Notes:
210
 *      (1) If cloning, up the refcount and return a ptr to %bas.
211
 * </pre>
212
 */
213
L_BYTEA *
214
l_byteaCopy(L_BYTEA  *bas,
215
            l_int32   copyflag)
216
0
{
217
0
    if (!bas)
218
0
        return (L_BYTEA *)ERROR_PTR("bas not defined", __func__, NULL);
219
220
0
    if (copyflag == L_CLONE) {
221
0
        bas->refcount++;
222
0
        return bas;
223
0
    }
224
225
0
    return l_byteaInitFromMem(bas->data, bas->size);
226
0
}
227
228
229
/*!
230
 * \brief   l_byteaDestroy()
231
 *
232
 * \param[in,out]   pba    will be set to null before returning
233
 * \return  void
234
 *
235
 * <pre>
236
 * Notes:
237
 *      (1) Decrements the ref count and, if 0, destroys the lba.
238
 *      (2) Always nulls the input ptr.
239
 *      (3) If the data has been previously removed, the lba will
240
 *          have been nulled, so this will do nothing.
241
 * </pre>
242
 */
243
void
244
l_byteaDestroy(L_BYTEA  **pba)
245
0
{
246
0
L_BYTEA  *ba;
247
248
0
    if (pba == NULL) {
249
0
        L_WARNING("ptr address is null!\n", __func__);
250
0
        return;
251
0
    }
252
253
0
    if ((ba = *pba) == NULL)
254
0
        return;
255
256
        /* Decrement the ref count.  If it is 0, destroy the lba. */
257
0
    if (--ba->refcount == 0) {
258
0
        if (ba->data) LEPT_FREE(ba->data);
259
0
        LEPT_FREE(ba);
260
0
    }
261
0
    *pba = NULL;
262
0
}
263
264
265
/*---------------------------------------------------------------------*
266
 *                               Accessors                             *
267
 *---------------------------------------------------------------------*/
268
/*!
269
 * \brief   l_byteaGetSize()
270
 *
271
 * \param[in]    ba
272
 * \return  size of stored byte array, or 0 on error
273
 */
274
size_t
275
l_byteaGetSize(L_BYTEA  *ba)
276
0
{
277
0
    if (!ba)
278
0
        return ERROR_INT("ba not defined", __func__, 0);
279
0
    return ba->size;
280
0
}
281
282
283
/*!
284
 * \brief   l_byteaGetData()
285
 *
286
 * \param[in]    ba
287
 * \param[out]   psize     size of data in lba
288
 * \return  ptr to existing data array, or NULL on error
289
 *
290
 * <pre>
291
 * Notes:
292
 *      (1) The returned ptr is owned by %ba.  Do not free it!
293
 * </pre>
294
 */
295
l_uint8 *
296
l_byteaGetData(L_BYTEA  *ba,
297
               size_t   *psize)
298
0
{
299
0
    if (!ba)
300
0
        return (l_uint8 *)ERROR_PTR("ba not defined", __func__, NULL);
301
0
    if (!psize)
302
0
        return (l_uint8 *)ERROR_PTR("&size not defined", __func__, NULL);
303
304
0
    *psize = ba->size;
305
0
    return ba->data;
306
0
}
307
308
309
/*!
310
 * \brief   l_byteaCopyData()
311
 *
312
 * \param[in]    ba
313
 * \param[out]   psize     size of data in lba
314
 * \return  copy of data in use in the data array, or NULL on error.
315
 *
316
 * <pre>
317
 * Notes:
318
 *      (1) The returned data is owned by the caller.  The input %ba
319
 *          still owns the original data array.
320
 * </pre>
321
 */
322
l_uint8 *
323
l_byteaCopyData(L_BYTEA  *ba,
324
                size_t   *psize)
325
0
{
326
0
l_uint8  *data;
327
328
0
    if (!psize)
329
0
        return (l_uint8 *)ERROR_PTR("&size not defined", __func__, NULL);
330
0
    *psize = 0;
331
0
    if (!ba)
332
0
        return (l_uint8 *)ERROR_PTR("ba not defined", __func__, NULL);
333
334
0
    data = l_byteaGetData(ba, psize);
335
0
    return l_binaryCopy(data, *psize);
336
0
}
337
338
339
/*---------------------------------------------------------------------*
340
 *                               Appending                             *
341
 *---------------------------------------------------------------------*/
342
/*!
343
 * \brief   l_byteaAppendData()
344
 *
345
 * \param[in]    ba
346
 * \param[in]    newdata    byte array to be appended
347
 * \param[in]    newbytes   size of data array
348
 * \return  0 if OK, 1 on error
349
 */
350
l_ok
351
l_byteaAppendData(L_BYTEA        *ba,
352
                  const l_uint8  *newdata,
353
                  size_t          newbytes)
354
0
{
355
0
size_t  size, nalloc, reqsize;
356
357
0
    if (!ba)
358
0
        return ERROR_INT("ba not defined", __func__, 1);
359
0
    if (!newdata)
360
0
        return ERROR_INT("newdata not defined", __func__, 1);
361
362
0
    size = l_byteaGetSize(ba);
363
0
    reqsize = size + newbytes + 1;
364
0
    nalloc = ba->nalloc;
365
0
    if (nalloc < reqsize) {
366
0
        if (l_byteaExtendArrayToSize(ba, 2 * reqsize))
367
0
            return ERROR_INT("extension failed", __func__, 1);
368
0
    }
369
370
0
    memcpy(ba->data + size, newdata, newbytes);
371
0
    ba->size += newbytes;
372
0
    return 0;
373
0
}
374
375
376
/*!
377
 * \brief   l_byteaAppendString()
378
 *
379
 * \param[in]    ba
380
 * \param[in]    str    null-terminated string to be appended
381
 * \return  0 if OK, 1 on error
382
 */
383
l_ok
384
l_byteaAppendString(L_BYTEA     *ba,
385
                    const char  *str)
386
0
{
387
0
size_t  size, len, nalloc, reqsize;
388
389
0
    if (!ba)
390
0
        return ERROR_INT("ba not defined", __func__, 1);
391
0
    if (!str)
392
0
        return ERROR_INT("str not defined", __func__, 1);
393
394
0
    size = l_byteaGetSize(ba);
395
0
    len = strlen(str);
396
0
    reqsize = size + len + 1;
397
0
    nalloc = ba->nalloc;
398
0
    if (nalloc < reqsize) {
399
0
        if (l_byteaExtendArrayToSize(ba, 2 * reqsize))
400
0
            return ERROR_INT("extension failed", __func__, 1);
401
0
    }
402
403
0
    memcpy(ba->data + size, str, len);
404
0
    ba->size += len;
405
0
    return 0;
406
0
}
407
408
409
/*!
410
 * \brief   l_byteaExtendArrayToSize()
411
 *
412
 * \param[in]    ba
413
 * \param[in]    size    new size of lba data array
414
 * \return  0 if OK; 1 on error
415
 *
416
 * <pre>
417
 * Notes:
418
 *      (1) If necessary, reallocs the byte array to %size.
419
 *      (2) The max buffer size is 1 GB.
420
 * </pre>
421
 */
422
static l_int32
423
l_byteaExtendArrayToSize(L_BYTEA  *ba,
424
                         size_t    size)
425
0
{
426
0
    if (!ba)
427
0
        return ERROR_INT("ba not defined", __func__, 1);
428
0
    if (ba->nalloc > MaxArraySize)  /* belt & suspenders */
429
0
        return ERROR_INT("ba has too many ptrs", __func__, 1);
430
0
    if (size > MaxArraySize)
431
0
        return ERROR_INT("size > 1 GB; too large", __func__, 1);
432
0
    if (size <= ba->nalloc) {
433
0
        L_INFO("size too small; no extension\n", __func__);
434
0
        return 0;
435
0
    }
436
437
0
    if ((ba->data =
438
0
        (l_uint8 *)reallocNew((void **)&ba->data, ba->nalloc, size)) == NULL)
439
0
        return ERROR_INT("new array not returned", __func__, 1);
440
0
    ba->nalloc = size;
441
0
    return 0;
442
0
}
443
444
445
/*---------------------------------------------------------------------*
446
 *                        String join/split                            *
447
 *---------------------------------------------------------------------*/
448
/*!
449
 * \brief   l_byteaJoin()
450
 *
451
 * \param[in]       ba1
452
 * \param[in,out]   pba2    data array is added to the one in ba1;
453
 *                          then ba2 is destroyed and its pointer is nulled.
454
 * \return  0 if OK, 1 on error
455
 *
456
 * <pre>
457
 * Notes:
458
 *      (1) It is a no-op, not an error, for %ba2 to be null.
459
 * </pre>
460
 */
461
l_ok
462
l_byteaJoin(L_BYTEA   *ba1,
463
            L_BYTEA  **pba2)
464
0
{
465
0
l_uint8  *data2;
466
0
size_t    nbytes2;
467
0
L_BYTEA  *ba2;
468
469
0
    if (!ba1)
470
0
        return ERROR_INT("ba1 not defined", __func__, 1);
471
0
    if (!pba2)
472
0
        return ERROR_INT("&ba2 not defined", __func__, 1);
473
0
    if ((ba2 = *pba2) == NULL) return 0;
474
475
0
    data2 = l_byteaGetData(ba2, &nbytes2);
476
0
    l_byteaAppendData(ba1, data2, nbytes2);
477
478
0
    l_byteaDestroy(pba2);
479
0
    return 0;
480
0
}
481
482
483
/*!
484
 * \brief   l_byteaSplit()
485
 *
486
 * \param[in]    ba1       lba to split; array bytes nulled beyond the split loc
487
 * \param[in]    splitloc  location in ba1 to split; ba2 begins there
488
 * \param[out]   pba2      with data starting at splitloc
489
 * \return  0 if OK, 1 on error
490
 */
491
l_ok
492
l_byteaSplit(L_BYTEA   *ba1,
493
             size_t     splitloc,
494
             L_BYTEA  **pba2)
495
0
{
496
0
l_uint8  *data1;
497
0
size_t    nbytes1, nbytes2;
498
499
0
    if (!pba2)
500
0
        return ERROR_INT("&ba2 not defined", __func__, 1);
501
0
    *pba2 = NULL;
502
0
    if (!ba1)
503
0
        return ERROR_INT("ba1 not defined", __func__, 1);
504
505
0
    data1 = l_byteaGetData(ba1, &nbytes1);
506
0
    if (splitloc >= nbytes1)
507
0
        return ERROR_INT("splitloc invalid", __func__, 1);
508
0
    nbytes2 = nbytes1 - splitloc;
509
510
        /* Make the new lba */
511
0
    *pba2 = l_byteaInitFromMem(data1 + splitloc, nbytes2);
512
513
        /* Null the removed bytes in the input lba */
514
0
    memset(data1 + splitloc, 0, nbytes2);
515
0
    ba1->size = splitloc;
516
0
    return 0;
517
0
}
518
519
520
/*---------------------------------------------------------------------*
521
 *                                Search                               *
522
 *---------------------------------------------------------------------*/
523
/*!
524
 * \brief   l_byteaFindEachSequence()
525
 *
526
 * \param[in]    ba
527
 * \param[in]    sequence   subarray of bytes to find in data
528
 * \param[in]    seqlen     length of sequence, in bytes
529
 * \param[out]   pda        byte positions of each occurrence of %sequence
530
 * \return  0 if OK, 1 on error
531
 */
532
l_ok
533
l_byteaFindEachSequence(L_BYTEA        *ba,
534
                        const l_uint8  *sequence,
535
                        size_t          seqlen,
536
                        L_DNA         **pda)
537
0
{
538
0
l_uint8  *data;
539
0
size_t    size;
540
541
0
    if (!pda)
542
0
        return ERROR_INT("&da not defined", __func__, 1);
543
0
    *pda = NULL;
544
0
    if (!ba)
545
0
        return ERROR_INT("ba not defined", __func__, 1);
546
0
    if (!sequence)
547
0
        return ERROR_INT("sequence not defined", __func__, 1);
548
549
0
    data = l_byteaGetData(ba, &size);
550
0
    *pda = arrayFindEachSequence(data, size, sequence, seqlen);
551
0
    return 0;
552
0
}
553
554
555
/*---------------------------------------------------------------------*
556
 *                              Output to file                         *
557
 *---------------------------------------------------------------------*/
558
/*!
559
 * \brief   l_byteaWrite()
560
 *
561
 * \param[in]    fname      output file
562
 * \param[in]    ba
563
 * \param[in]    startloc   first byte to output
564
 * \param[in]    nbytes     number of bytes to write; use 0 to write to
565
 *                          the end of the data array
566
 * \return  0 if OK, 1 on error
567
 */
568
l_ok
569
l_byteaWrite(const char  *fname,
570
             L_BYTEA     *ba,
571
             size_t       startloc,
572
             size_t       nbytes)
573
0
{
574
0
l_int32  ret;
575
0
FILE    *fp;
576
577
0
    if (!fname)
578
0
        return ERROR_INT("fname not defined", __func__, 1);
579
0
    if (!ba)
580
0
        return ERROR_INT("ba not defined", __func__, 1);
581
582
0
    if ((fp = fopenWriteStream(fname, "wb")) == NULL)
583
0
        return ERROR_INT_1("stream not opened", fname, __func__, 1);
584
0
    ret = l_byteaWriteStream(fp, ba, startloc, nbytes);
585
0
    fclose(fp);
586
0
    return ret;
587
0
}
588
589
590
/*!
591
 * \brief   l_byteaWriteStream()
592
 *
593
 * \param[in]    fp         file stream opened for binary write
594
 * \param[in]    ba
595
 * \param[in]    startloc   first byte to output
596
 * \param[in]    nbytes     number of bytes to write; use 0 to write to
597
 *                          the end of the data array
598
 * \return  0 if OK, 1 on error
599
 */
600
l_ok
601
l_byteaWriteStream(FILE     *fp,
602
                   L_BYTEA  *ba,
603
                   size_t    startloc,
604
                   size_t    nbytes)
605
0
{
606
0
l_uint8  *data;
607
0
size_t    size, maxbytes;
608
609
0
    if (!fp)
610
0
        return ERROR_INT("stream not defined", __func__, 1);
611
0
    if (!ba)
612
0
        return ERROR_INT("ba not defined", __func__, 1);
613
614
0
    data = l_byteaGetData(ba, &size);
615
0
    if (startloc >= size)
616
0
        return ERROR_INT("invalid startloc", __func__, 1);
617
0
    maxbytes = size - startloc;
618
0
    nbytes = (nbytes == 0) ? maxbytes : L_MIN(nbytes, maxbytes);
619
620
0
    fwrite(data + startloc, 1, nbytes, fp);
621
0
    return 0;
622
0
}