1 : /******************************************************************************
2 : * $Id: gdal_misc.cpp 23156 2011-10-01 15:34:16Z 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 23156 2011-10-01 15:34:16Z 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
67 : * @param eType2
68 : *
69 : * @return a data type able to express eType1 and eType2.
70 : */
71 :
72 : GDALDataType CPL_STDCALL
73 1342 : GDALDataTypeUnion( GDALDataType eType1, GDALDataType eType2 )
74 :
75 : {
76 : int bFloating, bComplex, nBits, bSigned;
77 :
78 1342 : bComplex = GDALDataTypeIsComplex(eType1) | GDALDataTypeIsComplex(eType2);
79 :
80 1342 : switch( eType1 )
81 : {
82 : case GDT_Byte:
83 888 : nBits = 8;
84 888 : bSigned = FALSE;
85 888 : bFloating = FALSE;
86 888 : 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 14 : nBits = 32;
104 14 : bSigned = TRUE;
105 14 : bFloating = FALSE;
106 14 : 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 440 : nBits = 32;
117 440 : bSigned = TRUE;
118 440 : bFloating = TRUE;
119 440 : 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 1342 : switch( eType2 )
134 : {
135 : case GDT_Byte:
136 386 : break;
137 :
138 : case GDT_Int16:
139 : case GDT_CInt16:
140 128 : nBits = MAX(nBits,16);
141 128 : bSigned = TRUE;
142 128 : break;
143 :
144 : case GDT_UInt16:
145 48 : nBits = MAX(nBits,16);
146 48 : break;
147 :
148 : case GDT_Int32:
149 : case GDT_CInt32:
150 548 : nBits = MAX(nBits,32);
151 548 : bSigned = TRUE;
152 548 : break;
153 :
154 : case GDT_UInt32:
155 46 : nBits = MAX(nBits,32);
156 46 : break;
157 :
158 : case GDT_Float32:
159 : case GDT_CFloat32:
160 92 : nBits = MAX(nBits,32);
161 92 : bSigned = TRUE;
162 92 : bFloating = TRUE;
163 92 : break;
164 :
165 : case GDT_Float64:
166 : case GDT_CFloat64:
167 94 : nBits = MAX(nBits,64);
168 94 : bSigned = TRUE;
169 94 : bFloating = TRUE;
170 94 : break;
171 :
172 : default:
173 0 : CPLAssert( FALSE );
174 0 : return GDT_Unknown;
175 : }
176 :
177 1342 : if( nBits == 8 )
178 386 : return GDT_Byte;
179 956 : else if( nBits == 16 && bComplex )
180 44 : return GDT_CInt16;
181 912 : else if( nBits == 16 && bSigned )
182 84 : return GDT_Int16;
183 828 : else if( nBits == 16 && !bSigned )
184 48 : return GDT_UInt16;
185 780 : else if( nBits == 32 && bFloating && bComplex )
186 46 : return GDT_CFloat32;
187 734 : else if( nBits == 32 && bFloating )
188 486 : return GDT_Float32;
189 248 : else if( nBits == 32 && bComplex )
190 44 : return GDT_CInt32;
191 204 : else if( nBits == 32 && bSigned )
192 64 : return GDT_Int32;
193 140 : else if( nBits == 32 && !bSigned )
194 46 : return GDT_UInt32;
195 94 : else if( nBits == 64 && bComplex )
196 46 : return GDT_CFloat64;
197 : else
198 48 : 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 15338858 : int CPL_STDCALL GDALGetDataTypeSize( GDALDataType eDataType )
216 :
217 : {
218 15338858 : switch( eDataType )
219 : {
220 : case GDT_Byte:
221 8746836 : return 8;
222 :
223 : case GDT_UInt16:
224 : case GDT_Int16:
225 2834116 : return 16;
226 :
227 : case GDT_UInt32:
228 : case GDT_Int32:
229 : case GDT_Float32:
230 : case GDT_CInt16:
231 3326254 : return 32;
232 :
233 : case GDT_Float64:
234 : case GDT_CInt32:
235 : case GDT_CFloat32:
236 88052 : return 64;
237 :
238 : case GDT_CFloat64:
239 343600 : 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 18514 : int CPL_STDCALL GDALDataTypeIsComplex( GDALDataType eDataType )
259 :
260 : {
261 18514 : switch( eDataType )
262 : {
263 : case GDT_CInt16:
264 : case GDT_CInt32:
265 : case GDT_CFloat32:
266 : case GDT_CFloat64:
267 666 : return TRUE;
268 :
269 : default:
270 17848 : 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 37078 : const char * CPL_STDCALL GDALGetDataTypeName( GDALDataType eDataType )
293 :
294 : {
295 37078 : switch( eDataType )
296 : {
297 : case GDT_Unknown:
298 460 : return "Unknown";
299 :
300 : case GDT_Byte:
301 19796 : return "Byte";
302 :
303 : case GDT_UInt16:
304 2160 : return "UInt16";
305 :
306 : case GDT_Int16:
307 2056 : return "Int16";
308 :
309 : case GDT_UInt32:
310 1834 : return "UInt32";
311 :
312 : case GDT_Int32:
313 1780 : return "Int32";
314 :
315 : case GDT_Float32:
316 1944 : return "Float32";
317 :
318 : case GDT_Float64:
319 1504 : return "Float64";
320 :
321 : case GDT_CInt16:
322 1416 : return "CInt16";
323 :
324 : case GDT_CInt32:
325 1384 : return "CInt32";
326 :
327 : case GDT_CFloat32:
328 1386 : return "CFloat32";
329 :
330 : case GDT_CFloat64:
331 1358 : 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 1024 : GDALDataType CPL_STDCALL GDALGetDataTypeByName( const char *pszName )
354 :
355 : {
356 1024 : VALIDATE_POINTER1( pszName, "GDALGetDataTypeByName", GDT_Unknown );
357 :
358 : int iType;
359 :
360 2362 : for( iType = 1; iType < GDT_TypeCount; iType++ )
361 : {
362 2360 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
363 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType), pszName) )
364 : {
365 1022 : return (GDALDataType)iType;
366 : }
367 : }
368 :
369 2 : 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 8 : const char *GDALGetPaletteInterpretationName( GDALPaletteInterp eInterp )
459 :
460 : {
461 8 : switch( eInterp )
462 : {
463 : case GPI_Gray:
464 0 : return "Gray";
465 :
466 : case GPI_RGB:
467 8 : 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 4090 : const char *GDALGetColorInterpretationName( GDALColorInterp eInterp )
499 :
500 : {
501 4090 : switch( eInterp )
502 : {
503 : case GCI_Undefined:
504 1040 : return "Undefined";
505 :
506 : case GCI_GrayIndex:
507 1698 : return "Gray";
508 :
509 : case GCI_PaletteIndex:
510 318 : return "Palette";
511 :
512 : case GCI_RedBand:
513 370 : return "Red";
514 :
515 : case GCI_GreenBand:
516 280 : return "Green";
517 :
518 : case GCI_BlueBand:
519 202 : return "Blue";
520 :
521 : case GCI_AlphaBand:
522 68 : return "Alpha";
523 :
524 : case GCI_HueBand:
525 12 : return "Hue";
526 :
527 : case GCI_SaturationBand:
528 12 : return "Saturation";
529 :
530 : case GCI_LightnessBand:
531 12 : return "Lightness";
532 :
533 : case GCI_CyanBand:
534 12 : return "Cyan";
535 :
536 : case GCI_MagentaBand:
537 12 : return "Magenta";
538 :
539 : case GCI_YellowBand:
540 12 : return "Yellow";
541 :
542 : case GCI_BlackBand:
543 12 : return "Black";
544 :
545 : case GCI_YCbCr_YBand:
546 14 : return "YCbCr_Y";
547 :
548 : case GCI_YCbCr_CbBand:
549 10 : return "YCbCr_Cb";
550 :
551 : case GCI_YCbCr_CrBand:
552 6 : 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 1036 : GDALColorInterp GDALGetColorInterpretationByName( const char *pszName )
577 :
578 : {
579 1036 : VALIDATE_POINTER1( pszName, "GDALGetColorInterpretationByName", GCI_Undefined );
580 :
581 : int iType;
582 :
583 3128 : for( iType = 0; iType <= GCI_Max; iType++ )
584 : {
585 3128 : if( EQUAL(GDALGetColorInterpretationName((GDALColorInterp)iType), pszName) )
586 : {
587 1036 : 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 195002 : int CPL_STDCALL GDALDummyProgress( double dfComplete, const char *pszMessage,
608 : void *pData )
609 :
610 : {
611 195002 : 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 66668 : int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
632 : void *pData )
633 :
634 : {
635 66668 : GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
636 :
637 : return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
638 : + psInfo->dfMin,
639 66668 : 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 1396 : void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
691 : GDALProgressFunc pfnProgress,
692 : void * pData )
693 :
694 : {
695 : GDALScaledProgressInfo *psInfo;
696 :
697 : psInfo = (GDALScaledProgressInfo *)
698 1396 : CPLCalloc(sizeof(GDALScaledProgressInfo),1);
699 :
700 1396 : if( ABS(dfMin-dfMax) < 0.0000001 )
701 0 : dfMax = dfMin + 0.01;
702 :
703 1396 : psInfo->pData = pData;
704 1396 : psInfo->pfnProgress = pfnProgress;
705 1396 : psInfo->dfMin = dfMin;
706 1396 : psInfo->dfMax = dfMax;
707 :
708 1396 : 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 1396 : void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
725 :
726 : {
727 1396 : CPLFree( pData );
728 1396 : }
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 69932 : int CPL_STDCALL GDALTermProgress( double dfComplete, const char *pszMessage,
763 : void * pProgressArg )
764 :
765 : {
766 : static int nLastTick = -1;
767 69932 : int nThisTick = (int) (dfComplete * 40.0);
768 :
769 : (void) pProgressArg;
770 :
771 69932 : nThisTick = MIN(40,MAX(0,nThisTick));
772 :
773 : // Have we started a new progress run?
774 69932 : if( nThisTick < nLastTick && nLastTick >= 39 )
775 28 : nLastTick = -1;
776 :
777 69932 : if( nThisTick <= nLastTick )
778 60992 : return TRUE;
779 :
780 51348 : while( nThisTick > nLastTick )
781 : {
782 33468 : nLastTick++;
783 33468 : if( nLastTick % 4 == 0 )
784 9048 : fprintf( stdout, "%d", (nLastTick / 4) * 10 );
785 : else
786 24420 : fprintf( stdout, "." );
787 : }
788 :
789 8940 : if( nThisTick == 40 )
790 814 : fprintf( stdout, " - done.\n" );
791 : else
792 8126 : fflush( stdout );
793 :
794 8940 : 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 39372 : void CPL_STDCALL GDALInitGCPs( int nCount, GDAL_GCP * psGCP )
966 :
967 : {
968 39372 : if( nCount > 0 )
969 : {
970 39246 : VALIDATE_POINTER0( psGCP, "GDALInitGCPs" );
971 : }
972 :
973 104596 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
974 : {
975 65224 : memset( psGCP, 0, sizeof(GDAL_GCP) );
976 65224 : psGCP->pszId = CPLStrdup("");
977 65224 : psGCP->pszInfo = CPLStrdup("");
978 65224 : psGCP++;
979 : }
980 : }
981 :
982 : /************************************************************************/
983 : /* GDALDeinitGCPs() */
984 : /************************************************************************/
985 :
986 12210 : void CPL_STDCALL GDALDeinitGCPs( int nCount, GDAL_GCP * psGCP )
987 :
988 : {
989 12210 : if ( nCount > 0 )
990 : {
991 710 : VALIDATE_POINTER0( psGCP, "GDALDeinitGCPs" );
992 : }
993 :
994 77948 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
995 : {
996 65738 : CPLFree( psGCP->pszId );
997 65738 : CPLFree( psGCP->pszInfo );
998 65738 : psGCP++;
999 : }
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* GDALDuplicateGCPs() */
1004 : /************************************************************************/
1005 :
1006 : GDAL_GCP * CPL_STDCALL
1007 222 : GDALDuplicateGCPs( int nCount, const GDAL_GCP *pasGCPList )
1008 :
1009 : {
1010 : GDAL_GCP *pasReturn;
1011 :
1012 222 : pasReturn = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nCount);
1013 222 : GDALInitGCPs( nCount, pasReturn );
1014 :
1015 714 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
1016 : {
1017 492 : CPLFree( pasReturn[iGCP].pszId );
1018 492 : pasReturn[iGCP].pszId = CPLStrdup( pasGCPList[iGCP].pszId );
1019 :
1020 492 : CPLFree( pasReturn[iGCP].pszInfo );
1021 492 : pasReturn[iGCP].pszInfo = CPLStrdup( pasGCPList[iGCP].pszInfo );
1022 :
1023 492 : pasReturn[iGCP].dfGCPPixel = pasGCPList[iGCP].dfGCPPixel;
1024 492 : pasReturn[iGCP].dfGCPLine = pasGCPList[iGCP].dfGCPLine;
1025 492 : pasReturn[iGCP].dfGCPX = pasGCPList[iGCP].dfGCPX;
1026 492 : pasReturn[iGCP].dfGCPY = pasGCPList[iGCP].dfGCPY;
1027 492 : pasReturn[iGCP].dfGCPZ = pasGCPList[iGCP].dfGCPZ;
1028 : }
1029 :
1030 222 : 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 12580 : CPLString GDALFindAssociatedFile( const char *pszBaseFilename,
1064 : const char *pszExt,
1065 : char **papszSiblingFiles,
1066 : int nFlags )
1067 :
1068 : {
1069 : (void) nFlags;
1070 :
1071 12580 : CPLString osTarget = CPLResetExtension( pszBaseFilename, pszExt );
1072 :
1073 12580 : if( papszSiblingFiles == NULL )
1074 : {
1075 : VSIStatBufL sStatBuf;
1076 :
1077 5806 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1078 : {
1079 5756 : CPLString osAltExt = pszExt;
1080 :
1081 5756 : if( islower( pszExt[0] ) )
1082 0 : osAltExt.toupper();
1083 : else
1084 5756 : osAltExt.tolower();
1085 :
1086 5756 : osTarget = CPLResetExtension( pszBaseFilename, osAltExt );
1087 :
1088 5756 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1089 5752 : return "";
1090 : }
1091 : }
1092 : else
1093 : {
1094 : int iSibling = CSLFindString( papszSiblingFiles,
1095 6774 : CPLGetFilename(osTarget) );
1096 6774 : if( iSibling < 0 )
1097 6756 : return "";
1098 :
1099 18 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
1100 18 : osTarget += papszSiblingFiles[iSibling];
1101 : }
1102 :
1103 72 : return osTarget;
1104 : }
1105 :
1106 : /************************************************************************/
1107 : /* GDALLoadOziMapFile() */
1108 : /************************************************************************/
1109 :
1110 : #define MAX_GCP 30
1111 :
1112 2 : 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 2 : int iLine, nLines=0;
1120 2 : int nCoordinateCount = 0;
1121 : GDAL_GCP asGCPs[MAX_GCP];
1122 :
1123 2 : VALIDATE_POINTER1( pszFilename, "GDALLoadOziMapFile", FALSE );
1124 2 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadOziMapFile", FALSE );
1125 2 : VALIDATE_POINTER1( pnGCPCount, "GDALLoadOziMapFile", FALSE );
1126 2 : VALIDATE_POINTER1( ppasGCPs, "GDALLoadOziMapFile", FALSE );
1127 :
1128 2 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
1129 :
1130 2 : if ( !papszLines )
1131 0 : return FALSE;
1132 :
1133 2 : nLines = CSLCount( papszLines );
1134 :
1135 : // Check the OziExplorer Map file signature
1136 4 : if ( nLines < 5
1137 2 : || !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 2 : OGRSpatialReference oSRS;
1147 2 : const char *pszProj = NULL, *pszProjParms = NULL;
1148 2 : OGRErr eErr = OGRERR_NONE;
1149 :
1150 : /* The Map Scale Factor has been introduced recently on the 6th line */
1151 : /* and is a trick that is used to just change that line without changing */
1152 : /* the rest of the MAP file but providing an imagery that is smaller or larger */
1153 : /* so we have to correct the pixel/line values read in the .MAP file so they */
1154 : /* match the actual imagery dimension. Well, this is a bad summary of what */
1155 : /* is explained at http://tech.groups.yahoo.com/group/OziUsers-L/message/12484 */
1156 2 : double dfMSF = 1;
1157 :
1158 104 : for ( iLine = 5; iLine < nLines; iLine++ )
1159 : {
1160 102 : if ( EQUALN(papszLines[iLine], "MSF,", 4) )
1161 : {
1162 0 : dfMSF = atof(papszLines[iLine] + 4);
1163 0 : if (dfMSF <= 0.01) /* Suspicious values */
1164 : {
1165 0 : CPLDebug("OZI", "Suspicious MSF value : %s", papszLines[iLine]);
1166 0 : dfMSF = 1;
1167 : }
1168 : }
1169 102 : else if ( EQUALN(papszLines[iLine], "Map Projection", 14) )
1170 : {
1171 2 : pszProj = papszLines[iLine];
1172 : }
1173 100 : else if ( EQUALN(papszLines[iLine], "Projection Setup", 16) )
1174 : {
1175 2 : pszProjParms = papszLines[iLine];
1176 : }
1177 : }
1178 :
1179 2 : if ( papszLines[4][0] != '\0' && pszProj && pszProjParms )
1180 : {
1181 2 : eErr = oSRS.importFromOzi( papszLines[4], pszProj, pszProjParms );
1182 2 : if ( eErr == OGRERR_NONE )
1183 : {
1184 2 : if ( ppszWKT != NULL )
1185 2 : oSRS.exportToWkt( ppszWKT );
1186 : }
1187 : }
1188 :
1189 : // Iterate all lines in the TAB-file
1190 104 : for ( iLine = 5; iLine < nLines; iLine++ )
1191 : {
1192 102 : char **papszTok = NULL;
1193 :
1194 102 : papszTok = CSLTokenizeString2( papszLines[iLine], ",",
1195 : CSLT_ALLOWEMPTYTOKENS
1196 : | CSLT_STRIPLEADSPACES
1197 204 : | CSLT_STRIPENDSPACES );
1198 :
1199 102 : if ( CSLCount(papszTok) < 12 )
1200 : {
1201 42 : CSLDestroy(papszTok);
1202 42 : continue;
1203 : }
1204 :
1205 188 : if ( CSLCount(papszTok) >= 17
1206 60 : && EQUALN(papszTok[0], "Point", 5)
1207 60 : && !EQUAL(papszTok[2], "")
1208 8 : && !EQUAL(papszTok[3], "")
1209 : && nCoordinateCount < MAX_GCP )
1210 : {
1211 8 : int bReadOk = FALSE;
1212 8 : double dfLon = 0., dfLat = 0.;
1213 :
1214 40 : if ( !EQUAL(papszTok[6], "")
1215 8 : && !EQUAL(papszTok[7], "")
1216 8 : && !EQUAL(papszTok[9], "")
1217 8 : && !EQUAL(papszTok[10], "") )
1218 : {
1219 : // Set geographical coordinates of the pixels
1220 8 : dfLon = CPLAtofM(papszTok[9]) + CPLAtofM(papszTok[10]) / 60.0;
1221 8 : dfLat = CPLAtofM(papszTok[6]) + CPLAtofM(papszTok[7]) / 60.0;
1222 8 : if ( EQUAL(papszTok[11], "W") )
1223 2 : dfLon = -dfLon;
1224 8 : if ( EQUAL(papszTok[8], "S") )
1225 0 : dfLat = -dfLat;
1226 :
1227 : // Transform from the geographical coordinates into projected
1228 : // coordinates.
1229 8 : if ( eErr == OGRERR_NONE )
1230 : {
1231 8 : OGRSpatialReference *poLatLong = NULL;
1232 8 : OGRCoordinateTransformation *poTransform = NULL;
1233 :
1234 8 : poLatLong = oSRS.CloneGeogCS();
1235 8 : if ( poLatLong )
1236 : {
1237 8 : poTransform = OGRCreateCoordinateTransformation( poLatLong, &oSRS );
1238 8 : if ( poTransform )
1239 : {
1240 8 : bReadOk = poTransform->Transform( 1, &dfLon, &dfLat );
1241 8 : delete poTransform;
1242 : }
1243 8 : delete poLatLong;
1244 : }
1245 : }
1246 : }
1247 0 : else if ( !EQUAL(papszTok[14], "")
1248 0 : && !EQUAL(papszTok[15], "") )
1249 : {
1250 : // Set cartesian coordinates of the pixels.
1251 0 : dfLon = CPLAtofM(papszTok[14]);
1252 0 : dfLat = CPLAtofM(papszTok[15]);
1253 0 : bReadOk = TRUE;
1254 :
1255 0 : if ( EQUAL(papszTok[16], "S") )
1256 0 : dfLat = -dfLat;
1257 : }
1258 :
1259 8 : if ( bReadOk )
1260 : {
1261 8 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1262 :
1263 : // Set pixel/line part
1264 8 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]) / dfMSF;
1265 8 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]) / dfMSF;
1266 :
1267 8 : asGCPs[nCoordinateCount].dfGCPX = dfLon;
1268 8 : asGCPs[nCoordinateCount].dfGCPY = dfLat;
1269 :
1270 8 : nCoordinateCount++;
1271 : }
1272 : }
1273 :
1274 60 : CSLDestroy( papszTok );
1275 : }
1276 :
1277 2 : CSLDestroy( papszLines );
1278 :
1279 2 : if ( nCoordinateCount == 0 )
1280 : {
1281 : CPLDebug( "GDAL", "GDALLoadOziMapFile(\"%s\") did read no GCPs.",
1282 0 : pszFilename );
1283 0 : return FALSE;
1284 : }
1285 :
1286 : /* -------------------------------------------------------------------- */
1287 : /* Try to convert the GCPs into a geotransform definition, if */
1288 : /* possible. Otherwise we will need to use them as GCPs. */
1289 : /* -------------------------------------------------------------------- */
1290 2 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1291 : CSLTestBoolean(CPLGetConfigOption("OZI_APPROX_GEOTRANSFORM", "NO")) ) )
1292 : {
1293 2 : if ( pnGCPCount && ppasGCPs )
1294 : {
1295 : CPLDebug( "GDAL",
1296 : "GDALLoadOziMapFile(%s) found file, wasn't able to derive a\n"
1297 : "first order geotransform. Using points as GCPs.",
1298 2 : pszFilename );
1299 :
1300 : *ppasGCPs = (GDAL_GCP *)
1301 2 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1302 2 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1303 2 : *pnGCPCount = nCoordinateCount;
1304 : }
1305 : }
1306 : else
1307 : {
1308 0 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1309 : }
1310 :
1311 2 : return TRUE;
1312 : }
1313 :
1314 : #undef MAX_GCP
1315 :
1316 : /************************************************************************/
1317 : /* GDALReadOziMapFile() */
1318 : /************************************************************************/
1319 :
1320 62 : int CPL_STDCALL GDALReadOziMapFile( const char * pszBaseFilename,
1321 : double *padfGeoTransform, char **ppszWKT,
1322 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1323 :
1324 :
1325 : {
1326 : const char *pszOzi;
1327 : FILE *fpOzi;
1328 :
1329 : /* -------------------------------------------------------------------- */
1330 : /* Try lower case, then upper case. */
1331 : /* -------------------------------------------------------------------- */
1332 62 : pszOzi = CPLResetExtension( pszBaseFilename, "map" );
1333 :
1334 62 : fpOzi = VSIFOpen( pszOzi, "rt" );
1335 :
1336 62 : if ( fpOzi == NULL && VSIIsCaseSensitiveFS(pszOzi) )
1337 : {
1338 62 : pszOzi = CPLResetExtension( pszBaseFilename, "MAP" );
1339 62 : fpOzi = VSIFOpen( pszOzi, "rt" );
1340 : }
1341 :
1342 62 : if ( fpOzi == NULL )
1343 62 : return FALSE;
1344 :
1345 0 : VSIFClose( fpOzi );
1346 :
1347 : /* -------------------------------------------------------------------- */
1348 : /* We found the file, now load and parse it. */
1349 : /* -------------------------------------------------------------------- */
1350 : return GDALLoadOziMapFile( pszOzi, padfGeoTransform, ppszWKT,
1351 0 : pnGCPCount, ppasGCPs );
1352 : }
1353 :
1354 : /************************************************************************/
1355 : /* GDALLoadTabFile() */
1356 : /* */
1357 : /* Helper function for translator implementators wanting */
1358 : /* support for MapInfo .tab-files. */
1359 : /************************************************************************/
1360 :
1361 : #define MAX_GCP 256
1362 :
1363 4 : int CPL_STDCALL GDALLoadTabFile( const char *pszFilename,
1364 : double *padfGeoTransform, char **ppszWKT,
1365 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1366 :
1367 :
1368 : {
1369 : char **papszLines;
1370 4 : char **papszTok=NULL;
1371 4 : int bTypeRasterFound = FALSE;
1372 4 : int bInsideTableDef = FALSE;
1373 4 : int iLine, numLines=0;
1374 4 : int nCoordinateCount = 0;
1375 : GDAL_GCP asGCPs[MAX_GCP];
1376 :
1377 4 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
1378 :
1379 4 : if ( !papszLines )
1380 0 : return FALSE;
1381 :
1382 4 : numLines = CSLCount(papszLines);
1383 :
1384 : // Iterate all lines in the TAB-file
1385 56 : for(iLine=0; iLine<numLines; iLine++)
1386 : {
1387 52 : CSLDestroy(papszTok);
1388 52 : papszTok = CSLTokenizeStringComplex(papszLines[iLine], " \t(),;",
1389 104 : TRUE, FALSE);
1390 :
1391 52 : if (CSLCount(papszTok) < 2)
1392 8 : continue;
1393 :
1394 : // Did we find table definition
1395 48 : if (EQUAL(papszTok[0], "Definition") && EQUAL(papszTok[1], "Table") )
1396 : {
1397 4 : bInsideTableDef = TRUE;
1398 : }
1399 44 : else if (bInsideTableDef && (EQUAL(papszTok[0], "Type")) )
1400 : {
1401 : // Only RASTER-type will be handled
1402 4 : if (EQUAL(papszTok[1], "RASTER"))
1403 : {
1404 4 : bTypeRasterFound = TRUE;
1405 : }
1406 : else
1407 : {
1408 0 : CSLDestroy(papszTok);
1409 0 : CSLDestroy(papszLines);
1410 0 : return FALSE;
1411 : }
1412 : }
1413 56 : else if (bTypeRasterFound && bInsideTableDef
1414 : && CSLCount(papszTok) > 4
1415 20 : && EQUAL(papszTok[4], "Label")
1416 : && nCoordinateCount < MAX_GCP )
1417 : {
1418 16 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1419 :
1420 16 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
1421 16 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
1422 16 : asGCPs[nCoordinateCount].dfGCPX = CPLAtofM(papszTok[0]);
1423 16 : asGCPs[nCoordinateCount].dfGCPY = CPLAtofM(papszTok[1]);
1424 16 : if( papszTok[5] != NULL )
1425 : {
1426 16 : CPLFree( asGCPs[nCoordinateCount].pszId );
1427 16 : asGCPs[nCoordinateCount].pszId = CPLStrdup(papszTok[5]);
1428 : }
1429 :
1430 16 : nCoordinateCount++;
1431 : }
1432 32 : else if( bTypeRasterFound && bInsideTableDef
1433 8 : && EQUAL(papszTok[0],"CoordSys")
1434 : && ppszWKT != NULL )
1435 : {
1436 4 : OGRSpatialReference oSRS;
1437 :
1438 4 : if( oSRS.importFromMICoordSys( papszLines[iLine] ) == OGRERR_NONE )
1439 4 : oSRS.exportToWkt( ppszWKT );
1440 : }
1441 20 : else if( EQUAL(papszTok[0],"Units")
1442 : && CSLCount(papszTok) > 1
1443 4 : && EQUAL(papszTok[1],"degree") )
1444 : {
1445 : /*
1446 : ** If we have units of "degree", but a projected coordinate
1447 : ** system we need to convert it to geographic. See to01_02.TAB.
1448 : */
1449 0 : if( ppszWKT != NULL && *ppszWKT != NULL
1450 : && EQUALN(*ppszWKT,"PROJCS",6) )
1451 : {
1452 0 : OGRSpatialReference oSRS, oSRSGeogCS;
1453 0 : char *pszSrcWKT = *ppszWKT;
1454 :
1455 0 : oSRS.importFromWkt( &pszSrcWKT );
1456 0 : oSRSGeogCS.CopyGeogCSFrom( &oSRS );
1457 0 : CPLFree( *ppszWKT );
1458 0 : oSRSGeogCS.exportToWkt( ppszWKT );
1459 : }
1460 : }
1461 :
1462 : }
1463 :
1464 4 : CSLDestroy(papszTok);
1465 4 : CSLDestroy(papszLines);
1466 :
1467 4 : if( nCoordinateCount == 0 )
1468 : {
1469 : CPLDebug( "GDAL", "GDALLoadTabFile(%s) did not get any GCPs.",
1470 0 : pszFilename );
1471 0 : return FALSE;
1472 : }
1473 :
1474 : /* -------------------------------------------------------------------- */
1475 : /* Try to convert the GCPs into a geotransform definition, if */
1476 : /* possible. Otherwise we will need to use them as GCPs. */
1477 : /* -------------------------------------------------------------------- */
1478 4 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1479 : FALSE ) )
1480 : {
1481 0 : if (pnGCPCount && ppasGCPs)
1482 : {
1483 : CPLDebug( "GDAL",
1484 : "GDALLoadTabFile(%s) found file, wasn't able to derive a\n"
1485 : "first order geotransform. Using points as GCPs.",
1486 0 : pszFilename );
1487 :
1488 : *ppasGCPs = (GDAL_GCP *)
1489 0 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1490 0 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1491 0 : *pnGCPCount = nCoordinateCount;
1492 : }
1493 : }
1494 : else
1495 : {
1496 4 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1497 : }
1498 :
1499 4 : return TRUE;
1500 : }
1501 :
1502 : #undef MAX_GCP
1503 :
1504 : /************************************************************************/
1505 : /* GDALReadTabFile() */
1506 : /* */
1507 : /* Helper function for translator implementators wanting */
1508 : /* support for MapInfo .tab-files. */
1509 : /************************************************************************/
1510 :
1511 0 : int CPL_STDCALL GDALReadTabFile( const char * pszBaseFilename,
1512 : double *padfGeoTransform, char **ppszWKT,
1513 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1514 :
1515 :
1516 : {
1517 : return GDALReadTabFile2(pszBaseFilename, padfGeoTransform,
1518 : ppszWKT, pnGCPCount, ppasGCPs,
1519 0 : NULL, NULL);
1520 : }
1521 :
1522 :
1523 2174 : int GDALReadTabFile2( const char * pszBaseFilename,
1524 : double *padfGeoTransform, char **ppszWKT,
1525 : int *pnGCPCount, GDAL_GCP **ppasGCPs,
1526 : char** papszSiblingFiles, char** ppszTabFileNameOut )
1527 : {
1528 : const char *pszTAB;
1529 : VSILFILE *fpTAB;
1530 :
1531 2174 : if (ppszTabFileNameOut)
1532 2174 : *ppszTabFileNameOut = NULL;
1533 :
1534 2174 : pszTAB = CPLResetExtension( pszBaseFilename, "tab" );
1535 :
1536 2174 : if (papszSiblingFiles)
1537 : {
1538 2006 : int iSibling = CSLFindString(papszSiblingFiles, CPLGetFilename(pszTAB));
1539 2006 : if (iSibling >= 0)
1540 : {
1541 4 : CPLString osTabFilename = pszBaseFilename;
1542 : osTabFilename.resize(strlen(pszBaseFilename) -
1543 4 : strlen(CPLGetFilename(pszBaseFilename)));
1544 4 : osTabFilename += papszSiblingFiles[iSibling];
1545 4 : if ( GDALLoadTabFile(osTabFilename, padfGeoTransform, ppszWKT,
1546 : pnGCPCount, ppasGCPs ) )
1547 : {
1548 4 : if (ppszTabFileNameOut)
1549 4 : *ppszTabFileNameOut = CPLStrdup(osTabFilename);
1550 4 : return TRUE;
1551 0 : }
1552 : }
1553 2002 : return FALSE;
1554 : }
1555 :
1556 : /* -------------------------------------------------------------------- */
1557 : /* Try lower case, then upper case. */
1558 : /* -------------------------------------------------------------------- */
1559 :
1560 168 : fpTAB = VSIFOpenL( pszTAB, "rt" );
1561 :
1562 168 : if( fpTAB == NULL && VSIIsCaseSensitiveFS(pszTAB) )
1563 : {
1564 168 : pszTAB = CPLResetExtension( pszBaseFilename, "TAB" );
1565 168 : fpTAB = VSIFOpenL( pszTAB, "rt" );
1566 : }
1567 :
1568 168 : if( fpTAB == NULL )
1569 168 : return FALSE;
1570 :
1571 0 : VSIFCloseL( fpTAB );
1572 :
1573 : /* -------------------------------------------------------------------- */
1574 : /* We found the file, now load and parse it. */
1575 : /* -------------------------------------------------------------------- */
1576 0 : if (GDALLoadTabFile( pszTAB, padfGeoTransform, ppszWKT,
1577 : pnGCPCount, ppasGCPs ) )
1578 : {
1579 0 : if (ppszTabFileNameOut)
1580 0 : *ppszTabFileNameOut = CPLStrdup(pszTAB);
1581 0 : return TRUE;
1582 : }
1583 0 : return FALSE;
1584 : }
1585 :
1586 : /************************************************************************/
1587 : /* GDALLoadWorldFile() */
1588 : /************************************************************************/
1589 :
1590 : /**
1591 : * \brief Read ESRI world file.
1592 : *
1593 : * This function reads an ESRI style world file, and formats a geotransform
1594 : * from its contents.
1595 : *
1596 : * The world file contains an affine transformation with the parameters
1597 : * in a different order than in a geotransform array.
1598 : *
1599 : * <ul>
1600 : * <li> geotransform[1] : width of pixel
1601 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1602 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1603 : * <li> geotransform[5] : height of pixel (but negative)
1604 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1605 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1606 : * </ul>
1607 : *
1608 : * @param pszFilename the world file name.
1609 : * @param padfGeoTransform the six double array into which the
1610 : * geotransformation should be placed.
1611 : *
1612 : * @return TRUE on success or FALSE on failure.
1613 : */
1614 :
1615 : int CPL_STDCALL
1616 38 : GDALLoadWorldFile( const char *pszFilename, double *padfGeoTransform )
1617 :
1618 : {
1619 : char **papszLines;
1620 :
1621 38 : VALIDATE_POINTER1( pszFilename, "GDALLoadWorldFile", FALSE );
1622 38 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadWorldFile", FALSE );
1623 :
1624 38 : papszLines = CSLLoad2( pszFilename, 100, 100, NULL );
1625 :
1626 38 : if ( !papszLines )
1627 0 : return FALSE;
1628 :
1629 : double world[6];
1630 : // reads the first 6 non-empty lines
1631 38 : int nLines = 0;
1632 38 : int nLinesCount = CSLCount(papszLines);
1633 38 : for( int i = 0; i < nLinesCount && nLines < 6; ++i )
1634 : {
1635 228 : CPLString line(papszLines[i]);
1636 228 : if( line.Trim().empty() )
1637 0 : continue;
1638 :
1639 228 : world[nLines] = CPLAtofM(line);
1640 228 : ++nLines;
1641 : }
1642 :
1643 114 : if( nLines == 6
1644 38 : && (world[0] != 0.0 || world[2] != 0.0)
1645 38 : && (world[3] != 0.0 || world[1] != 0.0) )
1646 : {
1647 38 : padfGeoTransform[0] = world[4];
1648 38 : padfGeoTransform[1] = world[0];
1649 38 : padfGeoTransform[2] = world[2];
1650 38 : padfGeoTransform[3] = world[5];
1651 38 : padfGeoTransform[4] = world[1];
1652 38 : padfGeoTransform[5] = world[3];
1653 :
1654 : // correct for center of pixel vs. top left of pixel
1655 38 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[1];
1656 38 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[2];
1657 38 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[4];
1658 38 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[5];
1659 :
1660 38 : CSLDestroy(papszLines);
1661 :
1662 38 : return TRUE;
1663 : }
1664 : else
1665 : {
1666 : CPLDebug( "GDAL",
1667 : "GDALLoadWorldFile(%s) found file, but it was corrupt.",
1668 0 : pszFilename );
1669 0 : CSLDestroy(papszLines);
1670 0 : return FALSE;
1671 : }
1672 : }
1673 :
1674 : /************************************************************************/
1675 : /* GDALReadWorldFile() */
1676 : /************************************************************************/
1677 :
1678 : /**
1679 : * \brief Read ESRI world file.
1680 : *
1681 : * This function reads an ESRI style world file, and formats a geotransform
1682 : * from its contents. It does the same as GDALLoadWorldFile() function, but
1683 : * it will form the filename for the worldfile from the filename of the raster
1684 : * file referred and the suggested extension. If no extension is provided,
1685 : * the code will internally try the unix style and windows style world file
1686 : * extensions (eg. for .tif these would be .tfw and .tifw).
1687 : *
1688 : * The world file contains an affine transformation with the parameters
1689 : * in a different order than in a geotransform array.
1690 : *
1691 : * <ul>
1692 : * <li> geotransform[1] : width of pixel
1693 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1694 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1695 : * <li> geotransform[5] : height of pixel (but negative)
1696 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1697 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1698 : * </ul>
1699 : *
1700 : * @param pszBaseFilename the target raster file.
1701 : * @param pszExtension the extension to use (ie. ".wld") or NULL to derive it
1702 : * from the pszBaseFilename
1703 : * @param padfGeoTransform the six double array into which the
1704 : * geotransformation should be placed.
1705 : *
1706 : * @return TRUE on success or FALSE on failure.
1707 : */
1708 :
1709 : int CPL_STDCALL
1710 2178 : GDALReadWorldFile( const char *pszBaseFilename, const char *pszExtension,
1711 : double *padfGeoTransform )
1712 :
1713 : {
1714 : return GDALReadWorldFile2(pszBaseFilename, pszExtension,
1715 2178 : padfGeoTransform, NULL, NULL);
1716 : }
1717 :
1718 11488 : int GDALReadWorldFile2( const char *pszBaseFilename, const char *pszExtension,
1719 : double *padfGeoTransform, char** papszSiblingFiles,
1720 : char** ppszWorldFileNameOut )
1721 : {
1722 : const char *pszTFW;
1723 : char szExtUpper[32], szExtLower[32];
1724 : int i;
1725 :
1726 11488 : VALIDATE_POINTER1( pszBaseFilename, "GDALReadWorldFile", FALSE );
1727 11488 : VALIDATE_POINTER1( padfGeoTransform, "GDALReadWorldFile", FALSE );
1728 :
1729 11488 : if (ppszWorldFileNameOut)
1730 8746 : *ppszWorldFileNameOut = NULL;
1731 :
1732 : /* -------------------------------------------------------------------- */
1733 : /* If we aren't given an extension, try both the unix and */
1734 : /* windows style extensions. */
1735 : /* -------------------------------------------------------------------- */
1736 11488 : if( pszExtension == NULL )
1737 : {
1738 : char szDerivedExtension[100];
1739 2598 : std::string oBaseExt = CPLGetExtension( pszBaseFilename );
1740 :
1741 5196 : if( oBaseExt.length() < 2 )
1742 212 : return FALSE;
1743 :
1744 : // windows version - first + last + 'w'
1745 2386 : szDerivedExtension[0] = oBaseExt[0];
1746 2386 : szDerivedExtension[1] = oBaseExt[oBaseExt.length()-1];
1747 2386 : szDerivedExtension[2] = 'w';
1748 2386 : szDerivedExtension[3] = '\0';
1749 :
1750 2386 : if( GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
1751 : padfGeoTransform, papszSiblingFiles,
1752 : ppszWorldFileNameOut ) )
1753 10 : return TRUE;
1754 :
1755 : // unix version - extension + 'w'
1756 2376 : if( oBaseExt.length() > sizeof(szDerivedExtension)-2 )
1757 0 : return FALSE;
1758 :
1759 2376 : strcpy( szDerivedExtension, oBaseExt.c_str() );
1760 2376 : strcat( szDerivedExtension, "w" );
1761 : return GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
1762 : padfGeoTransform, papszSiblingFiles,
1763 2376 : ppszWorldFileNameOut );
1764 : }
1765 :
1766 : /* -------------------------------------------------------------------- */
1767 : /* Skip the leading period in the extension if there is one. */
1768 : /* -------------------------------------------------------------------- */
1769 8890 : if( *pszExtension == '.' )
1770 640 : pszExtension++;
1771 :
1772 : /* -------------------------------------------------------------------- */
1773 : /* Generate upper and lower case versions of the extension. */
1774 : /* -------------------------------------------------------------------- */
1775 8890 : CPLStrlcpy( szExtUpper, pszExtension, sizeof(szExtUpper) );
1776 8890 : CPLStrlcpy( szExtLower, pszExtension, sizeof(szExtLower) );
1777 :
1778 37968 : for( i = 0; szExtUpper[i] != '\0'; i++ )
1779 : {
1780 29078 : szExtUpper[i] = (char) toupper(szExtUpper[i]);
1781 29078 : szExtLower[i] = (char) tolower(szExtLower[i]);
1782 : }
1783 :
1784 : VSIStatBufL sStatBuf;
1785 : int bGotTFW;
1786 :
1787 8890 : pszTFW = CPLResetExtension( pszBaseFilename, szExtLower );
1788 :
1789 8890 : if (papszSiblingFiles)
1790 : {
1791 6054 : int iSibling = CSLFindString(papszSiblingFiles, CPLGetFilename(pszTFW));
1792 6054 : if (iSibling >= 0)
1793 : {
1794 28 : CPLString osTFWFilename = pszBaseFilename;
1795 : osTFWFilename.resize(strlen(pszBaseFilename) -
1796 28 : strlen(CPLGetFilename(pszBaseFilename)));
1797 28 : osTFWFilename += papszSiblingFiles[iSibling];
1798 28 : if (GDALLoadWorldFile( osTFWFilename, padfGeoTransform ))
1799 : {
1800 28 : if (ppszWorldFileNameOut)
1801 28 : *ppszWorldFileNameOut = CPLStrdup(osTFWFilename);
1802 28 : return TRUE;
1803 0 : }
1804 : }
1805 6026 : return FALSE;
1806 : }
1807 :
1808 : /* -------------------------------------------------------------------- */
1809 : /* Try lower case, then upper case. */
1810 : /* -------------------------------------------------------------------- */
1811 :
1812 2836 : bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
1813 :
1814 2836 : if( !bGotTFW && VSIIsCaseSensitiveFS(pszTFW) )
1815 : {
1816 2826 : pszTFW = CPLResetExtension( pszBaseFilename, szExtUpper );
1817 2826 : bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
1818 : }
1819 :
1820 2836 : if( !bGotTFW )
1821 2826 : return FALSE;
1822 :
1823 : /* -------------------------------------------------------------------- */
1824 : /* We found the file, now load and parse it. */
1825 : /* -------------------------------------------------------------------- */
1826 10 : if (GDALLoadWorldFile( pszTFW, padfGeoTransform ))
1827 : {
1828 10 : if (ppszWorldFileNameOut)
1829 4 : *ppszWorldFileNameOut = CPLStrdup(pszTFW);
1830 10 : return TRUE;
1831 : }
1832 0 : return FALSE;
1833 : }
1834 :
1835 : /************************************************************************/
1836 : /* GDALWriteWorldFile() */
1837 : /* */
1838 : /* Helper function for translator implementators wanting */
1839 : /* support for ESRI world files. */
1840 : /************************************************************************/
1841 :
1842 : /**
1843 : * \brief Write ESRI world file.
1844 : *
1845 : * This function writes an ESRI style world file from the passed geotransform.
1846 : *
1847 : * The world file contains an affine transformation with the parameters
1848 : * in a different order than in a geotransform array.
1849 : *
1850 : * <ul>
1851 : * <li> geotransform[1] : width of pixel
1852 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1853 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1854 : * <li> geotransform[5] : height of pixel (but negative)
1855 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1856 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1857 : * </ul>
1858 : *
1859 : * @param pszBaseFilename the target raster file.
1860 : * @param pszExtension the extension to use (ie. ".wld"). Must not be NULL
1861 : * @param padfGeoTransform the six double array from which the
1862 : * geotransformation should be read.
1863 : *
1864 : * @return TRUE on success or FALSE on failure.
1865 : */
1866 :
1867 : int CPL_STDCALL
1868 14 : GDALWriteWorldFile( const char * pszBaseFilename, const char *pszExtension,
1869 : double *padfGeoTransform )
1870 :
1871 : {
1872 14 : VALIDATE_POINTER1( pszBaseFilename, "GDALWriteWorldFile", FALSE );
1873 14 : VALIDATE_POINTER1( pszExtension, "GDALWriteWorldFile", FALSE );
1874 14 : VALIDATE_POINTER1( padfGeoTransform, "GDALWriteWorldFile", FALSE );
1875 :
1876 : /* -------------------------------------------------------------------- */
1877 : /* Prepare the text to write to the file. */
1878 : /* -------------------------------------------------------------------- */
1879 14 : CPLString osTFWText;
1880 :
1881 : osTFWText.Printf( "%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n",
1882 : padfGeoTransform[1],
1883 : padfGeoTransform[4],
1884 : padfGeoTransform[2],
1885 : padfGeoTransform[5],
1886 14 : padfGeoTransform[0]
1887 14 : + 0.5 * padfGeoTransform[1]
1888 14 : + 0.5 * padfGeoTransform[2],
1889 14 : padfGeoTransform[3]
1890 14 : + 0.5 * padfGeoTransform[4]
1891 42 : + 0.5 * padfGeoTransform[5] );
1892 :
1893 : /* -------------------------------------------------------------------- */
1894 : /* Update extention, and write to disk. */
1895 : /* -------------------------------------------------------------------- */
1896 : const char *pszTFW;
1897 : VSILFILE *fpTFW;
1898 :
1899 14 : pszTFW = CPLResetExtension( pszBaseFilename, pszExtension );
1900 14 : fpTFW = VSIFOpenL( pszTFW, "wt" );
1901 14 : if( fpTFW == NULL )
1902 0 : return FALSE;
1903 :
1904 14 : VSIFWriteL( (void *) osTFWText.c_str(), 1, osTFWText.size(), fpTFW );
1905 14 : VSIFCloseL( fpTFW );
1906 :
1907 14 : return TRUE;
1908 : }
1909 :
1910 : /************************************************************************/
1911 : /* GDALVersionInfo() */
1912 : /************************************************************************/
1913 :
1914 : /**
1915 : * \brief Get runtime version information.
1916 : *
1917 : * Available pszRequest values:
1918 : * <ul>
1919 : * <li> "VERSION_NUM": Returns GDAL_VERSION_NUM formatted as a string. ie. "1170"
1920 : * <li> "RELEASE_DATE": Returns GDAL_RELEASE_DATE formatted as a string.
1921 : * ie. "20020416".
1922 : * <li> "RELEASE_NAME": Returns the GDAL_RELEASE_NAME. ie. "1.1.7"
1923 : * <li> "--version": Returns one line version message suitable for use in
1924 : * response to --version requests. ie. "GDAL 1.1.7, released 2002/04/16"
1925 : * <li> "LICENCE": Returns the content of the LICENSE.TXT file from the GDAL_DATA directory.
1926 : * Before GDAL 1.7.0, the returned string was leaking memory but this is now resolved.
1927 : * So the result should not been freed by the caller.
1928 : * </ul>
1929 : *
1930 : * @param pszRequest the type of version info desired, as listed above.
1931 : *
1932 : * @return an internal string containing the requested information.
1933 : */
1934 :
1935 4984 : const char * CPL_STDCALL GDALVersionInfo( const char *pszRequest )
1936 :
1937 : {
1938 : /* -------------------------------------------------------------------- */
1939 : /* LICENSE is a special case. We try to find and read the */
1940 : /* LICENSE.TXT file from the GDAL_DATA directory and return it */
1941 : /* -------------------------------------------------------------------- */
1942 4984 : if( pszRequest != NULL && EQUAL(pszRequest,"LICENSE") )
1943 : {
1944 0 : char* pszResultLicence = (char*) CPLGetTLS( CTLS_VERSIONINFO_LICENCE );
1945 0 : if( pszResultLicence != NULL )
1946 : {
1947 0 : return pszResultLicence;
1948 : }
1949 :
1950 0 : const char *pszFilename = CPLFindFile( "etc", "LICENSE.TXT" );
1951 0 : VSILFILE *fp = NULL;
1952 : int nLength;
1953 :
1954 0 : if( pszFilename != NULL )
1955 0 : fp = VSIFOpenL( pszFilename, "r" );
1956 :
1957 0 : if( fp != NULL )
1958 : {
1959 0 : VSIFSeekL( fp, 0, SEEK_END );
1960 0 : nLength = (int) VSIFTellL( fp ) + 1;
1961 0 : VSIFSeekL( fp, SEEK_SET, 0 );
1962 :
1963 0 : pszResultLicence = (char *) VSICalloc(1,nLength);
1964 0 : if (pszResultLicence)
1965 0 : VSIFReadL( pszResultLicence, 1, nLength-1, fp );
1966 :
1967 0 : VSIFCloseL( fp );
1968 : }
1969 :
1970 0 : if (!pszResultLicence)
1971 : {
1972 : pszResultLicence = CPLStrdup(
1973 : "GDAL/OGR is released under the MIT/X license.\n"
1974 : "The LICENSE.TXT distributed with GDAL/OGR should\n"
1975 0 : "contain additional details.\n" );
1976 : }
1977 :
1978 0 : CPLSetTLS( CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE );
1979 0 : return pszResultLicence;
1980 : }
1981 :
1982 4984 : char* pszResultSmall = (char*) CPLGetTLS( CTLS_VERSIONINFO );
1983 4984 : if( pszResultSmall == NULL )
1984 : {
1985 695 : pszResultSmall = (char*) CPLCalloc(128, 1);
1986 695 : CPLSetTLS( CTLS_VERSIONINFO, pszResultSmall, TRUE );
1987 : }
1988 :
1989 9506 : if( pszRequest == NULL || EQUAL(pszRequest,"VERSION_NUM") )
1990 4522 : sprintf(pszResultSmall, "%d", GDAL_VERSION_NUM );
1991 462 : else if( EQUAL(pszRequest,"RELEASE_DATE") )
1992 0 : sprintf(pszResultSmall, "%d", GDAL_RELEASE_DATE );
1993 462 : else if( EQUAL(pszRequest,"RELEASE_NAME") )
1994 58 : sprintf(pszResultSmall, GDAL_RELEASE_NAME );
1995 : else // --version
1996 : sprintf(pszResultSmall, "GDAL %s, released %d/%02d/%02d",
1997 : GDAL_RELEASE_NAME,
1998 : GDAL_RELEASE_DATE / 10000,
1999 : (GDAL_RELEASE_DATE % 10000) / 100,
2000 404 : GDAL_RELEASE_DATE % 100 );
2001 :
2002 4984 : return pszResultSmall;
2003 : }
2004 :
2005 : /************************************************************************/
2006 : /* GDALCheckVersion() */
2007 : /************************************************************************/
2008 :
2009 : /** Return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor.
2010 :
2011 : The purpose of this method is to ensure that calling code will run with the GDAL
2012 : version it is compiled for. It is primarly intented for external plugins.
2013 :
2014 : @param nVersionMajor Major version to be tested against
2015 : @param nVersionMinor Minor version to be tested against
2016 : @param pszCallingComponentName If not NULL, in case of version mismatch, the method
2017 : will issue a failure mentionning the name of
2018 : the calling component.
2019 :
2020 : @return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor, FALSE otherwise.
2021 : */
2022 26476 : int CPL_STDCALL GDALCheckVersion( int nVersionMajor, int nVersionMinor,
2023 : const char* pszCallingComponentName)
2024 : {
2025 26476 : if (nVersionMajor == GDAL_VERSION_MAJOR &&
2026 : nVersionMinor == GDAL_VERSION_MINOR)
2027 26476 : return TRUE;
2028 :
2029 0 : if (pszCallingComponentName)
2030 : {
2031 : CPLError( CE_Failure, CPLE_AppDefined,
2032 : "%s was compiled against GDAL %d.%d but current library version is %d.%d\n",
2033 : pszCallingComponentName, nVersionMajor, nVersionMinor,
2034 0 : GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
2035 : }
2036 0 : return FALSE;
2037 : }
2038 :
2039 : /************************************************************************/
2040 : /* GDALDecToDMS() */
2041 : /* */
2042 : /* Translate a decimal degrees value to a DMS string with */
2043 : /* hemisphere. */
2044 : /************************************************************************/
2045 :
2046 520 : const char * CPL_STDCALL GDALDecToDMS( double dfAngle, const char * pszAxis,
2047 : int nPrecision )
2048 :
2049 : {
2050 520 : return CPLDecToDMS( dfAngle, pszAxis, nPrecision );
2051 : }
2052 :
2053 : /************************************************************************/
2054 : /* GDALPackedDMSToDec() */
2055 : /************************************************************************/
2056 :
2057 : /**
2058 : * \brief Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
2059 : *
2060 : * See CPLPackedDMSToDec().
2061 : */
2062 :
2063 8 : double CPL_STDCALL GDALPackedDMSToDec( double dfPacked )
2064 :
2065 : {
2066 8 : return CPLPackedDMSToDec( dfPacked );
2067 : }
2068 :
2069 : /************************************************************************/
2070 : /* GDALDecToPackedDMS() */
2071 : /************************************************************************/
2072 :
2073 : /**
2074 : * \brief Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
2075 : *
2076 : * See CPLDecToPackedDMS().
2077 : */
2078 :
2079 8 : double CPL_STDCALL GDALDecToPackedDMS( double dfDec )
2080 :
2081 : {
2082 8 : return CPLDecToPackedDMS( dfDec );
2083 : }
2084 :
2085 : /************************************************************************/
2086 : /* GDALGCPsToGeoTransform() */
2087 : /************************************************************************/
2088 :
2089 : /**
2090 : * \brief Generate Geotransform from GCPs.
2091 : *
2092 : * Given a set of GCPs perform first order fit as a geotransform.
2093 : *
2094 : * Due to imprecision in the calculations the fit algorithm will often
2095 : * return non-zero rotational coefficients even if given perfectly non-rotated
2096 : * inputs. A special case has been implemented for corner corner coordinates
2097 : * given in TL, TR, BR, BL order. So when using this to get a geotransform
2098 : * from 4 corner coordinates, pass them in this order.
2099 : *
2100 : * @param nGCPCount the number of GCPs being passed in.
2101 : * @param pasGCPs the list of GCP structures.
2102 : * @param padfGeoTransform the six double array in which the affine
2103 : * geotransformation will be returned.
2104 : * @param bApproxOK If FALSE the function will fail if the geotransform is not
2105 : * essentially an exact fit (within 0.25 pixel) for all GCPs.
2106 : *
2107 : * @return TRUE on success or FALSE if there aren't enough points to prepare a
2108 : * geotransform, the pointers are ill-determined or if bApproxOK is FALSE
2109 : * and the fit is poor.
2110 : */
2111 :
2112 : int CPL_STDCALL
2113 606 : GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
2114 : double *padfGeoTransform, int bApproxOK )
2115 :
2116 : {
2117 : int i;
2118 :
2119 : /* -------------------------------------------------------------------- */
2120 : /* Recognise a few special cases. */
2121 : /* -------------------------------------------------------------------- */
2122 606 : if( nGCPCount < 2 )
2123 14 : return FALSE;
2124 :
2125 592 : if( nGCPCount == 2 )
2126 : {
2127 0 : if( pasGCPs[1].dfGCPPixel == pasGCPs[0].dfGCPPixel
2128 0 : || pasGCPs[1].dfGCPLine == pasGCPs[0].dfGCPLine )
2129 0 : return FALSE;
2130 :
2131 0 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2132 0 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2133 0 : padfGeoTransform[2] = 0.0;
2134 :
2135 0 : padfGeoTransform[4] = 0.0;
2136 0 : padfGeoTransform[5] = (pasGCPs[1].dfGCPY - pasGCPs[0].dfGCPY)
2137 0 : / (pasGCPs[1].dfGCPLine - pasGCPs[0].dfGCPLine);
2138 :
2139 : padfGeoTransform[0] = pasGCPs[0].dfGCPX
2140 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[1]
2141 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[2];
2142 :
2143 0 : padfGeoTransform[3] = pasGCPs[0].dfGCPY
2144 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[4]
2145 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2146 :
2147 0 : return TRUE;
2148 : }
2149 :
2150 : /* -------------------------------------------------------------------- */
2151 : /* Special case of 4 corner coordinates of a non-rotated */
2152 : /* image. The points must be in TL-TR-BR-BL order for now. */
2153 : /* This case helps avoid some imprecision in the general */
2154 : /* calcuations. */
2155 : /* -------------------------------------------------------------------- */
2156 5970 : if( nGCPCount == 4
2157 586 : && pasGCPs[0].dfGCPLine == pasGCPs[1].dfGCPLine
2158 680 : && pasGCPs[2].dfGCPLine == pasGCPs[3].dfGCPLine
2159 340 : && pasGCPs[0].dfGCPPixel == pasGCPs[3].dfGCPPixel
2160 680 : && pasGCPs[1].dfGCPPixel == pasGCPs[2].dfGCPPixel
2161 340 : && pasGCPs[0].dfGCPLine != pasGCPs[2].dfGCPLine
2162 336 : && pasGCPs[0].dfGCPPixel != pasGCPs[1].dfGCPPixel
2163 336 : && pasGCPs[0].dfGCPY == pasGCPs[1].dfGCPY
2164 620 : && pasGCPs[2].dfGCPY == pasGCPs[3].dfGCPY
2165 310 : && pasGCPs[0].dfGCPX == pasGCPs[3].dfGCPX
2166 620 : && pasGCPs[1].dfGCPX == pasGCPs[2].dfGCPX
2167 310 : && pasGCPs[0].dfGCPY != pasGCPs[2].dfGCPY
2168 220 : && pasGCPs[0].dfGCPX != pasGCPs[1].dfGCPX )
2169 : {
2170 220 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2171 220 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2172 220 : padfGeoTransform[2] = 0.0;
2173 220 : padfGeoTransform[4] = 0.0;
2174 440 : padfGeoTransform[5] = (pasGCPs[2].dfGCPY - pasGCPs[1].dfGCPY)
2175 440 : / (pasGCPs[2].dfGCPLine - pasGCPs[1].dfGCPLine);
2176 :
2177 : padfGeoTransform[0] =
2178 220 : pasGCPs[0].dfGCPX - pasGCPs[0].dfGCPPixel * padfGeoTransform[1];
2179 220 : padfGeoTransform[3] =
2180 220 : pasGCPs[0].dfGCPY - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2181 220 : return TRUE;
2182 : }
2183 :
2184 : /* -------------------------------------------------------------------- */
2185 : /* In the general case, do a least squares error approximation by */
2186 : /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum */
2187 : /* -------------------------------------------------------------------- */
2188 :
2189 372 : double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_xx = 0.0, sum_yy = 0.0;
2190 372 : double sum_Lon = 0.0, sum_Lonx = 0.0, sum_Lony = 0.0;
2191 372 : double sum_Lat = 0.0, sum_Latx = 0.0, sum_Laty = 0.0;
2192 : double divisor;
2193 :
2194 1866 : for (i = 0; i < nGCPCount; ++i) {
2195 1494 : sum_x += pasGCPs[i].dfGCPPixel;
2196 1494 : sum_y += pasGCPs[i].dfGCPLine;
2197 1494 : sum_xy += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPLine;
2198 1494 : sum_xx += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPPixel;
2199 1494 : sum_yy += pasGCPs[i].dfGCPLine * pasGCPs[i].dfGCPLine;
2200 1494 : sum_Lon += pasGCPs[i].dfGCPX;
2201 1494 : sum_Lonx += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPPixel;
2202 1494 : sum_Lony += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPLine;
2203 1494 : sum_Lat += pasGCPs[i].dfGCPY;
2204 1494 : sum_Latx += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPPixel;
2205 1494 : sum_Laty += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPLine;
2206 : }
2207 :
2208 : divisor = nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy)
2209 : + 2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx
2210 372 : - sum_x * sum_x * sum_yy;
2211 :
2212 : /* -------------------------------------------------------------------- */
2213 : /* If the divisor is zero, there is no valid solution. */
2214 : /* -------------------------------------------------------------------- */
2215 372 : if (divisor == 0.0)
2216 4 : return FALSE;
2217 :
2218 : /* -------------------------------------------------------------------- */
2219 : /* Compute top/left origin. */
2220 : /* -------------------------------------------------------------------- */
2221 :
2222 : padfGeoTransform[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy)
2223 : + sum_Lonx * (sum_y * sum_xy - sum_x * sum_yy)
2224 : + sum_Lony * (sum_x * sum_xy - sum_y * sum_xx))
2225 368 : / divisor;
2226 :
2227 368 : padfGeoTransform[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy)
2228 : + sum_Latx * (sum_y * sum_xy - sum_x * sum_yy)
2229 : + sum_Laty * (sum_x * sum_xy - sum_y * sum_xx))
2230 368 : / divisor;
2231 :
2232 : /* -------------------------------------------------------------------- */
2233 : /* Compute X related coefficients. */
2234 : /* -------------------------------------------------------------------- */
2235 368 : padfGeoTransform[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy)
2236 : + sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y)
2237 : + sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount))
2238 368 : / divisor;
2239 :
2240 368 : padfGeoTransform[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx)
2241 : + sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy)
2242 : + sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x))
2243 368 : / divisor;
2244 :
2245 : /* -------------------------------------------------------------------- */
2246 : /* Compute Y related coefficients. */
2247 : /* -------------------------------------------------------------------- */
2248 368 : padfGeoTransform[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy)
2249 : + sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y)
2250 : + sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount))
2251 368 : / divisor;
2252 :
2253 368 : padfGeoTransform[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx)
2254 : + sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy)
2255 : + sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x))
2256 368 : / divisor;
2257 :
2258 : /* -------------------------------------------------------------------- */
2259 : /* Now check if any of the input points fit this poorly. */
2260 : /* -------------------------------------------------------------------- */
2261 368 : if( !bApproxOK )
2262 : {
2263 736 : double dfPixelSize = ABS(padfGeoTransform[1])
2264 736 : + ABS(padfGeoTransform[2])
2265 736 : + ABS(padfGeoTransform[4])
2266 2208 : + ABS(padfGeoTransform[5]);
2267 :
2268 1812 : for( i = 0; i < nGCPCount; i++ )
2269 : {
2270 : double dfErrorX, dfErrorY;
2271 :
2272 : dfErrorX =
2273 2904 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[1]
2274 2904 : + pasGCPs[i].dfGCPLine * padfGeoTransform[2]
2275 1452 : + padfGeoTransform[0])
2276 7260 : - pasGCPs[i].dfGCPX;
2277 : dfErrorY =
2278 2904 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[4]
2279 2904 : + pasGCPs[i].dfGCPLine * padfGeoTransform[5]
2280 1452 : + padfGeoTransform[3])
2281 7260 : - pasGCPs[i].dfGCPY;
2282 :
2283 1452 : if( ABS(dfErrorX) > 0.25 * dfPixelSize
2284 : || ABS(dfErrorY) > 0.25 * dfPixelSize )
2285 8 : return FALSE;
2286 : }
2287 : }
2288 :
2289 360 : return TRUE;
2290 : }
2291 :
2292 : /************************************************************************/
2293 : /* GDALGeneralCmdLineProcessor() */
2294 : /************************************************************************/
2295 :
2296 : /**
2297 : * \brief General utility option processing.
2298 : *
2299 : * This function is intended to provide a variety of generic commandline
2300 : * options for all GDAL commandline utilities. It takes care of the following
2301 : * commandline options:
2302 : *
2303 : * --version: report version of GDAL in use.
2304 : * --license: report GDAL license info.
2305 : * --formats: report all format drivers configured.
2306 : * --format [format]: report details of one format driver.
2307 : * --optfile filename: expand an option file into the argument list.
2308 : * --config key value: set system configuration option.
2309 : * --debug [on/off/value]: set debug level.
2310 : * --mempreload dir: preload directory contents into /vsimem
2311 : * --pause: Pause for user input (allows time to attach debugger)
2312 : * --locale [locale]: Install a locale using setlocale() (debugging)
2313 : * --help-general: report detailed help on general options.
2314 : *
2315 : * The argument array is replaced "in place" and should be freed with
2316 : * CSLDestroy() when no longer needed. The typical usage looks something
2317 : * like the following. Note that the formats should be registered so that
2318 : * the --formats and --format options will work properly.
2319 : *
2320 : * int main( int argc, char ** argv )
2321 : * {
2322 : * GDALAllRegister();
2323 : *
2324 : * argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
2325 : * if( argc < 1 )
2326 : * exit( -argc );
2327 : *
2328 : * @param nArgc number of values in the argument list.
2329 : * @param ppapszArgv pointer to the argument list array (will be updated in place).
2330 : * @param nOptions unused for now.
2331 : *
2332 : * @return updated nArgc argument count. Return of 0 requests terminate
2333 : * without error, return of -1 requests exit with error code.
2334 : */
2335 :
2336 : int CPL_STDCALL
2337 1173 : GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
2338 :
2339 : {
2340 1173 : char **papszReturn = NULL;
2341 : int iArg;
2342 1173 : char **papszArgv = *ppapszArgv;
2343 :
2344 : (void) nOptions;
2345 :
2346 : /* -------------------------------------------------------------------- */
2347 : /* Preserve the program name. */
2348 : /* -------------------------------------------------------------------- */
2349 1173 : papszReturn = CSLAddString( papszReturn, papszArgv[0] );
2350 :
2351 : /* ==================================================================== */
2352 : /* Loop over all arguments. */
2353 : /* ==================================================================== */
2354 6957 : for( iArg = 1; iArg < nArgc; iArg++ )
2355 : {
2356 : /* -------------------------------------------------------------------- */
2357 : /* --version */
2358 : /* -------------------------------------------------------------------- */
2359 5784 : if( EQUAL(papszArgv[iArg],"--version") )
2360 : {
2361 0 : printf( "%s\n", GDALVersionInfo( "--version" ) );
2362 0 : CSLDestroy( papszReturn );
2363 0 : return 0;
2364 : }
2365 :
2366 : /* -------------------------------------------------------------------- */
2367 : /* --license */
2368 : /* -------------------------------------------------------------------- */
2369 5784 : else if( EQUAL(papszArgv[iArg],"--license") )
2370 : {
2371 0 : printf( "%s\n", GDALVersionInfo( "LICENSE" ) );
2372 0 : CSLDestroy( papszReturn );
2373 0 : return 0;
2374 : }
2375 :
2376 : /* -------------------------------------------------------------------- */
2377 : /* --config */
2378 : /* -------------------------------------------------------------------- */
2379 5784 : else if( EQUAL(papszArgv[iArg],"--config") )
2380 : {
2381 8 : if( iArg + 2 >= nArgc )
2382 : {
2383 : CPLError( CE_Failure, CPLE_AppDefined,
2384 0 : "--config option given without a key and value argument." );
2385 0 : CSLDestroy( papszReturn );
2386 0 : return -1;
2387 : }
2388 :
2389 8 : CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
2390 :
2391 8 : iArg += 2;
2392 : }
2393 :
2394 : /* -------------------------------------------------------------------- */
2395 : /* --mempreload */
2396 : /* -------------------------------------------------------------------- */
2397 5776 : else if( EQUAL(papszArgv[iArg],"--mempreload") )
2398 : {
2399 : int i;
2400 :
2401 0 : if( iArg + 1 >= nArgc )
2402 : {
2403 : CPLError( CE_Failure, CPLE_AppDefined,
2404 0 : "--mempreload option given without directory path.");
2405 0 : CSLDestroy( papszReturn );
2406 0 : return -1;
2407 : }
2408 :
2409 0 : char **papszFiles = CPLReadDir( papszArgv[iArg+1] );
2410 0 : if( CSLCount(papszFiles) == 0 )
2411 : {
2412 : CPLError( CE_Failure, CPLE_AppDefined,
2413 0 : "--mempreload given invalid or empty directory.");
2414 0 : CSLDestroy( papszReturn );
2415 0 : return -1;
2416 : }
2417 :
2418 0 : for( i = 0; papszFiles[i] != NULL; i++ )
2419 : {
2420 0 : CPLString osOldPath, osNewPath;
2421 : VSIStatBufL sStatBuf;
2422 :
2423 0 : if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
2424 0 : continue;
2425 :
2426 0 : osOldPath = CPLFormFilename( papszArgv[iArg+1],
2427 0 : papszFiles[i], NULL );
2428 0 : osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
2429 :
2430 0 : if( VSIStatL( osOldPath, &sStatBuf ) != 0
2431 : || VSI_ISDIR( sStatBuf.st_mode ) )
2432 : {
2433 : CPLDebug( "VSI", "Skipping preload of %s.",
2434 0 : osOldPath.c_str() );
2435 0 : continue;
2436 : }
2437 :
2438 : CPLDebug( "VSI", "Preloading %s to %s.",
2439 0 : osOldPath.c_str(), osNewPath.c_str() );
2440 :
2441 0 : if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
2442 : {
2443 : CPLError( CE_Failure, CPLE_AppDefined,
2444 : "Failed to copy %s to /vsimem",
2445 0 : osOldPath.c_str() );
2446 0 : return -1;
2447 : }
2448 : }
2449 :
2450 0 : CSLDestroy( papszFiles );
2451 0 : iArg += 1;
2452 : }
2453 :
2454 : /* -------------------------------------------------------------------- */
2455 : /* --debug */
2456 : /* -------------------------------------------------------------------- */
2457 5776 : else if( EQUAL(papszArgv[iArg],"--debug") )
2458 : {
2459 0 : if( iArg + 1 >= nArgc )
2460 : {
2461 : CPLError( CE_Failure, CPLE_AppDefined,
2462 0 : "--debug option given without debug level." );
2463 0 : CSLDestroy( papszReturn );
2464 0 : return -1;
2465 : }
2466 :
2467 0 : CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
2468 0 : iArg += 1;
2469 : }
2470 :
2471 : /* -------------------------------------------------------------------- */
2472 : /* --optfile */
2473 : /* */
2474 : /* Annoyingly the options inserted by --optfile will *not* be */
2475 : /* processed properly if they are general options. */
2476 : /* -------------------------------------------------------------------- */
2477 5776 : else if( EQUAL(papszArgv[iArg],"--optfile") )
2478 : {
2479 : const char *pszLine;
2480 : FILE *fpOptFile;
2481 :
2482 0 : if( iArg + 1 >= nArgc )
2483 : {
2484 : CPLError( CE_Failure, CPLE_AppDefined,
2485 0 : "--optfile option given without filename." );
2486 0 : CSLDestroy( papszReturn );
2487 0 : return -1;
2488 : }
2489 :
2490 0 : fpOptFile = VSIFOpen( papszArgv[iArg+1], "rb" );
2491 :
2492 0 : if( fpOptFile == NULL )
2493 : {
2494 : CPLError( CE_Failure, CPLE_AppDefined,
2495 : "Unable to open optfile '%s'.\n%s",
2496 0 : papszArgv[iArg+1], VSIStrerror( errno ) );
2497 0 : CSLDestroy( papszReturn );
2498 0 : return -1;
2499 : }
2500 :
2501 0 : while( (pszLine = CPLReadLine( fpOptFile )) != NULL )
2502 : {
2503 : char **papszTokens;
2504 : int i;
2505 :
2506 0 : if( pszLine[0] == '#' || strlen(pszLine) == 0 )
2507 0 : continue;
2508 :
2509 0 : papszTokens = CSLTokenizeString( pszLine );
2510 0 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++)
2511 0 : papszReturn = CSLAddString( papszReturn, papszTokens[i] );
2512 0 : CSLDestroy( papszTokens );
2513 : }
2514 :
2515 0 : VSIFClose( fpOptFile );
2516 :
2517 0 : iArg += 1;
2518 : }
2519 :
2520 : /* -------------------------------------------------------------------- */
2521 : /* --formats */
2522 : /* -------------------------------------------------------------------- */
2523 5776 : else if( EQUAL(papszArgv[iArg], "--formats") )
2524 : {
2525 : int iDr;
2526 :
2527 0 : printf( "Supported Formats:\n" );
2528 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
2529 : {
2530 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
2531 : const char *pszRWFlag, *pszVirtualIO;
2532 :
2533 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) )
2534 0 : pszRWFlag = "rw+";
2535 0 : else if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
2536 : NULL ) )
2537 0 : pszRWFlag = "rw";
2538 : else
2539 0 : pszRWFlag = "ro";
2540 :
2541 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL) )
2542 0 : pszVirtualIO = "v";
2543 : else
2544 0 : pszVirtualIO = "";
2545 :
2546 : printf( " %s (%s%s): %s\n",
2547 : GDALGetDriverShortName( hDriver ),
2548 : pszRWFlag, pszVirtualIO,
2549 0 : GDALGetDriverLongName( hDriver ) );
2550 : }
2551 :
2552 0 : CSLDestroy( papszReturn );
2553 0 : return 0;
2554 : }
2555 :
2556 : /* -------------------------------------------------------------------- */
2557 : /* --format */
2558 : /* -------------------------------------------------------------------- */
2559 5776 : else if( EQUAL(papszArgv[iArg], "--format") )
2560 : {
2561 : GDALDriverH hDriver;
2562 : char **papszMD;
2563 :
2564 0 : CSLDestroy( papszReturn );
2565 :
2566 0 : if( iArg + 1 >= nArgc )
2567 : {
2568 : CPLError( CE_Failure, CPLE_AppDefined,
2569 0 : "--format option given without a format code." );
2570 0 : return -1;
2571 : }
2572 :
2573 0 : hDriver = GDALGetDriverByName( papszArgv[iArg+1] );
2574 0 : if( hDriver == NULL )
2575 : {
2576 : CPLError( CE_Failure, CPLE_AppDefined,
2577 : "--format option given with format '%s', but that format not\n"
2578 : "recognised. Use the --formats option to get a list of available formats,\n"
2579 : "and use the short code (ie. GTiff or HFA) as the format identifier.\n",
2580 0 : papszArgv[iArg+1] );
2581 0 : return -1;
2582 : }
2583 :
2584 0 : printf( "Format Details:\n" );
2585 0 : printf( " Short Name: %s\n", GDALGetDriverShortName( hDriver ) );
2586 0 : printf( " Long Name: %s\n", GDALGetDriverLongName( hDriver ) );
2587 :
2588 0 : papszMD = GDALGetMetadata( hDriver, NULL );
2589 :
2590 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) )
2591 : printf( " Extension: %s\n",
2592 0 : CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) );
2593 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) )
2594 : printf( " Mime Type: %s\n",
2595 0 : CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) );
2596 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) )
2597 : printf( " Help Topic: %s\n",
2598 0 : CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) );
2599 :
2600 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATE, FALSE ) )
2601 0 : printf( " Supports: Create() - Create writeable dataset.\n" );
2602 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATECOPY, FALSE ) )
2603 0 : printf( " Supports: CreateCopy() - Create dataset by copying another.\n" );
2604 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_VIRTUALIO, FALSE ) )
2605 0 : printf( " Supports: Virtual IO - eg. /vsimem/\n" );
2606 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) )
2607 : printf( " Creation Datatypes: %s\n",
2608 0 : CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) );
2609 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONOPTIONLIST ) )
2610 : {
2611 : CPLXMLNode *psCOL =
2612 : CPLParseXMLString(
2613 : CSLFetchNameValue( papszMD,
2614 0 : GDAL_DMD_CREATIONOPTIONLIST ) );
2615 : char *pszFormattedXML =
2616 0 : CPLSerializeXMLTree( psCOL );
2617 :
2618 0 : CPLDestroyXMLNode( psCOL );
2619 :
2620 0 : printf( "\n%s\n", pszFormattedXML );
2621 0 : CPLFree( pszFormattedXML );
2622 : }
2623 0 : return 0;
2624 : }
2625 :
2626 : /* -------------------------------------------------------------------- */
2627 : /* --help-general */
2628 : /* -------------------------------------------------------------------- */
2629 5776 : else if( EQUAL(papszArgv[iArg],"--help-general") )
2630 : {
2631 0 : printf( "Generic GDAL utility command options:\n" );
2632 0 : printf( " --version: report version of GDAL in use.\n" );
2633 0 : printf( " --license: report GDAL license info.\n" );
2634 0 : printf( " --formats: report all configured format drivers.\n" );
2635 0 : printf( " --format [format]: details of one format.\n" );
2636 0 : printf( " --optfile filename: expand an option file into the argument list.\n" );
2637 0 : printf( " --config key value: set system configuration option.\n" );
2638 0 : printf( " --debug [on/off/value]: set debug level.\n" );
2639 0 : printf( " --pause: wait for user input, time to attach debugger\n" );
2640 0 : printf( " --locale [locale]: install locale for debugging (ie. en_US.UTF-8)\n" );
2641 0 : printf( " --help-general: report detailed help on general options.\n" );
2642 0 : CSLDestroy( papszReturn );
2643 0 : return 0;
2644 : }
2645 :
2646 : /* -------------------------------------------------------------------- */
2647 : /* --locale */
2648 : /* -------------------------------------------------------------------- */
2649 5776 : else if( EQUAL(papszArgv[iArg],"--locale") && iArg < nArgc-1 )
2650 : {
2651 0 : setlocale( LC_ALL, papszArgv[++iArg] );
2652 : }
2653 :
2654 : /* -------------------------------------------------------------------- */
2655 : /* --pause */
2656 : /* -------------------------------------------------------------------- */
2657 5776 : else if( EQUAL(papszArgv[iArg],"--pause") )
2658 : {
2659 0 : printf( "Hit <ENTER> to Continue.\n" );
2660 0 : CPLReadLine( stdin );
2661 : }
2662 :
2663 : /* -------------------------------------------------------------------- */
2664 : /* carry through unrecognised options. */
2665 : /* -------------------------------------------------------------------- */
2666 : else
2667 : {
2668 5776 : papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
2669 : }
2670 : }
2671 :
2672 1173 : *ppapszArgv = papszReturn;
2673 :
2674 1173 : return CSLCount( *ppapszArgv );
2675 : }
2676 :
2677 :
2678 : /************************************************************************/
2679 : /* _FetchDblFromMD() */
2680 : /************************************************************************/
2681 :
2682 180 : static int _FetchDblFromMD( char **papszMD, const char *pszKey,
2683 : double *padfTarget, int nCount, double dfDefault )
2684 :
2685 : {
2686 : char szFullKey[200];
2687 :
2688 180 : sprintf( szFullKey, "%s", pszKey );
2689 :
2690 180 : const char *pszValue = CSLFetchNameValue( papszMD, szFullKey );
2691 : int i;
2692 :
2693 1120 : for( i = 0; i < nCount; i++ )
2694 940 : padfTarget[i] = dfDefault;
2695 :
2696 180 : if( pszValue == NULL )
2697 40 : return FALSE;
2698 :
2699 140 : if( nCount == 1 )
2700 : {
2701 100 : *padfTarget = CPLAtofM( pszValue );
2702 100 : return TRUE;
2703 : }
2704 :
2705 : char **papszTokens = CSLTokenizeStringComplex( pszValue, " ,",
2706 40 : FALSE, FALSE );
2707 :
2708 40 : if( CSLCount( papszTokens ) != nCount )
2709 : {
2710 0 : CSLDestroy( papszTokens );
2711 0 : return FALSE;
2712 : }
2713 :
2714 840 : for( i = 0; i < nCount; i++ )
2715 800 : padfTarget[i] = CPLAtofM(papszTokens[i]);
2716 :
2717 40 : CSLDestroy( papszTokens );
2718 :
2719 40 : return TRUE;
2720 : }
2721 :
2722 : /************************************************************************/
2723 : /* GDALExtractRPCInfo() */
2724 : /* */
2725 : /* Extract RPC info from metadata, and apply to an RPCInfo */
2726 : /* structure. The inverse of this function is RPCInfoToMD() in */
2727 : /* alg/gdal_rpc.cpp (should it be needed). */
2728 : /************************************************************************/
2729 :
2730 10 : int CPL_STDCALL GDALExtractRPCInfo( char **papszMD, GDALRPCInfo *psRPC )
2731 :
2732 : {
2733 10 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL )
2734 0 : return FALSE;
2735 :
2736 10 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL
2737 : || CSLFetchNameValue( papszMD, "LINE_DEN_COEFF" ) == NULL
2738 : || CSLFetchNameValue( papszMD, "SAMP_NUM_COEFF" ) == NULL
2739 : || CSLFetchNameValue( papszMD, "SAMP_DEN_COEFF" ) == NULL )
2740 : {
2741 : CPLError( CE_Failure, CPLE_AppDefined,
2742 0 : "Some required RPC metadata missing in GDALExtractRPCInfo()");
2743 0 : return FALSE;
2744 : }
2745 :
2746 10 : _FetchDblFromMD( papszMD, "LINE_OFF", &(psRPC->dfLINE_OFF), 1, 0.0 );
2747 10 : _FetchDblFromMD( papszMD, "LINE_SCALE", &(psRPC->dfLINE_SCALE), 1, 1.0 );
2748 10 : _FetchDblFromMD( papszMD, "SAMP_OFF", &(psRPC->dfSAMP_OFF), 1, 0.0 );
2749 10 : _FetchDblFromMD( papszMD, "SAMP_SCALE", &(psRPC->dfSAMP_SCALE), 1, 1.0 );
2750 10 : _FetchDblFromMD( papszMD, "HEIGHT_OFF", &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
2751 10 : _FetchDblFromMD( papszMD, "HEIGHT_SCALE", &(psRPC->dfHEIGHT_SCALE),1, 1.0);
2752 10 : _FetchDblFromMD( papszMD, "LAT_OFF", &(psRPC->dfLAT_OFF), 1, 0.0 );
2753 10 : _FetchDblFromMD( papszMD, "LAT_SCALE", &(psRPC->dfLAT_SCALE), 1, 1.0 );
2754 10 : _FetchDblFromMD( papszMD, "LONG_OFF", &(psRPC->dfLONG_OFF), 1, 0.0 );
2755 10 : _FetchDblFromMD( papszMD, "LONG_SCALE", &(psRPC->dfLONG_SCALE), 1, 1.0 );
2756 :
2757 : _FetchDblFromMD( papszMD, "LINE_NUM_COEFF", psRPC->adfLINE_NUM_COEFF,
2758 10 : 20, 0.0 );
2759 : _FetchDblFromMD( papszMD, "LINE_DEN_COEFF", psRPC->adfLINE_DEN_COEFF,
2760 10 : 20, 0.0 );
2761 : _FetchDblFromMD( papszMD, "SAMP_NUM_COEFF", psRPC->adfSAMP_NUM_COEFF,
2762 10 : 20, 0.0 );
2763 : _FetchDblFromMD( papszMD, "SAMP_DEN_COEFF", psRPC->adfSAMP_DEN_COEFF,
2764 10 : 20, 0.0 );
2765 :
2766 10 : _FetchDblFromMD( papszMD, "MIN_LONG", &(psRPC->dfMIN_LONG), 1, -180.0 );
2767 10 : _FetchDblFromMD( papszMD, "MIN_LAT", &(psRPC->dfMIN_LAT), 1, -90.0 );
2768 10 : _FetchDblFromMD( papszMD, "MAX_LONG", &(psRPC->dfMAX_LONG), 1, 180.0 );
2769 10 : _FetchDblFromMD( papszMD, "MAX_LAT", &(psRPC->dfMAX_LAT), 1, 90.0 );
2770 :
2771 10 : return TRUE;
2772 : }
2773 :
2774 : /************************************************************************/
2775 : /* GDALFindAssociatedAuxFile() */
2776 : /************************************************************************/
2777 :
2778 7899 : GDALDataset *GDALFindAssociatedAuxFile( const char *pszBasename,
2779 : GDALAccess eAccess,
2780 : GDALDataset *poDependentDS )
2781 :
2782 : {
2783 7899 : const char *pszAuxSuffixLC = "aux";
2784 7899 : const char *pszAuxSuffixUC = "AUX";
2785 :
2786 7899 : if( EQUAL(CPLGetExtension(pszBasename), pszAuxSuffixLC) )
2787 36 : return NULL;
2788 :
2789 : /* -------------------------------------------------------------------- */
2790 : /* Don't even try to look for an .aux file if we don't have a */
2791 : /* path of any kind. */
2792 : /* -------------------------------------------------------------------- */
2793 7863 : if( strlen(pszBasename) == 0 )
2794 0 : return NULL;
2795 :
2796 : /* -------------------------------------------------------------------- */
2797 : /* We didn't find that, so try and find a corresponding aux */
2798 : /* file. Check that we are the dependent file of the aux */
2799 : /* file, or if we aren't verify that the dependent file does */
2800 : /* not exist, likely mean it is us but some sort of renaming */
2801 : /* has occured. */
2802 : /* -------------------------------------------------------------------- */
2803 7863 : CPLString osJustFile = CPLGetFilename(pszBasename); // without dir
2804 7863 : CPLString osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixLC);
2805 7863 : GDALDataset *poODS = NULL;
2806 : GByte abyHeader[32];
2807 : VSILFILE *fp;
2808 :
2809 7863 : fp = VSIFOpenL( osAuxFilename, "rb" );
2810 :
2811 :
2812 7863 : if ( fp == NULL && VSIIsCaseSensitiveFS(osAuxFilename))
2813 : {
2814 : // Can't found file with lower case suffix. Try the upper case one.
2815 7795 : osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixUC);
2816 7795 : fp = VSIFOpenL( osAuxFilename, "rb" );
2817 : }
2818 :
2819 7863 : if( fp != NULL )
2820 : {
2821 68 : if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
2822 : EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2823 : {
2824 : /* Avoid causing failure in opening of main file from SWIG bindings */
2825 : /* when auxiliary file cannot be opened (#3269) */
2826 20 : CPLTurnFailureIntoWarning(TRUE);
2827 20 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2828 20 : CPLTurnFailureIntoWarning(FALSE);
2829 : }
2830 68 : VSIFCloseL( fp );
2831 : }
2832 :
2833 : /* -------------------------------------------------------------------- */
2834 : /* Try replacing extension with .aux */
2835 : /* -------------------------------------------------------------------- */
2836 7863 : if( poODS != NULL )
2837 : {
2838 : const char *pszDep
2839 20 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2840 20 : if( pszDep == NULL )
2841 : {
2842 : CPLDebug( "AUX",
2843 : "Found %s but it has no dependent file, ignoring.",
2844 0 : osAuxFilename.c_str() );
2845 0 : GDALClose( poODS );
2846 0 : poODS = NULL;
2847 : }
2848 20 : else if( !EQUAL(pszDep,osJustFile) )
2849 : {
2850 : VSIStatBufL sStatBuf;
2851 :
2852 0 : if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
2853 : {
2854 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2855 : osAuxFilename.c_str(),
2856 0 : pszDep, osJustFile.c_str() );
2857 0 : GDALClose( poODS );
2858 0 : poODS = NULL;
2859 : }
2860 : else
2861 : {
2862 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2863 : "%s does not exist, we will use .aux file as our own.",
2864 : osAuxFilename.c_str(),
2865 : pszDep, osJustFile.c_str(),
2866 0 : pszDep );
2867 : }
2868 : }
2869 :
2870 : /* -------------------------------------------------------------------- */
2871 : /* Confirm that the aux file matches the configuration of the */
2872 : /* dependent dataset. */
2873 : /* -------------------------------------------------------------------- */
2874 20 : if( poODS != NULL && poDependentDS != NULL
2875 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2876 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2877 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2878 : {
2879 : CPLDebug( "AUX",
2880 : "Ignoring aux file %s as its raster configuration\n"
2881 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2882 : osAuxFilename.c_str(),
2883 : poODS->GetRasterXSize(),
2884 : poODS->GetRasterYSize(),
2885 : poODS->GetRasterCount(),
2886 : poDependentDS->GetRasterXSize(),
2887 : poDependentDS->GetRasterYSize(),
2888 10 : poDependentDS->GetRasterCount() );
2889 :
2890 10 : GDALClose( poODS );
2891 10 : poODS = NULL;
2892 : }
2893 : }
2894 :
2895 : /* -------------------------------------------------------------------- */
2896 : /* Try appending .aux to the end of the filename. */
2897 : /* -------------------------------------------------------------------- */
2898 7863 : if( poODS == NULL )
2899 : {
2900 7853 : osAuxFilename = pszBasename;
2901 7853 : osAuxFilename += ".";
2902 7853 : osAuxFilename += pszAuxSuffixLC;
2903 7853 : fp = VSIFOpenL( osAuxFilename, "rb" );
2904 7853 : if ( fp == NULL && VSIIsCaseSensitiveFS(osAuxFilename) )
2905 : {
2906 : // Can't found file with lower case suffix. Try the upper case one.
2907 7815 : osAuxFilename = pszBasename;
2908 7815 : osAuxFilename += ".";
2909 7815 : osAuxFilename += pszAuxSuffixUC;
2910 7815 : fp = VSIFOpenL( osAuxFilename, "rb" );
2911 : }
2912 :
2913 7853 : if( fp != NULL )
2914 : {
2915 38 : if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
2916 : EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2917 : {
2918 : /* Avoid causing failure in opening of main file from SWIG bindings */
2919 : /* when auxiliary file cannot be opened (#3269) */
2920 0 : CPLTurnFailureIntoWarning(TRUE);
2921 0 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2922 0 : CPLTurnFailureIntoWarning(FALSE);
2923 : }
2924 38 : VSIFCloseL( fp );
2925 : }
2926 :
2927 7853 : if( poODS != NULL )
2928 : {
2929 : const char *pszDep
2930 0 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2931 0 : if( pszDep == NULL )
2932 : {
2933 : CPLDebug( "AUX",
2934 : "Found %s but it has no dependent file, ignoring.",
2935 0 : osAuxFilename.c_str() );
2936 0 : GDALClose( poODS );
2937 0 : poODS = NULL;
2938 : }
2939 0 : else if( !EQUAL(pszDep,osJustFile) )
2940 : {
2941 : VSIStatBufL sStatBuf;
2942 :
2943 0 : if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
2944 : {
2945 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2946 : osAuxFilename.c_str(),
2947 0 : pszDep, osJustFile.c_str() );
2948 0 : GDALClose( poODS );
2949 0 : poODS = NULL;
2950 : }
2951 : else
2952 : {
2953 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2954 : "%s does not exist, we will use .aux file as our own.",
2955 : osAuxFilename.c_str(),
2956 : pszDep, osJustFile.c_str(),
2957 0 : pszDep );
2958 : }
2959 : }
2960 : }
2961 : }
2962 :
2963 : /* -------------------------------------------------------------------- */
2964 : /* Confirm that the aux file matches the configuration of the */
2965 : /* dependent dataset. */
2966 : /* -------------------------------------------------------------------- */
2967 7863 : if( poODS != NULL && poDependentDS != NULL
2968 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2969 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2970 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2971 : {
2972 : CPLDebug( "AUX",
2973 : "Ignoring aux file %s as its raster configuration\n"
2974 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2975 : osAuxFilename.c_str(),
2976 : poODS->GetRasterXSize(),
2977 : poODS->GetRasterYSize(),
2978 : poODS->GetRasterCount(),
2979 : poDependentDS->GetRasterXSize(),
2980 : poDependentDS->GetRasterYSize(),
2981 0 : poDependentDS->GetRasterCount() );
2982 :
2983 0 : GDALClose( poODS );
2984 0 : poODS = NULL;
2985 : }
2986 :
2987 7863 : return poODS;
2988 : }
2989 :
2990 : /************************************************************************/
2991 : /* -------------------------------------------------------------------- */
2992 : /* The following stubs are present to ensure that older GDAL */
2993 : /* bridges don't fail with newer libraries. */
2994 : /* -------------------------------------------------------------------- */
2995 : /************************************************************************/
2996 :
2997 : CPL_C_START
2998 :
2999 0 : void * CPL_STDCALL GDALCreateProjDef( const char * )
3000 : {
3001 0 : CPLDebug( "GDAL", "GDALCreateProjDef no longer supported." );
3002 0 : return NULL;
3003 : }
3004 :
3005 0 : CPLErr CPL_STDCALL GDALReprojectToLongLat( void *, double *, double * )
3006 : {
3007 0 : CPLDebug( "GDAL", "GDALReprojectToLatLong no longer supported." );
3008 0 : return CE_Failure;
3009 : }
3010 :
3011 0 : CPLErr CPL_STDCALL GDALReprojectFromLongLat( void *, double *, double * )
3012 : {
3013 0 : CPLDebug( "GDAL", "GDALReprojectFromLatLong no longer supported." );
3014 0 : return CE_Failure;
3015 : }
3016 :
3017 0 : void CPL_STDCALL GDALDestroyProjDef( void * )
3018 :
3019 : {
3020 0 : CPLDebug( "GDAL", "GDALDestroyProjDef no longer supported." );
3021 0 : }
3022 :
3023 : CPL_C_END
3024 :
3025 : /************************************************************************/
3026 : /* Infrastructure to check that dataset characteristics are valid */
3027 : /************************************************************************/
3028 :
3029 : CPL_C_START
3030 :
3031 : /**
3032 : * \brief Return TRUE if the dataset dimensions are valid.
3033 : *
3034 : * @param nXSize raster width
3035 : * @param nYSize raster height
3036 : *
3037 : * @since GDAL 1.7.0
3038 : */
3039 2418 : int GDALCheckDatasetDimensions( int nXSize, int nYSize )
3040 : {
3041 2418 : if (nXSize <= 0 || nYSize <= 0)
3042 : {
3043 : CPLError(CE_Failure, CPLE_AppDefined,
3044 0 : "Invalid dataset dimensions : %d x %d", nXSize, nYSize);
3045 0 : return FALSE;
3046 : }
3047 2418 : return TRUE;
3048 : }
3049 :
3050 : /**
3051 : * \brief Return TRUE if the band count is valid.
3052 : *
3053 : * If the configuration option GDAL_MAX_BAND_COUNT is defined,
3054 : * the band count will be compared to the maximum number of band allowed.
3055 : *
3056 : * @param nBands the band count
3057 : * @param bIsZeroAllowed TRUE if band count == 0 is allowed
3058 : *
3059 : * @since GDAL 1.7.0
3060 : */
3061 :
3062 1602 : int GDALCheckBandCount( int nBands, int bIsZeroAllowed )
3063 : {
3064 1602 : int nMaxBands = -1;
3065 1602 : const char* pszMaxBandCount = CPLGetConfigOption("GDAL_MAX_BAND_COUNT", NULL);
3066 1602 : if (pszMaxBandCount != NULL)
3067 : {
3068 0 : nMaxBands = atoi(pszMaxBandCount);
3069 : }
3070 1602 : if (nBands < 0 || (!bIsZeroAllowed && nBands == 0) ||
3071 : (nMaxBands >= 0 && nBands > nMaxBands) )
3072 : {
3073 : CPLError(CE_Failure, CPLE_AppDefined,
3074 12 : "Invalid band count : %d", nBands);
3075 12 : return FALSE;
3076 : }
3077 1590 : return TRUE;
3078 : }
3079 :
3080 : CPL_C_END
3081 :
|