Coverage Report

Created: 2024-06-18 06:05

/src/leptonica/src/utils1.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 utils1.c
29
 * <pre>
30
 *
31
 *       ------------------------------------------
32
 *       This file has these utilities:
33
 *         - error, warning and info messages
34
 *         - redirection of stderr
35
 *         - low-level endian conversions
36
 *         - file corruption operations
37
 *         - random and prime number operations
38
 *         - 64-bit hash functions
39
 *         - leptonica version number accessor
40
 *         - timing and date operations
41
 *       ------------------------------------------
42
 *
43
 *       Control of error, warning and info messages
44
 *           l_int32    setMsgSeverity()
45
 *
46
 *       Error return functions, invoked by macros
47
 *           l_int32    returnErrorInt()
48
 *           l_float32  returnErrorFloat()
49
 *           void      *returnErrorPtr()
50
 *           l_int32    returnErrorInt1()
51
 *           l_float32  returnErrorFloat1()
52
 *           void      *returnErrorPtr1()
53
 *
54
 *       Runtime redirection of stderr
55
 *           void leptSetStderrHandler()
56
 *           void lept_stderr()
57
 *
58
 *       Test files for equivalence
59
 *           l_int32    filesAreIdentical()
60
 *
61
 *       Byte-swapping data conversion
62
 *           l_uint16   convertOnBigEnd16()
63
 *           l_uint32   convertOnBigEnd32()
64
 *           l_uint16   convertOnLittleEnd16()
65
 *           l_uint32   convertOnLittleEnd32()
66
 *
67
 *       File corruption and byte replacement operations
68
 *           l_int32    fileCorruptByDeletion()
69
 *           l_int32    fileCorruptByMutation()
70
 *           l_int32    fileReplaceBytes()
71
 *
72
 *       Generate random integer in given interval
73
 *           l_int32    genRandomIntOnInterval()
74
 *
75
 *       Simple math functions
76
 *           l_int32    lept_roundftoi()
77
 *           l_int32    lept_floor()
78
 *           l_int32    lept_ceiling()
79
 *
80
 *       64-bit hash functions
81
 *           l_int32    l_hashStringToUint64()
82
 *           l_int32    l_hashStringToUint64Fast()
83
 *           l_int32    l_hashPtToUint64()
84
 *           l_int32    l_hashFloat64ToUint64()
85
 *
86
 *       Prime finders
87
 *           l_int32    findNextLargerPrime()
88
 *           l_int32    lept_isPrime()
89
 *
90
 *       Gray code conversion
91
 *           l_uint32   convertIntToGrayCode()
92
 *           l_uint32   convertGrayCodeToInt()
93
 *
94
 *       Leptonica version number
95
 *           char      *getLeptonicaVersion()
96
 *
97
 *       Timing
98
 *           void       startTimer()
99
 *           l_float32  stopTimer()
100
 *           L_TIMER    startTimerNested()
101
 *           l_float32  stopTimerNested()
102
 *           void       l_getCurrentTime()
103
 *           L_WALLTIMER  *startWallTimer()
104
 *           l_float32  stopWallTimer()
105
 *           void       l_getFormattedDate()
106
 *
107
 *  For all issues with cross-platform development, see utils2.c.
108
 * </pre>
109
 */
110
111
#ifdef HAVE_CONFIG_H
112
#include <config_auto.h>
113
#endif  /* HAVE_CONFIG_H */
114
115
#ifdef _WIN32
116
#include <windows.h>
117
#endif  /* _WIN32 */
118
119
#include <time.h>
120
#include "allheaders.h"
121
#include <math.h>
122
123
    /* Global for controlling message output at runtime */
124
LEPT_DLL l_int32  LeptMsgSeverity = DEFAULT_SEVERITY;
125
126
#define  DEBUG_SEV     0
127
128
/*----------------------------------------------------------------------*
129
 *                Control of error, warning and info messages           *
130
 *----------------------------------------------------------------------*/
131
/*!
132
 * \brief   setMsgSeverity()
133
 *
134
 * \param[in]    newsev
135
 * \return  oldsev
136
 *
137
 * <pre>
138
 * Notes:
139
 *      (1) setMsgSeverity() allows the user to specify the desired
140
 *          message severity threshold.  Messages of equal or greater
141
 *          severity will be output.  The previous message severity is
142
 *          returned when the new severity is set.
143
 *      (2) If L_SEVERITY_EXTERNAL is passed, then the severity will be
144
 *          obtained from the LEPT_MSG_SEVERITY environment variable.
145
 * </pre>
146
 */
147
l_int32
148
setMsgSeverity(l_int32  newsev)
149
0
{
150
0
l_int32  oldsev;
151
0
char    *envsev;
152
153
0
    oldsev = LeptMsgSeverity;
154
0
    if (newsev == L_SEVERITY_EXTERNAL) {
155
0
        envsev = getenv("LEPT_MSG_SEVERITY");
156
0
        if (envsev) {
157
0
            LeptMsgSeverity = atoi(envsev);
158
#if DEBUG_SEV
159
            L_INFO("message severity set to external\n", "setMsgSeverity");
160
#endif  /* DEBUG_SEV */
161
0
        } else {
162
#if DEBUG_SEV
163
            L_WARNING("environment var LEPT_MSG_SEVERITY not defined\n",
164
                      "setMsgSeverity");
165
#endif  /* DEBUG_SEV */
166
0
        }
167
0
    } else {
168
0
        LeptMsgSeverity = newsev;
169
#if DEBUG_SEV
170
        L_INFO("message severity set to %d\n", "setMsgSeverity", newsev);
171
#endif  /* DEBUG_SEV */
172
0
    }
173
174
0
    return oldsev;
175
0
}
176
177
178
/*----------------------------------------------------------------------*
179
 *                Error return functions, invoked by macros             *
180
 *----------------------------------------------------------------------*
181
 *                                                                      *
182
 *    (1) These error functions print messages to stderr and allow      *
183
 *        exit from the function that called them.                      *
184
 *    (2) They must be invoked only by the three argument macros        *
185
 *           ERROR_INT, ERROR_FLOAT, ERROR_PTR                          *
186
 *        or the four argument macros                                   *
187
 *           ERROR_INT_1, ERROR_FLOAT_1, ERROR_PTR_1                    *
188
 *        which are in environ.h.                                       *
189
 *    (3) The print output can be disabled at compile time, either      *
190
 *        by using -DNO_CONSOLE_IO or by setting LeptMsgSeverity.       *
191
 *----------------------------------------------------------------------*/
192
/*!
193
 * \brief   returnErrorInt()
194
 *
195
 * \param[in]    msg        error message
196
 * \param[in]    procname   use __func__
197
 * \param[in]    ival       return error val (typically 1 for an error)  
198
 * \return  ival
199
 */
