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