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