200
l_int32
201
returnErrorInt(const char  *msg,
202
               const char  *procname,
203
               l_int32      ival)
204
4.83k
{
205
4.83k
    lept_stderr("Error in %s: %s\n", procname, msg);
206
4.83k
    return ival;
207
4.83k
}
208
209
210
/*!
211
 * \brief   returnErrorFloat()
212
 *
213
 * \param[in]    msg        error message
214
 * \param[in]    procname   use __func__
215
 * \param[in]    fval       return float error val
216
 * \return  fval
217
 */
218
l_float32
219
returnErrorFloat(const char  *msg,
220
                 const char  *procname,
221
                 l_float32    fval)
222
0
{
223
0
    lept_stderr("Error in %s: %s\n", procname, msg);
224
0
    return fval;
225
0
}
226
227
228
/*!
229
 * \brief   returnErrorPtr()
230
 *
231
 * \param[in]    msg        error message
232
 * \param[in]    procname   use __func__
233
 * \param[in]    pval       return error val (typically null for an error)
234
 * \return  pval
235
 */
236
void *
237
returnErrorPtr(const char  *msg,
238
               const char  *procname,
239
               void        *pval)
240
9.92k
{
241
9.92k
    lept_stderr("Error in %s: %s\n", procname, msg);
242
9.92k
    return pval;
243
9.92k
}
244
245
246
/*!
247
 * \brief   returnErrorInt1()
248
 *
249
 * \param[in]    msg        error message
250
 * \param[in]    arg        additional error message argument
251
 *                          (will be appended to the error message)
252
 * \param[in]    procname   use __func__
253
 * \param[in]    ival       return error val; typically 1 for an error return
254
 * \return  ival   typically 1 for an error return
255
 */
256
l_int32
257
returnErrorInt1(const char  *msg,
258
                const char  *arg,
259
                const char  *procname,
260
                l_int32      ival)
261
0
{
262
0
    lept_stderr("Leptonica Error in %s: %s: %s\n", procname, msg, arg);
263
0
    return ival;
264
0
}
265
266
267
/*!
268
 * \brief   returnErrorFloat1()
269
 *
270
 * \param[in]    msg        error message
271
 * \param[in]    arg        additional error message argument
272
 *                          (will be appended to the error message)
273
 * \param[in]    procname   use __func__
274
 * \param[in]    fval       return float error val
275
 * \return  fval
276
 */
277
l_float32
278
returnErrorFloat1(const char  *msg,
279
                  const char  *arg,
280
                  const char  *procname,
281
                  l_float32    fval)
282
0
{
283
0
    lept_stderr("Leptonica Error in %s: %s: %s\n", procname, msg, arg);
284
0
    return fval;
285
0
}
286
287
288
/*!
289
 * \brief   returnErrorPtr1()
290
 *
291
 * \param[in]    msg        error message
292
 * \param[in]    arg        additional error message argument
293
 *                          (will be appended to the error message)
294
 * \param[in]    procname   use __func__
295
 * \param[in]    pval       return error val (typically null for an error)
296
 * \return  pval
297
 */
298
void *
299
returnErrorPtr1(const char  *msg,
300
                const char  *arg,
301
                const char  *procname,
302
                void        *pval)
303
6.51k
{
304
6.51k
    lept_stderr("Leptonica Error in %s: %s: %s\n", procname, msg, arg);
305
6.51k
    return pval;
306
6.51k
}
307
308
309
/*------------------------------------------------------------------------*
310
 *                   Runtime redirection of stderr                        *
311
 *------------------------------------------------------------------------*
312
 *                                                                        *
313
 *  The user can provide a callback function to redirect messages         *
314
 *  that would otherwise go to stderr.  Here are two examples:            *
315
 *  (1) to stop all messages:                                             *
316
 *      void send_to_devnull(const char *msg) {}                          *
317
 *  (2) to write to the system logger:                                    *
318
 *      void send_to_syslog(const char *msg) {                            *
319
 *           syslog(1, msg);                                              *
320
 *      }                                                                 *
321
 *  These would then be registered using                                  *
322
 *      leptSetStderrHandler(send_to_devnull);                            *
323
 *  and                                                                   *
324
 *      leptSetStderrHandler(send_to_syslog);                             *
325
 *------------------------------------------------------------------------*/
326
    /* By default, all messages go to stderr */
327
static void lept_default_stderr_handler(const char *formatted_msg)
328
0
{
329
0
    if (formatted_msg)
330
0
        fputs(formatted_msg, stderr);
331
0
}
332
333
    /* The stderr callback handler is private to leptonica.
334
     * By default it writes to stderr.  */
335
void (*stderr_handler)(const char *) = lept_default_stderr_handler;
336
337
338
/*!
339
 * \brief   leptSetStderrHandler()
340
 *
341
 * \param[in]    handler   callback function for lept_stderr output
342
 * \return  void
343
 *
344
 * <pre>
345
 * Notes:
346
 *      (1) This registers a handler for redirection of output to stderr
347
 *          at runtime.
348
 *      (2) If called with NULL, the output goes to stderr.
349
 * </pre>
350
 */
351
void leptSetStderrHandler(void (*handler)(const char *))
352
1.61k
{
353
1.61k
    if (handler)
354
1.61k
        stderr_handler = handler;
355
0
    else
356
0
        stderr_handler = lept_default_stderr_handler;
357
1.61k
}
358
359
360
#define MAX_DEBUG_MESSAGE   2000
361
/*!
362
 * \brief   lept_stderr()
363
 *
364
 * \param[in]    fmt      format string
365
 * \param[in]    ...      varargs
366
 * \return  void
367
 *
368
 * <pre>
369
 * Notes:
370
 *      (1) This is a replacement for fprintf(), to allow redirection
371
 *          of output.  All calls to fprintf(stderr, ...) are replaced
372
 *          with calls to lept_stderr(...).
373
 *      (2) The message size is limited to 2K bytes.
374
        (3) This utility was provided by jbarlow83.
375
 * </pre>
376
 */
377
void lept_stderr(const char *fmt, ...)
378
34.5k
{
379
34.5k
va_list  args;
380
34.5k
char     msg[MAX_DEBUG_MESSAGE];
381
34.5k
l_int32  n;
382
383
34.5k
    va_start(args, fmt);
384
34.5k
    n = vsnprintf(msg, sizeof(msg), fmt, args);
385
34.5k
    va_end(args);
386
34.5k
    if (n < 0)
387
0
        return;
388
34.5k
    (*stderr_handler)(msg);
389
34.5k
}
390
391
392
/*--------------------------------------------------------------------*
393
 *                    Test files for equivalence                      *
394
 *--------------------------------------------------------------------*/
