00001 /****************************************************************************** 00002 * $Id: cpl_conv_cpp-source.html,v 1.13 2002/12/21 19:13:12 warmerda Exp $ 00003 * 00004 * Project: CPL - Common Portability Library 00005 * Purpose: Convenience functions. 00006 * Author: Frank Warmerdam, warmerda@home.com 00007 * 00008 ****************************************************************************** 00009 * Copyright (c) 1998, Frank Warmerdam 00010 * 00011 * Permission is hereby granted, free of charge, to any person obtaining a 00012 * copy of this software and associated documentation files (the "Software"), 00013 * to deal in the Software without restriction, including without limitation 00014 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00015 * and/or sell copies of the Software, and to permit persons to whom the 00016 * Software is furnished to do so, subject to the following conditions: 00017 * 00018 * The above copyright notice and this permission notice shall be included 00019 * in all copies or substantial portions of the Software. 00020 * 00021 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00022 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00023 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00024 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00025 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00026 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00027 * DEALINGS IN THE SOFTWARE. 00028 ****************************************************************************** 00029 * 00030 * $Log: cpl_conv_cpp-source.html,v $ 00030 * Revision 1.13 2002/12/21 19:13:12 warmerda 00030 * updated 00030 * 00031 * Revision 1.18 2002/12/18 20:22:53 warmerda 00032 * fiddle with roundoff issues in DecToDMS 00033 * 00034 * Revision 1.17 2002/12/10 19:46:04 warmerda 00035 * modified CPLReadLine() to seek back if it overreads past a CR or LF 00036 * 00037 * Revision 1.16 2002/12/09 18:52:51 warmerda 00038 * added DMS conversion 00039 * 00040 * Revision 1.15 2002/03/05 14:26:57 warmerda 00041 * expanded tabs 00042 * 00043 * Revision 1.14 2001/12/12 17:06:57 warmerda 00044 * added CPLStat 00045 * 00046 * Revision 1.13 2001/07/18 04:00:49 warmerda 00047 * added CPL_CVSID 00048 * 00049 * Revision 1.12 2001/03/09 03:19:24 danmo 00050 * Set pszRLBuffer=NULL after freeing it to avoid reallocating an invalid ptr 00051 * 00052 * Revision 1.11 2001/03/05 03:37:19 warmerda 00053 * Improve support for recovering CPLReadLine() working buffer. 00054 * 00055 * Revision 1.10 2001/01/19 21:16:41 warmerda 00056 * expanded tabs 00057 * 00058 * Revision 1.9 2000/04/17 15:56:11 warmerda 00059 * make configuration tests always happen 00060 * 00061 * Revision 1.8 2000/04/05 21:02:47 warmerda 00062 * Added CPLVerifyConfiguration() 00063 * 00064 * Revision 1.7 1999/08/27 12:55:39 danmo 00065 * Support 0 bytes allocations in CPLRealloc() 00066 * 00067 * Revision 1.6 1999/06/25 04:38:03 warmerda 00068 * Fixed CPLReadLine() to work for long lines. 00069 * 00070 * Revision 1.5 1999/05/20 02:54:37 warmerda 00071 * Added API documentation 00072 * 00073 * Revision 1.4 1999/01/02 20:29:53 warmerda 00074 * Allow zero length allocations 00075 * 00076 * Revision 1.3 1998/12/15 19:01:07 warmerda 00077 * Added CPLReadLine(). 00078 * 00079 * Revision 1.2 1998/12/03 18:30:04 warmerda 00080 * Use CPLError() instead of GPSError(). 00081 * 00082 * Revision 1.1 1998/12/02 19:33:23 warmerda 00083 * New 00084 * 00085 */ 00086 00087 #include "cpl_conv.h" 00088 00089 CPL_CVSID("$Id: cpl_conv_cpp-source.html,v 1.13 2002/12/21 19:13:12 warmerda Exp $"); 00090 00091 /************************************************************************/ 00092 /* CPLCalloc() */ 00093 /************************************************************************/ 00094 00112 void *CPLCalloc( size_t nCount, size_t nSize ) 00113 00114 { 00115 void *pReturn; 00116 00117 if( nSize * nCount == 0 ) 00118 return NULL; 00119 00120 pReturn = VSICalloc( nCount, nSize ); 00121 if( pReturn == NULL ) 00122 { 00123 CPLError( CE_Fatal, CPLE_OutOfMemory, 00124 "CPLCalloc(): Out of memory allocating %d bytes.\n", 00125 nSize * nCount ); 00126 } 00127 00128 return pReturn; 00129 } 00130 00131 /************************************************************************/ 00132 /* CPLMalloc() */ 00133 /************************************************************************/ 00134 00150 void *CPLMalloc( size_t nSize ) 00151 00152 { 00153 void *pReturn; 00154 00155 CPLVerifyConfiguration(); 00156 00157 if( nSize == 0 ) 00158 return NULL; 00159 00160 pReturn = VSIMalloc( nSize ); 00161 if( pReturn == NULL ) 00162 { 00163 CPLError( CE_Fatal, CPLE_OutOfMemory, 00164 "CPLMalloc(): Out of memory allocating %d bytes.\n", 00165 nSize ); 00166 } 00167 00168 return pReturn; 00169 } 00170 00171 /************************************************************************/ 00172 /* CPLRealloc() */ 00173 /************************************************************************/ 00174 00195 void * CPLRealloc( void * pData, size_t nNewSize ) 00196 00197 { 00198 void *pReturn; 00199 00200 if ( nNewSize == 0 ) 00201 { 00202 VSIFree(pData); 00203 return NULL; 00204 } 00205 00206 if( pData == NULL ) 00207 pReturn = VSIMalloc( nNewSize ); 00208 else 00209 pReturn = VSIRealloc( pData, nNewSize ); 00210 00211 if( pReturn == NULL ) 00212 { 00213 CPLError( CE_Fatal, CPLE_OutOfMemory, 00214 "CPLRealloc(): Out of memory allocating %d bytes.\n", 00215 nNewSize ); 00216 } 00217 00218 return pReturn; 00219 } 00220 00221 /************************************************************************/ 00222 /* CPLStrdup() */ 00223 /************************************************************************/ 00224 00243 char *CPLStrdup( const char * pszString ) 00244 00245 { 00246 char *pszReturn; 00247 00248 if( pszString == NULL ) 00249 pszString = ""; 00250 00251 pszReturn = VSIStrdup( pszString ); 00252 00253 if( pszReturn == NULL ) 00254 { 00255 CPLError( CE_Fatal, CPLE_OutOfMemory, 00256 "CPLStrdup(): Out of memory allocating %d bytes.\n", 00257 strlen(pszString) ); 00258 00259 } 00260 00261 return( pszReturn ); 00262 } 00263 00264 /************************************************************************/ 00265 /* CPLReadLine() */ 00266 /************************************************************************/ 00267 00289 const char *CPLReadLine( FILE * fp ) 00290 00291 { 00292 static char *pszRLBuffer = NULL; 00293 static int nRLBufferSize = 0; 00294 int nLength, nReadSoFar = 0, nStripped = 0, i; 00295 00296 /* -------------------------------------------------------------------- */ 00297 /* Cleanup case. */ 00298 /* -------------------------------------------------------------------- */ 00299 if( fp == NULL ) 00300 { 00301 CPLFree( pszRLBuffer ); 00302 pszRLBuffer = NULL; 00303 nRLBufferSize = 0; 00304 return NULL; 00305 } 00306 00307 /* -------------------------------------------------------------------- */ 00308 /* Loop reading chunks of the line till we get to the end of */ 00309 /* the line. */ 00310 /* -------------------------------------------------------------------- */ 00311 do { 00312 /* -------------------------------------------------------------------- */ 00313 /* Grow the working buffer if we have it nearly full. Fail out */ 00314 /* of read line if we can't reallocate it big enough (for */ 00315 /* instance for a _very large_ file with no newlines). */ 00316 /* -------------------------------------------------------------------- */ 00317 if( nRLBufferSize-nReadSoFar < 128 ) 00318 { 00319 nRLBufferSize = nRLBufferSize*2 + 128; 00320 pszRLBuffer = (char *) VSIRealloc(pszRLBuffer, nRLBufferSize); 00321 if( pszRLBuffer == NULL ) 00322 { 00323 nRLBufferSize = 0; 00324 return NULL; 00325 } 00326 } 00327 00328 /* -------------------------------------------------------------------- */ 00329 /* Do the actual read. */ 00330 /* -------------------------------------------------------------------- */ 00331 if( VSIFGets( pszRLBuffer+nReadSoFar, nRLBufferSize-nReadSoFar, fp ) 00332 == NULL ) 00333 { 00334 CPLFree( pszRLBuffer ); 00335 pszRLBuffer = NULL; 00336 nRLBufferSize = 0; 00337 00338 return NULL; 00339 } 00340 00341 nReadSoFar = strlen(pszRLBuffer); 00342 00343 } while( nReadSoFar == nRLBufferSize - 1 00344 && pszRLBuffer[nRLBufferSize-2] != 13 00345 && pszRLBuffer[nRLBufferSize-2] != 10 ); 00346 00347 /* -------------------------------------------------------------------- */ 00348 /* Clear CR and LF off the end. */ 00349 /* -------------------------------------------------------------------- */ 00350 nLength = strlen(pszRLBuffer); 00351 if( nLength > 0 00352 && (pszRLBuffer[nLength-1] == 10 || pszRLBuffer[nLength-1] == 13) ) 00353 { 00354 pszRLBuffer[--nLength] = '\0'; 00355 nStripped++; 00356 } 00357 00358 if( nLength > 0 00359 && (pszRLBuffer[nLength-1] == 10 || pszRLBuffer[nLength-1] == 13) ) 00360 { 00361 pszRLBuffer[--nLength] = '\0'; 00362 nStripped++; 00363 } 00364 00365 /* -------------------------------------------------------------------- */ 00366 /* Check that there aren't any extra CR or LF characters */ 00367 /* embedded in what is left. I have encountered files with */ 00368 /* embedded CR (13) characters that should have acted as line */ 00369 /* terminators but got sucked up by VSIFGetc(). */ 00370 /* -------------------------------------------------------------------- */ 00371 for( i = 0; i < nLength; i++ ) 00372 { 00373 if( pszRLBuffer[i] == 10 || pszRLBuffer[i] == 13 ) 00374 { 00375 /* we need to chop off the buffer here, and seek the input back 00376 to after the character that should have been the line 00377 terminator. */ 00378 VSIFSeek( fp, (i+1) - (nLength+nStripped), SEEK_CUR ); 00379 pszRLBuffer[i] = '\0'; 00380 } 00381 } 00382 00383 return( pszRLBuffer ); 00384 } 00385 00386 /************************************************************************/ 00387 /* CPLVerifyConfiguration() */ 00388 /************************************************************************/ 00389 00390 void CPLVerifyConfiguration() 00391 00392 { 00393 /* -------------------------------------------------------------------- */ 00394 /* Verify data types. */ 00395 /* -------------------------------------------------------------------- */ 00396 CPLAssert( sizeof(GInt32) == 4 ); 00397 CPLAssert( sizeof(GInt16) == 2 ); 00398 CPLAssert( sizeof(GByte) == 1 ); 00399 00400 if( sizeof(GInt32) != 4 ) 00401 CPLError( CE_Fatal, CPLE_AppDefined, 00402 "sizeof(GInt32) == %d ... yow!\n", 00403 sizeof(GInt32) ); 00404 00405 /* -------------------------------------------------------------------- */ 00406 /* Verify byte order */ 00407 /* -------------------------------------------------------------------- */ 00408 GInt32 nTest; 00409 00410 nTest = 1; 00411 00412 #ifdef CPL_LSB 00413 if( ((GByte *) &nTest)[0] != 1 ) 00414 #endif 00415 #ifdef CPL_MSB 00416 if( ((GByte *) &nTest)[3] != 1 ) 00417 #endif 00418 CPLError( CE_Fatal, CPLE_AppDefined, 00419 "CPLVerifyConfiguration(): byte order set wrong.\n" ); 00420 } 00421 00422 /************************************************************************/ 00423 /* CPLStat() */ 00424 /* */ 00425 /* Same as VSIStat() except it works on "C:" as if it were */ 00426 /* "C:\". */ 00427 /************************************************************************/ 00428 00429 int CPLStat( const char *pszPath, VSIStatBuf *psStatBuf ) 00430 00431 { 00432 if( strlen(pszPath) == 2 && pszPath[1] == ':' ) 00433 { 00434 char szAltPath[10]; 00435 00436 strcpy( szAltPath, pszPath ); 00437 strcat( szAltPath, "\\" ); 00438 return VSIStat( szAltPath, psStatBuf ); 00439 } 00440 else 00441 return VSIStat( pszPath, psStatBuf ); 00442 } 00443 00444 /************************************************************************/ 00445 /* proj_strtod() */ 00446 /************************************************************************/ 00447 static double 00448 proj_strtod(char *nptr, char **endptr) 00449 00450 { 00451 char c, *cp = nptr; 00452 double result; 00453 00454 /* 00455 * Scan for characters which cause problems with VC++ strtod() 00456 */ 00457 while ((c = *cp) != '\0') { 00458 if (c == 'd' || c == 'D') { 00459 00460 /* 00461 * Found one, so NUL it out, call strtod(), 00462 * then restore it and return 00463 */ 00464 *cp = '\0'; 00465 result = strtod(nptr, endptr); 00466 *cp = c; 00467 return result; 00468 } 00469 ++cp; 00470 } 00471 00472 /* no offending characters, just handle normally */ 00473 00474 return strtod(nptr, endptr); 00475 } 00476 00477 /************************************************************************/ 00478 /* CPLDMSToDec() */ 00479 /************************************************************************/ 00480 00481 static const char*sym = "NnEeSsWw"; 00482 static const double vm[] = { 1.0, 0.0166666666667, 0.00027777778 }; 00483 00484 double CPLDMSToDec( const char *is ) 00485 00486 { 00487 int sign, n, nl; 00488 char *p, *s, work[64]; 00489 double v, tv; 00490 00491 /* copy sting into work space */ 00492 while (isspace(sign = *is)) ++is; 00493 for (n = sizeof(work), s = work, p = (char *)is; isgraph(*p) && --n ; ) 00494 *s++ = *p++; 00495 *s = '\0'; 00496 /* it is possible that a really odd input (like lots of leading 00497 zeros) could be truncated in copying into work. But ... */ 00498 sign = *(s = work); 00499 if (sign == '+' || sign == '-') s++; 00500 else sign = '+'; 00501 for (v = 0., nl = 0 ; nl < 3 ; nl = n + 1 ) { 00502 if (!(isdigit(*s) || *s == '.')) break; 00503 if ((tv = proj_strtod(s, &s)) == HUGE_VAL) 00504 return tv; 00505 switch (*s) { 00506 case 'D': case 'd': 00507 n = 0; break; 00508 case '\'': 00509 n = 1; break; 00510 case '"': 00511 n = 2; break; 00512 case 'r': case 'R': 00513 if (nl) { 00514 return 0.0; 00515 } 00516 ++s; 00517 v = tv; 00518 goto skip; 00519 default: 00520 v += tv * vm[nl]; 00521 skip: n = 4; 00522 continue; 00523 } 00524 if (n < nl) { 00525 return 0.0; 00526 } 00527 v += tv * vm[n]; 00528 ++s; 00529 } 00530 /* postfix sign */ 00531 if (*s && (p = strchr(sym, *s))) { 00532 sign = (p - sym) >= 4 ? '-' : '+'; 00533 ++s; 00534 } 00535 if (sign == '-') 00536 v = -v; 00537 00538 return v; 00539 } 00540 00541 00542 /************************************************************************/ 00543 /* CPLDecToDMS() */ 00544 /* */ 00545 /* Translate a decimal degrees value to a DMS string with */ 00546 /* hemisphere. */ 00547 /************************************************************************/ 00548 00549 const char *CPLDecToDMS( double dfAngle, const char * pszAxis, 00550 int nPrecision ) 00551 00552 { 00553 int nDegrees, nMinutes; 00554 double dfSeconds, dfABSAngle, dfEpsilon; 00555 char szFormat[30]; 00556 static char szBuffer[50]; 00557 const char *pszHemisphere; 00558 00559 dfEpsilon = (0.5/3600.0) * pow(0.1,nPrecision); 00560 00561 dfABSAngle = ABS(dfAngle) + dfEpsilon; 00562 00563 nDegrees = (int) dfABSAngle; 00564 nMinutes = (int) ((dfABSAngle - nDegrees) * 60); 00565 dfSeconds = dfABSAngle * 3600 - nDegrees*3600 - nMinutes*60; 00566 00567 if( dfSeconds > dfEpsilon * 3600.0 ) 00568 dfSeconds -= dfEpsilon * 3600.0; 00569 00570 if( EQUAL(pszAxis,"Long") && dfAngle < 0.0 ) 00571 pszHemisphere = "W"; 00572 else if( EQUAL(pszAxis,"Long") ) 00573 pszHemisphere = "E"; 00574 else if( dfAngle < 0.0 ) 00575 pszHemisphere = "S"; 00576 else 00577 pszHemisphere = "N"; 00578 00579 sprintf( szFormat, "%%3dd%%2d\'%%.%df\"%s", nPrecision, pszHemisphere ); 00580 sprintf( szBuffer, szFormat, nDegrees, nMinutes, dfSeconds ); 00581 00582 return( szBuffer ); 00583 } 00584