ultimatepp/bazaar/PixRaster/lib/utils.c
micio a74e1468c9 PixRaster : updated Leptonica library to version 1.65
git-svn-id: svn://ultimatepp.org/upp/trunk@2598 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2010-08-07 23:38:03 +00:00

2140 lines
56 KiB
C

/*====================================================================*
- Copyright (C) 2001 Leptonica. All rights reserved.
- This software is distributed in the hope that it will be
- useful, but with NO WARRANTY OF ANY KIND.
- No author or distributor accepts responsibility to anyone for the
- consequences of using this software, or for whether it serves any
- particular purpose or works at all, unless he or she says so in
- writing. Everyone is granted permission to copy, modify and
- redistribute this source code, for commercial or non-commercial
- purposes, with the following restrictions: (1) the origin of this
- source code must not be misrepresented; (2) modified versions must
- be plainly marked as such; and (3) this notice may not be removed
- or altered from any source or modified source distribution.
*====================================================================*/
/*
* utils.c
*
* Error, warning and info procs; all invoked by macros
* l_int32 returnErrorInt()
* l_float32 returnErrorFloat()
* void *returnErrorPtr()
* void l_error()
* void l_errorString()
* void l_errorInt()
* void l_errorFloat()
* void l_warning()
* void l_warningString()
* void l_warningInt()
* void l_warningInt2()
* void l_warningFloat()
* void l_warningFloat2()
* void l_info()
* void l_infoString()
* void l_infoInt()
* void l_infoInt2()
* void l_infoFloat()
* void l_infoFloat2()
*
* Safe string procs
* char *stringNew()
* l_int32 stringReplace()
* char *stringJoin()
* char *stringReverse()
* char *strtokSafe()
* l_int32 stringSplitOnToken()
*
* Find and replace string procs
* char *stringRemoveChars()
* l_int32 stringFindSubstr()
* char *stringReplaceSubstr()
* char *stringReplaceEachSubstr()
* l_int32 arrayFindSequence()
*
* Safe realloc
* void *reallocNew()
*
* Read and write between file and memory
* l_uint8 *arrayRead()
* l_uint8 *arrayReadStream()
* l_int32 nbytesInFile()
* l_int32 fnbytesInFile()
* l_int32 arrayWrite()
*
* Copy in memory
* l_uint8 *arrayCopy()
*
* File copy operations
* l_int32 fileCopy()
* l_int32 fileConcatenate()
* l_int32 fileAppendString()
*
* Test files for equivalence
* l_int32 filesAreIdentical()
*
* Byte-swapping data conversion
* l_uint16 convertOnBigEnd16()
* l_uint32 convertOnBigEnd32()
* l_uint16 convertOnLittleEnd16()
* l_uint32 convertOnLittleEnd32()
*
* File opening
* FILE *fopenReadStream()
*
* File name operations
* l_int32 splitPathAtDirectory()
* l_int32 splitPathAtExtension()
* char *genPathname()
* char *genTempFilename()
* l_int32 extractNumberFromFilename()
*
* Version number
* char *getLeptonlibVersion()
*
* Timing
* void startTimer()
* l_float32 stopTimer()
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if COMPILER_MSVC
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "allheaders.h"
#if COMPILER_MSVC
static const char sepchar = '\\';
#else
static const char sepchar = '/';
#endif
/*----------------------------------------------------------------------*
* Error, warning and info message procs *
* *
* --------------------- N.B. --------------------- *
* *
* (1) These functions all print messages to stderr. *
* *
* (2) They must be invoked only by macros, which are in *
* environ.h, so that the print output can be disabled *
* at compile time, using -DNO_CONSOLE_IO. *
* *
*----------------------------------------------------------------------*/
/*!
* returnErrorInt()
*
* Input: msg (error message)
* procname
* ival (return val)
* Return: ival (typically 1)
*/
l_int32
returnErrorInt(const char *msg,
const char *procname,
l_int32 ival)
{
fprintf(stderr, "Error in %s: %s\n", procname, msg);
return ival;
}
/*!
* returnErrorFloat()
*
* Input: msg (error message)
* procname
* fval (return val)
* Return: fval
*/
l_float32
returnErrorFloat(const char *msg,
const char *procname,
l_float32 fval)
{
fprintf(stderr, "Error in %s: %s\n", procname, msg);
return fval;
}
/*!
* returnErrorPtr()
*
* Input: msg (error message)
* procname
* pval (return val)
* Return: pval (typically null)
*/
void *
returnErrorPtr(const char *msg,
const char *procname,
void *pval)
{
fprintf(stderr, "Error in %s: %s\n", procname, msg);
return pval;
}
/*!
* l_error()
*
* Input: msg (error message)
* procname
*/
void
l_error(const char *msg,
const char *procname)
{
fprintf(stderr, "Error in %s: %s\n", procname, msg);
return;
}
/*!
* l_errorString()
*
* Input: msg (error message; must include '%s')
* procname
* str (embedded in error message via %s)
*/
void
l_errorString(const char *msg,
const char *procname,
const char *str)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname || !str) {
L_ERROR("msg, procname or str not defined in l_errorString()",
procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_errorString()", procname);
return;
}
sprintf(charbuf, "Error in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, str);
FREE(charbuf);
return;
}
/*!
* l_errorInt()
*
* Input: msg (error message; must include '%d')
* procname
* ival (embedded in error message via %d)
*/
void
l_errorInt(const char *msg,
const char *procname,
l_int32 ival)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_errorInt()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_errorInt()", procname);
return;
}
sprintf(charbuf, "Error in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, ival);
FREE(charbuf);
return;
}
/*!
* l_errorFloat()
*
* Input: msg (error message; must include '%f')
* procname
* fval (embedded in error message via %f)
*/
void
l_errorFloat(const char *msg,
const char *procname,
l_float32 fval)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_errorFloat()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_errorFloat()", procname);
return;
}
sprintf(charbuf, "Error in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, fval);
FREE(charbuf);
return;
}
/*!
* l_warning()
*
* Input: msg (warning message)
* procname
*/
void
l_warning(const char *msg,
const char *procname)
{
fprintf(stderr, "Warning in %s: %s\n", procname, msg);
return;
}
/*!
* l_warningString()
*
* Input: msg (warning message; must include '%s')
* procname
* str (embedded in warning message via %s)
*/
void
l_warningString(const char *msg,
const char *procname,
const char *str)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname || !str) {
L_ERROR("msg, procname or str not defined in l_warningString()",
procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_warningString()", procname);
return;
}
sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, str);
FREE(charbuf);
return;
}
/*!
* l_warningInt()
*
* Input: msg (warning message; must include '%d')
* procname
* ival (embedded in warning message via %d)
*/
void
l_warningInt(const char *msg,
const char *procname,
l_int32 ival)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_warningInt()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_warningInt()", procname);
return;
}
sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, ival);
FREE(charbuf);
return;
}
/*!
* l_warningInt2()
*
* Input: msg (warning message; must include '%d')
* procname
* ival1, ival2 (two args, embedded in message via %d)
*/
void
l_warningInt2(const char *msg,
const char *procname,
l_int32 ival1,
l_int32 ival2)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_warningInt2()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_warningInt()", procname);
return;
}
sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, ival1, ival2);
FREE(charbuf);
return;
}
/*!
* l_warningFloat()
*
* Input: msg (warning message; must include '%f')
* procname
* fval (embedded in warning message via %f)
*/
void
l_warningFloat(const char *msg,
const char *procname,
l_float32 fval)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_warningFloat()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_warningFloat()", procname);
return;
}
sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, fval);
FREE(charbuf);
return;
}
/*!
* l_warningFloat2()
*
* Input: msg (warning message; must include '%f')
* procname
* fval1, fval2 (two args, embedded in message via %f)
*/
void
l_warningFloat2(const char *msg,
const char *procname,
l_float32 fval1,
l_float32 fval2)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_warningFloat2()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_warningFloat()", procname);
return;
}
sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, fval1, fval2);
FREE(charbuf);
return;
}
/*!
* l_info()
*
* Input: msg (info message)
* procname
*/
void
l_info(const char *msg,
const char *procname)
{
fprintf(stderr, "Info in %s: %s\n", procname, msg);
return;
}
/*!
* l_infoString()
*
* Input: msg (info message; must include '%s')
* procname
* str (embedded in warning message via %s)
*/
void
l_infoString(const char *msg,
const char *procname,
const char *str)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname || !str) {
L_ERROR("msg, procname or str not defined in l_infoString()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_infoString()", procname);
return;
}
sprintf(charbuf, "Info in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, str);
FREE(charbuf);
return;
}
/*!
* l_infoInt()
*
* Input: msg (info message; must include '%d')
* procname
* ival (embedded in info message via %d)
*/
void
l_infoInt(const char *msg,
const char *procname,
l_int32 ival)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_infoInt()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_infoInt()", procname);
return;
}
sprintf(charbuf, "Info in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, ival);
FREE(charbuf);
return;
}
/*!
* l_infoInt2()
*
* Input: msg (info message; must include two '%d')
* procname
* ival1, ival2 (two args, embedded in info message via %d)
*/
void
l_infoInt2(const char *msg,
const char *procname,
l_int32 ival1,
l_int32 ival2)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_infoInt2()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_infoInt2()", procname);
return;
}
sprintf(charbuf, "Info in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, ival1, ival2);
FREE(charbuf);
return;
}
/*!
* l_infoFloat()
*
* Input: msg (info message; must include '%f')
* procname
* fval (embedded in info message via %f)
*/
void
l_infoFloat(const char *msg,
const char *procname,
l_float32 fval)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_infoFloat()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_infoFloat()", procname);
return;
}
sprintf(charbuf, "Info in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, fval);
FREE(charbuf);
return;
}
/*!
* l_infoFloat2()
*
* Input: msg (info message; must include two '%f')
* procname
* fval1, fval2 (two args, embedded in info message via %f)
*/
void
l_infoFloat2(const char *msg,
const char *procname,
l_float32 fval1,
l_float32 fval2)
{
l_int32 bufsize;
char *charbuf;
if (!msg || !procname) {
L_ERROR("msg or procname not defined in l_infoFloat2()", procname);
return;
}
bufsize = strlen(msg) + strlen(procname) + 128;
if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
L_ERROR("charbuf not made in l_infoFloat()", procname);
return;
}
sprintf(charbuf, "Info in %s: %s\n", procname, msg);
fprintf(stderr, charbuf, fval1, fval2);
FREE(charbuf);
return;
}
/*--------------------------------------------------------------------*
* Safe string operations *
*--------------------------------------------------------------------*/
/*!
* stringNew()
*
* Input: src string
* Return: dest copy of src string, or null on error
*/
char *
stringNew(const char *src)
{
char *dest;
PROCNAME("stringNew");
if (!src)
return (char *)ERROR_PTR("src not defined", procName, NULL);
if ((dest = (char *)CALLOC(strlen(src) + 2, sizeof(char))) == NULL)
return (char *)ERROR_PTR("dest not made", procName, NULL);
strcpy(dest, src);
return dest;
}
/*!
* stringReplace()
*
* Input: &dest string (<return> copy)
* src string
* Return: 0 if OK; 1 on error
*
* Notes:
* (1) Frees any existing dest string
* (2) Puts a copy of src string in the dest
* (3) If either or both strings are null, does the reasonable thing.
*/
l_int32
stringReplace(char **pdest,
const char *src)
{
char *scopy;
PROCNAME("stringReplace");
if (!pdest)
return ERROR_INT("pdest not defined", procName, 1);
if (*pdest)
FREE(*pdest);
if (src) {
if ((scopy = (char *)CALLOC(strlen(src) + 2, sizeof(char))) == NULL)
return ERROR_INT("scopy not made", procName, 1);
strcpy(scopy, src);
*pdest = scopy;
}
else
*pdest = NULL;
return 0;
}
/*!
* stringJoin()
*
* Input: src1 string (<optional>)
* src2 string (<optional>)
* Return: concatenated string, or null on error
*
* Notes:
* (1) This is the safe version of strcat; it makes a new string.
* (2) It is not an error if either or both of the strings
* are empty, or if either or both the pointers are null.
*/
char *
stringJoin(const char *src1,
const char *src2)
{
char *dest;
l_int32 srclen1, srclen2, destlen;
PROCNAME("stringJoin");
srclen1 = srclen2 = 0;
if (src1)
srclen1 = strlen(src1);
if (src2)
srclen2 = strlen(src2);
destlen = srclen1 + srclen2 + 3;
if ((dest = (char *)CALLOC(destlen, sizeof(char))) == NULL)
return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
if (src1)
strcpy(dest, src1);
if (src2)
strncat(dest, src2, srclen2);
return dest;
}
/*!
* stringReverse()
*
* Input: src (string)
* Return: dest (newly-allocated reversed string)
*/
char *
stringReverse(const char *src)
{
char *dest;
l_int32 i, len;
PROCNAME("stringReverse");
if (!src)
return (char *)ERROR_PTR("src not defined", procName, NULL);
len = strlen(src);
if ((dest = (char *)CALLOC(len + 1, sizeof(char))) == NULL)
return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
for (i = 0; i < len; i++)
dest[i] = src[len - 1 - i];
return dest;
}
/*!
* strtokSafe()
*
* Input: cstr (input string to be sequentially parsed;
* use NULL after the first call)
* seps (a string of character separators)
* &saveptr (<return> ptr to the next char after
* the last encountered separator)
* Return: substr (a new string that is copied from the previous
* saveptr up to but not including the next
* separator character), or NULL if end of cstr.
*
* Notes:
* (1) This is a thread-safe implementation of strtok.
* (2) It has the same interface as strtok_r.
* (3) It differs from strtok_r in usage in two respects:
* (a) the input string is not altered
* (b) each returned substring is newly allocated and must
* be freed after use.
* (4) Let me repeat that. This is "safe" because the input
* string is not altered and because each returned string
* is newly allocated on the heap.
* (5) It is here because, surprisingly, some C libraries don't
* include strtok_r.
* (6) Important usage points:
* - Input the string to be parsed on the first invocation.
* - Then input NULL after that; the value returned in saveptr
* is used in all subsequent calls.
* (7) This is only slightly slower than strtok_k.
*/
char *
strtokSafe(char *cstr,
const char *seps,
char **psaveptr)
{
char nextc;
char *start, *substr;
l_int32 istart, i, j, nchars;
PROCNAME("strtokSafe");
if (!seps)
return (char *)ERROR_PTR("seps not defined", procName, NULL);
if (!psaveptr)
return (char *)ERROR_PTR("&saveptr not defined", procName, NULL);
if (!cstr)
start = *psaveptr;
else
start = cstr;
if (!start) /* nothing to do */
return NULL;
/* First time, scan for the first non-sep character */
istart = 0;
if (cstr) {
for (istart = 0;; istart++) {
if ((nextc = start[istart]) == '\0') {
*psaveptr = NULL; /* in case caller doesn't check ret value */
return NULL;
}
if (!strchr(seps, nextc))
break;
}
}
/* Scan through, looking for a sep character; if none is
* found, 'i' will be at the end of the string. */
for (i = istart;; i++) {
if ((nextc = start[i]) == '\0')
break;
if (strchr(seps, nextc))
break;
}
/* Save the substring */
nchars = i - istart;
substr = (char *)CALLOC(nchars + 1, sizeof(char));
strncpy(substr, start + istart, nchars);
/* Look for the next non-sep character.
* If this is the last substring, return a null saveptr. */
for (j = i;; j++) {
if ((nextc = start[j]) == '\0') {
*psaveptr = NULL; /* no more non-sep characters */
break;
}
if (!strchr(seps, nextc)) {
*psaveptr = start + j; /* start here on next call */
break;
}
}
return substr;
}
/*!
* stringSplitOnToken()
*
* Input: cstr (input string to be split; not altered)
* seps (a string of character separators)
* &head (<return> ptr to copy of the input string, up to
* the first separator token encountered)
* &tail (<return> ptr to copy of the part of the input string
* starting with the first non-separator character
* that occurs after the first separator is found)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) The input string is not altered; all split parts are new strings.
* (2) The split occurs around the first consecutive sequence of
* tokens encountered.
* (3) The head goes from the beginning of the string up to
* but not including the first token found.
* (4) The tail contains the second part of the string, starting
* with the first char in that part that is NOT a token.
* (5) If no separator token is found, 'head' contains a copy
* of the input string and 'tail' is null.
*/
l_int32
stringSplitOnToken(char *cstr,
const char *seps,
char **phead,
char **ptail)
{
char *saveptr;
PROCNAME("stringSplitOnToken");
if (!phead)
return ERROR_INT("&head not defined", procName, 1);
if (!ptail)
return ERROR_INT("&tail not defined", procName, 1);
*phead = *ptail = NULL;
if (!cstr)
return ERROR_INT("cstr not defined", procName, 1);
if (!seps)
return ERROR_INT("seps not defined", procName, 1);
*phead = strtokSafe(cstr, seps, &saveptr);
if (saveptr)
*ptail = stringNew(saveptr);
return 0;
}
/*--------------------------------------------------------------------*
* Find and replace procs *
*--------------------------------------------------------------------*/
/*!
* stringRemoveChars()
*
* Input: src (input string; can be of zero length)
* remchars (string of chars to be removed from src)
* Return: dest (string with specified chars removed), or null on error
*/
char *
stringRemoveChars(const char *src,
const char *remchars)
{
char ch;
char *dest;
l_int32 nsrc, i, k;
PROCNAME("stringRemoveChars");
if (!src)
return (char *)ERROR_PTR("src not defined", procName, NULL);
if (!remchars)
return stringNew(src);
if ((dest = (char *)CALLOC(strlen(src) + 1, sizeof(char))) == NULL)
return (char *)ERROR_PTR("dest not made", procName, NULL);
nsrc = strlen(src);
for (i = 0, k = 0; i < nsrc; i++) {
ch = src[i];
if (!strchr(remchars, ch))
dest[k++] = ch;
}
return dest;
}
/*!
* stringFindSubstr()
*
* Input: src (input string; can be of zero length)
* sub (substring to be searched for)
* &loc (<return optional> location of substring in src)
* Return: 1 if found; 0 if not found or on error
*
* Notes:
* (1) This is a wrapper around strstr().
* (2) Both @src and @sub must be defined, and @sub must have
* length of at least 1.
* (3) If the substring is not found and loc is returned, it has
* the value -1.
*/
l_int32
stringFindSubstr(const char *src,
const char *sub,
l_int32 *ploc)
{
char *ptr;
PROCNAME("stringFindSubstr");
if (!src)
return ERROR_INT("src not defined", procName, 0);
if (!sub)
return ERROR_INT("sub not defined", procName, 0);
if (ploc) *ploc = -1;
if (strlen(sub) == 0)
return ERROR_INT("substring length 0", procName, 0);
if (strlen(src) == 0)
return 0;
if ((ptr = (char *)strstr(src, sub)) == NULL) /* not found */
return 0;
if (ploc)
*ploc = ptr - src;
return 1;
}
/*!
* stringReplaceSubstr()
*
* Input: src (input string; can be of zero length)
* sub1 (substring to be replaced)
* sub2 (substring to put in; can be "")
* &found (<return optional> 1 if sub1 is found; 0 otherwise)
* &loc (<return optional> location of ptr after replacement)
* Return: dest (string with substring replaced), or null if the
* substring not found or on error.
*
* Notes:
* (1) Replaces the first instance.
* (2) To only remove sub1, use "" for sub2
* (3) Returns a new string if sub1 and sub2 are the same.
* (4) The optional loc is input as the byte offset within the src
* from which the search starts, and after the search it is the
* char position in the string of the next character after
* the substituted string.
* (5) N.B. If ploc is not null, loc must always be initialized.
* To search the string from the beginning, set loc = 0.
*/
char *
stringReplaceSubstr(const char *src,
const char *sub1,
const char *sub2,
l_int32 *pfound,
l_int32 *ploc)
{
char *ptr, *dest;
l_int32 nsrc, nsub1, nsub2, len, npre, loc;
PROCNAME("stringReplaceSubstr");
if (!src)
return (char *)ERROR_PTR("src not defined", procName, NULL);
if (!sub1)
return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
if (!sub2)
return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
if (pfound)
*pfound = 0;
if (ploc)
loc = *ploc;
else
loc = 0;
if ((ptr = (char *)strstr(src + loc, sub1)) == NULL) {
return NULL;
}
if (pfound)
*pfound = 1;
nsrc = strlen(src);
nsub1 = strlen(sub1);
nsub2 = strlen(sub2);
len = nsrc + nsub2 - nsub1;
if ((dest = (char *)CALLOC(len + 1, sizeof(char))) == NULL)
return (char *)ERROR_PTR("dest not made", procName, NULL);
npre = ptr - src;
memcpy(dest, src, npre);
strcpy(dest + npre, sub2);
strcpy(dest + npre + nsub2, ptr + nsub1);
if (ploc)
*ploc = npre + nsub2;
return dest;
}
/*!
* stringReplaceEachSubstr()
*
* Input: src (input string; can be of zero length)
* sub1 (substring to be replaced)
* sub2 (substring to put in; can be "")
* &count (<optional return > the number of times that sub1
* is found in src; 0 if not found)
* Return: dest (string with substring replaced), or null if the
* substring not found or on error.
*
* Notes:
* (1) Replaces every instance.
* (2) To only remove each instance of sub1, use "" for sub2
* (3) Returns NULL if sub1 and sub2 are the same.
*/
char *
stringReplaceEachSubstr(const char *src,
const char *sub1,
const char *sub2,
l_int32 *pcount)
{
char *currstr, *newstr;
l_int32 loc;
PROCNAME("stringReplaceEachSubstr");
if (!src)
return (char *)ERROR_PTR("src not defined", procName, NULL);
if (!sub1)
return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
if (!sub2)
return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
if (pcount)
*pcount = 0;
loc = 0;
if ((newstr = stringReplaceSubstr(src, sub1, sub2, NULL, &loc)) == NULL)
return NULL;
if (pcount)
(*pcount)++;
while (1) {
currstr = newstr;
newstr = stringReplaceSubstr(currstr, sub1, sub2, NULL, &loc);
if (!newstr)
return currstr;
FREE(currstr);
if (pcount)
(*pcount)++;
}
}
/*!
* arrayFindSequence()
*
* Input: data (byte array)
* datalen (length of data, in bytes)
* sequence (subarray of bytes to find in data)
* seqlen (length of sequence, in bytes)
* &offset (return> offset from beginning of
* data where the sequence begins)
* &found (<return> 1 if sequence is found; 0 otherwise)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) The byte arrays 'data' and 'sequence' are not C strings,
* as they can contain null bytes. Therefore, for each
* we must give the length of the array.
* (2) This searches for the first occurrence in 'data' of
* the first 'seqlen' bytes of 'sequence'. The parameter 'seqlen'
* must not exceed the actual length of the 'sequence' byte array.
* (3) If the sequence is not found, the offset will be set to -1.
*/
l_int32
arrayFindSequence(const l_uint8 *data,
l_int32 datalen,
const l_uint8 *sequence,
l_int32 seqlen,
l_int32 *poffset,
l_int32 *pfound)
{
l_int32 i, j, found, lastpos;
PROCNAME("arrayFindSequence");
if (!data || !sequence)
return ERROR_INT("data & sequence not both defined", procName, 1);
if (!poffset || !pfound)
return ERROR_INT("&offset and &found not both defined", procName, 1);
*pfound = 0;
*poffset = -1;
lastpos = datalen - seqlen + 1;
found = 0;
for (i = 0; i < lastpos; i++) {
for (j = 0; j < seqlen; j++) {
if (data[i + j] != sequence[j])
break;
if (j == seqlen - 1)
found = 1;
}
if (found)
break;
}
if (found) {
*pfound = 1;
*poffset = i;
}
return 0;
}
/*--------------------------------------------------------------------*
* Safe realloc *
*--------------------------------------------------------------------*/
/*!
* reallocNew()
*
* Input: &indata (<optional>; nulls indata)
* size of input data to be copied (bytes)
* size of data to be reallocated (bytes)
* Return: ptr to new data, or null on error
*
* Action: !N.B. (3) and (4)!
* (1) Allocates memory, initialized to 0
* (2) Copies as much of the input data as possible
* to the new block, truncating the copy if necessary
* (3) Frees the input data
* (4) Zeroes the input data ptr
*
* Notes:
* (1) If newsize <=0, just frees input data and nulls ptr
* (2) If input ptr is null, just callocs new memory
* (3) This differs from realloc in that it always allocates
* new memory (if newsize > 0) and initializes it to 0,
* it requires the amount of old data to be copied,
* and it takes the address of the input ptr and
* nulls the handle.
*/
void *
reallocNew(void **pindata,
l_int32 oldsize,
l_int32 newsize)
{
l_int32 minsize;
void *indata;
void *newdata;
PROCNAME("reallocNew");
if (!pindata)
return ERROR_PTR("input data not defined", procName, NULL);
indata = *pindata;
if (newsize <= 0) { /* nonstandard usage */
if (indata) {
FREE(indata);
*pindata = NULL;
}
return NULL;
}
if (!indata) /* nonstandard usage */
{
if ((newdata = (void *)CALLOC(1, newsize)) == NULL)
return ERROR_PTR("newdata not made", procName, NULL);
return newdata;
}
/* Standard usage */
if ((newdata = (void *)CALLOC(1, newsize)) == NULL)
return ERROR_PTR("newdata not made", procName, NULL);
minsize = L_MIN(oldsize, newsize);
memcpy((char *)newdata, (char *)indata, minsize);
FREE(indata);
*pindata = NULL;
return newdata;
}
/*--------------------------------------------------------------------*
* Reading bytes from file *
*--------------------------------------------------------------------*/
/*!
* arrayRead()
*
* Input: filename
* &nbytes (<return> number of bytes read)
* Return: array, or null on error
*/
l_uint8 *
arrayRead(const char *fname,
l_int32 *pnbytes)
{
l_uint8 *data;
FILE *fp;
PROCNAME("arrayRead");
if (!fname)
return (l_uint8 *)ERROR_PTR("fname not defined", procName, NULL);
if (!pnbytes)
return (l_uint8 *)ERROR_PTR("pnbytes not defined", procName, NULL);
*pnbytes = 0;
if ((fp = fopen(fname, "rb")) == NULL)
return (l_uint8 *)ERROR_PTR("file stream not opened", procName, NULL);
data = arrayReadStream(fp, pnbytes);
fclose(fp);
return data;
}
/*!
* arrayReadStream()
*
* Input: stream
* &nbytes (<return> number of bytes read)
* Return: null-terminated array, or null on error
* (reading 0 bytes is not an error)
*
* Notes:
* (1) N.B.: as a side effect, this always re-positions the
* stream ptr to the beginning of the file.
*/
l_uint8 *
arrayReadStream(FILE *fp,
l_int32 *pnbytes)
{
l_uint8 *data;
PROCNAME("arrayReadStream");
if (!fp)
return (l_uint8 *)ERROR_PTR("stream not defined", procName, NULL);
if (!pnbytes)
return (l_uint8 *)ERROR_PTR("ptr to nbytes not defined", procName, NULL);
*pnbytes = fnbytesInFile(fp);
if ((data = (l_uint8 *)CALLOC(1, *pnbytes + 1)) == NULL)
return (l_uint8 *)ERROR_PTR("CALLOC fail for data", procName, NULL);
fread(data, *pnbytes, 1, fp);
return data;
}
/*!
* nbytesInFile()
*
* Input: filename
* Return: nbytes in file; 0 on error
*/
l_int32
nbytesInFile(const char *filename)
{
l_int32 nbytes;
FILE *fp;
PROCNAME("nbytesInFile");
if (!filename)
return ERROR_INT("filename not defined", procName, 0);
if ((fp = fopen(filename, "rb")) == NULL)
return ERROR_INT("stream not opened", procName, 0);
nbytes = fnbytesInFile(fp);
fclose(fp);
return nbytes;
}
/*!
* fnbytesInFile()
*
* Input: file stream
* Return: nbytes in file; 0 on error
*/
l_int32
fnbytesInFile(FILE *fp)
{
l_int32 nbytes, pos;
PROCNAME("fnbytesInFile");
if (!fp)
return ERROR_INT("stream not open", procName, 0);
pos = ftell(fp); /* initial position */
fseek(fp, 0, SEEK_END); /* EOF */
nbytes = ftell(fp);
fseek(fp, 0, pos); /* back to initial position */
return nbytes;
}
/*!
* arrayWrite()
*
* Input: filename (output)
* operation ("w" for write; "a" for append)
* data (binary data to be written)
* nbytes (size of data array)
* Return: 0 if OK; 1 on error
*/
l_int32
arrayWrite(const char *filename,
const char *operation,
void *data,
l_int32 nbytes)
{
FILE *fp;
char actualOperation[20];
PROCNAME("arrayWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!operation)
return ERROR_INT("operation not defined", procName, 1);
if (!data)
return ERROR_INT("data not defined", procName, 1);
if (nbytes <= 0)
return ERROR_INT("nbytes must be > 0", procName, 1);
if (!strcmp(operation, "w") && !strcmp(operation, "a"))
return ERROR_INT("operation not one of {'w','a'}", procName, 1);
strncpy(actualOperation, operation, 2);
strncat(actualOperation, "b", 2); /* for windows */
if ((fp = fopen(filename, actualOperation)) == NULL)
return ERROR_INT("stream not opened", procName, 1);
fwrite(data, 1, nbytes, fp);
fclose(fp);
return 0;
}
/*--------------------------------------------------------------------*
* Copy in memory *
*--------------------------------------------------------------------*/
/*!
* arrayCopy()
*
* Input: datas
* size (of data array)
* Return: datad (on heap), or null on error
*/
l_uint8 *
arrayCopy(l_uint8 *datas,
size_t size)
{
l_uint8 *datad;
PROCNAME("arrayCopy");
if (!datas)
return (l_uint8 *)ERROR_PTR("datas not defined", procName, NULL);
if ((datad = (l_uint8 *)CALLOC(size, sizeof(l_uint8))) == NULL)
return (l_uint8 *)ERROR_PTR("datad not made", procName, NULL);
memcpy(datad, datas, size);
return datad;
}
/*--------------------------------------------------------------------*
* File copy operations *
*--------------------------------------------------------------------*/
/*!
* fileCopy()
*
* Input: filename1 (copy this file)
* filename2 (to this file)
* Return: 0 if OK, 1 on error
*/
l_int32
fileCopy(const char *filename1,
const char *filename2)
{
l_uint8 *data;
l_int32 nbytes, ret;
PROCNAME("fileCopy");
if ((data = arrayRead(filename1, &nbytes)) == NULL)
return ERROR_INT("data not returned", procName, 1);
ret = arrayWrite(filename2, "w", data, nbytes);
FREE(data);
return ret;
}
/*!
* fileConcatenate()
*
* Input: filename1
* filename2 (file to add to filename1)
* Return: 0 if OK, 1 on error
*/
l_int32
fileConcatenate(const char *filename1,
const char *filename2)
{
l_uint8 *data;
l_int32 nbytes;
PROCNAME("fileConcatenate");
if (!filename1)
return ERROR_INT("filename1 not defined", procName, 1);
if (!filename2)
return ERROR_INT("filename2 not defined", procName, 1);
data = arrayRead(filename2, &nbytes);
arrayWrite(filename1, "a", data, nbytes);
FREE(data);
return 0;
}
/*!
* fileAppendString()
*
* Input: filename
* str (string to append to file)
* Return: 0 if OK, 1 on error
*/
l_int32
fileAppendString(const char *filename,
const char *str)
{
FILE *fp;
PROCNAME("fileAppendString");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!str)
return ERROR_INT("str not defined", procName, 1);
if ((fp = fopen(filename, "a")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
fprintf(fp, str);
fclose(fp);
return 0;
}
/*--------------------------------------------------------------------*
* Test files for equivalence *
*--------------------------------------------------------------------*/
/*!
* filesAreIdentical()
*
* Input: fname1
* fname2
* &same (<return> 1 if identical; 0 if different)
* Return: 0 if OK, 1 on error
*/
l_int32
filesAreIdentical(const char *fname1,
const char *fname2,
l_int32 *psame)
{
l_int32 i, same, nbytes1, nbytes2;
l_uint8 *array1, *array2;
PROCNAME("filesAreIdentical");
if (!psame)
return ERROR_INT("&same not defined", procName, 1);
*psame = 0;
if (!fname1 || !fname2)
return ERROR_INT("both names not defined", procName, 1);
nbytes1 = nbytesInFile(fname1);
nbytes2 = nbytesInFile(fname2);
if (nbytes1 != nbytes2)
return 0;
if ((array1 = arrayRead(fname1, &nbytes1)) == NULL)
return ERROR_INT("array1 not read", procName, 1);
if ((array2 = arrayRead(fname2, &nbytes2)) == NULL)
return ERROR_INT("array2 not read", procName, 1);
same = 1;
for (i = 0; i < nbytes1; i++) {
if (array1[i] != array2[i]) {
same = 0;
break;
}
}
FREE(array1);
FREE(array2);
*psame = same;
return 0;
}
/*--------------------------------------------------------------------------*
* 16 and 32 bit byte-swapping on big endian and little endian machines *
* *
* These are typically used for I/O conversions: *
* (1) endian conversion for data that was read from a file *
* (2) endian conversion on data before it is written to a file *
*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------*
* 16-bit byte swapping *
*--------------------------------------------------------------------*/
#ifdef L_BIG_ENDIAN
l_uint16
convertOnBigEnd16(l_uint16 shortin)
{
return ((shortin << 8) | (shortin >> 8));
}
l_uint16
convertOnLittleEnd16(l_uint16 shortin)
{
return shortin;
}
#else /* L_LITTLE_ENDIAN */
l_uint16
convertOnLittleEnd16(l_uint16 shortin)
{
return ((shortin << 8) | (shortin >> 8));
}
l_uint16
convertOnBigEnd16(l_uint16 shortin)
{
return shortin;
}
#endif /* L_BIG_ENDIAN */
/*--------------------------------------------------------------------*
* 32-bit byte swapping *
*--------------------------------------------------------------------*/
#ifdef L_BIG_ENDIAN
l_uint32
convertOnBigEnd32(l_uint32 wordin)
{
return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
}
l_uint32
convertOnLittleEnd32(l_uint32 wordin)
{
return wordin;
}
#else /* L_LITTLE_ENDIAN */
l_uint32
convertOnLittleEnd32(l_uint32 wordin)
{
return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
}
l_uint32
convertOnBigEnd32(l_uint32 wordin)
{
return wordin;
}
#endif /* L_BIG_ENDIAN */
/*--------------------------------------------------------------------*
* Opening read stream *
*--------------------------------------------------------------------*/
/*!
* fopenReadStream()
*
* Input: filename
* Return: stream or null on error
*/
FILE *
fopenReadStream(const char *filename)
{
char *tail;
FILE *fp;
PROCNAME("fopenReadStream");
if (!filename)
return (FILE *)ERROR_PTR("filename not defined", procName, NULL);
/* Try input filename */
if ((fp = fopen(filename, "rb")))
return fp;
/* Else, strip directory and try locally */
splitPathAtDirectory(filename, NULL, &tail);
if ((fp = fopen(tail, "rb"))) {
FREE(tail);
return fp;
}
FREE(tail);
return (FILE *)ERROR_PTR("file not found", procName, NULL);
}
/*--------------------------------------------------------------------*
* File name operations *
*--------------------------------------------------------------------*/
/*!
* splitPathAtDirectory()
*
* Input: pathname (full path; can be a directory)
* &dir (<optional return> root directory name of
* input path, including trailing '/')
* &tail (<optional return> path tail, which is either
* the file name within the root directory or
* the last sub-directory in the path)
* Return: 0 if OK, 1 on error
*
* Note: (1) if you only want the tail, input null for
* the root directory ptr.
* (2) if you only want the root directory name,
* input null for the tail ptr.
* (3) This function makes decisions based only on the lexical
* structure of the input. Examples:
* /usr/tmp/abc --> dir: /usr/tmp/ tail: abc
* /usr/tmp/ --> dir: /usr/tmp/ tail: [empty string]
* /usr/tmp --> dir: /usr/ tail: tmp
*/
l_int32
splitPathAtDirectory(const char *pathname,
char **pdir,
char **ptail)
{
char *cpathname, *lastslash;
PROCNAME("splitPathAtDirectory");
if (!pdir && !ptail)
return ERROR_INT("null input for both strings", procName, 1);
if (pdir) *pdir = NULL;
if (ptail) *ptail = NULL;
if (!pathname)
return ERROR_INT("pathname not defined", procName, 1);
cpathname = stringNew(pathname);
if ((lastslash = strrchr(cpathname, sepchar))) {
if (ptail)
*ptail = stringNew(lastslash + 1);
if (pdir) {
*(lastslash + 1) = '\0';
*pdir = cpathname;
}
else
FREE(cpathname);
}
else { /* no directory */
if (pdir)
*pdir = stringNew("");
if (ptail)
*ptail = cpathname;
else
FREE(cpathname);
}
return 0;
}
/*!
* splitPathAtExtension()
*
* Input: pathname (full path; can be a directory)
* &basename (<optional return> pathname not including the
* last dot and characters after that)
* &extension (<optional return> path extension, which is
* the last dot and the characters after it. If
* there is no extension, it returns the empty string)
* Return: 0 if OK, 1 on error
*
* Notes:
* (1) If you only want the extension, input null for the basename ptr.
* (2) If you only want the basename without extension, input null
* for the extension ptr.
* (3) This function makes decisions based only on the lexical
* structure of the input. Examples:
* /usr/tmp/abc.jpg --> basename: /usr/tmp/abc ext: .jpg
* /usr/tmp/.jpg --> basename: /usr/tmp/ tail: .jpg
* /usr/tmp.jpg/ --> basename: /usr/tmp.jpg/ tail: [empty str]
* ./.jpg --> basename: ./ tail: .jpg
*/
l_int32
splitPathAtExtension(const char *pathname,
char **pbasename,
char **pextension)
{
char *tail, *dir, *lastdot;
char empty[4] = "";
PROCNAME("splitPathExtension");
if (!pbasename && !pextension)
return ERROR_INT("null input for both strings", procName, 1);
if (pbasename) *pbasename = NULL;
if (pextension) *pextension = NULL;
if (!pathname)
return ERROR_INT("pathname not defined", procName, 1);
/* Split out the directory first */
splitPathAtDirectory(pathname, &dir, &tail);
/* Then look for a "." in the tail part.
* This way we ignore all "." in the directory. */
if ((lastdot = strrchr(tail, '.'))) {
if (pextension)
*pextension = stringNew(lastdot);
if (pbasename) {
*lastdot = '\0';
*pbasename = stringJoin(dir, tail);
}
}
else {
if (pextension)
*pextension = stringNew(empty);
if (pbasename)
*pbasename = stringNew(pathname);
}
FREE(dir);
FREE(tail);
return 0;
}
/*!
* genPathname()
*
* Input: dir (directory name, with or without trailing '/')
* fname (file name within the directory)
* Return: full pathname, or null on error
*/
char *
genPathname(const char *dir,
const char *fname)
{
char *charbuf;
l_int32 dirlen, namelen, totlen;
PROCNAME("genPathname");
if (!dir)
return (char *)ERROR_PTR("dir not defined", procName, NULL);
if (!fname)
return (char *)ERROR_PTR("fname not defined", procName, NULL);
dirlen = strlen(dir);
namelen = strlen(fname);
totlen = dirlen + namelen + 20;
if ((charbuf = (char *)CALLOC(totlen, sizeof(char))) == NULL)
return (char *)ERROR_PTR("charbuf not made", procName, NULL);
#if COMPILER_MSVC
if (stringFindSubstr(dir, "/", NULL) > 0) {
char *tempname;
tempname = stringReplaceEachSubstr(dir, "/", "\\", NULL);
strncpy(charbuf, tempname, strlen(tempname));
FREE(tempname);
}
else {
strncpy(charbuf, dir, dirlen);
}
#else
strncpy(charbuf, dir, dirlen);
#endif /* COMPILER_MSVC */
dirlen = strlen(charbuf);
if (charbuf[dirlen - 1] != sepchar) /* append sepchar */
charbuf[dirlen] = sepchar;
strncat(charbuf, fname, namelen);
return charbuf;
}
/*!
* genTempFilename()
*
* Input: dir (directory name; use '.' for local dir; no trailing '/')
* segment (an additional part of the name; can be null)
* extension (<optional> filename extension with '.'; can be null)
* Return: tempname (with pid embedded in file name), or null on error
*
* Notes:
* (1) This function is useful when there can be more than one
* process writing and reading temporary files. It will not
* work properly when multiple threads from a single process call
* this function. Furthermore, as with any function that
* provides easily guessed temporary filenames, it is not designed
* to be safe from an attack where the intruder is logged onto
* the server.
*/
char *
genTempFilename(const char *dir,
const char *segment,
const char *extension)
{
char buf[256];
char *name, *outname;
l_int32 pid, nseg, next;
PROCNAME("genTempFilename");
if (!dir)
return (char *)ERROR_PTR("dir not defined", procName, NULL);
#if COMPILER_MSVC
pid=GetCurrentProcessId();
#else
pid = getpid();
#endif
if (segment)
nseg = strlen(segment);
else
nseg = 0;
if (extension)
next = strlen(extension);
else
next = 0;
#if COMPILER_MSVC
snprintf(buf, 255 - nseg - next, "%s\\%d_", dir, pid);
#else
snprintf(buf, 255 - nseg - next, "%s/%d_", dir, pid);
#endif
name = stringJoin(buf, segment);
outname = stringJoin(name, extension);
FREE(name);
return outname;
}
/*!
* extractNumberFromFilename()
*
* Input: fname
* numpre (number of characters before the digits to be found)
* numpost (number of characters after the digits to be found)
* Return: num (number embedded in the filename); -1 on error or if
* not found
*
* Notes:
* (1) The number is to be found in the basename, which is the
* filename without either the directory or the last extension.
* (2) When a number is found, it is non-negative. If no number
* is found, this returns -1, without an error message. The
* caller needs to check.
*/
l_int32
extractNumberFromFilename(const char *fname,
l_int32 numpre,
l_int32 numpost)
{
char *tail, *basename;
l_int32 len, nret, num;
PROCNAME("extractNumberFromFilename");
if (!fname)
return ERROR_INT("fname not defined", procName, -1);
splitPathAtDirectory(fname, NULL, &tail);
splitPathAtExtension(tail, &basename, NULL);
FREE(tail);
len = strlen(basename);
if (numpre + numpost > len - 1) {
FREE(basename);
return ERROR_INT("numpre + numpost too big", procName, -1);
}
basename[len - numpost] = '\0';
nret = sscanf(basename + numpre, "%d", &num);
FREE(basename);
if (nret == 1)
return num;
else
return -1; /* not found */
}
/*---------------------------------------------------------------------*
* Version number *
*---------------------------------------------------------------------*/
/*!
* getLeptonlibVersion()
*
* Return: string of version number (e.g., 'leptonlib-1.65')
*
* Notes:
* (1) The caller has responsibility to free the memory.
*/
char *
getLeptonlibVersion()
{
char *version = (char *)CALLOC(100, sizeof(char));
#if COMPILER_MSVC
#ifdef _DLL
char dllStr[] = "DLL";
#else
char dllStr[] = "LIB";
#endif
#ifdef _DEBUG
char debugStr[] = "Debug";
#else
char debugStr[] = "Release";
#endif
#ifdef _M_IX86
char bitStr[] = " 32 bit";
#elif _M_X64
char bitStr[] = " 64 bit";
#else
char bitStr[] = ""
#endif
snprintf(version, 100, "leptonlib-%d.%d (%s, %s) [MSC v.%d %s %s%s]",
LIBLEPT_MAJOR_VERSION, LIBLEPT_MINOR_VERSION,
__DATE__, __TIME__, _MSC_VER, dllStr, debugStr, bitStr);
#else
snprintf(version, 100, "leptonlib-%d.%d", LIBLEPT_MAJOR_VERSION,
LIBLEPT_MINOR_VERSION);
#endif /* COMPILER_MSVC */
return version;
}
/*---------------------------------------------------------------------*
* Timing procs *
*---------------------------------------------------------------------*/
/*
* Example of use:
*
* startTimer();
* ....
* fprintf(stderr, "Elapsed time = %7.3f sec\n", stopTimer());
*/
#if !defined(__MINGW32__) && !defined(COMPILER_MSVC)
#include <sys/time.h>
#include <sys/resource.h>
static struct rusage rusage_before;
static struct rusage rusage_after;
void
startTimer(void)
{
getrusage(RUSAGE_SELF, &rusage_before);
}
l_float32
stopTimer(void)
{
l_int32 tsec, tusec;
getrusage(RUSAGE_SELF, &rusage_after);
tsec = rusage_after.ru_utime.tv_sec - rusage_before.ru_utime.tv_sec;
tusec = rusage_after.ru_utime.tv_usec - rusage_before.ru_utime.tv_usec;
return (tsec + ((l_float32)tusec) / 1000000.0);
}
#else /* __MINGW32__ : resource.h not implemented under MINGW */
#include <windows.h>
static ULARGE_INTEGER utime_before;
static ULARGE_INTEGER utime_after;
void
startTimer(void)
{
HANDLE this_process;
FILETIME start, stop, kernel, user;
this_process = GetCurrentProcess ();
GetProcessTimes (this_process, &start, &stop, &kernel, &user);
utime_before.LowPart = user.dwLowDateTime;
utime_before.HighPart = user.dwHighDateTime;
}
l_float32
stopTimer(void)
{
HANDLE this_process;
FILETIME start, stop, kernel, user;
this_process = GetCurrentProcess ();
GetProcessTimes (this_process, &start, &stop, &kernel, &user);
utime_after.LowPart = user.dwLowDateTime;
utime_after.HighPart = user.dwHighDateTime;
return ((l_float32)(signed)(utime_after.QuadPart - utime_before.QuadPart) /
10000000.0);
}
#endif