395
/*!
396
 * \brief   filesAreIdentical()
397
 *
398
 * \param[in]    fname1
399
 * \param[in]    fname2
400
 * \param[out]   psame     1 if identical; 0 if different
401
 * \return  0 if OK, 1 on error
402
 */
403
l_ok
404
filesAreIdentical(const char  *fname1,
405
                  const char  *fname2,
406
                  l_int32     *psame)
407
0
{
408
0
l_int32   i, same;
409
0
size_t    nbytes1, nbytes2;
410
0
l_uint8  *array1, *array2;
411
412
0
    if (!psame)
413
0
        return ERROR_INT("&same not defined", __func__, 1);
414
0
    *psame = 0;
415
0
    if (!fname1 || !fname2)
416
0
        return ERROR_INT("both names not defined", __func__, 1);
417
418
0
    nbytes1 = nbytesInFile(fname1);
419
0
    nbytes2 = nbytesInFile(fname2);
420
0
    if (nbytes1 != nbytes2)
421
0
        return 0;
422
423
0
    if ((array1 = l_binaryRead(fname1, &nbytes1)) == NULL)
424
0
        return ERROR_INT("array1 not read", __func__, 1);
425
0
    if ((array2 = l_binaryRead(fname2, &nbytes2)) == NULL) {
426
0
        LEPT_FREE(array1);
427
0
        return ERROR_INT("array2 not read", __func__, 1);
428
0
    }
429
0
    same = 1;
430
0
    for (i = 0; i < nbytes1; i++) {
431
0
        if (array1[i] != array2[i]) {
432
0
            same = 0;
433
0
            break;
434
0
        }
435
0
    }
436
0
    LEPT_FREE(array1);
437
0
    LEPT_FREE(array2);
438
0
    *psame = same;
439
440
0
    return 0;
441
0
}
442
443
444
/*--------------------------------------------------------------------------*
445
 *   16 and 32 bit byte-swapping on big endian and little  endian machines  *
446
 *--------------------------------------------------------------------------*
447
 *                                                                          *
448
 *   These are typically used for I/O conversions:                          *
449
 *      (1) endian conversion for data that was read from a file            *
450
 *      (2) endian conversion on data before it is written to a file        *
451
 *--------------------------------------------------------------------------*/
452
453
/*--------------------------------------------------------------------*
454
 *                        16-bit byte swapping                        *
455
 *--------------------------------------------------------------------*/
456
#ifdef L_BIG_ENDIAN
457
458
l_uint16
459
convertOnBigEnd16(l_uint16  shortin)
460
{
461
    return ((shortin << 8) | (shortin >> 8));
462
}
463
464
l_uint16
465
convertOnLittleEnd16(l_uint16  shortin)
466
{
467
    return  shortin;
468
}
469
470
#else     /* L_LITTLE_ENDIAN */
471
472
l_uint16
473
convertOnLittleEnd16(l_uint16  shortin)
474
0
{
475
0
    return ((shortin << 8) | (shortin >> 8));
476
0
}
477
478
l_uint16
479
convertOnBigEnd16(l_uint16  shortin)
480
0
{
481
0
    return  shortin;
482
0
}
483
484
#endif  /* L_BIG_ENDIAN */
485
486
487
/*--------------------------------------------------------------------*
488
 *                        32-bit byte swapping                        *
489
 *--------------------------------------------------------------------*/
