ultimatepp/bazaar/plugin/gdal/port/cpl_conv.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

2753 lines
90 KiB
C++

/******************************************************************************
* $Id: cpl_conv.cpp 28601 2015-03-03 11:06:40Z rouault $
*
* Project: CPL - Common Portability Library
* Purpose: Convenience functions.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1998, Frank Warmerdam
* Copyright (c) 2007-2014, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifdef MSVC_USE_VLD
#include <vld.h>
#endif
#include "cpl_conv.h"
#include "cpl_string.h"
#include "cpl_vsi.h"
#include "cpl_multiproc.h"
#include <errno.h>
CPL_CVSID("$Id: cpl_conv.cpp 28601 2015-03-03 11:06:40Z rouault $");
#if defined(WIN32CE)
# include "cpl_wince.h"
#endif
static CPLMutex *hConfigMutex = NULL;
static volatile char **papszConfigOptions = NULL;
/* Used by CPLOpenShared() and friends */
static CPLMutex *hSharedFileMutex = NULL;
static volatile int nSharedFileCount = 0;
static volatile CPLSharedFileInfo *pasSharedFileList = NULL;
/* Used by CPLsetlocale() */
static CPLMutex *hSetLocaleMutex = NULL;
/* Note: ideally this should be added in CPLSharedFileInfo* */
/* but CPLSharedFileInfo is exposed in the API, hence that trick */
/* to hide this detail */
typedef struct
{
GIntBig nPID; // pid of opening thread
} CPLSharedFileInfoExtra;
static volatile CPLSharedFileInfoExtra *pasSharedFileListExtra = NULL;
/************************************************************************/
/* CPLCalloc() */
/************************************************************************/
/**
* Safe version of calloc().
*
* This function is like the C library calloc(), but raises a CE_Fatal
* error with CPLError() if it fails to allocate the desired memory. It
* should be used for small memory allocations that are unlikely to fail
* and for which the application is unwilling to test for out of memory
* conditions. It uses VSICalloc() to get the memory, so any hooking of
* VSICalloc() will apply to CPLCalloc() as well. CPLFree() or VSIFree()
* can be used free memory allocated by CPLCalloc().
*
* @param nCount number of objects to allocate.
* @param nSize size (in bytes) of object to allocate.
* @return pointer to newly allocated memory, only NULL if nSize * nCount is
* NULL.
*/
void *CPLCalloc( size_t nCount, size_t nSize )
{
void *pReturn;
if( nSize * nCount == 0 )
return NULL;
pReturn = CPLMalloc( nCount * nSize );
memset( pReturn, 0, nCount * nSize );
return pReturn;
}
/************************************************************************/
/* CPLMalloc() */
/************************************************************************/
/**
* Safe version of malloc().
*
* This function is like the C library malloc(), but raises a CE_Fatal
* error with CPLError() if it fails to allocate the desired memory. It
* should be used for small memory allocations that are unlikely to fail
* and for which the application is unwilling to test for out of memory
* conditions. It uses VSIMalloc() to get the memory, so any hooking of
* VSIMalloc() will apply to CPLMalloc() as well. CPLFree() or VSIFree()
* can be used free memory allocated by CPLMalloc().
*
* @param nSize size (in bytes) of memory block to allocate.
* @return pointer to newly allocated memory, only NULL if nSize is zero.
*/
void *CPLMalloc( size_t nSize )
{
void *pReturn;
CPLVerifyConfiguration();
if( nSize == 0 )
return NULL;
if( long(nSize) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"CPLMalloc(%ld): Silly size requested.\n",
(long) nSize );
return NULL;
}
pReturn = VSIMalloc( nSize );
if( pReturn == NULL )
{
if( nSize > 0 && nSize < 2000 )
{
char szSmallMsg[60];
sprintf( szSmallMsg,
"CPLMalloc(): Out of memory allocating %ld bytes.",
(long) nSize );
CPLEmergencyError( szSmallMsg );
}
else
CPLError( CE_Fatal, CPLE_OutOfMemory,
"CPLMalloc(): Out of memory allocating %ld bytes.\n",
(long) nSize );
}
return pReturn;
}
/************************************************************************/
/* CPLRealloc() */
/************************************************************************/
/**
* Safe version of realloc().
*
* This function is like the C library realloc(), but raises a CE_Fatal
* error with CPLError() if it fails to allocate the desired memory. It
* should be used for small memory allocations that are unlikely to fail
* and for which the application is unwilling to test for out of memory
* conditions. It uses VSIRealloc() to get the memory, so any hooking of
* VSIRealloc() will apply to CPLRealloc() as well. CPLFree() or VSIFree()
* can be used free memory allocated by CPLRealloc().
*
* It is also safe to pass NULL in as the existing memory block for
* CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block.
*
* @param pData existing memory block which should be copied to the new block.
* @param nNewSize new size (in bytes) of memory block to allocate.
* @return pointer to allocated memory, only NULL if nNewSize is zero.
*/
void * CPLRealloc( void * pData, size_t nNewSize )
{
void *pReturn;
if ( nNewSize == 0 )
{
VSIFree(pData);
return NULL;
}
if( long(nNewSize) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"CPLRealloc(%ld): Silly size requested.\n",
(long) nNewSize );
return NULL;
}
if( pData == NULL )
pReturn = VSIMalloc( nNewSize );
else
pReturn = VSIRealloc( pData, nNewSize );
if( pReturn == NULL )
{
if( nNewSize > 0 && nNewSize < 2000 )
{
char szSmallMsg[60];
sprintf( szSmallMsg,
"CPLRealloc(): Out of memory allocating %ld bytes.",
(long) nNewSize );
CPLEmergencyError( szSmallMsg );
}
else
CPLError( CE_Fatal, CPLE_OutOfMemory,
"CPLRealloc(): Out of memory allocating %ld bytes.\n",
(long) nNewSize );
}
return pReturn;
}
/************************************************************************/
/* CPLStrdup() */
/************************************************************************/
/**
* Safe version of strdup() function.
*
* This function is similar to the C library strdup() function, but if
* the memory allocation fails it will issue a CE_Fatal error with
* CPLError() instead of returning NULL. It uses VSIStrdup(), so any
* hooking of that function will apply to CPLStrdup() as well. Memory
* allocated with CPLStrdup() can be freed with CPLFree() or VSIFree().
*
* It is also safe to pass a NULL string into CPLStrdup(). CPLStrdup()
* will allocate and return a zero length string (as opposed to a NULL
* string).
*
* @param pszString input string to be duplicated. May be NULL.
* @return pointer to a newly allocated copy of the string. Free with
* CPLFree() or VSIFree().
*/
char *CPLStrdup( const char * pszString )
{
char *pszReturn;
if( pszString == NULL )
pszString = "";
pszReturn = (char *) CPLMalloc(strlen(pszString)+1);
if( pszReturn == NULL )
{
CPLError( CE_Fatal, CPLE_OutOfMemory,
"CPLStrdup(): Out of memory allocating %ld bytes.\n",
(long) strlen(pszString) );
}
strcpy( pszReturn, pszString );
return( pszReturn );
}
/************************************************************************/
/* CPLStrlwr() */
/************************************************************************/
/**
* Convert each characters of the string to lower case.
*
* For example, "ABcdE" will be converted to "abcde".
* This function is locale dependent.
*
* @param pszString input string to be converted.
* @return pointer to the same string, pszString.
*/
char *CPLStrlwr( char *pszString )
{
if (pszString)
{
char *pszTemp = pszString;
while (*pszTemp)
{
*pszTemp = (char) tolower (*pszTemp);
pszTemp++;
}
}
return pszString;
}
/************************************************************************/
/* CPLFGets() */
/* */
/* Note: CR = \r = ASCII 13 */
/* LF = \n = ASCII 10 */
/************************************************************************/
/**
* Reads in at most one less than nBufferSize characters from the fp
* stream and stores them into the buffer pointed to by pszBuffer.
* Reading stops after an EOF or a newline. If a newline is read, it
* is _not_ stored into the buffer. A '\\0' is stored after the last
* character in the buffer. All three types of newline terminators
* recognized by the CPLFGets(): single '\\r' and '\\n' and '\\r\\n'
* combination.
*
* @param pszBuffer pointer to the targeting character buffer.
* @param nBufferSize maximum size of the string to read (not including
* termonating '\\0').
* @param fp file pointer to read from.
* @return pointer to the pszBuffer containing a string read
* from the file or NULL if the error or end of file was encountered.
*/
char *CPLFGets( char *pszBuffer, int nBufferSize, FILE * fp )
{
int nActuallyRead, nOriginalOffset;
if ( nBufferSize == 0 || pszBuffer == NULL || fp == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Let the OS level call read what it things is one line. This */
/* will include the newline. On windows, if the file happens */
/* to be in text mode, the CRLF will have been converted to */
/* just the newline (LF). If it is in binary mode it may well */
/* have both. */
/* -------------------------------------------------------------------- */
nOriginalOffset = VSIFTell( fp );
if( VSIFGets( pszBuffer, nBufferSize, fp ) == NULL )
return NULL;
nActuallyRead = strlen(pszBuffer);
if ( nActuallyRead == 0 )
return NULL;
/* -------------------------------------------------------------------- */
/* If we found \r and out buffer is full, it is possible there */
/* is also a pending \n. Check for it. */
/* -------------------------------------------------------------------- */
if( nBufferSize == nActuallyRead+1
&& pszBuffer[nActuallyRead-1] == 13 )
{
int chCheck;
chCheck = fgetc( fp );
if( chCheck != 10 )
{
// unget the character.
VSIFSeek( fp, nOriginalOffset+nActuallyRead, SEEK_SET );
}
}
/* -------------------------------------------------------------------- */
/* Trim off \n, \r or \r\n if it appears at the end. We don't */
/* need to do any "seeking" since we want the newline eaten. */
/* -------------------------------------------------------------------- */
if( nActuallyRead > 1
&& pszBuffer[nActuallyRead-1] == 10
&& pszBuffer[nActuallyRead-2] == 13 )
{
pszBuffer[nActuallyRead-2] = '\0';
}
else if( pszBuffer[nActuallyRead-1] == 10
|| pszBuffer[nActuallyRead-1] == 13 )
{
pszBuffer[nActuallyRead-1] = '\0';
}
/* -------------------------------------------------------------------- */
/* Search within the string for a \r (MacOS convention */
/* apparently), and if we find it we need to trim the string, */
/* and seek back. */
/* -------------------------------------------------------------------- */
char *pszExtraNewline = strchr( pszBuffer, 13 );
if( pszExtraNewline != NULL )
{
int chCheck;
nActuallyRead = pszExtraNewline - pszBuffer + 1;
*pszExtraNewline = '\0';
VSIFSeek( fp, nOriginalOffset + nActuallyRead - 1, SEEK_SET );
/*
* This hackery is necessary to try and find our correct
* spot on win32 systems with text mode line translation going
* on. Sometimes the fseek back overshoots, but it doesn't
* "realize it" till a character has been read. Try to read till
* we get to the right spot and get our CR.
*/
chCheck = fgetc( fp );
while( (chCheck != 13 && chCheck != EOF)
|| VSIFTell(fp) < nOriginalOffset + nActuallyRead )
{
static volatile int bWarned = FALSE;
if( !bWarned )
{
bWarned = TRUE;
CPLDebug( "CPL", "CPLFGets() correcting for DOS text mode translation seek problem." );
}
chCheck = fgetc( fp );
}
}
return pszBuffer;
}
/************************************************************************/
/* CPLReadLineBuffer() */
/* */
/* Fetch readline buffer, and ensure it is the desired size, */
/* reallocating if needed. Manages TLS (thread local storage) */
/* issues for the buffer. */
/* We use a special trick to track the actual size of the buffer */
/* The first 4 bytes are reserved to store it as a int, hence the */
/* -4 / +4 hacks with the size and pointer. */
/************************************************************************/
static char *CPLReadLineBuffer( int nRequiredSize )
{
/* -------------------------------------------------------------------- */
/* A required size of -1 means the buffer should be freed. */
/* -------------------------------------------------------------------- */
if( nRequiredSize == -1 )
{
if( CPLGetTLS( CTLS_RLBUFFERINFO ) != NULL )
{
CPLFree( CPLGetTLS( CTLS_RLBUFFERINFO ) );
CPLSetTLS( CTLS_RLBUFFERINFO, NULL, FALSE );
}
return NULL;
}
/* -------------------------------------------------------------------- */
/* If the buffer doesn't exist yet, create it. */
/* -------------------------------------------------------------------- */
GUInt32 *pnAlloc = (GUInt32 *) CPLGetTLS( CTLS_RLBUFFERINFO );
if( pnAlloc == NULL )
{
pnAlloc = (GUInt32 *) CPLMalloc(200);
*pnAlloc = 196;
CPLSetTLS( CTLS_RLBUFFERINFO, pnAlloc, TRUE );
}
/* -------------------------------------------------------------------- */
/* If it is too small, grow it bigger. */
/* -------------------------------------------------------------------- */
if( ((int) *pnAlloc) -1 < nRequiredSize )
{
int nNewSize = nRequiredSize + 4 + 500;
if (nNewSize <= 0)
{
VSIFree( pnAlloc );
CPLSetTLS( CTLS_RLBUFFERINFO, NULL, FALSE );
CPLError( CE_Failure, CPLE_OutOfMemory,
"CPLReadLineBuffer(): Trying to allocate more than 2 GB." );
return NULL;
}
GUInt32* pnAllocNew = (GUInt32 *) VSIRealloc(pnAlloc,nNewSize);
if( pnAllocNew == NULL )
{
VSIFree( pnAlloc );
CPLSetTLS( CTLS_RLBUFFERINFO, NULL, FALSE );
CPLError( CE_Failure, CPLE_OutOfMemory,
"CPLReadLineBuffer(): Out of memory allocating %ld bytes.",
(long) nNewSize );
return NULL;
}
pnAlloc = pnAllocNew;
*pnAlloc = nNewSize - 4;
CPLSetTLS( CTLS_RLBUFFERINFO, pnAlloc, TRUE );
}
return (char *) (pnAlloc+1);
}
/************************************************************************/
/* CPLReadLine() */
/************************************************************************/
/**
* Simplified line reading from text file.
*
* Read a line of text from the given file handle, taking care
* to capture CR and/or LF and strip off ... equivelent of
* DKReadLine(). Pointer to an internal buffer is returned.
* The application shouldn't free it, or depend on it's value
* past the next call to CPLReadLine().
*
* Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file
* services should apply to CPLReadLine() as well.
*
* CPLReadLine() maintains an internal buffer, which will appear as a
* single block memory leak in some circumstances. CPLReadLine() may
* be called with a NULL FILE * at any time to free this working buffer.
*
* @param fp file pointer opened with VSIFOpen().
*
* @return pointer to an internal buffer containing a line of text read
* from the file or NULL if the end of file was encountered.
*/
const char *CPLReadLine( FILE * fp )
{
char *pszRLBuffer = CPLReadLineBuffer(1);
int nReadSoFar = 0;
/* -------------------------------------------------------------------- */
/* Cleanup case. */
/* -------------------------------------------------------------------- */
if( fp == NULL )
{
CPLReadLineBuffer( -1 );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Loop reading chunks of the line till we get to the end of */
/* the line. */
/* -------------------------------------------------------------------- */
int nBytesReadThisTime;
do {
/* -------------------------------------------------------------------- */
/* Grow the working buffer if we have it nearly full. Fail out */
/* of read line if we can't reallocate it big enough (for */
/* instance for a _very large_ file with no newlines). */
/* -------------------------------------------------------------------- */
if( nReadSoFar > 100 * 1024 * 1024 )
return NULL; /* it is dubious that we need to read a line longer than 100 MB ! */
pszRLBuffer = CPLReadLineBuffer( nReadSoFar + 129 );
if( pszRLBuffer == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Do the actual read. */
/* -------------------------------------------------------------------- */
if( CPLFGets( pszRLBuffer+nReadSoFar, 128, fp ) == NULL
&& nReadSoFar == 0 )
return NULL;
nBytesReadThisTime = strlen(pszRLBuffer+nReadSoFar);
nReadSoFar += nBytesReadThisTime;
} while( nBytesReadThisTime >= 127
&& pszRLBuffer[nReadSoFar-1] != 13
&& pszRLBuffer[nReadSoFar-1] != 10 );
return( pszRLBuffer );
}
/************************************************************************/
/* CPLReadLineL() */
/************************************************************************/
/**
* Simplified line reading from text file.
*
* Similar to CPLReadLine(), but reading from a large file API handle.
*
* @param fp file pointer opened with VSIFOpenL().
*
* @return pointer to an internal buffer containing a line of text read
* from the file or NULL if the end of file was encountered.
*/
const char *CPLReadLineL( VSILFILE * fp )
{
return CPLReadLine2L( fp, -1, NULL );
}
/************************************************************************/
/* CPLReadLine2L() */
/************************************************************************/
/**
* Simplified line reading from text file.
*
* Similar to CPLReadLine(), but reading from a large file API handle.
*
* @param fp file pointer opened with VSIFOpenL().
* @param nMaxCars maximum number of characters allowed, or -1 for no limit.
* @param papszOptions NULL-terminated array of options. Unused for now.
* @return pointer to an internal buffer containing a line of text read
* from the file or NULL if the end of file was encountered or the maximum
* number of characters allowed readched.
*
* @since GDAL 1.7.0
*/
const char *CPLReadLine2L( VSILFILE * fp, int nMaxCars, char** papszOptions )
{
(void) papszOptions;
/* -------------------------------------------------------------------- */
/* Cleanup case. */
/* -------------------------------------------------------------------- */
if( fp == NULL )
{
CPLReadLineBuffer( -1 );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Loop reading chunks of the line till we get to the end of */
/* the line. */
/* -------------------------------------------------------------------- */
char *pszRLBuffer;
const size_t nChunkSize = 40;
char szChunk[nChunkSize];
size_t nChunkBytesRead = 0;
int nBufLength = 0;
size_t nChunkBytesConsumed = 0;
while( TRUE )
{
/* -------------------------------------------------------------------- */
/* Read a chunk from the input file. */
/* -------------------------------------------------------------------- */
if ( nBufLength > INT_MAX - (int)nChunkSize - 1 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Too big line : more than 2 billion characters!." );
CPLReadLineBuffer( -1 );
return NULL;
}
pszRLBuffer = CPLReadLineBuffer( nBufLength + nChunkSize + 1 );
if( pszRLBuffer == NULL )
return NULL;
if( nChunkBytesRead == nChunkBytesConsumed + 1 )
{
// case where one character is left over from last read.
szChunk[0] = szChunk[nChunkBytesConsumed];
nChunkBytesConsumed = 0;
nChunkBytesRead = VSIFReadL( szChunk+1, 1, nChunkSize-1, fp ) + 1;
}
else
{
nChunkBytesConsumed = 0;
// fresh read.
nChunkBytesRead = VSIFReadL( szChunk, 1, nChunkSize, fp );
if( nChunkBytesRead == 0 )
{
if( nBufLength == 0 )
return NULL;
else
break;
}
}
/* -------------------------------------------------------------------- */
/* copy over characters watching for end-of-line. */
/* -------------------------------------------------------------------- */
int bBreak = FALSE;
while( nChunkBytesConsumed < nChunkBytesRead-1 && !bBreak )
{
if( (szChunk[nChunkBytesConsumed] == 13
&& szChunk[nChunkBytesConsumed+1] == 10)
|| (szChunk[nChunkBytesConsumed] == 10
&& szChunk[nChunkBytesConsumed+1] == 13) )
{
nChunkBytesConsumed += 2;
bBreak = TRUE;
}
else if( szChunk[nChunkBytesConsumed] == 10
|| szChunk[nChunkBytesConsumed] == 13 )
{
nChunkBytesConsumed += 1;
bBreak = TRUE;
}
else
{
pszRLBuffer[nBufLength++] = szChunk[nChunkBytesConsumed++];
if (nMaxCars >= 0 && nBufLength == nMaxCars)
{
CPLError( CE_Failure, CPLE_AppDefined,
"Maximum number of characters allowed reached.");
return NULL;
}
}
}
if( bBreak )
break;
/* -------------------------------------------------------------------- */
/* If there is a remaining character and it is not a newline */
/* consume it. If it is a newline, but we are clearly at the */
/* end of the file then consume it. */
/* -------------------------------------------------------------------- */
if( nChunkBytesConsumed == nChunkBytesRead-1
&& nChunkBytesRead < nChunkSize )
{
if( szChunk[nChunkBytesConsumed] == 10
|| szChunk[nChunkBytesConsumed] == 13 )
{
nChunkBytesConsumed++;
break;
}
pszRLBuffer[nBufLength++] = szChunk[nChunkBytesConsumed++];
break;
}
}
/* -------------------------------------------------------------------- */
/* If we have left over bytes after breaking out, seek back to */
/* ensure they remain to be read next time. */
/* -------------------------------------------------------------------- */
if( nChunkBytesConsumed < nChunkBytesRead )
{
size_t nBytesToPush = nChunkBytesRead - nChunkBytesConsumed;
VSIFSeekL( fp, VSIFTellL( fp ) - nBytesToPush, SEEK_SET );
}
pszRLBuffer[nBufLength] = '\0';
return( pszRLBuffer );
}
/************************************************************************/
/* CPLScanString() */
/************************************************************************/
/**
* Scan up to a maximum number of characters from a given string,
* allocate a buffer for a new string and fill it with scanned characters.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to read. Less
* characters will be read if a null character is encountered.
*
* @param bTrimSpaces If TRUE, trim ending spaces from the input string.
* Character considered as empty using isspace(3) function.
*
* @param bNormalize If TRUE, replace ':' symbol with the '_'. It is needed if
* resulting string will be used in CPL dictionaries.
*
* @return Pointer to the resulting string buffer. Caller responsible to free
* this buffer with CPLFree().
*/
char *CPLScanString( const char *pszString, int nMaxLength,
int bTrimSpaces, int bNormalize )
{
char *pszBuffer;
if ( !pszString )
return NULL;
if ( !nMaxLength )
return CPLStrdup( "" );
pszBuffer = (char *)CPLMalloc( nMaxLength + 1 );
if ( !pszBuffer )
return NULL;
strncpy( pszBuffer, pszString, nMaxLength );
pszBuffer[nMaxLength] = '\0';
if ( bTrimSpaces )
{
size_t i = strlen( pszBuffer );
while ( i-- > 0 && isspace((unsigned char)pszBuffer[i]) )
pszBuffer[i] = '\0';
}
if ( bNormalize )
{
size_t i = strlen( pszBuffer );
while ( i-- > 0 )
{
if ( pszBuffer[i] == ':' )
pszBuffer[i] = '_';
}
}
return pszBuffer;
}
/************************************************************************/
/* CPLScanLong() */
/************************************************************************/
/**
* Scan up to a maximum number of characters from a string and convert
* the result to a long.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to consider as part
* of the number. Less characters will be considered if a null character
* is encountered.
*
* @return Long value, converted from its ASCII form.
*/
long CPLScanLong( const char *pszString, int nMaxLength )
{
long iValue;
char *pszValue = (char *)CPLMalloc( nMaxLength + 1);
/* -------------------------------------------------------------------- */
/* Compute string into local buffer, and terminate it. */
/* -------------------------------------------------------------------- */
strncpy( pszValue, pszString, nMaxLength );
pszValue[nMaxLength] = '\0';
/* -------------------------------------------------------------------- */
/* Use atol() to fetch out the result */
/* -------------------------------------------------------------------- */
iValue = atol( pszValue );
CPLFree( pszValue );
return iValue;
}
/************************************************************************/
/* CPLScanULong() */
/************************************************************************/
/**
* Scan up to a maximum number of characters from a string and convert
* the result to a unsigned long.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to consider as part
* of the number. Less characters will be considered if a null character
* is encountered.
*
* @return Unsigned long value, converted from its ASCII form.
*/
unsigned long CPLScanULong( const char *pszString, int nMaxLength )
{
unsigned long uValue;
char *pszValue = (char *)CPLMalloc( nMaxLength + 1);
/* -------------------------------------------------------------------- */
/* Compute string into local buffer, and terminate it. */
/* -------------------------------------------------------------------- */
strncpy( pszValue, pszString, nMaxLength );
pszValue[nMaxLength] = '\0';
/* -------------------------------------------------------------------- */
/* Use strtoul() to fetch out the result */
/* -------------------------------------------------------------------- */
uValue = strtoul( pszValue, NULL, 10 );
CPLFree( pszValue );
return uValue;
}
/************************************************************************/
/* CPLScanUIntBig() */
/************************************************************************/
/**
* Extract big integer from string.
*
* Scan up to a maximum number of characters from a string and convert
* the result to a GUIntBig.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to consider as part
* of the number. Less characters will be considered if a null character
* is encountered.
*
* @return GUIntBig value, converted from its ASCII form.
*/
GUIntBig CPLScanUIntBig( const char *pszString, int nMaxLength )
{
GUIntBig iValue;
char *pszValue = (char *)CPLMalloc( nMaxLength + 1);
/* -------------------------------------------------------------------- */
/* Compute string into local buffer, and terminate it. */
/* -------------------------------------------------------------------- */
strncpy( pszValue, pszString, nMaxLength );
pszValue[nMaxLength] = '\0';
/* -------------------------------------------------------------------- */
/* Fetch out the result */
/* -------------------------------------------------------------------- */
#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
iValue = (GUIntBig)_atoi64( pszValue );
# elif HAVE_ATOLL
iValue = atoll( pszValue );
#else
iValue = atol( pszValue );
#endif
CPLFree( pszValue );
return iValue;
}
/************************************************************************/
/* CPLAtoGIntBig() */
/************************************************************************/
/**
* Convert a string to a 64 bit signed integer.
*
* @param pszString String containing 64 bit signed integer.
* @return 64 bit signed integer.
* @since GDAL 2.0
*/
GIntBig CPLAtoGIntBig( const char* pszString )
{
#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
return _atoi64( pszString );
# elif HAVE_ATOLL
return atoll( pszString );
#else
return atol( pszString );
#endif
}
#if defined(__MINGW32__)
// mingw atoll() doesn't return ERANGE in case of overflow
int CPLAtoGIntBigExHasOverflow(const char* pszString, GIntBig nVal)
{
if( strlen(pszString) <= 18 )
return FALSE;
while( *pszString == ' ' )
pszString ++;
if( *pszString == '+' )
pszString ++;
char szBuffer[32];
sprintf(szBuffer, CPL_FRMT_GIB, nVal);
return strcmp(szBuffer, pszString) != 0;
}
#endif
/************************************************************************/
/* CPLAtoGIntBigEx() */
/************************************************************************/
/**
* Convert a string to a 64 bit signed integer.
*
* @param pszString String containing 64 bit signed integer.
* @param bWarn Issue a warning if an overflow occurs during conversion
* @param pbOverflow Pointer to an integer to store if an overflow occured, or NULL
* @return 64 bit signed integer.
* @since GDAL 2.0
*/
GIntBig CPLAtoGIntBigEx( const char* pszString, int bWarn, int *pbOverflow )
{
GIntBig nVal;
errno = 0;
#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
nVal = _atoi64( pszString );
# elif HAVE_ATOLL
nVal = atoll( pszString );
#else
nVal = atol( pszString );
#endif
if( errno == ERANGE
#if defined(__MINGW32__)
|| CPLAtoGIntBigExHasOverflow(pszString, nVal)
#endif
)
{
if( pbOverflow ) *pbOverflow = TRUE;
if( bWarn )
{
CPLError(CE_Warning, CPLE_AppDefined,
"64 bit integer overflow when converting %s",
pszString);
}
while( *pszString == ' ' )
pszString ++;
return (*pszString == '-' ) ? GINTBIG_MIN : GINTBIG_MAX;
}
else if( pbOverflow ) *pbOverflow = FALSE;
return nVal;
}
/************************************************************************/
/* CPLScanPointer() */
/************************************************************************/
/**
* Extract pointer from string.
*
* Scan up to a maximum number of characters from a string and convert
* the result to a pointer.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to consider as part
* of the number. Less characters will be considered if a null character
* is encountered.
*
* @return pointer value, converted from its ASCII form.
*/
void *CPLScanPointer( const char *pszString, int nMaxLength )
{
void *pResult;
char szTemp[128];
/* -------------------------------------------------------------------- */
/* Compute string into local buffer, and terminate it. */
/* -------------------------------------------------------------------- */
if( nMaxLength > (int) sizeof(szTemp)-1 )
nMaxLength = sizeof(szTemp)-1;
strncpy( szTemp, pszString, nMaxLength );
szTemp[nMaxLength] = '\0';
/* -------------------------------------------------------------------- */
/* On MSVC we have to scanf pointer values without the 0x */
/* prefix. */
/* -------------------------------------------------------------------- */
if( EQUALN(szTemp,"0x",2) )
{
pResult = NULL;
#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
sscanf( szTemp+2, "%p", &pResult );
#else
sscanf( szTemp, "%p", &pResult );
/* Solaris actually behaves like MSVCRT... */
if (pResult == NULL)
{
sscanf( szTemp+2, "%p", &pResult );
}
#endif
}
else
{
#if SIZEOF_VOIDP == 8
pResult = (void *) CPLScanUIntBig( szTemp, nMaxLength );
#else
pResult = (void *) CPLScanULong( szTemp, nMaxLength );
#endif
}
return pResult;
}
/************************************************************************/
/* CPLScanDouble() */
/************************************************************************/
/**
* Extract double from string.
*
* Scan up to a maximum number of characters from a string and convert the
* result to a double. This function uses CPLAtof() to convert string to
* double value, so it uses a comma as a decimal delimiter.
*
* @param pszString String containing characters to be scanned. It may be
* terminated with a null character.
*
* @param nMaxLength The maximum number of character to consider as part
* of the number. Less characters will be considered if a null character
* is encountered.
*
* @return Double value, converted from its ASCII form.
*/
double CPLScanDouble( const char *pszString, int nMaxLength )
{
int i;
double dfValue;
char *pszValue = (char *)CPLMalloc( nMaxLength + 1);
/* -------------------------------------------------------------------- */
/* Compute string into local buffer, and terminate it. */
/* -------------------------------------------------------------------- */
strncpy( pszValue, pszString, nMaxLength );
pszValue[nMaxLength] = '\0';
/* -------------------------------------------------------------------- */
/* Make a pass through converting 'D's to 'E's. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nMaxLength; i++ )
if ( pszValue[i] == 'd' || pszValue[i] == 'D' )
pszValue[i] = 'E';
/* -------------------------------------------------------------------- */
/* The conversion itself. */
/* -------------------------------------------------------------------- */
dfValue = CPLAtof( pszValue );
CPLFree( pszValue );
return dfValue;
}
/************************************************************************/
/* CPLPrintString() */
/************************************************************************/
/**
* Copy the string pointed to by pszSrc, NOT including the terminating
* `\\0' character, to the array pointed to by pszDest.
*
* @param pszDest Pointer to the destination string buffer. Should be
* large enough to hold the resulting string.
*
* @param pszSrc Pointer to the source buffer.
*
* @param nMaxLen Maximum length of the resulting string. If string length
* is greater than nMaxLen, it will be truncated.
*
* @return Number of characters printed.
*/
int CPLPrintString( char *pszDest, const char *pszSrc, int nMaxLen )
{
char *pszTemp = pszDest;
int nChars = 0;
if ( !pszDest )
return 0;
if ( !pszSrc )
{
*pszDest = '\0';
return 1;
}
while ( nChars < nMaxLen && *pszSrc )
{
*pszTemp++ = *pszSrc++;
nChars++;
}
return nChars;
}
/************************************************************************/
/* CPLPrintStringFill() */
/************************************************************************/
/**
* Copy the string pointed to by pszSrc, NOT including the terminating
* `\\0' character, to the array pointed to by pszDest. Remainder of the
* destination string will be filled with space characters. This is only
* difference from the PrintString().
*
* @param pszDest Pointer to the destination string buffer. Should be
* large enough to hold the resulting string.
*
* @param pszSrc Pointer to the source buffer.
*
* @param nMaxLen Maximum length of the resulting string. If string length
* is greater than nMaxLen, it will be truncated.
*
* @return Number of characters printed.
*/
int CPLPrintStringFill( char *pszDest, const char *pszSrc, int nMaxLen )
{
char *pszTemp = pszDest;
if ( !pszDest )
return 0;
if ( !pszSrc )
{
memset( pszDest, ' ', nMaxLen );
return nMaxLen;
}
while ( nMaxLen && *pszSrc )
{
*pszTemp++ = *pszSrc++;
nMaxLen--;
}
if ( nMaxLen )
memset( pszTemp, ' ', nMaxLen );
return nMaxLen;
}
/************************************************************************/
/* CPLPrintInt32() */
/************************************************************************/
/**
* Print GInt32 value into specified string buffer. This string will not
* be NULL-terminated.
*
* @param pszBuffer Pointer to the destination string buffer. Should be
* large enough to hold the resulting string. Note, that the string will
* not be NULL-terminated, so user should do this himself, if needed.
*
* @param iValue Numerical value to print.
*
* @param nMaxLen Maximum length of the resulting string. If string length
* is greater than nMaxLen, it will be truncated.
*
* @return Number of characters printed.
*/
int CPLPrintInt32( char *pszBuffer, GInt32 iValue, int nMaxLen )
{
char szTemp[64];
if ( !pszBuffer )
return 0;
if ( nMaxLen >= 64 )
nMaxLen = 63;
#if UINT_MAX == 65535
sprintf( szTemp, "%*ld", nMaxLen, iValue );
#else
sprintf( szTemp, "%*d", nMaxLen, iValue );
#endif
return CPLPrintString( pszBuffer, szTemp, nMaxLen );
}
/************************************************************************/
/* CPLPrintUIntBig() */
/************************************************************************/
/**
* Print GUIntBig value into specified string buffer. This string will not
* be NULL-terminated.
*
* @param pszBuffer Pointer to the destination string buffer. Should be
* large enough to hold the resulting string. Note, that the string will
* not be NULL-terminated, so user should do this himself, if needed.
*
* @param iValue Numerical value to print.
*
* @param nMaxLen Maximum length of the resulting string. If string length
* is greater than nMaxLen, it will be truncated.
*
* @return Number of characters printed.
*/
int CPLPrintUIntBig( char *pszBuffer, GUIntBig iValue, int nMaxLen )
{
char szTemp[64];
if ( !pszBuffer )
return 0;
if ( nMaxLen >= 64 )
nMaxLen = 63;
#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
sprintf( szTemp, "%*I64d", nMaxLen, iValue );
# elif HAVE_LONG_LONG
sprintf( szTemp, "%*lld", nMaxLen, (long long) iValue );
// sprintf( szTemp, "%*Ld", nMaxLen, (long long) iValue );
#else
sprintf( szTemp, "%*ld", nMaxLen, iValue );
#endif
return CPLPrintString( pszBuffer, szTemp, nMaxLen );
}
/************************************************************************/
/* CPLPrintPointer() */
/************************************************************************/
/**
* Print pointer value into specified string buffer. This string will not
* be NULL-terminated.
*
* @param pszBuffer Pointer to the destination string buffer. Should be
* large enough to hold the resulting string. Note, that the string will
* not be NULL-terminated, so user should do this himself, if needed.
*
* @param pValue Pointer to ASCII encode.
*
* @param nMaxLen Maximum length of the resulting string. If string length
* is greater than nMaxLen, it will be truncated.
*
* @return Number of characters printed.
*/
int CPLPrintPointer( char *pszBuffer, void *pValue, int nMaxLen )
{
char szTemp[64];
if ( !pszBuffer )
return 0;
if ( nMaxLen >= 64 )
nMaxLen = 63;
sprintf( szTemp, "%p", pValue );
// On windows, and possibly some other platforms the sprintf("%p")
// does not prefix things with 0x so it is hard to know later if the
// value is hex encoded. Fix this up here.
if( !EQUALN(szTemp,"0x",2) )
sprintf( szTemp, "0x%p", pValue );
return CPLPrintString( pszBuffer, szTemp, nMaxLen );
}
/************************************************************************/
/* CPLPrintDouble() */
/************************************************************************/
/**
* Print double value into specified string buffer. Exponential character
* flag 'E' (or 'e') will be replaced with 'D', as in Fortran. Resulting
* string will not to be NULL-terminated.
*
* @param pszBuffer Pointer to the destination string buffer. Should be
* large enough to hold the resulting string. Note, that the string will
* not be NULL-terminated, so user should do this himself, if needed.
*
* @param pszFormat Format specifier (for example, "%16.9E").
*
* @param dfValue Numerical value to print.
*
* @param pszLocale Pointer to a character string containing locale name
* ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
* manipulate with locale settings and current process locale will be used for
* printing. With the pszLocale option we can control what exact locale
* will be used for printing a numeric value to the string (in most cases
* it should be C/POSIX).
*
* @return Number of characters printed.
*/
int CPLPrintDouble( char *pszBuffer, const char *pszFormat,
double dfValue, CPL_UNUSED const char *pszLocale )
{
if ( !pszBuffer )
return 0;
const int double_buffer_size = 64;
char szTemp[double_buffer_size];
#if defined(HAVE_SNPRINTF)
CPLsnprintf( szTemp, double_buffer_size, pszFormat, dfValue );
#else
CPLsprintf( szTemp, pszFormat, dfValue );
#endif
szTemp[double_buffer_size - 1] = '\0';
for( int i = 0; szTemp[i] != '\0'; i++ )
{
if( szTemp[i] == 'E' || szTemp[i] == 'e' )
szTemp[i] = 'D';
}
return CPLPrintString( pszBuffer, szTemp, 64 );
}
/************************************************************************/
/* CPLPrintTime() */
/************************************************************************/
/**
* Print specified time value accordingly to the format options and
* specified locale name. This function does following:
*
* - if locale parameter is not NULL, the current locale setting will be
* stored and replaced with the specified one;
* - format time value with the strftime(3) function;
* - restore back current locale, if was saved.
*
* @param pszBuffer Pointer to the destination string buffer. Should be
* large enough to hold the resulting string. Note, that the string will
* not be NULL-terminated, so user should do this himself, if needed.
*
* @param nMaxLen Maximum length of the resulting string. If string length is
* greater than nMaxLen, it will be truncated.
*
* @param pszFormat Controls the output format. Options are the same as
* for strftime(3) function.
*
* @param poBrokenTime Pointer to the broken-down time structure. May be
* requested with the VSIGMTime() and VSILocalTime() functions.
*
* @param pszLocale Pointer to a character string containing locale name
* ("C", "POSIX", "us_US", "ru_RU.KOI8-R" etc.). If NULL we will not
* manipulate with locale settings and current process locale will be used for
* printing. Be aware that it may be unsuitable to use current locale for
* printing time, because all names will be printed in your native language,
* as well as time format settings also may be ajusted differently from the
* C/POSIX defaults. To solve these problems this option was introdiced.
*
* @return Number of characters printed.
*/
#ifndef WIN32CE /* XXX - mloskot - strftime is not available yet. */
int CPLPrintTime( char *pszBuffer, int nMaxLen, const char *pszFormat,
const struct tm *poBrokenTime, const char *pszLocale )
{
char *pszTemp = (char *)CPLMalloc( (nMaxLen + 1) * sizeof(char) );
int nChars;
#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
char *pszCurLocale = NULL;
if ( pszLocale || EQUAL( pszLocale, "" ) )
{
// Save the current locale
pszCurLocale = CPLsetlocale(LC_ALL, NULL );
// Set locale to the specified value
CPLsetlocale( LC_ALL, pszLocale );
}
#else
(void) pszLocale;
#endif
if ( !strftime( pszTemp, nMaxLen + 1, pszFormat, poBrokenTime ) )
memset( pszTemp, 0, nMaxLen + 1);
#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
// Restore stored locale back
if ( pszCurLocale )
CPLsetlocale( LC_ALL, pszCurLocale );
#endif
nChars = CPLPrintString( pszBuffer, pszTemp, nMaxLen );
CPLFree( pszTemp );
return nChars;
}
#endif
/************************************************************************/
/* CPLVerifyConfiguration() */
/************************************************************************/
void CPLVerifyConfiguration()
{
/* -------------------------------------------------------------------- */
/* Verify data types. */
/* -------------------------------------------------------------------- */
CPLAssert( sizeof(GInt32) == 4 );
CPLAssert( sizeof(GInt16) == 2 );
CPLAssert( sizeof(GByte) == 1 );
if( sizeof(GInt32) != 4 )
CPLError( CE_Fatal, CPLE_AppDefined,
"sizeof(GInt32) == %d ... yow!\n",
(int) sizeof(GInt32) );
/* -------------------------------------------------------------------- */
/* Verify byte order */
/* -------------------------------------------------------------------- */
GInt32 nTest;
nTest = 1;
#ifdef CPL_LSB
if( ((GByte *) &nTest)[0] != 1 )
#endif
#ifdef CPL_MSB
if( ((GByte *) &nTest)[3] != 1 )
#endif
CPLError( CE_Fatal, CPLE_AppDefined,
"CPLVerifyConfiguration(): byte order set wrong.\n" );
}
/* Uncomment to get list of options that have been fetched and set */
//#define DEBUG_CONFIG_OPTIONS
#ifdef DEBUG_CONFIG_OPTIONS
#include <set>
#include "cpl_multiproc.h"
static void* hRegisterConfigurationOptionMutex = 0;
static std::set<CPLString>* paoGetKeys = NULL;
static std::set<CPLString>* paoSetKeys = NULL;
/************************************************************************/
/* CPLShowAccessedOptions() */
/************************************************************************/
static void CPLShowAccessedOptions()
{
std::set<CPLString>::iterator aoIter;
printf("Configuration options accessed in reading : "),
aoIter = paoGetKeys->begin();
while(aoIter != paoGetKeys->end())
{
printf("%s, ", (*aoIter).c_str());
aoIter ++;
}
printf("\n");
printf("Configuration options accessed in writing : "),
aoIter = paoSetKeys->begin();
while(aoIter != paoSetKeys->end())
{
printf("%s, ", (*aoIter).c_str());
aoIter ++;
}
printf("\n");
delete paoGetKeys;
delete paoSetKeys;
paoGetKeys = paoSetKeys = NULL;
}
/************************************************************************/
/* CPLAccessConfigOption() */
/************************************************************************/
static void CPLAccessConfigOption(const char* pszKey, int bGet)
{
CPLMutexHolderD(&hRegisterConfigurationOptionMutex);
if (paoGetKeys == NULL)
{
paoGetKeys = new std::set<CPLString>;
paoSetKeys = new std::set<CPLString>;
atexit(CPLShowAccessedOptions);
}
if (bGet)
paoGetKeys->insert(pszKey);
else
paoSetKeys->insert(pszKey);
}
#endif
/************************************************************************/
/* CPLGetConfigOption() */
/************************************************************************/
/**
* Get the value of a configuration option.
*
* The value is the value of a (key, value) option set with CPLSetConfigOption().
* If the given option was no defined with CPLSetConfigOption(), it tries to find
* it in environment variables.
*
* Note: the string returned by CPLGetConfigOption() might be short-lived, and in
* particular it will become invalid after a call to CPLSetConfigOption() with the
* same key.
*
* To override temporary a potentially existing option with a new value, you can
* use the following snippet :
* <pre>
* // backup old value
* const char* pszOldValTmp = CPLGetConfigOption(pszKey, NULL);
* char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
* // override with new value
* CPLSetConfigOption(pszKey, pszNewVal);
* // do something useful
* // restore old value
* CPLSetConfigOption(pszKey, pszOldVal);
* CPLFree(pszOldVal);
* </pre>
*
* @param pszKey the key of the option to retrieve
* @param pszDefault a default value if the key does not match existing defined options (may be NULL)
* @return the value associated to the key, or the default value if not found
*
* @see CPLSetConfigOption(), http://trac.osgeo.org/gdal/wiki/ConfigOptions
*/
const char * CPL_STDCALL
CPLGetConfigOption( const char *pszKey, const char *pszDefault )
{
#ifdef DEBUG_CONFIG_OPTIONS
CPLAccessConfigOption(pszKey, TRUE);
#endif
const char *pszResult = NULL;
char **papszTLConfigOptions = (char **) CPLGetTLS( CTLS_CONFIGOPTIONS );
if( papszTLConfigOptions != NULL )
pszResult = CSLFetchNameValue( papszTLConfigOptions, pszKey );
if( pszResult == NULL )
{
CPLMutexHolderD( &hConfigMutex );
pszResult = CSLFetchNameValue( (char **) papszConfigOptions, pszKey );
}
#if !defined(WIN32CE)
if( pszResult == NULL )
pszResult = getenv( pszKey );
#endif
if( pszResult == NULL )
return pszDefault;
else
return pszResult;
}
/************************************************************************/
/* CPLSetConfigOption() */
/************************************************************************/
/**
* Set a configuration option for GDAL/OGR use.
*
* Those options are defined as a (key, value) couple. The value corresponding
* to a key can be got later with the CPLGetConfigOption() method.
*
* This mechanism is similar to environment variables, but options set with
* CPLSetConfigOption() overrides, for CPLGetConfigOption() point of view,
* values defined in the environment.
*
* If CPLSetConfigOption() is called several times with the same key, the
* value provided during the last call will be used.
*
* Options can also be passed on the command line of most GDAL utilities
* with the with '--config KEY VALUE'. For example,
* ogrinfo --config CPL_DEBUG ON ~/data/test/point.shp
*
* This function can also be used to clear a setting by passing NULL as the
* value (note: passing NULL will not unset an existing environment variable;
* it will just unset a value previously set by CPLSetConfigOption()).
*
* @param pszKey the key of the option
* @param pszValue the value of the option, or NULL to clear a setting.
*
* @see http://trac.osgeo.org/gdal/wiki/ConfigOptions
*/
void CPL_STDCALL
CPLSetConfigOption( const char *pszKey, const char *pszValue )
{
#ifdef DEBUG_CONFIG_OPTIONS
CPLAccessConfigOption(pszKey, FALSE);
#endif
CPLMutexHolderD( &hConfigMutex );
papszConfigOptions = (volatile char **)
CSLSetNameValue( (char **) papszConfigOptions, pszKey, pszValue );
}
/************************************************************************/
/* CPLSetThreadLocalTLSFreeFunc() */
/************************************************************************/
/* non-stdcall wrapper function for CSLDestroy() (#5590) */
static void CPLSetThreadLocalTLSFreeFunc( void* pData )
{
CSLDestroy( (char**) pData );
}
/************************************************************************/
/* CPLSetThreadLocalConfigOption() */
/************************************************************************/
/**
* Set a configuration option for GDAL/OGR use.
*
* Those options are defined as a (key, value) couple. The value corresponding
* to a key can be got later with the CPLGetConfigOption() method.
*
* This function sets the configuration option that only applies in the
* current thread, as opposed to CPLSetConfigOption() which sets an option
* that applies on all threads.
*
* This function can also be used to clear a setting by passing NULL as the
* value (note: passing NULL will not unset an existing environment variable;
* it will just unset a value previously set by CPLSetThreadLocalConfigOption()).
*
* @param pszKey the key of the option
* @param pszValue the value of the option, or NULL to clear a setting.
*/
void CPL_STDCALL
CPLSetThreadLocalConfigOption( const char *pszKey, const char *pszValue )
{
#ifdef DEBUG_CONFIG_OPTIONS
CPLAccessConfigOption(pszKey, FALSE);
#endif
char **papszTLConfigOptions = (char **) CPLGetTLS( CTLS_CONFIGOPTIONS );
papszTLConfigOptions =
CSLSetNameValue( papszTLConfigOptions, pszKey, pszValue );
CPLSetTLSWithFreeFunc( CTLS_CONFIGOPTIONS, papszTLConfigOptions,
CPLSetThreadLocalTLSFreeFunc );
}
/************************************************************************/
/* CPLFreeConfig() */
/************************************************************************/
void CPL_STDCALL CPLFreeConfig()
{
{
CPLMutexHolderD( &hConfigMutex );
CSLDestroy( (char **) papszConfigOptions);
papszConfigOptions = NULL;
char **papszTLConfigOptions = (char **) CPLGetTLS( CTLS_CONFIGOPTIONS );
if( papszTLConfigOptions != NULL )
{
CSLDestroy( papszTLConfigOptions );
CPLSetTLS( CTLS_CONFIGOPTIONS, NULL, FALSE );
}
}
CPLDestroyMutex( hConfigMutex );
hConfigMutex = NULL;
}
/************************************************************************/
/* CPLStat() */
/* */
/* Same as VSIStat() except it works on "C:" as if it were */
/* "C:\". */
/************************************************************************/
int CPLStat( const char *pszPath, VSIStatBuf *psStatBuf )
{
if( strlen(pszPath) == 2 && pszPath[1] == ':' )
{
char szAltPath[4];
szAltPath[0] = pszPath[0];
szAltPath[1] = pszPath[1];
szAltPath[2] = '\\';
szAltPath[3] = '\0';
return VSIStat( szAltPath, psStatBuf );
}
else
return VSIStat( pszPath, psStatBuf );
}
/************************************************************************/
/* proj_strtod() */
/************************************************************************/
static double
proj_strtod(char *nptr, char **endptr)
{
char c, *cp = nptr;
double result;
/*
* Scan for characters which cause problems with VC++ strtod()
*/
while ((c = *cp) != '\0') {
if (c == 'd' || c == 'D') {
/*
* Found one, so NUL it out, call strtod(),
* then restore it and return
*/
*cp = '\0';
result = CPLStrtod(nptr, endptr);
*cp = c;
return result;
}
++cp;
}
/* no offending characters, just handle normally */
return CPLStrtod(nptr, endptr);
}
/************************************************************************/
/* CPLDMSToDec() */
/************************************************************************/
static const char*sym = "NnEeSsWw";
static const double vm[] = { 1.0, 0.0166666666667, 0.00027777778 };
double CPLDMSToDec( const char *is )
{
int sign, n, nl;
char *p, *s, work[64];
double v, tv;
/* copy sting into work space */
while (isspace((unsigned char)(sign = *is))) ++is;
for (n = sizeof(work), s = work, p = (char *)is; isgraph(*p) && --n ; )
*s++ = *p++;
*s = '\0';
/* it is possible that a really odd input (like lots of leading
zeros) could be truncated in copying into work. But ... */
sign = *(s = work);
if (sign == '+' || sign == '-') s++;
else sign = '+';
for (v = 0., nl = 0 ; nl < 3 ; nl = n + 1 ) {
if (!(isdigit(*s) || *s == '.')) break;
if ((tv = proj_strtod(s, &s)) == HUGE_VAL)
return tv;
switch (*s) {
case 'D': case 'd':
n = 0; break;
case '\'':
n = 1; break;
case '"':
n = 2; break;
case 'r': case 'R':
if (nl) {
return 0.0;
}
++s;
v = tv;
goto skip;
default:
v += tv * vm[nl];
skip: n = 4;
continue;
}
if (n < nl) {
return 0.0;
}
v += tv * vm[n];
++s;
}
/* postfix sign */
if (*s && ((p = (char *) strchr(sym, *s))) != NULL) {
sign = (p - sym) >= 4 ? '-' : '+';
++s;
}
if (sign == '-')
v = -v;
return v;
}
/************************************************************************/
/* CPLDecToDMS() */
/* */
/* Translate a decimal degrees value to a DMS string with */
/* hemisphere. */
/************************************************************************/
const char *CPLDecToDMS( double dfAngle, const char * pszAxis,
int nPrecision )
{
VALIDATE_POINTER1( pszAxis, "CPLDecToDMS", "" );
int nDegrees, nMinutes;
double dfSeconds, dfABSAngle, dfEpsilon;
char szFormat[30];
const char *pszHemisphere;
static CPL_THREADLOCAL char szBuffer[50] = { 0 };
dfEpsilon = (0.5/3600.0) * pow(0.1,nPrecision);
dfABSAngle = ABS(dfAngle) + dfEpsilon;
if (dfABSAngle > 361)
{
return "Invalid angle";
}
nDegrees = (int) dfABSAngle;
nMinutes = (int) ((dfABSAngle - nDegrees) * 60);
dfSeconds = dfABSAngle * 3600 - nDegrees*3600 - nMinutes*60;
if( dfSeconds > dfEpsilon * 3600.0 )
dfSeconds -= dfEpsilon * 3600.0;
if( EQUAL(pszAxis,"Long") && dfAngle < 0.0 )
pszHemisphere = "W";
else if( EQUAL(pszAxis,"Long") )
pszHemisphere = "E";
else if( dfAngle < 0.0 )
pszHemisphere = "S";
else
pszHemisphere = "N";
CPLsprintf( szFormat, "%%3dd%%2d\'%%%d.%df\"%s", nPrecision+3, nPrecision, pszHemisphere );
CPLsprintf( szBuffer, szFormat, nDegrees, nMinutes, dfSeconds );
return( szBuffer );
}
/************************************************************************/
/* CPLPackedDMSToDec() */
/************************************************************************/
/**
* Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
*
* This function converts a packed DMS angle to seconds. The standard
* packed DMS format is:
*
* degrees * 1000000 + minutes * 1000 + seconds
*
* Example: ang = 120025045.25 yields
* deg = 120
* min = 25
* sec = 45.25
*
* The algorithm used for the conversion is as follows:
*
* 1. The absolute value of the angle is used.
*
* 2. The degrees are separated out:
* deg = ang/1000000 (fractional portion truncated)
*
* 3. The minutes are separated out:
* min = (ang - deg * 1000000) / 1000 (fractional portion truncated)
*
* 4. The seconds are then computed:
* sec = ang - deg * 1000000 - min * 1000
*
* 5. The total angle in seconds is computed:
* sec = deg * 3600.0 + min * 60.0 + sec
*
* 6. The sign of sec is set to that of the input angle.
*
* Packed DMS values used by the USGS GCTP package and probably by other
* software.
*
* NOTE: This code does not validate input value. If you give the wrong
* value, you will get the wrong result.
*
* @param dfPacked Angle in packed DMS format.
*
* @return Angle in decimal degrees.
*
*/
double CPLPackedDMSToDec( double dfPacked )
{
double dfDegrees, dfMinutes, dfSeconds, dfSign;
dfSign = ( dfPacked < 0.0 )? -1 : 1;
dfSeconds = ABS( dfPacked );
dfDegrees = floor(dfSeconds / 1000000.0);
dfSeconds = dfSeconds - dfDegrees * 1000000.0;
dfMinutes = floor(dfSeconds / 1000.0);
dfSeconds = dfSeconds - dfMinutes * 1000.0;
dfSeconds = dfSign * ( dfDegrees * 3600.0 + dfMinutes * 60.0 + dfSeconds);
dfDegrees = dfSeconds / 3600.0;
return dfDegrees;
}
/************************************************************************/
/* CPLDecToPackedDMS() */
/************************************************************************/
/**
* Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
*
* This function converts a value, specified in decimal degrees into
* packed DMS angle. The standard packed DMS format is:
*
* degrees * 1000000 + minutes * 1000 + seconds
*
* See also CPLPackedDMSToDec().
*
* @param dfDec Angle in decimal degrees.
*
* @return Angle in packed DMS format.
*
*/
double CPLDecToPackedDMS( double dfDec )
{
double dfDegrees, dfMinutes, dfSeconds, dfSign;
dfSign = ( dfDec < 0.0 )? -1 : 1;
dfDec = ABS( dfDec );
dfDegrees = floor( dfDec );
dfMinutes = floor( ( dfDec - dfDegrees ) * 60.0 );
dfSeconds = ( dfDec - dfDegrees ) * 3600.0 - dfMinutes * 60.0;
return dfSign * (dfDegrees * 1000000.0 + dfMinutes * 1000.0 + dfSeconds);
}
/************************************************************************/
/* CPLStringToComplex() */
/************************************************************************/
void CPL_DLL CPLStringToComplex( const char *pszString,
double *pdfReal, double *pdfImag )
{
int i;
int iPlus = -1, iImagEnd = -1;
while( *pszString == ' ' )
pszString++;
*pdfReal = CPLAtof(pszString);
*pdfImag = 0.0;
for( i = 0; pszString[i] != '\0' && pszString[i] != ' ' && i < 100; i++ )
{
if( pszString[i] == '+' && i > 0 )
iPlus = i;
if( pszString[i] == '-' && i > 0 )
iPlus = i;
if( pszString[i] == 'i' )
iImagEnd = i;
}
if( iPlus > -1 && iImagEnd > -1 && iPlus < iImagEnd )
{
*pdfImag = CPLAtof(pszString + iPlus);
}
return;
}
/************************************************************************/
/* CPLOpenShared() */
/************************************************************************/
/**
* Open a shared file handle.
*
* Some operating systems have limits on the number of file handles that can
* be open at one time. This function attempts to maintain a registry of
* already open file handles, and reuse existing ones if the same file
* is requested by another part of the application.
*
* Note that access is only shared for access types "r", "rb", "r+" and
* "rb+". All others will just result in direct VSIOpen() calls. Keep in
* mind that a file is only reused if the file name is exactly the same.
* Different names referring to the same file will result in different
* handles.
*
* The VSIFOpen() or VSIFOpenL() function is used to actually open the file,
* when an existing file handle can't be shared.
*
* @param pszFilename the name of the file to open.
* @param pszAccess the normal fopen()/VSIFOpen() style access string.
* @param bLarge If TRUE VSIFOpenL() (for large files) will be used instead of
* VSIFOpen().
*
* @return a file handle or NULL if opening fails.
*/
FILE *CPLOpenShared( const char *pszFilename, const char *pszAccess,
int bLarge )
{
int i;
int bReuse;
CPLMutexHolderD( &hSharedFileMutex );
GIntBig nPID = CPLGetPID();
/* -------------------------------------------------------------------- */
/* Is there an existing file we can use? */
/* -------------------------------------------------------------------- */
bReuse = EQUAL(pszAccess,"rb") || EQUAL(pszAccess, "rb+");
for( i = 0; bReuse && i < nSharedFileCount; i++ )
{
if( strcmp(pasSharedFileList[i].pszFilename,pszFilename) == 0
&& !bLarge == !pasSharedFileList[i].bLarge
&& EQUAL(pasSharedFileList[i].pszAccess,pszAccess)
&& nPID == pasSharedFileListExtra[i].nPID)
{
pasSharedFileList[i].nRefCount++;
return pasSharedFileList[i].fp;
}
}
/* -------------------------------------------------------------------- */
/* Open the file. */
/* -------------------------------------------------------------------- */
FILE *fp;
if( bLarge )
fp = (FILE*) VSIFOpenL( pszFilename, pszAccess );
else
fp = VSIFOpen( pszFilename, pszAccess );
if( fp == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Add an entry to the list. */
/* -------------------------------------------------------------------- */
nSharedFileCount++;
pasSharedFileList = (CPLSharedFileInfo *)
CPLRealloc( (void *) pasSharedFileList,
sizeof(CPLSharedFileInfo) * nSharedFileCount );
pasSharedFileListExtra = (CPLSharedFileInfoExtra *)
CPLRealloc( (void *) pasSharedFileListExtra,
sizeof(CPLSharedFileInfoExtra) * nSharedFileCount );
pasSharedFileList[nSharedFileCount-1].fp = fp;
pasSharedFileList[nSharedFileCount-1].nRefCount = 1;
pasSharedFileList[nSharedFileCount-1].bLarge = bLarge;
pasSharedFileList[nSharedFileCount-1].pszFilename =CPLStrdup(pszFilename);
pasSharedFileList[nSharedFileCount-1].pszAccess = CPLStrdup(pszAccess);
pasSharedFileListExtra[nSharedFileCount-1].nPID = nPID;
return fp;
}
/************************************************************************/
/* CPLCloseShared() */
/************************************************************************/
/**
* Close shared file.
*
* Dereferences the indicated file handle, and closes it if the reference
* count has dropped to zero. A CPLError() is issued if the file is not
* in the shared file list.
*
* @param fp file handle from CPLOpenShared() to deaccess.
*/
void CPLCloseShared( FILE * fp )
{
CPLMutexHolderD( &hSharedFileMutex );
int i;
/* -------------------------------------------------------------------- */
/* Search for matching information. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nSharedFileCount && fp != pasSharedFileList[i].fp; i++ ){}
if( i == nSharedFileCount )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Unable to find file handle %p in CPLCloseShared().",
fp );
return;
}
/* -------------------------------------------------------------------- */
/* Dereference and return if there are still some references. */
/* -------------------------------------------------------------------- */
if( --pasSharedFileList[i].nRefCount > 0 )
return;
/* -------------------------------------------------------------------- */
/* Close the file, and remove the information. */
/* -------------------------------------------------------------------- */
if( pasSharedFileList[i].bLarge )
VSIFCloseL( (VSILFILE*) pasSharedFileList[i].fp );
else
VSIFClose( pasSharedFileList[i].fp );
CPLFree( pasSharedFileList[i].pszFilename );
CPLFree( pasSharedFileList[i].pszAccess );
nSharedFileCount --;
memmove( (void *) (pasSharedFileList + i),
(void *) (pasSharedFileList + nSharedFileCount),
sizeof(CPLSharedFileInfo) );
memmove( (void *) (pasSharedFileListExtra + i),
(void *) (pasSharedFileListExtra + nSharedFileCount),
sizeof(CPLSharedFileInfoExtra) );
if( nSharedFileCount == 0 )
{
CPLFree( (void *) pasSharedFileList );
pasSharedFileList = NULL;
CPLFree( (void *) pasSharedFileListExtra );
pasSharedFileListExtra = NULL;
}
}
/************************************************************************/
/* CPLCleanupSharedFileMutex() */
/************************************************************************/
void CPLCleanupSharedFileMutex()
{
if( hSharedFileMutex != NULL )
{
CPLDestroyMutex(hSharedFileMutex);
hSharedFileMutex = NULL;
}
}
/************************************************************************/
/* CPLGetSharedList() */
/************************************************************************/
/**
* Fetch list of open shared files.
*
* @param pnCount place to put the count of entries.
*
* @return the pointer to the first in the array of shared file info
* structures.
*/
CPLSharedFileInfo *CPLGetSharedList( int *pnCount )
{
if( pnCount != NULL )
*pnCount = nSharedFileCount;
return (CPLSharedFileInfo *) pasSharedFileList;
}
/************************************************************************/
/* CPLDumpSharedList() */
/************************************************************************/
/**
* Report open shared files.
*
* Dumps all open shared files to the indicated file handle. If the
* file handle is NULL information is sent via the CPLDebug() call.
*
* @param fp File handle to write to.
*/
void CPLDumpSharedList( FILE *fp )
{
int i;
if( nSharedFileCount > 0 )
{
if( fp == NULL )
CPLDebug( "CPL", "%d Shared files open.", nSharedFileCount );
else
fprintf( fp, "%d Shared files open.", nSharedFileCount );
}
for( i = 0; i < nSharedFileCount; i++ )
{
if( fp == NULL )
CPLDebug( "CPL",
"%2d %d %4s %s",
pasSharedFileList[i].nRefCount,
pasSharedFileList[i].bLarge,
pasSharedFileList[i].pszAccess,
pasSharedFileList[i].pszFilename );
else
fprintf( fp, "%2d %d %4s %s",
pasSharedFileList[i].nRefCount,
pasSharedFileList[i].bLarge,
pasSharedFileList[i].pszAccess,
pasSharedFileList[i].pszFilename );
}
}
/************************************************************************/
/* CPLUnlinkTree() */
/************************************************************************/
/**
* @return 0 on successful completion, -1 if function fails.
*/
int CPLUnlinkTree( const char *pszPath )
{
/* -------------------------------------------------------------------- */
/* First, ensure there is such a file. */
/* -------------------------------------------------------------------- */
VSIStatBufL sStatBuf;
if( VSIStatL( pszPath, &sStatBuf ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"It seems no file system object called '%s' exists.",
pszPath );
return -1;
}
/* -------------------------------------------------------------------- */
/* If it's a simple file, just delete it. */
/* -------------------------------------------------------------------- */
if( VSI_ISREG( sStatBuf.st_mode ) )
{
if( VSIUnlink( pszPath ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
pszPath );
return -1;
}
else
return 0;
}
/* -------------------------------------------------------------------- */
/* If it is a directory recurse then unlink the directory. */
/* -------------------------------------------------------------------- */
else if( VSI_ISDIR( sStatBuf.st_mode ) )
{
char **papszItems = CPLReadDir( pszPath );
int i;
for( i = 0; papszItems != NULL && papszItems[i] != NULL; i++ )
{
char *pszSubPath;
int nErr;
if( EQUAL(papszItems[i],".") || EQUAL(papszItems[i],"..") )
continue;
pszSubPath = CPLStrdup(
CPLFormFilename( pszPath, papszItems[i], NULL ) );
nErr = CPLUnlinkTree( pszSubPath );
CPLFree( pszSubPath );
if( nErr != 0 )
{
CSLDestroy( papszItems );
return nErr;
}
}
CSLDestroy( papszItems );
if( VSIRmdir( pszPath ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined, "Failed to unlink %s.",
pszPath );
return -1;
}
else
return 0;
}
/* -------------------------------------------------------------------- */
/* otherwise report an error. */
/* -------------------------------------------------------------------- */
else
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to unlink %s.\nUnrecognised filesystem object.",
pszPath );
return 1000;
}
}
/************************************************************************/
/* CPLCopyFile() */
/************************************************************************/
int CPLCopyFile( const char *pszNewPath, const char *pszOldPath )
{
VSILFILE *fpOld, *fpNew;
GByte *pabyBuffer;
size_t nBufferSize;
size_t nBytesRead;
int nRet = 0;
/* -------------------------------------------------------------------- */
/* Open old and new file. */
/* -------------------------------------------------------------------- */
fpOld = VSIFOpenL( pszOldPath, "rb" );
if( fpOld == NULL )
return -1;
fpNew = VSIFOpenL( pszNewPath, "wb" );
if( fpNew == NULL )
{
VSIFCloseL( fpOld );
return -1;
}
/* -------------------------------------------------------------------- */
/* Prepare buffer. */
/* -------------------------------------------------------------------- */
nBufferSize = 1024 * 1024;
pabyBuffer = (GByte *) CPLMalloc(nBufferSize);
/* -------------------------------------------------------------------- */
/* Copy file over till we run out of stuff. */
/* -------------------------------------------------------------------- */
do {
nBytesRead = VSIFReadL( pabyBuffer, 1, nBufferSize, fpOld );
if( long(nBytesRead) < 0 )
nRet = -1;
if( nRet == 0
&& VSIFWriteL( pabyBuffer, 1, nBytesRead, fpNew ) < nBytesRead )
nRet = -1;
} while( nRet == 0 && nBytesRead == nBufferSize );
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
VSIFCloseL( fpNew );
VSIFCloseL( fpOld );
CPLFree( pabyBuffer );
return nRet;
}
/************************************************************************/
/* CPLCopyTree() */
/************************************************************************/
int CPLCopyTree( const char *pszNewPath, const char *pszOldPath )
{
VSIStatBufL sStatBuf;
if( VSIStatL( pszOldPath, &sStatBuf ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"It seems no file system object called '%s' exists.",
pszOldPath );
return -1;
}
if( VSIStatL( pszNewPath, &sStatBuf ) == 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"It seems that a file system object called '%s' already exists.",
pszNewPath );
return -1;
}
if( VSI_ISDIR( sStatBuf.st_mode ) )
{
if( VSIMkdir( pszNewPath, 0755 ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Cannot create directory '%s'.",
pszNewPath );
return -1;
}
char **papszItems = CPLReadDir( pszOldPath );
int i;
for( i = 0; papszItems != NULL && papszItems[i] != NULL; i++ )
{
char *pszNewSubPath;
char *pszOldSubPath;
int nErr;
if( EQUAL(papszItems[i],".") || EQUAL(papszItems[i],"..") )
continue;
pszNewSubPath = CPLStrdup(
CPLFormFilename( pszNewPath, papszItems[i], NULL ) );
pszOldSubPath = CPLStrdup(
CPLFormFilename( pszOldPath, papszItems[i], NULL ) );
nErr = CPLCopyTree( pszNewSubPath, pszOldSubPath );
CPLFree( pszNewSubPath );
CPLFree( pszOldSubPath );
if( nErr != 0 )
{
CSLDestroy( papszItems );
return nErr;
}
}
CSLDestroy( papszItems );
return 0;
}
else if( VSI_ISREG( sStatBuf.st_mode ) )
{
return CPLCopyFile( pszNewPath, pszOldPath );
}
else
{
CPLError( CE_Failure, CPLE_AppDefined,
"Unrecognised filesystem object : '%s'.",
pszOldPath );
return -1;
}
}
/************************************************************************/
/* CPLMoveFile() */
/************************************************************************/
int CPLMoveFile( const char *pszNewPath, const char *pszOldPath )
{
if( VSIRename( pszOldPath, pszNewPath ) == 0 )
return 0;
int nRet = CPLCopyFile( pszNewPath, pszOldPath );
if( nRet == 0 )
VSIUnlink( pszOldPath );
return nRet;
}
/************************************************************************/
/* ==================================================================== */
/* CPLLocaleC */
/* ==================================================================== */
/************************************************************************/
#include <locale.h>
/************************************************************************/
/* CPLLocaleC() */
/************************************************************************/
CPLLocaleC::CPLLocaleC()
{
if( CSLTestBoolean(CPLGetConfigOption("GDAL_DISABLE_CPLLOCALEC","NO")) )
{
pszOldLocale = NULL;
}
else
{
pszOldLocale = CPLStrdup(CPLsetlocale(LC_NUMERIC,NULL));
if( EQUAL(pszOldLocale,"C")
|| EQUAL(pszOldLocale,"POSIX")
|| CPLsetlocale(LC_NUMERIC,"C") == NULL )
{
CPLFree( pszOldLocale );
pszOldLocale = NULL;
}
}
}
/************************************************************************/
/* ~CPLLocaleC() */
/************************************************************************/
CPLLocaleC::~CPLLocaleC()
{
if( pszOldLocale != NULL )
{
CPLsetlocale( LC_NUMERIC, pszOldLocale );
CPLFree( pszOldLocale );
}
}
/************************************************************************/
/* CPLsetlocale() */
/************************************************************************/
/**
* Prevents parallel executions of setlocale().
*
* Calling setlocale() concurrently from two or more threads is a
* potential data race. A mutex is used to provide a critical region so
* that only one thread at a time can be executing setlocale().
*
* The return should not be freed, and copied quickly as it may be invalidated
* by a following next call to CPLsetlocale().
*
* @param category See your compiler's documentation on setlocale.
* @param locale See your compiler's documentation on setlocale.
*
* @return See your compiler's documentation on setlocale.
*/
char* CPLsetlocale (int category, const char* locale)
{
CPLMutexHolder oHolder(&hSetLocaleMutex);
char* pszRet = setlocale(category, locale);
if( pszRet == NULL )
return pszRet;
return (char*)CPLSPrintf("%s", pszRet); /* to make it thread-locale storage */
}
/************************************************************************/
/* CPLCleanupSetlocaleMutex() */
/************************************************************************/
void CPLCleanupSetlocaleMutex(void)
{
if( hSetLocaleMutex != NULL )
CPLDestroyMutex(hSetLocaleMutex);
hSetLocaleMutex = NULL;
}
/************************************************************************/
/* CPLCheckForFile() */
/************************************************************************/
/**
* Check for file existance.
*
* The function checks if a named file exists in the filesystem, hopefully
* in an efficient fashion if a sibling file list is available. It exists
* primarily to do faster file checking for functions like GDAL open methods
* that get a list of files from the target directory.
*
* If the sibling file list exists (is not NULL) it is assumed to be a list
* of files in the same directory as the target file, and it will be checked
* (case insensitively) for a match. If a match is found, pszFilename is
* updated with the correct case and TRUE is returned.
*
* If papszSiblingFiles is NULL, a VSIStatL() is used to test for the files
* existance, and no case insensitive testing is done.
*
* @param pszFilename name of file to check for - filename case updated in some cases.
* @param papszSiblingFiles a list of files in the same directory as
* pszFilename if available, or NULL. This list should have no path components.
*
* @return TRUE if a match is found, or FALSE if not.
*/
int CPLCheckForFile( char *pszFilename, char **papszSiblingFiles )
{
/* -------------------------------------------------------------------- */
/* Fallback case if we don't have a sibling file list. */
/* -------------------------------------------------------------------- */
if( papszSiblingFiles == NULL )
{
VSIStatBufL sStatBuf;
return VSIStatL( pszFilename, &sStatBuf ) == 0;
}
/* -------------------------------------------------------------------- */
/* We have sibling files, compare the non-path filename portion */
/* of pszFilename too all entries. */
/* -------------------------------------------------------------------- */
CPLString osFileOnly = CPLGetFilename( pszFilename );
int i;
for( i = 0; papszSiblingFiles[i] != NULL; i++ )
{
if( EQUAL(papszSiblingFiles[i],osFileOnly) )
{
strcpy( pszFilename + strlen(pszFilename) - strlen(osFileOnly),
papszSiblingFiles[i] );
return TRUE;
}
}
return FALSE;
}
/************************************************************************/
/* Stub implementation of zip services if we don't have libz. */
/************************************************************************/
#if !defined(HAVE_LIBZ)
void *CPLCreateZip( const char *pszZipFilename, char **papszOptions )
{
CPLError( CE_Failure, CPLE_NotSupported,
"This GDAL/OGR build does not include zlib and zip services." );
return NULL;
}
CPLErr CPLCreateFileInZip( void *hZip, const char *pszFilename,
char **papszOptions )
{
return CE_Failure;
}
CPLErr CPLWriteFileInZip( void *hZip, const void *pBuffer, int nBufferSize )
{
return CE_Failure;
}
CPLErr CPLCloseFileInZip( void *hZip )
{
return CE_Failure;
}
CPLErr CPLCloseZip( void *hZip )
{
return CE_Failure;
}
void* CPLZLibDeflate( const void* ptr, size_t nBytes, int nLevel,
void* outptr, size_t nOutAvailableBytes,
size_t* pnOutBytes )
{
if( pnOutBytes != NULL )
*pnOutBytes = 0;
return NULL;
}
void* CPLZLibInflate( const void* ptr, size_t nBytes,
void* outptr, size_t nOutAvailableBytes,
size_t* pnOutBytes )
{
if( pnOutBytes != NULL )
*pnOutBytes = 0;
return NULL;
}
#endif /* !defined(HAVE_LIBZ) */