1 /******************************************************************************
2  *
3  * Project:  GDAL Core
4  * Purpose:  Free standing functions for GDAL.
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 1999, Frank Warmerdam
9  * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
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 "cpl_port.h"
31 
32 #include <cctype>
33 #include <cerrno>
34 #include <clocale>
35 #include <cmath>
36 #include <cstddef>
37 #include <cstdio>
38 #include <cstdlib>
39 #include <cstring>
40 #include <fcntl.h>
41 
42 #include <algorithm>
43 #include <iostream>
44 #include <limits>
45 #include <string>
46 
47 #include "cpl_conv.h"
48 #include "cpl_error.h"
49 #include "cpl_minixml.h"
50 #include "cpl_multiproc.h"
51 #include "cpl_string.h"
52 #include "cpl_vsi.h"
53 #include "gdal_version.h"
54 #include "gdal.h"
55 #include "gdal_mdreader.h"
56 #include "gdal_priv.h"
57 #include "ogr_core.h"
58 #include "ogr_spatialref.h"
59 #include "ogr_geos.h"
60 
61 CPL_CVSID("$Id: gdal_misc.cpp eb2f5b33947e577fc14b62e62f930728dc573f17 2021-09-14 00:16:31 +0200 Even Rouault $")
62 
GetMinBitsForPair(const bool pabSigned[],const bool pabFloating[],const int panBits[])63 static int GetMinBitsForPair(
64     const bool pabSigned[], const bool pabFloating[], const int panBits[])
65 {
66     if(pabFloating[0] != pabFloating[1])
67     {
68         const int nNotFloatingTypeIndex = pabFloating[0] ? 1 : 0;
69         const int nFloatingTypeIndex = pabFloating[0] ? 0 : 1;
70 
71         return std::max(panBits[nFloatingTypeIndex],
72                         2 * panBits[nNotFloatingTypeIndex]);
73     }
74 
75     if( pabSigned[0] != pabSigned[1] )
76     {
77         const int nUnsignedTypeIndex = pabSigned[0] ? 1 : 0;
78         const int nSignedTypeIndex = pabSigned[0] ? 0 : 1;
79 
80         return std::max(panBits[nSignedTypeIndex],
81                         2 * panBits[nUnsignedTypeIndex]);
82     }
83 
84     return std::max(panBits[0], panBits[1]);
85 }
86 
GetDataTypeElementSizeBits(GDALDataType eDataType)87 static int GetDataTypeElementSizeBits( GDALDataType eDataType )
88 {
89     switch( eDataType )
90     {
91       case GDT_Byte:
92         return 8;
93 
94       case GDT_UInt16:
95       case GDT_Int16:
96       case GDT_CInt16:
97         return 16;
98 
99       case GDT_UInt32:
100       case GDT_Int32:
101       case GDT_Float32:
102       case GDT_CInt32:
103       case GDT_CFloat32:
104         return 32;
105 
106       case GDT_Float64:
107       case GDT_CFloat64:
108         return 64;
109 
110       default:
111         return 0;
112     }
113 }
114 
115 /************************************************************************/
116 /*                         GDALDataTypeUnion()                          */
117 /************************************************************************/
118 
119 /**
120  * \brief Return the smallest data type that can fully express both input data
121  * types.
122  *
123  * @param eType1 first data type.
124  * @param eType2 second data type.
125  *
126  * @return a data type able to express eType1 and eType2.
127  */
128 
129 GDALDataType CPL_STDCALL
GDALDataTypeUnion(GDALDataType eType1,GDALDataType eType2)130 GDALDataTypeUnion( GDALDataType eType1, GDALDataType eType2 )
131 
132 {
133     const int panBits[] = {
134         GetDataTypeElementSizeBits( eType1 ),
135         GetDataTypeElementSizeBits( eType2 )
136     };
137 
138     if( panBits[0] == 0 || panBits[1] == 0 )
139         return GDT_Unknown;
140 
141     const bool pabSigned[] = {
142         CPL_TO_BOOL( GDALDataTypeIsSigned( eType1 ) ),
143         CPL_TO_BOOL( GDALDataTypeIsSigned( eType2 ) )
144     };
145 
146     const bool bSigned = pabSigned[0] || pabSigned[1];
147     const bool pabFloating[] = {
148         CPL_TO_BOOL(GDALDataTypeIsFloating(eType1)),
149         CPL_TO_BOOL(GDALDataTypeIsFloating(eType2))
150     };
151     const bool bFloating = pabFloating[0] || pabFloating[1];
152     const bool bComplex =
153         CPL_TO_BOOL( GDALDataTypeIsComplex( eType1 ) ) ||
154         CPL_TO_BOOL( GDALDataTypeIsComplex( eType2 ) );
155 
156     const int nBits = GetMinBitsForPair(pabSigned, pabFloating, panBits);
157 
158     return GDALFindDataType(nBits, bSigned, bFloating, bComplex);
159 }
160 
161 /************************************************************************/
162 /*                        GDALDataTypeUnionWithValue()                  */
163 /************************************************************************/
164 
165 /**
166  * \brief Union a data type with the one found for a value
167  *
168  * @param eDT the first data type
169  * @param dValue the value for which to find a data type and union with eDT
170  * @param bComplex if the value is complex
171  *
172  * @return a data type able to express eDT and dValue.
173  * @since GDAL 2.3
174  */
GDALDataTypeUnionWithValue(GDALDataType eDT,double dValue,int bComplex)175 GDALDataType CPL_STDCALL GDALDataTypeUnionWithValue(
176     GDALDataType eDT, double dValue, int bComplex )
177 {
178     if( eDT == GDT_Float32 && !bComplex && static_cast<float>(dValue) == dValue )
179         return eDT;
180 
181     const GDALDataType eDT2 = GDALFindDataTypeForValue(dValue, bComplex);
182     return GDALDataTypeUnion(eDT, eDT2);
183 }
184 
185 /************************************************************************/
186 /*                        GetMinBitsForValue()                          */
187 /************************************************************************/
GetMinBitsForValue(double dValue)188 static int GetMinBitsForValue(double dValue)
189 {
190     if( round(dValue) == dValue )
191     {
192         if( dValue <= std::numeric_limits<GByte>::max() &&
193             dValue >= std::numeric_limits<GByte>::min() )
194             return 8;
195 
196         if( dValue <= std::numeric_limits<GInt16>::max() &&
197             dValue >= std::numeric_limits<GInt16>::min() )
198             return 16;
199 
200         if( dValue <= std::numeric_limits<GUInt16>::max() &&
201             dValue >= std::numeric_limits<GUInt16>::min() )
202             return 16;
203 
204         if( dValue <= std::numeric_limits<GInt32>::max() &&
205             dValue >= std::numeric_limits<GInt32>::min() )
206             return 32;
207 
208         if( dValue <= std::numeric_limits<GUInt32>::max() &&
209             dValue >= std::numeric_limits<GUInt32>::min() )
210             return 32;
211     }
212     else if( static_cast<float>(dValue) == dValue )
213     {
214         return 32;
215     }
216 
217     return 64;
218 }
219 
220 /************************************************************************/
221 /*                        GDALFindDataType()                            */
222 /************************************************************************/
223 
224 /**
225  * \brief Finds the smallest data type able to support the given
226  *  requirements
227  *
228  * @param nBits number of bits necessary
229  * @param bSigned if negative values are necessary
230  * @param bFloating if non-integer values necessary
231  * @param bComplex if complex values are necessary
232  *
233  * @return a best fit GDALDataType for supporting the requirements
234  * @since GDAL 2.3
235  */
GDALFindDataType(int nBits,int bSigned,int bFloating,int bComplex)236 GDALDataType CPL_STDCALL GDALFindDataType(
237     int nBits, int bSigned, int bFloating, int bComplex )
238 {
239     if( bSigned ) { nBits = std::max(nBits, 16); }
240     if( bComplex ) { nBits = std::max(nBits, !bSigned ? 32 : 16); } // we don't have complex unsigned data types, so for a complex uint16, promote to complex int32
241     if( bFloating ) { nBits = std::max(nBits, 32); }
242 
243     if( nBits <= 8 ) { return GDT_Byte; }
244 
245     if( nBits <= 16 )
246     {
247         if( bComplex ) return GDT_CInt16;
248         if( bSigned ) return GDT_Int16;
249         return GDT_UInt16;
250     }
251 
252     if( nBits <= 32 )
253     {
254         if( bFloating )
255         {
256             if( bComplex ) return GDT_CFloat32;
257             return GDT_Float32;
258         }
259 
260         if( bComplex ) return GDT_CInt32;
261         if( bSigned ) return GDT_Int32;
262         return GDT_UInt32;
263     }
264 
265     if( bComplex )
266         return GDT_CFloat64;
267 
268     return GDT_Float64;
269 }
270 
271 /************************************************************************/
272 /*                        GDALFindDataTypeForValue()                    */
273 /************************************************************************/
274 
275 /**
276  * \brief Finds the smallest data type able to support the provided value
277  *
278  * @param dValue value to support
279  * @param bComplex is the value complex
280  *
281  * @return a best fit GDALDataType for supporting the value
282  * @since GDAL 2.3
283  */
GDALFindDataTypeForValue(double dValue,int bComplex)284 GDALDataType CPL_STDCALL GDALFindDataTypeForValue(
285     double dValue, int bComplex )
286 {
287     const bool bFloating = round(dValue) != dValue;
288     const bool bSigned = bFloating || dValue < 0;
289     const int nBits = GetMinBitsForValue(dValue);
290 
291     return GDALFindDataType(nBits, bSigned, bFloating, bComplex);
292 }
293 
294 /************************************************************************/
295 /*                        GDALGetDataTypeSizeBytes()                    */
296 /************************************************************************/
297 
298 /**
299  * \brief Get data type size in <b>bytes</b>.
300  *
301  * Returns the size of a GDT_* type in bytes.  In contrast,
302  * GDALGetDataTypeSize() returns the size in <b>bits</b>.
303  *
304  * @param eDataType type, such as GDT_Byte.
305  * @return the number of bytes or zero if it is not recognised.
306  */
307 
GDALGetDataTypeSizeBytes(GDALDataType eDataType)308 int CPL_STDCALL GDALGetDataTypeSizeBytes( GDALDataType eDataType )
309 
310 {
311     switch( eDataType )
312     {
313       case GDT_Byte:
314         return 1;
315 
316       case GDT_UInt16:
317       case GDT_Int16:
318         return 2;
319 
320       case GDT_UInt32:
321       case GDT_Int32:
322       case GDT_Float32:
323       case GDT_CInt16:
324         return 4;
325 
326       case GDT_Float64:
327       case GDT_CInt32:
328       case GDT_CFloat32:
329         return 8;
330 
331       case GDT_CFloat64:
332         return 16;
333 
334       default:
335         return 0;
336     }
337 }
338 
339 /************************************************************************/
340 /*                        GDALGetDataTypeSizeBits()                     */
341 /************************************************************************/
342 
343 /**
344  * \brief Get data type size in <b>bits</b>.
345  *
346  * Returns the size of a GDT_* type in bits, <b>not bytes</b>!  Use
347  * GDALGetDataTypeSizeBytes() for bytes.
348  *
349  * @param eDataType type, such as GDT_Byte.
350  * @return the number of bits or zero if it is not recognised.
351  */
352 
GDALGetDataTypeSizeBits(GDALDataType eDataType)353 int CPL_STDCALL GDALGetDataTypeSizeBits( GDALDataType eDataType )
354 
355 {
356     return GDALGetDataTypeSizeBytes( eDataType ) * 8;
357 }
358 
359 /************************************************************************/
360 /*                        GDALGetDataTypeSize()                         */
361 /************************************************************************/
362 
363 /**
364  * \brief Get data type size in bits.  <b>Deprecated</b>.
365  *
366  * Returns the size of a GDT_* type in bits, <b>not bytes</b>!
367  *
368  * Use GDALGetDataTypeSizeBytes() for bytes.
369  * Use GDALGetDataTypeSizeBits() for bits.
370  *
371  * @param eDataType type, such as GDT_Byte.
372  * @return the number of bits or zero if it is not recognised.
373  */
374 
GDALGetDataTypeSize(GDALDataType eDataType)375 int CPL_STDCALL GDALGetDataTypeSize( GDALDataType eDataType )
376 
377 {
378     return GDALGetDataTypeSizeBytes( eDataType ) * 8;
379 }
380 
381 /************************************************************************/
382 /*                       GDALDataTypeIsComplex()                        */
383 /************************************************************************/
384 
385 /**
386  * \brief Is data type complex?
387  *
388  * @return TRUE if the passed type is complex (one of GDT_CInt16, GDT_CInt32,
389  * GDT_CFloat32 or GDT_CFloat64), that is it consists of a real and imaginary
390  * component.
391  */
392 
GDALDataTypeIsComplex(GDALDataType eDataType)393 int CPL_STDCALL GDALDataTypeIsComplex( GDALDataType eDataType )
394 
395 {
396     switch( eDataType )
397     {
398       case GDT_CInt16:
399       case GDT_CInt32:
400       case GDT_CFloat32:
401       case GDT_CFloat64:
402         return TRUE;
403 
404       default:
405         return FALSE;
406     }
407 }
408 
409 /************************************************************************/
410 /*                       GDALDataTypeIsFloating()                       */
411 /************************************************************************/
412 
413 /**
414  * \brief Is data type floating? (might be complex)
415  *
416  * @return TRUE if the passed type is floating (one of GDT_Float32, GDT_Float64,
417  * GDT_CFloat32, GDT_CFloat64)
418  * @since GDAL 2.3
419  */
420 
GDALDataTypeIsFloating(GDALDataType eDataType)421 int CPL_STDCALL GDALDataTypeIsFloating( GDALDataType eDataType )
422 {
423     switch( eDataType )
424     {
425       case GDT_Float32:
426       case GDT_Float64:
427       case GDT_CFloat32:
428       case GDT_CFloat64:
429         return TRUE;
430 
431       default:
432         return FALSE;
433     }
434 }
435 
436 /************************************************************************/
437 /*                       GDALDataTypeIsInteger()                        */
438 /************************************************************************/
439 
440 /**
441  * \brief Is data type integer? (might be complex)
442  *
443  * @return TRUE if the passed type is integer (one of GDT_Byte, GDT_Int16,
444  * GDT_UInt16, GDT_Int32, GDT_UInt32, GDT_CInt16, GDT_CInt32).
445  * @since GDAL 2.3
446  */
447 
GDALDataTypeIsInteger(GDALDataType eDataType)448 int CPL_STDCALL GDALDataTypeIsInteger( GDALDataType eDataType )
449 
450 {
451     switch( eDataType )
452     {
453       case GDT_Byte:
454       case GDT_Int16:
455       case GDT_UInt16:
456       case GDT_Int32:
457       case GDT_UInt32:
458       case GDT_CInt16:
459       case GDT_CInt32:
460         return TRUE;
461 
462       default:
463         return FALSE;
464     }
465 }
466 
467 /************************************************************************/
468 /*                       GDALDataTypeIsSigned()                         */
469 /************************************************************************/
470 
471 /**
472  * \brief Is data type signed?
473  *
474  * @return TRUE if the passed type is signed.
475  * @since GDAL 2.3
476  */
477 
GDALDataTypeIsSigned(GDALDataType eDataType)478 int CPL_STDCALL GDALDataTypeIsSigned( GDALDataType eDataType )
479 {
480     switch( eDataType )
481     {
482       case GDT_Byte:
483       case GDT_UInt16:
484       case GDT_UInt32:
485         return FALSE;
486 
487       default:
488         return TRUE;
489     }
490 }
491 
492 /************************************************************************/
493 /*                    GDALDataTypeIsConversionLossy()                   */
494 /************************************************************************/
495 
496 /**
497  * \brief Is conversion from eTypeFrom to eTypeTo potentially lossy
498  *
499  * @param eTypeFrom input datatype
500  * @param eTypeTo output datatype
501  * @return TRUE if conversion from eTypeFrom to eTypeTo potentially lossy.
502  * @since GDAL 2.3
503  */
504 
GDALDataTypeIsConversionLossy(GDALDataType eTypeFrom,GDALDataType eTypeTo)505 int CPL_STDCALL GDALDataTypeIsConversionLossy( GDALDataType eTypeFrom,
506                                                GDALDataType eTypeTo )
507 {
508     // E.g cfloat32 -> float32
509     if( GDALDataTypeIsComplex(eTypeFrom) && !GDALDataTypeIsComplex(eTypeTo) )
510         return TRUE;
511 
512     eTypeFrom = GDALGetNonComplexDataType(eTypeFrom);
513     eTypeTo = GDALGetNonComplexDataType(eTypeTo);
514 
515     if( GDALDataTypeIsInteger(eTypeTo) )
516     {
517         // E.g. float32 -> int32
518         if( GDALDataTypeIsFloating(eTypeFrom) )
519             return TRUE;
520 
521         // E.g. Int16 to UInt16
522         const int bIsFromSigned = GDALDataTypeIsSigned(eTypeFrom);
523         const int bIsToSigned = GDALDataTypeIsSigned(eTypeTo);
524         if( bIsFromSigned && !bIsToSigned )
525             return TRUE;
526 
527         // E.g UInt32 to UInt16
528         const int nFromSize =  GDALGetDataTypeSize(eTypeFrom);
529         const int nToSize = GDALGetDataTypeSize(eTypeTo);
530         if( nFromSize > nToSize )
531             return TRUE;
532 
533         // E.g UInt16 to Int16
534         if( nFromSize == nToSize && !bIsFromSigned && bIsToSigned )
535             return TRUE;
536 
537         return FALSE;
538     }
539 
540     if( eTypeTo == GDT_Float32 && (eTypeFrom == GDT_Int32 ||
541                                    eTypeFrom == GDT_UInt32 ||
542                                    eTypeFrom == GDT_Float64) )
543     {
544         return TRUE;
545     }
546 
547     return FALSE;
548 }
549 
550 /************************************************************************/
551 /*                        GDALGetDataTypeName()                         */
552 /************************************************************************/
553 
554 /**
555  * \brief Get name of data type.
556  *
557  * Returns a symbolic name for the data type.  This is essentially the
558  * the enumerated item name with the GDT_ prefix removed.  So GDT_Byte returns
559  * "Byte".  The returned strings are static strings and should not be modified
560  * or freed by the application.  These strings are useful for reporting
561  * datatypes in debug statements, errors and other user output.
562  *
563  * @param eDataType type to get name of.
564  * @return string corresponding to existing data type
565  *         or NULL pointer if invalid type given.
566  */
567 
GDALGetDataTypeName(GDALDataType eDataType)568 const char * CPL_STDCALL GDALGetDataTypeName( GDALDataType eDataType )
569 
570 {
571     switch( eDataType )
572     {
573       case GDT_Unknown:
574         return "Unknown";
575 
576       case GDT_Byte:
577         return "Byte";
578 
579       case GDT_UInt16:
580         return "UInt16";
581 
582       case GDT_Int16:
583         return "Int16";
584 
585       case GDT_UInt32:
586         return "UInt32";
587 
588       case GDT_Int32:
589         return "Int32";
590 
591       case GDT_Float32:
592         return "Float32";
593 
594       case GDT_Float64:
595         return "Float64";
596 
597       case GDT_CInt16:
598         return "CInt16";
599 
600       case GDT_CInt32:
601         return "CInt32";
602 
603       case GDT_CFloat32:
604         return "CFloat32";
605 
606       case GDT_CFloat64:
607         return "CFloat64";
608 
609       default:
610         return nullptr;
611     }
612 }
613 
614 /************************************************************************/
615 /*                        GDALGetDataTypeByName()                       */
616 /************************************************************************/
617 
618 /**
619  * \brief Get data type by symbolic name.
620  *
621  * Returns a data type corresponding to the given symbolic name. This
622  * function is opposite to the GDALGetDataTypeName().
623  *
624  * @param pszName string containing the symbolic name of the type.
625  *
626  * @return GDAL data type.
627  */
628 
GDALGetDataTypeByName(const char * pszName)629 GDALDataType CPL_STDCALL GDALGetDataTypeByName( const char *pszName )
630 
631 {
632     VALIDATE_POINTER1( pszName, "GDALGetDataTypeByName", GDT_Unknown );
633 
634     for( int iType = 1; iType < GDT_TypeCount; iType++ )
635     {
636         const auto eType = static_cast<GDALDataType>(iType);
637         if( GDALGetDataTypeName(eType) != nullptr
638             && EQUAL(GDALGetDataTypeName(eType), pszName) )
639         {
640             return eType;
641         }
642     }
643 
644     return GDT_Unknown;
645 }
646 
647 /************************************************************************/
648 /*                      GDALAdjustValueToDataType()                     */
649 /************************************************************************/
650 
ClampAndRound(double & dfValue,bool & bClamped,bool & bRounded)651 template<class T> static inline void ClampAndRound(
652     double& dfValue, bool& bClamped, bool &bRounded )
653 {
654     // TODO(schwehr): Rework this template.  ::min() versus ::lowest.
655 
656     if (dfValue < std::numeric_limits<T>::min())
657     {
658         bClamped = true;
659         dfValue = static_cast<double>(std::numeric_limits<T>::min());
660     }
661     else if (dfValue > std::numeric_limits<T>::max())
662     {
663         bClamped = true;
664         dfValue = static_cast<double>(std::numeric_limits<T>::max());
665     }
666     else if (dfValue != static_cast<double>(static_cast<T>(dfValue)))
667     {
668         bRounded = true;
669         dfValue = static_cast<double>(static_cast<T>(floor(dfValue + 0.5)));
670     }
671 }
672 
673 /**
674  * \brief Adjust a value to the output data type
675  *
676  * Adjustment consist in clamping to minimum/maxmimum values of the data type
677  * and rounding for integral types.
678  *
679  * @param eDT target data type.
680  * @param dfValue value to adjust.
681  * @param pbClamped pointer to a integer(boolean) to indicate if clamping has been made, or NULL
682  * @param pbRounded pointer to a integer(boolean) to indicate if rounding has been made, or NULL
683  *
684  * @return adjusted value
685  * @since GDAL 2.1
686  */
687 
GDALAdjustValueToDataType(GDALDataType eDT,double dfValue,int * pbClamped,int * pbRounded)688 double GDALAdjustValueToDataType(
689     GDALDataType eDT, double dfValue, int* pbClamped, int* pbRounded )
690 {
691     bool bClamped = false;
692     bool bRounded = false;
693     switch(eDT)
694     {
695         case GDT_Byte:
696             ClampAndRound<GByte>(dfValue, bClamped, bRounded);
697             break;
698         case GDT_Int16:
699             ClampAndRound<GInt16>(dfValue, bClamped, bRounded);
700             break;
701         case GDT_UInt16:
702             ClampAndRound<GUInt16>(dfValue, bClamped, bRounded);
703             break;
704         case GDT_Int32:
705             ClampAndRound<GInt32>(dfValue, bClamped, bRounded);
706             break;
707         case GDT_UInt32:
708             ClampAndRound<GUInt32>(dfValue, bClamped, bRounded);
709             break;
710         case GDT_Float32:
711         {
712             if( !CPLIsFinite(dfValue) )
713                 break;
714 
715             // TODO(schwehr): ::min() versus ::lowest.
716             // Use ClampAndRound after it has been fixed.
717             if ( dfValue < -std::numeric_limits<float>::max())
718             {
719                 bClamped = TRUE;
720                 dfValue = static_cast<double>(
721                     -std::numeric_limits<float>::max());
722             }
723             else if (dfValue > std::numeric_limits<float>::max())
724             {
725                 bClamped = TRUE;
726                 dfValue = static_cast<double>(
727                     std::numeric_limits<float>::max());
728             }
729             else
730             {
731                 // Intentionally loose precision.
732                 // TODO(schwehr): Is the double cast really necessary?
733                 // If so, why?  What will fail?
734                 dfValue = static_cast<double>(static_cast<float>(dfValue));
735             }
736             break;
737         }
738         default:
739             break;
740     }
741     if( pbClamped )
742         *pbClamped = bClamped;
743     if( pbRounded )
744         *pbRounded = bRounded;
745     return dfValue;
746 }
747 
748 /************************************************************************/
749 /*                        GDALGetNonComplexDataType()                */
750 /************************************************************************/
751 /**
752  * \brief Return the base data type for the specified input.
753  *
754  * If the input data type is complex this function returns the base type
755  * i.e. the data type of the real and imaginary parts (non-complex).
756  * If the input data type is already non-complex, then it is returned
757  * unchanged.
758  *
759  * @param eDataType type, such as GDT_CFloat32.
760  *
761  * @return GDAL data type.
762  */
GDALGetNonComplexDataType(GDALDataType eDataType)763 GDALDataType CPL_STDCALL GDALGetNonComplexDataType( GDALDataType eDataType )
764 {
765     switch( eDataType )
766     {
767       case GDT_CInt16:
768         return GDT_Int16;
769       case GDT_CInt32:
770         return GDT_Int32;
771       case GDT_CFloat32:
772         return GDT_Float32;
773       case GDT_CFloat64:
774         return GDT_Float64;
775       default:
776         return eDataType;
777     }
778 }
779 
780 /************************************************************************/
781 /*                        GDALGetAsyncStatusTypeByName()                */
782 /************************************************************************/
783 /**
784  * Get AsyncStatusType by symbolic name.
785  *
786  * Returns a data type corresponding to the given symbolic name. This
787  * function is opposite to the GDALGetAsyncStatusTypeName().
788  *
789  * @param pszName string containing the symbolic name of the type.
790  *
791  * @return GDAL AsyncStatus type.
792  */
GDALGetAsyncStatusTypeByName(const char * pszName)793 GDALAsyncStatusType CPL_DLL CPL_STDCALL GDALGetAsyncStatusTypeByName(
794     const char *pszName )
795 {
796     VALIDATE_POINTER1( pszName, "GDALGetAsyncStatusTypeByName", GARIO_ERROR);
797 
798     for( int iType = 0; iType < GARIO_TypeCount; iType++ )
799     {
800         const auto eType = static_cast<GDALAsyncStatusType>(iType);
801         if( GDALGetAsyncStatusTypeName(eType) != nullptr
802             && EQUAL(GDALGetAsyncStatusTypeName(eType), pszName) )
803         {
804             return eType;
805         }
806     }
807 
808     return GARIO_ERROR;
809 }
810 
811 /************************************************************************/
812 /*                        GDALGetAsyncStatusTypeName()                 */
813 /************************************************************************/
814 
815 /**
816  * Get name of AsyncStatus data type.
817  *
818  * Returns a symbolic name for the AsyncStatus data type.  This is essentially the
819  * the enumerated item name with the GARIO_ prefix removed.  So GARIO_COMPLETE returns
820  * "COMPLETE".  The returned strings are static strings and should not be modified
821  * or freed by the application.  These strings are useful for reporting
822  * datatypes in debug statements, errors and other user output.
823  *
824  * @param eAsyncStatusType type to get name of.
825  * @return string corresponding to type.
826  */
827 
GDALGetAsyncStatusTypeName(GDALAsyncStatusType eAsyncStatusType)828  const char * CPL_STDCALL GDALGetAsyncStatusTypeName(
829      GDALAsyncStatusType eAsyncStatusType )
830 
831 {
832     switch( eAsyncStatusType )
833     {
834       case GARIO_PENDING:
835         return "PENDING";
836 
837       case GARIO_UPDATE:
838         return "UPDATE";
839 
840       case GARIO_ERROR:
841         return "ERROR";
842 
843       case GARIO_COMPLETE:
844         return "COMPLETE";
845 
846       default:
847         return nullptr;
848     }
849 }
850 
851 /************************************************************************/
852 /*                  GDALGetPaletteInterpretationName()                  */
853 /************************************************************************/
854 
855 /**
856  * \brief Get name of palette interpretation
857  *
858  * Returns a symbolic name for the palette interpretation.  This is the
859  * the enumerated item name with the GPI_ prefix removed.  So GPI_Gray returns
860  * "Gray".  The returned strings are static strings and should not be modified
861  * or freed by the application.
862  *
863  * @param eInterp palette interpretation to get name of.
864  * @return string corresponding to palette interpretation.
865  */
866 
GDALGetPaletteInterpretationName(GDALPaletteInterp eInterp)867 const char *GDALGetPaletteInterpretationName( GDALPaletteInterp eInterp )
868 
869 {
870     switch( eInterp )
871     {
872       case GPI_Gray:
873         return "Gray";
874 
875       case GPI_RGB:
876         return "RGB";
877 
878       case GPI_CMYK:
879         return "CMYK";
880 
881       case GPI_HLS:
882         return "HLS";
883 
884       default:
885         return "Unknown";
886     }
887 }
888 
889 /************************************************************************/
890 /*                   GDALGetColorInterpretationName()                   */
891 /************************************************************************/
892 
893 /**
894  * \brief Get name of color interpretation
895  *
896  * Returns a symbolic name for the color interpretation.  This is derived from
897  * the enumerated item name with the GCI_ prefix removed, but there are some
898  * variations. So GCI_GrayIndex returns "Gray" and GCI_RedBand returns "Red".
899  * The returned strings are static strings and should not be modified
900  * or freed by the application.
901  *
902  * @param eInterp color interpretation to get name of.
903  * @return string corresponding to color interpretation
904  *         or NULL pointer if invalid enumerator given.
905  */
906 
GDALGetColorInterpretationName(GDALColorInterp eInterp)907 const char *GDALGetColorInterpretationName( GDALColorInterp eInterp )
908 
909 {
910     switch( eInterp )
911     {
912       case GCI_Undefined:
913         return "Undefined";
914 
915       case GCI_GrayIndex:
916         return "Gray";
917 
918       case GCI_PaletteIndex:
919         return "Palette";
920 
921       case GCI_RedBand:
922         return "Red";
923 
924       case GCI_GreenBand:
925         return "Green";
926 
927       case GCI_BlueBand:
928         return "Blue";
929 
930       case GCI_AlphaBand:
931         return "Alpha";
932 
933       case GCI_HueBand:
934         return "Hue";
935 
936       case GCI_SaturationBand:
937         return "Saturation";
938 
939       case GCI_LightnessBand:
940         return "Lightness";
941 
942       case GCI_CyanBand:
943         return "Cyan";
944 
945       case GCI_MagentaBand:
946         return "Magenta";
947 
948       case GCI_YellowBand:
949         return "Yellow";
950 
951       case GCI_BlackBand:
952         return "Black";
953 
954       case GCI_YCbCr_YBand:
955         return "YCbCr_Y";
956 
957       case GCI_YCbCr_CbBand:
958         return "YCbCr_Cb";
959 
960       case GCI_YCbCr_CrBand:
961         return "YCbCr_Cr";
962 
963       default:
964         return "Unknown";
965     }
966 }
967 
968 /************************************************************************/
969 /*                GDALGetColorInterpretationByName()                    */
970 /************************************************************************/
971 
972 /**
973  * \brief Get color interpretation by symbolic name.
974  *
975  * Returns a color interpretation corresponding to the given symbolic name. This
976  * function is opposite to the GDALGetColorInterpretationName().
977  *
978  * @param pszName string containing the symbolic name of the color
979  * interpretation.
980  *
981  * @return GDAL color interpretation.
982  *
983  * @since GDAL 1.7.0
984  */
985 
GDALGetColorInterpretationByName(const char * pszName)986 GDALColorInterp GDALGetColorInterpretationByName( const char *pszName )
987 
988 {
989     VALIDATE_POINTER1( pszName, "GDALGetColorInterpretationByName",
990                        GCI_Undefined );
991 
992     for( int iType = 0; iType <= GCI_Max; iType++ )
993     {
994         if( EQUAL(GDALGetColorInterpretationName(static_cast<GDALColorInterp>(iType)),
995                   pszName) )
996         {
997             return static_cast<GDALColorInterp>(iType);
998         }
999     }
1000 
1001     return GCI_Undefined;
1002 }
1003 
1004 /************************************************************************/
1005 /*                     GDALGetRandomRasterSample()                      */
1006 /************************************************************************/
1007 
1008 /** Undocumented
1009  * @param hBand undocumented.
1010  * @param nSamples undocumented.
1011  * @param pafSampleBuf undocumented.
1012  * @return undocumented
1013  */
1014 int CPL_STDCALL
GDALGetRandomRasterSample(GDALRasterBandH hBand,int nSamples,float * pafSampleBuf)1015 GDALGetRandomRasterSample( GDALRasterBandH hBand, int nSamples,
1016                            float *pafSampleBuf )
1017 
1018 {
1019     VALIDATE_POINTER1( hBand, "GDALGetRandomRasterSample", 0 );
1020 
1021     GDALRasterBand *poBand;
1022 
1023     poBand = GDALRasterBand::FromHandle(GDALGetRasterSampleOverview( hBand, nSamples ));
1024     CPLAssert( nullptr != poBand );
1025 
1026 /* -------------------------------------------------------------------- */
1027 /*      Figure out the ratio of blocks we will read to get an           */
1028 /*      approximate value.                                              */
1029 /* -------------------------------------------------------------------- */
1030     int bGotNoDataValue = FALSE;
1031 
1032     double dfNoDataValue = poBand->GetNoDataValue( &bGotNoDataValue );
1033 
1034     int nBlockXSize = 0;
1035     int nBlockYSize = 0;
1036     poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
1037 
1038     const int nBlocksPerRow =
1039         (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
1040     const int nBlocksPerColumn =
1041         (poBand->GetYSize() + nBlockYSize - 1) / nBlockYSize;
1042 
1043     const int nBlockPixels = nBlockXSize * nBlockYSize;
1044     const int nBlockCount = nBlocksPerRow * nBlocksPerColumn;
1045 
1046     if( nBlocksPerRow == 0 || nBlocksPerColumn == 0 || nBlockPixels == 0
1047         || nBlockCount == 0 )
1048     {
1049         CPLError( CE_Failure, CPLE_AppDefined,
1050                   "GDALGetRandomRasterSample(): returning because band"
1051                   " appears degenerate." );
1052 
1053         return FALSE;
1054     }
1055 
1056     int nSampleRate = static_cast<int>(
1057         std::max(1.0, sqrt( static_cast<double>(nBlockCount) ) - 2.0));
1058 
1059     if( nSampleRate == nBlocksPerRow && nSampleRate > 1 )
1060         nSampleRate--;
1061 
1062     while( nSampleRate > 1
1063            && ((nBlockCount-1) / nSampleRate + 1) * nBlockPixels < nSamples )
1064         nSampleRate--;
1065 
1066     int nBlockSampleRate = 1;
1067 
1068     if ((nSamples / ((nBlockCount-1) / nSampleRate + 1)) != 0)
1069         nBlockSampleRate =
1070             std::max( 1,
1071                  nBlockPixels /
1072                  (nSamples / ((nBlockCount-1) / nSampleRate + 1)));
1073 
1074     int nActualSamples = 0;
1075 
1076     for( int iSampleBlock = 0;
1077          iSampleBlock < nBlockCount;
1078          iSampleBlock += nSampleRate )
1079     {
1080 
1081         const int iYBlock = iSampleBlock / nBlocksPerRow;
1082         const int iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
1083 
1084         GDALRasterBlock * const poBlock =
1085             poBand->GetLockedBlockRef( iXBlock, iYBlock );
1086         if( poBlock == nullptr )
1087             continue;
1088         void* pDataRef = poBlock->GetDataRef();
1089 
1090         int iXValid = nBlockXSize;
1091         if( (iXBlock + 1) * nBlockXSize > poBand->GetXSize() )
1092             iXValid = poBand->GetXSize() - iXBlock * nBlockXSize;
1093 
1094         int iYValid = nBlockYSize;
1095         if( (iYBlock + 1) * nBlockYSize > poBand->GetYSize() )
1096             iYValid = poBand->GetYSize() - iYBlock * nBlockYSize;
1097 
1098         int iRemainder = 0;
1099 
1100         for( int iY = 0; iY < iYValid; iY++ )
1101         {
1102             int iX = iRemainder;  // Used after for.
1103             for( ; iX < iXValid; iX += nBlockSampleRate )
1104             {
1105                 double dfValue = 0.0;
1106                 const int iOffset = iX + iY * nBlockXSize;
1107 
1108                 switch( poBlock->GetDataType() )
1109                 {
1110                   case GDT_Byte:
1111                     dfValue = reinterpret_cast<const GByte*>(pDataRef)[iOffset];
1112                     break;
1113                   case GDT_UInt16:
1114                     dfValue = reinterpret_cast<const GUInt16*>(pDataRef)[iOffset];
1115                     break;
1116                   case GDT_Int16:
1117                     dfValue = reinterpret_cast<const GInt16*>(pDataRef)[iOffset];
1118                     break;
1119                   case GDT_UInt32:
1120                     dfValue = reinterpret_cast<const GUInt32*>(pDataRef)[iOffset];
1121                     break;
1122                   case GDT_Int32:
1123                     dfValue = reinterpret_cast<const GInt32*>(pDataRef)[iOffset];
1124                     break;
1125                   case GDT_Float32:
1126                     dfValue = reinterpret_cast<const float*>(pDataRef)[iOffset];
1127                     break;
1128                   case GDT_Float64:
1129                     dfValue = reinterpret_cast<const double*>(pDataRef)[iOffset];
1130                     break;
1131                   case GDT_CInt16:
1132                   {
1133                     // TODO(schwehr): Clean up casts.
1134                     const double dfReal = reinterpret_cast<const GInt16*>(pDataRef)[iOffset*2];
1135                     const double dfImag = reinterpret_cast<const GInt16*>(pDataRef)[iOffset*2+1];
1136                     dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
1137                     break;
1138                   }
1139                   case GDT_CInt32:
1140                   {
1141                     const double dfReal = reinterpret_cast<const GInt32*>(pDataRef)[iOffset*2];
1142                     const double dfImag = reinterpret_cast<const GInt32*>(pDataRef)[iOffset*2+1];
1143                     dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
1144                     break;
1145                   }
1146                   case GDT_CFloat32:
1147                   {
1148                     const double dfReal = reinterpret_cast<const float*>(pDataRef)[iOffset*2];
1149                     const double dfImag = reinterpret_cast<const float*>(pDataRef)[iOffset*2+1];
1150                     dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
1151                     break;
1152                   }
1153                   case GDT_CFloat64:
1154                   {
1155                     const double dfReal = reinterpret_cast<const double*>(pDataRef)[iOffset*2];
1156                     const double dfImag = reinterpret_cast<const double*>(pDataRef)[iOffset*2+1];
1157                     dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
1158                     break;
1159                   }
1160                   default:
1161                     CPLAssert( false );
1162                 }
1163 
1164                 if( bGotNoDataValue && dfValue == dfNoDataValue )
1165                     continue;
1166 
1167                 if( nActualSamples < nSamples )
1168                     pafSampleBuf[nActualSamples++] = static_cast<float>(dfValue);
1169             }
1170 
1171             iRemainder = iX - iXValid;
1172         }
1173 
1174         poBlock->DropLock();
1175     }
1176 
1177     return nActualSamples;
1178 }
1179 
1180 /************************************************************************/
1181 /*                            GDALInitGCPs()                            */
1182 /************************************************************************/
1183 
1184 /** Initialize an array of GCPs.
1185  *
1186  * Numeric values are initialized to 0 and strings to the empty string ""
1187  * allocated with CPLStrdup()
1188  * An array initialized with GDALInitGCPs() must be de-initialized with
1189  * GDALDeinitGCPs().
1190  *
1191  * @param nCount number of GCPs in psGCP
1192  * @param psGCP array of GCPs of size nCount.
1193  */
GDALInitGCPs(int nCount,GDAL_GCP * psGCP)1194 void CPL_STDCALL GDALInitGCPs( int nCount, GDAL_GCP *psGCP )
1195 
1196 {
1197     if( nCount > 0 )
1198     {
1199         VALIDATE_POINTER0( psGCP, "GDALInitGCPs" );
1200     }
1201 
1202     for( int iGCP = 0; iGCP < nCount; iGCP++ )
1203     {
1204         memset( psGCP, 0, sizeof(GDAL_GCP) );
1205         psGCP->pszId = CPLStrdup("");
1206         psGCP->pszInfo = CPLStrdup("");
1207         psGCP++;
1208     }
1209 }
1210 
1211 /************************************************************************/
1212 /*                           GDALDeinitGCPs()                           */
1213 /************************************************************************/
1214 
1215 /** De-initialize an array of GCPs (initialized with GDALInitGCPs())
1216  *
1217  * @param nCount number of GCPs in psGCP
1218  * @param psGCP array of GCPs of size nCount.
1219  */
GDALDeinitGCPs(int nCount,GDAL_GCP * psGCP)1220 void CPL_STDCALL GDALDeinitGCPs( int nCount, GDAL_GCP *psGCP )
1221 
1222 {
1223     if ( nCount > 0 )
1224     {
1225         VALIDATE_POINTER0( psGCP, "GDALDeinitGCPs" );
1226     }
1227 
1228     for( int iGCP = 0; iGCP < nCount; iGCP++ )
1229     {
1230         CPLFree( psGCP->pszId );
1231         CPLFree( psGCP->pszInfo );
1232         psGCP++;
1233     }
1234 }
1235 
1236 /************************************************************************/
1237 /*                         GDALDuplicateGCPs()                          */
1238 /************************************************************************/
1239 
1240 /** Duplicate an array of GCPs
1241  *
1242  * The return must be freed with GDALDeinitGCPs() followed by CPLFree()
1243  *
1244  * @param nCount number of GCPs in psGCP
1245  * @param pasGCPList array of GCPs of size nCount.
1246  */
GDALDuplicateGCPs(int nCount,const GDAL_GCP * pasGCPList)1247 GDAL_GCP * CPL_STDCALL GDALDuplicateGCPs( int nCount, const GDAL_GCP *pasGCPList )
1248 
1249 {
1250     GDAL_GCP *pasReturn = static_cast<GDAL_GCP *>(
1251         CPLMalloc(sizeof(GDAL_GCP) * nCount) );
1252     GDALInitGCPs( nCount, pasReturn );
1253 
1254     for( int iGCP = 0; iGCP < nCount; iGCP++ )
1255     {
1256         CPLFree( pasReturn[iGCP].pszId );
1257         pasReturn[iGCP].pszId = CPLStrdup( pasGCPList[iGCP].pszId );
1258 
1259         CPLFree( pasReturn[iGCP].pszInfo );
1260         pasReturn[iGCP].pszInfo = CPLStrdup( pasGCPList[iGCP].pszInfo );
1261 
1262         pasReturn[iGCP].dfGCPPixel = pasGCPList[iGCP].dfGCPPixel;
1263         pasReturn[iGCP].dfGCPLine = pasGCPList[iGCP].dfGCPLine;
1264         pasReturn[iGCP].dfGCPX = pasGCPList[iGCP].dfGCPX;
1265         pasReturn[iGCP].dfGCPY = pasGCPList[iGCP].dfGCPY;
1266         pasReturn[iGCP].dfGCPZ = pasGCPList[iGCP].dfGCPZ;
1267     }
1268 
1269     return pasReturn;
1270 }
1271 
1272 /************************************************************************/
1273 /*                       GDALFindAssociatedFile()                       */
1274 /************************************************************************/
1275 
1276 /**
1277  * \brief Find file with alternate extension.
1278  *
1279  * Finds the file with the indicated extension, substituting it in place
1280  * of the extension of the base filename.  Generally used to search for
1281  * associated files like world files .RPB files, etc.  If necessary, the
1282  * extension will be tried in both upper and lower case.  If a sibling file
1283  * list is available it will be used instead of doing VSIStatExL() calls to
1284  * probe the file system.
1285  *
1286  * Note that the result is a dynamic CPLString so this method should not
1287  * be used in a situation where there could be cross heap issues.  It is
1288  * generally imprudent for application built on GDAL to use this function
1289  * unless they are sure they will always use the same runtime heap as GDAL.
1290  *
1291  * @param pszBaseFilename the filename relative to which to search.
1292  * @param pszExt the target extension in either upper or lower case.
1293  * @param papszSiblingFiles the list of files in the same directory as
1294  * pszBaseFilename or NULL if they are not known.
1295  * @param nFlags special options controlling search.  None defined yet, just
1296  * pass 0.
1297  *
1298  * @return an empty string if the target is not found, otherwise the target
1299  * file with similar path style as the pszBaseFilename.
1300  */
1301 
1302 /**/
1303 /**/
1304 
GDALFindAssociatedFile(const char * pszBaseFilename,const char * pszExt,CSLConstList papszSiblingFiles,CPL_UNUSED int nFlags)1305 CPLString GDALFindAssociatedFile( const char *pszBaseFilename,
1306                                   const char *pszExt,
1307                                   CSLConstList papszSiblingFiles,
1308                                   CPL_UNUSED int nFlags )
1309 
1310 {
1311     CPLString osTarget = CPLResetExtension( pszBaseFilename, pszExt );
1312 
1313     if( papszSiblingFiles == nullptr ||
1314         !GDALCanReliablyUseSiblingFileList(osTarget.c_str()) )
1315     {
1316         VSIStatBufL sStatBuf;
1317 
1318         if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1319         {
1320             CPLString osAltExt = pszExt;
1321 
1322             if( islower( pszExt[0] ) )
1323                 osAltExt.toupper();
1324             else
1325                 osAltExt.tolower();
1326 
1327             osTarget = CPLResetExtension( pszBaseFilename, osAltExt );
1328 
1329             if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
1330                 return "";
1331         }
1332     }
1333     else
1334     {
1335         const int iSibling = CSLFindString( papszSiblingFiles,
1336                                             CPLGetFilename(osTarget) );
1337         if( iSibling < 0 )
1338             return "";
1339 
1340         osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
1341         osTarget += papszSiblingFiles[iSibling];
1342     }
1343 
1344     return osTarget;
1345 }
1346 
1347 /************************************************************************/
1348 /*                         GDALLoadOziMapFile()                         */
1349 /************************************************************************/
1350 
1351 /** Helper function for translator implementer wanting support for OZI .map
1352  *
1353  * @param pszFilename filename of .tab file
1354  * @param padfGeoTransform output geotransform. Must hold 6 doubles.
1355  * @param ppszWKT output pointer to a string that will be allocated with CPLMalloc().
1356  * @param pnGCPCount output pointer to GCP count.
1357  * @param ppasGCPs outputer pointer to an array of GCPs.
1358  * @return TRUE in case of success, FALSE otherwise.
1359  */
GDALLoadOziMapFile(const char * pszFilename,double * padfGeoTransform,char ** ppszWKT,int * pnGCPCount,GDAL_GCP ** ppasGCPs)1360 int CPL_STDCALL GDALLoadOziMapFile( const char *pszFilename,
1361                                     double *padfGeoTransform, char **ppszWKT,
1362                                     int *pnGCPCount, GDAL_GCP **ppasGCPs )
1363 
1364 {
1365     VALIDATE_POINTER1( pszFilename, "GDALLoadOziMapFile", FALSE );
1366     VALIDATE_POINTER1( padfGeoTransform, "GDALLoadOziMapFile", FALSE );
1367     VALIDATE_POINTER1( pnGCPCount, "GDALLoadOziMapFile", FALSE );
1368     VALIDATE_POINTER1( ppasGCPs, "GDALLoadOziMapFile", FALSE );
1369 
1370     char **papszLines = CSLLoad2( pszFilename, 1000, 200, nullptr );
1371 
1372     if ( !papszLines )
1373         return FALSE;
1374 
1375     int nLines = CSLCount( papszLines );
1376 
1377     // Check the OziExplorer Map file signature
1378     if ( nLines < 5
1379          || !STARTS_WITH_CI(papszLines[0], "OziExplorer Map Data File Version ") )
1380     {
1381         CPLError( CE_Failure, CPLE_AppDefined,
1382         "GDALLoadOziMapFile(): file \"%s\" is not in OziExplorer Map format.",
1383                   pszFilename );
1384         CSLDestroy( papszLines );
1385         return FALSE;
1386     }
1387 
1388     OGRSpatialReference oSRS;
1389     OGRErr eErr = OGRERR_NONE;
1390 
1391     /* The Map Scale Factor has been introduced recently on the 6th line */
1392     /* and is a trick that is used to just change that line without changing */
1393     /* the rest of the MAP file but providing an imagery that is smaller or larger */
1394     /* so we have to correct the pixel/line values read in the .MAP file so they */
1395     /* match the actual imagery dimension. Well, this is a bad summary of what */
1396     /* is explained at http://tech.groups.yahoo.com/group/OziUsers-L/message/12484 */
1397     double dfMSF = 1;
1398 
1399     for ( int iLine = 5; iLine < nLines; iLine++ )
1400     {
1401         if ( STARTS_WITH_CI(papszLines[iLine], "MSF,") )
1402         {
1403             dfMSF = CPLAtof(papszLines[iLine] + 4);
1404             if (dfMSF <= 0.01) /* Suspicious values */
1405             {
1406                 CPLDebug("OZI", "Suspicious MSF value : %s", papszLines[iLine]);
1407                 dfMSF = 1;
1408             }
1409         }
1410     }
1411 
1412     eErr = oSRS.importFromOzi( papszLines );
1413     if ( eErr == OGRERR_NONE )
1414     {
1415         if ( ppszWKT != nullptr )
1416             oSRS.exportToWkt( ppszWKT );
1417     }
1418 
1419     int nCoordinateCount = 0;
1420     // TODO(schwehr): Initialize asGCPs.
1421     GDAL_GCP asGCPs[30];
1422 
1423     // Iterate all lines in the MAP-file
1424     for ( int iLine = 5; iLine < nLines; iLine++ )
1425     {
1426         char **papszTok = CSLTokenizeString2( papszLines[iLine], ",",
1427                                               CSLT_ALLOWEMPTYTOKENS
1428                                               | CSLT_STRIPLEADSPACES
1429                                               | CSLT_STRIPENDSPACES );
1430 
1431         if ( CSLCount(papszTok) < 12 )
1432         {
1433             CSLDestroy(papszTok);
1434             continue;
1435         }
1436 
1437         if ( CSLCount(papszTok) >= 17
1438              && STARTS_WITH_CI(papszTok[0], "Point")
1439              && !EQUAL(papszTok[2], "")
1440              && !EQUAL(papszTok[3], "")
1441              && nCoordinateCount <
1442              static_cast<int>(CPL_ARRAYSIZE(asGCPs)) )
1443         {
1444             bool bReadOk = false;
1445             double dfLon = 0.0;
1446             double dfLat = 0.0;
1447 
1448             if ( !EQUAL(papszTok[6], "")
1449                  && !EQUAL(papszTok[7], "")
1450                  && !EQUAL(papszTok[9], "")
1451                  && !EQUAL(papszTok[10], "") )
1452             {
1453                 // Set geographical coordinates of the pixels
1454                 dfLon = CPLAtofM(papszTok[9]) + CPLAtofM(papszTok[10]) / 60.0;
1455                 dfLat = CPLAtofM(papszTok[6]) + CPLAtofM(papszTok[7]) / 60.0;
1456                 if ( EQUAL(papszTok[11], "W") )
1457                     dfLon = -dfLon;
1458                 if ( EQUAL(papszTok[8], "S") )
1459                     dfLat = -dfLat;
1460 
1461                 // Transform from the geographical coordinates into projected
1462                 // coordinates.
1463                 if ( eErr == OGRERR_NONE )
1464                 {
1465                     OGRSpatialReference *poLongLat = oSRS.CloneGeogCS();
1466 
1467                     if ( poLongLat )
1468                     {
1469                         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1470                         poLongLat->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1471 
1472                         OGRCoordinateTransformation *poTransform =
1473                             OGRCreateCoordinateTransformation( poLongLat,
1474                                                                &oSRS );
1475                         if ( poTransform )
1476                         {
1477                             bReadOk = CPL_TO_BOOL(
1478                                 poTransform->Transform( 1, &dfLon, &dfLat ));
1479                             delete poTransform;
1480                         }
1481                         delete poLongLat;
1482                     }
1483                 }
1484             }
1485             else if ( !EQUAL(papszTok[14], "")
1486                       && !EQUAL(papszTok[15], "") )
1487             {
1488                 // Set cartesian coordinates of the pixels.
1489                 dfLon = CPLAtofM(papszTok[14]);
1490                 dfLat = CPLAtofM(papszTok[15]);
1491                 bReadOk = true;
1492 
1493                 //if ( EQUAL(papszTok[16], "S") )
1494                 //    dfLat = -dfLat;
1495             }
1496 
1497             if ( bReadOk )
1498             {
1499                 GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1500 
1501                 // Set pixel/line part
1502                 asGCPs[nCoordinateCount].dfGCPPixel =
1503                     CPLAtofM(papszTok[2]) / dfMSF;
1504                 asGCPs[nCoordinateCount].dfGCPLine =
1505                     CPLAtofM(papszTok[3]) / dfMSF;
1506 
1507                 asGCPs[nCoordinateCount].dfGCPX = dfLon;
1508                 asGCPs[nCoordinateCount].dfGCPY = dfLat;
1509 
1510                 nCoordinateCount++;
1511             }
1512         }
1513 
1514         CSLDestroy( papszTok );
1515     }
1516 
1517     CSLDestroy( papszLines );
1518 
1519     if ( nCoordinateCount == 0 )
1520     {
1521         CPLDebug( "GDAL", "GDALLoadOziMapFile(\"%s\") did read no GCPs.",
1522                   pszFilename );
1523         return FALSE;
1524     }
1525 
1526 /* -------------------------------------------------------------------- */
1527 /*      Try to convert the GCPs into a geotransform definition, if      */
1528 /*      possible.  Otherwise we will need to use them as GCPs.          */
1529 /* -------------------------------------------------------------------- */
1530     if( !GDALGCPsToGeoTransform(
1531             nCoordinateCount, asGCPs, padfGeoTransform,
1532             CPLTestBool(CPLGetConfigOption("OZI_APPROX_GEOTRANSFORM", "NO")) ) )
1533     {
1534         if ( pnGCPCount && ppasGCPs )
1535         {
1536             CPLDebug( "GDAL",
1537                 "GDALLoadOziMapFile(%s) found file, was not able to derive a\n"
1538                 "first order geotransform.  Using points as GCPs.",
1539                 pszFilename );
1540 
1541             *ppasGCPs = static_cast<GDAL_GCP *>(
1542                 CPLCalloc( sizeof(GDAL_GCP), nCoordinateCount ) );
1543             memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1544             *pnGCPCount = nCoordinateCount;
1545         }
1546     }
1547     else
1548     {
1549         GDALDeinitGCPs( nCoordinateCount, asGCPs );
1550     }
1551 
1552     return TRUE;
1553 }
1554 
1555 /************************************************************************/
1556 /*                       GDALReadOziMapFile()                           */
1557 /************************************************************************/
1558 
1559 /** Helper function for translator implementer wanting support for OZI .map
1560  *
1561  * @param pszBaseFilename filename whose basename will help building the .map filename.
1562  * @param padfGeoTransform output geotransform. Must hold 6 doubles.
1563  * @param ppszWKT output pointer to a string that will be allocated with CPLMalloc().
1564  * @param pnGCPCount output pointer to GCP count.
1565  * @param ppasGCPs outputer pointer to an array of GCPs.
1566  * @return TRUE in case of success, FALSE otherwise.
1567  */
GDALReadOziMapFile(const char * pszBaseFilename,double * padfGeoTransform,char ** ppszWKT,int * pnGCPCount,GDAL_GCP ** ppasGCPs)1568 int CPL_STDCALL GDALReadOziMapFile( const char * pszBaseFilename,
1569                                     double *padfGeoTransform, char **ppszWKT,
1570                                     int *pnGCPCount, GDAL_GCP **ppasGCPs )
1571 
1572 {
1573 /* -------------------------------------------------------------------- */
1574 /*      Try lower case, then upper case.                                */
1575 /* -------------------------------------------------------------------- */
1576     const char *pszOzi = CPLResetExtension( pszBaseFilename, "map" );
1577 
1578     VSILFILE *fpOzi = VSIFOpenL( pszOzi, "rt" );
1579 
1580     if ( fpOzi == nullptr && VSIIsCaseSensitiveFS(pszOzi) )
1581     {
1582         pszOzi = CPLResetExtension( pszBaseFilename, "MAP" );
1583         fpOzi = VSIFOpenL( pszOzi, "rt" );
1584     }
1585 
1586     if ( fpOzi == nullptr )
1587         return FALSE;
1588 
1589     CPL_IGNORE_RET_VAL(VSIFCloseL( fpOzi ));
1590 
1591 /* -------------------------------------------------------------------- */
1592 /*      We found the file, now load and parse it.                       */
1593 /* -------------------------------------------------------------------- */
1594     return GDALLoadOziMapFile( pszOzi, padfGeoTransform, ppszWKT,
1595                                pnGCPCount, ppasGCPs );
1596 }
1597 
1598 /************************************************************************/
1599 /*                         GDALLoadTabFile()                            */
1600 /*                                                                      */
1601 /************************************************************************/
1602 
1603 /** Helper function for translator implementer wanting support for MapInfo
1604  * .tab files.
1605  *
1606  * @param pszFilename filename of .tab
1607  * @param padfGeoTransform output geotransform. Must hold 6 doubles.
1608  * @param ppszWKT output pointer to a string that will be allocated with CPLMalloc().
1609  * @param pnGCPCount output pointer to GCP count.
1610  * @param ppasGCPs outputer pointer to an array of GCPs.
1611  * @return TRUE in case of success, FALSE otherwise.
1612  */
GDALLoadTabFile(const char * pszFilename,double * padfGeoTransform,char ** ppszWKT,int * pnGCPCount,GDAL_GCP ** ppasGCPs)1613 int CPL_STDCALL GDALLoadTabFile( const char *pszFilename,
1614                                  double *padfGeoTransform, char **ppszWKT,
1615                                  int *pnGCPCount, GDAL_GCP **ppasGCPs )
1616 
1617 {
1618     char **papszLines = CSLLoad2( pszFilename, 1000, 200, nullptr );
1619 
1620     if ( !papszLines )
1621         return FALSE;
1622 
1623     char **papszTok = nullptr;
1624     bool bTypeRasterFound = false;
1625     bool bInsideTableDef = false;
1626     int nCoordinateCount = 0;
1627     GDAL_GCP asGCPs[256];  // TODO(schwehr): Initialize.
1628     const int numLines = CSLCount(papszLines);
1629 
1630     // Iterate all lines in the TAB-file
1631     for( int iLine=0; iLine<numLines; iLine++ )
1632     {
1633         CSLDestroy(papszTok);
1634         papszTok = CSLTokenizeStringComplex(papszLines[iLine], " \t(),;",
1635                                             TRUE, FALSE);
1636 
1637         if (CSLCount(papszTok) < 2)
1638             continue;
1639 
1640         // Did we find table definition
1641         if (EQUAL(papszTok[0], "Definition") && EQUAL(papszTok[1], "Table") )
1642         {
1643             bInsideTableDef = TRUE;
1644         }
1645         else if (bInsideTableDef && (EQUAL(papszTok[0], "Type")) )
1646         {
1647             // Only RASTER-type will be handled
1648             if (EQUAL(papszTok[1], "RASTER"))
1649             {
1650                 bTypeRasterFound = true;
1651             }
1652             else
1653             {
1654                 CSLDestroy(papszTok);
1655                 CSLDestroy(papszLines);
1656                 return FALSE;
1657             }
1658         }
1659         else if (bTypeRasterFound && bInsideTableDef
1660                  && CSLCount(papszTok) > 4
1661                  && EQUAL(papszTok[4], "Label")
1662                  && nCoordinateCount <
1663                  static_cast<int>(CPL_ARRAYSIZE(asGCPs)) )
1664         {
1665             GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1666 
1667             asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
1668             asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
1669             asGCPs[nCoordinateCount].dfGCPX = CPLAtofM(papszTok[0]);
1670             asGCPs[nCoordinateCount].dfGCPY = CPLAtofM(papszTok[1]);
1671             if( papszTok[5] != nullptr )
1672             {
1673                 CPLFree( asGCPs[nCoordinateCount].pszId );
1674                 asGCPs[nCoordinateCount].pszId = CPLStrdup(papszTok[5]);
1675             }
1676 
1677             nCoordinateCount++;
1678         }
1679         else if( bTypeRasterFound && bInsideTableDef
1680                  && EQUAL(papszTok[0],"CoordSys")
1681                  && ppszWKT != nullptr )
1682         {
1683             OGRSpatialReference oSRS;
1684 
1685             if( oSRS.importFromMICoordSys( papszLines[iLine] ) == OGRERR_NONE )
1686                 oSRS.exportToWkt( ppszWKT );
1687         }
1688         else if( EQUAL(papszTok[0],"Units")
1689                  && CSLCount(papszTok) > 1
1690                  && EQUAL(papszTok[1],"degree") )
1691         {
1692             /*
1693             ** If we have units of "degree", but a projected coordinate
1694             ** system we need to convert it to geographic.  See to01_02.TAB.
1695             */
1696             if( ppszWKT != nullptr && *ppszWKT != nullptr
1697                 && STARTS_WITH_CI(*ppszWKT, "PROJCS") )
1698             {
1699                 OGRSpatialReference oSRS;
1700                 oSRS.importFromWkt( *ppszWKT );
1701 
1702                 OGRSpatialReference oSRSGeogCS;
1703                 oSRSGeogCS.CopyGeogCSFrom( &oSRS );
1704                 CPLFree( *ppszWKT );
1705 
1706                 oSRSGeogCS.exportToWkt( ppszWKT );
1707             }
1708         }
1709     }
1710 
1711     CSLDestroy(papszTok);
1712     CSLDestroy(papszLines);
1713 
1714     if( nCoordinateCount == 0 )
1715     {
1716         CPLDebug( "GDAL", "GDALLoadTabFile(%s) did not get any GCPs.",
1717                   pszFilename );
1718         return FALSE;
1719     }
1720 
1721 /* -------------------------------------------------------------------- */
1722 /*      Try to convert the GCPs into a geotransform definition, if      */
1723 /*      possible.  Otherwise we will need to use them as GCPs.          */
1724 /* -------------------------------------------------------------------- */
1725     if( !GDALGCPsToGeoTransform(
1726             nCoordinateCount, asGCPs, padfGeoTransform,
1727             CPLTestBool(CPLGetConfigOption("TAB_APPROX_GEOTRANSFORM", "NO")) ) )
1728     {
1729         if (pnGCPCount && ppasGCPs)
1730         {
1731             CPLDebug( "GDAL",
1732                 "GDALLoadTabFile(%s) found file, was not able to derive a "
1733                 "first order geotransform.  Using points as GCPs.",
1734                 pszFilename );
1735 
1736             *ppasGCPs = static_cast<GDAL_GCP *>(
1737                 CPLCalloc( sizeof(GDAL_GCP), nCoordinateCount ) );
1738             memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1739             *pnGCPCount = nCoordinateCount;
1740         }
1741     }
1742     else
1743     {
1744         GDALDeinitGCPs( nCoordinateCount, asGCPs );
1745     }
1746 
1747     return TRUE;
1748 }
1749 
1750 /************************************************************************/
1751 /*                         GDALReadTabFile()                            */
1752 /************************************************************************/
1753 
1754 /** Helper function for translator implementer wanting support for MapInfo
1755  * .tab files.
1756  *
1757  * @param pszBaseFilename filename whose basename will help building the .tab filename.
1758  * @param padfGeoTransform output geotransform. Must hold 6 doubles.
1759  * @param ppszWKT output pointer to a string that will be allocated with CPLMalloc().
1760  * @param pnGCPCount output pointer to GCP count.
1761  * @param ppasGCPs outputer pointer to an array of GCPs.
1762  * @return TRUE in case of success, FALSE otherwise.
1763  */
GDALReadTabFile(const char * pszBaseFilename,double * padfGeoTransform,char ** ppszWKT,int * pnGCPCount,GDAL_GCP ** ppasGCPs)1764 int CPL_STDCALL GDALReadTabFile( const char * pszBaseFilename,
1765                                  double *padfGeoTransform, char **ppszWKT,
1766                                  int *pnGCPCount, GDAL_GCP **ppasGCPs )
1767 
1768 {
1769     return GDALReadTabFile2( pszBaseFilename, padfGeoTransform,
1770                              ppszWKT, pnGCPCount, ppasGCPs,
1771                              nullptr, nullptr );
1772 }
1773 
GDALReadTabFile2(const char * pszBaseFilename,double * padfGeoTransform,char ** ppszWKT,int * pnGCPCount,GDAL_GCP ** ppasGCPs,char ** papszSiblingFiles,char ** ppszTabFileNameOut)1774 int GDALReadTabFile2( const char * pszBaseFilename,
1775                       double *padfGeoTransform, char **ppszWKT,
1776                       int *pnGCPCount, GDAL_GCP **ppasGCPs,
1777                       char** papszSiblingFiles, char** ppszTabFileNameOut )
1778 {
1779     if (ppszTabFileNameOut)
1780         *ppszTabFileNameOut = nullptr;
1781 
1782     if( !GDALCanFileAcceptSidecarFile(pszBaseFilename) )
1783         return FALSE;
1784 
1785     const char *pszTAB = CPLResetExtension( pszBaseFilename, "tab" );
1786 
1787     if (papszSiblingFiles && GDALCanReliablyUseSiblingFileList(pszTAB))
1788     {
1789         int iSibling = CSLFindString(papszSiblingFiles, CPLGetFilename(pszTAB));
1790         if (iSibling >= 0)
1791         {
1792             CPLString osTabFilename = pszBaseFilename;
1793             osTabFilename.resize(strlen(pszBaseFilename) -
1794                                  strlen(CPLGetFilename(pszBaseFilename)));
1795             osTabFilename += papszSiblingFiles[iSibling];
1796             if ( GDALLoadTabFile(osTabFilename, padfGeoTransform, ppszWKT,
1797                                  pnGCPCount, ppasGCPs ) )
1798             {
1799                 if (ppszTabFileNameOut)
1800                     *ppszTabFileNameOut = CPLStrdup(osTabFilename);
1801                 return TRUE;
1802             }
1803         }
1804         return FALSE;
1805     }
1806 
1807 /* -------------------------------------------------------------------- */
1808 /*      Try lower case, then upper case.                                */
1809 /* -------------------------------------------------------------------- */
1810 
1811     VSILFILE *fpTAB = VSIFOpenL( pszTAB, "rt" );
1812 
1813     if( fpTAB == nullptr && VSIIsCaseSensitiveFS(pszTAB) )
1814     {
1815         pszTAB = CPLResetExtension( pszBaseFilename, "TAB" );
1816         fpTAB = VSIFOpenL( pszTAB, "rt" );
1817     }
1818 
1819     if( fpTAB == nullptr )
1820         return FALSE;
1821 
1822     CPL_IGNORE_RET_VAL(VSIFCloseL( fpTAB ));
1823 
1824 /* -------------------------------------------------------------------- */
1825 /*      We found the file, now load and parse it.                       */
1826 /* -------------------------------------------------------------------- */
1827     if (GDALLoadTabFile( pszTAB, padfGeoTransform, ppszWKT,
1828                          pnGCPCount, ppasGCPs ) )
1829     {
1830         if (ppszTabFileNameOut)
1831             *ppszTabFileNameOut = CPLStrdup(pszTAB);
1832         return TRUE;
1833     }
1834     return FALSE;
1835 }
1836 
1837 /************************************************************************/
1838 /*                         GDALLoadWorldFile()                          */
1839 /************************************************************************/
1840 
1841 /**
1842  * \brief Read ESRI world file.
1843  *
1844  * This function reads an ESRI style world file, and formats a geotransform
1845  * from its contents.
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 pszFilename the world file name.
1860  * @param padfGeoTransform the six double array into which the
1861  * geotransformation should be placed.
1862  *
1863  * @return TRUE on success or FALSE on failure.
1864  */
1865 
1866 int CPL_STDCALL
GDALLoadWorldFile(const char * pszFilename,double * padfGeoTransform)1867 GDALLoadWorldFile( const char *pszFilename, double *padfGeoTransform )
1868 
1869 {
1870     VALIDATE_POINTER1( pszFilename, "GDALLoadWorldFile", FALSE );
1871     VALIDATE_POINTER1( padfGeoTransform, "GDALLoadWorldFile", FALSE );
1872 
1873     char **papszLines = CSLLoad2( pszFilename, 100, 100, nullptr );
1874 
1875     if ( !papszLines )
1876         return FALSE;
1877 
1878     double world[6] = { 0.0 };
1879     // reads the first 6 non-empty lines
1880     int nLines = 0;
1881     const int nLinesCount = CSLCount(papszLines);
1882     for( int i = 0;
1883          i < nLinesCount && nLines < static_cast<int>(CPL_ARRAYSIZE(world));
1884          ++i )
1885     {
1886         CPLString line(papszLines[i]);
1887         if( line.Trim().empty() )
1888           continue;
1889 
1890         world[nLines] = CPLAtofM(line);
1891         ++nLines;
1892     }
1893 
1894     if( nLines == 6
1895         && (world[0] != 0.0 || world[2] != 0.0)
1896         && (world[3] != 0.0 || world[1] != 0.0) )
1897     {
1898         padfGeoTransform[0] = world[4];
1899         padfGeoTransform[1] = world[0];
1900         padfGeoTransform[2] = world[2];
1901         padfGeoTransform[3] = world[5];
1902         padfGeoTransform[4] = world[1];
1903         padfGeoTransform[5] = world[3];
1904 
1905         // correct for center of pixel vs. top left of pixel
1906         padfGeoTransform[0] -= 0.5 * padfGeoTransform[1];
1907         padfGeoTransform[0] -= 0.5 * padfGeoTransform[2];
1908         padfGeoTransform[3] -= 0.5 * padfGeoTransform[4];
1909         padfGeoTransform[3] -= 0.5 * padfGeoTransform[5];
1910 
1911         CSLDestroy(papszLines);
1912 
1913         return TRUE;
1914     }
1915     else
1916     {
1917         CPLDebug( "GDAL",
1918                   "GDALLoadWorldFile(%s) found file, but it was corrupt.",
1919                   pszFilename );
1920         CSLDestroy(papszLines);
1921         return FALSE;
1922     }
1923 }
1924 
1925 /************************************************************************/
1926 /*                         GDALReadWorldFile()                          */
1927 /************************************************************************/
1928 
1929 /**
1930  * \brief Read ESRI world file.
1931  *
1932  * This function reads an ESRI style world file, and formats a geotransform
1933  * from its contents.  It does the same as GDALLoadWorldFile() function, but
1934  * it will form the filename for the worldfile from the filename of the raster
1935  * file referred and the suggested extension.  If no extension is provided,
1936  * the code will internally try the unix style and windows style world file
1937  * extensions (eg. for .tif these would be .tfw and .tifw).
1938  *
1939  * The world file contains an affine transformation with the parameters
1940  * in a different order than in a geotransform array.
1941  *
1942  * <ul>
1943  * <li> geotransform[1] : width of pixel
1944  * <li> geotransform[4] : rotational coefficient, zero for north up images.
1945  * <li> geotransform[2] : rotational coefficient, zero for north up images.
1946  * <li> geotransform[5] : height of pixel (but negative)
1947  * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1948  * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1949  * </ul>
1950  *
1951  * @param pszBaseFilename the target raster file.
1952  * @param pszExtension the extension to use (i.e. "wld") or NULL to derive it
1953  * from the pszBaseFilename
1954  * @param padfGeoTransform the six double array into which the
1955  * geotransformation should be placed.
1956  *
1957  * @return TRUE on success or FALSE on failure.
1958  */
1959 
1960 int CPL_STDCALL
GDALReadWorldFile(const char * pszBaseFilename,const char * pszExtension,double * padfGeoTransform)1961 GDALReadWorldFile( const char *pszBaseFilename, const char *pszExtension,
1962                    double *padfGeoTransform )
1963 
1964 {
1965     return GDALReadWorldFile2( pszBaseFilename, pszExtension,
1966                                padfGeoTransform, nullptr, nullptr );
1967 }
1968 
GDALReadWorldFile2(const char * pszBaseFilename,const char * pszExtension,double * padfGeoTransform,char ** papszSiblingFiles,char ** ppszWorldFileNameOut)1969 int GDALReadWorldFile2( const char *pszBaseFilename, const char *pszExtension,
1970                         double *padfGeoTransform, char** papszSiblingFiles,
1971                         char** ppszWorldFileNameOut )
1972 {
1973     VALIDATE_POINTER1( pszBaseFilename, "GDALReadWorldFile", FALSE );
1974     VALIDATE_POINTER1( padfGeoTransform, "GDALReadWorldFile", FALSE );
1975 
1976     if (ppszWorldFileNameOut)
1977         *ppszWorldFileNameOut = nullptr;
1978 
1979     if( !GDALCanFileAcceptSidecarFile(pszBaseFilename) )
1980         return FALSE;
1981 
1982 /* -------------------------------------------------------------------- */
1983 /*      If we aren't given an extension, try both the unix and          */
1984 /*      windows style extensions.                                       */
1985 /* -------------------------------------------------------------------- */
1986     if( pszExtension == nullptr )
1987     {
1988         const std::string oBaseExt = CPLGetExtension( pszBaseFilename );
1989 
1990         if( oBaseExt.length() < 2 )
1991             return FALSE;
1992 
1993         // windows version - first + last + 'w'
1994         char szDerivedExtension[100] = { '\0' };
1995         szDerivedExtension[0] = oBaseExt[0];
1996         szDerivedExtension[1] = oBaseExt[oBaseExt.length()-1];
1997         szDerivedExtension[2] = 'w';
1998         szDerivedExtension[3] = '\0';
1999 
2000         if( GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
2001                                 padfGeoTransform, papszSiblingFiles,
2002                                 ppszWorldFileNameOut ) )
2003             return TRUE;
2004 
2005         // unix version - extension + 'w'
2006         if( oBaseExt.length() > sizeof(szDerivedExtension)-2 )
2007             return FALSE;
2008 
2009         snprintf( szDerivedExtension, sizeof(szDerivedExtension),
2010                   "%sw", oBaseExt.c_str() );
2011         return GDALReadWorldFile2( pszBaseFilename, szDerivedExtension,
2012                                    padfGeoTransform, papszSiblingFiles,
2013                                    ppszWorldFileNameOut );
2014     }
2015 
2016 /* -------------------------------------------------------------------- */
2017 /*      Skip the leading period in the extension if there is one.       */
2018 /* -------------------------------------------------------------------- */
2019     if( *pszExtension == '.' )
2020         pszExtension++;
2021 
2022 /* -------------------------------------------------------------------- */
2023 /*      Generate upper and lower case versions of the extension.        */
2024 /* -------------------------------------------------------------------- */
2025     char szExtUpper[32] = { '\0' };
2026     char szExtLower[32] = { '\0' };
2027     CPLStrlcpy( szExtUpper, pszExtension, sizeof(szExtUpper) );
2028     CPLStrlcpy( szExtLower, pszExtension, sizeof(szExtLower) );
2029 
2030     for( int i = 0; szExtUpper[i] != '\0'; i++ )
2031     {
2032         szExtUpper[i] = static_cast<char>( toupper(szExtUpper[i]) );
2033         szExtLower[i] = static_cast<char>( tolower(szExtLower[i]) );
2034     }
2035 
2036     const char *pszTFW = CPLResetExtension( pszBaseFilename, szExtLower );
2037 
2038     if (papszSiblingFiles && GDALCanReliablyUseSiblingFileList(pszTFW))
2039     {
2040         const int iSibling =
2041             CSLFindString(papszSiblingFiles, CPLGetFilename(pszTFW));
2042         if (iSibling >= 0)
2043         {
2044             CPLString osTFWFilename = pszBaseFilename;
2045             osTFWFilename.resize(strlen(pszBaseFilename) -
2046                                  strlen(CPLGetFilename(pszBaseFilename)));
2047             osTFWFilename += papszSiblingFiles[iSibling];
2048             if (GDALLoadWorldFile( osTFWFilename, padfGeoTransform ))
2049             {
2050                 if (ppszWorldFileNameOut)
2051                     *ppszWorldFileNameOut = CPLStrdup(osTFWFilename);
2052                 return TRUE;
2053             }
2054         }
2055         return FALSE;
2056     }
2057 
2058 /* -------------------------------------------------------------------- */
2059 /*      Try lower case, then upper case.                                */
2060 /* -------------------------------------------------------------------- */
2061 
2062     VSIStatBufL sStatBuf;
2063     bool bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
2064 
2065     if( !bGotTFW  && VSIIsCaseSensitiveFS(pszTFW) )
2066     {
2067         pszTFW = CPLResetExtension( pszBaseFilename, szExtUpper );
2068         bGotTFW = VSIStatExL( pszTFW, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0;
2069     }
2070 
2071     if( !bGotTFW )
2072         return FALSE;
2073 
2074 /* -------------------------------------------------------------------- */
2075 /*      We found the file, now load and parse it.                       */
2076 /* -------------------------------------------------------------------- */
2077     if (GDALLoadWorldFile( pszTFW, padfGeoTransform ))
2078     {
2079         if (ppszWorldFileNameOut)
2080             *ppszWorldFileNameOut = CPLStrdup(pszTFW);
2081         return TRUE;
2082     }
2083     return FALSE;
2084 }
2085 
2086 /************************************************************************/
2087 /*                         GDALWriteWorldFile()                         */
2088 /*                                                                      */
2089 /*      Helper function for translator implementer wanting              */
2090 /*      support for ESRI world files.                                   */
2091 /************************************************************************/
2092 
2093 /**
2094  * \brief Write ESRI world file.
2095  *
2096  * This function writes an ESRI style world file from the passed geotransform.
2097  *
2098  * The world file contains an affine transformation with the parameters
2099  * in a different order than in a geotransform array.
2100  *
2101  * <ul>
2102  * <li> geotransform[1] : width of pixel
2103  * <li> geotransform[4] : rotational coefficient, zero for north up images.
2104  * <li> geotransform[2] : rotational coefficient, zero for north up images.
2105  * <li> geotransform[5] : height of pixel (but negative)
2106  * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
2107  * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
2108  * </ul>
2109  *
2110  * @param pszBaseFilename the target raster file.
2111  * @param pszExtension the extension to use (i.e. "wld"). Must not be NULL
2112  * @param padfGeoTransform the six double array from which the
2113  * geotransformation should be read.
2114  *
2115  * @return TRUE on success or FALSE on failure.
2116  */
2117 
2118 int CPL_STDCALL
GDALWriteWorldFile(const char * pszBaseFilename,const char * pszExtension,double * padfGeoTransform)2119 GDALWriteWorldFile( const char * pszBaseFilename, const char *pszExtension,
2120                     double *padfGeoTransform )
2121 
2122 {
2123     VALIDATE_POINTER1( pszBaseFilename, "GDALWriteWorldFile", FALSE );
2124     VALIDATE_POINTER1( pszExtension, "GDALWriteWorldFile", FALSE );
2125     VALIDATE_POINTER1( padfGeoTransform, "GDALWriteWorldFile", FALSE );
2126 
2127 /* -------------------------------------------------------------------- */
2128 /*      Prepare the text to write to the file.                          */
2129 /* -------------------------------------------------------------------- */
2130     CPLString osTFWText;
2131 
2132     osTFWText.Printf( "%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n",
2133                       padfGeoTransform[1],
2134                       padfGeoTransform[4],
2135                       padfGeoTransform[2],
2136                       padfGeoTransform[5],
2137                       padfGeoTransform[0]
2138                       + 0.5 * padfGeoTransform[1]
2139                       + 0.5 * padfGeoTransform[2],
2140                       padfGeoTransform[3]
2141                       + 0.5 * padfGeoTransform[4]
2142                       + 0.5 * padfGeoTransform[5] );
2143 
2144 /* -------------------------------------------------------------------- */
2145 /*      Update extension, and write to disk.                            */
2146 /* -------------------------------------------------------------------- */
2147     const char *pszTFW = CPLResetExtension( pszBaseFilename, pszExtension );
2148     VSILFILE * const fpTFW = VSIFOpenL( pszTFW, "wt" );
2149     if( fpTFW == nullptr )
2150         return FALSE;
2151 
2152     const int bRet =
2153         VSIFWriteL( osTFWText.c_str(), osTFWText.size(), 1, fpTFW )
2154         == 1;
2155     if( VSIFCloseL( fpTFW ) != 0 )
2156         return FALSE;
2157 
2158     return bRet;
2159 }
2160 
2161 /************************************************************************/
2162 /*                          GDALVersionInfo()                           */
2163 /************************************************************************/
2164 
2165 /**
2166  * \brief Get runtime version information.
2167  *
2168  * Available pszRequest values:
2169  * <ul>
2170  * <li> "VERSION_NUM": Returns GDAL_VERSION_NUM formatted as a string.  i.e. "1170"
2171  *      Note: starting with GDAL 1.10, this string will be longer than 4 characters.
2172  * <li> "RELEASE_DATE": Returns GDAL_RELEASE_DATE formatted as a string.
2173  * i.e. "20020416".
2174  * <li> "RELEASE_NAME": Returns the GDAL_RELEASE_NAME. ie. "1.1.7"
2175  * <li> "--version": Returns one line version message suitable for use in
2176  * response to --version requests.  i.e. "GDAL 1.1.7, released 2002/04/16"
2177  * <li> "LICENSE": Returns the content of the LICENSE.TXT file from the GDAL_DATA directory.
2178  *      Before GDAL 1.7.0, the returned string was leaking memory but this is now resolved.
2179  *      So the result should not been freed by the caller.
2180  * <li> "BUILD_INFO": List of NAME=VALUE pairs separated by newlines with
2181  * information on build time options.
2182  * </ul>
2183  *
2184  * @param pszRequest the type of version info desired, as listed above.
2185  *
2186  * @return an internal string containing the requested information.
2187  */
2188 
GDALVersionInfo(const char * pszRequest)2189 const char * CPL_STDCALL GDALVersionInfo( const char *pszRequest )
2190 
2191 {
2192 /* -------------------------------------------------------------------- */
2193 /*      Try to capture as much build information as practical.          */
2194 /* -------------------------------------------------------------------- */
2195     if( pszRequest != nullptr && EQUAL(pszRequest,"BUILD_INFO") )
2196     {
2197         CPLString osBuildInfo;
2198 
2199 #ifdef ESRI_BUILD
2200         osBuildInfo += "ESRI_BUILD=YES\n";
2201 #endif
2202 #ifdef PAM_ENABLED
2203         osBuildInfo += "PAM_ENABLED=YES\n";
2204 #endif
2205         osBuildInfo += "OGR_ENABLED=YES\n";  // Deprecated.  Always yes.
2206 #ifdef HAVE_GEOS
2207         osBuildInfo += "GEOS_ENABLED=YES\n";
2208 #ifdef GEOS_CAPI_VERSION
2209         osBuildInfo += CPLString("GEOS_VERSION=") + GEOS_CAPI_VERSION + "\n";
2210 #endif
2211 #endif
2212         CPLFree(CPLGetTLS(CTLS_VERSIONINFO));
2213         CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osBuildInfo), TRUE );
2214         return static_cast<char *>( CPLGetTLS(CTLS_VERSIONINFO) );
2215     }
2216 
2217 /* -------------------------------------------------------------------- */
2218 /*      LICENSE is a special case. We try to find and read the          */
2219 /*      LICENSE.TXT file from the GDAL_DATA directory and return it     */
2220 /* -------------------------------------------------------------------- */
2221     if( pszRequest != nullptr && EQUAL(pszRequest,"LICENSE") )
2222     {
2223         char* pszResultLicence = reinterpret_cast<char *>(
2224             CPLGetTLS( CTLS_VERSIONINFO_LICENCE ) );
2225         if( pszResultLicence != nullptr )
2226         {
2227             return pszResultLicence;
2228         }
2229 
2230         const char *pszFilename = CPLFindFile( "etc", "LICENSE.TXT" );
2231         VSILFILE *fp = nullptr;
2232 
2233         if( pszFilename != nullptr )
2234             fp = VSIFOpenL( pszFilename, "r" );
2235 
2236         if( fp != nullptr )
2237         {
2238             if( VSIFSeekL( fp, 0, SEEK_END ) == 0 )
2239             {
2240                 // TODO(schwehr): Handle if VSITellL returns a value too large
2241                 // for size_t.
2242                 const size_t nLength =
2243                     static_cast<size_t>( VSIFTellL( fp ) + 1 );
2244                 if( VSIFSeekL( fp, SEEK_SET, 0 ) == 0 )
2245                 {
2246                     pszResultLicence = static_cast<char *>(
2247                         VSICalloc(1, nLength) );
2248                     if (pszResultLicence)
2249                         CPL_IGNORE_RET_VAL(
2250                             VSIFReadL( pszResultLicence, 1, nLength - 1, fp ) );
2251                 }
2252             }
2253 
2254             CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2255         }
2256 
2257         if (!pszResultLicence)
2258         {
2259             pszResultLicence = CPLStrdup(
2260                      "GDAL/OGR is released under the MIT/X license.\n"
2261                      "The LICENSE.TXT distributed with GDAL/OGR should\n"
2262                      "contain additional details.\n" );
2263         }
2264 
2265         CPLSetTLS( CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE );
2266         return pszResultLicence;
2267     }
2268 
2269 /* -------------------------------------------------------------------- */
2270 /*      All other strings are fairly small.                             */
2271 /* -------------------------------------------------------------------- */
2272     CPLString osVersionInfo;
2273 
2274     if( pszRequest == nullptr || EQUAL(pszRequest,"VERSION_NUM") )
2275         osVersionInfo.Printf( "%d", GDAL_VERSION_NUM );
2276     else if( EQUAL(pszRequest,"RELEASE_DATE") )
2277         osVersionInfo.Printf( "%d", GDAL_RELEASE_DATE );
2278     else if( EQUAL(pszRequest,"RELEASE_NAME") )
2279         osVersionInfo.Printf( GDAL_RELEASE_NAME );
2280     else // --version
2281         osVersionInfo.Printf( "GDAL %s, released %d/%02d/%02d",
2282                               GDAL_RELEASE_NAME,
2283                               GDAL_RELEASE_DATE / 10000,
2284                               (GDAL_RELEASE_DATE % 10000) / 100,
2285                               GDAL_RELEASE_DATE % 100 );
2286 
2287     CPLFree(CPLGetTLS(CTLS_VERSIONINFO)); // clear old value.
2288     CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osVersionInfo), TRUE );
2289     return static_cast<char *>( CPLGetTLS(CTLS_VERSIONINFO) );
2290 }
2291 
2292 /************************************************************************/
2293 /*                         GDALCheckVersion()                           */
2294 /************************************************************************/
2295 
2296 /** Return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor.
2297 
2298     The purpose of this method is to ensure that calling code will run
2299     with the GDAL version it is compiled for. It is primarily intended
2300     for external plugins.
2301 
2302     @param nVersionMajor Major version to be tested against
2303     @param nVersionMinor Minor version to be tested against
2304     @param pszCallingComponentName If not NULL, in case of version mismatch, the method
2305                                    will issue a failure mentioning the name of
2306                                    the calling component.
2307 
2308     @return TRUE if GDAL library version at runtime matches
2309     nVersionMajor.nVersionMinor, FALSE otherwise.
2310   */
GDALCheckVersion(int nVersionMajor,int nVersionMinor,const char * pszCallingComponentName)2311 int CPL_STDCALL GDALCheckVersion( int nVersionMajor, int nVersionMinor,
2312                                   const char* pszCallingComponentName)
2313 {
2314     if (nVersionMajor == GDAL_VERSION_MAJOR &&
2315         nVersionMinor == GDAL_VERSION_MINOR)
2316         return TRUE;
2317 
2318     if (pszCallingComponentName)
2319     {
2320         CPLError( CE_Failure, CPLE_AppDefined,
2321                   "%s was compiled against GDAL %d.%d, but "
2322                   "the current library version is %d.%d",
2323                   pszCallingComponentName, nVersionMajor, nVersionMinor,
2324                   GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
2325     }
2326     return FALSE;
2327 }
2328 
2329 /************************************************************************/
2330 /*                            GDALDecToDMS()                            */
2331 /************************************************************************/
2332 
2333 /** Translate a decimal degrees value to a DMS string with hemisphere.
2334  */
GDALDecToDMS(double dfAngle,const char * pszAxis,int nPrecision)2335 const char * CPL_STDCALL GDALDecToDMS( double dfAngle, const char * pszAxis,
2336                           int nPrecision )
2337 
2338 {
2339     return CPLDecToDMS( dfAngle, pszAxis, nPrecision );
2340 }
2341 
2342 /************************************************************************/
2343 /*                         GDALPackedDMSToDec()                         */
2344 /************************************************************************/
2345 
2346 /**
2347  * \brief Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
2348  *
2349  * See CPLPackedDMSToDec().
2350  */
2351 
GDALPackedDMSToDec(double dfPacked)2352 double CPL_STDCALL GDALPackedDMSToDec( double dfPacked )
2353 
2354 {
2355     return CPLPackedDMSToDec( dfPacked );
2356 }
2357 
2358 /************************************************************************/
2359 /*                         GDALDecToPackedDMS()                         */
2360 /************************************************************************/
2361 
2362 /**
2363  * \brief Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
2364  *
2365  * See CPLDecToPackedDMS().
2366  */
2367 
GDALDecToPackedDMS(double dfDec)2368 double CPL_STDCALL GDALDecToPackedDMS( double dfDec )
2369 
2370 {
2371     return CPLDecToPackedDMS( dfDec );
2372 }
2373 
2374 /************************************************************************/
2375 /*                       GDALGCPsToGeoTransform()                       */
2376 /************************************************************************/
2377 
2378 /**
2379  * \brief Generate Geotransform from GCPs.
2380  *
2381  * Given a set of GCPs perform first order fit as a geotransform.
2382  *
2383  * Due to imprecision in the calculations the fit algorithm will often
2384  * return non-zero rotational coefficients even if given perfectly non-rotated
2385  * inputs.  A special case has been implemented for corner corner coordinates
2386  * given in TL, TR, BR, BL order.  So when using this to get a geotransform
2387  * from 4 corner coordinates, pass them in this order.
2388  *
2389  * Starting with GDAL 2.2.2, if bApproxOK = FALSE, the
2390  * GDAL_GCPS_TO_GEOTRANSFORM_APPROX_OK configuration option will be read. If
2391  * set to YES, then bApproxOK will be overridden with TRUE.
2392  * Starting with GDAL 2.2.2, when exact fit is asked, the
2393  * GDAL_GCPS_TO_GEOTRANSFORM_APPROX_THRESHOLD configuration option can be set to
2394  * give the maximum error threshold in pixel. The default is 0.25.
2395  *
2396  * @param nGCPCount the number of GCPs being passed in.
2397  * @param pasGCPs the list of GCP structures.
2398  * @param padfGeoTransform the six double array in which the affine
2399  * geotransformation will be returned.
2400  * @param bApproxOK If FALSE the function will fail if the geotransform is not
2401  * essentially an exact fit (within 0.25 pixel) for all GCPs.
2402  *
2403  * @return TRUE on success or FALSE if there aren't enough points to prepare a
2404  * geotransform, the pointers are ill-determined or if bApproxOK is FALSE
2405  * and the fit is poor.
2406  */
2407 
2408 // TODO(schwehr): Add consts to args.
2409 int CPL_STDCALL
GDALGCPsToGeoTransform(int nGCPCount,const GDAL_GCP * pasGCPs,double * padfGeoTransform,int bApproxOK)2410 GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
2411                         double *padfGeoTransform, int bApproxOK )
2412 
2413 {
2414     double dfPixelThreshold = 0.25;
2415     if( !bApproxOK )
2416     {
2417         bApproxOK =
2418             CPLTestBool(CPLGetConfigOption(
2419                             "GDAL_GCPS_TO_GEOTRANSFORM_APPROX_OK", "NO"));
2420         if( !bApproxOK )
2421         {
2422             // coverity[tainted_data]
2423             dfPixelThreshold =
2424                 CPLAtof(CPLGetConfigOption(
2425                     "GDAL_GCPS_TO_GEOTRANSFORM_APPROX_THRESHOLD", "0.25"));
2426         }
2427     }
2428 
2429 /* -------------------------------------------------------------------- */
2430 /*      Recognise a few special cases.                                  */
2431 /* -------------------------------------------------------------------- */
2432     if( nGCPCount < 2 )
2433         return FALSE;
2434 
2435     if( nGCPCount == 2 )
2436     {
2437         if( pasGCPs[1].dfGCPPixel == pasGCPs[0].dfGCPPixel
2438             || pasGCPs[1].dfGCPLine == pasGCPs[0].dfGCPLine )
2439             return FALSE;
2440 
2441         padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2442             / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2443         padfGeoTransform[2] = 0.0;
2444 
2445         padfGeoTransform[4] = 0.0;
2446         padfGeoTransform[5] = (pasGCPs[1].dfGCPY - pasGCPs[0].dfGCPY)
2447             / (pasGCPs[1].dfGCPLine - pasGCPs[0].dfGCPLine);
2448 
2449         padfGeoTransform[0] = pasGCPs[0].dfGCPX
2450             - pasGCPs[0].dfGCPPixel * padfGeoTransform[1]
2451             - pasGCPs[0].dfGCPLine * padfGeoTransform[2];
2452 
2453         padfGeoTransform[3] = pasGCPs[0].dfGCPY
2454             - pasGCPs[0].dfGCPPixel * padfGeoTransform[4]
2455             - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2456 
2457         return TRUE;
2458     }
2459 
2460 /* -------------------------------------------------------------------- */
2461 /*      Special case of 4 corner coordinates of a non-rotated           */
2462 /*      image.  The points must be in TL-TR-BR-BL order for now.        */
2463 /*      This case helps avoid some imprecision in the general           */
2464 /*      calculations.                                                   */
2465 /* -------------------------------------------------------------------- */
2466     if( nGCPCount == 4
2467         && pasGCPs[0].dfGCPLine == pasGCPs[1].dfGCPLine
2468         && pasGCPs[2].dfGCPLine == pasGCPs[3].dfGCPLine
2469         && pasGCPs[0].dfGCPPixel == pasGCPs[3].dfGCPPixel
2470         && pasGCPs[1].dfGCPPixel == pasGCPs[2].dfGCPPixel
2471         && pasGCPs[0].dfGCPLine != pasGCPs[2].dfGCPLine
2472         && pasGCPs[0].dfGCPPixel != pasGCPs[1].dfGCPPixel
2473         && pasGCPs[0].dfGCPY == pasGCPs[1].dfGCPY
2474         && pasGCPs[2].dfGCPY == pasGCPs[3].dfGCPY
2475         && pasGCPs[0].dfGCPX == pasGCPs[3].dfGCPX
2476         && pasGCPs[1].dfGCPX == pasGCPs[2].dfGCPX
2477         && pasGCPs[0].dfGCPY != pasGCPs[2].dfGCPY
2478         && pasGCPs[0].dfGCPX != pasGCPs[1].dfGCPX )
2479     {
2480         padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
2481             / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
2482         padfGeoTransform[2] = 0.0;
2483         padfGeoTransform[4] = 0.0;
2484         padfGeoTransform[5] = (pasGCPs[2].dfGCPY - pasGCPs[1].dfGCPY)
2485             / (pasGCPs[2].dfGCPLine - pasGCPs[1].dfGCPLine);
2486 
2487         padfGeoTransform[0] =
2488             pasGCPs[0].dfGCPX - pasGCPs[0].dfGCPPixel * padfGeoTransform[1];
2489         padfGeoTransform[3] =
2490             pasGCPs[0].dfGCPY - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
2491         return TRUE;
2492     }
2493 
2494 /* -------------------------------------------------------------------- */
2495 /*      Compute source and destination ranges so we can normalize       */
2496 /*      the values to make the least squares computation more stable.   */
2497 /* -------------------------------------------------------------------- */
2498     double min_pixel = pasGCPs[0].dfGCPPixel;
2499     double max_pixel = pasGCPs[0].dfGCPPixel;
2500     double min_line = pasGCPs[0].dfGCPLine;
2501     double max_line = pasGCPs[0].dfGCPLine;
2502     double min_geox = pasGCPs[0].dfGCPX;
2503     double max_geox = pasGCPs[0].dfGCPX;
2504     double min_geoy = pasGCPs[0].dfGCPY;
2505     double max_geoy = pasGCPs[0].dfGCPY;
2506 
2507     for( int i = 1; i < nGCPCount; ++i ) {
2508         min_pixel = std::min(min_pixel, pasGCPs[i].dfGCPPixel);
2509         max_pixel = std::max(max_pixel, pasGCPs[i].dfGCPPixel);
2510         min_line = std::min(min_line, pasGCPs[i].dfGCPLine);
2511         max_line = std::max(max_line, pasGCPs[i].dfGCPLine);
2512         min_geox = std::min(min_geox, pasGCPs[i].dfGCPX);
2513         max_geox = std::max(max_geox, pasGCPs[i].dfGCPX);
2514         min_geoy = std::min(min_geoy, pasGCPs[i].dfGCPY);
2515         max_geoy = std::max(max_geoy, pasGCPs[i].dfGCPY);
2516     }
2517 
2518     double EPS = 1.0e-12;
2519 
2520     if( std::abs(max_pixel - min_pixel) < EPS
2521         || std::abs(max_line - min_line) < EPS
2522         || std::abs(max_geox - min_geox) < EPS
2523         || std::abs(max_geoy - min_geoy) < EPS)
2524     {
2525         return FALSE;  // degenerate in at least one dimension.
2526     }
2527 
2528     double pl_normalize[6], geo_normalize[6];
2529 
2530     pl_normalize[0] = -min_pixel / (max_pixel - min_pixel);
2531     pl_normalize[1] = 1.0 / (max_pixel - min_pixel);
2532     pl_normalize[2] = 0.0;
2533     pl_normalize[3] = -min_line / (max_line - min_line);
2534     pl_normalize[4] = 0.0;
2535     pl_normalize[5] = 1.0 / (max_line - min_line);
2536 
2537     geo_normalize[0] = -min_geox / (max_geox - min_geox);
2538     geo_normalize[1] = 1.0 / (max_geox - min_geox);
2539     geo_normalize[2] = 0.0;
2540     geo_normalize[3] = -min_geoy / (max_geoy - min_geoy);
2541     geo_normalize[4] = 0.0;
2542     geo_normalize[5] = 1.0 / (max_geoy - min_geoy);
2543 
2544 /* -------------------------------------------------------------------- */
2545 /* In the general case, do a least squares error approximation by       */
2546 /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum          */
2547 /* -------------------------------------------------------------------- */
2548 
2549     double sum_x = 0.0;
2550     double sum_y = 0.0;
2551     double sum_xy = 0.0;
2552     double sum_xx = 0.0;
2553     double sum_yy = 0.0;
2554     double sum_Lon = 0.0;
2555     double sum_Lonx = 0.0;
2556     double sum_Lony = 0.0;
2557     double sum_Lat = 0.0;
2558     double sum_Latx = 0.0;
2559     double sum_Laty = 0.0;
2560 
2561     for ( int i = 0; i < nGCPCount; ++i ) {
2562         double pixel, line, geox, geoy;
2563 
2564         GDALApplyGeoTransform(pl_normalize,
2565                               pasGCPs[i].dfGCPPixel,
2566                               pasGCPs[i].dfGCPLine,
2567                               &pixel, &line);
2568         GDALApplyGeoTransform(geo_normalize,
2569                               pasGCPs[i].dfGCPX,
2570                               pasGCPs[i].dfGCPY,
2571                               &geox, &geoy);
2572 
2573         sum_x += pixel;
2574         sum_y += line;
2575         sum_xy += pixel * line;
2576         sum_xx += pixel * pixel;
2577         sum_yy += line * line;
2578         sum_Lon += geox;
2579         sum_Lonx += geox * pixel;
2580         sum_Lony += geox * line;
2581         sum_Lat += geoy;
2582         sum_Latx += geoy * pixel;
2583         sum_Laty += geoy * line;
2584     }
2585 
2586     const double divisor =
2587         nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy)
2588         + 2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx
2589         - sum_x * sum_x * sum_yy;
2590 
2591 /* -------------------------------------------------------------------- */
2592 /*      If the divisor is zero, there is no valid solution.             */
2593 /* -------------------------------------------------------------------- */
2594     if (divisor == 0.0)
2595         return FALSE;
2596 
2597 /* -------------------------------------------------------------------- */
2598 /*      Compute top/left origin.                                        */
2599 /* -------------------------------------------------------------------- */
2600   double gt_normalized[6] = { 0.0 };
2601     gt_normalized[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy)
2602                   + sum_Lonx * (sum_y * sum_xy - sum_x *  sum_yy)
2603                   + sum_Lony * (sum_x * sum_xy - sum_y * sum_xx))
2604         / divisor;
2605 
2606     gt_normalized[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy)
2607                   + sum_Latx * (sum_y * sum_xy - sum_x *  sum_yy)
2608                   + sum_Laty * (sum_x * sum_xy - sum_y * sum_xx))
2609         / divisor;
2610 
2611 /* -------------------------------------------------------------------- */
2612 /*      Compute X related coefficients.                                 */
2613 /* -------------------------------------------------------------------- */
2614     gt_normalized[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy)
2615                   + sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y)
2616                   + sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount))
2617         / divisor;
2618 
2619     gt_normalized[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx)
2620                   + sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy)
2621                   + sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x))
2622         / divisor;
2623 
2624 /* -------------------------------------------------------------------- */
2625 /*      Compute Y related coefficients.                                 */
2626 /* -------------------------------------------------------------------- */
2627     gt_normalized[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy)
2628                   + sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y)
2629                   + sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount))
2630         / divisor;
2631 
2632     gt_normalized[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx)
2633                   + sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy)
2634                   + sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x))
2635         / divisor;
2636 
2637 /* -------------------------------------------------------------------- */
2638 /*      Compose the resulting transformation with the normalization     */
2639 /*      geotransformations.                                             */
2640 /* -------------------------------------------------------------------- */
2641     double gt1p2[6] = { 0.0 };
2642     double inv_geo_normalize[6] = { 0.0 };
2643     if( !GDALInvGeoTransform(geo_normalize, inv_geo_normalize))
2644         return FALSE;
2645 
2646     GDALComposeGeoTransforms(pl_normalize, gt_normalized, gt1p2);
2647     GDALComposeGeoTransforms(gt1p2, inv_geo_normalize, padfGeoTransform);
2648 
2649 /* -------------------------------------------------------------------- */
2650 /*      Now check if any of the input points fit this poorly.           */
2651 /* -------------------------------------------------------------------- */
2652     if( !bApproxOK )
2653     {
2654         // FIXME? Not sure if it is the more accurate way of computing
2655         // pixel size
2656         double dfPixelSize =
2657             0.5 * (std::abs(padfGeoTransform[1])
2658             + std::abs(padfGeoTransform[2])
2659             + std::abs(padfGeoTransform[4])
2660             + std::abs(padfGeoTransform[5]));
2661         if( dfPixelSize == 0.0 )
2662         {
2663             CPLDebug("GDAL", "dfPixelSize = 0");
2664             return FALSE;
2665         }
2666 
2667         for( int i = 0; i < nGCPCount; i++ )
2668         {
2669             const double dfErrorX =
2670                 (pasGCPs[i].dfGCPPixel * padfGeoTransform[1]
2671                  + pasGCPs[i].dfGCPLine * padfGeoTransform[2]
2672                  + padfGeoTransform[0])
2673                 - pasGCPs[i].dfGCPX;
2674             const double dfErrorY =
2675                 (pasGCPs[i].dfGCPPixel * padfGeoTransform[4]
2676                  + pasGCPs[i].dfGCPLine * padfGeoTransform[5]
2677                  + padfGeoTransform[3])
2678                 - pasGCPs[i].dfGCPY;
2679 
2680             if( std::abs(dfErrorX) > dfPixelThreshold * dfPixelSize
2681                 || std::abs(dfErrorY) > dfPixelThreshold * dfPixelSize )
2682             {
2683                 CPLDebug("GDAL", "dfErrorX/dfPixelSize = %.2f, "
2684                          "dfErrorY/dfPixelSize = %.2f",
2685                          std::abs(dfErrorX)/dfPixelSize,
2686                          std::abs(dfErrorY)/dfPixelSize);
2687                 return FALSE;
2688             }
2689         }
2690     }
2691 
2692     return TRUE;
2693 }
2694 
2695 /************************************************************************/
2696 /*                      GDALComposeGeoTransforms()                      */
2697 /************************************************************************/
2698 
2699 /**
2700  * \brief Compose two geotransforms.
2701  *
2702  * The resulting geotransform is the equivalent to padfGT1 and then padfGT2
2703  * being applied to a point.
2704  *
2705  * @param padfGT1 the first geotransform, six values.
2706  * @param padfGT2 the second geotransform, six values.
2707  * @param padfGTOut the output geotransform, six values, may safely be the same
2708  * array as padfGT1 or padfGT2.
2709  */
2710 
GDALComposeGeoTransforms(const double * padfGT1,const double * padfGT2,double * padfGTOut)2711 void GDALComposeGeoTransforms(const double *padfGT1, const double *padfGT2,
2712                               double *padfGTOut)
2713 
2714 {
2715     double gtwrk[6] = { 0.0 };
2716     // We need to think of the geotransform in a more normal form to do
2717     // the matrix multiple:
2718     //
2719     //  __                     __
2720     //  | gt[1]   gt[2]   gt[0] |
2721     //  | gt[4]   gt[5]   gt[3] |
2722     //  |  0.0     0.0     1.0  |
2723     //  --                     --
2724     //
2725     // Then we can use normal matrix multiplication to produce the
2726     // composed transformation.  I don't actually reform the matrix
2727     // explicitly which is why the following may seem kind of spagettish.
2728 
2729     gtwrk[1] =
2730         padfGT2[1] * padfGT1[1]
2731         + padfGT2[2] * padfGT1[4];
2732     gtwrk[2] =
2733         padfGT2[1] * padfGT1[2]
2734         + padfGT2[2] * padfGT1[5];
2735     gtwrk[0] =
2736         padfGT2[1] * padfGT1[0]
2737         + padfGT2[2] * padfGT1[3]
2738         + padfGT2[0] * 1.0;
2739 
2740     gtwrk[4] =
2741         padfGT2[4] * padfGT1[1]
2742         + padfGT2[5] * padfGT1[4];
2743     gtwrk[5] =
2744         padfGT2[4] * padfGT1[2]
2745         + padfGT2[5] * padfGT1[5];
2746     gtwrk[3] =
2747         padfGT2[4] * padfGT1[0]
2748         + padfGT2[5] * padfGT1[3]
2749         + padfGT2[3] * 1.0;
2750     memcpy(padfGTOut, gtwrk, sizeof(gtwrk));
2751 }
2752 
2753 /************************************************************************/
2754 /*                      StripIrrelevantOptions()                        */
2755 /************************************************************************/
2756 
StripIrrelevantOptions(CPLXMLNode * psCOL,int nOptions)2757 static void StripIrrelevantOptions(CPLXMLNode* psCOL, int nOptions)
2758 {
2759     if( psCOL == nullptr )
2760         return;
2761     if( nOptions == 0 )
2762         nOptions = GDAL_OF_RASTER;
2763     if( (nOptions & GDAL_OF_RASTER) != 0 && (nOptions & GDAL_OF_VECTOR) != 0 )
2764         return;
2765 
2766     CPLXMLNode* psPrev = nullptr;
2767     for( CPLXMLNode* psIter = psCOL->psChild; psIter; )
2768     {
2769         if( psIter->eType == CXT_Element )
2770         {
2771             CPLXMLNode* psScope = CPLGetXMLNode(psIter, "scope");
2772             bool bStrip = false;
2773             if( nOptions == GDAL_OF_RASTER &&
2774                 psScope && psScope->psChild &&
2775                 psScope->psChild->pszValue &&
2776                 EQUAL(psScope->psChild->pszValue, "vector") )
2777             {
2778                 bStrip = true;
2779             }
2780             else if( nOptions == GDAL_OF_VECTOR &&
2781                 psScope && psScope->psChild &&
2782                 psScope->psChild->pszValue &&
2783                 EQUAL(psScope->psChild->pszValue, "raster") )
2784             {
2785                 bStrip = true;
2786             }
2787             if( psScope )
2788             {
2789                 CPLRemoveXMLChild(psIter, psScope);
2790                 CPLDestroyXMLNode(psScope);
2791             }
2792 
2793             CPLXMLNode* psNext = psIter->psNext;
2794             if( bStrip )
2795             {
2796                 if( psPrev )
2797                     psPrev->psNext = psNext;
2798                 else if( psCOL->psChild == psIter )
2799                     psCOL->psChild = psNext;
2800                 psIter->psNext = nullptr;
2801                 CPLDestroyXMLNode(psIter);
2802                 psIter = psNext;
2803             }
2804             else
2805             {
2806                 psPrev = psIter;
2807                 psIter = psNext;
2808             }
2809         }
2810         else
2811         {
2812             psIter = psIter->psNext;
2813         }
2814     }
2815 }
2816 
2817 /************************************************************************/
2818 /*                    GDALGeneralCmdLineProcessor()                     */
2819 /************************************************************************/
2820 
2821 /**
2822  * \brief General utility option processing.
2823  *
2824  * This function is intended to provide a variety of generic commandline
2825  * options for all GDAL commandline utilities.  It takes care of the following
2826  * commandline options:
2827  *
2828  *  --version: report version of GDAL in use.
2829  *  --build: report build info about GDAL in use.
2830  *  --license: report GDAL license info.
2831  *  --formats: report all format drivers configured.
2832  *  --format [format]: report details of one format driver.
2833  *  --optfile filename: expand an option file into the argument list.
2834  *  --config key value: set system configuration option.
2835  *  --debug [on/off/value]: set debug level.
2836  *  --mempreload dir: preload directory contents into /vsimem
2837  *  --pause: Pause for user input (allows time to attach debugger)
2838  *  --locale [locale]: Install a locale using setlocale() (debugging)
2839  *  --help-general: report detailed help on general options.
2840  *
2841  * The argument array is replaced "in place" and should be freed with
2842  * CSLDestroy() when no longer needed.  The typical usage looks something
2843  * like the following.  Note that the formats should be registered so that
2844  * the --formats and --format options will work properly.
2845  *
2846  *  int main( int argc, char ** argv )
2847  *  {
2848  *    GDALAllRegister();
2849  *
2850  *    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
2851  *    if( argc < 1 )
2852  *        exit( -argc );
2853  *
2854  * @param nArgc number of values in the argument list.
2855  * @param ppapszArgv pointer to the argument list array (will be updated in place).
2856  * @param nOptions a or-able combination of GDAL_OF_RASTER and GDAL_OF_VECTOR
2857  *                 to determine which drivers should be displayed by --formats.
2858  *                 If set to 0, GDAL_OF_RASTER is assumed.
2859  *
2860  * @return updated nArgc argument count.  Return of 0 requests terminate
2861  * without error, return of -1 requests exit with error code.
2862  */
2863 
2864 int CPL_STDCALL
GDALGeneralCmdLineProcessor(int nArgc,char *** ppapszArgv,int nOptions)2865 GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
2866 
2867 {
2868     char **papszReturn = nullptr;
2869     int  iArg;
2870     char **papszArgv = *ppapszArgv;
2871 
2872 /* -------------------------------------------------------------------- */
2873 /*      Preserve the program name.                                      */
2874 /* -------------------------------------------------------------------- */
2875     papszReturn = CSLAddString( papszReturn, papszArgv[0] );
2876 
2877 /* ==================================================================== */
2878 /*      Loop over all arguments.                                        */
2879 /* ==================================================================== */
2880     for( iArg = 1; iArg < nArgc; iArg++ )
2881     {
2882 /* -------------------------------------------------------------------- */
2883 /*      --version                                                       */
2884 /* -------------------------------------------------------------------- */
2885         if( EQUAL(papszArgv[iArg],"--version") )
2886         {
2887             printf( "%s\n", GDALVersionInfo( "--version" ) );/*ok*/
2888             CSLDestroy( papszReturn );
2889             return 0;
2890         }
2891 
2892 /* -------------------------------------------------------------------- */
2893 /*      --build                                                         */
2894 /* -------------------------------------------------------------------- */
2895         else if( EQUAL(papszArgv[iArg],"--build") )
2896         {
2897             printf( "%s", GDALVersionInfo( "BUILD_INFO" ) );/*ok*/
2898             CSLDestroy( papszReturn );
2899             return 0;
2900         }
2901 
2902 /* -------------------------------------------------------------------- */
2903 /*      --license                                                       */
2904 /* -------------------------------------------------------------------- */
2905         else if( EQUAL(papszArgv[iArg],"--license") )
2906         {
2907             printf( "%s\n", GDALVersionInfo( "LICENSE" ) );/*ok*/
2908             CSLDestroy( papszReturn );
2909             return 0;
2910         }
2911 
2912 /* -------------------------------------------------------------------- */
2913 /*      --config                                                        */
2914 /* -------------------------------------------------------------------- */
2915         else if( EQUAL(papszArgv[iArg],"--config") )
2916         {
2917             if( iArg + 2 >= nArgc )
2918             {
2919                 CPLError( CE_Failure, CPLE_AppDefined,
2920                           "--config option given without a key and value argument." );
2921                 CSLDestroy( papszReturn );
2922                 return -1;
2923             }
2924 
2925             CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
2926 
2927             iArg += 2;
2928         }
2929 
2930 /* -------------------------------------------------------------------- */
2931 /*      --mempreload                                                    */
2932 /* -------------------------------------------------------------------- */
2933         else if( EQUAL(papszArgv[iArg],"--mempreload") )
2934         {
2935             if( iArg + 1 >= nArgc )
2936             {
2937                 CPLError( CE_Failure, CPLE_AppDefined,
2938                           "--mempreload option given without directory path.");
2939                 CSLDestroy( papszReturn );
2940                 return -1;
2941             }
2942 
2943             char **papszFiles = VSIReadDir( papszArgv[iArg+1] );
2944             if( CSLCount(papszFiles) == 0 )
2945             {
2946                 CPLError( CE_Failure, CPLE_AppDefined,
2947                           "--mempreload given invalid or empty directory.");
2948                 CSLDestroy( papszReturn );
2949                 return -1;
2950             }
2951 
2952             for( int i = 0; papszFiles[i] != nullptr; i++ )
2953             {
2954                 if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
2955                     continue;
2956 
2957                 CPLString osOldPath, osNewPath;
2958                 osOldPath = CPLFormFilename( papszArgv[iArg+1],
2959                                              papszFiles[i], nullptr );
2960                 osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
2961 
2962                 VSIStatBufL sStatBuf;
2963                 if( VSIStatL( osOldPath, &sStatBuf ) != 0
2964                     || VSI_ISDIR( sStatBuf.st_mode ) )
2965                 {
2966                     CPLDebug( "VSI", "Skipping preload of %s.",
2967                               osOldPath.c_str() );
2968                     continue;
2969                 }
2970 
2971                 CPLDebug( "VSI", "Preloading %s to %s.",
2972                           osOldPath.c_str(), osNewPath.c_str() );
2973 
2974                 if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
2975                 {
2976                     CPLError( CE_Failure, CPLE_AppDefined,
2977                               "Failed to copy %s to /vsimem",
2978                               osOldPath.c_str() );
2979                     CSLDestroy( papszReturn );
2980                     return -1;
2981                 }
2982             }
2983 
2984             CSLDestroy( papszFiles );
2985             iArg += 1;
2986         }
2987 
2988 /* -------------------------------------------------------------------- */
2989 /*      --debug                                                         */
2990 /* -------------------------------------------------------------------- */
2991         else if( EQUAL(papszArgv[iArg],"--debug") )
2992         {
2993             if( iArg + 1 >= nArgc )
2994             {
2995                 CPLError( CE_Failure, CPLE_AppDefined,
2996                           "--debug option given without debug level." );
2997                 CSLDestroy( papszReturn );
2998                 return -1;
2999             }
3000 
3001             CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
3002             iArg += 1;
3003         }
3004 
3005 /* -------------------------------------------------------------------- */
3006 /*      --optfile                                                       */
3007 /* -------------------------------------------------------------------- */
3008         else if( EQUAL(papszArgv[iArg],"--optfile") )
3009         {
3010             if( iArg + 1 >= nArgc )
3011             {
3012                 CPLError( CE_Failure, CPLE_AppDefined,
3013                           "--optfile option given without filename." );
3014                 CSLDestroy( papszReturn );
3015                 return -1;
3016             }
3017 
3018             VSILFILE *fpOptFile = VSIFOpenL( papszArgv[iArg+1], "rb" );
3019 
3020             if( fpOptFile == nullptr )
3021             {
3022                 CPLError( CE_Failure, CPLE_AppDefined,
3023                           "Unable to open optfile '%s'.\n%s",
3024                           papszArgv[iArg+1], VSIStrerror( errno ) );
3025                 CSLDestroy( papszReturn );
3026                 return -1;
3027             }
3028 
3029             const char *pszLine;
3030             // dummy value as first argument to please
3031             // GDALGeneralCmdLineProcessor()
3032             char** papszArgvOptfile = CSLAddString(nullptr, "");
3033             bool bHasOptfile = false;
3034             while( (pszLine = CPLReadLineL( fpOptFile )) != nullptr )
3035             {
3036                 if( pszLine[0] == '#' || strlen(pszLine) == 0 )
3037                     continue;
3038 
3039                 char **papszTokens = CSLTokenizeString( pszLine );
3040                 for( int i = 0; papszTokens != nullptr && papszTokens[i] != nullptr; i++)
3041                 {
3042                     if( EQUAL( papszTokens[i], "--optfile") )
3043                     {
3044                         // To avoid potential recursion
3045                         CPLError(CE_Warning, CPLE_AppDefined,
3046                                  "--optfile not supported in a option file");
3047                         bHasOptfile = true;
3048                     }
3049                     papszArgvOptfile = CSLAddString( papszArgvOptfile, papszTokens[i] );
3050                 }
3051                 CSLDestroy( papszTokens );
3052             }
3053 
3054             VSIFCloseL( fpOptFile );
3055 
3056             if( !bHasOptfile )
3057             {
3058                 char** papszArgvOptfileBefore = papszArgvOptfile;
3059                 if( GDALGeneralCmdLineProcessor(CSLCount(papszArgvOptfile),
3060                                         &papszArgvOptfile, nOptions) < 0 )
3061                 {
3062                     CSLDestroy( papszReturn );
3063                     CSLDestroy(papszArgvOptfile);
3064                     return -1;
3065                 }
3066                 CSLDestroy(papszArgvOptfileBefore);
3067             }
3068 
3069             char** papszIter = papszArgvOptfile + 1;
3070             while( *papszIter )
3071             {
3072                 papszReturn = CSLAddString(papszReturn, *papszIter);
3073                 ++ papszIter;
3074             }
3075             CSLDestroy(papszArgvOptfile);
3076 
3077             iArg += 1;
3078         }
3079 
3080 /* -------------------------------------------------------------------- */
3081 /*      --formats                                                       */
3082 /* -------------------------------------------------------------------- */
3083         else if( EQUAL(papszArgv[iArg], "--formats") )
3084         {
3085             if( nOptions == 0 )
3086                 nOptions = GDAL_OF_RASTER;
3087 
3088             printf( "Supported Formats:\n" );/*ok*/
3089             for( int iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
3090             {
3091                 GDALDriverH hDriver = GDALGetDriver(iDr);
3092 
3093                 const char *pszRFlag = "", *pszWFlag, *pszVirtualIO, *pszSubdatasets;
3094                 char** papszMD = GDALGetMetadata( hDriver, nullptr );
3095 
3096                 if( nOptions == GDAL_OF_RASTER &&
3097                     !CPLFetchBool( papszMD, GDAL_DCAP_RASTER, false ) )
3098                     continue;
3099                 if( nOptions == GDAL_OF_VECTOR &&
3100                     !CPLFetchBool( papszMD, GDAL_DCAP_VECTOR, false ) )
3101                     continue;
3102                 if( nOptions == GDAL_OF_GNM &&
3103                     !CPLFetchBool( papszMD, GDAL_DCAP_GNM, false ) )
3104                     continue;
3105                 if( nOptions == GDAL_OF_MULTIDIM_RASTER &&
3106                     !CPLFetchBool( papszMD, GDAL_DCAP_MULTIDIM_RASTER, false ) )
3107                     continue;
3108 
3109                 if( CPLFetchBool( papszMD, GDAL_DCAP_OPEN, false ) )
3110                     pszRFlag = "r";
3111 
3112                 if( CPLFetchBool( papszMD, GDAL_DCAP_CREATE, false ) )
3113                     pszWFlag = "w+";
3114                 else if( CPLFetchBool( papszMD, GDAL_DCAP_CREATECOPY, false ) )
3115                     pszWFlag = "w";
3116                 else
3117                     pszWFlag = "o";
3118 
3119                 if( CPLFetchBool( papszMD, GDAL_DCAP_VIRTUALIO, false ) )
3120                     pszVirtualIO = "v";
3121                 else
3122                     pszVirtualIO = "";
3123 
3124                 if( CPLFetchBool( papszMD, GDAL_DMD_SUBDATASETS, false ) )
3125                     pszSubdatasets = "s";
3126                 else
3127                     pszSubdatasets = "";
3128 
3129                 CPLString osKind;
3130                 if( CPLFetchBool( papszMD, GDAL_DCAP_RASTER, false ) )
3131                     osKind = "raster";
3132                 if( CPLFetchBool( papszMD, GDAL_DCAP_MULTIDIM_RASTER, false ) )
3133                 {
3134                     if( !osKind.empty() ) osKind += ',';
3135                     osKind += "multidimensional raster";
3136                 }
3137                 if( CPLFetchBool( papszMD, GDAL_DCAP_VECTOR, false ) )
3138                 {
3139                     if( !osKind.empty() ) osKind += ',';
3140                     osKind += "vector";
3141                 }
3142                 if( CPLFetchBool( papszMD, GDAL_DCAP_GNM, false ) )
3143                 {
3144                     if( !osKind.empty() ) osKind += ',';
3145                     osKind += "geography network";
3146                 }
3147                 if( osKind.empty() )
3148                     osKind = "unknown kind";
3149 
3150                 printf( "  %s -%s- (%s%s%s%s): %s\n",/*ok*/
3151                         GDALGetDriverShortName( hDriver ),
3152                         osKind.c_str(),
3153                         pszRFlag, pszWFlag, pszVirtualIO, pszSubdatasets,
3154                         GDALGetDriverLongName( hDriver ) );
3155             }
3156 
3157             CSLDestroy( papszReturn );
3158             return 0;
3159         }
3160 
3161 /* -------------------------------------------------------------------- */
3162 /*      --format                                                        */
3163 /* -------------------------------------------------------------------- */
3164         else if( EQUAL(papszArgv[iArg], "--format") )
3165         {
3166             GDALDriverH hDriver;
3167             char **papszMD;
3168 
3169             CSLDestroy( papszReturn );
3170 
3171             if( iArg + 1 >= nArgc )
3172             {
3173                 CPLError( CE_Failure, CPLE_AppDefined,
3174                           "--format option given without a format code." );
3175                 return -1;
3176             }
3177 
3178             hDriver = GDALGetDriverByName( papszArgv[iArg+1] );
3179             if( hDriver == nullptr )
3180             {
3181                 CPLError( CE_Failure, CPLE_AppDefined,
3182                           "--format option given with format '%s', but that "
3183                           "format not\nrecognised.  Use the --formats option "
3184                           "to get a list of available formats,\n"
3185                           "and use the short code (i.e. GTiff or HFA) as the "
3186                           "format identifier.\n",
3187                           papszArgv[iArg+1] );
3188                 return -1;
3189             }
3190 
3191             printf( "Format Details:\n" );/*ok*/
3192             printf( "  Short Name: %s\n", GDALGetDriverShortName( hDriver ) );/*ok*/
3193             printf( "  Long Name: %s\n", GDALGetDriverLongName( hDriver ) );/*ok*/
3194 
3195             papszMD = GDALGetMetadata( hDriver, nullptr );
3196             if( CPLFetchBool( papszMD, GDAL_DCAP_RASTER, false ) )
3197                 printf( "  Supports: Raster\n" );/*ok*/
3198             if( CPLFetchBool( papszMD, GDAL_DCAP_MULTIDIM_RASTER, false ) )
3199                 printf( "  Supports: Multidimensional raster\n" );/*ok*/
3200             if( CPLFetchBool( papszMD, GDAL_DCAP_VECTOR, false ) )
3201                 printf( "  Supports: Vector\n" );/*ok*/
3202             if( CPLFetchBool( papszMD, GDAL_DCAP_GNM, false ) )
3203                 printf( "  Supports: Geography Network\n" );/*ok*/
3204 
3205             const char* pszExt = CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSIONS );
3206             if( pszExt != nullptr )
3207                 printf( "  Extension%s: %s\n", (strchr(pszExt, ' ') ? "s" : ""),/*ok*/
3208                         pszExt );
3209 
3210             if( CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) )
3211                 printf( "  Mime Type: %s\n",/*ok*/
3212                         CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) );
3213             if( CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) )
3214                 printf( "  Help Topic: %s\n",/*ok*/
3215                         CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) );
3216 
3217             if( CPLFetchBool( papszMD, GDAL_DMD_SUBDATASETS, false ) )
3218                 printf( "  Supports: Subdatasets\n" );/*ok*/
3219             if( CPLFetchBool( papszMD, GDAL_DCAP_OPEN, false ) )
3220                 printf( "  Supports: Open() - Open existing dataset.\n" );/*ok*/
3221             if( CPLFetchBool( papszMD, GDAL_DCAP_CREATE, false ) )
3222                 printf( "  Supports: Create() - Create writable dataset.\n" );/*ok*/
3223             if( CPLFetchBool( papszMD, GDAL_DCAP_CREATE_MULTIDIMENSIONAL, false ) )
3224                 printf( "  Supports: CreateMultiDimensional() - Create multidimensional dataset.\n" );/*ok*/
3225             if( CPLFetchBool( papszMD, GDAL_DCAP_CREATECOPY, false ) )
3226                 printf( "  Supports: CreateCopy() - Create dataset by copying another.\n" );/*ok*/
3227             if( CPLFetchBool( papszMD, GDAL_DCAP_VIRTUALIO, false ) )
3228                 printf( "  Supports: Virtual IO - eg. /vsimem/\n" );/*ok*/
3229             if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) )
3230                 printf( "  Creation Datatypes: %s\n",/*ok*/
3231                         CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) );
3232             if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATATYPES ) )
3233                 printf( "  Creation Field Datatypes: %s\n",/*ok*/
3234                         CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATATYPES ) );
3235             if ( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATASUBTYPES ) )
3236               printf( "  Creation Field Data Sub-types: %s\n",/*ok*/
3237                       CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATASUBTYPES ) );
3238             if( CPLFetchBool( papszMD, GDAL_DCAP_NOTNULL_FIELDS, false ) )
3239                 printf( "  Supports: Creating fields with NOT NULL constraint.\n" );/*ok*/
3240             if( CPLFetchBool( papszMD, GDAL_DCAP_UNIQUE_FIELDS, false ) )
3241                 printf( "  Supports: Creating fields with UNIQUE constraint.\n" );/*ok*/
3242             if( CPLFetchBool( papszMD, GDAL_DCAP_DEFAULT_FIELDS, false ) )
3243                 printf( "  Supports: Creating fields with DEFAULT values.\n" );/*ok*/
3244             if( CPLFetchBool( papszMD, GDAL_DCAP_NOTNULL_GEOMFIELDS, false ) )
3245                 printf( "  Supports: Creating geometry fields with NOT NULL constraint.\n" );/*ok*/
3246             if( CPLFetchBool( papszMD, GDAL_DCAP_NONSPATIAL, false ) )
3247                 printf( "  No support for geometries.\n" );/*ok*/
3248             if( CPLFetchBool( papszMD, GDAL_DCAP_FEATURE_STYLES, false ) )
3249                 printf( "  Supports: Feature styles.\n" );/*ok*/
3250 
3251             for( const char* key: { GDAL_DMD_CREATIONOPTIONLIST,
3252                                     GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
3253                                     GDAL_DMD_MULTIDIM_GROUP_CREATIONOPTIONLIST,
3254                                     GDAL_DMD_MULTIDIM_DIMENSION_CREATIONOPTIONLIST,
3255                                     GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
3256                                     GDAL_DMD_MULTIDIM_ATTRIBUTE_CREATIONOPTIONLIST,
3257                                     GDAL_DS_LAYER_CREATIONOPTIONLIST } )
3258             {
3259                 if( CSLFetchNameValue( papszMD, key ) )
3260                 {
3261                     CPLXMLNode *psCOL =
3262                         CPLParseXMLString(
3263                             CSLFetchNameValue( papszMD,
3264                                             key ) );
3265                     StripIrrelevantOptions(psCOL, nOptions);
3266                     char *pszFormattedXML =
3267                         CPLSerializeXMLTree( psCOL );
3268 
3269                     CPLDestroyXMLNode( psCOL );
3270 
3271                     printf( "\n%s\n", pszFormattedXML );/*ok*/
3272                     CPLFree( pszFormattedXML );
3273                 }
3274             }
3275 
3276             if( CSLFetchNameValue( papszMD, GDAL_DMD_CONNECTION_PREFIX ) )
3277                 printf( "  Connection prefix: %s\n",/*ok*/
3278                         CSLFetchNameValue( papszMD, GDAL_DMD_CONNECTION_PREFIX ) );
3279 
3280             if( CSLFetchNameValue( papszMD, GDAL_DMD_OPENOPTIONLIST ) )
3281             {
3282                 CPLXMLNode *psCOL =
3283                     CPLParseXMLString(
3284                         CSLFetchNameValue( papszMD,
3285                                            GDAL_DMD_OPENOPTIONLIST ) );
3286                 StripIrrelevantOptions(psCOL, nOptions);
3287                 char *pszFormattedXML =
3288                     CPLSerializeXMLTree( psCOL );
3289 
3290                 CPLDestroyXMLNode( psCOL );
3291 
3292                 printf( "%s\n", pszFormattedXML );/*ok*/
3293                 CPLFree( pszFormattedXML );
3294             }
3295 
3296             bool bFirstOtherOption = true;
3297             for( char** papszIter = papszMD;
3298                  papszIter && *papszIter; ++papszIter )
3299             {
3300                 if( !STARTS_WITH(*papszIter, "DCAP_") &&
3301                     !STARTS_WITH(*papszIter, "DMD_") &&
3302                     !STARTS_WITH(*papszIter, "DS_") &&
3303                     !STARTS_WITH(*papszIter, "OGR_DRIVER=") )
3304                 {
3305                     if( bFirstOtherOption )
3306                         printf("  Other metadata items:\n"); /*ok*/
3307                     bFirstOtherOption = false;
3308                     printf("    %s\n", *papszIter); /*ok*/
3309                 }
3310             }
3311 
3312             return 0;
3313         }
3314 
3315 /* -------------------------------------------------------------------- */
3316 /*      --help-general                                                  */
3317 /* -------------------------------------------------------------------- */
3318         else if( EQUAL(papszArgv[iArg],"--help-general") )
3319         {
3320             printf( "Generic GDAL utility command options:\n" );/*ok*/
3321             printf( "  --version: report version of GDAL in use.\n" );/*ok*/
3322             printf( "  --license: report GDAL license info.\n" );/*ok*/
3323             printf( "  --formats: report all configured format drivers.\n" );/*ok*/
3324             printf( "  --format [format]: details of one format.\n" );/*ok*/
3325             printf( "  --optfile filename: expand an option file into the argument list.\n" );/*ok*/
3326             printf( "  --config key value: set system configuration option.\n" );/*ok*/
3327             printf( "  --debug [on/off/value]: set debug level.\n" );/*ok*/
3328             printf( "  --pause: wait for user input, time to attach debugger\n" );/*ok*/
3329             printf( "  --locale [locale]: install locale for debugging "/*ok*/
3330                     "(i.e. en_US.UTF-8)\n" );
3331             printf( "  --help-general: report detailed help on general options.\n" );/*ok*/
3332             CSLDestroy( papszReturn );
3333             return 0;
3334         }
3335 
3336 /* -------------------------------------------------------------------- */
3337 /*      --locale                                                        */
3338 /* -------------------------------------------------------------------- */
3339         else if( iArg < nArgc-1 && EQUAL(papszArgv[iArg],"--locale") )
3340         {
3341             CPLsetlocale( LC_ALL, papszArgv[++iArg] );
3342         }
3343 
3344 /* -------------------------------------------------------------------- */
3345 /*      --pause                                                         */
3346 /* -------------------------------------------------------------------- */
3347         else if( EQUAL(papszArgv[iArg],"--pause") )
3348         {
3349             std::cout << "Hit <ENTER> to Continue." << std::endl;
3350             std::cin.clear();
3351             std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
3352         }
3353 
3354 /* -------------------------------------------------------------------- */
3355 /*      Carry through unrecognized options.                             */
3356 /* -------------------------------------------------------------------- */
3357         else
3358         {
3359             papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
3360         }
3361     }
3362 
3363     *ppapszArgv = papszReturn;
3364 
3365     return CSLCount( *ppapszArgv );
3366 }
3367 
3368 /************************************************************************/
3369 /*                          _FetchDblFromMD()                           */
3370 /************************************************************************/
3371 
_FetchDblFromMD(CSLConstList papszMD,const char * pszKey,double * padfTarget,int nCount,double dfDefault)3372 static bool _FetchDblFromMD( CSLConstList papszMD, const char *pszKey,
3373                              double *padfTarget, int nCount, double dfDefault )
3374 
3375 {
3376     char szFullKey[200];
3377 
3378     snprintf( szFullKey, sizeof(szFullKey), "%s", pszKey );
3379 
3380     const char *pszValue = CSLFetchNameValue( papszMD, szFullKey );
3381 
3382     for( int i = 0; i < nCount; i++ )
3383         padfTarget[i] = dfDefault;
3384 
3385     if( pszValue == nullptr )
3386         return false;
3387 
3388     if( nCount == 1 )
3389     {
3390         *padfTarget = CPLAtofM( pszValue );
3391         return true;
3392     }
3393 
3394     char **papszTokens = CSLTokenizeStringComplex( pszValue, " ,",
3395                                                    FALSE, FALSE );
3396 
3397     if( CSLCount( papszTokens ) != nCount )
3398     {
3399         CSLDestroy( papszTokens );
3400         return false;
3401     }
3402 
3403     for( int i = 0; i < nCount; i++ )
3404         padfTarget[i] = CPLAtofM(papszTokens[i]);
3405 
3406     CSLDestroy( papszTokens );
3407 
3408     return true;
3409 }
3410 
3411 /************************************************************************/
3412 /*                         GDALExtractRPCInfo()                         */
3413 /************************************************************************/
3414 
3415 /** Extract RPC info from metadata, and apply to an RPCInfo structure.
3416  *
3417  * The inverse of this function is RPCInfoV1ToMD() in alg/gdal_rpc.cpp
3418  *
3419  * @param papszMD Dictionary of metadata representing RPC
3420  * @param psRPC (output) Pointer to structure to hold the RPC values.
3421  * @return TRUE in case of success. FALSE in case of failure.
3422  */
GDALExtractRPCInfoV1(CSLConstList papszMD,GDALRPCInfoV1 * psRPC)3423 int CPL_STDCALL GDALExtractRPCInfoV1( CSLConstList papszMD, GDALRPCInfoV1 *psRPC )
3424 
3425 {
3426     GDALRPCInfoV2 sRPC;
3427     if( !GDALExtractRPCInfoV2(papszMD, &sRPC) )
3428         return FALSE;
3429     memcpy(psRPC, &sRPC, sizeof(GDALRPCInfoV1) );
3430     return TRUE;
3431 }
3432 
3433 /** Extract RPC info from metadata, and apply to an RPCInfo structure.
3434  *
3435  * The inverse of this function is RPCInfoV2ToMD() in alg/gdal_rpc.cpp
3436  *
3437  * @param papszMD Dictionary of metadata representing RPC
3438  * @param psRPC (output) Pointer to structure to hold the RPC values.
3439  * @return TRUE in case of success. FALSE in case of failure.
3440  */
GDALExtractRPCInfoV2(CSLConstList papszMD,GDALRPCInfoV2 * psRPC)3441 int CPL_STDCALL GDALExtractRPCInfoV2( CSLConstList papszMD, GDALRPCInfoV2 *psRPC )
3442 
3443 {
3444     if( CSLFetchNameValue( papszMD, RPC_LINE_NUM_COEFF ) == nullptr )
3445         return FALSE;
3446 
3447     if( CSLFetchNameValue( papszMD, RPC_LINE_NUM_COEFF ) == nullptr
3448         || CSLFetchNameValue( papszMD, RPC_LINE_DEN_COEFF ) == nullptr
3449         || CSLFetchNameValue( papszMD, RPC_SAMP_NUM_COEFF ) == nullptr
3450         || CSLFetchNameValue( papszMD, RPC_SAMP_DEN_COEFF ) == nullptr )
3451     {
3452         CPLError( CE_Failure, CPLE_AppDefined,
3453                  "Some required RPC metadata missing in GDALExtractRPCInfo()");
3454         return FALSE;
3455     }
3456 
3457     _FetchDblFromMD( papszMD, RPC_ERR_BIAS, &(psRPC->dfERR_BIAS), 1, -1.0 );
3458     _FetchDblFromMD( papszMD, RPC_ERR_RAND, &(psRPC->dfERR_RAND), 1, -1.0 );
3459     _FetchDblFromMD( papszMD, RPC_LINE_OFF, &(psRPC->dfLINE_OFF), 1, 0.0 );
3460     _FetchDblFromMD( papszMD, RPC_LINE_SCALE, &(psRPC->dfLINE_SCALE), 1, 1.0 );
3461     _FetchDblFromMD( papszMD, RPC_SAMP_OFF, &(psRPC->dfSAMP_OFF), 1, 0.0 );
3462     _FetchDblFromMD( papszMD, RPC_SAMP_SCALE, &(psRPC->dfSAMP_SCALE), 1, 1.0 );
3463     _FetchDblFromMD( papszMD, RPC_HEIGHT_OFF, &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
3464     _FetchDblFromMD( papszMD, RPC_HEIGHT_SCALE, &(psRPC->dfHEIGHT_SCALE),1, 1.0);
3465     _FetchDblFromMD( papszMD, RPC_LAT_OFF, &(psRPC->dfLAT_OFF), 1, 0.0 );
3466     _FetchDblFromMD( papszMD, RPC_LAT_SCALE, &(psRPC->dfLAT_SCALE), 1, 1.0 );
3467     _FetchDblFromMD( papszMD, RPC_LONG_OFF, &(psRPC->dfLONG_OFF), 1, 0.0 );
3468     _FetchDblFromMD( papszMD, RPC_LONG_SCALE, &(psRPC->dfLONG_SCALE), 1, 1.0 );
3469 
3470     _FetchDblFromMD( papszMD, RPC_LINE_NUM_COEFF, psRPC->adfLINE_NUM_COEFF,
3471                      20, 0.0 );
3472     _FetchDblFromMD( papszMD, RPC_LINE_DEN_COEFF, psRPC->adfLINE_DEN_COEFF,
3473                      20, 0.0 );
3474     _FetchDblFromMD( papszMD, RPC_SAMP_NUM_COEFF, psRPC->adfSAMP_NUM_COEFF,
3475                      20, 0.0 );
3476     _FetchDblFromMD( papszMD, RPC_SAMP_DEN_COEFF, psRPC->adfSAMP_DEN_COEFF,
3477                      20, 0.0 );
3478 
3479     _FetchDblFromMD( papszMD, RPC_MIN_LONG, &(psRPC->dfMIN_LONG), 1, -180.0 );
3480     _FetchDblFromMD( papszMD, RPC_MIN_LAT, &(psRPC->dfMIN_LAT), 1, -90.0 );
3481     _FetchDblFromMD( papszMD, RPC_MAX_LONG, &(psRPC->dfMAX_LONG), 1, 180.0 );
3482     _FetchDblFromMD( papszMD, RPC_MAX_LAT, &(psRPC->dfMAX_LAT), 1, 90.0 );
3483 
3484     return TRUE;
3485 }
3486 
3487 /************************************************************************/
3488 /*                     GDALFindAssociatedAuxFile()                      */
3489 /************************************************************************/
3490 
GDALFindAssociatedAuxFile(const char * pszBasename,GDALAccess eAccess,GDALDataset * poDependentDS)3491 GDALDataset *GDALFindAssociatedAuxFile( const char *pszBasename,
3492                                         GDALAccess eAccess,
3493                                         GDALDataset *poDependentDS )
3494 
3495 {
3496     const char *pszAuxSuffixLC = "aux";
3497     const char *pszAuxSuffixUC = "AUX";
3498 
3499     if( EQUAL(CPLGetExtension(pszBasename), pszAuxSuffixLC) )
3500         return nullptr;
3501 
3502 /* -------------------------------------------------------------------- */
3503 /*      Don't even try to look for an .aux file if we don't have a      */
3504 /*      path of any kind.                                               */
3505 /* -------------------------------------------------------------------- */
3506     if( strlen(pszBasename) == 0 )
3507         return nullptr;
3508 
3509 /* -------------------------------------------------------------------- */
3510 /*      We didn't find that, so try and find a corresponding aux        */
3511 /*      file.  Check that we are the dependent file of the aux          */
3512 /*      file, or if we aren't verify that the dependent file does       */
3513 /*      not exist, likely mean it is us but some sort of renaming       */
3514 /*      has occurred.                                                   */
3515 /* -------------------------------------------------------------------- */
3516     CPLString osJustFile = CPLGetFilename(pszBasename); // without dir
3517     CPLString osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixLC);
3518     GDALDataset *poODS = nullptr;
3519     GByte abyHeader[32];
3520 
3521     VSILFILE *fp = VSIFOpenL( osAuxFilename, "rb" );
3522 
3523     if ( fp == nullptr && VSIIsCaseSensitiveFS(osAuxFilename))
3524     {
3525         // Can't found file with lower case suffix. Try the upper case one.
3526         osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixUC);
3527         fp = VSIFOpenL( osAuxFilename, "rb" );
3528     }
3529 
3530     if( fp != nullptr )
3531     {
3532         if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
3533             STARTS_WITH_CI(reinterpret_cast<const char *>(abyHeader), "EHFA_HEADER_TAG") )
3534         {
3535             /* Avoid causing failure in opening of main file from SWIG bindings */
3536             /* when auxiliary file cannot be opened (#3269) */
3537             CPLTurnFailureIntoWarning(TRUE);
3538             if( poDependentDS != nullptr && poDependentDS->GetShared() )
3539                 poODS = GDALDataset::FromHandle(GDALOpenShared( osAuxFilename, eAccess ));
3540             else
3541                 poODS = GDALDataset::FromHandle(GDALOpen( osAuxFilename, eAccess ));
3542             CPLTurnFailureIntoWarning(FALSE);
3543         }
3544         CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
3545     }
3546 
3547 /* -------------------------------------------------------------------- */
3548 /*      Try replacing extension with .aux                               */
3549 /* -------------------------------------------------------------------- */
3550     if( poODS != nullptr )
3551     {
3552         const char *pszDep
3553             = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
3554         if( pszDep == nullptr  )
3555         {
3556             CPLDebug( "AUX",
3557                       "Found %s but it has no dependent file, ignoring.",
3558                       osAuxFilename.c_str() );
3559             GDALClose( poODS );
3560             poODS = nullptr;
3561         }
3562         else if( !EQUAL(pszDep,osJustFile) )
3563         {
3564             VSIStatBufL sStatBuf;
3565 
3566             if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
3567             {
3568                 CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
3569                           osAuxFilename.c_str(),
3570                           pszDep, osJustFile.c_str() );
3571                 GDALClose( poODS );
3572                 poODS = nullptr;
3573             }
3574             else
3575             {
3576                 CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
3577                           "%s does not exist, we will use .aux file as our own.",
3578                           osAuxFilename.c_str(),
3579                           pszDep, osJustFile.c_str(),
3580                           pszDep );
3581             }
3582         }
3583 
3584 /* -------------------------------------------------------------------- */
3585 /*      Confirm that the aux file matches the configuration of the      */
3586 /*      dependent dataset.                                              */
3587 /* -------------------------------------------------------------------- */
3588         if( poODS != nullptr && poDependentDS != nullptr
3589             && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
3590                 || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
3591                 || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
3592         {
3593             CPLDebug( "AUX",
3594                       "Ignoring aux file %s as its raster configuration\n"
3595                       "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
3596                       osAuxFilename.c_str(),
3597                       poODS->GetRasterXSize(),
3598                       poODS->GetRasterYSize(),
3599                       poODS->GetRasterCount(),
3600                       poDependentDS->GetRasterXSize(),
3601                       poDependentDS->GetRasterYSize(),
3602                       poDependentDS->GetRasterCount() );
3603 
3604             GDALClose( poODS );
3605             poODS = nullptr;
3606         }
3607     }
3608 
3609 /* -------------------------------------------------------------------- */
3610 /*      Try appending .aux to the end of the filename.                  */
3611 /* -------------------------------------------------------------------- */
3612     if( poODS == nullptr )
3613     {
3614         osAuxFilename = pszBasename;
3615         osAuxFilename += ".";
3616         osAuxFilename += pszAuxSuffixLC;
3617         fp = VSIFOpenL( osAuxFilename, "rb" );
3618         if ( fp == nullptr && VSIIsCaseSensitiveFS(osAuxFilename) )
3619         {
3620             // Can't found file with lower case suffix. Try the upper case one.
3621             osAuxFilename = pszBasename;
3622             osAuxFilename += ".";
3623             osAuxFilename += pszAuxSuffixUC;
3624             fp = VSIFOpenL( osAuxFilename, "rb" );
3625         }
3626 
3627         if( fp != nullptr )
3628         {
3629             if( VSIFReadL( abyHeader, 1, 32, fp ) == 32 &&
3630                 STARTS_WITH_CI(reinterpret_cast<const char *>(abyHeader), "EHFA_HEADER_TAG") )
3631             {
3632                 /* Avoid causing failure in opening of main file from SWIG bindings */
3633                 /* when auxiliary file cannot be opened (#3269) */
3634                 CPLTurnFailureIntoWarning(TRUE);
3635                 if( poDependentDS != nullptr && poDependentDS->GetShared() )
3636                     poODS = GDALDataset::FromHandle(GDALOpenShared( osAuxFilename, eAccess ));
3637                 else
3638                     poODS = GDALDataset::FromHandle(GDALOpen( osAuxFilename, eAccess ));
3639                 CPLTurnFailureIntoWarning(FALSE);
3640             }
3641             CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
3642         }
3643 
3644         if( poODS != nullptr )
3645         {
3646             const char *pszDep
3647                 = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
3648             if( pszDep == nullptr  )
3649             {
3650                 CPLDebug( "AUX",
3651                           "Found %s but it has no dependent file, ignoring.",
3652                           osAuxFilename.c_str() );
3653                 GDALClose( poODS );
3654                 poODS = nullptr;
3655             }
3656             else if( !EQUAL(pszDep,osJustFile) )
3657             {
3658                 VSIStatBufL sStatBuf;
3659 
3660                 if( VSIStatExL( pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG ) == 0 )
3661                 {
3662                     CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
3663                               osAuxFilename.c_str(),
3664                               pszDep, osJustFile.c_str() );
3665                     GDALClose( poODS );
3666                     poODS = nullptr;
3667                 }
3668                 else
3669                 {
3670                     CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
3671                               "%s does not exist, we will use .aux file as our own.",
3672                               osAuxFilename.c_str(),
3673                               pszDep, osJustFile.c_str(),
3674                               pszDep );
3675                 }
3676             }
3677         }
3678     }
3679 
3680 /* -------------------------------------------------------------------- */
3681 /*      Confirm that the aux file matches the configuration of the      */
3682 /*      dependent dataset.                                              */
3683 /* -------------------------------------------------------------------- */
3684     if( poODS != nullptr && poDependentDS != nullptr
3685         && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
3686             || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
3687             || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
3688     {
3689         CPLDebug( "AUX",
3690                   "Ignoring aux file %s as its raster configuration\n"
3691                   "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
3692                   osAuxFilename.c_str(),
3693                   poODS->GetRasterXSize(),
3694                   poODS->GetRasterYSize(),
3695                   poODS->GetRasterCount(),
3696                   poDependentDS->GetRasterXSize(),
3697                   poDependentDS->GetRasterYSize(),
3698                   poDependentDS->GetRasterCount() );
3699 
3700         GDALClose( poODS );
3701         poODS = nullptr;
3702     }
3703 
3704     return poODS;
3705 }
3706 
3707 /************************************************************************/
3708 /* Infrastructure to check that dataset characteristics are valid       */
3709 /************************************************************************/
3710 
3711 CPL_C_START
3712 
3713 /**
3714   * \brief Return TRUE if the dataset dimensions are valid.
3715   *
3716   * @param nXSize raster width
3717   * @param nYSize raster height
3718   *
3719   * @since GDAL 1.7.0
3720   */
GDALCheckDatasetDimensions(int nXSize,int nYSize)3721 int GDALCheckDatasetDimensions( int nXSize, int nYSize )
3722 {
3723     if (nXSize <= 0 || nYSize <= 0)
3724     {
3725         CPLError(CE_Failure, CPLE_AppDefined,
3726                  "Invalid dataset dimensions : %d x %d", nXSize, nYSize);
3727         return FALSE;
3728     }
3729     return TRUE;
3730 }
3731 
3732 /**
3733   * \brief Return TRUE if the band count is valid.
3734   *
3735   * If the configuration option GDAL_MAX_BAND_COUNT is defined,
3736   * the band count will be compared to the maximum number of band allowed.
3737   * If not defined, the maximum number allowed is 65536.
3738   *
3739   * @param nBands the band count
3740   * @param bIsZeroAllowed TRUE if band count == 0 is allowed
3741   *
3742   * @since GDAL 1.7.0
3743   */
3744 
GDALCheckBandCount(int nBands,int bIsZeroAllowed)3745 int GDALCheckBandCount( int nBands, int bIsZeroAllowed )
3746 {
3747     if (nBands < 0 || (!bIsZeroAllowed && nBands == 0) )
3748     {
3749         CPLError(CE_Failure, CPLE_AppDefined,
3750                  "Invalid band count : %d", nBands);
3751         return FALSE;
3752     }
3753     const char* pszMaxBandCount = CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536");
3754     /* coverity[tainted_data] */
3755     int nMaxBands = atoi(pszMaxBandCount);
3756     if ( nBands > nMaxBands )
3757     {
3758         CPLError(CE_Failure, CPLE_AppDefined,
3759                  "Invalid band count : %d. Maximum allowed currently is %d. "
3760                  "Define GDAL_MAX_BAND_COUNT to a higher level if it is a legitimate number.",
3761                  nBands, nMaxBands);
3762         return FALSE;
3763     }
3764     return TRUE;
3765 }
3766 
3767 CPL_C_END
3768 
3769 /************************************************************************/
3770 /*                     GDALSerializeGCPListToXML()                      */
3771 /************************************************************************/
3772 
GDALSerializeGCPListToXML(CPLXMLNode * psParentNode,GDAL_GCP * pasGCPList,int nGCPCount,const OGRSpatialReference * poGCP_SRS)3773 void GDALSerializeGCPListToXML( CPLXMLNode* psParentNode,
3774                                 GDAL_GCP* pasGCPList,
3775                                 int nGCPCount,
3776                                 const OGRSpatialReference* poGCP_SRS )
3777 {
3778     CPLString oFmt;
3779 
3780     CPLXMLNode *psPamGCPList = CPLCreateXMLNode( psParentNode, CXT_Element,
3781                                                  "GCPList" );
3782 
3783     CPLXMLNode* psLastChild = nullptr;
3784 
3785     if( poGCP_SRS != nullptr && !poGCP_SRS->IsEmpty() )
3786     {
3787         char* pszWKT = nullptr;
3788         poGCP_SRS->exportToWkt(&pszWKT);
3789         CPLSetXMLValue( psPamGCPList, "#Projection",
3790                         pszWKT );
3791         CPLFree(pszWKT);
3792         const auto& mapping = poGCP_SRS->GetDataAxisToSRSAxisMapping();
3793         CPLString osMapping;
3794         for( size_t i = 0; i < mapping.size(); ++i )
3795         {
3796             if( !osMapping.empty() )
3797                 osMapping += ",";
3798             osMapping += CPLSPrintf("%d", mapping[i]);
3799         }
3800         CPLSetXMLValue(psPamGCPList, "#dataAxisToSRSAxisMapping",
3801                       osMapping.c_str());
3802 
3803         psLastChild = psPamGCPList->psChild->psNext;
3804     }
3805 
3806     for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
3807     {
3808         GDAL_GCP *psGCP = pasGCPList + iGCP;
3809 
3810         CPLXMLNode *psXMLGCP = CPLCreateXMLNode( nullptr, CXT_Element, "GCP" );
3811 
3812         if( psLastChild == nullptr )
3813             psPamGCPList->psChild = psXMLGCP;
3814         else
3815             psLastChild->psNext = psXMLGCP;
3816         psLastChild = psXMLGCP;
3817 
3818         CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
3819 
3820         if( psGCP->pszInfo != nullptr && strlen(psGCP->pszInfo) > 0 )
3821             CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
3822 
3823         CPLSetXMLValue( psXMLGCP, "#Pixel",
3824                         oFmt.Printf( "%.4f", psGCP->dfGCPPixel ) );
3825 
3826         CPLSetXMLValue( psXMLGCP, "#Line",
3827                         oFmt.Printf( "%.4f", psGCP->dfGCPLine ) );
3828 
3829         CPLSetXMLValue( psXMLGCP, "#X",
3830                         oFmt.Printf( "%.12E", psGCP->dfGCPX ) );
3831 
3832         CPLSetXMLValue( psXMLGCP, "#Y",
3833                         oFmt.Printf( "%.12E", psGCP->dfGCPY ) );
3834 
3835         /* Note: GDAL 1.10.1 and older generated #GCPZ, but could not read it back */
3836         if( psGCP->dfGCPZ != 0.0 )
3837             CPLSetXMLValue( psXMLGCP, "#Z",
3838                             oFmt.Printf( "%.12E", psGCP->dfGCPZ ) );
3839     }
3840 }
3841 
3842 /************************************************************************/
3843 /*                     GDALDeserializeGCPListFromXML()                  */
3844 /************************************************************************/
3845 
GDALDeserializeGCPListFromXML(CPLXMLNode * psGCPList,GDAL_GCP ** ppasGCPList,int * pnGCPCount,OGRSpatialReference ** ppoGCP_SRS)3846 void GDALDeserializeGCPListFromXML( CPLXMLNode* psGCPList,
3847                                     GDAL_GCP** ppasGCPList,
3848                                     int* pnGCPCount,
3849                                     OGRSpatialReference** ppoGCP_SRS )
3850 {
3851     if( ppoGCP_SRS )
3852     {
3853         const char *pszRawProj = CPLGetXMLValue(psGCPList, "Projection", nullptr);
3854 
3855         *ppoGCP_SRS = nullptr;
3856         if( pszRawProj && pszRawProj[0] )
3857         {
3858             *ppoGCP_SRS = new OGRSpatialReference();
3859             (*ppoGCP_SRS)->SetFromUserInput( pszRawProj );
3860 
3861             const char* pszMapping =
3862                 CPLGetXMLValue(psGCPList, "dataAxisToSRSAxisMapping", nullptr);
3863             if( pszMapping )
3864             {
3865                 char** papszTokens = CSLTokenizeStringComplex( pszMapping, ",", FALSE, FALSE);
3866                 std::vector<int> anMapping;
3867                 for( int i = 0; papszTokens && papszTokens[i]; i++ )
3868                 {
3869                     anMapping.push_back(atoi(papszTokens[i]));
3870                 }
3871                 CSLDestroy(papszTokens);
3872                 (*ppoGCP_SRS)->SetDataAxisToSRSAxisMapping(anMapping);
3873             }
3874             else
3875             {
3876                 (*ppoGCP_SRS)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
3877             }
3878         }
3879     }
3880 
3881     // Count GCPs.
3882     int nGCPMax = 0;
3883 
3884     for( CPLXMLNode *psXMLGCP = psGCPList->psChild;
3885          psXMLGCP != nullptr;
3886          psXMLGCP = psXMLGCP->psNext )
3887     {
3888 
3889         if( !EQUAL(psXMLGCP->pszValue,"GCP") ||
3890             psXMLGCP->eType != CXT_Element )
3891             continue;
3892 
3893         nGCPMax++;
3894     }
3895 
3896     *ppasGCPList = static_cast<GDAL_GCP *>(
3897         nGCPMax ? CPLCalloc(sizeof(GDAL_GCP), nGCPMax) : nullptr );
3898     *pnGCPCount = 0;
3899 
3900     if( nGCPMax == 0 )
3901         return;
3902 
3903     for( CPLXMLNode *psXMLGCP = psGCPList->psChild;
3904          *ppasGCPList != nullptr && psXMLGCP != nullptr;
3905          psXMLGCP = psXMLGCP->psNext )
3906     {
3907         GDAL_GCP *psGCP = *ppasGCPList + *pnGCPCount;
3908 
3909         if( !EQUAL(psXMLGCP->pszValue,"GCP") ||
3910             psXMLGCP->eType != CXT_Element )
3911             continue;
3912 
3913         GDALInitGCPs( 1, psGCP );
3914 
3915         CPLFree( psGCP->pszId );
3916         psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
3917 
3918         CPLFree( psGCP->pszInfo );
3919         psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
3920 
3921         psGCP->dfGCPPixel = CPLAtof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
3922         psGCP->dfGCPLine = CPLAtof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
3923 
3924         psGCP->dfGCPX = CPLAtof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
3925         psGCP->dfGCPY = CPLAtof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
3926         const char* pszZ = CPLGetXMLValue(psXMLGCP,"Z",nullptr);
3927         if( pszZ == nullptr )
3928         {
3929             // Note: GDAL 1.10.1 and older generated #GCPZ,
3930             // but could not read it back.
3931             pszZ = CPLGetXMLValue(psXMLGCP,"GCPZ","0.0");
3932         }
3933         psGCP->dfGCPZ = CPLAtof(pszZ);
3934 
3935         (*pnGCPCount)++;
3936     }
3937 }
3938 
3939 /************************************************************************/
3940 /*                   GDALSerializeOpenOptionsToXML()                    */
3941 /************************************************************************/
3942 
GDALSerializeOpenOptionsToXML(CPLXMLNode * psParentNode,char ** papszOpenOptions)3943 void GDALSerializeOpenOptionsToXML( CPLXMLNode* psParentNode, char** papszOpenOptions)
3944 {
3945     if( papszOpenOptions != nullptr )
3946     {
3947         CPLXMLNode* psOpenOptions = CPLCreateXMLNode( psParentNode, CXT_Element, "OpenOptions" );
3948         CPLXMLNode* psLastChild = nullptr;
3949 
3950         for(char** papszIter = papszOpenOptions; *papszIter != nullptr; papszIter ++ )
3951         {
3952             const char *pszRawValue;
3953             char *pszKey = nullptr;
3954             CPLXMLNode *psOOI;
3955 
3956             pszRawValue = CPLParseNameValue( *papszIter, &pszKey );
3957 
3958             psOOI = CPLCreateXMLNode( nullptr, CXT_Element, "OOI" );
3959             if( psLastChild == nullptr )
3960                 psOpenOptions->psChild = psOOI;
3961             else
3962                 psLastChild->psNext = psOOI;
3963             psLastChild = psOOI;
3964 
3965             CPLSetXMLValue( psOOI, "#key", pszKey );
3966             CPLCreateXMLNode( psOOI, CXT_Text, pszRawValue );
3967 
3968             CPLFree( pszKey );
3969         }
3970     }
3971 }
3972 
3973 /************************************************************************/
3974 /*                  GDALDeserializeOpenOptionsFromXML()                 */
3975 /************************************************************************/
3976 
GDALDeserializeOpenOptionsFromXML(CPLXMLNode * psParentNode)3977 char** GDALDeserializeOpenOptionsFromXML( CPLXMLNode* psParentNode )
3978 {
3979     char** papszOpenOptions = nullptr;
3980     CPLXMLNode* psOpenOptions = CPLGetXMLNode(psParentNode, "OpenOptions");
3981     if( psOpenOptions != nullptr )
3982     {
3983         CPLXMLNode* psOOI;
3984         for( psOOI = psOpenOptions->psChild; psOOI != nullptr;
3985                 psOOI = psOOI->psNext )
3986         {
3987             if( !EQUAL(psOOI->pszValue,"OOI")
3988                 || psOOI->eType != CXT_Element
3989                 || psOOI->psChild == nullptr
3990                 || psOOI->psChild->psNext == nullptr
3991                 || psOOI->psChild->eType != CXT_Attribute
3992                 || psOOI->psChild->psChild == nullptr )
3993                 continue;
3994 
3995             char* pszName = psOOI->psChild->psChild->pszValue;
3996             char* pszValue = psOOI->psChild->psNext->pszValue;
3997             if( pszName != nullptr && pszValue != nullptr )
3998                 papszOpenOptions = CSLSetNameValue( papszOpenOptions, pszName, pszValue );
3999         }
4000     }
4001     return papszOpenOptions;
4002 }
4003 
4004 /************************************************************************/
4005 /*                    GDALRasterIOGetResampleAlg()                      */
4006 /************************************************************************/
4007 
GDALRasterIOGetResampleAlg(const char * pszResampling)4008 GDALRIOResampleAlg GDALRasterIOGetResampleAlg(const char* pszResampling)
4009 {
4010     GDALRIOResampleAlg eResampleAlg = GRIORA_NearestNeighbour;
4011     if( STARTS_WITH_CI(pszResampling, "NEAR") )
4012         eResampleAlg = GRIORA_NearestNeighbour;
4013     else if( EQUAL(pszResampling, "BILINEAR") )
4014         eResampleAlg = GRIORA_Bilinear;
4015     else if( EQUAL(pszResampling, "CUBIC") )
4016         eResampleAlg = GRIORA_Cubic;
4017     else if( EQUAL(pszResampling, "CUBICSPLINE") )
4018         eResampleAlg = GRIORA_CubicSpline;
4019     else if( EQUAL(pszResampling, "LANCZOS") )
4020         eResampleAlg = GRIORA_Lanczos;
4021     else if( EQUAL(pszResampling, "AVERAGE") )
4022         eResampleAlg = GRIORA_Average;
4023     else if( EQUAL(pszResampling, "RMS") )
4024         eResampleAlg = GRIORA_RMS;
4025     else if( EQUAL(pszResampling, "MODE") )
4026         eResampleAlg = GRIORA_Mode;
4027     else if( EQUAL(pszResampling, "GAUSS") )
4028         eResampleAlg = GRIORA_Gauss;
4029     else
4030         CPLError(CE_Warning, CPLE_NotSupported,
4031                 "GDAL_RASTERIO_RESAMPLING = %s not supported", pszResampling);
4032     return eResampleAlg;
4033 }
4034 
4035 /************************************************************************/
4036 /*                    GDALRasterIOGetResampleAlgStr()                   */
4037 /************************************************************************/
4038 
GDALRasterIOGetResampleAlg(GDALRIOResampleAlg eResampleAlg)4039 const char* GDALRasterIOGetResampleAlg(GDALRIOResampleAlg eResampleAlg)
4040 {
4041     switch(eResampleAlg)
4042     {
4043         case GRIORA_NearestNeighbour:
4044             return "NearestNeighbour";
4045         case GRIORA_Bilinear:
4046             return "Bilinear";
4047         case GRIORA_Cubic:
4048             return "Cubic";
4049         case GRIORA_CubicSpline:
4050             return "CubicSpline";
4051         case GRIORA_Lanczos:
4052             return "Lanczos";
4053         case GRIORA_Average:
4054             return "Average";
4055         case GRIORA_RMS:
4056             return "RMS";
4057         case GRIORA_Mode:
4058             return "Mode";
4059         case GRIORA_Gauss:
4060             return "Gauss";
4061         default:
4062             CPLAssert(false);
4063             return "Unknown";
4064     }
4065 }
4066 
4067 /************************************************************************/
4068 /*                   GDALRasterIOExtraArgSetResampleAlg()               */
4069 /************************************************************************/
4070 
GDALRasterIOExtraArgSetResampleAlg(GDALRasterIOExtraArg * psExtraArg,int nXSize,int nYSize,int nBufXSize,int nBufYSize)4071 void GDALRasterIOExtraArgSetResampleAlg(GDALRasterIOExtraArg* psExtraArg,
4072                                         int nXSize, int nYSize,
4073                                         int nBufXSize, int nBufYSize)
4074 {
4075     if( (nBufXSize != nXSize || nBufYSize != nYSize) &&
4076         psExtraArg->eResampleAlg == GRIORA_NearestNeighbour  )
4077     {
4078         const char* pszResampling = CPLGetConfigOption("GDAL_RASTERIO_RESAMPLING", nullptr);
4079         if( pszResampling != nullptr )
4080         {
4081             psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(pszResampling);
4082         }
4083     }
4084 }
4085 
4086 /************************************************************************/
4087 /*                     GDALCanFileAcceptSidecarFile()                   */
4088 /************************************************************************/
4089 
GDALCanFileAcceptSidecarFile(const char * pszFilename)4090 int GDALCanFileAcceptSidecarFile(const char* pszFilename)
4091 {
4092     if( strstr(pszFilename, "/vsicurl/") && strchr(pszFilename, '?') )
4093         return FALSE;
4094     // Do no attempt reading side-car files on /vsisubfile/ (#6241)
4095     if( strncmp(pszFilename, "/vsisubfile/", strlen("/vsisubfile/")) == 0 )
4096         return FALSE;
4097     return TRUE;
4098 }
4099 
4100 /************************************************************************/
4101 /*                   GDALCanReliablyUseSiblingFileList()                */
4102 /************************************************************************/
4103 
4104 /* Try to address https://github.com/OSGeo/gdal/issues/2903 */
4105 /* - On Apple HFS+ filesystem, filenames are stored in a variant of UTF-8 NFD */
4106 /*   (normalization form decomposed). The filesystem takes care of converting */
4107 /*   precomposed form as often coming from user interface to this NFD variant */
4108 /*   See https://stackoverflow.com/questions/6153345/different-utf8-encoding-in-filenames-os-x */
4109 /*   And readdir() will return such NFD variant encoding. Consequently comparing */
4110 /*   the user filename with ones with readdir() is not reliable */
4111 /* - APFS preserves both case and normalization of the filename on disk in all */
4112 /*   variants. In macOS High Sierra, APFS is normalization-insensitive in both */
4113 /*   the case-insensitive and case-sensitive variants, using a hash-based native */
4114 /*   normalization scheme. APFS preserves the normalization of the filename and */
4115 /*   uses hashes of the normalized form of the filename to provide normalization */
4116 /*   insensitivity. */
4117 /*   From https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html */
4118 /*   Issues might still arise if the file has been created using one of the UTF-8 */
4119 /*   encoding (likely the decomposed one if using MacOS specific API), but the */
4120 /*   string passed to GDAL for opening would be with another one (likely the precomposed one) */
GDALCanReliablyUseSiblingFileList(const char * pszFilename)4121 bool GDALCanReliablyUseSiblingFileList(const char* pszFilename)
4122 {
4123 #ifdef __APPLE__
4124     for( int i = 0; pszFilename[i] != 0; ++i )
4125     {
4126         if( reinterpret_cast<const unsigned char*>(pszFilename)[i] > 127 )
4127         {
4128             // non-ASCII character found
4129 
4130             // if this is a network storage, assume no issue
4131             if( strstr(pszFilename, "/vsicurl/") ||
4132                 strstr(pszFilename, "/vsis3/") ||
4133                 strstr(pszFilename, "/vsicurl/") )
4134             {
4135                 return true;
4136             }
4137             return false;
4138         }
4139     }
4140     return true;
4141 #else
4142     (void) pszFilename;
4143     return true;
4144 #endif
4145 }
4146 
4147 /************************************************************************/
4148 /*                    GDALAdjustNoDataCloseToFloatMax()                 */
4149 /************************************************************************/
4150 
GDALAdjustNoDataCloseToFloatMax(double dfVal)4151 double GDALAdjustNoDataCloseToFloatMax(double dfVal)
4152 {
4153     const auto kMaxFloat = std::numeric_limits<float>::max();
4154     if( std::fabs(dfVal - -kMaxFloat) < 1e-10 * kMaxFloat )
4155         return -kMaxFloat;
4156     if( std::fabs(dfVal - kMaxFloat) < 1e-10 * kMaxFloat )
4157         return kMaxFloat;
4158     return dfVal;
4159 }
4160