490
#ifdef L_BIG_ENDIAN
491
492
l_uint32
493
convertOnBigEnd32(l_uint32  wordin)
494
{
495
    return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
496
            ((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
497
}
498
499
l_uint32
500
convertOnLittleEnd32(l_uint32  wordin)
501
{
502
    return wordin;
503
}
504
505
#else  /*  L_LITTLE_ENDIAN */
506
507
l_uint32
508
convertOnLittleEnd32(l_uint32  wordin)
509
0
{
510
0
    return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
511
0
            ((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
512
0
}
513
514
l_uint32
515
convertOnBigEnd32(l_uint32  wordin)
516
0
{
517
0
    return wordin;
518
0
}
519
520
#endif  /* L_BIG_ENDIAN */
521
522
523
/*---------------------------------------------------------------------*
524
 *           File corruption and byte replacement operations           *
525
 *---------------------------------------------------------------------*/
526
/*!
527
 * \brief   fileCorruptByDeletion()
528
 *
529
 * \param[in]    filein
530
 * \param[in]    loc       fractional location of start of deletion
531
 * \param[in]    size      fractional size of deletion
532
 * \param[in]    fileout   corrupted file
533
 * \return  0 if OK, 1 on error
534
 *
535
 * <pre>
536
 * Notes:
537
 *      (1) %loc and %size are expressed as a fraction of the file size.
538
 *      (2) This makes a copy of the data in %filein, where bytes in the
539
 *          specified region have deleted.
540
 *      (3) If (%loc + %size) >= 1.0, this deletes from the position
541
 *          represented by %loc to the end of the file.
542
 *      (4) It is useful for testing robustness of I/O wrappers when the
543
 *          data is corrupted, by simulating data corruption by deletion.
544
 * </pre>
545
 */
546
l_ok
547
fileCorruptByDeletion(const char  *filein,
548
                      l_float32    loc,
549
                      l_float32    size,
550
                      const char  *fileout)
551
0
{
552
0
l_int32   i, locb, sizeb, rembytes;
553
0
size_t    inbytes, outbytes;
554
0
l_uint8  *datain, *dataout;
555
556
0
    if (!filein || !fileout)
557
0
        return ERROR_INT("filein and fileout not both specified", __func__, 1);
558
0
    if (loc < 0.0 || loc >= 1.0)
559
0
        return ERROR_INT("loc must be in [0.0 ... 1.0)", __func__, 1);
560
0
    if (size <= 0.0)
561
0
        return ERROR_INT("size must be > 0.0", __func__, 1);
562
0
    if (loc + size > 1.0)
563
0
        size = 1.0f - loc;
564
565
0
    datain = l_binaryRead(filein, &inbytes);
566
0
    locb = (l_int32)(loc * inbytes + 0.5);
567
0
    locb = L_MIN(locb, inbytes - 1);
568
0
    sizeb = (l_int32)(size * inbytes + 0.5);
569
0
    sizeb = L_MAX(1, sizeb);
570
0
    sizeb = L_MIN(sizeb, inbytes - locb);  /* >= 1 */
571
0
    L_INFO("Removed %d bytes at location %d\n", __func__, sizeb, locb);
572
0
    rembytes = inbytes - locb - sizeb;  /* >= 0; to be copied, after excision */
573
574
0
    outbytes = inbytes - sizeb;
575
0
    dataout = (l_uint8 *)LEPT_CALLOC(outbytes, 1);
576
0
    for (i = 0; i < locb; i++)
577
0
        dataout[i] = datain[i];
578
0
    for (i = 0; i < rembytes; i++)
579
0
        dataout[locb + i] = datain[locb + sizeb + i];
580
0
    l_binaryWrite(fileout, "w", dataout, outbytes);
581
582
0
    LEPT_FREE(datain);
583
0
    LEPT_FREE(dataout);
584
0
    return 0;
585
0
}
586
587
588
/*!
589
 * \brief   fileCorruptByMutation()
590
 *
591
 * \param[in]    filein
592
 * \param[in]    loc       fractional location of start of randomization
593
 * \param[in]    size      fractional size of randomization
594
 * \param[in]    fileout   corrupted file
595
 * \return  0 if OK, 1 on error
596
 *
597
 * <pre>
598
 * Notes:
599
 *      (1) %loc and %size are expressed as a fraction of the file size.
600
 *      (2) This makes a copy of the data in %filein, where bytes in the
601
 *          specified region have been replaced by random data.
602
 *      (3) If (%loc + %size) >= 1.0, this modifies data from the position
603
 *          represented by %loc to the end of the file.
604
 *      (4) It is useful for testing robustness of I/O wrappers when the
605
 *          data is corrupted, by simulating data corruption.
606
 * </pre>
607
 */
608
l_ok
609
fileCorruptByMutation(const char  *filein,
610
                      l_float32    loc,
611
                      l_float32    size,
612
                      const char  *fileout)
613
0
{
614
0
l_int32   i, locb, sizeb;
615
0
size_t    bytes;
616
0
l_uint8  *data;
617
618
0
    if (!filein || !fileout)
619
0
        return ERROR_INT("filein and fileout not both specified", __func__, 1);
620
0
    if (loc < 0.0 || loc >= 1.0)
621
0
        return ERROR_INT("loc must be in [0.0 ... 1.0)", __func__, 1);
622
0
    if (size <= 0.0)
623
0
        return ERROR_INT("size must be > 0.0", __func__, 1);
624
0
    if (loc + size > 1.0)
625
0
        size = 1.0f - loc;
626
627
0
    data = l_binaryRead(filein, &bytes);
628
0
    locb = (l_int32)(loc * bytes + 0.5);
629
0
    locb = L_MIN(locb, bytes - 1);
630
0
    sizeb = (l_int32)(size * bytes + 0.5);
631
0
    sizeb = L_MAX(1, sizeb);
632
0
    sizeb = L_MIN(sizeb, bytes - locb);  /* >= 1 */
633
0
    L_INFO("Randomizing %d bytes at location %d\n", __func__, sizeb, locb);
634
635
        /* Make an array of random bytes and do the substitution */
636
0
    for (i = 0; i < sizeb; i++) {
637
0
        data[locb + i] =
638
0
            (l_uint8)(255.9 * ((l_float64)rand() / (l_float64)RAND_MAX));
639
0
    }
640
641
0
    l_binaryWrite(fileout, "w", data, bytes);
642
0
    LEPT_FREE(data);
643
0
    return 0;
644
0
}
645
646
647
/*!
648
 * \brief   fileReplaceBytes()
649
 *
650
 * \param[in]    filein      input file
651
 * \param[in]    start       start location for replacement
652
 * \param[in]    nbytes      number of bytes to be removed
653
 * \param[in]    newdata     replacement bytes
654
 * \param[in]    newsize     size of replacement bytes
655
 * \param[in]    fileout     output file
656
 * \return  0 if OK, 1 on error
657
 *
658
 * <pre>
659
 * Notes:
660
 *      (1) To remove %nbytes without replacement, set %newdata == NULL.
661
 *      (2) One use is for replacing the date/time in a pdf file by a
662
 *          string of 12 '0's, effectively removing the date without
663
 *          invalidating the byte counters in the pdf file:
664
 *              fileReplaceBytes(filein 86 12 (char *)"000000000000" 12 fileout
665
 * </pre>
666
 */
667
l_ok
668
fileReplaceBytes(const char  *filein,
669
                 l_int32      start,
670
                 l_int32      nbytes,
671
                 l_uint8     *newdata,
672
                 size_t       newsize,
673
                 const char  *fileout)
674
0
{
675
0
l_int32   i, index;
676
0
size_t    inbytes, outbytes;
677
0
l_uint8  *datain, *dataout;
678
679
0
    if (!filein || !fileout)
680
0
        return ERROR_INT("filein and fileout not both specified", __func__, 1);
681
682
0
    datain = l_binaryRead(filein, &inbytes);
683
0
    if (start + nbytes > inbytes)
684
0
        L_WARNING("start + nbytes > length(filein) = %zu\n", __func__, inbytes);
685
686
0
    if (!newdata) newsize = 0;
687
0
    outbytes = inbytes - nbytes + newsize;
688
0
    if ((dataout = (l_uint8 *)LEPT_CALLOC(outbytes, 1)) == NULL) {
689
0
        LEPT_FREE(datain);
690
0
        return ERROR_INT("calloc fail for dataout", __func__, 1);
691
0
    }
692
693
0
    for (i = 0; i < start; i++)
694
0
        dataout[i] = datain[i];
695
0
    for (i = start; i < start + newsize; i++)
696
0
        dataout[i] = newdata[i - start];
697
0
    index = start + nbytes;  /* for datain */
698
0
    start += newsize;  /* for dataout */
699
0
    for (i = start; i < outbytes; i++, index++)
700
0
        dataout[i] = datain[index];
701
0
    l_binaryWrite(fileout, "w", dataout, outbytes);
702
703
0
    LEPT_FREE(datain);
704
0
    LEPT_FREE(dataout);
705
0
    return 0;
706
0
}
707
708
709
/*---------------------------------------------------------------------*
710
 *              Generate random integer in given interval              *
711
 *---------------------------------------------------------------------*/
712
/*!
713
 * \brief   genRandomIntOnInterval()
714
 *
715
 * \param[in]    start     beginning of interval; can be < 0
716
 * \param[in]    end       end of interval; must be >= start
717
 * \param[in]    seed      use 0 to skip; otherwise call srand
718
 * \param[out]   pval      random integer in interval [start ... end]
719
 * \return  0 if OK, 1 on error
720
 */
721
l_ok
722
genRandomIntOnInterval(l_int32   start,
723
                       l_int32   end,
724
                       l_int32   seed,
725
                       l_int32  *pval)
726
0
{
727
0
l_float64  range;
728
729
0
    if (!pval)
730
0
        return ERROR_INT("&val not defined", __func__, 1);
731
0
    *pval = 0;
732
0
    if (end < start)
733
0
        return ERROR_INT("invalid range", __func__, 1);
734
735
0
    if (seed > 0) srand(seed);
736
0
    range = (l_float64)(end - start + 1);
737
0
    *pval = start + (l_int32)((l_float64)range *
738
0
                       ((l_float64)rand() / (l_float64)RAND_MAX));
739
0
    return 0;
740
0
}
741
742
743
/*---------------------------------------------------------------------*
744
 *                        Simple math functions                        *
745
 *---------------------------------------------------------------------*/
746
/*!
747
 * \brief   lept_roundftoi()
748
 *
749
 * \param[in]    fval
750
 * \return  value rounded to the nearest integer
751
 *
752
 * <pre>
753
 * Notes:
754
 *      (1) For fval >= 0, fval --> round(fval) == floor(fval + 0.5)
755
 *          For fval < 0, fval --> -round(-fval))
756
 *          This is symmetric around 0.
757
 *          e.g., for fval in (-0.5 ... 0.5), fval --> 0
758
 * </pre>
759
 */
760
l_int32
761
lept_roundftoi(l_float32  fval)
762
0
{
763
0
    return (fval >= 0.0) ? (l_int32)(fval + 0.5) : (l_int32)(fval - 0.5);
764
0
}
765
766
767
/*!
768
 * \brief   lept_floor()
769
 *
770
 * \param[in]    fval
771
 * \return  largest integer that is not greater than %fval
772
 */
773
l_int32
774
lept_floor(l_float32  fval)
775
0
{
776
0
    return (fval >= 0.0) ? (l_int32)(fval) : -(l_int32)(-fval);
777
0
}
778
779
780
/*!
781
 * \brief   lept_ceiling()
782
 *
783
 * \param[in]    fval
784
 * \return  smallest integer that is not less than %fval
785
 *
786
 * <pre>
787
 * Notes:
788
 *      (1) If fval is equal to its interger value, return that.
789
 *          Otherwise:
790
 *            For fval > 0, fval --> 1 + floor(fval)
791
 *            For fval < 0, fval --> -(1 + floor(-fval))
792
 * </pre>
793
 */
794
l_int32
795
lept_ceiling(l_float32  fval)
796
0
{
797
0
    return (fval == (l_int32)fval ? (l_int32)fval :
798
0
            fval > 0.0 ? 1 + (l_int32)(fval) : -(1 + (l_int32)(-fval)));
799
0
}
800
801
802
/*---------------------------------------------------------------------*
803
 *                        64-bit hash functions                        *
804
 *---------------------------------------------------------------------*/
805
/*!
806
 * \brief   l_hashStringToUint64()
807
 *
808
 * \param[in]    str
809
 * \param[out]   phash    hash value
810
 * \return  0 if OK, 1 on error
811
 *
812
 * <pre>
813
 * Notes:
814
 *      (1) The intent of the hash is to avoid collisions by mapping
815
 *          the string as randomly as possible into 64 bits.
816
 *      (2) To the extent that the hashes are random, the probability of
817
 *          a collision can be approximated by the square of the number
818
 *          of strings divided by 2^64.  For 1 million strings, the
819
 *          collision probability is about 1 in 16 million.
820
 *      (3) I expect non-randomness of the distribution to be most evident
821
 *          for small text strings.  This hash function has been tested
822
 *          for all 5-character text strings composed of 26 letters,
823
 *          of which there are 26^5 = 12356630.  There are no hash
824
 *          collisions for this set.
825
 * </pre>
826
 */
827
l_ok
828
l_hashStringToUint64(const char  *str,
829
                     l_uint64    *phash)
830
0
{
831
0
l_uint64  hash, mulp;
832
833
0
    if (phash) *phash = 0;
834
0
    if (!str || (str[0] == '\0'))
835
0
        return ERROR_INT("str not defined or empty", __func__, 1);
836
0
    if (!phash)
837
0
        return ERROR_INT("&hash not defined", __func__, 1);
838
839
0
    mulp = 26544357894361247;  /* prime, about 1/700 of the max uint64 */
840
0
    hash = 104395301;
841
0
    while (*str) {
842
0
        hash += (*str++ * mulp) ^ (hash >> 7);   /* shift [1...23] are ok */
843
0
    }
844
0
    *phash = hash ^ (hash << 37);
845
0
    return 0;
846
0
}
847
848
849
/*!
850
 * \brief   l_hashStringToUint64Fast()
851
 *
852
 * \param[in]    str
853
 * \param[out]   phash    hash value
854
 * \return  0 if OK, 1 on error
855
 *
856
 * <pre>
857
 * Notes:
858
 *     (1) This very simple hash algorithm is described in "The Practice
859
 *         of Programming" by Kernighan and Pike, p. 57 (1999).
860
 *     (2) The returned hash value would then be hashed into an index into
861
 *         the hashtable, using the mod operator with the hashtable size.
862
 * </pre>
863
 */
864
l_ok
865
l_hashStringToUint64Fast(const char  *str,
866
                         l_uint64    *phash)
867
0
{
868
0
l_uint64  h;
869
0
l_uint8  *p;
870
871
0
    if (phash) *phash = 0;
872
0
    if (!str || (str[0] == '\0'))
873
0
        return ERROR_INT("str not defined or empty", __func__, 1);
874
0
    if (!phash)
875
0
        return ERROR_INT("&hash not defined", __func__, 1);
876
877
0
    h = 0;
878
0
    for (p = (l_uint8 *)str; *p != '\0'; p++)
879
0
        h = 37 * h + *p;  /* 37 is good prime number for this */
880
0
    *phash = h;
881
0
    return 0;
882
0
}
883
884
885
/*!
886
 * \brief   l_hashPtToUint64()
887
 *
888
 * \param[in]    x, y
889
 * \param[out]   phash    hash value
890
 * \return  0 if OK, 1 on error
891
 *
892
 * <pre>
893
 * Notes:
894
 *      (1) This simple hash function has no collisions for
895
 *          any of 400 million points with x and y up to 20000.
896
 * </pre>
897
 */
898
l_ok
899
l_hashPtToUint64(l_int32    x,
900
                 l_int32    y,
901
                 l_uint64  *phash)
902
0
{
903
0
    if (!phash)
904
0
        return ERROR_INT("&hash not defined", __func__, 1);
905
906
0
    *phash = (l_uint64)(2173249142.3849 * x + 3763193258.6227 * y);
907
0
    return 0;
908
0
}
909
910
911
/*!
912
 * \brief   l_hashFloat64ToUint64()
913
 *
914
 * \param[in]    val
915
 * \param[out]   phash      hash key
916
 * \return  0 if OK, 1 on error
917
 *
918
 * <pre>
919
 * Notes:
920
 *      (1) This is a simple hash for using hashmaps with 64-bit float data.
921
 *      (2) The resulting hash is called a "key" in a lookup operation.
922
 *          The bucket for %val in a hashmap is then found by taking the mod
923
 *          of the hash key with the number of buckets (which is prime).
924
 * </pre>
925
 */
926
l_ok
927
l_hashFloat64ToUint64(l_float64  val,
928
                      l_uint64  *phash)
929
0
{
930
0
    if (!phash)
931
0
        return ERROR_INT("&hash not defined", __func__, 1);
932
0
    val = (val >= 0.0) ? 847019.66701 * val : -217324.91613 * val;
933
0
    *phash = (l_uint64)val;
934
0
    return 0;
935
0
}
936
937
938
/*---------------------------------------------------------------------*
939
 *                           Prime finders                             *
940
 *---------------------------------------------------------------------*/
941
/*!
942
 * \brief   findNextLargerPrime()
943
 *
944
 * \param[in]    start
945
 * \param[out]   pprime    first prime larger than %start
946
 * \return  0 if OK, 1 on error
947
 */
948
l_ok
949
findNextLargerPrime(l_int32    start,
950
                    l_uint32  *pprime)
951
0
{
952
0
l_int32  i, is_prime;
953
954
0
    if (!pprime)
955
0
        return ERROR_INT("&prime not defined", __func__, 1);
956
0
    *pprime = 0;
957
0
    if (start <= 0)
958
0
        return ERROR_INT("start must be > 0", __func__, 1);
959
960
0
    for (i = start + 1; ; i++) {
961
0
        lept_isPrime(i, &is_prime, NULL);
962
0
        if (is_prime) {
963
0
            *pprime = i;
964
0
            return 0;
965
0
        }
966
0
    }
967
968
0
    return ERROR_INT("prime not found!", __func__, 1);
969
0
}
970
971
972
/*!
973
 * \brief   lept_isPrime()
974
 *
975
 * \param[in]    n           64-bit unsigned
976
 * \param[out]   pis_prime   1 if prime, 0 otherwise
977
 * \param[out]   pfactor     [optional] smallest divisor, or 0 on error
978
 *                           or if prime
979
 * \return  0 if OK, 1 on error
980
 */
981
l_ok
982
lept_isPrime(l_uint64   n,
983
             l_int32   *pis_prime,
984
             l_uint32  *pfactor)
985
0
{
986
0
l_uint32  div;
987
0
l_uint64  limit, ratio;
988
989
0
    if (pis_prime) *pis_prime = 0;
990
0
    if (pfactor) *pfactor = 0;
991
0
    if (!pis_prime)
992
0
        return ERROR_INT("&is_prime not defined", __func__, 1);
993
0
    if (n <= 0)
994
0
        return ERROR_INT("n must be > 0", __func__, 1);
995
996
0
    if (n % 2 == 0) {
997
0
        if (pfactor) *pfactor = 2;
998
0
        return 0;
999
0
    }
1000
1001
0
    limit = (l_uint64)sqrt((l_float64)n);
1002
0
    for (div = 3; div < limit; div += 2) {
1003
0
       ratio = n / div;
1004
0
       if (ratio * div == n) {
1005
0
           if (pfactor) *pfactor = div;
1006
0
           return 0;
1007
0
       }
1008
0
    }
1009
1010
0
    *pis_prime = 1;
1011
0
    return 0;
1012
0
}
1013
1014
1015
/*---------------------------------------------------------------------*
1016
 *                         Gray code conversion                        *
1017
 *---------------------------------------------------------------------*/
1018
/*!
1019
 * \brief   convertIntToGrayCode()
1020
 *
1021
 * \param[in]  val    integer value
1022
 * \return     corresponding gray code value
1023
 *
1024
 * <pre>
1025
 * Notes:
1026
 *      (1) Gray code values corresponding to integers differ by
1027
 *          only one bit transition between successive integers.
1028
 * </pre>
1029
 */
1030
l_uint32
1031
convertIntToGrayCode(l_uint32 val)
1032
0
{
1033
0
    return (val >> 1) ^ val;
1034
0
}
1035
1036
1037
/*!
1038
 * \brief   convertGrayCodeToInt()
1039
 *
1040
 * \param[in]  val    gray code value
1041
 * \return     corresponding integer value
1042
 */
1043
l_uint32
1044
convertGrayCodeToInt(l_uint32 val)
1045
0
{
1046
0
l_uint32  shift;
1047
1048
0
    for (shift = 1; shift < 32; shift <<= 1)
1049
0
        val ^= val >> shift;
1050
0
    return val;
1051
0
}
1052
1053
1054
/*---------------------------------------------------------------------*
1055
 *                       Leptonica version number                      *
1056
 *---------------------------------------------------------------------*/
1057
/*!
1058
 * \brief   getLeptonicaVersion()
1059
 *
1060
 *      Return: string of version number (e.g., 'leptonica-1.74.2')
1061
 *
1062
 *  Notes:
1063
 *      (1) The caller has responsibility to free the memory.
1064
 */
1065
char *
1066
getLeptonicaVersion(void)
1067
0
{
1068
0
size_t  bufsize = 100;
1069
1070
0
    char *version = (char *)LEPT_CALLOC(bufsize, sizeof(char));
1071
1072
#ifdef _MSC_VER
1073
  #ifdef _USRDLL
1074
    char dllStr[] = "DLL";
1075
  #else
1076
    char dllStr[] = "LIB";
1077
  #endif
1078
  #ifdef _DEBUG
1079
    char debugStr[] = "Debug";
1080
  #else
1081
    char debugStr[] = "Release";
1082
  #endif
1083
  #ifdef _M_IX86
1084
    char bitStr[] = " x86";
1085
  #elif _M_X64
1086
    char bitStr[] = " x64";
1087
  #else
1088
    char bitStr[] = "";
1089
  #endif
1090
    snprintf(version, bufsize, "leptonica-%d.%d.%d (%s, %s) [MSC v.%d %s %s%s]",
1091
           LIBLEPT_MAJOR_VERSION, LIBLEPT_MINOR_VERSION, LIBLEPT_PATCH_VERSION,
1092
           __DATE__, __TIME__, _MSC_VER, dllStr, debugStr, bitStr);
1093
1094
#else
1095
1096
0
    snprintf(version, bufsize, "leptonica-%d.%d.%d", LIBLEPT_MAJOR_VERSION,
1097
0
             LIBLEPT_MINOR_VERSION, LIBLEPT_PATCH_VERSION);
1098
1099
0
#endif   /* _MSC_VER */
1100
0
    return version;
1101
0
}
1102
1103
1104
/*---------------------------------------------------------------------*
1105
 *                           Timing procs                              *
1106
 *---------------------------------------------------------------------*/
1107
#if !defined(_WIN32) && !defined(__Fuchsia__)
1108
1109
#include <sys/time.h>
1110
#include <sys/resource.h>
1111
1112
static struct rusage rusage_before;
1113
static struct rusage rusage_after;
1114
1115
/*!
1116
 * \brief   startTimer(), stopTimer()
1117
 *
1118
 *  Notes:
1119
 *      (1) These measure the cpu time elapsed between the two calls:
1120
 *            startTimer();
1121
 *            ....
1122
 *            lept_stderr( "Elapsed time = %7.3f sec\n", stopTimer());
1123
 */
1124
void
1125
startTimer(void)
1126
0
{
1127
0
    getrusage(RUSAGE_SELF, &rusage_before);
1128
0
}
1129
1130
l_float32
1131
stopTimer(void)
1132
0
{
1133
0
l_int32  tsec, tusec;
1134
1135
0
    getrusage(RUSAGE_SELF, &rusage_after);
1136
1137
0
    tsec = rusage_after.ru_utime.tv_sec - rusage_before.ru_utime.tv_sec;
1138
0
    tusec = rusage_after.ru_utime.tv_usec - rusage_before.ru_utime.tv_usec;
1139
0
    return (tsec + ((l_float32)tusec) / 1000000.0);
1140
0
}
1141
1142
1143
/*!
1144
 * \brief   startTimerNested(), stopTimerNested()
1145
 *
1146
 *  Example of usage:
1147
 *
1148
 *      L_TIMER  t1 = startTimerNested();
1149
 *      ....
1150
 *      L_TIMER  t2 = startTimerNested();
1151
 *      ....
1152
 *      lept_stderr( "Elapsed time 2 = %7.3f sec\n", stopTimerNested(t2));
1153
 *      ....
1154
 *      lept_stderr( "Elapsed time 1 = %7.3f sec\n", stopTimerNested(t1));
1155
 */
1156
L_TIMER
1157
startTimerNested(void)
1158
0
{
1159
0
struct rusage  *rusage_start;
1160
1161
0
    rusage_start = (struct rusage *)LEPT_CALLOC(1, sizeof(struct rusage));
1162
0
    getrusage(RUSAGE_SELF, rusage_start);
1163
0
    return rusage_start;
1164
0
}
1165
1166
l_float32
1167
stopTimerNested(L_TIMER  rusage_start)
1168
0
{
1169
0
l_int32        tsec, tusec;
1170
0
struct rusage  rusage_stop;
1171
1172
0
    getrusage(RUSAGE_SELF, &rusage_stop);
1173
1174
0
    tsec = rusage_stop.ru_utime.tv_sec -
1175
0
           ((struct rusage *)rusage_start)->ru_utime.tv_sec;
1176
0
    tusec = rusage_stop.ru_utime.tv_usec -
1177
0
           ((struct rusage *)rusage_start)->ru_utime.tv_usec;
1178
0
    LEPT_FREE(rusage_start);
1179
0
    return (tsec + ((l_float32)tusec) / 1000000.0);
1180
0
}
1181
1182
1183
/*!
1184
 * \brief   l_getCurrentTime()
1185
 *
1186
 * \param[out]   sec     [optional] in seconds since birth of Unix
1187
 * \param[out]   usec    [optional] in microseconds since birth of Unix
1188
 * \return  void
1189
 */
1190
void
1191
l_getCurrentTime(l_int32  *sec,
1192
                 l_int32  *usec)
1193
0
{
1194
0
struct timeval tv;
1195
1196
0
    gettimeofday(&tv, NULL);
1197
0
    if (sec) *sec = (l_int32)tv.tv_sec;
1198
0
    if (usec) *usec = (l_int32)tv.tv_usec;
1199
0
}
1200
1201
#elif defined(__Fuchsia__) /* resource.h not implemented on Fuchsia. */
1202
1203
    /* Timer functions are used for testing and debugging, and
1204
     * are stubbed out.  If they are needed in the future, they
1205
     * can be implemented in Fuchsia using the zircon syscall
1206
     * zx_object_get_info() in ZX_INFOR_THREAD_STATS mode.  */
1207
void
1208
startTimer(void)
1209
{
1210
}
1211
1212
l_float32
1213
stopTimer(void)
1214
{
1215
    return 0.0;
1216
}
1217
1218
L_TIMER
1219
startTimerNested(void)
1220
{
1221
    return NULL;
1222
}
1223
1224
l_float32
1225
stopTimerNested(L_TIMER  rusage_start)
1226
{
1227
    return 0.0;
1228
}
1229
1230
void
1231
l_getCurrentTime(l_int32  *sec,
1232
                 l_int32  *usec)
1233
{
1234
}
1235
1236
#else   /* _WIN32 : resource.h not implemented under Windows */
1237
1238
    /* Note: if division by 10^7 seems strange, the time is expressed
1239
     * as the number of 100-nanosecond intervals that have elapsed
1240
     * since 12:00 A.M. January 1, 1601.  */
1241
1242
static ULARGE_INTEGER utime_before;
1243
static ULARGE_INTEGER utime_after;
1244
1245
void
1246
startTimer(void)
1247
{
1248
HANDLE    this_process;
1249
FILETIME  start, stop, kernel, user;
1250
1251
    this_process = GetCurrentProcess();
1252
1253
    GetProcessTimes(this_process, &start, &stop, &kernel, &user);
1254
1255
    utime_before.LowPart  = user.dwLowDateTime;
1256
    utime_before.HighPart = user.dwHighDateTime;
1257
}
1258
1259
l_float32
1260
stopTimer(void)
1261
{
1262
HANDLE     this_process;
1263
FILETIME   start, stop, kernel, user;
1264
ULONGLONG  hnsec;  /* in units of hecto-nanosecond (100 ns) intervals */
1265
1266
    this_process = GetCurrentProcess();
1267
1268
    GetProcessTimes(this_process, &start, &stop, &kernel, &user);
1269
1270
    utime_after.LowPart  = user.dwLowDateTime;
1271
    utime_after.HighPart = user.dwHighDateTime;
1272
    hnsec = utime_after.QuadPart - utime_before.QuadPart;
1273
    return (l_float32)(signed)hnsec / 10000000.0f;
1274
}
1275
1276
L_TIMER
1277
startTimerNested(void)
1278
{
1279
HANDLE           this_process;
1280
FILETIME         start, stop, kernel, user;
1281
ULARGE_INTEGER  *utime_start;
1282
1283
    this_process = GetCurrentProcess();
1284
1285
    GetProcessTimes (this_process, &start, &stop, &kernel, &user);
1286
1287
    utime_start = (ULARGE_INTEGER *)LEPT_CALLOC(1, sizeof(ULARGE_INTEGER));
1288
    utime_start->LowPart  = user.dwLowDateTime;
1289
    utime_start->HighPart = user.dwHighDateTime;
1290
    return utime_start;
1291
}
1292
1293
l_float32
1294
stopTimerNested(L_TIMER  utime_start)
1295
{
1296
HANDLE          this_process;
1297
FILETIME        start, stop, kernel, user;
1298
ULARGE_INTEGER  utime_stop;
1299
ULONGLONG       hnsec;  /* in units of 100 ns intervals */
1300
1301
    this_process = GetCurrentProcess ();
1302
1303
    GetProcessTimes (this_process, &start, &stop, &kernel, &user);
1304
1305
    utime_stop.LowPart  = user.dwLowDateTime;
1306
    utime_stop.HighPart = user.dwHighDateTime;
1307
    hnsec = utime_stop.QuadPart - ((ULARGE_INTEGER *)utime_start)->QuadPart;
1308
    LEPT_FREE(utime_start);
1309
    return (l_float32)(signed)hnsec / 10000000.0f;
1310
}
1311
1312
void
1313
l_getCurrentTime(l_int32  *sec,
1314
                 l_int32  *usec)
1315
{
1316
ULARGE_INTEGER  utime, birthunix;
1317
FILETIME        systemtime;
1318
LONGLONG        birthunixhnsec = 116444736000000000;  /*in units of 100 ns */
1319
LONGLONG        usecs;
1320
1321
    GetSystemTimeAsFileTime(&systemtime);
1322
    utime.LowPart  = systemtime.dwLowDateTime;
1323
    utime.HighPart = systemtime.dwHighDateTime;
1324
1325
    birthunix.LowPart = (DWORD) birthunixhnsec;
1326
    birthunix.HighPart = birthunixhnsec >> 32;
1327
1328
    usecs = (LONGLONG) ((utime.QuadPart - birthunix.QuadPart) / 10);
1329
1330
    if (sec) *sec = (l_int32) (usecs / 1000000);
1331
    if (usec) *usec = (l_int32) (usecs % 1000000);
1332
}
1333
1334
#endif
1335
1336
1337
/*!
1338
 * \brief   startWallTimer()
1339
 *
1340
 * \return  walltimer-ptr
1341
 *
1342
 * <pre>
1343
 * Notes:
1344
 *      (1) These measure the wall clock time  elapsed between the two calls:
1345
 *            L_WALLTIMER *timer = startWallTimer();
1346
 *            ....
1347
 *            lept_stderr( "Elapsed time = %f sec\n", stopWallTimer(&timer);
1348
 *      (2) Note that the timer object is destroyed by stopWallTimer().
1349
 * </pre>
1350
 */
1351
L_WALLTIMER *
1352
startWallTimer(void)
1353
0
{
1354
0
L_WALLTIMER  *timer;
1355
1356
0
    timer = (L_WALLTIMER *)LEPT_CALLOC(1, sizeof(L_WALLTIMER));
1357
0
    l_getCurrentTime(&timer->start_sec, &timer->start_usec);
1358
0
    return timer;
1359
0
}
1360
1361
/*!
1362
 * \brief   stopWallTimer()
1363
 *
1364
 * \param[in,out]  ptimer     walltimer pointer
1365
 * \return  time wall time elapsed in seconds
1366
 */
1367
l_float32
1368
stopWallTimer(L_WALLTIMER  **ptimer)
1369
0
{
1370
0
l_int32       tsec, tusec;
1371
0
L_WALLTIMER  *timer;
1372
1373
0
    if (!ptimer)
1374
0
        return (l_float32)ERROR_FLOAT("&timer not defined", __func__, 0.0);
1375
0
    timer = *ptimer;
1376
0
    if (!timer)
1377
0
        return (l_float32)ERROR_FLOAT("timer not defined", __func__, 0.0);
1378
1379
0
    l_getCurrentTime(&timer->stop_sec, &timer->stop_usec);
1380
0
    tsec = timer->stop_sec - timer->start_sec;
1381
0
    tusec = timer->stop_usec - timer->start_usec;
1382
0
    LEPT_FREE(timer);
1383
0
    *ptimer = NULL;
1384
0
    return (tsec + ((l_float32)tusec) / 1000000.0f);
1385
0
}
1386
1387
1388
/*!
1389
 * \brief   l_getFormattedDate()
1390
 *
1391
 * \return  formatted date string, or NULL on error
1392
 *
1393
 * <pre>
1394
 * Notes:
1395
 *      (1) This is used in pdf, in the form specified in section 3.8.2 of
1396
 *          http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf
1397
 *      (2) Contributed by Dave Bryan.  Works on all platforms.
1398
 * </pre>
1399
 */
1400
char *
1401
l_getFormattedDate(void)
1402
0
{
1403
0
char        buf[128] = "", sep = 'Z';
1404
0
l_int32     gmt_offset, relh, relm;
1405
0
time_t      ut, lt;
1406
0
struct tm   Tm;
1407
0
struct tm  *tptr = &Tm;
1408
1409
0
    ut = time(NULL);
1410
1411
        /* This generates a second "time_t" value by calling "gmtime" to
1412
           fill in a "tm" structure expressed as UTC and then calling
1413
           "mktime", which expects a "tm" structure expressed as the
1414
           local time.  The result is a value that is offset from the
1415
           value returned by the "time" function by the local UTC offset.
1416
           "tm_isdst" is set to -1 to tell "mktime" to determine for
1417
           itself whether DST is in effect.  This is necessary because
1418
           "gmtime" always sets "tm_isdst" to 0, which would tell
1419
           "mktime" to presume that DST is not in effect. */
1420
#ifdef _WIN32
1421
  #ifdef _MSC_VER
1422
    gmtime_s(tptr, &ut);
1423
  #else  /* mingw */
1424
    tptr = gmtime(&ut);
1425
  #endif
1426
#else
1427
0
    gmtime_r(&ut, tptr);
1428
0
#endif
1429
0
    tptr->tm_isdst = -1;
1430
0
    lt = mktime(tptr);
1431
1432
        /* Calls "difftime" to obtain the resulting difference in seconds,
1433
         * because "time_t" is an opaque type, per the C standard. */
1434
0
    gmt_offset = (l_int32) difftime(ut, lt);
1435
0
    if (gmt_offset > 0)
1436
0
        sep = '+';
1437
0
    else if (gmt_offset < 0)
1438
0
        sep = '-';
1439
0
    relh = L_ABS(gmt_offset) / 3600;
1440
0
    relm = (L_ABS(gmt_offset) % 3600) / 60;
1441
1442
#ifdef _WIN32
1443
  #ifdef _MSC_VER
1444
    localtime_s(tptr, &ut);
1445
  #else  /* mingw */
1446
    tptr = localtime(&ut);
1447
  #endif
1448
#else
1449
0
    localtime_r(&ut, tptr);
1450
0
#endif
1451
0
    strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tptr);
1452
0
    sprintf(buf + 14, "%c%02d'%02d'", sep, relh, relm);
1453
0
    return stringNew(buf);
1454
0
}