1 : /******************************************************************************
2 : * $Id: gdal_misc.cpp 25340 2012-12-21 20:30:21Z rouault $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Free standing functions for GDAL.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_priv.h"
31 : #include "cpl_string.h"
32 : #include "cpl_minixml.h"
33 : #include "cpl_multiproc.h"
34 : #include <ctype.h>
35 : #include <string>
36 :
37 : CPL_CVSID("$Id: gdal_misc.cpp 25340 2012-12-21 20:30:21Z rouault $");
38 :
39 : #include "ogr_spatialref.h"
40 :
41 : /************************************************************************/
42 : /* __pure_virtual() */
43 : /* */
44 : /* The following is a gross hack to remove the last remaining */
45 : /* dependency on the GNU C++ standard library. */
46 : /************************************************************************/
47 :
48 : #ifdef __GNUC__
49 :
50 : extern "C"
51 0 : void __pure_virtual()
52 :
53 : {
54 0 : }
55 :
56 : #endif
57 :
58 : /************************************************************************/
59 : /* GDALDataTypeUnion() */
60 : /************************************************************************/
61 :
62 : /**
63 : * \brief Return the smallest data type that can fully express both input data
64 : * types.
65 : *
66 : * @param eType1 first data type.
67 : * @param eType2 second data type.
68 : *
69 : * @return a data type able to express eType1 and eType2.
70 : */
71 :
72 : GDALDataType CPL_STDCALL
73 740 : GDALDataTypeUnion( GDALDataType eType1, GDALDataType eType2 )
74 :
75 : {
76 : int bFloating, bComplex, nBits, bSigned;
77 :
78 740 : bComplex = GDALDataTypeIsComplex(eType1) | GDALDataTypeIsComplex(eType2);
79 :
80 740 : switch( eType1 )
81 : {
82 : case GDT_Byte:
83 513 : nBits = 8;
84 513 : bSigned = FALSE;
85 513 : bFloating = FALSE;
86 513 : break;
87 :
88 : case GDT_Int16:
89 : case GDT_CInt16:
90 0 : nBits = 16;
91 0 : bSigned = TRUE;
92 0 : bFloating = FALSE;
93 0 : break;
94 :
95 : case GDT_UInt16:
96 0 : nBits = 16;
97 0 : bSigned = FALSE;
98 0 : bFloating = FALSE;
99 0 : break;
100 :
101 : case GDT_Int32:
102 : case GDT_CInt32:
103 7 : nBits = 32;
104 7 : bSigned = TRUE;
105 7 : bFloating = FALSE;
106 7 : break;
107 :
108 : case GDT_UInt32:
109 0 : nBits = 32;
110 0 : bSigned = FALSE;
111 0 : bFloating = FALSE;
112 0 : break;
113 :
114 : case GDT_Float32:
115 : case GDT_CFloat32:
116 220 : nBits = 32;
117 220 : bSigned = TRUE;
118 220 : bFloating = TRUE;
119 220 : break;
120 :
121 : case GDT_Float64:
122 : case GDT_CFloat64:
123 0 : nBits = 64;
124 0 : bSigned = TRUE;
125 0 : bFloating = TRUE;
126 0 : break;
127 :
128 : default:
129 0 : CPLAssert( FALSE );
130 0 : return GDT_Unknown;
131 : }
132 :
133 740 : switch( eType2 )
134 : {
135 : case GDT_Byte:
136 248 : break;
137 :
138 : case GDT_Int16:
139 : case GDT_CInt16:
140 66 : nBits = MAX(nBits,16);
141 66 : bSigned = TRUE;
142 66 : break;
143 :
144 : case GDT_UInt16:
145 26 : nBits = MAX(nBits,16);
146 26 : break;
147 :
148 : case GDT_Int32:
149 : case GDT_CInt32:
150 276 : nBits = MAX(nBits,32);
151 276 : bSigned = TRUE;
152 276 : break;
153 :
154 : case GDT_UInt32:
155 25 : nBits = MAX(nBits,32);
156 25 : break;
157 :
158 : case GDT_Float32:
159 : case GDT_CFloat32:
160 49 : nBits = MAX(nBits,32);
161 49 : bSigned = TRUE;
162 49 : bFloating = TRUE;
163 49 : break;
164 :
165 : case GDT_Float64:
166 : case GDT_CFloat64:
167 50 : nBits = MAX(nBits,64);
168 50 : bSigned = TRUE;
169 50 : bFloating = TRUE;
170 50 : break;
171 :
172 : default:
173 0 : CPLAssert( FALSE );
174 0 : return GDT_Unknown;
175 : }
176 :
177 740 : if( nBits == 8 )
178 248 : return GDT_Byte;
179 492 : else if( nBits == 16 && bComplex )
180 22 : return GDT_CInt16;
181 470 : else if( nBits == 16 && bSigned )
182 44 : return GDT_Int16;
183 426 : else if( nBits == 16 && !bSigned )
184 26 : return GDT_UInt16;
185 400 : else if( nBits == 32 && bFloating && bComplex )
186 24 : return GDT_CFloat32;
187 376 : else if( nBits == 32 && bFloating )
188 245 : return GDT_Float32;
189 131 : else if( nBits == 32 && bComplex )
190 22 : return GDT_CInt32;
191 109 : else if( nBits == 32 && bSigned )
192 34 : return GDT_Int32;
193 75 : else if( nBits == 32 && !bSigned )
194 25 : return GDT_UInt32;
195 50 : else if( nBits == 64 && bComplex )
196 24 : return GDT_CFloat64;
197 : else
198 26 : return GDT_Float64;
199 : }
200 :
201 :
202 : /************************************************************************/
203 : /* GDALGetDataTypeSize() */
204 : /************************************************************************/
205 :
206 : /**
207 : * \brief Get data type size in bits.
208 : *
209 : * Returns the size of a a GDT_* type in bits, <b>not bytes</b>!
210 : *
211 : * @param eDataType type, such as GDT_Byte.
212 : * @return the number of bits or zero if it is not recognised.
213 : */
214 :
215 8975314 : int CPL_STDCALL GDALGetDataTypeSize( GDALDataType eDataType )
216 :
217 : {
218 8975314 : switch( eDataType )
219 : {
220 : case GDT_Byte:
221 5538994 : return 8;
222 :
223 : case GDT_UInt16:
224 : case GDT_Int16:
225 1486909 : return 16;
226 :
227 : case GDT_UInt32:
228 : case GDT_Int32:
229 : case GDT_Float32:
230 : case GDT_CInt16:
231 1731482 : return 32;
232 :
233 : case GDT_Float64:
234 : case GDT_CInt32:
235 : case GDT_CFloat32:
236 46054 : return 64;
237 :
238 : case GDT_CFloat64:
239 171875 : return 128;
240 :
241 : default:
242 0 : return 0;
243 : }
244 : }
245 :
246 : /************************************************************************/
247 : /* GDALDataTypeIsComplex() */
248 : /************************************************************************/
249 :
250 : /**
251 : * \brief Is data type complex?
252 : *
253 : * @return TRUE if the passed type is complex (one of GDT_CInt16, GDT_CInt32,
254 : * GDT_CFloat32 or GDT_CFloat64), that is it consists of a real and imaginary
255 : * component.
256 : */
257 :
258 288535 : int CPL_STDCALL GDALDataTypeIsComplex( GDALDataType eDataType )
259 :
260 : {
261 288535 : switch( eDataType )
262 : {
263 : case GDT_CInt16:
264 : case GDT_CInt32:
265 : case GDT_CFloat32:
266 : case GDT_CFloat64:
267 584 : return TRUE;
268 :
269 : default:
270 287951 : return FALSE;
271 : }
272 : }
273 :
274 : /************************************************************************/
275 : /* GDALGetDataTypeName() */
276 : /************************************************************************/
277 :
278 : /**
279 : * \brief Get name of data type.
280 : *
281 : * Returns a symbolic name for the data type. This is essentially the
282 : * the enumerated item name with the GDT_ prefix removed. So GDT_Byte returns
283 : * "Byte". The returned strings are static strings and should not be modified
284 : * or freed by the application. These strings are useful for reporting
285 : * datatypes in debug statements, errors and other user output.
286 : *
287 : * @param eDataType type to get name of.
288 : * @return string corresponding to existing data type
289 : * or NULL pointer if invalid type given.
290 : */
291 :
292 19352 : const char * CPL_STDCALL GDALGetDataTypeName( GDALDataType eDataType )
293 :
294 : {
295 19352 : switch( eDataType )
296 : {
297 : case GDT_Unknown:
298 238 : return "Unknown";
299 :
300 : case GDT_Byte:
301 10404 : return "Byte";
302 :
303 : case GDT_UInt16:
304 1117 : return "UInt16";
305 :
306 : case GDT_Int16:
307 1063 : return "Int16";
308 :
309 : case GDT_UInt32:
310 949 : return "UInt32";
311 :
312 : case GDT_Int32:
313 924 : return "Int32";
314 :
315 : case GDT_Float32:
316 1007 : return "Float32";
317 :
318 : case GDT_Float64:
319 788 : return "Float64";
320 :
321 : case GDT_CInt16:
322 731 : return "CInt16";
323 :
324 : case GDT_CInt32:
325 715 : return "CInt32";
326 :
327 : case GDT_CFloat32:
328 715 : return "CFloat32";
329 :
330 : case GDT_CFloat64:
331 701 : return "CFloat64";
332 :
333 : default:
334 0 : return NULL;
335 : }
336 : }
337 :
338 : /************************************************************************/
339 : /* GDALGetDataTypeByName() */
340 : /************************************************************************/
341 :
342 : /**
343 : * \brief Get data type by symbolic name.
344 : *
345 : * Returns a data type corresponding to the given symbolic name. This
346 : * function is opposite to the GDALGetDataTypeName().
347 : *
348 : * @param pszName string containing the symbolic name of the type.
349 : *
350 : * @return GDAL data type.
351 : */
352 :
353 647 : GDALDataType CPL_STDCALL GDALGetDataTypeByName( const char *pszName )
354 :
355 : {
356 647 : VALIDATE_POINTER1( pszName, "GDALGetDataTypeByName", GDT_Unknown );
357 :
358 : int iType;
359 :
360 1321 : for( iType = 1; iType < GDT_TypeCount; iType++ )
361 : {
362 1320 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
363 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType), pszName) )
364 : {
365 646 : return (GDALDataType)iType;
366 : }
367 : }
368 :
369 1 : return GDT_Unknown;
370 : }
371 :
372 : /************************************************************************/
373 : /* GDALGetAsyncStatusTypeByName() */
374 : /************************************************************************/
375 : /**
376 : * Get AsyncStatusType by symbolic name.
377 : *
378 : * Returns a data type corresponding to the given symbolic name. This
379 : * function is opposite to the GDALGetAsyncStatusTypeName().
380 : *
381 : * @param pszName string containing the symbolic name of the type.
382 : *
383 : * @return GDAL AsyncStatus type.
384 : */
385 0 : GDALAsyncStatusType CPL_DLL CPL_STDCALL GDALGetAsyncStatusTypeByName( const char *pszName )
386 : {
387 0 : VALIDATE_POINTER1( pszName, "GDALGetAsyncStatusTypeByName", GARIO_ERROR);
388 :
389 : int iType;
390 :
391 0 : for( iType = 1; iType < GARIO_TypeCount; iType++ )
392 : {
393 0 : if( GDALGetAsyncStatusTypeName((GDALAsyncStatusType)iType) != NULL
394 : && EQUAL(GDALGetAsyncStatusTypeName((GDALAsyncStatusType)iType), pszName) )
395 : {
396 0 : return (GDALAsyncStatusType)iType;
397 : }
398 : }
399 :
400 0 : return GARIO_ERROR;
401 : }
402 :
403 :
404 : /************************************************************************/
405 : /* GDALGetAsyncStatusTypeName() */
406 : /************************************************************************/
407 :
408 : /**
409 : * Get name of AsyncStatus data type.
410 : *
411 : * Returns a symbolic name for the AsyncStatus data type. This is essentially the
412 : * the enumerated item name with the GARIO_ prefix removed. So GARIO_COMPLETE returns
413 : * "COMPLETE". The returned strings are static strings and should not be modified
414 : * or freed by the application. These strings are useful for reporting
415 : * datatypes in debug statements, errors and other user output.
416 : *
417 : * @param eAsyncStatusType type to get name of.
418 : * @return string corresponding to type.
419 : */
420 :
421 0 : const char * CPL_STDCALL GDALGetAsyncStatusTypeName( GDALAsyncStatusType eAsyncStatusType )
422 :
423 : {
424 0 : switch( eAsyncStatusType )
425 : {
426 : case GARIO_PENDING:
427 0 : return "PENDING";
428 :
429 : case GARIO_UPDATE:
430 0 : return "UPDATE";
431 :
432 : case GARIO_ERROR:
433 0 : return "ERROR";
434 :
435 : case GARIO_COMPLETE:
436 0 : return "COMPLETE";
437 : default:
438 0 : return NULL;
439 : }
440 : }
441 :
442 : /************************************************************************/
443 : /* GDALGetPaletteInterpretationName() */
444 : /************************************************************************/
445 :
446 : /**
447 : * \brief Get name of palette interpretation
448 : *
449 : * Returns a symbolic name for the palette interpretation. This is the
450 : * the enumerated item name with the GPI_ prefix removed. So GPI_Gray returns
451 : * "Gray". The returned strings are static strings and should not be modified
452 : * or freed by the application.
453 : *
454 : * @param eInterp palette interpretation to get name of.
455 : * @return string corresponding to palette interpretation.
456 : */
457 :
458 4 : const char *GDALGetPaletteInterpretationName( GDALPaletteInterp eInterp )
459 :
460 : {
461 4 : switch( eInterp )
462 : {
463 : case GPI_Gray:
464 0 : return "Gray";
465 :
466 : case GPI_RGB:
467 4 : return "RGB";
468 :
469 : case GPI_CMYK:
470 0 : return "CMYK";
471 :
472 : case GPI_HLS:
473 0 : return "HLS";
474 :
475 : default:
476 0 : return "Unknown";
477 : }
478 : }
479 :
480 : /************************************************************************/
481 : /* GDALGetColorInterpretationName() */
482 : /************************************************************************/
483 :
484 : /**
485 : * \brief Get name of color interpretation
486 : *
487 : * Returns a symbolic name for the color interpretation. This is derived from
488 : * the enumerated item name with the GCI_ prefix removed, but there are some
489 : * variations. So GCI_GrayIndex returns "Gray" and GCI_RedBand returns "Red".
490 : * The returned strings are static strings and should not be modified
491 : * or freed by the application.
492 : *
493 : * @param eInterp color interpretation to get name of.
494 : * @return string corresponding to color interpretation
495 : * or NULL pointer if invalid enumerator given.
496 : */
497 :
498 2098 : const char *GDALGetColorInterpretationName( GDALColorInterp eInterp )
499 :
500 : {
501 2098 : switch( eInterp )
502 : {
503 : case GCI_Undefined:
504 526 : return "Undefined";
505 :
506 : case GCI_GrayIndex:
507 883 : return "Gray";
508 :
509 : case GCI_PaletteIndex:
510 162 : return "Palette";
511 :
512 : case GCI_RedBand:
513 189 : return "Red";
514 :
515 : case GCI_GreenBand:
516 143 : return "Green";
517 :
518 : case GCI_BlueBand:
519 103 : return "Blue";
520 :
521 : case GCI_AlphaBand:
522 35 : return "Alpha";
523 :
524 : case GCI_HueBand:
525 6 : return "Hue";
526 :
527 : case GCI_SaturationBand:
528 6 : return "Saturation";
529 :
530 : case GCI_LightnessBand:
531 6 : return "Lightness";
532 :
533 : case GCI_CyanBand:
534 6 : return "Cyan";
535 :
536 : case GCI_MagentaBand:
537 6 : return "Magenta";
538 :
539 : case GCI_YellowBand:
540 6 : return "Yellow";
541 :
542 : case GCI_BlackBand:
543 6 : return "Black";
544 :
545 : case GCI_YCbCr_YBand:
546 7 : return "YCbCr_Y";
547 :
548 : case GCI_YCbCr_CbBand:
549 5 : return "YCbCr_Cb";
550 :
551 : case GCI_YCbCr_CrBand:
552 3 : return "YCbCr_Cr";
553 :
554 : default:
555 0 : return "Unknown";
556 : }
557 : }
558 :
559 : /************************************************************************/
560 : /* GDALGetColorInterpretationByName() */
561 : /************************************************************************/
562 :
563 : /**
564 : * \brief Get color interpreation by symbolic name.
565 : *
566 : * Returns a color interpreation corresponding to the given symbolic name. This
567 : * function is opposite to the GDALGetColorInterpretationName().
568 : *
569 : * @param pszName string containing the symbolic name of the color interpretation.
570 : *
571 : * @return GDAL color interpretation.
572 : *
573 : * @since GDAL 1.7.0
574 : */
575 :
576 524 : GDALColorInterp GDALGetColorInterpretationByName( const char *pszName )
577 :
578 : {
579 524 : VALIDATE_POINTER1( pszName, "GDALGetColorInterpretationByName", GCI_Undefined );
580 :
581 : int iType;
582 :
583 1585 : for( iType = 0; iType <= GCI_Max; iType++ )
584 : {
585 1585 : if( EQUAL(GDALGetColorInterpretationName((GDALColorInterp)iType), pszName) )
586 : {
587 524 : return (GDALColorInterp)iType;
588 : }
589 : }
590 :
591 0 : return GCI_Undefined;
592 : }
593 :
594 : /************************************************************************/
595 : /* GDALDummyProgress() */
596 : /************************************************************************/
597 :
598 : /**
599 : * \brief Stub progress function.
600 : *
601 : * This is a stub (does nothing) implementation of the GDALProgressFunc()
602 : * semantics. It is primarily useful for passing to functions that take
603 : * a GDALProgressFunc() argument but for which the application does not want
604 : * to use one of the other progress functions that actually do something.
605 : */
606 :
607 103300 : int CPL_STDCALL GDALDummyProgress( double dfComplete, const char *pszMessage,
608 : void *pData )
609 :
610 : {
611 103300 : return TRUE;
612 : }
613 :
614 : /************************************************************************/
615 : /* GDALScaledProgress() */
616 : /************************************************************************/
617 : typedef struct {
618 : GDALProgressFunc pfnProgress;
619 : void *pData;
620 : double dfMin;
621 : double dfMax;
622 : } GDALScaledProgressInfo;
623 :
624 : /**
625 : * \brief Scaled progress transformer.
626 : *
627 : * This is the progress function that should be passed along with the
628 : * callback data returned by GDALCreateScaledProgress().
629 : */
630 :
631 35326 : int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
632 : void *pData )
633 :
634 : {
635 35326 : GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
636 :
637 : return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
638 : + psInfo->dfMin,
639 35326 : pszMessage, psInfo->pData );
640 : }
641 :
642 : /************************************************************************/
643 : /* GDALCreateScaledProgress() */
644 : /************************************************************************/
645 :
646 : /**
647 : * \brief Create scaled progress transformer.
648 : *
649 : * Sometimes when an operations wants to report progress it actually
650 : * invokes several subprocesses which also take GDALProgressFunc()s,
651 : * and it is desirable to map the progress of each sub operation into
652 : * a portion of 0.0 to 1.0 progress of the overall process. The scaled
653 : * progress function can be used for this.
654 : *
655 : * For each subsection a scaled progress function is created and
656 : * instead of passing the overall progress func down to the sub functions,
657 : * the GDALScaledProgress() function is passed instead.
658 : *
659 : * @param dfMin the value to which 0.0 in the sub operation is mapped.
660 : * @param dfMax the value to which 1.0 is the sub operation is mapped.
661 : * @param pfnProgress the overall progress function.
662 : * @param pData the overall progress function callback data.
663 : *
664 : * @return pointer to pass as pProgressArg to sub functions. Should be freed
665 : * with GDALDestroyScaledProgress().
666 : *
667 : * Example:
668 : *
669 : * \code
670 : * int MyOperation( ..., GDALProgressFunc pfnProgress, void *pProgressData );
671 : *
672 : * {
673 : * void *pScaledProgress;
674 : *
675 : * pScaledProgress = GDALCreateScaledProgress( 0.0, 0.5, pfnProgress,
676 : * pProgressData );
677 : * GDALDoLongSlowOperation( ..., GDALScaledProgress, pScaledProgress );
678 : * GDALDestroyScaledProgress( pScaledProgress );
679 : *
680 : * pScaledProgress = GDALCreateScaledProgress( 0.5, 1.0, pfnProgress,
681 : * pProgressData );
682 : * GDALDoAnotherOperation( ..., GDALScaledProgress, pScaledProgress );
683 : * GDALDestroyScaledProgress( pScaledProgress );
684 : *
685 : * return ...;
686 : * }
687 : * \endcode
688 : */
689 :
690 798 : void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
691 : GDALProgressFunc pfnProgress,
692 : void * pData )
693 :
694 : {
695 : GDALScaledProgressInfo *psInfo;
696 :
697 : psInfo = (GDALScaledProgressInfo *)
698 798 : CPLCalloc(sizeof(GDALScaledProgressInfo),1);
699 :
700 798 : if( ABS(dfMin-dfMax) < 0.0000001 )
701 0 : dfMax = dfMin + 0.01;
702 :
703 798 : psInfo->pData = pData;
704 798 : psInfo->pfnProgress = pfnProgress;
705 798 : psInfo->dfMin = dfMin;
706 798 : psInfo->dfMax = dfMax;
707 :
708 798 : return (void *) psInfo;
709 : }
710 :
711 : /************************************************************************/
712 : /* GDALDestroyScaledProgress() */
713 : /************************************************************************/
714 :
715 : /**
716 : * \brief Cleanup scaled progress handle.
717 : *
718 : * This function cleans up the data associated with a scaled progress function
719 : * as returned by GADLCreateScaledProgress().
720 : *
721 : * @param pData scaled progress handle returned by GDALCreateScaledProgress().
722 : */
723 :
724 798 : void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
725 :
726 : {
727 798 : CPLFree( pData );
728 798 : }
729 :
730 : /************************************************************************/
731 : /* GDALTermProgress() */
732 : /************************************************************************/
733 :
734 : /**
735 : * \brief Simple progress report to terminal.
736 : *
737 : * This progress reporter prints simple progress report to the
738 : * terminal window. The progress report generally looks something like
739 : * this:
740 :
741 : \verbatim
742 : 0...10...20...30...40...50...60...70...80...90...100 - done.
743 : \endverbatim
744 :
745 : * Every 2.5% of progress another number or period is emitted. Note that
746 : * GDALTermProgress() uses internal static data to keep track of the last
747 : * percentage reported and will get confused if two terminal based progress
748 : * reportings are active at the same time.
749 : *
750 : * The GDALTermProgress() function maintains an internal memory of the
751 : * last percentage complete reported in a static variable, and this makes
752 : * it unsuitable to have multiple GDALTermProgress()'s active eithin a
753 : * single thread or across multiple threads.
754 : *
755 : * @param dfComplete completion ratio from 0.0 to 1.0.
756 : * @param pszMessage optional message.
757 : * @param pProgressArg ignored callback data argument.
758 : *
759 : * @return Always returns TRUE indicating the process should continue.
760 : */
761 :
762 35084 : int CPL_STDCALL GDALTermProgress( double dfComplete, const char *pszMessage,
763 : void * pProgressArg )
764 :
765 : {
766 : static int nLastTick = -1;
767 35084 : int nThisTick = (int) (dfComplete * 40.0);
768 :
769 : (void) pProgressArg;
770 :
771 35084 : nThisTick = MIN(40,MAX(0,nThisTick));
772 :
773 : // Have we started a new progress run?
774 35084 : if( nThisTick < nLastTick && nLastTick >= 39 )
775 14 : nLastTick = -1;
776 :
777 35084 : if( nThisTick <= nLastTick )
778 30572 : return TRUE;
779 :
780 26045 : while( nThisTick > nLastTick )
781 : {
782 17021 : nLastTick++;
783 17021 : if( nLastTick % 4 == 0 )
784 4601 : fprintf( stdout, "%d", (nLastTick / 4) * 10 );
785 : else
786 12420 : fprintf( stdout, "." );
787 : }
788 :
789 4512 : if( nThisTick == 40 )
790 414 : fprintf( stdout, " - done.\n" );
791 : else
792 4098 : fflush( stdout );
793 :
794 4512 : return TRUE;
795 : }
796 :
797 : /************************************************************************/
798 : /* GDALGetRandomRasterSample() */
799 : /************************************************************************/
800 :
801 : int CPL_STDCALL
802 0 : GDALGetRandomRasterSample( GDALRasterBandH hBand, int nSamples,
803 : float *pafSampleBuf )
804 :
805 : {
806 0 : VALIDATE_POINTER1( hBand, "GDALGetRandomRasterSample", 0 );
807 :
808 : GDALRasterBand *poBand;
809 :
810 0 : poBand = (GDALRasterBand *) GDALGetRasterSampleOverview( hBand, nSamples );
811 0 : CPLAssert( NULL != poBand );
812 :
813 : /* -------------------------------------------------------------------- */
814 : /* Figure out the ratio of blocks we will read to get an */
815 : /* approximate value. */
816 : /* -------------------------------------------------------------------- */
817 : int nBlockXSize, nBlockYSize;
818 : int nBlocksPerRow, nBlocksPerColumn;
819 : int nSampleRate;
820 : int bGotNoDataValue;
821 : double dfNoDataValue;
822 0 : int nActualSamples = 0;
823 : int nBlockSampleRate;
824 : int nBlockPixels, nBlockCount;
825 :
826 0 : dfNoDataValue = poBand->GetNoDataValue( &bGotNoDataValue );
827 :
828 0 : poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
829 :
830 0 : nBlocksPerRow = (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
831 0 : nBlocksPerColumn = (poBand->GetYSize() + nBlockYSize - 1) / nBlockYSize;
832 :
833 0 : nBlockPixels = nBlockXSize * nBlockYSize;
834 0 : nBlockCount = nBlocksPerRow * nBlocksPerColumn;
835 :
836 0 : if( nBlocksPerRow == 0 || nBlocksPerColumn == 0 || nBlockPixels == 0
837 : || nBlockCount == 0 )
838 : {
839 : CPLError( CE_Failure, CPLE_AppDefined,
840 : "GDALGetRandomRasterSample(): returning because band"
841 0 : " appears degenerate." );
842 :
843 0 : return FALSE;
844 : }
845 :
846 0 : nSampleRate = (int) MAX(1,sqrt((double) nBlockCount)-2.0);
847 :
848 0 : if( nSampleRate == nBlocksPerRow && nSampleRate > 1 )
849 0 : nSampleRate--;
850 :
851 0 : while( nSampleRate > 1
852 : && ((nBlockCount-1) / nSampleRate + 1) * nBlockPixels < nSamples )
853 0 : nSampleRate--;
854 :
855 0 : if ((nSamples / ((nBlockCount-1) / nSampleRate + 1)) == 0)
856 0 : nBlockSampleRate = 1;
857 : else
858 : nBlockSampleRate =
859 0 : MAX(1,nBlockPixels / (nSamples / ((nBlockCount-1) / nSampleRate + 1)));
860 :
861 0 : for( int iSampleBlock = 0;
862 : iSampleBlock < nBlockCount;
863 : iSampleBlock += nSampleRate )
864 : {
865 0 : double dfValue = 0.0, dfReal, dfImag;
866 0 : int iXBlock, iYBlock, iX, iY, iXValid, iYValid, iRemainder = 0;
867 : GDALRasterBlock *poBlock;
868 :
869 0 : iYBlock = iSampleBlock / nBlocksPerRow;
870 0 : iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
871 :
872 0 : poBlock = poBand->GetLockedBlockRef( iXBlock, iYBlock );
873 0 : if( poBlock == NULL )
874 0 : continue;
875 0 : if( poBlock->GetDataRef() == NULL )
876 : {
877 0 : poBlock->DropLock();
878 0 : continue;
879 : }
880 :
881 0 : if( (iXBlock + 1) * nBlockXSize > poBand->GetXSize() )
882 0 : iXValid = poBand->GetXSize() - iXBlock * nBlockXSize;
883 : else
884 0 : iXValid = nBlockXSize;
885 :
886 0 : if( (iYBlock + 1) * nBlockYSize > poBand->GetYSize() )
887 0 : iYValid = poBand->GetYSize() - iYBlock * nBlockYSize;
888 : else
889 0 : iYValid = nBlockYSize;
890 :
891 0 : for( iY = 0; iY < iYValid; iY++ )
892 : {
893 0 : for( iX = iRemainder; iX < iXValid; iX += nBlockSampleRate )
894 : {
895 : int iOffset;
896 :
897 0 : iOffset = iX + iY * nBlockXSize;
898 0 : switch( poBlock->GetDataType() )
899 : {
900 : case GDT_Byte:
901 0 : dfValue = ((GByte *) poBlock->GetDataRef())[iOffset];
902 0 : break;
903 : case GDT_UInt16:
904 0 : dfValue = ((GUInt16 *) poBlock->GetDataRef())[iOffset];
905 0 : break;
906 : case GDT_Int16:
907 0 : dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset];
908 0 : break;
909 : case GDT_UInt32:
910 0 : dfValue = ((GUInt32 *) poBlock->GetDataRef())[iOffset];
911 0 : break;
912 : case GDT_Int32:
913 0 : dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset];
914 0 : break;
915 : case GDT_Float32:
916 0 : dfValue = ((float *) poBlock->GetDataRef())[iOffset];
917 0 : break;
918 : case GDT_Float64:
919 0 : dfValue = ((double *) poBlock->GetDataRef())[iOffset];
920 0 : break;
921 : case GDT_CInt16:
922 0 : dfReal = ((GInt16 *) poBlock->GetDataRef())[iOffset*2];
923 0 : dfImag = ((GInt16 *) poBlock->GetDataRef())[iOffset*2+1];
924 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
925 0 : break;
926 : case GDT_CInt32:
927 0 : dfReal = ((GInt32 *) poBlock->GetDataRef())[iOffset*2];
928 0 : dfImag = ((GInt32 *) poBlock->GetDataRef())[iOffset*2+1];
929 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
930 0 : break;
931 : case GDT_CFloat32:
932 0 : dfReal = ((float *) poBlock->GetDataRef())[iOffset*2];
933 0 : dfImag = ((float *) poBlock->GetDataRef())[iOffset*2+1];
934 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
935 0 : break;
936 : case GDT_CFloat64:
937 0 : dfReal = ((double *) poBlock->GetDataRef())[iOffset*2];
938 0 : dfImag = ((double *) poBlock->GetDataRef())[iOffset*2+1];
939 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
940 0 : break;
941 : default:
942 0 : CPLAssert( FALSE );
943 : }
944 :
945 0 : if( bGotNoDataValue && dfValue == dfNoDataValue )
946 0 : continue;
947 :
948 0 : if( nActualSamples < nSamples )
949 0 : pafSampleBuf[nActualSamples++] = (float) dfValue;
950 : }
951 :
952 0 : iRemainder = iX - iXValid;
953 : }
954 :
955 0 : poBlock->DropLock();
956 : }
957 :
958 0 : return nActualSamples;
959 : }
960 :
961 : /************************************************************************/
962 : /* GDALInitGCPs() */
963 : /************************************************************************/
964 :
965 19718 : void CPL_STDCALL GDALInitGCPs( int nCount, GDAL_GCP * psGCP )
966 :
967 : {
968 19718 : if( nCount > 0 )
969 : {
970 19648 : VALIDATE_POINTER0( psGCP, "GDALInitGCPs" );
971 : }
972 :
973 52371 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
974 : {
975 32653 : memset( psGCP, 0, sizeof(GDAL_GCP) );
976 32653 : psGCP->pszId = CPLStrdup("");
977 32653 : psGCP->pszInfo = CPLStrdup("");
978 32653 : psGCP++;
979 : }
980 : }
981 :
982 : /************************************************************************/
983 : /* GDALDeinitGCPs() */
984 : /************************************************************************/
985 :
986 6223 : void CPL_STDCALL GDALDeinitGCPs( int nCount, GDAL_GCP * psGCP )
987 :
988 : {
989 6223 : if ( nCount > 0 )
990 : {
991 370 : VALIDATE_POINTER0( psGCP, "GDALDeinitGCPs" );
992 : }
993 :
994 39133 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
995 : {
996 32910 : CPLFree( psGCP->pszId );
997 32910 : CPLFree( psGCP->pszInfo );
998 32910 : psGCP++;
999 : }
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* GDALDuplicateGCPs() */
1004 : /************************************************************************/
1005 :
1006 : GDAL_GCP * CPL_STDCALL
1007 126 : GDALDuplicateGCPs( int nCount, const GDAL_GCP *pasGCPList )
1008 :
1009 : {
1010 : GDAL_GCP *pasReturn;
1011 :
1012 126 : pasReturn = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nCount);
1013 126 : GDALInitGCPs( nCount, pasReturn );
1014 :
1015 390 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
1016 : {
1017 264 : CPLFree( pasReturn[iGCP].pszId );
1018 264 : pasReturn[iGCP].pszId = CPLStrdup( pasGCPList[iGCP].pszId );
1019 :
1020 264 : CPLFree( pasReturn[iGCP].pszInfo );
1021 264 : pasReturn[iGCP].pszInfo = CPLStrdup( pasGCPList[iGCP].pszInfo );
1022 :
1023 264 : pasReturn[iGCP].dfGCPPixel = pasGCPList[iGCP].dfGCPPixel;
1024 264 : pasReturn[iGCP].dfGCPLine = pasGCPList[iGCP].dfGCPLine;
1025 264 : pasReturn[iGCP].dfGCPX = pasGCPList[iGCP].dfGCPX;
1026 264 : pasReturn[iGCP].dfGCPY = pasGCPList[iGCP].dfGCPY;
1027 264 : pasReturn[iGCP].dfGCPZ = pasGCPList[iGCP].dfGCPZ;
1028 : }
1029 :
1030 126 : return pasReturn;
1031 : }
1032 :
1033 : /************************************************************************/
1034 : /* GDALFindAssociatedFile() */
1035 : /************************************************************************/
1036 :
1037 : /**
1038 : * Find file with alternate extension.
1039 : *
1040 : * Finds the file with the indicated extension, substituting it in place
1041 : * of the extension of the base filename. Generally used to search for
1042 : * associated files like world files .RPB files, etc. If necessary, the
1043 : * extension will be tried in both upper and lower case. If a sibling file
1044 : * list is available it will be used instead of doing VSIStatExL() calls to
1045 : * probe the file system.
1046 : *
1047 : * Note that the result is a dynamic CPLString so this method should not
1048 : * be used in a situation where there could be cross heap issues. It is
1049 : * generally imprudent for application built on GDAL to use this function
1050 : * unless they are sure they will always use the same runtime heap as GDAL.
1051 : *
1052 : * @param pszBaseFilename the filename relative to which to search.
1053 : * @param pszExt the target extension in either upper or lower case.
1054 : * @param papszSiblingFiles the list of files in the same directory as
1055 : * pszBaseFilename or NULL if they are not known.
1056 : * @param nFlags special options controlling search. None defined yet, just
1057 : * pass 0.
1058 : *
1059 : * @return an empty string if the target is not found, otherwise the target
1060 : * file with similar path style as the pszBaseFilename.
1061 : */
1062 :
1063 6409 : CPLString GDALFindAssociatedFile( const char *pszBaseFilename,
1064 : const char *pszExt,
1065 : char **papszSiblingFiles,
1066 : int nFlags )
1067 :
1068 : {
1069 : (void) nFlags;
1070 :
1071 6409 : CPLString osTarget = CPLResetExtension( pszBaseFilename, pszExt );
1072 :
1073 6409 : if( papszSiblingFiles == NULL )
1074 : {
1075 : VSIStatBufL sStatBuf;
1076 :
1077 2978 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1078 : {
1079 2953 : CPLString osAltExt = pszExt;
1080 :
1081 2953 : if( islower( pszExt[0] ) )
1082 0 : osAltExt.toupper();
1083 : else
1084 2953 : osAltExt.tolower();
1085 :
1086 2953 : osTarget = CPLResetExtension( pszBaseFilename, osAltExt );
1087 :
1088 2953 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1089 2951 : return "";
1090 : }
1091 : }
1092 : else
1093 : {
1094 : int iSibling = CSLFindString( papszSiblingFiles,
1095 3431 : CPLGetFilename(osTarget) );
1096 3431 : if( iSibling < 0 )
1097 3422 : return "";
1098 :
1099 9 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
1100 9 : osTarget += papszSiblingFiles[iSibling];
1101 : }
1102 :
1103 36 : return osTarget;
1104 : }
1105 :
1106 : /************************************************************************/
1107 : /* GDALLoadOziMapFile() */
1108 : /************************************************************************/
1109 :
1110 : #define MAX_GCP 30
1111 :
1112 1 : int CPL_STDCALL GDALLoadOziMapFile( const char *pszFilename,
1113 : double *padfGeoTransform, char **ppszWKT,
1114 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1115 :
1116 :
1117 : {
1118 : char **papszLines;
1119 1 : int iLine, nLines=0;
1120 1 : int nCoordinateCount = 0;
1121 : GDAL_GCP asGCPs[MAX_GCP];
1122 :
1123 1 : VALIDATE_POINTER1( pszFilename, "GDALLoadOziMapFile", FALSE );
1124 1 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadOziMapFile", FALSE );
1125 1 : VALIDATE_POINTER1( pnGCPCount, "GDALLoadOziMapFile", FALSE );
1126 1 : VALIDATE_POINTER1( ppasGCPs, "GDALLoadOziMapFile", FALSE );
1127 :
1128 1 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
1129 :
1130 1 : if ( !papszLines )
1131 0 : return FALSE;
1132 :
1133 1 : nLines = CSLCount( papszLines );
1134 :
1135 : // Check the OziExplorer Map file signature
1136 2 : if ( nLines < 5
1137 1 : || !EQUALN(papszLines[0], "OziExplorer Map Data File Version ", 34) )
1138 : {
1139 : CPLError( CE_Failure, CPLE_AppDefined,
1140 : "GDALLoadOziMapFile(): file \"%s\" is not in OziExplorer Map format.",
1141 0 : pszFilename );
1142 0 : CSLDestroy( papszLines );
1143 0 : return FALSE;
1144 : }
1145 :
1146 1 : OGRSpatialReference oSRS;
1147 1 : OGRErr eErr = OGRERR_NONE;
1148 :
1149 : /* The Map Scale Factor has been introduced recently on the 6th line */
1150 : /* and is a trick that is used to just change that line without changing */
1151 : /* the rest of the MAP file but providing an imagery that is smaller or larger */
1152 : /* so we have to correct the pixel/line values read in the .MAP file so they */
1153 : /* match the actual imagery dimension. Well, this is a bad summary of what */
1154 : /* is explained at http://tech.groups.yahoo.com/group/OziUsers-L/message/12484 */
1155 1 : double dfMSF = 1;
1156 :
1157 52 : for ( iLine = 5; iLine < nLines; iLine++ )
1158 : {
1159 51 : if ( EQUALN(papszLines[iLine], "MSF,", 4) )
1160 : {
1161 0 : dfMSF = atof(papszLines[iLine] + 4);
1162 0 : if (dfMSF <= 0.01) /* Suspicious values */
1163 : {
1164 0 : CPLDebug("OZI", "Suspicious MSF value : %s", papszLines[iLine]);
1165 0 : dfMSF = 1;
1166 : }
1167 : }
1168 : }
1169 :
1170 1 : eErr = oSRS.importFromOzi( papszLines );
1171 1 : if ( eErr == OGRERR_NONE )
1172 : {
1173 1 : if ( ppszWKT != NULL )
1174 1 : oSRS.exportToWkt( ppszWKT );
1175 : }
1176 :
1177 : // Iterate all lines in the MAP-file
1178 52 : for ( iLine = 5; iLine < nLines; iLine++ )
1179 : {
1180 51 : char **papszTok = NULL;
1181 :
1182 51 : papszTok = CSLTokenizeString2( papszLines[iLine], ",",
1183 : CSLT_ALLOWEMPTYTOKENS
1184 : | CSLT_STRIPLEADSPACES
1185 102 : | CSLT_STRIPENDSPACES );
1186 :
1187 51 : if ( CSLCount(papszTok) < 12 )
1188 : {
1189 21 : CSLDestroy(papszTok);
1190 21 : continue;
1191 : }
1192 :
1193 94 : if ( CSLCount(papszTok) >= 17
1194 30 : && EQUALN(papszTok[0], "Point", 5)
1195 30 : && !EQUAL(papszTok[2], "")
1196 4 : && !EQUAL(papszTok[3], "")
1197 : && nCoordinateCount < MAX_GCP )
1198 : {
1199 4 : int bReadOk = FALSE;
1200 4 : double dfLon = 0., dfLat = 0.;
1201 :
1202 20 : if ( !EQUAL(papszTok[6], "")
1203 4 : && !EQUAL(papszTok[7], "")
1204 4 : && !EQUAL(papszTok[9], "")
1205 4 : && !EQUAL(papszTok[10], "") )
1206 : {
1207 : // Set geographical coordinates of the pixels
1208 4 : dfLon = CPLAtofM(papszTok[9]) + CPLAtofM(papszTok[10]) / 60.0;
1209 4 : dfLat = CPLAtofM(papszTok[6]) + CPLAtofM(papszTok[7]) / 60.0;
1210 4 : if ( EQUAL(papszTok[11], "W") )
1211 1 : dfLon = -dfLon;
1212 4 : if ( EQUAL(papszTok[8], "S") )
1213 0 : dfLat = -dfLat;
1214 :
1215 : // Transform from the geographical coordinates into projected
1216 : // coordinates.
1217 4 : if ( eErr == OGRERR_NONE )
1218 : {
1219 4 : OGRSpatialReference *poLatLong = NULL;
1220 4 : OGRCoordinateTransformation *poTransform = NULL;
1221 :
1222 4 : poLatLong = oSRS.CloneGeogCS();
1223 4 : if ( poLatLong )
1224 : {
1225 4 : poTransform = OGRCreateCoordinateTransformation( poLatLong, &oSRS );
1226 4 : if ( poTransform )
1227 : {
1228 4 : bReadOk = poTransform->Transform( 1, &dfLon, &dfLat );
1229 4 : delete poTransform;
1230 : }
1231 4 : delete poLatLong;
1232 : }
1233 : }
1234 : }
1235 0 : else if ( !EQUAL(papszTok[14], "")
1236 0 : && !EQUAL(papszTok[15], "") )
1237 : {
1238 : // Set cartesian coordinates of the pixels.
1239 0 : dfLon = CPLAtofM(papszTok[14]);
1240 0 : dfLat = CPLAtofM(papszTok[15]);
1241 0 : bReadOk = TRUE;
1242 :
1243 : //if ( EQUAL(papszTok[16], "S") )
1244 : // dfLat = -dfLat;
1245 : }
1246 :
1247 4 : if ( bReadOk )
1248 : {
1249 4 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1250 :
1251 : // Set pixel/line part
1252 4 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]) / dfMSF;
1253 4 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]) / dfMSF;
1254 :
1255 4 : asGCPs[nCoordinateCount].dfGCPX = dfLon;
1256 4 : asGCPs[nCoordinateCount].dfGCPY = dfLat;
1257 :
1258 4 : nCoordinateCount++;
1259 : }
1260 : }
1261 :
1262 30 : CSLDestroy( papszTok );
1263 : }
1264 :
1265 1 : CSLDestroy( papszLines );
1266 :
1267 1 : if ( nCoordinateCount == 0 )
1268 : {
1269 : CPLDebug( "GDAL", "GDALLoadOziMapFile(\"%s\") did read no GCPs.",
1270 0 : pszFilename );
1271 0 : return FALSE;
1272 : }
1273 :
1274 : /* -------------------------------------------------------------------- */
1275 : /* Try to convert the GCPs into a geotransform definition, if */
1276 : /* possible. Otherwise we will need to use them as GCPs. */
1277 : /* -------------------------------------------------------------------- */
1278 1 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1279 : CSLTestBoolean(CPLGetConfigOption("OZI_APPROX_GEOTRANSFORM", "NO")) ) )
1280 : {
1281 1 : if ( pnGCPCount && ppasGCPs )
1282 : {
1283 : CPLDebug( "GDAL",
1284 : "GDALLoadOziMapFile(%s) found file, wasn't able to derive a\n"
1285 : "first order geotransform. Using points as GCPs.",
1286 1 : pszFilename );
1287 :
1288 : *ppasGCPs = (GDAL_GCP *)
1289 1 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1290 1 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1291 1 : *pnGCPCount = nCoordinateCount;
1292 : }
1293 : }
1294 : else
1295 : {
1296 0 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1297 : }
1298 :
1299 1 : return TRUE;
1300 : }
1301 :
1302 : #undef MAX_GCP
1303 :
1304 : /************************************************************************/
1305 : /* GDALReadOziMapFile() */
1306 : /************************************************************************/
1307 :
1308 0 : int CPL_STDCALL GDALReadOziMapFile( const char * pszBaseFilename,
1309 : double *padfGeoTransform, char **ppszWKT,
1310 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1311 :
1312 :
1313 : {
1314 : const char *pszOzi;
1315 : FILE *fpOzi;
1316 :
1317 : /* -------------------------------------------------------------------- */
1318 : /* Try lower case, then upper case. */
1319 : /* -------------------------------------------------------------------- */
1320 0 : pszOzi = CPLResetExtension( pszBaseFilename, "map" );
1321 :
1322 0 : fpOzi = VSIFOpen( pszOzi, "rt" );
1323 :
1324 0 : if ( fpOzi == NULL && VSIIsCaseSensitiveFS(pszOzi) )
1325 : {
1326 0 : pszOzi = CPLResetExtension( pszBaseFilename, "MAP" );
1327 0 : fpOzi = VSIFOpen( pszOzi, "rt" );
1328 : }
1329 :
1330 0 : if ( fpOzi == NULL )
1331 0 : return FALSE;
1332 :
1333 0 : VSIFClose( fpOzi );
1334 :
1335 : /* -------------------------------------------------------------------- */
1336 : /* We found the file, now load and parse it. */
1337 : /* -------------------------------------------------------------------- */
1338 : return GDALLoadOziMapFile( pszOzi, padfGeoTransform, ppszWKT,
1339 0 : pnGCPCount, ppasGCPs );
1340 : }
1341 :
1342 : /************************************************************************/
1343 : /* GDALLoadTabFile() */
1344 : /* */
1345 : /* Helper function for translator implementators wanting */
1346 : /* support for MapInfo .tab-files. */
1347 : /************************************************************************/
1348 :
1349 : #define MAX_GCP 256
1350 :
1351 2 : int CPL_STDCALL GDALLoadTabFile( const char *pszFilename,
1352 : double *padfGeoTransform, char **ppszWKT,
1353 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1354 :
1355 :
1356 : {
1357 : char **papszLines;
1358 2 : char **papszTok=NULL;
1359 2 : int bTypeRasterFound = FALSE;
1360 2 : int bInsideTableDef = FALSE;
1361 2 : int iLine, numLines=0;
1362 2 : int nCoordinateCount = 0;
1363 : GDAL_GCP asGCPs[MAX_GCP];
1364 :
1365 2 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
1366 :
1367 2 : if ( !papszLines )
1368 0 : return FALSE;
1369 :
1370 2 : numLines = CSLCount(papszLines);
1371 :
1372 : // Iterate all lines in the TAB-file
1373 28 : for(iLine=0; iLine<numLines; iLine++)
1374 : {
1375 26 : CSLDestroy(papszTok);
1376 26 : papszTok = CSLTokenizeStringComplex(papszLines[iLine], " \t(),;",
1377 52 : TRUE, FALSE);
1378 :
1379 26 : if (CSLCount(papszTok) < 2)
1380 4 : continue;
1381 :
1382 : // Did we find table definition
1383 24 : if (EQUAL(papszTok[0], "Definition") && EQUAL(papszTok[1], "Table") )
1384 : {
1385 2 : bInsideTableDef = TRUE;
1386 : }
1387 22 : else if (bInsideTableDef && (EQUAL(papszTok[0], "Type")) )
1388 : {
1389 : // Only RASTER-type will be handled
1390 2 : if (EQUAL(papszTok[1], "RASTER"))
1391 : {
1392 2 : bTypeRasterFound = TRUE;
1393 : }
1394 : else
1395 : {
1396 0 : CSLDestroy(papszTok);
1397 0 : CSLDestroy(papszLines);
1398 0 : return FALSE;
1399 : }
1400 : }
1401 28 : else if (bTypeRasterFound && bInsideTableDef
1402 : && CSLCount(papszTok) > 4
1403 10 : && EQUAL(papszTok[4], "Label")
1404 : && nCoordinateCount < MAX_GCP )
1405 : {
1406 8 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1407 :
1408 8 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
1409 8 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
1410 8 : asGCPs[nCoordinateCount].dfGCPX = CPLAtofM(papszTok[0]);
1411 8 : asGCPs[nCoordinateCount].dfGCPY = CPLAtofM(papszTok[1]);
1412 8 : if( papszTok[5] != NULL )
1413 : {
1414 8 : CPLFree( asGCPs[nCoordinateCount].pszId );
1415 8 : asGCPs[nCoordinateCount].pszId = CPLStrdup(papszTok[5]);
1416 : }
1417 :
1418 8 : nCoordinateCount++;
1419 : }
1420 16 : else if( bTypeRasterFound && bInsideTableDef
1421 4 : && EQUAL(papszTok[0],"CoordSys")
1422 : && ppszWKT != NULL )
1423 : {
1424 2 : OGRSpatialReference oSRS;
1425 :
1426 2 : if( oSRS.importFromMICoordSys( papszLines[iLine] ) == OGRERR_NONE )
1427 2 : oSRS.exportToWkt( ppszWKT );
1428 : }
1429 10 : else if( EQUAL(papszTok[0],"Units")
1430 : && CSLCount(papszTok) > 1
1431 2 : && EQUAL(papszTok[1],"degree") )
1432 : {
1433 : /*
1434 : ** If we have units of "degree", but a projected coordinate
1435 : ** system we need to convert it to geographic. See to01_02.TAB.
1436 : */
1437 0 : if( ppszWKT != NULL && *ppszWKT != NULL
1438 : && EQUALN(*ppszWKT,"PROJCS",6) )
1439 : {
1440 0 : OGRSpatialReference oSRS, oSRSGeogCS;
1441 0 : char *pszSrcWKT = *ppszWKT;
1442 :
1443 0 : oSRS.importFromWkt( &pszSrcWKT );
1444 0 : oSRSGeogCS.CopyGeogCSFrom( &oSRS );
1445 0 : CPLFree( *ppszWKT );
1446 0 : oSRSGeogCS.exportToWkt( ppszWKT );
1447 : }
1448 : }
1449 :
1450 : }
1451 :
1452 2 : CSLDestroy(papszTok);
1453 2 : CSLDestroy(papszLines);
1454 :
1455 2 : if( nCoordinateCount == 0 )
1456 : {
1457 : CPLDebug( "GDAL", "GDALLoadTabFile(%s) did not get any GCPs.",
1458 0 : pszFilename );
1459 0 : return FALSE;
1460 : }
1461 :
1462 : /* -------------------------------------------------------------------- */
1463 : /* Try to convert the GCPs into a geotransform definition, if */
1464 : /* possible. Otherwise we will need to use them as GCPs. */
1465 : /* -------------------------------------------------------------------- */
1466 2 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1467 : FALSE ) )
1468 : {
1469 0 : if (pnGCPCount && ppasGCPs)
1470 : {
1471 : CPLDebug( "GDAL",
1472 : "GDALLoadTabFile(%s) found file, wasn't able to derive a\n"
1473 : "first order geotransform. Using points as GCPs.",
1474 0 : pszFilename );
1475 :
1476 : *ppasGCPs = (GDAL_GCP *)
1477 0 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1478 0 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1479 0 : *pnGCPCount = nCoordinateCount;
1480 : }
1481 : }
1482 : else
1483 : {
1484 2 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1485 : }
1486 :
1487 2 : return TRUE;
1488 : }
1489 :
1490 : #undef MAX_GCP
1491 :
1492 : /************************************************************************/
1493 : /* GDALReadTabFile() */
1494 : /* */
1495 : /* Helper function for translator implementators wanting */
1496 : /* support for MapInfo .tab-files. */
1497 : /************************************************************************/
1498 :
1499 0 : int CPL_STDCALL GDALReadTabFile( const char * pszBaseFilename,
1500 : double *padfGeoTransform, char **ppszWKT,
1501 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1502 :
1503 :
1504 : {
1505 : return GDALReadTabFile2(pszBaseFilename, padfGeoTransform,
1506 : ppszWKT, pnGCPCount, ppasGCPs,
1507 0 : NULL, NULL);
1508 : }
1509 :
1510 :
1511 1133 : int GDALReadTabFile2( const char * pszBaseFilename,
1512 : double *padfGeoTransform, char **ppszWKT,
1513 : int *pnGCPCount, GDAL_GCP **ppasGCPs,
1514 : char** papszSiblingFiles, char** ppszTabFileNameOut )
1515 : {
1516 : const char *pszTAB;
1517 : VSILFILE *fpTAB;
1518 :
1519 1133 : if (ppszTabFileNameOut)
1520 1133 : *ppszTabFileNameOut = NULL;
1521 :
1522 1133 : pszTAB = CPLResetExtension( pszBaseFilename, "tab" );
1523 :
1524 1133 : if (papszSiblingFiles)
1525 : {
1526 1034 : int iSibling = CSLFindString(papszSiblingFiles, CPLGetFilename(pszTAB));
1527 1034 : if (iSibling >= 0)
1528 : {
1529 2 : CPLString osTabFilename = pszBaseFilename;
1530 : osTabFilename.resize(strlen(pszBaseFilename) -
1531 2 : strlen(CPLGetFilename(pszBaseFilename)));
1532 2 : osTabFilename += papszSiblingFiles[iSibling];
1533 2 : if ( GDALLoadTabFile(osTabFilename, padfGeoTransform, ppszWKT,
1534 : pnGCPCount, ppasGCPs ) )
1535 : {
1536 2 : if (ppszTabFileNameOut)
1537 2 : *ppszTabFileNameOut = CPLStrdup(osTabFilename);
1538 2 : return TRUE;
1539 0 : }
1540 : }
1541 1032 : return FALSE;
1542 : }
1543 :
1544 : /* -------------------------------------------------------------------- */
1545 : /* Try lower case, then upper case. */
1546 : /* -------------------------------------------------------------------- */
1547 :
1548 99 : fpTAB = VSIFOpenL( pszTAB, "rt" );
1549 :
1550 99 : if( fpTAB == NULL && VSIIsCaseSensitiveFS(pszTAB) )
1551 : {
1552 99 : pszTAB = CPLResetExtension( pszBaseFilename, "TAB" );
1553 99 : fpTAB = VSIFOpenL( pszTAB, "rt" );
1554 : }
1555 :
1556 99 : if( fpTAB == NULL )
1557 99 : return FALSE;
1558 :
1559 0 : VSIFCloseL( fpTAB );
1560 :
1561 : /* -------------------------------------------------------------------- */
1562 : /* We found the file, now load and parse it. */
1563 : /* -------------------------------------------------------------------- */
1564 0 : if (GDALLoadTabFile( pszTAB, padfGeoTransform, ppszWKT,
1565 : pnGCPCount, ppasGCPs ) )
1566 : {
1567 0 : if (ppszTabFileNameOut)
1568 0 : *ppszTabFileNameOut = CPLStrdup(pszTAB);
1569 0 : return TRUE;
1570 : }
1571 0 : return FALSE;
1572 : }
1573 :
1574 : /************************************************************************/
1575 : /* GDALLoadWorldFile() */
1576 : /************************************************************************/
1577 :
1578 : /**
1579 : * \brief Read ESRI world file.
1580 : *
1581 : * This function reads an ESRI style world file, and formats a geotransform
1582 : * from its contents.
1583 : *
1584 : * The world file contains an affine transformation with the parameters
1585 : * in a different order than in a geotransform array.
1586 : *
1587 : * <ul>
1588 : * <li> geotransform[1] : width of pixel
1589 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1590 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1591 : * <li> geotransform[5] : height of pixel (but negative)
1592 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1593 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1594 : * </ul>
1595 : *
1596 : * @param pszFilename the world file name.
1597 : * @param padfGeoTransform the six double array into which the
1598 : * geotransformation should be placed.
1599 : *
1600 : * @return TRUE on success or FALSE on failure.
1601 : */
1602 :
1603 : int CPL_STDCALL
1604 24 : GDALLoadWorldFile( const char *pszFilename, double *padfGeoTransform )
1605 :
1606 : {
1607 : char **papszLines;
1608 :
1609 24 : VALIDATE_POINTER1( pszFilename, "GDALLoadWorldFile", FALSE );
1610 24 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadWorldFile", FALSE );
1611 :
1612 24 : papszLines = CSLLoad2( pszFilename, 100, 100, NULL );
1613 :
1614 24 : if ( !papszLines )
1615 0 : return FALSE;
1616 :
1617 : double world[6];
1618 : // reads the first 6 non-empty lines
1619 24 : int nLines = 0;
1620 24 : int nLinesCount = CSLCount(papszLines);
1621 24 : for( int i = 0; i < nLinesCount && nLines < 6; ++i )
1622 : {
1623 144 : CPLString line(papszLines[i]);
1624 144 : if( line.Trim().empty() )
1625 0 : continue;
1626 :
1627 144 : world[nLines] = CPLAtofM(line);
1628 144 : ++nLines;
1629 : }
1630 :
1631 72 : if( nLines == 6
1632 24 : && (world[0] != 0.0 || world[2] != 0.0)
1633 24 : && (world[3] != 0.0 || world[1] != 0.0) )
1634 : {
1635 24 : padfGeoTransform[0] = world[4];
1636 24 : padfGeoTransform[1] = world[0];
1637 24 : padfGeoTransform[2] = world[2];
1638 24 : padfGeoTransform[3] = world[5];
1639 24 : padfGeoTransform[4] = world[1];
1640 24 : padfGeoTransform[5] = world[3];
1641 :
1642 : // correct for center of pixel vs. top left of pixel
1643 24 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[1];
1644 24 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[2];
1645 24 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[4];
1646 24 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[5];
1647 :
1648 24 : CSLDestroy(papszLines);
1649 :
1650 24 : return TRUE;
1651 : }
1652 : else
1653 : {
1654 : CPLDebug( "GDAL",
1655 : "GDALLoadWorldFile(%s) found file, but it was corrupt.",
1656 0 : pszFilename );
1657 0 : CSLDestroy(papszLines);
1658 0 : return FALSE;
1659 : }
1660 : }
1661 :
1662 : /************************************************************************/
1663 : /* GDALReadWorldFile() */
1664 : /************************************************************************/
1665 :
1666 : /**
1667 : * \brief Read ESRI world file.
1668 : *
1669 : * This function reads an ESRI style world file, and formats a geotransform
1670 : * from its contents. It does the same as GDALLoadWorldFile() function, but
1671 : * it will form the filename for the worldfile from the filename of the raster
1672 : * file referred and the suggested extension. If no extension is provided,
1673 : * the code will internally try the unix style and windows style world file
1674 : * extensions (eg. for .tif these would be .tfw and .tifw).
1675 : *
1676 : * The world file contains an affine transformation with the parameters
1677 : * in a different order than in a geotransform array.
1678 : *
1679 : * <ul>
1680 : * <li> geotransform[1] : width of pixel
1681 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1682 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1683 : * <li> geotransform[5] : height of pixel (but negative)
1684 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1685 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1686 : * </ul>
1687 : *
1688 : * @param pszBaseFilename the target raster file.
1689 : * @param pszExtension the extension to use (ie. ".wld") or NULL to derive it
1690 : * from the pszBaseFilename
1691 : * @param padfGeoTransform the six double array into which the
1692 : * geotransformation should be placed.
1693 : *
1694 : * @return TRUE on success or FALSE on failure.
1695 : */
1696 :
1697 : int CPL_STDCALL
1698 1104 : GDALReadWorldFile( const char *pszBaseFilename, const char *pszExtension,
1699 : double *padfGeoTransform )
1700 :
1701 : {
1702 : return GDALReadWorldFile2(pszBaseFilename, pszExtension,
1703 1104 : padfGeoTransform, NULL, NULL);
1704 : }
1705 :
1706 6201 : int GDALReadWorldFile2( const char *pszBaseFilename, const char *pszExtension,
1707 : double *padfGeoTransform, char** papszSiblingFiles,
1708 : char** ppszWorldFileNameOut )
1709 : {
1710 : const char *pszTFW;
1711 : char szExtUpper[32], szExtLower[32];
1712 : int i;
1713 :
1714 6201 : VALIDATE_POINTER1( pszBaseFilename, "GDALReadWorldFile", FALSE );
1715 6201 : VALIDATE_POINTER1( padfGeoTransform, "GDALReadWorldFile", FALSE );
1716 :
1717 6201 : if (ppszWorldFileNameOut)
1718 4530 : *ppszWorldFileNameOut = NULL;
1719 :
1720 : /* -------------------------------------------------------------------- */
1721 : /* If we aren't given an extension, try both the unix and */
1722 : /* windows style extensions. */
1723 : /* -------------------------------------------------------------------- */
1724 6201 : if( pszExtension == NULL )
1725 : {
1726 : char szDerivedExtension[100];
1727 1431 : std::string oBaseExt = CPLGetExtension( pszBaseFilename );
1728 :
1729 2862 : if( oBaseExt.length() < 2 )
1730 120 : return FALSE;
1731 :
1732 : // windows version - first + last + 'w'
1733 1311 : szDerivedExtension[0] = oBaseExt[0];
1734 1311 : szDerivedExtension[1] = oBaseExt[oBaseExt.length()-1];
1735 1311 : szDerivedExtension[2] = 'w';
1736 1311 : szDerivedExtension[3] = '\0';
1737 :
1738 1311 : if( GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
1739 : padfGeoTransform, papszSiblingFiles,
1740 : ppszWorldFileNameOut ) )
1741 10 : return TRUE;
1742 :
1743 : // unix version - extension + 'w'
1744 1301 : if( oBaseExt.length() > sizeof(szDerivedExtension)-2 )
1745 0 : return FALSE;
1746 :
1747 1301 : strcpy( szDerivedExtension, oBaseExt.c_str() );
1748 1301 : strcat( szDerivedExtension, "w" );
1749 : return GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
1750 : padfGeoTransform, papszSiblingFiles,
1751 1301 : ppszWorldFileNameOut );
1752 : }
1753 :
1754 : /* -------------------------------------------------------------------- */
1755 : /* Skip the leading period in the extension if there is one. */
1756 : /* -------------------------------------------------------------------- */
1757 4770 : if( *pszExtension == '.' )
1758 367 : pszExtension++;
1759 :
1760 : /* -------------------------------------------------------------------- */
1761 : /* Generate upper and lower case versions of the extension. */
1762 : /* -------------------------------------------------------------------- */
1763 4770 : CPLStrlcpy( szExtUpper, pszExtension, sizeof(szExtUpper) );
1764 4770 : CPLStrlcpy( szExtLower, pszExtension, sizeof(szExtLower) );
1765 :
1766 20385 : for( i = 0; szExtUpper[i] != '\0'; i++ )
1767 : {
1768 15615 : szExtUpper[i] = (char) toupper(szExtUpper[i]);
1769 15615 : szExtLower[i] = (char) tolower(szExtLower[i]);
1770 : }
1771 :
1772 : VSIStatBufL sStatBuf;
1773 : int bGotTFW;
1774 :
1775 4770 : pszTFW = CPLResetExtension( pszBaseFilename, szExtLower );
1776 :
1777 4770 : if (papszSiblingFiles)
1778 : {
1779 3210 : int iSibling = CSLFindString(papszSiblingFiles, CPLGetFilename(pszTFW));
1780 3210 : if (iSibling >= 0)
1781 : {
1782 13 : CPLString osTFWFilename = pszBaseFilename;
1783 : osTFWFilename.resize(strlen(pszBaseFilename) -
1784 13 : strlen(CPLGetFilename(pszBaseFilename)));
1785 13 : osTFWFilename += papszSiblingFiles[iSibling];
1786 13 : if (GDALLoadWorldFile( osTFWFilename, padfGeoTransform ))
1787 : {
1788 13 : if (ppszWorldFileNameOut)
1789 13 : *ppszWorldFileNameOut = CPLStrdup(osTFWFilename);
1790 13 : return TRUE;
1791 0 : }
1792 : }
1793 3197 : return FALSE;
1794 : }
1795 :
1796 : /* -------------------------------------------------------------------- */
1797 : /* Try lower case, then upper case. */
1798 : /* -------------------------------------------------------------------- */
1799 :
1800 1560 : bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
1801 :
1802 1560 : if( !bGotTFW && VSIIsCaseSensitiveFS(pszTFW) )
1803 : {
1804 1549 : pszTFW = CPLResetExtension( pszBaseFilename, szExtUpper );
1805 1549 : bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
1806 : }
1807 :
1808 1560 : if( !bGotTFW )
1809 1549 : return FALSE;
1810 :
1811 : /* -------------------------------------------------------------------- */
1812 : /* We found the file, now load and parse it. */
1813 : /* -------------------------------------------------------------------- */
1814 11 : if (GDALLoadWorldFile( pszTFW, padfGeoTransform ))
1815 : {
1816 11 : if (ppszWorldFileNameOut)
1817 3 : *ppszWorldFileNameOut = CPLStrdup(pszTFW);
1818 11 : return TRUE;
1819 : }
1820 0 : return FALSE;
1821 : }
1822 :
1823 : /************************************************************************/
1824 : /* GDALWriteWorldFile() */
1825 : /* */
1826 : /* Helper function for translator implementators wanting */
1827 : /* support for ESRI world files. */
1828 : /************************************************************************/
1829 :
1830 : /**
1831 : * \brief Write ESRI world file.
1832 : *
1833 : * This function writes an ESRI style world file from the passed geotransform.
1834 : *
1835 : * The world file contains an affine transformation with the parameters
1836 : * in a different order than in a geotransform array.
1837 : *
1838 : * <ul>
1839 : * <li> geotransform[1] : width of pixel
1840 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1841 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1842 : * <li> geotransform[5] : height of pixel (but negative)
1843 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1844 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1845 : * </ul>
1846 : *
1847 : * @param pszBaseFilename the target raster file.
1848 : * @param pszExtension the extension to use (ie. ".wld"). Must not be NULL
1849 : * @param padfGeoTransform the six double array from which the
1850 : * geotransformation should be read.
1851 : *
1852 : * @return TRUE on success or FALSE on failure.
1853 : */
1854 :
1855 : int CPL_STDCALL
1856 7 : GDALWriteWorldFile( const char * pszBaseFilename, const char *pszExtension,
1857 : double *padfGeoTransform )
1858 :
1859 : {
1860 7 : VALIDATE_POINTER1( pszBaseFilename, "GDALWriteWorldFile", FALSE );
1861 7 : VALIDATE_POINTER1( pszExtension, "GDALWriteWorldFile", FALSE );
1862 7 : VALIDATE_POINTER1( padfGeoTransform, "GDALWriteWorldFile", FALSE );
1863 :
1864 : /* -------------------------------------------------------------------- */
1865 : /* Prepare the text to write to the file. */
1866 : /* -------------------------------------------------------------------- */
1867 7 : CPLString osTFWText;
1868 :
1869 : osTFWText.Printf( "%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n",
1870 : padfGeoTransform[1],
1871 : padfGeoTransform[4],
1872 : padfGeoTransform[2],
1873 : padfGeoTransform[5],
1874 7 : padfGeoTransform[0]
1875 7 : + 0.5 * padfGeoTransform[1]
1876 7 : + 0.5 * padfGeoTransform[2],
1877 7 : padfGeoTransform[3]
1878 7 : + 0.5 * padfGeoTransform[4]
1879 21 : + 0.5 * padfGeoTransform[5] );
1880 :
1881 : /* -------------------------------------------------------------------- */
1882 : /* Update extention, and write to disk. */
1883 : /* -------------------------------------------------------------------- */
1884 : const char *pszTFW;
1885 : VSILFILE *fpTFW;
1886 :
1887 7 : pszTFW = CPLResetExtension( pszBaseFilename, pszExtension );
1888 7 : fpTFW = VSIFOpenL( pszTFW, "wt" );
1889 7 : if( fpTFW == NULL )
1890 0 : return FALSE;
1891 :
1892 7 : VSIFWriteL( (void *) osTFWText.c_str(), 1, osTFWText.size(), fpTFW );
1893 7 : VSIFCloseL( fpTFW );
1894 :
1895 7 : return TRUE;
1896 : }
1897 :
1898 : /************************************************************************/
1899 : /* GDALVersionInfo() */
1900 : /************************************************************************/
1901 :
1902 : /**
1903 : * \brief Get runtime version information.
1904 : *
1905 : * Available pszRequest values:
1906 : * <ul>
1907 : * <li> "VERSION_NUM": Returns GDAL_VERSION_NUM formatted as a string. ie. "1170"
1908 : * Note: starting with GDAL 1.10, this string will be longer than 4 characters.
1909 : * <li> "RELEASE_DATE": Returns GDAL_RELEASE_DATE formatted as a string.
1910 : * ie. "20020416".
1911 : * <li> "RELEASE_NAME": Returns the GDAL_RELEASE_NAME. ie. "1.1.7"
1912 : * <li> "--version": Returns one line version message suitable for use in
1913 : * response to --version requests. ie. "GDAL 1.1.7, released 2002/04/16"
1914 : * <li> "LICENCE": Returns the content of the LICENSE.TXT file from the GDAL_DATA directory.
1915 : * Before GDAL 1.7.0, the returned string was leaking memory but this is now resolved.
1916 : * So the result should not been freed by the caller.
1917 : * <li> "BUILD_INFO": List of NAME=VALUE pairs separated by newlines with
1918 : * information on build time options.
1919 : * </ul>
1920 : *
1921 : * @param pszRequest the type of version info desired, as listed above.
1922 : *
1923 : * @return an internal string containing the requested information.
1924 : */
1925 :
1926 2548 : const char * CPL_STDCALL GDALVersionInfo( const char *pszRequest )
1927 :
1928 : {
1929 : /* -------------------------------------------------------------------- */
1930 : /* Try to capture as much build information as practical. */
1931 : /* -------------------------------------------------------------------- */
1932 2548 : if( pszRequest != NULL && EQUAL(pszRequest,"BUILD_INFO") )
1933 : {
1934 1 : CPLString osBuildInfo;
1935 :
1936 : #ifdef ESRI_BUILD
1937 : osBuildInfo += "ESRI_BUILD=YES\n";
1938 : #endif
1939 : #ifdef PAM_ENABLED
1940 1 : osBuildInfo += "PAM_ENABLED=YES\n";
1941 : #endif
1942 : #ifdef OGR_ENABLED
1943 1 : osBuildInfo += "OGR_ENABLED=YES\n";
1944 : #endif
1945 :
1946 1 : CPLFree(CPLGetTLS(CTLS_VERSIONINFO));
1947 1 : CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osBuildInfo), TRUE );
1948 1 : return (char *) CPLGetTLS(CTLS_VERSIONINFO);
1949 : }
1950 :
1951 : /* -------------------------------------------------------------------- */
1952 : /* LICENSE is a special case. We try to find and read the */
1953 : /* LICENSE.TXT file from the GDAL_DATA directory and return it */
1954 : /* -------------------------------------------------------------------- */
1955 2547 : if( pszRequest != NULL && EQUAL(pszRequest,"LICENSE") )
1956 : {
1957 0 : char* pszResultLicence = (char*) CPLGetTLS( CTLS_VERSIONINFO_LICENCE );
1958 0 : if( pszResultLicence != NULL )
1959 : {
1960 0 : return pszResultLicence;
1961 : }
1962 :
1963 0 : const char *pszFilename = CPLFindFile( "etc", "LICENSE.TXT" );
1964 0 : VSILFILE *fp = NULL;
1965 : int nLength;
1966 :
1967 0 : if( pszFilename != NULL )
1968 0 : fp = VSIFOpenL( pszFilename, "r" );
1969 :
1970 0 : if( fp != NULL )
1971 : {
1972 0 : VSIFSeekL( fp, 0, SEEK_END );
1973 0 : nLength = (int) VSIFTellL( fp ) + 1;
1974 0 : VSIFSeekL( fp, SEEK_SET, 0 );
1975 :
1976 0 : pszResultLicence = (char *) VSICalloc(1,nLength);
1977 0 : if (pszResultLicence)
1978 0 : VSIFReadL( pszResultLicence, 1, nLength-1, fp );
1979 :
1980 0 : VSIFCloseL( fp );
1981 : }
1982 :
1983 0 : if (!pszResultLicence)
1984 : {
1985 : pszResultLicence = CPLStrdup(
1986 : "GDAL/OGR is released under the MIT/X license.\n"
1987 : "The LICENSE.TXT distributed with GDAL/OGR should\n"
1988 0 : "contain additional details.\n" );
1989 : }
1990 :
1991 0 : CPLSetTLS( CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE );
1992 0 : return pszResultLicence;
1993 : }
1994 :
1995 : /* -------------------------------------------------------------------- */
1996 : /* All other strings are fairly small. */
1997 : /* -------------------------------------------------------------------- */
1998 2547 : CPLString osVersionInfo;
1999 :
2000 4961 : if( pszRequest == NULL || EQUAL(pszRequest,"VERSION_NUM") )
2001 2414 : osVersionInfo.Printf( "%d", GDAL_VERSION_NUM );
2002 133 : else if( EQUAL(pszRequest,"RELEASE_DATE") )
2003 0 : osVersionInfo.Printf( "%d", GDAL_RELEASE_DATE );
2004 133 : else if( EQUAL(pszRequest,"RELEASE_NAME") )
2005 32 : osVersionInfo.Printf( GDAL_RELEASE_NAME );
2006 : else // --version
2007 : osVersionInfo.Printf( "GDAL %s, released %d/%02d/%02d",
2008 : GDAL_RELEASE_NAME,
2009 : GDAL_RELEASE_DATE / 10000,
2010 : (GDAL_RELEASE_DATE % 10000) / 100,
2011 101 : GDAL_RELEASE_DATE % 100 );
2012 :
2013 2547 : CPLFree(CPLGetTLS(CTLS_VERSIONINFO)); // clear old value.
2014 2547 : CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osVersionInfo), TRUE );
2015 2547 : return (char *) CPLGetTLS(CTLS_VERSIONINFO);
2016 : }
2017 :
2018 : /************************************************************************/
2019 : /* GDALCheckVersion() */
2020 : /************************************************************************/
2021 :
2022 : /** Return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor.
2023 :
2024 : The purpose of this method is to ensure that calling code will run with the GDAL
2025 : version it is compiled for. It is primarly intented for external plugins.
2026 :
2027 : @param nVersionMajor Major version to be tested against
2028 : @param nVersionMinor Minor version to be tested against
2029 : @param pszCallingComponentName If not NULL, in case of version mismatch, the method
2030 : will issue a failure mentionning the name of
2031 : the calling component.
2032 :
2033 : @return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor, FALSE otherwise.
2034 : */
2035 14188 : int CPL_STDCALL GDALCheckVersion( int nVersionMajor, int nVersionMinor,
2036 : const char* pszCallingComponentName)
2037 : {
2038 14188 : if (nVersionMajor == GDAL_VERSION_MAJOR &&
2039 : nVersionMinor == GDAL_VERSION_MINOR)
2040 14188 : return TRUE;
2041 :
2042 0 : if (pszCallingComponentName)
2043 : {
2044 : CPLError( CE_Failure, CPLE_AppDefined,
2045 : "%s was compiled against GDAL %d.%d but current library version is %d.%d\n",
2046 : pszCallingComponentName, nVersionMajor, nVersionMinor,
2047 0 : GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
2048 : }
2049 0 : return FALSE;
2050 : }
2051 :
2052 : /************************************************************************/
2053 : /* GDALDecToDMS() */
2054 : /* */
2055 : /* Translate a decimal degrees value to a DMS string with */
2056 : /* hemisphere. */
2057 : /************************************************************************/
2058 :
2059 260 : const char * CPL_STDCALL GDALDecToDMS( double dfAngle, const char * pszAxis,
2060 : int nPrecision )
2061 :
2062 : {
2063 260 : return CPLDecToDMS( dfAngle, pszAxis, nPrecision );
2064 : }
2065 :
2066 : /************************************************************************/
2067 : /* GDALPackedDMSToDec() */
2068 : /************************************************************************/
2069 :
2070 : /**
2071 : * \brief Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
2072 : *
2073 : * See CPLPackedDMSToDec().
2074 : */
2075 :
2076 4 : double CPL_STDCALL GDALPackedDMSToDec( double dfPacked )
2077 :
2078 : {
2079 4 : return CPLPackedDMSToDec( dfPacked );
2080 : }
2081 :
2082 : /************************************************************************/
2083 : /* GDALDecToPackedDMS() */
2084 : /************************************************************************/
2085 :
2086 : /**
2087 : * \brief Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
2088 : *
2089 : * See CPLDecToPackedDMS().
2090 : */
2091 :
2092 4 : double CPL_STDCALL GDALDecToPackedDMS( double dfDec )
2093 :
2094 : {
2095 4 : return CPLDecToPackedDMS( dfDec );
2096 : }
2097 :
2098 : /************************************************************************/
2099 : /* GDALGCPsToGeoTransform() */
2100 : /************************************************************************/
2101 :
2102 : /**
2103 : * \brief Generate Geotransform from GCPs.
2104 : *
2105 : * Given a set of GCPs perform first order fit as a geotransform.
2106 : *
2107 : * Due to imprecision in the calculations the fit algorithm will often
2108 : * return non-zero rotational coefficients even if given perfectly non-rotated
2109 : * inputs. A special case has been implemented for corner corner coordinates
2110 : * given in TL, TR, BR, BL order. So when using this to get a geotransform
2111 : * from 4 corner coordinates, pass them in this order.
2112 : *
2113 : * @param nGCPCount the number of GCPs being passed in.
2114 : * @param pasGCPs the list of GCP structures.
2115 : * @param padfGeoTransform the six double array in which the affine
2116 : * geotransformation will be returned.
2117 : * @param bApproxOK If FALSE the function will fail if the geotransform is not
2118 : * essentially an exact fit (within 0.25 pixel) for all GCPs.
2119 : *
2120 : * @return TRUE on success or FALSE if there aren't enough points to prepare a
2121 : * geotransform, the pointers are ill-determined or if bApproxOK is FALSE
2122 : * and the fit is poor.
2123 : */
2124 :
2125 : int CPL_STDCALL
2126 315 : GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
2127 : double *padfGeoTransform, int bApproxOK )
2128 :
2129 : {
2130 : int i;
2131 :
2132 : /* -------------------------------------------------------------------- */
2133 : /* Recognise a few special cases. */
2134 : /* -------------------------------------------------------------------- */
2135 315 : if( nGCPCount < 2 )
2136 7 : return FALSE;
2137 :
2138 308 : if( nGCPCount == 2 )
2139 : {
2140 0 : if( pasGCPs[1].dfGCPPixel == pasGCPs[0].dfGCPPixel
2141 0 : || pasGCPs[1].dfGCPLine == pasGCPs[0].dfGCPLine )
2142 0 : return FALSE;
2143 :
2144 0 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2145 0 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2146 0 : padfGeoTransform[2] = 0.0;
2147 :
2148 0 : padfGeoTransform[4] = 0.0;
2149 0 : padfGeoTransform[5] = (pasGCPs[1].dfGCPY - pasGCPs[0].dfGCPY)
2150 0 : / (pasGCPs[1].dfGCPLine - pasGCPs[0].dfGCPLine);
2151 :
2152 : padfGeoTransform[0] = pasGCPs[0].dfGCPX
2153 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[1]
2154 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[2];
2155 :
2156 0 : padfGeoTransform[3] = pasGCPs[0].dfGCPY
2157 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[4]
2158 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2159 :
2160 0 : return TRUE;
2161 : }
2162 :
2163 : /* -------------------------------------------------------------------- */
2164 : /* Special case of 4 corner coordinates of a non-rotated */
2165 : /* image. The points must be in TL-TR-BR-BL order for now. */
2166 : /* This case helps avoid some imprecision in the general */
2167 : /* calcuations. */
2168 : /* -------------------------------------------------------------------- */
2169 3039 : if( nGCPCount == 4
2170 305 : && pasGCPs[0].dfGCPLine == pasGCPs[1].dfGCPLine
2171 344 : && pasGCPs[2].dfGCPLine == pasGCPs[3].dfGCPLine
2172 172 : && pasGCPs[0].dfGCPPixel == pasGCPs[3].dfGCPPixel
2173 344 : && pasGCPs[1].dfGCPPixel == pasGCPs[2].dfGCPPixel
2174 172 : && pasGCPs[0].dfGCPLine != pasGCPs[2].dfGCPLine
2175 170 : && pasGCPs[0].dfGCPPixel != pasGCPs[1].dfGCPPixel
2176 170 : && pasGCPs[0].dfGCPY == pasGCPs[1].dfGCPY
2177 314 : && pasGCPs[2].dfGCPY == pasGCPs[3].dfGCPY
2178 157 : && pasGCPs[0].dfGCPX == pasGCPs[3].dfGCPX
2179 314 : && pasGCPs[1].dfGCPX == pasGCPs[2].dfGCPX
2180 157 : && pasGCPs[0].dfGCPY != pasGCPs[2].dfGCPY
2181 112 : && pasGCPs[0].dfGCPX != pasGCPs[1].dfGCPX )
2182 : {
2183 112 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2184 112 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2185 112 : padfGeoTransform[2] = 0.0;
2186 112 : padfGeoTransform[4] = 0.0;
2187 224 : padfGeoTransform[5] = (pasGCPs[2].dfGCPY - pasGCPs[1].dfGCPY)
2188 224 : / (pasGCPs[2].dfGCPLine - pasGCPs[1].dfGCPLine);
2189 :
2190 : padfGeoTransform[0] =
2191 112 : pasGCPs[0].dfGCPX - pasGCPs[0].dfGCPPixel * padfGeoTransform[1];
2192 112 : padfGeoTransform[3] =
2193 112 : pasGCPs[0].dfGCPY - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2194 112 : return TRUE;
2195 : }
2196 :
2197 : /* -------------------------------------------------------------------- */
2198 : /* In the general case, do a least squares error approximation by */
2199 : /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum */
2200 : /* -------------------------------------------------------------------- */
2201 :
2202 196 : double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_xx = 0.0, sum_yy = 0.0;
2203 196 : double sum_Lon = 0.0, sum_Lonx = 0.0, sum_Lony = 0.0;
2204 196 : double sum_Lat = 0.0, sum_Latx = 0.0, sum_Laty = 0.0;
2205 : double divisor;
2206 :
2207 983 : for (i = 0; i < nGCPCount; ++i) {
2208 787 : sum_x += pasGCPs[i].dfGCPPixel;
2209 787 : sum_y += pasGCPs[i].dfGCPLine;
2210 787 : sum_xy += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPLine;
2211 787 : sum_xx += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPPixel;
2212 787 : sum_yy += pasGCPs[i].dfGCPLine * pasGCPs[i].dfGCPLine;
2213 787 : sum_Lon += pasGCPs[i].dfGCPX;
2214 787 : sum_Lonx += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPPixel;
2215 787 : sum_Lony += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPLine;
2216 787 : sum_Lat += pasGCPs[i].dfGCPY;
2217 787 : sum_Latx += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPPixel;
2218 787 : sum_Laty += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPLine;
2219 : }
2220 :
2221 : divisor = nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy)
2222 : + 2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx
2223 196 : - sum_x * sum_x * sum_yy;
2224 :
2225 : /* -------------------------------------------------------------------- */
2226 : /* If the divisor is zero, there is no valid solution. */
2227 : /* -------------------------------------------------------------------- */
2228 196 : if (divisor == 0.0)
2229 2 : return FALSE;
2230 :
2231 : /* -------------------------------------------------------------------- */
2232 : /* Compute top/left origin. */
2233 : /* -------------------------------------------------------------------- */
2234 :
2235 : padfGeoTransform[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy)
2236 : + sum_Lonx * (sum_y * sum_xy - sum_x * sum_yy)
2237 : + sum_Lony * (sum_x * sum_xy - sum_y * sum_xx))
2238 194 : / divisor;
2239 :
2240 194 : padfGeoTransform[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy)
2241 : + sum_Latx * (sum_y * sum_xy - sum_x * sum_yy)
2242 : + sum_Laty * (sum_x * sum_xy - sum_y * sum_xx))
2243 194 : / divisor;
2244 :
2245 : /* -------------------------------------------------------------------- */
2246 : /* Compute X related coefficients. */
2247 : /* -------------------------------------------------------------------- */
2248 194 : padfGeoTransform[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy)
2249 : + sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y)
2250 : + sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount))
2251 194 : / divisor;
2252 :
2253 194 : padfGeoTransform[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx)
2254 : + sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy)
2255 : + sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x))
2256 194 : / divisor;
2257 :
2258 : /* -------------------------------------------------------------------- */
2259 : /* Compute Y related coefficients. */
2260 : /* -------------------------------------------------------------------- */
2261 194 : padfGeoTransform[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy)
2262 : + sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y)
2263 : + sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount))
2264 194 : / divisor;
2265 :
2266 194 : padfGeoTransform[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx)
2267 : + sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy)
2268 : + sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x))
2269 194 : / divisor;
2270 :
2271 : /* -------------------------------------------------------------------- */
2272 : /* Now check if any of the input points fit this poorly. */
2273 : /* -------------------------------------------------------------------- */
2274 194 : if( !bApproxOK )
2275 : {
2276 388 : double dfPixelSize = ABS(padfGeoTransform[1])
2277 388 : + ABS(padfGeoTransform[2])
2278 388 : + ABS(padfGeoTransform[4])
2279 1164 : + ABS(padfGeoTransform[5]);
2280 :
2281 956 : for( i = 0; i < nGCPCount; i++ )
2282 : {
2283 : double dfErrorX, dfErrorY;
2284 :
2285 : dfErrorX =
2286 1532 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[1]
2287 1532 : + pasGCPs[i].dfGCPLine * padfGeoTransform[2]
2288 766 : + padfGeoTransform[0])
2289 3830 : - pasGCPs[i].dfGCPX;
2290 : dfErrorY =
2291 1532 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[4]
2292 1532 : + pasGCPs[i].dfGCPLine * padfGeoTransform[5]
2293 766 : + padfGeoTransform[3])
2294 3830 : - pasGCPs[i].dfGCPY;
2295 :
2296 766 : if( ABS(dfErrorX) > 0.25 * dfPixelSize
2297 : || ABS(dfErrorY) > 0.25 * dfPixelSize )
2298 4 : return FALSE;
2299 : }
2300 : }
2301 :
2302 190 : return TRUE;
2303 : }
2304 :
2305 : /************************************************************************/
2306 : /* GDALGeneralCmdLineProcessor() */
2307 : /************************************************************************/
2308 :
2309 : /**
2310 : * \brief General utility option processing.
2311 : *
2312 : * This function is intended to provide a variety of generic commandline
2313 : * options for all GDAL commandline utilities. It takes care of the following
2314 : * commandline options:
2315 : *
2316 : * --version: report version of GDAL in use.
2317 : * --build: report build info about GDAL in use.
2318 : * --license: report GDAL license info.
2319 : * --formats: report all format drivers configured.
2320 : * --format [format]: report details of one format driver.
2321 : * --optfile filename: expand an option file into the argument list.
2322 : * --config key value: set system configuration option.
2323 : * --debug [on/off/value]: set debug level.
2324 : * --mempreload dir: preload directory contents into /vsimem
2325 : * --pause: Pause for user input (allows time to attach debugger)
2326 : * --locale [locale]: Install a locale using setlocale() (debugging)
2327 : * --help-general: report detailed help on general options.
2328 : *
2329 : * The argument array is replaced "in place" and should be freed with
2330 : * CSLDestroy() when no longer needed. The typical usage looks something
2331 : * like the following. Note that the formats should be registered so that
2332 : * the --formats and --format options will work properly.
2333 : *
2334 : * int main( int argc, char ** argv )
2335 : * {
2336 : * GDALAllRegister();
2337 : *
2338 : * argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
2339 : * if( argc < 1 )
2340 : * exit( -argc );
2341 : *
2342 : * @param nArgc number of values in the argument list.
2343 : * @param ppapszArgv pointer to the argument list array (will be updated in place).
2344 : * @param nOptions unused for now.
2345 : *
2346 : * @return updated nArgc argument count. Return of 0 requests terminate
2347 : * without error, return of -1 requests exit with error code.
2348 : */
2349 :
2350 : int CPL_STDCALL
2351 601 : GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
2352 :
2353 : {
2354 601 : char **papszReturn = NULL;
2355 : int iArg;
2356 601 : char **papszArgv = *ppapszArgv;
2357 :
2358 : (void) nOptions;
2359 :
2360 : /* -------------------------------------------------------------------- */
2361 : /* Preserve the program name. */
2362 : /* -------------------------------------------------------------------- */
2363 601 : papszReturn = CSLAddString( papszReturn, papszArgv[0] );
2364 :
2365 : /* ==================================================================== */
2366 : /* Loop over all arguments. */
2367 : /* ==================================================================== */
2368 3604 : for( iArg = 1; iArg < nArgc; iArg++ )
2369 : {
2370 : /* -------------------------------------------------------------------- */
2371 : /* --version */
2372 : /* -------------------------------------------------------------------- */
2373 3003 : if( EQUAL(papszArgv[iArg],"--version") )
2374 : {
2375 0 : printf( "%s\n", GDALVersionInfo( "--version" ) );
2376 0 : CSLDestroy( papszReturn );
2377 0 : return 0;
2378 : }
2379 :
2380 : /* -------------------------------------------------------------------- */
2381 : /* --build */
2382 : /* -------------------------------------------------------------------- */
2383 3003 : else if( EQUAL(papszArgv[iArg],"--build") )
2384 : {
2385 0 : printf( "%s", GDALVersionInfo( "BUILD_INFO" ) );
2386 0 : CSLDestroy( papszReturn );
2387 0 : return 0;
2388 : }
2389 :
2390 : /* -------------------------------------------------------------------- */
2391 : /* --license */
2392 : /* -------------------------------------------------------------------- */
2393 3003 : else if( EQUAL(papszArgv[iArg],"--license") )
2394 : {
2395 0 : printf( "%s\n", GDALVersionInfo( "LICENSE" ) );
2396 0 : CSLDestroy( papszReturn );
2397 0 : return 0;
2398 : }
2399 :
2400 : /* -------------------------------------------------------------------- */
2401 : /* --config */
2402 : /* -------------------------------------------------------------------- */
2403 3003 : else if( EQUAL(papszArgv[iArg],"--config") )
2404 : {
2405 8 : if( iArg + 2 >= nArgc )
2406 : {
2407 : CPLError( CE_Failure, CPLE_AppDefined,
2408 0 : "--config option given without a key and value argument." );
2409 0 : CSLDestroy( papszReturn );
2410 0 : return -1;
2411 : }
2412 :
2413 8 : CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
2414 :
2415 8 : iArg += 2;
2416 : }
2417 :
2418 : /* -------------------------------------------------------------------- */
2419 : /* --mempreload */
2420 : /* -------------------------------------------------------------------- */
2421 2995 : else if( EQUAL(papszArgv[iArg],"--mempreload") )
2422 : {
2423 : int i;
2424 :
2425 0 : if( iArg + 1 >= nArgc )
2426 : {
2427 : CPLError( CE_Failure, CPLE_AppDefined,
2428 0 : "--mempreload option given without directory path.");
2429 0 : CSLDestroy( papszReturn );
2430 0 : return -1;
2431 : }
2432 :
2433 0 : char **papszFiles = CPLReadDir( papszArgv[iArg+1] );
2434 0 : if( CSLCount(papszFiles) == 0 )
2435 : {
2436 : CPLError( CE_Failure, CPLE_AppDefined,
2437 0 : "--mempreload given invalid or empty directory.");
2438 0 : CSLDestroy( papszReturn );
2439 0 : return -1;
2440 : }
2441 :
2442 0 : for( i = 0; papszFiles[i] != NULL; i++ )
2443 : {
2444 0 : CPLString osOldPath, osNewPath;
2445 : VSIStatBufL sStatBuf;
2446 :
2447 0 : if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
2448 0 : continue;
2449 :
2450 0 : osOldPath = CPLFormFilename( papszArgv[iArg+1],
2451 0 : papszFiles[i], NULL );
2452 0 : osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
2453 :
2454 0 : if( VSIStatL( osOldPath, &sStatBuf ) != 0
2455 : || VSI_ISDIR( sStatBuf.st_mode ) )
2456 : {
2457 : CPLDebug( "VSI", "Skipping preload of %s.",
2458 0 : osOldPath.c_str() );
2459 0 : continue;
2460 : }
2461 :
2462 : CPLDebug( "VSI", "Preloading %s to %s.",
2463 0 : osOldPath.c_str(), osNewPath.c_str() );
2464 :
2465 0 : if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
2466 : {
2467 : CPLError( CE_Failure, CPLE_AppDefined,
2468 : "Failed to copy %s to /vsimem",
2469 0 : osOldPath.c_str() );
2470 0 : return -1;
2471 : }
2472 : }
2473 :
2474 0 : CSLDestroy( papszFiles );
2475 0 : iArg += 1;
2476 : }
2477 :
2478 : /* -------------------------------------------------------------------- */
2479 : /* --debug */
2480 : /* -------------------------------------------------------------------- */
2481 2995 : else if( EQUAL(papszArgv[iArg],"--debug") )
2482 : {
2483 0 : if( iArg + 1 >= nArgc )
2484 : {
2485 : CPLError( CE_Failure, CPLE_AppDefined,
2486 0 : "--debug option given without debug level." );
2487 0 : CSLDestroy( papszReturn );
2488 0 : return -1;
2489 : }
2490 :
2491 0 : CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
2492 0 : iArg += 1;
2493 : }
2494 :
2495 : /* -------------------------------------------------------------------- */
2496 : /* --optfile */
2497 : /* */
2498 : /* Annoyingly the options inserted by --optfile will *not* be */
2499 : /* processed properly if they are general options. */
2500 : /* -------------------------------------------------------------------- */
2501 2995 : else if( EQUAL(papszArgv[iArg],"--optfile") )
2502 : {
2503 : const char *pszLine;
2504 : FILE *fpOptFile;
2505 :
2506 0 : if( iArg + 1 >= nArgc )
2507 : {
2508 : CPLError( CE_Failure, CPLE_AppDefined,
2509 0 : "--optfile option given without filename." );
2510 0 : CSLDestroy( papszReturn );
2511 0 : return -1;
2512 : }
2513 :
2514 0 : fpOptFile = VSIFOpen( papszArgv[iArg+1], "rb" );
2515 :
2516 0 : if( fpOptFile == NULL )
2517 : {
2518 : CPLError( CE_Failure, CPLE_AppDefined,
2519 : "Unable to open optfile '%s'.\n%s",
2520 0 : papszArgv[iArg+1], VSIStrerror( errno ) );
2521 0 : CSLDestroy( papszReturn );
2522 0 : return -1;
2523 : }
2524 :
2525 0 : while( (pszLine = CPLReadLine( fpOptFile )) != NULL )
2526 : {
2527 : char **papszTokens;
2528 : int i;
2529 :
2530 0 : if( pszLine[0] == '#' || strlen(pszLine) == 0 )
2531 0 : continue;
2532 :
2533 0 : papszTokens = CSLTokenizeString( pszLine );
2534 0 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++)
2535 0 : papszReturn = CSLAddString( papszReturn, papszTokens[i] );
2536 0 : CSLDestroy( papszTokens );
2537 : }
2538 :
2539 0 : VSIFClose( fpOptFile );
2540 :
2541 0 : iArg += 1;
2542 : }
2543 :
2544 : /* -------------------------------------------------------------------- */
2545 : /* --formats */
2546 : /* -------------------------------------------------------------------- */
2547 2995 : else if( EQUAL(papszArgv[iArg], "--formats") )
2548 : {
2549 : int iDr;
2550 :
2551 0 : printf( "Supported Formats:\n" );
2552 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
2553 : {
2554 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
2555 : const char *pszRWFlag, *pszVirtualIO;
2556 :
2557 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) )
2558 0 : pszRWFlag = "rw+";
2559 0 : else if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
2560 : NULL ) )
2561 0 : pszRWFlag = "rw";
2562 : else
2563 0 : pszRWFlag = "ro";
2564 :
2565 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL) )
2566 0 : pszVirtualIO = "v";
2567 : else
2568 0 : pszVirtualIO = "";
2569 :
2570 : printf( " %s (%s%s): %s\n",
2571 : GDALGetDriverShortName( hDriver ),
2572 : pszRWFlag, pszVirtualIO,
2573 0 : GDALGetDriverLongName( hDriver ) );
2574 : }
2575 :
2576 0 : CSLDestroy( papszReturn );
2577 0 : return 0;
2578 : }
2579 :
2580 : /* -------------------------------------------------------------------- */
2581 : /* --format */
2582 : /* -------------------------------------------------------------------- */
2583 2995 : else if( EQUAL(papszArgv[iArg], "--format") )
2584 : {
2585 : GDALDriverH hDriver;
2586 : char **papszMD;
2587 :
2588 0 : CSLDestroy( papszReturn );
2589 :
2590 0 : if( iArg + 1 >= nArgc )
2591 : {
2592 : CPLError( CE_Failure, CPLE_AppDefined,
2593 0 : "--format option given without a format code." );
2594 0 : return -1;
2595 : }
2596 :
2597 0 : hDriver = GDALGetDriverByName( papszArgv[iArg+1] );
2598 0 : if( hDriver == NULL )
2599 : {
2600 : CPLError( CE_Failure, CPLE_AppDefined,
2601 : "--format option given with format '%s', but that format not\n"
2602 : "recognised. Use the --formats option to get a list of available formats,\n"
2603 : "and use the short code (ie. GTiff or HFA) as the format identifier.\n",
2604 0 : papszArgv[iArg+1] );
2605 0 : return -1;
2606 : }
2607 :
2608 0 : printf( "Format Details:\n" );
2609 0 : printf( " Short Name: %s\n", GDALGetDriverShortName( hDriver ) );
2610 0 : printf( " Long Name: %s\n", GDALGetDriverLongName( hDriver ) );
2611 :
2612 0 : papszMD = GDALGetMetadata( hDriver, NULL );
2613 :
2614 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) )
2615 : printf( " Extension: %s\n",
2616 0 : CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) );
2617 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) )
2618 : printf( " Mime Type: %s\n",
2619 0 : CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) );
2620 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) )
2621 : printf( " Help Topic: %s\n",
2622 0 : CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) );
2623 :
2624 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATE, FALSE ) )
2625 0 : printf( " Supports: Create() - Create writeable dataset.\n" );
2626 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATECOPY, FALSE ) )
2627 0 : printf( " Supports: CreateCopy() - Create dataset by copying another.\n" );
2628 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_VIRTUALIO, FALSE ) )
2629 0 : printf( " Supports: Virtual IO - eg. /vsimem/\n" );
2630 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) )
2631 : printf( " Creation Datatypes: %s\n",
2632 0 : CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) );
2633 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONOPTIONLIST ) )
2634 : {
2635 : CPLXMLNode *psCOL =
2636 : CPLParseXMLString(
2637 : CSLFetchNameValue( papszMD,
2638 0 : GDAL_DMD_CREATIONOPTIONLIST ) );
2639 : char *pszFormattedXML =
2640 0 : CPLSerializeXMLTree( psCOL );
2641 :
2642 0 : CPLDestroyXMLNode( psCOL );
2643 :
2644 0 : printf( "\n%s\n", pszFormattedXML );
2645 0 : CPLFree( pszFormattedXML );
2646 : }
2647 0 : return 0;
2648 : }
2649 :
2650 : /* -------------------------------------------------------------------- */
2651 : /* --help-general */
2652 : /* -------------------------------------------------------------------- */
2653 2995 : else if( EQUAL(papszArgv[iArg],"--help-general") )
2654 : {
2655 0 : printf( "Generic GDAL utility command options:\n" );
2656 0 : printf( " --version: report version of GDAL in use.\n" );
2657 0 : printf( " --license: report GDAL license info.\n" );
2658 0 : printf( " --formats: report all configured format drivers.\n" );
2659 0 : printf( " --format [format]: details of one format.\n" );
2660 0 : printf( " --optfile filename: expand an option file into the argument list.\n" );
2661 0 : printf( " --config key value: set system configuration option.\n" );
2662 0 : printf( " --debug [on/off/value]: set debug level.\n" );
2663 0 : printf( " --pause: wait for user input, time to attach debugger\n" );
2664 0 : printf( " --locale [locale]: install locale for debugging (ie. en_US.UTF-8)\n" );
2665 0 : printf( " --help-general: report detailed help on general options.\n" );
2666 0 : CSLDestroy( papszReturn );
2667 0 : return 0;
2668 : }
2669 :
2670 : /* -------------------------------------------------------------------- */
2671 : /* --locale */
2672 : /* -------------------------------------------------------------------- */
2673 2995 : else if( EQUAL(papszArgv[iArg],"--locale") && iArg < nArgc-1 )
2674 : {
2675 0 : setlocale( LC_ALL, papszArgv[++iArg] );
2676 : }
2677 :
2678 : /* -------------------------------------------------------------------- */
2679 : /* --pause */
2680 : /* -------------------------------------------------------------------- */
2681 2995 : else if( EQUAL(papszArgv[iArg],"--pause") )
2682 : {
2683 0 : printf( "Hit <ENTER> to Continue.\n" );
2684 0 : CPLReadLine( stdin );
2685 : }
2686 :
2687 : /* -------------------------------------------------------------------- */
2688 : /* carry through unrecognised options. */
2689 : /* -------------------------------------------------------------------- */
2690 : else
2691 : {
2692 2995 : papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
2693 : }
2694 : }
2695 :
2696 601 : *ppapszArgv = papszReturn;
2697 :
2698 601 : return CSLCount( *ppapszArgv );
2699 : }
2700 :
2701 :
2702 : /************************************************************************/
2703 : /* _FetchDblFromMD() */
2704 : /************************************************************************/
2705 :
2706 90 : static int _FetchDblFromMD( char **papszMD, const char *pszKey,
2707 : double *padfTarget, int nCount, double dfDefault )
2708 :
2709 : {
2710 : char szFullKey[200];
2711 :
2712 90 : sprintf( szFullKey, "%s", pszKey );
2713 :
2714 90 : const char *pszValue = CSLFetchNameValue( papszMD, szFullKey );
2715 : int i;
2716 :
2717 560 : for( i = 0; i < nCount; i++ )
2718 470 : padfTarget[i] = dfDefault;
2719 :
2720 90 : if( pszValue == NULL )
2721 20 : return FALSE;
2722 :
2723 70 : if( nCount == 1 )
2724 : {
2725 50 : *padfTarget = CPLAtofM( pszValue );
2726 50 : return TRUE;
2727 : }
2728 :
2729 : char **papszTokens = CSLTokenizeStringComplex( pszValue, " ,",
2730 20 : FALSE, FALSE );
2731 :
2732 20 : if( CSLCount( papszTokens ) != nCount )
2733 : {
2734 0 : CSLDestroy( papszTokens );
2735 0 : return FALSE;
2736 : }
2737 :
2738 420 : for( i = 0; i < nCount; i++ )
2739 400 : padfTarget[i] = CPLAtofM(papszTokens[i]);
2740 :
2741 20 : CSLDestroy( papszTokens );
2742 :
2743 20 : return TRUE;
2744 : }
2745 :
2746 : /************************************************************************/
2747 : /* GDALExtractRPCInfo() */
2748 : /* */
2749 : /* Extract RPC info from metadata, and apply to an RPCInfo */
2750 : /* structure. The inverse of this function is RPCInfoToMD() in */
2751 : /* alg/gdal_rpc.cpp (should it be needed). */
2752 : /************************************************************************/
2753 :
2754 5 : int CPL_STDCALL GDALExtractRPCInfo( char **papszMD, GDALRPCInfo *psRPC )
2755 :
2756 : {
2757 5 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL )
2758 0 : return FALSE;
2759 :
2760 5 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL
2761 : || CSLFetchNameValue( papszMD, "LINE_DEN_COEFF" ) == NULL
2762 : || CSLFetchNameValue( papszMD, "SAMP_NUM_COEFF" ) == NULL
2763 : || CSLFetchNameValue( papszMD, "SAMP_DEN_COEFF" ) == NULL )
2764 : {
2765 : CPLError( CE_Failure, CPLE_AppDefined,
2766 0 : "Some required RPC metadata missing in GDALExtractRPCInfo()");
2767 0 : return FALSE;
2768 : }
2769 :
2770 5 : _FetchDblFromMD( papszMD, "LINE_OFF", &(psRPC->dfLINE_OFF), 1, 0.0 );
2771 5 : _FetchDblFromMD( papszMD, "LINE_SCALE", &(psRPC->dfLINE_SCALE), 1, 1.0 );
2772 5 : _FetchDblFromMD( papszMD, "SAMP_OFF", &(psRPC->dfSAMP_OFF), 1, 0.0 );
2773 5 : _FetchDblFromMD( papszMD, "SAMP_SCALE", &(psRPC->dfSAMP_SCALE), 1, 1.0 );
2774 5 : _FetchDblFromMD( papszMD, "HEIGHT_OFF", &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
2775 5 : _FetchDblFromMD( papszMD, "HEIGHT_SCALE", &(psRPC->dfHEIGHT_SCALE),1, 1.0);
2776 5 : _FetchDblFromMD( papszMD, "LAT_OFF", &(psRPC->dfLAT_OFF), 1, 0.0 );
2777 5 : _FetchDblFromMD( papszMD, "LAT_SCALE", &(psRPC->dfLAT_SCALE), 1, 1.0 );
2778 5 : _FetchDblFromMD( papszMD, "LONG_OFF", &(psRPC->dfLONG_OFF), 1, 0.0 );
2779 5 : _FetchDblFromMD( papszMD, "LONG_SCALE", &(psRPC->dfLONG_SCALE), 1, 1.0 );
2780 :
2781 : _FetchDblFromMD( papszMD, "LINE_NUM_COEFF", psRPC->adfLINE_NUM_COEFF,
2782 5 : 20, 0.0 );
2783 : _FetchDblFromMD( papszMD, "LINE_DEN_COEFF", psRPC->adfLINE_DEN_COEFF,
2784 5 : 20, 0.0 );
2785 : _FetchDblFromMD( papszMD, "SAMP_NUM_COEFF", psRPC->adfSAMP_NUM_COEFF,
2786 5 : 20, 0.0 );
2787 : _FetchDblFromMD( papszMD, "SAMP_DEN_COEFF", psRPC->adfSAMP_DEN_COEFF,
2788 5 : 20, 0.0 );
2789 :
2790 5 : _FetchDblFromMD( papszMD, "MIN_LONG", &(psRPC->dfMIN_LONG), 1, -180.0 );
2791 5 : _FetchDblFromMD( papszMD, "MIN_LAT", &(psRPC->dfMIN_LAT), 1, -90.0 );
2792 5 : _FetchDblFromMD( papszMD, "MAX_LONG", &(psRPC->dfMAX_LONG), 1, 180.0 );
2793 5 : _FetchDblFromMD( papszMD, "MAX_LAT", &(psRPC->dfMAX_LAT), 1, 90.0 );
2794 :
2795 5 : return TRUE;
2796 : }
2797 :
2798 : /************************************************************************/
2799 : /* GDALFindAssociatedAuxFile() */
2800 : /************************************************************************/
2801 :
2802 4565 : GDALDataset *GDALFindAssociatedAuxFile( const char *pszBasename,
2803 : GDALAccess eAccess,
2804 : GDALDataset *poDependentDS )
2805 :
2806 : {
2807 4565 : const char *pszAuxSuffixLC = "aux";
2808 4565 : const char *pszAuxSuffixUC = "AUX";
2809 :
2810 4565 : if( EQUAL(CPLGetExtension(pszBasename), pszAuxSuffixLC) )
2811 33 : return NULL;
2812 :
2813 : /* -------------------------------------------------------------------- */
2814 : /* Don't even try to look for an .aux file if we don't have a */
2815 : /* path of any kind. */
2816 : /* -------------------------------------------------------------------- */
2817 4532 : if( strlen(pszBasename) == 0 )
2818 0 : return NULL;
2819 :
2820 : /* -------------------------------------------------------------------- */
2821 : /* We didn't find that, so try and find a corresponding aux */
2822 : /* file. Check that we are the dependent file of the aux */
2823 : /* file, or if we aren't verify that the dependent file does */
2824 : /* not exist, likely mean it is us but some sort of renaming */
2825 : /* has occured. */
2826 : /* -------------------------------------------------------------------- */
2827 4532 : CPLString osJustFile = CPLGetFilename(pszBasename); // without dir
2828 4532 : CPLString osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixLC);
2829 4532 : GDALDataset *poODS = NULL;
2830 : GByte abyHeader[32];
2831 : VSILFILE *fp;
2832 :
2833 4532 : fp = VSIFOpenL( osAuxFilename, "rb" );
2834 :
2835 :
2836 4532 : if ( fp == NULL && VSIIsCaseSensitiveFS(osAuxFilename))
2837 : {
2838 : // Can't found file with lower case suffix. Try the upper case one.
2839 4488 : osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixUC);
2840 4488 : fp = VSIFOpenL( osAuxFilename, "rb" );
2841 : }
2842 :
2843 4532 : if( fp != NULL )
2844 : {
2845 44 : if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
2846 : EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2847 : {
2848 : /* Avoid causing failure in opening of main file from SWIG bindings */
2849 : /* when auxiliary file cannot be opened (#3269) */
2850 20 : CPLTurnFailureIntoWarning(TRUE);
2851 20 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2852 20 : CPLTurnFailureIntoWarning(FALSE);
2853 : }
2854 44 : VSIFCloseL( fp );
2855 : }
2856 :
2857 : /* -------------------------------------------------------------------- */
2858 : /* Try replacing extension with .aux */
2859 : /* -------------------------------------------------------------------- */
2860 4532 : if( poODS != NULL )
2861 : {
2862 : const char *pszDep
2863 20 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2864 20 : if( pszDep == NULL )
2865 : {
2866 : CPLDebug( "AUX",
2867 : "Found %s but it has no dependent file, ignoring.",
2868 0 : osAuxFilename.c_str() );
2869 0 : GDALClose( poODS );
2870 0 : poODS = NULL;
2871 : }
2872 20 : else if( !EQUAL(pszDep,osJustFile) )
2873 : {
2874 : VSIStatBufL sStatBuf;
2875 :
2876 0 : if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
2877 : {
2878 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2879 : osAuxFilename.c_str(),
2880 0 : pszDep, osJustFile.c_str() );
2881 0 : GDALClose( poODS );
2882 0 : poODS = NULL;
2883 : }
2884 : else
2885 : {
2886 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2887 : "%s does not exist, we will use .aux file as our own.",
2888 : osAuxFilename.c_str(),
2889 : pszDep, osJustFile.c_str(),
2890 0 : pszDep );
2891 : }
2892 : }
2893 :
2894 : /* -------------------------------------------------------------------- */
2895 : /* Confirm that the aux file matches the configuration of the */
2896 : /* dependent dataset. */
2897 : /* -------------------------------------------------------------------- */
2898 20 : if( poODS != NULL && poDependentDS != NULL
2899 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2900 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2901 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2902 : {
2903 : CPLDebug( "AUX",
2904 : "Ignoring aux file %s as its raster configuration\n"
2905 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2906 : osAuxFilename.c_str(),
2907 : poODS->GetRasterXSize(),
2908 : poODS->GetRasterYSize(),
2909 : poODS->GetRasterCount(),
2910 : poDependentDS->GetRasterXSize(),
2911 : poDependentDS->GetRasterYSize(),
2912 5 : poDependentDS->GetRasterCount() );
2913 :
2914 5 : GDALClose( poODS );
2915 5 : poODS = NULL;
2916 : }
2917 : }
2918 :
2919 : /* -------------------------------------------------------------------- */
2920 : /* Try appending .aux to the end of the filename. */
2921 : /* -------------------------------------------------------------------- */
2922 4532 : if( poODS == NULL )
2923 : {
2924 4517 : osAuxFilename = pszBasename;
2925 4517 : osAuxFilename += ".";
2926 4517 : osAuxFilename += pszAuxSuffixLC;
2927 4517 : fp = VSIFOpenL( osAuxFilename, "rb" );
2928 4517 : if ( fp == NULL && VSIIsCaseSensitiveFS(osAuxFilename) )
2929 : {
2930 : // Can't found file with lower case suffix. Try the upper case one.
2931 4498 : osAuxFilename = pszBasename;
2932 4498 : osAuxFilename += ".";
2933 4498 : osAuxFilename += pszAuxSuffixUC;
2934 4498 : fp = VSIFOpenL( osAuxFilename, "rb" );
2935 : }
2936 :
2937 4517 : if( fp != NULL )
2938 : {
2939 19 : if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
2940 : EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2941 : {
2942 : /* Avoid causing failure in opening of main file from SWIG bindings */
2943 : /* when auxiliary file cannot be opened (#3269) */
2944 0 : CPLTurnFailureIntoWarning(TRUE);
2945 0 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2946 0 : CPLTurnFailureIntoWarning(FALSE);
2947 : }
2948 19 : VSIFCloseL( fp );
2949 : }
2950 :
2951 4517 : if( poODS != NULL )
2952 : {
2953 : const char *pszDep
2954 0 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2955 0 : if( pszDep == NULL )
2956 : {
2957 : CPLDebug( "AUX",
2958 : "Found %s but it has no dependent file, ignoring.",
2959 0 : osAuxFilename.c_str() );
2960 0 : GDALClose( poODS );
2961 0 : poODS = NULL;
2962 : }
2963 0 : else if( !EQUAL(pszDep,osJustFile) )
2964 : {
2965 : VSIStatBufL sStatBuf;
2966 :
2967 0 : if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
2968 : {
2969 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2970 : osAuxFilename.c_str(),
2971 0 : pszDep, osJustFile.c_str() );
2972 0 : GDALClose( poODS );
2973 0 : poODS = NULL;
2974 : }
2975 : else
2976 : {
2977 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2978 : "%s does not exist, we will use .aux file as our own.",
2979 : osAuxFilename.c_str(),
2980 : pszDep, osJustFile.c_str(),
2981 0 : pszDep );
2982 : }
2983 : }
2984 : }
2985 : }
2986 :
2987 : /* -------------------------------------------------------------------- */
2988 : /* Confirm that the aux file matches the configuration of the */
2989 : /* dependent dataset. */
2990 : /* -------------------------------------------------------------------- */
2991 4532 : if( poODS != NULL && poDependentDS != NULL
2992 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2993 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2994 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2995 : {
2996 : CPLDebug( "AUX",
2997 : "Ignoring aux file %s as its raster configuration\n"
2998 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2999 : osAuxFilename.c_str(),
3000 : poODS->GetRasterXSize(),
3001 : poODS->GetRasterYSize(),
3002 : poODS->GetRasterCount(),
3003 : poDependentDS->GetRasterXSize(),
3004 : poDependentDS->GetRasterYSize(),
3005 0 : poDependentDS->GetRasterCount() );
3006 :
3007 0 : GDALClose( poODS );
3008 0 : poODS = NULL;
3009 : }
3010 :
3011 4532 : return poODS;
3012 : }
3013 :
3014 : /************************************************************************/
3015 : /* -------------------------------------------------------------------- */
3016 : /* The following stubs are present to ensure that older GDAL */
3017 : /* bridges don't fail with newer libraries. */
3018 : /* -------------------------------------------------------------------- */
3019 : /************************************************************************/
3020 :
3021 : CPL_C_START
3022 :
3023 0 : void * CPL_STDCALL GDALCreateProjDef( const char * )
3024 : {
3025 0 : CPLDebug( "GDAL", "GDALCreateProjDef no longer supported." );
3026 0 : return NULL;
3027 : }
3028 :
3029 0 : CPLErr CPL_STDCALL GDALReprojectToLongLat( void *, double *, double * )
3030 : {
3031 0 : CPLDebug( "GDAL", "GDALReprojectToLatLong no longer supported." );
3032 0 : return CE_Failure;
3033 : }
3034 :
3035 0 : CPLErr CPL_STDCALL GDALReprojectFromLongLat( void *, double *, double * )
3036 : {
3037 0 : CPLDebug( "GDAL", "GDALReprojectFromLatLong no longer supported." );
3038 0 : return CE_Failure;
3039 : }
3040 :
3041 0 : void CPL_STDCALL GDALDestroyProjDef( void * )
3042 :
3043 : {
3044 0 : CPLDebug( "GDAL", "GDALDestroyProjDef no longer supported." );
3045 0 : }
3046 :
3047 : CPL_C_END
3048 :
3049 : /************************************************************************/
3050 : /* Infrastructure to check that dataset characteristics are valid */
3051 : /************************************************************************/
3052 :
3053 : CPL_C_START
3054 :
3055 : /**
3056 : * \brief Return TRUE if the dataset dimensions are valid.
3057 : *
3058 : * @param nXSize raster width
3059 : * @param nYSize raster height
3060 : *
3061 : * @since GDAL 1.7.0
3062 : */
3063 1368 : int GDALCheckDatasetDimensions( int nXSize, int nYSize )
3064 : {
3065 1368 : if (nXSize <= 0 || nYSize <= 0)
3066 : {
3067 : CPLError(CE_Failure, CPLE_AppDefined,
3068 0 : "Invalid dataset dimensions : %d x %d", nXSize, nYSize);
3069 0 : return FALSE;
3070 : }
3071 1368 : return TRUE;
3072 : }
3073 :
3074 : /**
3075 : * \brief Return TRUE if the band count is valid.
3076 : *
3077 : * If the configuration option GDAL_MAX_BAND_COUNT is defined,
3078 : * the band count will be compared to the maximum number of band allowed.
3079 : *
3080 : * @param nBands the band count
3081 : * @param bIsZeroAllowed TRUE if band count == 0 is allowed
3082 : *
3083 : * @since GDAL 1.7.0
3084 : */
3085 :
3086 925 : int GDALCheckBandCount( int nBands, int bIsZeroAllowed )
3087 : {
3088 925 : int nMaxBands = -1;
3089 925 : const char* pszMaxBandCount = CPLGetConfigOption("GDAL_MAX_BAND_COUNT", NULL);
3090 925 : if (pszMaxBandCount != NULL)
3091 : {
3092 0 : nMaxBands = atoi(pszMaxBandCount);
3093 : }
3094 925 : if (nBands < 0 || (!bIsZeroAllowed && nBands == 0) ||
3095 : (nMaxBands >= 0 && nBands > nMaxBands) )
3096 : {
3097 : CPLError(CE_Failure, CPLE_AppDefined,
3098 6 : "Invalid band count : %d", nBands);
3099 6 : return FALSE;
3100 : }
3101 919 : return TRUE;
3102 : }
3103 :
3104 : CPL_C_END
3105 :
|