1 : /******************************************************************************
2 : * $Id: ogrutils.cpp 19722 2010-05-15 11:35:37Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Utility functions for OGR classes, including some related to
6 : * parsing well known text format vectors.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include <ctype.h>
32 :
33 : #include "ogr_geometry.h"
34 : #include "ogr_p.h"
35 :
36 : #ifdef OGR_ENABLED
37 : # include "ogrsf_frmts.h"
38 : #endif /* OGR_ENABLED */
39 :
40 : CPL_CVSID("$Id: ogrutils.cpp 19722 2010-05-15 11:35:37Z rouault $");
41 :
42 : /************************************************************************/
43 : /* OGRFormatDouble() */
44 : /************************************************************************/
45 :
46 9783 : void OGRFormatDouble( char *pszBuffer, int nBufferLen, double dfVal, char chDecimalSep, int nPrecision )
47 : {
48 : int i;
49 9783 : int bHasTruncated = FALSE;
50 : char szFormat[16];
51 9783 : sprintf(szFormat, "%%.%df", nPrecision);
52 :
53 9783 : int ret = snprintf(pszBuffer, nBufferLen, szFormat, dfVal);
54 : /* Windows CRT doesn't conform with C99 and return -1 when buffer is truncated */
55 9783 : if (ret >= nBufferLen || ret == -1)
56 2 : return;
57 :
58 2 : while(TRUE)
59 : {
60 9783 : i = 0;
61 224716 : while( pszBuffer[i] != '\0' )
62 : {
63 205150 : if ((pszBuffer[i] == '.' || pszBuffer[i] == ',') && chDecimalSep != '\0')
64 9783 : pszBuffer[i] = chDecimalSep;
65 205150 : i++;
66 : }
67 :
68 : /* -------------------------------------------------------------------- */
69 : /* Trim trailing 00000x's as they are likely roundoff error. */
70 : /* -------------------------------------------------------------------- */
71 9783 : if( i > 10)
72 : {
73 17796 : if (/* && pszBuffer[i-1] == '1' &&*/
74 : pszBuffer[i-2] == '0'
75 : && pszBuffer[i-3] == '0'
76 : && pszBuffer[i-4] == '0'
77 : && pszBuffer[i-5] == '0'
78 : && pszBuffer[i-6] == '0' )
79 : {
80 8389 : pszBuffer[--i] = '\0';
81 : }
82 1018 : else if( /* pszBuffer[i-1] == '1' */
83 : /* && pszBuffer[i-2] == '0' && */
84 : pszBuffer[i-3] == '0'
85 : && pszBuffer[i-4] == '0'
86 : && pszBuffer[i-5] == '0'
87 : && pszBuffer[i-6] == '0'
88 : && pszBuffer[i-7] == '0'
89 : && pszBuffer[i-8] == '0'
90 : && pszBuffer[i-9] == '0')
91 : {
92 0 : pszBuffer[--i] = '\0';
93 0 : pszBuffer[--i] = '\0';
94 : }
95 : }
96 :
97 : /* -------------------------------------------------------------------- */
98 : /* Trim trailing zeros. */
99 : /* -------------------------------------------------------------------- */
100 115309 : while( i > 2 && pszBuffer[i-1] == '0' && pszBuffer[i-2] != '.' )
101 : {
102 95743 : pszBuffer[--i] = '\0';
103 : }
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Detect trailing 99999X's as they are likely roundoff error. */
107 : /* -------------------------------------------------------------------- */
108 9783 : if( !bHasTruncated &&
109 : i > 10 &&
110 : nPrecision >= 15)
111 : {
112 4072 : if (/*pszBuffer[i-1] == '9' && */
113 : pszBuffer[i-2] == '9'
114 : && pszBuffer[i-3] == '9'
115 : && pszBuffer[i-4] == '9'
116 : && pszBuffer[i-5] == '9'
117 : && pszBuffer[i-6] == '9' )
118 : {
119 2 : snprintf(pszBuffer, nBufferLen, "%.10f", dfVal);
120 2 : bHasTruncated = TRUE;
121 2 : continue;
122 : }
123 4070 : else if (/*pszBuffer[i-1] == '9' && */
124 : /*pszBuffer[i-2] == '9' && */
125 : pszBuffer[i-3] == '9'
126 : && pszBuffer[i-4] == '9'
127 : && pszBuffer[i-5] == '9'
128 : && pszBuffer[i-6] == '9'
129 : && pszBuffer[i-7] == '9'
130 : && pszBuffer[i-8] == '9'
131 : && pszBuffer[i-9] == '9')
132 : {
133 0 : snprintf(pszBuffer, nBufferLen, "%.10f", dfVal);
134 0 : bHasTruncated = TRUE;
135 0 : continue;
136 : }
137 : }
138 :
139 9781 : break;
140 : }
141 :
142 : }
143 :
144 : /************************************************************************/
145 : /* OGRMakeWktCoordinate() */
146 : /* */
147 : /* Format a well known text coordinate, trying to keep the */
148 : /* ASCII representation compact, but accurate. These rules */
149 : /* will have to tighten up in the future. */
150 : /* */
151 : /* Currently a new point should require no more than 64 */
152 : /* characters barring the X or Y value being extremely large. */
153 : /************************************************************************/
154 :
155 : void OGRMakeWktCoordinate( char *pszTarget, double x, double y, double z,
156 5678 : int nDimension )
157 :
158 : {
159 5678 : const size_t bufSize = 75;
160 5678 : const size_t maxTargetSize = 75; /* Assumed max length of the target buffer. */
161 :
162 : char szX[bufSize];
163 : char szY[bufSize];
164 : char szZ[bufSize];
165 :
166 5678 : szZ[0] = '\0';
167 :
168 : int nLenX, nLenY;
169 :
170 6773 : if( x == (int) x && y == (int) y )
171 : {
172 1095 : snprintf( szX, bufSize, "%d", (int) x );
173 1095 : snprintf( szY, bufSize, "%d", (int) y );
174 : }
175 : else
176 : {
177 4583 : OGRFormatDouble( szX, bufSize, x, '.' );
178 4583 : OGRFormatDouble( szY, bufSize, y, '.' );
179 : }
180 :
181 5678 : nLenX = strlen(szX);
182 5678 : nLenY = strlen(szY);
183 :
184 5678 : if( nDimension == 3 )
185 : {
186 652 : if( z == (int) z )
187 : {
188 645 : snprintf( szZ, bufSize, "%d", (int) z );
189 : }
190 : else
191 : {
192 7 : OGRFormatDouble( szZ, bufSize, z, '.' );
193 : }
194 : }
195 :
196 5678 : if( nLenX + 1 + nLenY + ((nDimension == 3) ? (1 + strlen(szZ)) : 0) >= maxTargetSize )
197 : {
198 : #ifdef DEBUG
199 : CPLDebug( "OGR",
200 : "Yow! Got this big result in OGRMakeWktCoordinate()\n"
201 : "%s %s %s",
202 1 : szX, szY, szZ );
203 : #endif
204 1 : if( nDimension == 3 )
205 1 : strcpy( pszTarget, "0 0 0");
206 : else
207 0 : strcpy( pszTarget, "0 0");
208 : }
209 : else
210 : {
211 5677 : memcpy( pszTarget, szX, nLenX );
212 5677 : pszTarget[nLenX] = ' ';
213 5677 : memcpy( pszTarget + nLenX + 1, szY, nLenY );
214 5677 : if (nDimension == 3)
215 : {
216 651 : pszTarget[nLenX + 1 + nLenY] = ' ';
217 651 : strcpy( pszTarget + nLenX + 1 + nLenY + 1, szZ );
218 : }
219 : else
220 : {
221 5026 : pszTarget[nLenX + 1 + nLenY] = '\0';
222 : }
223 : }
224 5678 : }
225 :
226 : /************************************************************************/
227 : /* OGRWktReadToken() */
228 : /* */
229 : /* Read one token or delimeter and put into token buffer. Pre */
230 : /* and post white space is swallowed. */
231 : /************************************************************************/
232 :
233 143412 : const char *OGRWktReadToken( const char * pszInput, char * pszToken )
234 :
235 : {
236 143412 : if( pszInput == NULL )
237 0 : return NULL;
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Swallow pre-white space. */
241 : /* -------------------------------------------------------------------- */
242 286825 : while( *pszInput == ' ' || *pszInput == '\t' )
243 1 : pszInput++;
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* If this is a delimeter, read just one character. */
247 : /* -------------------------------------------------------------------- */
248 181857 : if( *pszInput == '(' || *pszInput == ')' || *pszInput == ',' )
249 : {
250 38445 : pszToken[0] = *pszInput;
251 38445 : pszToken[1] = '\0';
252 :
253 38445 : pszInput++;
254 : }
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Or if it alpha numeric read till we reach non-alpha numeric */
258 : /* text. */
259 : /* -------------------------------------------------------------------- */
260 : else
261 : {
262 104967 : int iChar = 0;
263 :
264 940019 : while( iChar < OGR_WKT_TOKEN_MAX-1
265 : && ((*pszInput >= 'a' && *pszInput <= 'z')
266 : || (*pszInput >= 'A' && *pszInput <= 'Z')
267 : || (*pszInput >= '0' && *pszInput <= '9')
268 : || *pszInput == '.'
269 : || *pszInput == '+'
270 : || *pszInput == '-') )
271 : {
272 730085 : pszToken[iChar++] = *(pszInput++);
273 : }
274 :
275 104967 : pszToken[iChar++] = '\0';
276 : }
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* Eat any trailing white space. */
280 : /* -------------------------------------------------------------------- */
281 340006 : while( *pszInput == ' ' || *pszInput == '\t' )
282 53182 : pszInput++;
283 :
284 143412 : return( pszInput );
285 : }
286 :
287 : /************************************************************************/
288 : /* OGRWktReadPoints() */
289 : /* */
290 : /* Read a point string. The point list must be contained in */
291 : /* brackets and each point pair separated by a comma. */
292 : /************************************************************************/
293 :
294 : const char * OGRWktReadPoints( const char * pszInput,
295 : OGRRawPoint ** ppaoPoints, double **ppadfZ,
296 : int * pnMaxPoints,
297 15901 : int * pnPointsRead )
298 :
299 : {
300 15901 : const char *pszOrigInput = pszInput;
301 15901 : *pnPointsRead = 0;
302 :
303 15901 : if( pszInput == NULL )
304 0 : return NULL;
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* Eat any leading white space. */
308 : /* -------------------------------------------------------------------- */
309 31802 : while( *pszInput == ' ' || *pszInput == '\t' )
310 0 : pszInput++;
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* If this isn't an opening bracket then we have a problem! */
314 : /* -------------------------------------------------------------------- */
315 15901 : if( *pszInput != '(' )
316 : {
317 : CPLDebug( "OGR",
318 : "Expected '(', but got %s in OGRWktReadPoints().\n",
319 39 : pszInput );
320 :
321 39 : return pszInput;
322 : }
323 :
324 15862 : pszInput++;
325 :
326 : /* ==================================================================== */
327 : /* This loop reads a single point. It will continue till we */
328 : /* run out of well formed points, or a closing bracket is */
329 : /* encountered. */
330 : /* ==================================================================== */
331 : char szDelim[OGR_WKT_TOKEN_MAX];
332 :
333 19950 : do {
334 : /* -------------------------------------------------------------------- */
335 : /* Read the X and Y values, verify they are numeric. */
336 : /* -------------------------------------------------------------------- */
337 : char szTokenX[OGR_WKT_TOKEN_MAX];
338 : char szTokenY[OGR_WKT_TOKEN_MAX];
339 :
340 19998 : pszInput = OGRWktReadToken( pszInput, szTokenX );
341 19998 : pszInput = OGRWktReadToken( pszInput, szTokenY );
342 :
343 19998 : if( (!isdigit(szTokenX[0]) && szTokenX[0] != '-' && szTokenX[0] != '.' )
344 : || (!isdigit(szTokenY[0]) && szTokenY[0] != '-' && szTokenY[0] != '.') )
345 38 : return NULL;
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* Do we need to grow the point list to hold this point? */
349 : /* -------------------------------------------------------------------- */
350 19960 : if( *pnPointsRead == *pnMaxPoints )
351 : {
352 15682 : *pnMaxPoints = *pnMaxPoints * 2 + 10;
353 : *ppaoPoints = (OGRRawPoint *)
354 15682 : CPLRealloc(*ppaoPoints, sizeof(OGRRawPoint) * *pnMaxPoints);
355 :
356 15682 : if( *ppadfZ != NULL )
357 : {
358 : *ppadfZ = (double *)
359 53 : CPLRealloc(*ppadfZ, sizeof(double) * *pnMaxPoints);
360 : }
361 : }
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Add point to list. */
365 : /* -------------------------------------------------------------------- */
366 19960 : (*ppaoPoints)[*pnPointsRead].x = CPLAtof(szTokenX);
367 19960 : (*ppaoPoints)[*pnPointsRead].y = CPLAtof(szTokenY);
368 :
369 : /* -------------------------------------------------------------------- */
370 : /* Do we have a Z coordinate? */
371 : /* -------------------------------------------------------------------- */
372 19960 : pszInput = OGRWktReadToken( pszInput, szDelim );
373 :
374 19960 : if( isdigit(szDelim[0]) || szDelim[0] == '-' || szDelim[0] == '.' )
375 : {
376 16421 : if( *ppadfZ == NULL )
377 : {
378 14864 : *ppadfZ = (double *) CPLCalloc(sizeof(double),*pnMaxPoints);
379 : }
380 :
381 16421 : (*ppadfZ)[*pnPointsRead] = CPLAtof(szDelim);
382 :
383 16421 : pszInput = OGRWktReadToken( pszInput, szDelim );
384 : }
385 :
386 19960 : (*pnPointsRead)++;
387 :
388 : /* -------------------------------------------------------------------- */
389 : /* Do we have a M coordinate? */
390 : /* If we do, just skip it. */
391 : /* -------------------------------------------------------------------- */
392 19960 : if( isdigit(szDelim[0]) || szDelim[0] == '-' || szDelim[0] == '.' )
393 : {
394 54 : pszInput = OGRWktReadToken( pszInput, szDelim );
395 : }
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Read next delimeter ... it should be a comma if there are */
399 : /* more points. */
400 : /* -------------------------------------------------------------------- */
401 19960 : if( szDelim[0] != ')' && szDelim[0] != ',' )
402 : {
403 : CPLDebug( "OGR",
404 : "Corrupt input in OGRWktReadPoints()\n"
405 : "Got `%s' when expecting `,' or `)', near `%s' in %s.\n",
406 10 : szDelim, pszInput, pszOrigInput );
407 10 : return NULL;
408 : }
409 :
410 : } while( szDelim[0] == ',' );
411 :
412 15814 : return pszInput;
413 : }
414 :
415 : /************************************************************************/
416 : /* OGRMalloc() */
417 : /* */
418 : /* Cover for CPLMalloc() */
419 : /************************************************************************/
420 :
421 0 : void *OGRMalloc( size_t size )
422 :
423 : {
424 0 : return CPLMalloc( size );
425 : }
426 :
427 : /************************************************************************/
428 : /* OGRCalloc() */
429 : /* */
430 : /* Cover for CPLCalloc() */
431 : /************************************************************************/
432 :
433 5267 : void * OGRCalloc( size_t count, size_t size )
434 :
435 : {
436 5267 : return CPLCalloc( count, size );
437 : }
438 :
439 : /************************************************************************/
440 : /* OGRRealloc() */
441 : /* */
442 : /* Cover for CPLRealloc() */
443 : /************************************************************************/
444 :
445 45982 : void *OGRRealloc( void * pOld, size_t size )
446 :
447 : {
448 45982 : return CPLRealloc( pOld, size );
449 : }
450 :
451 : /************************************************************************/
452 : /* OGRFree() */
453 : /* */
454 : /* Cover for CPLFree(). */
455 : /************************************************************************/
456 :
457 30857 : void OGRFree( void * pMemory )
458 :
459 : {
460 30857 : CPLFree( pMemory );
461 30857 : }
462 :
463 : /**
464 : * General utility option processing.
465 : *
466 : * This function is intended to provide a variety of generic commandline
467 : * options for all OGR commandline utilities. It takes care of the following
468 : * commandline options:
469 : *
470 : * --formats: report all format drivers configured.
471 : * --optfile filename: expand an option file into the argument list.
472 : * --config key value: set system configuration option.
473 : * --debug [on/off/value]: set debug level.
474 : * --help-general: report detailed help on general options.
475 : *
476 : * The argument array is replaced "in place" and should be freed with
477 : * CSLDestroy() when no longer needed. The typical usage looks something
478 : * like the following. Note that the formats should be registered so that
479 : * the --formats option will work properly.
480 : *
481 : * int main( int argc, char ** argv )
482 : * {
483 : * OGRAllRegister();
484 : *
485 : * argc = OGRGeneralCmdLineProcessor( argc, &argv, 0 );
486 : * if( argc < 1 )
487 : * exit( -argc );
488 : *
489 : * @param nArgc number of values in the argument list.
490 : * @param Pointer to the argument list array (will be updated in place).
491 : *
492 : * @return updated nArgc argument count. Return of 0 requests terminate
493 : * without error, return of -1 requests exit with error code.
494 : */
495 :
496 87 : int OGRGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
497 :
498 : {
499 87 : char **papszReturn = NULL;
500 : int iArg;
501 87 : char **papszArgv = *ppapszArgv;
502 :
503 : (void) nOptions;
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Preserve the program name. */
507 : /* -------------------------------------------------------------------- */
508 87 : papszReturn = CSLAddString( papszReturn, papszArgv[0] );
509 :
510 : /* ==================================================================== */
511 : /* Loop over all arguments. */
512 : /* ==================================================================== */
513 448 : for( iArg = 1; iArg < nArgc; iArg++ )
514 : {
515 : /* -------------------------------------------------------------------- */
516 : /* --version */
517 : /* -------------------------------------------------------------------- */
518 361 : if( EQUAL(papszArgv[iArg],"--version") )
519 : {
520 0 : printf( "%s\n", GDALVersionInfo( "--version" ) );
521 0 : CSLDestroy( papszReturn );
522 0 : return 0;
523 : }
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* --license */
527 : /* -------------------------------------------------------------------- */
528 361 : else if( EQUAL(papszArgv[iArg],"--license") )
529 : {
530 0 : printf( "%s\n", GDALVersionInfo( "LICENSE" ) );
531 0 : CSLDestroy( papszReturn );
532 0 : return 0;
533 : }
534 :
535 : /* -------------------------------------------------------------------- */
536 : /* --config */
537 : /* -------------------------------------------------------------------- */
538 361 : else if( EQUAL(papszArgv[iArg],"--config") )
539 : {
540 0 : if( iArg + 2 >= nArgc )
541 : {
542 : CPLError( CE_Failure, CPLE_AppDefined,
543 0 : "--config option given without a key and value argument." );
544 0 : CSLDestroy( papszReturn );
545 0 : return -1;
546 : }
547 :
548 0 : CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
549 :
550 0 : iArg += 2;
551 : }
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* --mempreload */
555 : /* -------------------------------------------------------------------- */
556 361 : else if( EQUAL(papszArgv[iArg],"--mempreload") )
557 : {
558 : int i;
559 :
560 0 : if( iArg + 1 >= nArgc )
561 : {
562 : CPLError( CE_Failure, CPLE_AppDefined,
563 0 : "--mempreload option given without directory path.");
564 0 : CSLDestroy( papszReturn );
565 0 : return -1;
566 : }
567 :
568 0 : char **papszFiles = CPLReadDir( papszArgv[iArg+1] );
569 0 : if( CSLCount(papszFiles) == 0 )
570 : {
571 : CPLError( CE_Failure, CPLE_AppDefined,
572 0 : "--mempreload given invalid or empty directory.");
573 0 : CSLDestroy( papszReturn );
574 0 : return -1;
575 : }
576 :
577 0 : for( i = 0; papszFiles[i] != NULL; i++ )
578 : {
579 0 : CPLString osOldPath, osNewPath;
580 :
581 0 : if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
582 0 : continue;
583 :
584 : osOldPath = CPLFormFilename( papszArgv[iArg+1],
585 0 : papszFiles[i], NULL );
586 0 : osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
587 :
588 : CPLDebug( "VSI", "Preloading %s to %s.",
589 0 : osOldPath.c_str(), osNewPath.c_str() );
590 :
591 0 : if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
592 0 : return -1;
593 : }
594 :
595 0 : CSLDestroy( papszFiles );
596 0 : iArg += 1;
597 : }
598 :
599 : /* -------------------------------------------------------------------- */
600 : /* --debug */
601 : /* -------------------------------------------------------------------- */
602 361 : else if( EQUAL(papszArgv[iArg],"--debug") )
603 : {
604 0 : if( iArg + 1 >= nArgc )
605 : {
606 : CPLError( CE_Failure, CPLE_AppDefined,
607 0 : "--debug option given without debug level." );
608 0 : CSLDestroy( papszReturn );
609 0 : return -1;
610 : }
611 :
612 0 : CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
613 0 : iArg += 1;
614 : }
615 :
616 : /* -------------------------------------------------------------------- */
617 : /* --optfile */
618 : /* */
619 : /* Annoyingly the options inserted by --optfile will *not* be */
620 : /* processed properly if they are general options. */
621 : /* -------------------------------------------------------------------- */
622 361 : else if( EQUAL(papszArgv[iArg],"--optfile") )
623 : {
624 : const char *pszLine;
625 : FILE *fpOptFile;
626 :
627 0 : if( iArg + 1 >= nArgc )
628 : {
629 : CPLError( CE_Failure, CPLE_AppDefined,
630 0 : "--optfile option given without filename." );
631 0 : CSLDestroy( papszReturn );
632 0 : return -1;
633 : }
634 :
635 0 : fpOptFile = VSIFOpen( papszArgv[iArg+1], "rb" );
636 :
637 0 : if( fpOptFile == NULL )
638 : {
639 : CPLError( CE_Failure, CPLE_AppDefined,
640 : "Unable to open optfile '%s'.\n%s",
641 0 : papszArgv[iArg+1], VSIStrerror( errno ) );
642 0 : CSLDestroy( papszReturn );
643 0 : return -1;
644 : }
645 :
646 0 : while( (pszLine = CPLReadLine( fpOptFile )) != NULL )
647 : {
648 : char **papszTokens;
649 : int i;
650 :
651 0 : if( pszLine[0] == '#' || strlen(pszLine) == 0 )
652 0 : continue;
653 :
654 0 : papszTokens = CSLTokenizeString( pszLine );
655 0 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++)
656 0 : papszReturn = CSLAddString( papszReturn, papszTokens[i] );
657 0 : CSLDestroy( papszTokens );
658 : }
659 :
660 0 : VSIFClose( fpOptFile );
661 :
662 0 : iArg += 1;
663 : }
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* --formats */
667 : /* -------------------------------------------------------------------- */
668 : #ifdef OGR_ENABLED
669 361 : else if( EQUAL(papszArgv[iArg], "--formats") )
670 : {
671 : int iDr;
672 :
673 0 : printf( "Supported Formats:\n" );
674 :
675 0 : OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
676 :
677 0 : for( iDr = 0; iDr < poR->GetDriverCount(); iDr++ )
678 : {
679 0 : OGRSFDriver *poDriver = poR->GetDriver(iDr);
680 :
681 0 : if( poDriver->TestCapability( ODrCCreateDataSource ) )
682 : printf( " -> \"%s\" (read/write)\n",
683 0 : poDriver->GetName() );
684 : else
685 : printf( " -> \"%s\" (readonly)\n",
686 0 : poDriver->GetName() );
687 : }
688 :
689 0 : CSLDestroy( papszReturn );
690 0 : return 0;
691 : }
692 : #endif /* OGR_ENABLED */
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* --locale */
696 : /* -------------------------------------------------------------------- */
697 361 : else if( EQUAL(papszArgv[iArg],"--locale") && iArg < nArgc-1 )
698 : {
699 0 : setlocale( LC_ALL, papszArgv[++iArg] );
700 : }
701 :
702 : /* -------------------------------------------------------------------- */
703 : /* --help-general */
704 : /* -------------------------------------------------------------------- */
705 361 : else if( EQUAL(papszArgv[iArg],"--help-general") )
706 : {
707 0 : printf( "Generic GDAL/OGR utility command options:\n" );
708 0 : printf( " --version: report version of GDAL/OGR in use.\n" );
709 0 : printf( " --license: report GDAL/OGR license info.\n" );
710 : #ifdef OGR_ENABLED
711 0 : printf( " --formats: report all configured format drivers.\n" );
712 : #endif /* OGR_ENABLED */
713 0 : printf( " --optfile filename: expand an option file into the argument list.\n" );
714 0 : printf( " --config key value: set system configuration option.\n" );
715 0 : printf( " --debug [on/off/value]: set debug level.\n" );
716 0 : printf( " --help-general: report detailed help on general options.\n" );
717 0 : CSLDestroy( papszReturn );
718 0 : return 0;
719 : }
720 :
721 : /* -------------------------------------------------------------------- */
722 : /* carry through unrecognised options. */
723 : /* -------------------------------------------------------------------- */
724 : else
725 : {
726 361 : papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
727 : }
728 : }
729 :
730 87 : *ppapszArgv = papszReturn;
731 :
732 87 : return CSLCount( *ppapszArgv );
733 : }
734 :
735 : /************************************************************************/
736 : /* OGRParseDate() */
737 : /* */
738 : /* Parse a variety of text date formats into an OGRField. */
739 : /************************************************************************/
740 :
741 : /**
742 : * Parse date string.
743 : *
744 : * This function attempts to parse a date string in a variety of formats
745 : * into the OGRField.Date format suitable for use with OGR. Generally
746 : * speaking this function is expecting values like:
747 : *
748 : * YYYY-MM-DD HH:MM:SS+nn
749 : *
750 : * The seconds may also have a decimal portion (which is ignored). And
751 : * just dates (YYYY-MM-DD) or just times (HH:MM:SS) are also supported.
752 : * The date may also be in YYYY/MM/DD format. If the year is less than 100
753 : * and greater than 30 a "1900" century value will be set. If it is less than
754 : * 30 and greater than -1 then a "2000" century value will be set. In
755 : * the future this function may be generalized, and additional control
756 : * provided through nOptions, but an nOptions value of "0" should always do
757 : * a reasonable default form of processing.
758 : *
759 : * The value of psField will be indeterminate if the function fails (returns
760 : * FALSE).
761 : *
762 : * @param pszInput the input date string.
763 : * @param psField the OGRField that will be updated with the parsed result.
764 : * @param nOptions parsing options, for now always 0.
765 : *
766 : * @return TRUE if apparently successful or FALSE on failure.
767 : */
768 :
769 238 : int OGRParseDate( const char *pszInput, OGRField *psField, int nOptions )
770 :
771 : {
772 238 : int bGotSomething = FALSE;
773 :
774 238 : psField->Date.Year = 0;
775 238 : psField->Date.Month = 0;
776 238 : psField->Date.Day = 0;
777 238 : psField->Date.Hour = 0;
778 238 : psField->Date.Minute = 0;
779 238 : psField->Date.Second = 0;
780 238 : psField->Date.TZFlag = 0;
781 :
782 : /* -------------------------------------------------------------------- */
783 : /* Do we have a date? */
784 : /* -------------------------------------------------------------------- */
785 476 : while( *pszInput == ' ' )
786 0 : pszInput++;
787 :
788 238 : if( strstr(pszInput,"-") != NULL || strstr(pszInput,"/") != NULL )
789 : {
790 196 : psField->Date.Year = (GInt16)atoi(pszInput);
791 196 : if( psField->Date.Year < 100 && psField->Date.Year >= 30 )
792 0 : psField->Date.Year += 1900;
793 196 : else if( psField->Date.Year < 30 && psField->Date.Year >= 0 )
794 0 : psField->Date.Year += 2000;
795 :
796 1176 : while( *pszInput >= '0' && *pszInput <= '9' )
797 784 : pszInput++;
798 196 : if( *pszInput != '-' && *pszInput != '/' )
799 0 : return FALSE;
800 : else
801 196 : pszInput++;
802 :
803 196 : psField->Date.Month = (GByte)atoi(pszInput);
804 196 : if( psField->Date.Month > 12 )
805 0 : return FALSE;
806 :
807 784 : while( *pszInput >= '0' && *pszInput <= '9' )
808 392 : pszInput++;
809 196 : if( *pszInput != '-' && *pszInput != '/' )
810 0 : return FALSE;
811 : else
812 196 : pszInput++;
813 :
814 196 : psField->Date.Day = (GByte)atoi(pszInput);
815 196 : if( psField->Date.Day > 31 )
816 0 : return FALSE;
817 :
818 784 : while( *pszInput >= '0' && *pszInput <= '9' )
819 392 : pszInput++;
820 :
821 196 : bGotSomething = TRUE;
822 : }
823 :
824 : /* -------------------------------------------------------------------- */
825 : /* Do we have a time? */
826 : /* -------------------------------------------------------------------- */
827 636 : while( *pszInput == ' ' )
828 160 : pszInput++;
829 :
830 238 : if( strstr(pszInput,":") != NULL )
831 : {
832 197 : psField->Date.Hour = (GByte)atoi(pszInput);
833 197 : if( psField->Date.Hour > 23 )
834 0 : return FALSE;
835 :
836 787 : while( *pszInput >= '0' && *pszInput <= '9' )
837 393 : pszInput++;
838 197 : if( *pszInput != ':' )
839 1 : return FALSE;
840 : else
841 196 : pszInput++;
842 :
843 196 : psField->Date.Minute = (GByte)atoi(pszInput);
844 196 : if( psField->Date.Minute > 59 )
845 0 : return FALSE;
846 :
847 784 : while( *pszInput >= '0' && *pszInput <= '9' )
848 392 : pszInput++;
849 196 : if( *pszInput != ':' )
850 0 : return FALSE;
851 : else
852 196 : pszInput++;
853 :
854 196 : psField->Date.Second = (GByte)atoi(pszInput);
855 196 : if( psField->Date.Second > 59 )
856 0 : return FALSE;
857 :
858 784 : while( (*pszInput >= '0' && *pszInput <= '9')
859 : || *pszInput == '.' )
860 392 : pszInput++;
861 :
862 196 : bGotSomething = TRUE;
863 : }
864 :
865 : // No date or time!
866 237 : if( !bGotSomething )
867 0 : return FALSE;
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Do we have a timezone? */
871 : /* -------------------------------------------------------------------- */
872 474 : while( *pszInput == ' ' )
873 0 : pszInput++;
874 :
875 237 : if( *pszInput == '-' || *pszInput == '+' )
876 : {
877 : // +HH integral offset
878 46 : if( strlen(pszInput) <= 3 )
879 42 : psField->Date.TZFlag = (GByte)(100 + atoi(pszInput) * 4);
880 :
881 8 : else if( pszInput[3] == ':' // +HH:MM offset
882 : && atoi(pszInput+4) % 15 == 0 )
883 : {
884 : psField->Date.TZFlag = (GByte)(100
885 : + atoi(pszInput+1) * 4
886 4 : + (atoi(pszInput+4) / 15));
887 :
888 4 : if( pszInput[0] == '-' )
889 4 : psField->Date.TZFlag = -1 * (psField->Date.TZFlag - 100) + 100;
890 : }
891 0 : else if( isdigit(pszInput[3]) && isdigit(pszInput[4]) // +HHMM offset
892 : && atoi(pszInput+3) % 15 == 0 )
893 : {
894 : psField->Date.TZFlag = (GByte)(100
895 : + static_cast<GByte>(CPLScanLong(pszInput+1,2)) * 4
896 0 : + (atoi(pszInput+3) / 15));
897 :
898 0 : if( pszInput[0] == '-' )
899 0 : psField->Date.TZFlag = -1 * (psField->Date.TZFlag - 100) + 100;
900 : }
901 0 : else if( isdigit(pszInput[3]) && pszInput[4] == '\0' // +HMM offset
902 : && atoi(pszInput+2) % 15 == 0 )
903 : {
904 : psField->Date.TZFlag = (GByte)(100
905 : + static_cast<GByte>(CPLScanLong(pszInput+1,1)) * 4
906 0 : + (atoi(pszInput+2) / 15));
907 :
908 0 : if( pszInput[0] == '-' )
909 0 : psField->Date.TZFlag = -1 * (psField->Date.TZFlag - 100) + 100;
910 : }
911 : // otherwise ignore any timezone info.
912 : }
913 :
914 237 : return TRUE;
915 : }
916 :
917 :
918 : /************************************************************************/
919 : /* OGRParseXMLDateTime() */
920 : /************************************************************************/
921 :
922 : int OGRParseXMLDateTime( const char* pszXMLDateTime,
923 : int *pnYear, int *pnMonth, int *pnDay,
924 27 : int *pnHour, int *pnMinute, float* pfSecond, int *pnTZ)
925 : {
926 27 : int year = 0, month = 0, day = 0, hour = 0, minute = 0, TZHour, TZMinute;
927 27 : float second = 0;
928 : char c;
929 27 : int TZ = 0;
930 27 : int bRet = FALSE;
931 :
932 : /* Date is expressed as a UTC date */
933 27 : if (sscanf(pszXMLDateTime, "%04d-%02d-%02dT%02d:%02d:%f%c",
934 : &year, &month, &day, &hour, &minute, &second, &c) == 7 && c == 'Z')
935 : {
936 4 : TZ = 100;
937 4 : bRet = TRUE;
938 : }
939 : /* Date is expressed as a UTC date, with a timezone */
940 23 : else if (sscanf(pszXMLDateTime, "%04d-%02d-%02dT%02d:%02d:%f%c%02d:%02d",
941 : &year, &month, &day, &hour, &minute, &second, &c, &TZHour, &TZMinute) == 9 &&
942 : (c == '+' || c == '-'))
943 : {
944 23 : TZ = 100 + ((c == '+') ? 1 : -1) * ((TZHour * 60 + TZMinute) / 15);
945 23 : bRet = TRUE;
946 : }
947 : /* Date is expressed into an unknown timezone */
948 0 : else if (sscanf(pszXMLDateTime, "%04d-%02d-%02dT%02d:%02d:%f",
949 : &year, &month, &day, &hour, &minute, &second) == 6)
950 : {
951 0 : TZ = 0;
952 0 : bRet = TRUE;
953 : }
954 27 : if (bRet)
955 : {
956 27 : if (pnYear) *pnYear = year;
957 27 : if (pnMonth) *pnMonth = month;
958 27 : if (pnDay) *pnDay = day;
959 27 : if (pnHour) *pnHour = hour;
960 27 : if (pnMinute) *pnMinute = minute;
961 27 : if (pfSecond) *pfSecond = second;
962 27 : if (pnTZ) *pnTZ = TZ;
963 : }
964 :
965 27 : return bRet;
966 : }
967 :
968 : /************************************************************************/
969 : /* OGRParseRFC822DateTime() */
970 : /************************************************************************/
971 :
972 : static const char* aszMonthStr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
973 : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
974 :
975 : int OGRParseRFC822DateTime( const char* pszRFC822DateTime,
976 : int *pnYear, int *pnMonth, int *pnDay,
977 25 : int *pnHour, int *pnMinute, int *pnSecond, int *pnTZ)
978 : {
979 : /* Following http://asg.web.cmu.edu/rfc/rfc822.html#sec-5 : [Fri,] 28 Dec 2007 05:24[:17] GMT */
980 25 : char** papszTokens = CSLTokenizeStringComplex( pszRFC822DateTime, " ,:", TRUE, FALSE );
981 25 : char** papszVal = papszTokens;
982 25 : int bRet = FALSE;
983 25 : int nTokens = CSLCount(papszTokens);
984 25 : if (nTokens >= 6)
985 : {
986 21 : if ( ! ((*papszVal)[0] >= '0' && (*papszVal)[0] <= '9') )
987 : {
988 : /* Ignore day of week */
989 21 : papszVal ++;
990 : }
991 :
992 21 : int day = atoi(*papszVal);
993 21 : papszVal ++;
994 :
995 21 : int month = 0;
996 :
997 273 : for(int i = 0; i < 12; i++)
998 : {
999 252 : if (EQUAL(*papszVal, aszMonthStr[i]))
1000 21 : month = i + 1;
1001 : }
1002 21 : papszVal ++;
1003 :
1004 21 : int year = atoi(*papszVal);
1005 21 : papszVal ++;
1006 21 : if( year < 100 && year >= 30 )
1007 0 : year += 1900;
1008 21 : else if( year < 30 && year >= 0 )
1009 0 : year += 2000;
1010 :
1011 21 : int hour = atoi(*papszVal);
1012 21 : papszVal ++;
1013 :
1014 21 : int minute = atoi(*papszVal);
1015 21 : papszVal ++;
1016 :
1017 21 : int second = 0;
1018 21 : if (*papszVal != NULL && (*papszVal)[0] >= '0' && (*papszVal)[0] <= '9')
1019 : {
1020 21 : second = atoi(*papszVal);
1021 21 : papszVal ++;
1022 : }
1023 :
1024 21 : if (month != 0)
1025 : {
1026 21 : bRet = TRUE;
1027 21 : int TZ = 0;
1028 :
1029 21 : if (*papszVal == NULL)
1030 : {
1031 : }
1032 42 : else if (strlen(*papszVal) == 5 &&
1033 : ((*papszVal)[0] == '+' || (*papszVal)[0] == '-'))
1034 : {
1035 : char szBuf[3];
1036 21 : szBuf[0] = (*papszVal)[1];
1037 21 : szBuf[1] = (*papszVal)[2];
1038 21 : szBuf[2] = 0;
1039 21 : int TZHour = atoi(szBuf);
1040 21 : szBuf[0] = (*papszVal)[3];
1041 21 : szBuf[1] = (*papszVal)[4];
1042 21 : szBuf[2] = 0;
1043 21 : int TZMinute = atoi(szBuf);
1044 21 : TZ = 100 + (((*papszVal)[0] == '+') ? 1 : -1) * ((TZHour * 60 + TZMinute) / 15);
1045 : }
1046 : else
1047 : {
1048 0 : const char* aszTZStr[] = { "GMT", "UT", "Z", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT" };
1049 0 : int anTZVal[] = { 0, 0, 0, -5, -4, -6, -5, -7, -6, -8, -7 };
1050 0 : for(int i = 0; i < 11; i++)
1051 : {
1052 0 : if (EQUAL(*papszVal, aszTZStr[i]))
1053 : {
1054 0 : TZ = 100 + anTZVal[i] * 4;
1055 0 : break;
1056 : }
1057 : }
1058 : }
1059 :
1060 21 : if (pnYear) *pnYear = year;
1061 21 : if (pnMonth) *pnMonth = month;
1062 21 : if (pnDay) *pnDay = day;
1063 21 : if (pnHour) *pnHour = hour;
1064 21 : if (pnMinute) *pnMinute = minute;
1065 21 : if (pnSecond) *pnSecond = second;
1066 21 : if (pnTZ) *pnTZ = TZ;
1067 : }
1068 : }
1069 25 : CSLDestroy(papszTokens);
1070 25 : return bRet;
1071 : }
1072 :
1073 :
1074 : /**
1075 : * Returns the day of the week in Gregorian calendar
1076 : *
1077 : * @param day : day of the month, between 1 and 31
1078 : * @param month : month of the year, between 1 (Jan) and 12 (Dec)
1079 : * @param year : year
1080 :
1081 : * @return day of the week : 0 for Monday, ... 6 for Sunday
1082 : */
1083 :
1084 12 : int OGRGetDayOfWeek(int day, int month, int year)
1085 : {
1086 : /* Reference: Zeller's congruence */
1087 12 : int q = day;
1088 : int m;
1089 12 : if (month >=3)
1090 12 : m = month;
1091 : else
1092 : {
1093 0 : m = month + 12;
1094 0 : year --;
1095 : }
1096 12 : int K = year % 100;
1097 12 : int J = year / 100;
1098 12 : int h = ( q + (((m+1)*26)/10) + K + K/4 + J/4 + 5 * J) % 7;
1099 12 : return ( h + 5 ) % 7;
1100 : }
1101 :
1102 :
1103 : /************************************************************************/
1104 : /* OGRGetRFC822DateTime() */
1105 : /************************************************************************/
1106 :
1107 12 : char* OGRGetRFC822DateTime(int year, int month, int day, int hour, int minute, int second, int TZFlag)
1108 : {
1109 12 : char* pszTZ = NULL;
1110 12 : const char* aszDayOfWeek[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
1111 :
1112 12 : int dayofweek = OGRGetDayOfWeek(day, month, year);
1113 :
1114 12 : if (month < 1 || month > 12)
1115 0 : month = 1;
1116 :
1117 12 : if (TZFlag == 0 || TZFlag == 100)
1118 : {
1119 0 : pszTZ = CPLStrdup("GMT");
1120 : }
1121 : else
1122 : {
1123 12 : int TZOffset = ABS(TZFlag - 100) * 15;
1124 12 : int TZHour = TZOffset / 60;
1125 12 : int TZMinute = TZOffset - TZHour * 60;
1126 : pszTZ = CPLStrdup(CPLSPrintf("%c%02d%02d", TZFlag > 100 ? '+' : '-',
1127 12 : TZHour, TZMinute));
1128 : }
1129 : char* pszRet = CPLStrdup(CPLSPrintf("%s, %02d %s %04d %02d:%02d:%02d %s",
1130 12 : aszDayOfWeek[dayofweek], day, aszMonthStr[month - 1], year, hour, minute, second, pszTZ));
1131 12 : CPLFree(pszTZ);
1132 12 : return pszRet;
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* OGRGetXMLDateTime() */
1137 : /************************************************************************/
1138 :
1139 4 : char* OGRGetXMLDateTime(int year, int month, int day, int hour, int minute, int second, int TZFlag)
1140 : {
1141 : char* pszRet;
1142 6 : if (TZFlag == 0 || TZFlag == 100)
1143 : {
1144 : pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
1145 2 : year, month, day, hour, minute, second));
1146 : }
1147 : else
1148 : {
1149 2 : int TZOffset = ABS(TZFlag - 100) * 15;
1150 2 : int TZHour = TZOffset / 60;
1151 2 : int TZMinute = TZOffset - TZHour * 60;
1152 : pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
1153 : year, month, day, hour, minute, second,
1154 2 : (TZFlag > 100) ? '+' : '-', TZHour, TZMinute));
1155 : }
1156 4 : return pszRet;
1157 : }
1158 :
1159 : /************************************************************************/
1160 : /* OGRGetXML_UTF8_EscapedString() */
1161 : /************************************************************************/
1162 :
1163 101 : char* OGRGetXML_UTF8_EscapedString(const char* pszString)
1164 : {
1165 : char *pszEscaped;
1166 101 : if (!CPLIsUTF8(pszString, -1) &&
1167 : CSLTestBoolean(CPLGetConfigOption("OGR_FORCE_ASCII", "YES")))
1168 : {
1169 : static int bFirstTime = TRUE;
1170 1 : if (bFirstTime)
1171 : {
1172 1 : bFirstTime = FALSE;
1173 : CPLError(CE_Warning, CPLE_AppDefined,
1174 : "%s is not a valid UTF-8 string. Forcing it to ASCII.\n"
1175 : "If you still want the original string and change the XML file encoding\n"
1176 : "afterwards, you can define OGR_FORCE_ASCII=NO as configuration option.\n"
1177 1 : "This warning won't be issued anymore", pszString);
1178 : }
1179 : else
1180 : {
1181 : CPLDebug("OGR", "%s is not a valid UTF-8 string. Forcing it to ASCII",
1182 0 : pszString);
1183 : }
1184 1 : char* pszTemp = CPLForceToASCII(pszString, -1, '?');
1185 1 : pszEscaped = CPLEscapeString( pszTemp, -1, CPLES_XML );
1186 1 : CPLFree(pszTemp);
1187 : }
1188 : else
1189 100 : pszEscaped = CPLEscapeString( pszString, -1, CPLES_XML );
1190 101 : return pszEscaped;
1191 : }
1192 :
1193 : /************************************************************************/
1194 : /* OGRCompareDate() */
1195 : /************************************************************************/
1196 :
1197 : int OGRCompareDate( OGRField *psFirstTuple,
1198 52 : OGRField *psSecondTuple )
1199 : {
1200 : /* FIXME? : We ignore TZFlag */
1201 :
1202 52 : if (psFirstTuple->Date.Year < psSecondTuple->Date.Year)
1203 13 : return -1;
1204 39 : else if (psFirstTuple->Date.Year > psSecondTuple->Date.Year)
1205 0 : return 1;
1206 :
1207 39 : if (psFirstTuple->Date.Month < psSecondTuple->Date.Month)
1208 5 : return -1;
1209 34 : else if (psFirstTuple->Date.Month > psSecondTuple->Date.Month)
1210 21 : return 1;
1211 :
1212 13 : if (psFirstTuple->Date.Day < psSecondTuple->Date.Day)
1213 3 : return -1;
1214 10 : else if (psFirstTuple->Date.Day > psSecondTuple->Date.Day)
1215 0 : return 1;
1216 :
1217 10 : if (psFirstTuple->Date.Hour < psSecondTuple->Date.Hour)
1218 0 : return -1;
1219 10 : else if (psFirstTuple->Date.Hour > psSecondTuple->Date.Hour)
1220 4 : return 1;
1221 :
1222 6 : if (psFirstTuple->Date.Minute < psSecondTuple->Date.Minute)
1223 0 : return -1;
1224 6 : else if (psFirstTuple->Date.Minute > psSecondTuple->Date.Minute)
1225 0 : return 1;
1226 :
1227 6 : if (psFirstTuple->Date.Second < psSecondTuple->Date.Second)
1228 0 : return -1;
1229 6 : else if (psFirstTuple->Date.Second > psSecondTuple->Date.Second)
1230 0 : return 1;
1231 :
1232 6 : return 0;
1233 : }
1234 :
1235 : /************************************************************************/
1236 : /* OGRFastAtof() */
1237 : /************************************************************************/
1238 :
1239 : /* On Windows, atof() is very slow if the number */
1240 : /* is followed by other long content. */
1241 : /* So we just extract the number into a short string */
1242 : /* before calling atof() on it */
1243 : static
1244 0 : double OGRCallAtofOnShortString(const char* pszStr)
1245 : {
1246 : char szTemp[128];
1247 0 : int nCounter = 0;
1248 0 : const char* p = pszStr;
1249 0 : while(*p == ' ' || *p == '\t')
1250 0 : p++;
1251 0 : while(*p == '+' ||
1252 : *p == '-' ||
1253 : (*p >= '0' && *p <= '9') ||
1254 : (*p == 'e' || *p == 'E' || *p == 'd' || *p == 'D'))
1255 : {
1256 0 : szTemp[nCounter++] = *(p++);
1257 0 : if (nCounter == 127)
1258 0 : return atof(pszStr);
1259 : }
1260 0 : szTemp[nCounter] = '\0';
1261 0 : return atof(szTemp);
1262 : }
1263 :
1264 : /** Same contract as CPLAtof, except than it doesn't always call the
1265 : * system atof() that may be slow on some platforms. For simple but
1266 : * common strings, it'll use a faster implementation (up to 20x faster
1267 : * than atof() on MS runtime libraries) that has no garanty to return
1268 : * exactly the same floating point number.
1269 : */
1270 :
1271 806 : double OGRFastAtof(const char* pszStr)
1272 : {
1273 806 : double dfVal = 0;
1274 806 : double dfSign = 1.0;
1275 806 : const char* p = pszStr;
1276 :
1277 : static const double adfTenPower[] =
1278 : {
1279 : 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,
1280 : 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
1281 : 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31
1282 : };
1283 :
1284 1614 : while(*p == ' ' || *p == '\t')
1285 2 : p++;
1286 :
1287 806 : if (*p == '+')
1288 9 : p++;
1289 797 : else if (*p == '-')
1290 : {
1291 62 : dfSign = -1.0;
1292 62 : p++;
1293 : }
1294 :
1295 2542 : while(TRUE)
1296 : {
1297 3348 : if (*p >= '0' && *p <= '9')
1298 : {
1299 2542 : dfVal = dfVal * 10.0 + (*p - '0');
1300 2542 : p++;
1301 : }
1302 806 : else if (*p == '.')
1303 : {
1304 288 : p++;
1305 : break;
1306 : }
1307 518 : else if (*p == 'e' || *p == 'E' || *p == 'd' || *p == 'D')
1308 0 : return OGRCallAtofOnShortString(pszStr);
1309 : else
1310 518 : return dfSign * dfVal;
1311 : }
1312 :
1313 288 : unsigned int countFractionnal = 0;
1314 3313 : while(TRUE)
1315 : {
1316 3601 : if (*p >= '0' && *p <= '9')
1317 : {
1318 3313 : dfVal = dfVal * 10.0 + (*p - '0');
1319 3313 : countFractionnal ++;
1320 3313 : p++;
1321 : }
1322 288 : else if (*p == 'e' || *p == 'E' || *p == 'd' || *p == 'D')
1323 0 : return OGRCallAtofOnShortString(pszStr);
1324 : else
1325 : {
1326 288 : if (countFractionnal < sizeof(adfTenPower) / sizeof(adfTenPower[0]))
1327 288 : return dfSign * (dfVal / adfTenPower[countFractionnal]);
1328 : else
1329 0 : return OGRCallAtofOnShortString(pszStr);
1330 : }
1331 : }
1332 : }
|