1 /******************************************************************************
2  *
3  * Project:  MapServer
4  * Purpose:  Commandline App to build tile index for raster files.
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 2001, Frank Warmerdam, DM Solutions Group Inc
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 #include "cpl_conv.h"
32 #include "cpl_string.h"
33 #include "gdal_version.h"
34 #include "gdal.h"
35 #include "ogr_api.h"
36 #include "ogr_srs_api.h"
37 #include "commonutils.h"
38 
39 #include <cmath>
40 
41 CPL_CVSID("$Id: gdaltindex.cpp 327bfdc0f5dd563c3b1c4cbf26d34967c5c9c790 2020-02-28 13:51:40 +0100 Even Rouault $")
42 
43 /************************************************************************/
44 /*                               Usage()                                */
45 /************************************************************************/
46 
Usage(const char * pszErrorMsg)47 static void Usage(const char* pszErrorMsg)
48 
49 {
50     fprintf(stdout, "%s",
51             "\n"
52             "Usage: gdaltindex [-f format] [-tileindex field_name] [-write_absolute_path] \n"
53             "                  [-skip_different_projection] [-t_srs target_srs]\n"
54             "                  [-src_srs_name field_name] [-src_srs_format [AUTO|WKT|EPSG|PROJ]\n"
55             "                  [-lyr_name name] index_file [gdal_file]*\n"
56             "\n"
57             "e.g.\n"
58             "  % gdaltindex doq_index.shp doq/*.tif\n"
59             "\n"
60             "NOTES:\n"
61             "  o The index will be created if it doesn't already exist.\n"
62             "  o The default tile index field is 'location'.\n"
63             "  o Raster filenames will be put in the file exactly as they are specified\n"
64             "    on the commandline unless the option -write_absolute_path is used.\n"
65             "  o If -skip_different_projection is specified, only files with same projection ref\n"
66             "    as files already inserted in the tileindex will be inserted (unless t_srs is specified).\n"
67             "  o If -t_srs is specified, geometries of input files will be transformed to the desired\n"
68             "    target coordinate reference system.\n"
69             "    Note that using this option generates files that are NOT compatible with MapServer < 6.4.\n"
70             "  o Simple rectangular polygons are generated in the same coordinate reference system\n"
71             "    as the rasters, or in target reference system if the -t_srs option is used.\n");
72 
73     if( pszErrorMsg != nullptr )
74         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
75 
76     exit(1);
77 }
78 
79 /************************************************************************/
80 /*                                main()                                */
81 /************************************************************************/
82 
83 #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
84     do { if (iArg + nExtraArg >= argc) \
85         Usage(CPLSPrintf("%s option requires %d argument(s)", \
86                          argv[iArg], nExtraArg)); } while( false )
87 
88 typedef enum
89 {
90     FORMAT_AUTO,
91     FORMAT_WKT,
92     FORMAT_EPSG,
93     FORMAT_PROJ
94 } SrcSRSFormat;
95 
MAIN_START(argc,argv)96 MAIN_START(argc, argv)
97 {
98     // Check that we are running against at least GDAL 1.4.
99     // Note to developers: if we use newer API, please change the requirement.
100     if( atoi(GDALVersionInfo("VERSION_NUM")) < 1400 )
101     {
102         fprintf(stderr,
103                 "At least, GDAL >= 1.4.0 is required for this version of %s, "
104                 "which was compiled against GDAL %s\n",
105                 argv[0], GDAL_RELEASE_NAME);
106         exit(1);
107     }
108 
109     GDALAllRegister();
110     OGRRegisterAll();
111 
112     argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
113     if( argc < 1 )
114         exit( -argc );
115 
116 /* -------------------------------------------------------------------- */
117 /*      Get commandline arguments other than the GDAL raster filenames. */
118 /* -------------------------------------------------------------------- */
119     const char* pszIndexLayerName = nullptr;
120     const char *index_filename = nullptr;
121     const char *tile_index = "location";
122     const char* pszDriverName = nullptr;
123     size_t nMaxFieldSize = 254;
124     bool write_absolute_path = false;
125     char* current_path = nullptr;
126     bool skip_different_projection = false;
127     const char *pszTargetSRS = "";
128     bool bSetTargetSRS = false;
129     const char* pszSrcSRSName = nullptr;
130     int i_SrcSRSName = -1;
131     bool bSrcSRSFormatSpecified = false;
132     SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
133 
134     int iArg = 1;  // Used after for.
135     for( ; iArg < argc; iArg++ )
136     {
137         if( EQUAL(argv[iArg], "--utility_version") )
138         {
139             printf("%s was compiled against GDAL %s and is running against "
140                    "GDAL %s\n",
141                    argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
142             CSLDestroy( argv );
143             return 0;
144         }
145         else if( EQUAL(argv[iArg],"--help") )
146             Usage(nullptr);
147         else if( (strcmp(argv[iArg],"-f") == 0 || strcmp(argv[iArg],"-of") == 0) )
148         {
149             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
150             pszDriverName = argv[++iArg];
151         }
152         else if( strcmp(argv[iArg],"-lyr_name") == 0 )
153         {
154             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
155             pszIndexLayerName = argv[++iArg];
156         }
157         else if( strcmp(argv[iArg],"-tileindex") == 0 )
158         {
159             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
160             tile_index = argv[++iArg];
161         }
162         else if( strcmp(argv[iArg],"-t_srs") == 0 )
163         {
164             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
165             pszTargetSRS = argv[++iArg];
166             bSetTargetSRS = true;
167         }
168         else if ( strcmp(argv[iArg],"-write_absolute_path") == 0 )
169         {
170             write_absolute_path = true;
171         }
172         else if ( strcmp(argv[iArg],"-skip_different_projection") == 0 )
173         {
174             skip_different_projection = true;
175         }
176         else if( strcmp(argv[iArg], "-src_srs_name") == 0 )
177         {
178             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
179             pszSrcSRSName = argv[++iArg];
180         }
181         else if( strcmp(argv[iArg], "-src_srs_format") == 0 )
182         {
183             const char* pszFormat;
184             bSrcSRSFormatSpecified = true;
185             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
186             pszFormat = argv[++iArg];
187             if( EQUAL(pszFormat, "AUTO") )
188                 eSrcSRSFormat = FORMAT_AUTO;
189             else if( EQUAL(pszFormat, "WKT") )
190                 eSrcSRSFormat = FORMAT_WKT;
191             else if( EQUAL(pszFormat, "EPSG") )
192                 eSrcSRSFormat = FORMAT_EPSG;
193             else if( EQUAL(pszFormat, "PROJ") )
194                 eSrcSRSFormat = FORMAT_PROJ;
195         }
196         else if( argv[iArg][0] == '-' )
197             Usage(CPLSPrintf("Unknown option name '%s'", argv[iArg]));
198         else if( index_filename == nullptr )
199         {
200             index_filename = argv[iArg];
201             iArg++;
202             break;
203         }
204     }
205 
206     if( index_filename == nullptr )
207         Usage("No index filename specified.");
208     if( iArg == argc )
209         Usage("No file to index specified.");
210     if( bSrcSRSFormatSpecified && pszSrcSRSName == nullptr )
211         Usage("-src_srs_name must be specified when -src_srs_format is "
212               "specified.");
213 
214 /* -------------------------------------------------------------------- */
215 /*      Create and validate target SRS if given.                        */
216 /* -------------------------------------------------------------------- */
217     OGRSpatialReferenceH hTargetSRS = nullptr;
218     if( bSetTargetSRS )
219     {
220         if( skip_different_projection )
221         {
222             fprintf( stderr,
223                      "Warning : -skip_different_projection does not apply "
224                      "when -t_srs is requested.\n" );
225         }
226         hTargetSRS = OSRNewSpatialReference("");
227         OSRSetAxisMappingStrategy(hTargetSRS, OAMS_TRADITIONAL_GIS_ORDER);
228         // coverity[tainted_data]
229         if( OSRSetFromUserInput( hTargetSRS, pszTargetSRS ) != CE_None )
230         {
231             OSRDestroySpatialReference( hTargetSRS );
232             fprintf( stderr, "Invalid target SRS `%s'.\n",
233                      pszTargetSRS );
234             exit(1);
235         }
236     }
237 
238 /* -------------------------------------------------------------------- */
239 /*      Open or create the target datasource                            */
240 /* -------------------------------------------------------------------- */
241     GDALDatasetH hTileIndexDS = GDALOpenEx(
242         index_filename, GDAL_OF_VECTOR | GDAL_OF_UPDATE, nullptr, nullptr, nullptr );
243     OGRLayerH hLayer = nullptr;
244     CPLString osFormat;
245     if( hTileIndexDS != nullptr )
246     {
247         GDALDriverH hDriver = GDALGetDatasetDriver(hTileIndexDS);
248         if( hDriver )
249             osFormat = GDALGetDriverShortName(hDriver);
250 
251         if( GDALDatasetGetLayerCount(hTileIndexDS) == 1 )
252         {
253             hLayer = GDALDatasetGetLayer(hTileIndexDS, 0);
254         }
255         else
256         {
257             if( pszIndexLayerName == nullptr )
258             {
259                 printf( "-lyr_name must be specified.\n" );
260                 exit( 1 );
261             }
262             CPLPushErrorHandler(CPLQuietErrorHandler);
263             hLayer = GDALDatasetGetLayerByName(hTileIndexDS, pszIndexLayerName);
264             CPLPopErrorHandler();
265         }
266     }
267     else
268     {
269         printf( "Creating new index file...\n" );
270         if( pszDriverName == nullptr )
271         {
272             std::vector<CPLString> aoDrivers =
273                 GetOutputDriversFor(index_filename, GDAL_OF_VECTOR);
274             if( aoDrivers.empty() )
275             {
276                 CPLError( CE_Failure, CPLE_AppDefined,
277                         "Cannot guess driver for %s", index_filename);
278                 exit( 10 );
279             }
280             else
281             {
282                 if( aoDrivers.size() > 1 )
283                 {
284                     CPLError( CE_Warning, CPLE_AppDefined,
285                             "Several drivers matching %s extension. Using %s",
286                             CPLGetExtension(index_filename), aoDrivers[0].c_str() );
287                 }
288                 osFormat = aoDrivers[0];
289             }
290         }
291         else
292         {
293             osFormat = pszDriverName;
294         }
295         if( !EQUAL(osFormat, "ESRI Shapefile") )
296             nMaxFieldSize = 0;
297 
298 
299         GDALDriverH hDriver = GDALGetDriverByName( osFormat.c_str() );
300         if( hDriver == nullptr )
301         {
302             printf( "%s driver not available.\n", osFormat.c_str() );
303             exit( 1 );
304         }
305 
306         hTileIndexDS =
307             GDALCreate( hDriver, index_filename, 0, 0, 0, GDT_Unknown, nullptr );
308     }
309 
310     if( hTileIndexDS != nullptr && hLayer == nullptr )
311     {
312         OGRSpatialReferenceH hSpatialRef = nullptr;
313         char* pszLayerName = nullptr;
314         if( pszIndexLayerName == nullptr )
315         {
316             VSIStatBuf sStat;
317             if( EQUAL(osFormat, "ESRI Shapefile") ||
318                 VSIStat(index_filename, &sStat) == 0 )
319             {
320                 pszLayerName = CPLStrdup(CPLGetBasename(index_filename));
321             }
322             else
323             {
324                 printf( "-lyr_name must be specified.\n" );
325                 exit( 1 );
326             }
327         }
328         else
329         {
330             pszLayerName = CPLStrdup(pszIndexLayerName);
331         }
332 
333         /* get spatial reference for output file from target SRS (if set) */
334         /* or from first input file */
335         if( bSetTargetSRS )
336         {
337             hSpatialRef = OSRClone( hTargetSRS );
338         }
339         else
340         {
341             GDALDatasetH hDS = GDALOpen( argv[iArg], GA_ReadOnly );
342             if( hDS )
343             {
344                 const char* pszWKT = GDALGetProjectionRef(hDS);
345                 if (pszWKT != nullptr && pszWKT[0] != '\0')
346                 {
347                     hSpatialRef = OSRNewSpatialReference(pszWKT);
348                     OSRSetAxisMappingStrategy(hSpatialRef, OAMS_TRADITIONAL_GIS_ORDER);
349                 }
350                 GDALClose(hDS);
351             }
352         }
353 
354         hLayer =
355             GDALDatasetCreateLayer( hTileIndexDS, pszLayerName, hSpatialRef,
356                                 wkbPolygon, nullptr );
357         CPLFree(pszLayerName);
358         if( hSpatialRef )
359             OSRRelease(hSpatialRef);
360 
361         if( hLayer )
362         {
363             OGRFieldDefnH hFieldDefn = OGR_Fld_Create( tile_index, OFTString );
364             if( nMaxFieldSize )
365                 OGR_Fld_SetWidth( hFieldDefn, static_cast<int>(nMaxFieldSize));
366             OGR_L_CreateField( hLayer, hFieldDefn, TRUE );
367             OGR_Fld_Destroy(hFieldDefn);
368             if( pszSrcSRSName != nullptr )
369             {
370                 hFieldDefn = OGR_Fld_Create( pszSrcSRSName, OFTString );
371                 if( nMaxFieldSize )
372                     OGR_Fld_SetWidth(hFieldDefn,
373                                      static_cast<int>(nMaxFieldSize));
374                 OGR_L_CreateField( hLayer, hFieldDefn, TRUE );
375                 OGR_Fld_Destroy(hFieldDefn);
376             }
377         }
378     }
379 
380     if( hTileIndexDS == nullptr || hLayer == nullptr )
381     {
382         fprintf( stderr, "Unable to open/create shapefile `%s'.\n",
383                  index_filename );
384         exit(2);
385     }
386 
387     OGRFeatureDefnH hFDefn = OGR_L_GetLayerDefn(hLayer);
388 
389     const int ti_field = OGR_FD_GetFieldIndex( hFDefn, tile_index );
390     if( ti_field < 0 )
391     {
392         fprintf( stderr, "Unable to find field `%s' in file `%s'.\n",
393                  tile_index, index_filename );
394         exit(2);
395     }
396 
397     if( pszSrcSRSName != nullptr )
398         i_SrcSRSName = OGR_FD_GetFieldIndex( hFDefn, pszSrcSRSName );
399 
400     // Load in memory existing file names in SHP.
401     int nExistingFiles = static_cast<int>(OGR_L_GetFeatureCount(hLayer, FALSE));
402     if( nExistingFiles < 0)
403         nExistingFiles = 0;
404 
405     char** existingFilesTab = nullptr;
406     bool alreadyExistingProjectionRefValid = false;
407     char* alreadyExistingProjectionRef = nullptr;
408     if( nExistingFiles > 0 )
409     {
410         OGRFeatureH hFeature = nullptr;
411         existingFilesTab = static_cast<char **>(
412             CPLMalloc(nExistingFiles * sizeof(char*)));
413         for( int i = 0; i < nExistingFiles; i++ )
414         {
415             hFeature = OGR_L_GetNextFeature(hLayer);
416             existingFilesTab[i] =
417                 CPLStrdup(OGR_F_GetFieldAsString( hFeature, ti_field ));
418             if( i == 0 )
419             {
420                 GDALDatasetH hDS = GDALOpen(existingFilesTab[i], GA_ReadOnly );
421                 if( hDS )
422                 {
423                     alreadyExistingProjectionRefValid = true;
424                     alreadyExistingProjectionRef =
425                         CPLStrdup(GDALGetProjectionRef(hDS));
426                     GDALClose(hDS);
427                 }
428             }
429             OGR_F_Destroy( hFeature );
430         }
431     }
432 
433     if( write_absolute_path )
434     {
435         current_path = CPLGetCurrentDir();
436         if (current_path == nullptr)
437         {
438             fprintf( stderr,
439                      "This system does not support the CPLGetCurrentDir call. "
440                      "The option -write_absolute_path will have no effect\n" );
441             write_absolute_path = FALSE;
442         }
443     }
444 
445 /* -------------------------------------------------------------------- */
446 /*      loop over GDAL files, processing.                               */
447 /* -------------------------------------------------------------------- */
448     for( ; iArg < argc; iArg++ )
449     {
450         char *fileNameToWrite = nullptr;
451         VSIStatBuf sStatBuf;
452 
453         // Make sure it is a file before building absolute path name.
454         if( write_absolute_path && CPLIsFilenameRelative( argv[iArg] ) &&
455             VSIStat( argv[iArg], &sStatBuf ) == 0 )
456         {
457             fileNameToWrite =
458                 CPLStrdup(CPLProjectRelativeFilename(current_path, argv[iArg]));
459         }
460         else
461         {
462             fileNameToWrite = CPLStrdup(argv[iArg]);
463         }
464 
465         // Checks that file is not already in tileindex.
466         {
467             int i = 0;  // Used after for.
468             for( ; i < nExistingFiles; i++ )
469             {
470                 if (EQUAL(fileNameToWrite, existingFilesTab[i]))
471                 {
472                     fprintf(stderr,
473                             "File %s is already in tileindex. Skipping it.\n",
474                             fileNameToWrite);
475                     break;
476                 }
477             }
478             if (i != nExistingFiles)
479             {
480                 CPLFree(fileNameToWrite);
481                 continue;
482             }
483         }
484 
485         GDALDatasetH hDS = GDALOpen( argv[iArg], GA_ReadOnly );
486         if( hDS == nullptr )
487         {
488             fprintf( stderr, "Unable to open %s, skipping.\n",
489                      argv[iArg] );
490             CPLFree(fileNameToWrite);
491             continue;
492         }
493 
494         double adfGeoTransform[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
495         GDALGetGeoTransform( hDS, adfGeoTransform );
496         if( adfGeoTransform[0] == 0.0
497             && adfGeoTransform[1] == 1.0
498             && adfGeoTransform[3] == 0.0
499             && std::abs(adfGeoTransform[5]) == 1.0 )
500         {
501             fprintf( stderr,
502                      "It appears no georeferencing is available for\n"
503                      "`%s', skipping.\n",
504                      argv[iArg] );
505             GDALClose( hDS );
506             CPLFree(fileNameToWrite);
507             continue;
508         }
509 
510         const char *projectionRef = GDALGetProjectionRef(hDS);
511 
512         // If not set target srs, test that the current file uses same
513         // projection as others.
514         if( !bSetTargetSRS )
515         {
516             if( alreadyExistingProjectionRefValid )
517             {
518                 int projectionRefNotNull, alreadyExistingProjectionRefNotNull;
519                 projectionRefNotNull = projectionRef && projectionRef[0];
520                 alreadyExistingProjectionRefNotNull =
521                     alreadyExistingProjectionRef &&
522                     alreadyExistingProjectionRef[0];
523                 if ((projectionRefNotNull &&
524                      alreadyExistingProjectionRefNotNull &&
525                      EQUAL(projectionRef, alreadyExistingProjectionRef) == 0) ||
526                     (projectionRefNotNull != alreadyExistingProjectionRefNotNull))
527                 {
528                     fprintf(
529                         stderr,
530                         "Warning : %s is not using the same projection system "
531                         "as other files in the tileindex.\n"
532                         "This may cause problems when using it in MapServer "
533                         "for example.\n"
534                         "Use -t_srs option to set target projection system "
535                         "(not supported by MapServer).\n"
536                         "%s\n", argv[iArg],
537                         skip_different_projection ? "Skipping this file." : "");
538                     if( skip_different_projection )
539                     {
540                         CPLFree(fileNameToWrite);
541                         GDALClose( hDS );
542                         continue;
543                     }
544                 }
545             }
546             else
547             {
548                 alreadyExistingProjectionRefValid = true;
549                 alreadyExistingProjectionRef = CPLStrdup(projectionRef);
550             }
551         }
552 
553         const int nXSize = GDALGetRasterXSize( hDS );
554         const int nYSize = GDALGetRasterYSize( hDS );
555 
556         double adfX[5] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
557         double adfY[5] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
558         adfX[0] = adfGeoTransform[0]
559             + 0 * adfGeoTransform[1]
560             + 0 * adfGeoTransform[2];
561         adfY[0] = adfGeoTransform[3]
562             + 0 * adfGeoTransform[4]
563             + 0 * adfGeoTransform[5];
564 
565         adfX[1] = adfGeoTransform[0]
566             + nXSize * adfGeoTransform[1]
567             + 0 * adfGeoTransform[2];
568         adfY[1] = adfGeoTransform[3]
569             + nXSize * adfGeoTransform[4]
570             + 0 * adfGeoTransform[5];
571 
572         adfX[2] = adfGeoTransform[0]
573             + nXSize * adfGeoTransform[1]
574             + nYSize * adfGeoTransform[2];
575         adfY[2] = adfGeoTransform[3]
576             + nXSize * adfGeoTransform[4]
577             + nYSize * adfGeoTransform[5];
578 
579         adfX[3] = adfGeoTransform[0]
580             + 0 * adfGeoTransform[1]
581             + nYSize * adfGeoTransform[2];
582         adfY[3] = adfGeoTransform[3]
583             + 0 * adfGeoTransform[4]
584             + nYSize * adfGeoTransform[5];
585 
586         adfX[4] = adfGeoTransform[0]
587             + 0 * adfGeoTransform[1]
588             + 0 * adfGeoTransform[2];
589         adfY[4] = adfGeoTransform[3]
590             + 0 * adfGeoTransform[4]
591             + 0 * adfGeoTransform[5];
592 
593         OGRSpatialReferenceH hSourceSRS = nullptr;
594         if( (bSetTargetSRS || i_SrcSRSName >= 0) &&
595             projectionRef != nullptr &&
596             projectionRef[0] != '\0' )
597         {
598             hSourceSRS = OSRNewSpatialReference( projectionRef );
599             OSRSetAxisMappingStrategy(hSourceSRS, OAMS_TRADITIONAL_GIS_ORDER);
600         }
601 
602         // If set target srs, do the forward transformation of all points.
603         if( bSetTargetSRS && projectionRef != nullptr && projectionRef[0] != '\0' )
604         {
605             OGRCoordinateTransformationH hCT = nullptr;
606             if( hSourceSRS && !OSRIsSame( hSourceSRS, hTargetSRS ) )
607             {
608                 hCT = OCTNewCoordinateTransformation( hSourceSRS, hTargetSRS );
609                 if( hCT == nullptr || !OCTTransform( hCT, 5, adfX, adfY, nullptr ) )
610                 {
611                     fprintf(
612                         stderr,
613                         "Warning : unable to transform points from source "
614                         "SRS `%s' to target SRS `%s'\n"
615                         "for file `%s' - file skipped\n",
616                         projectionRef, pszTargetSRS, fileNameToWrite );
617                     if( hCT )
618                         OCTDestroyCoordinateTransformation( hCT );
619                     OSRDestroySpatialReference( hSourceSRS );
620                     continue;
621                 }
622                 OCTDestroyCoordinateTransformation( hCT );
623             }
624         }
625 
626         OGRFeatureH hFeature = OGR_F_Create( OGR_L_GetLayerDefn( hLayer ) );
627         OGR_F_SetFieldString( hFeature, ti_field, fileNameToWrite );
628 
629         if( i_SrcSRSName >= 0 && hSourceSRS != nullptr )
630         {
631             const char* pszAuthorityCode =
632                 OSRGetAuthorityCode(hSourceSRS, nullptr);
633             const char* pszAuthorityName =
634                 OSRGetAuthorityName(hSourceSRS, nullptr);
635             if( eSrcSRSFormat == FORMAT_AUTO )
636             {
637                 if( pszAuthorityName != nullptr && pszAuthorityCode != nullptr )
638                 {
639                     OGR_F_SetFieldString(
640                         hFeature, i_SrcSRSName,
641                         CPLSPrintf("%s:%s",
642                                    pszAuthorityName, pszAuthorityCode) );
643                 }
644                 else if( nMaxFieldSize == 0 ||
645                          strlen(projectionRef) <= nMaxFieldSize )
646                 {
647                     OGR_F_SetFieldString(hFeature, i_SrcSRSName, projectionRef);
648                 }
649                 else
650                 {
651                     char* pszProj4 = nullptr;
652                     if( OSRExportToProj4(hSourceSRS, &pszProj4) == OGRERR_NONE )
653                     {
654                         OGR_F_SetFieldString( hFeature, i_SrcSRSName,
655                                               pszProj4 );
656                         CPLFree(pszProj4);
657                     }
658                     else
659                     {
660                         OGR_F_SetFieldString( hFeature, i_SrcSRSName,
661                                               projectionRef );
662                     }
663                 }
664             }
665             else if( eSrcSRSFormat == FORMAT_WKT )
666             {
667                 if( nMaxFieldSize == 0 ||
668                     strlen(projectionRef) <= nMaxFieldSize )
669                 {
670                     OGR_F_SetFieldString( hFeature, i_SrcSRSName,
671                                           projectionRef );
672                 }
673                 else
674                 {
675                     fprintf(stderr,
676                             "Cannot write WKT for file %s as it is too long!\n",
677                             fileNameToWrite);
678                 }
679             }
680             else if( eSrcSRSFormat == FORMAT_PROJ )
681             {
682                 char* pszProj4 = nullptr;
683                 if( OSRExportToProj4(hSourceSRS, &pszProj4) == OGRERR_NONE )
684                 {
685                     OGR_F_SetFieldString( hFeature, i_SrcSRSName, pszProj4 );
686                     CPLFree(pszProj4);
687                 }
688             }
689             else if( eSrcSRSFormat == FORMAT_EPSG )
690             {
691                 if( pszAuthorityName != nullptr && pszAuthorityCode != nullptr )
692                     OGR_F_SetFieldString(
693                         hFeature, i_SrcSRSName,
694                         CPLSPrintf("%s:%s",
695                                    pszAuthorityName, pszAuthorityCode) );
696             }
697         }
698         if( hSourceSRS )
699             OSRDestroySpatialReference( hSourceSRS );
700 
701         OGRGeometryH hPoly = OGR_G_CreateGeometry(wkbPolygon);
702         OGRGeometryH hRing = OGR_G_CreateGeometry(wkbLinearRing);
703         for( int k = 0; k < 5; k++ )
704             OGR_G_SetPoint_2D(hRing, k, adfX[k], adfY[k]);
705         OGR_G_AddGeometryDirectly( hPoly, hRing );
706         OGR_F_SetGeometryDirectly( hFeature, hPoly );
707 
708         if( OGR_L_CreateFeature( hLayer, hFeature ) != OGRERR_NONE )
709         {
710            printf( "Failed to create feature in shapefile.\n" );
711            break;
712         }
713 
714         OGR_F_Destroy( hFeature );
715 
716         CPLFree(fileNameToWrite);
717 
718         GDALClose( hDS );
719     }
720 
721     CPLFree(current_path);
722 
723     if (nExistingFiles)
724     {
725         for( int i = 0; i < nExistingFiles; i++ )
726         {
727             CPLFree(existingFilesTab[i]);
728         }
729         CPLFree(existingFilesTab);
730     }
731     CPLFree(alreadyExistingProjectionRef);
732 
733     if ( hTargetSRS )
734         OSRDestroySpatialReference( hTargetSRS );
735 
736     GDALClose( hTileIndexDS );
737 
738     GDALDestroyDriverManager();
739     OGRCleanupAll();
740     CSLDestroy(argv);
741 
742     exit( 0 );
743 }
744 MAIN_END
745