1 /******************************************************************************
2  *
3  * Project:  GDAL Utilities
4  * Purpose:  Common utility routines
5  * Author:   Even Rouault, <even dot rouault at spatialys.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2011-2012, Even Rouault <even dot rouault at spatialys.com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "commonutils.h"
30 
31 #include <cstdio>
32 #include <cstring>
33 
34 #include <string>
35 
36 #include "cpl_conv.h"
37 #include "cpl_string.h"
38 #include "gdal.h"
39 
40 CPL_CVSID("$Id: commonutils.cpp a7cdc486d524bef67fe59ab48bff81c8880be984 2019-06-22 19:30:01 +0200 Even Rouault $")
41 
42 /* -------------------------------------------------------------------- */
43 /*                   DoesDriverHandleExtension()                        */
44 /* -------------------------------------------------------------------- */
45 
DoesDriverHandleExtension(GDALDriverH hDriver,const char * pszExt)46 static bool DoesDriverHandleExtension( GDALDriverH hDriver, const char* pszExt )
47 {
48     bool bRet = false;
49     const char* pszDriverExtensions =
50         GDALGetMetadataItem( hDriver, GDAL_DMD_EXTENSIONS, nullptr );
51     if( pszDriverExtensions )
52     {
53         char** papszTokens = CSLTokenizeString( pszDriverExtensions );
54         for( int j = 0; papszTokens[j]; j++ )
55         {
56             if( EQUAL(pszExt, papszTokens[j]) )
57             {
58                 bRet = true;
59                 break;
60             }
61         }
62         CSLDestroy(papszTokens);
63     }
64     return bRet;
65 }
66 
67 /* -------------------------------------------------------------------- */
68 /*                         GetOutputDriversFor()                        */
69 /* -------------------------------------------------------------------- */
70 
GetOutputDriversFor(const char * pszDestFilename,int nFlagRasterVector)71 std::vector<CPLString> GetOutputDriversFor(const char* pszDestFilename,
72                                            int nFlagRasterVector)
73 {
74     std::vector<CPLString> aoDriverList;
75 
76     CPLString osExt = CPLGetExtension(pszDestFilename);
77     if( EQUAL(osExt, "zip") &&
78             (CPLString(pszDestFilename).endsWith(".shp.zip") ||
79              CPLString(pszDestFilename).endsWith(".SHP.ZIP")) )
80     {
81         osExt = "shp.zip";
82     }
83     const int nDriverCount = GDALGetDriverCount();
84     for( int i = 0; i < nDriverCount; i++ )
85     {
86         GDALDriverH hDriver = GDALGetDriver(i);
87         if( (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, nullptr ) != nullptr ||
88              GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, nullptr ) != nullptr ) &&
89             (((nFlagRasterVector & GDAL_OF_RASTER) &&
90                 GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, nullptr ) != nullptr) ||
91             ((nFlagRasterVector & GDAL_OF_VECTOR) &&
92                 GDALGetMetadataItem( hDriver, GDAL_DCAP_VECTOR, nullptr ) != nullptr)) )
93         {
94             if( !osExt.empty() && DoesDriverHandleExtension(hDriver, osExt) )
95             {
96                 aoDriverList.push_back( GDALGetDriverShortName(hDriver) );
97             }
98             else
99             {
100                 const char* pszPrefix = GDALGetMetadataItem(hDriver,
101                     GDAL_DMD_CONNECTION_PREFIX, nullptr);
102                 if( pszPrefix && STARTS_WITH_CI(pszDestFilename, pszPrefix) )
103                 {
104                     aoDriverList.push_back( GDALGetDriverShortName(hDriver) );
105                 }
106             }
107         }
108     }
109 
110     // GMT is registered before netCDF for opening reasons, but we want
111     // netCDF to be used by default for output.
112     if( EQUAL(osExt, "nc") && aoDriverList.size() == 2 &&
113         EQUAL(aoDriverList[0], "GMT") && EQUAL(aoDriverList[1], "NETCDF") )
114     {
115         aoDriverList.clear();
116         aoDriverList.push_back("NETCDF");
117         aoDriverList.push_back("GMT");
118     }
119 
120     return aoDriverList;
121 }
122 
123 /* -------------------------------------------------------------------- */
124 /*                      GetOutputDriverForRaster()                      */
125 /* -------------------------------------------------------------------- */
126 
GetOutputDriverForRaster(const char * pszDestFilename)127 CPLString GetOutputDriverForRaster(const char* pszDestFilename)
128 {
129     CPLString osFormat;
130     std::vector<CPLString> aoDrivers =
131         GetOutputDriversFor(pszDestFilename, GDAL_OF_RASTER);
132     CPLString osExt(CPLGetExtension(pszDestFilename));
133     if( aoDrivers.empty() )
134     {
135         if( osExt.empty() )
136         {
137             osFormat = "GTiff";
138         }
139         else
140         {
141             CPLError( CE_Failure, CPLE_AppDefined,
142                     "Cannot guess driver for %s", pszDestFilename);
143             return "";
144         }
145     }
146     else
147     {
148         if( aoDrivers.size() > 1 )
149         {
150             CPLError( CE_Warning, CPLE_AppDefined,
151                       "Several drivers matching %s extension. Using %s",
152                       osExt.c_str(),
153                       aoDrivers[0].c_str() );
154         }
155         osFormat = aoDrivers[0];
156     }
157     CPLDebug("GDAL", "Using %s driver", osFormat.c_str());
158     return osFormat;
159 }
160 
161 /* -------------------------------------------------------------------- */
162 /*                        EarlySetConfigOptions()                       */
163 /* -------------------------------------------------------------------- */
164 
EarlySetConfigOptions(int argc,char ** argv)165 void EarlySetConfigOptions( int argc, char ** argv )
166 {
167     // Must process some config options before GDALAllRegister() or
168     // OGRRegisterAll(), but we can't call GDALGeneralCmdLineProcessor() or
169     // OGRGeneralCmdLineProcessor(), because it needs the drivers to be
170     // registered for the --format or --formats options.
171     for( int i = 1; i < argc; i++ )
172     {
173         if( EQUAL(argv[i],"--config") && i + 2 < argc )
174         {
175             CPLSetConfigOption( argv[i+1], argv[i+2] );
176 
177             i += 2;
178         }
179         else if( EQUAL(argv[i],"--debug") && i + 1 < argc )
180         {
181             CPLSetConfigOption( "CPL_DEBUG", argv[i+1] );
182             i += 1;
183         }
184     }
185 }
186