LCOV - code coverage report
Current view: top level - apps - ogrtindex.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 86 390 22.1 %
Date: 2025-01-18 12:42:00 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Program to generate a UMN MapServer compatible tile index for a
       5             :  *           set of OGR data sources.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2002, Frank Warmerdam
      10             :  * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : 
      17             : #include <cassert>
      18             : #include <vector>
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_string.h"
      22             : #include "gdal_version.h"
      23             : #include "gdalargumentparser.h"
      24             : #include "ogr_api.h"
      25             : #include "ogrsf_frmts.h"
      26             : #include "commonutils.h"
      27             : 
      28             : typedef enum
      29             : {
      30             :     FORMAT_AUTO,
      31             :     FORMAT_WKT,
      32             :     FORMAT_EPSG,
      33             :     FORMAT_PROJ
      34             : } SrcSRSFormat;
      35             : 
      36             : /**
      37             :  * @brief Makes sure the GDAL library is properly cleaned up before exiting.
      38             :  * @param nCode exit code
      39             :  * @todo Move to API
      40             :  */
      41           2 : static void GDALExit(int nCode)
      42             : {
      43           2 :     GDALDestroy();
      44           2 :     exit(nCode);
      45             : }
      46             : 
      47             : /************************************************************************/
      48             : /*                                main()                                */
      49             : /************************************************************************/
      50             : 
      51           2 : MAIN_START(nArgc, papszArgv)
      52             : 
      53             : {
      54             : 
      55             :     // Check strict compilation and runtime library version as we use C++ API.
      56           2 :     if (!GDAL_CHECK_VERSION(papszArgv[0]))
      57           0 :         GDALExit(1);
      58             : 
      59           2 :     EarlySetConfigOptions(nArgc, papszArgv);
      60             : 
      61             :     /* -------------------------------------------------------------------- */
      62             :     /*      Processing command line arguments.                              */
      63             :     /* -------------------------------------------------------------------- */
      64           2 :     bool bLayersWildcarded = true;
      65           2 :     std::string osOutputFormat;
      66           2 :     std::string osTileIndexField;
      67           2 :     std::string osOutputName;
      68           2 :     bool bWriteAbsolutePath{false};
      69           2 :     bool bSkipDifferentProjection{false};
      70           2 :     char *pszCurrentPath = nullptr;
      71           2 :     bool bAcceptDifferentSchemas{false};
      72           2 :     bool bFirstWarningForNonMatchingAttributes = true;
      73           2 :     std::string osTargetSRS;
      74           2 :     bool bSetTargetSRS = false;
      75           2 :     std::string osSrcSRSName;
      76           2 :     int i_SrcSRSName = -1;
      77           2 :     SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
      78           2 :     size_t nMaxFieldSize = 254;
      79           2 :     std::vector<std::string> aosSrcDatasets;
      80           2 :     std::vector<std::string> aosLayerNames;
      81           2 :     std::vector<int> anLayerNumbers;
      82             : 
      83           4 :     GDALArgumentParser argParser{"ogrtindex", true};
      84             : 
      85             :     argParser.add_description(
      86             :         _("Program to generate a UMN MapServer compatible "
      87           2 :           "tile index for a set of OGR data sources."));
      88             : 
      89             :     argParser.add_epilog(
      90             :         _("For more details, see the full documentation for ogrtindex "
      91           2 :           "at\nhttps://gdal.org/programs/ogrtindex.html"));
      92             : 
      93           2 :     argParser.add_argument("-lnum")
      94           4 :         .metavar("<n>")
      95           2 :         .append()
      96           2 :         .scan<'i', int>()
      97           2 :         .store_into(anLayerNumbers)
      98             :         .help(
      99           2 :             _("Add layer number <n> from each source file in the tile index."));
     100             : 
     101           2 :     argParser.add_argument("-lname")
     102           4 :         .metavar("<name>")
     103           2 :         .append()
     104           2 :         .store_into(aosLayerNames)
     105             :         .help(_(
     106           2 :             "Add layer named <name> from each source file in the tile index."));
     107             : 
     108           2 :     argParser.add_output_format_argument(osOutputFormat);
     109             : 
     110           2 :     argParser.add_argument("-tileindex")
     111           4 :         .metavar("<tileindex>")
     112           2 :         .default_value("LOCATION")
     113           2 :         .nargs(1)
     114           2 :         .store_into(osTileIndexField)
     115           2 :         .help(_("Name to use for the dataset name."));
     116             : 
     117           2 :     argParser.add_argument("-write_absolute_path")
     118           2 :         .flag()
     119           2 :         .store_into(bWriteAbsolutePath)
     120           2 :         .help(_("Write absolute path of the source file in the tile index."));
     121             : 
     122           2 :     argParser.add_argument("-skip_different_projection")
     123           2 :         .flag()
     124           2 :         .store_into(bSkipDifferentProjection)
     125             :         .help(_("Skip layers that are not in the same projection as the first "
     126           2 :                 "layer."));
     127             : 
     128           2 :     argParser.add_argument("-t_srs")
     129           4 :         .metavar("<srs_def>")
     130           2 :         .store_into(osTargetSRS)
     131             :         .help(
     132             :             _("Extent of input files will be transformed to the desired target "
     133           2 :               "coordinate reference system."));
     134             : 
     135           2 :     argParser.add_argument("-src_srs_name")
     136           4 :         .metavar("<field_name>")
     137           2 :         .store_into(osSrcSRSName)
     138           2 :         .help(_("Name of the field to store the SRS of each tile."));
     139             : 
     140           2 :     argParser.add_argument("-src_srs_format")
     141           4 :         .metavar("{AUTO|WKT|EPSG|PROJ}")
     142           2 :         .choices("AUTO", "WKT", "EPSG", "PROJ")
     143             :         .action(
     144           0 :             [&eSrcSRSFormat](const auto &f)
     145             :             {
     146           0 :                 if (f == "WKT")
     147           0 :                     eSrcSRSFormat = FORMAT_WKT;
     148           0 :                 else if (f == "EPSG")
     149           0 :                     eSrcSRSFormat = FORMAT_EPSG;
     150           0 :                 else if (f == "PROJ")
     151           0 :                     eSrcSRSFormat = FORMAT_PROJ;
     152             :                 else
     153           0 :                     eSrcSRSFormat = FORMAT_AUTO;
     154           2 :             })
     155           2 :         .help(_("Format of the source SRS to store in the tile index file."));
     156             : 
     157           2 :     argParser.add_argument("-accept_different_schemas")
     158           2 :         .flag()
     159           2 :         .store_into(bAcceptDifferentSchemas)
     160             :         .help(_(
     161           2 :             "Disable check for identical schemas for layers in input files."));
     162             : 
     163           2 :     argParser.add_argument("output_dataset")
     164           4 :         .metavar("<output_dataset>")
     165           2 :         .store_into(osOutputName)
     166           2 :         .help(_("Name of the output dataset."));
     167             : 
     168           2 :     argParser.add_argument("src_dataset")
     169           4 :         .metavar("<src_dataset>")
     170           2 :         .nargs(nargs_pattern::at_least_one)
     171           2 :         .store_into(aosSrcDatasets)
     172           2 :         .help(_("Name of the source dataset(s)."));
     173             : 
     174           2 :     CPLStringList aosArgv;
     175             : 
     176           6 :     for (int i = 0; i < nArgc; i++)
     177             :     {
     178           4 :         aosArgv.AddString(papszArgv[i]);
     179             :     }
     180             : 
     181             :     try
     182             :     {
     183           2 :         argParser.parse_args(aosArgv);
     184             :     }
     185           2 :     catch (const std::exception &e)
     186             :     {
     187           2 :         argParser.display_error_and_usage(e);
     188           2 :         GDALExit(1);
     189             :     }
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      Validate input                                                  */
     193             :     /* -------------------------------------------------------------------- */
     194             : 
     195             :     //srs_name must be specified when srs_format is specified.
     196           0 :     if (argParser.is_used("-src_srs_format") &&
     197           0 :         !argParser.is_used("-src_srs_name"))
     198             :     {
     199           0 :         fprintf(stderr, "-src_srs_name must be specified when -src_srs_format "
     200             :                         "is specified.\n");
     201           0 :         GDALExit(1);
     202             :     }
     203             : 
     204           0 :     bLayersWildcarded = aosLayerNames.empty() && anLayerNumbers.empty();
     205             : 
     206             :     /* -------------------------------------------------------------------- */
     207             :     /*      Register format(s).                                             */
     208             :     /* -------------------------------------------------------------------- */
     209           0 :     OGRRegisterAll();
     210             : 
     211             :     /* -------------------------------------------------------------------- */
     212             :     /*      Create and validate target SRS if given.                        */
     213             :     /* -------------------------------------------------------------------- */
     214             : 
     215           0 :     OGRSpatialReference *poTargetSRS = nullptr;
     216             : 
     217           0 :     if (!osTargetSRS.empty())
     218             :     {
     219           0 :         if (bSkipDifferentProjection)
     220             :         {
     221           0 :             fprintf(stderr,
     222             :                     "Warning : -skip_different_projection does not apply "
     223             :                     "when -t_srs is requested.\n");
     224             :         }
     225           0 :         poTargetSRS = new OGRSpatialReference();
     226           0 :         poTargetSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     227             :         // coverity[tainted_data]
     228           0 :         if (poTargetSRS->SetFromUserInput(osTargetSRS.c_str()) != CE_None)
     229             :         {
     230           0 :             delete poTargetSRS;
     231           0 :             fprintf(stderr, "Invalid target SRS `%s'.\n", osTargetSRS.c_str());
     232           0 :             GDALExit(1);
     233             :         }
     234           0 :         bSetTargetSRS = true;
     235             :     }
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      Try to open as an existing dataset for update access.           */
     239             :     /* -------------------------------------------------------------------- */
     240             :     GDALDataset *poDstDS =
     241           0 :         GDALDataset::FromHandle(OGROpen(osOutputName.c_str(), TRUE, nullptr));
     242             : 
     243             :     /* -------------------------------------------------------------------- */
     244             :     /*      If that failed, find the driver so we can create the tile index.*/
     245             :     /* -------------------------------------------------------------------- */
     246           0 :     OGRLayer *poDstLayer = nullptr;
     247             : 
     248           0 :     if (poDstDS == nullptr)
     249             :     {
     250           0 :         CPLString osFormat;
     251           0 :         if (osOutputFormat.empty())
     252             :         {
     253             :             const auto aoDrivers =
     254           0 :                 GetOutputDriversFor(osOutputName.c_str(), GDAL_OF_VECTOR);
     255           0 :             if (aoDrivers.empty())
     256             :             {
     257           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     258             :                          "Cannot guess driver for %s", osOutputName.c_str());
     259           0 :                 GDALExit(10);
     260             :             }
     261             :             else
     262             :             {
     263           0 :                 if (aoDrivers.size() > 1)
     264             :                 {
     265           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     266             :                              "Several drivers matching %s extension. Using %s",
     267           0 :                              CPLGetExtensionSafe(osOutputName.c_str()).c_str(),
     268           0 :                              aoDrivers[0].c_str());
     269             :                 }
     270           0 :                 osFormat = aoDrivers[0];
     271             :             }
     272             :         }
     273             :         else
     274             :         {
     275           0 :             osFormat = osOutputFormat;
     276             :         }
     277             : 
     278           0 :         if (!EQUAL(osFormat, "ESRI Shapefile"))
     279           0 :             nMaxFieldSize = 0;
     280             : 
     281           0 :         GDALDriverH hDriver = GDALGetDriverByName(osFormat.c_str());
     282           0 :         if (hDriver == nullptr)
     283             :         {
     284           0 :             GDALDriverManager *poDM = GetGDALDriverManager();
     285           0 :             for (int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++)
     286             :             {
     287           0 :                 fprintf(stderr, "Unable to find driver `%s'.\n",
     288             :                         osFormat.c_str());
     289           0 :                 fprintf(stderr, "The following drivers are available:\n");
     290             : 
     291           0 :                 GDALDriver *poIter = poDM->GetDriver(iDriver);
     292           0 :                 char **papszDriverMD = poIter->GetMetadata();
     293           0 :                 if (CPLTestBool(CSLFetchNameValueDef(
     294           0 :                         papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) &&
     295           0 :                     CPLTestBool(CSLFetchNameValueDef(
     296             :                         papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
     297             :                 {
     298           0 :                     fprintf(stderr, "  -> `%s'\n", poIter->GetDescription());
     299             :                 }
     300             :             }
     301           0 :             GDALExit(1);
     302             :         }
     303             : 
     304           0 :         if (!CPLTestBool(CSLFetchNameValueDef(GDALGetMetadata(hDriver, nullptr),
     305             :                                               GDAL_DCAP_CREATE, "FALSE")))
     306             :         {
     307           0 :             fprintf(stderr,
     308             :                     "%s driver does not support data source creation.\n",
     309             :                     osFormat.c_str());
     310           0 :             GDALExit(1);
     311             :         }
     312             : 
     313             :         /* --------------------------------------------------------------------
     314             :          */
     315             :         /*      Now create it. */
     316             :         /* --------------------------------------------------------------------
     317             :          */
     318             : 
     319           0 :         poDstDS = GDALDataset::FromHandle(GDALCreate(
     320             :             hDriver, osOutputName.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
     321           0 :         if (poDstDS == nullptr)
     322             :         {
     323           0 :             fprintf(stderr, "%s driver failed to create %s\n", osFormat.c_str(),
     324             :                     osOutputName.c_str());
     325           0 :             GDALExit(1);
     326             :         }
     327             : 
     328           0 :         if (poDstDS->GetLayerCount() == 0)
     329             :         {
     330             : 
     331           0 :             OGRSpatialReference *poSrcSpatialRef = nullptr;
     332           0 :             if (bSetTargetSRS)
     333             :             {
     334             :                 // Fetches the SRS from target SRS (if set), or from the SRS of
     335             :                 // the first layer and use it when creating the
     336             :                 // tileindex layer.
     337           0 :                 poSrcSpatialRef = poTargetSRS->Clone();
     338             :             }
     339           0 :             else if (!aosSrcDatasets.empty())
     340             :             {
     341           0 :                 GDALDataset *poDS = GDALDataset::FromHandle(
     342           0 :                     OGROpen(aosSrcDatasets.front().c_str(), FALSE, nullptr));
     343           0 :                 if (poDS != nullptr)
     344             :                 {
     345           0 :                     for (int iLayer = 0; iLayer < poDS->GetLayerCount();
     346             :                          iLayer++)
     347             :                     {
     348           0 :                         bool bRequested = bLayersWildcarded;
     349           0 :                         OGRLayer *poLayer = poDS->GetLayer(iLayer);
     350             : 
     351           0 :                         if (!bRequested)
     352             :                         {
     353           0 :                             if (std::find(anLayerNumbers.cbegin(),
     354             :                                           anLayerNumbers.cend(),
     355           0 :                                           iLayer) != anLayerNumbers.cend())
     356           0 :                                 bRequested = true;
     357           0 :                             else if (std::find(
     358             :                                          aosLayerNames.cbegin(),
     359             :                                          aosLayerNames.cend(),
     360           0 :                                          poLayer->GetLayerDefn()->GetName()) !=
     361           0 :                                      aosLayerNames.cend())
     362           0 :                                 bRequested = true;
     363             :                         }
     364             : 
     365           0 :                         if (!bRequested)
     366           0 :                             continue;
     367             : 
     368           0 :                         if (poLayer->GetSpatialRef())
     369           0 :                             poSrcSpatialRef = poLayer->GetSpatialRef()->Clone();
     370           0 :                         break;
     371             :                     }
     372             :                 }
     373             : 
     374           0 :                 GDALClose(poDS);
     375             :             }
     376             : 
     377           0 :             poDstLayer = poDstDS->CreateLayer("tileindex", poSrcSpatialRef);
     378             : 
     379           0 :             OGRFieldDefn oLocation(osTileIndexField.c_str(), OFTString);
     380           0 :             oLocation.SetWidth(200);
     381           0 :             poDstLayer->CreateField(&oLocation);
     382             : 
     383           0 :             if (!osSrcSRSName.empty())
     384             :             {
     385           0 :                 OGRFieldDefn oSrcSRSNameField(osSrcSRSName.c_str(), OFTString);
     386           0 :                 poDstLayer->CreateField(&oSrcSRSNameField);
     387             :             }
     388             : 
     389           0 :             if (poSrcSpatialRef)
     390           0 :                 poSrcSpatialRef->Release();
     391             :         }
     392             :     }
     393             : 
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      Identify target layer and field.                                */
     396             :     /* -------------------------------------------------------------------- */
     397             : 
     398           0 :     poDstLayer = poDstDS->GetLayer(0);
     399           0 :     if (poDstLayer == nullptr)
     400             :     {
     401           0 :         fprintf(stderr, "Can't find any layer in output tileindex!\n");
     402           0 :         GDALExit(1);
     403             :     }
     404             : 
     405             :     const int iTileIndexField =
     406           0 :         poDstLayer->GetLayerDefn()->GetFieldIndex(osTileIndexField.c_str());
     407           0 :     if (iTileIndexField == -1)
     408             :     {
     409           0 :         fprintf(stderr, "Can't find %s field in tile index dataset.\n",
     410             :                 osTileIndexField.c_str());
     411           0 :         GDALExit(1);
     412             :     }
     413             : 
     414           0 :     if (!osSrcSRSName.empty())
     415             :         i_SrcSRSName =
     416           0 :             poDstLayer->GetLayerDefn()->GetFieldIndex(osSrcSRSName.c_str());
     417             : 
     418           0 :     OGRFeatureDefn *poFeatureDefn = nullptr;
     419             : 
     420             :     // Load in memory existing file names in SHP.
     421           0 :     char **existingLayersTab = nullptr;
     422           0 :     OGRSpatialReference *alreadyExistingSpatialRef = nullptr;
     423           0 :     bool alreadyExistingSpatialRefValid = false;
     424           0 :     const int nExistingLayers = static_cast<int>(poDstLayer->GetFeatureCount());
     425           0 :     if (nExistingLayers)
     426             :     {
     427             :         existingLayersTab =
     428           0 :             static_cast<char **>(CPLMalloc(nExistingLayers * sizeof(char *)));
     429           0 :         for (int i = 0; i < nExistingLayers; i++)
     430             :         {
     431           0 :             OGRFeature *feature = poDstLayer->GetNextFeature();
     432           0 :             existingLayersTab[i] =
     433           0 :                 CPLStrdup(feature->GetFieldAsString(iTileIndexField));
     434           0 :             if (i == 0)
     435             :             {
     436           0 :                 char *filename = CPLStrdup(existingLayersTab[i]);
     437             :                 // j used after for.
     438           0 :                 int j = static_cast<int>(strlen(filename)) - 1;
     439           0 :                 for (; j >= 0; j--)
     440             :                 {
     441           0 :                     if (filename[j] == ',')
     442           0 :                         break;
     443             :                 }
     444           0 :                 GDALDataset *poDS = nullptr;
     445           0 :                 if (j >= 0)
     446             :                 {
     447           0 :                     const int iLayer = atoi(filename + j + 1);
     448           0 :                     filename[j] = 0;
     449           0 :                     poDS = GDALDataset::FromHandle(
     450           0 :                         OGROpen(filename, FALSE, nullptr));
     451           0 :                     if (poDS != nullptr)
     452             :                     {
     453           0 :                         OGRLayer *poLayer = poDS->GetLayer(iLayer);
     454           0 :                         if (poLayer)
     455             :                         {
     456           0 :                             alreadyExistingSpatialRefValid = true;
     457           0 :                             alreadyExistingSpatialRef =
     458           0 :                                 poLayer->GetSpatialRef()
     459           0 :                                     ? poLayer->GetSpatialRef()->Clone()
     460             :                                     : nullptr;
     461             : 
     462           0 :                             if (poFeatureDefn == nullptr)
     463             :                                 poFeatureDefn =
     464           0 :                                     poLayer->GetLayerDefn()->Clone();
     465             :                         }
     466           0 :                         GDALClose(poDS);
     467             :                     }
     468             :                 }
     469             :             }
     470             :         }
     471             :     }
     472             : 
     473           0 :     if (bWriteAbsolutePath)
     474             :     {
     475           0 :         pszCurrentPath = CPLGetCurrentDir();
     476           0 :         if (pszCurrentPath == nullptr)
     477             :         {
     478           0 :             fprintf(stderr,
     479             :                     "This system does not support the CPLGetCurrentDir call. "
     480             :                     "The option -write_absolute_path will have no effect\n");
     481           0 :             bWriteAbsolutePath = false;
     482             :         }
     483             :     }
     484             :     /* ==================================================================== */
     485             :     /*      Process each input datasource in turn.                          */
     486             :     /* ==================================================================== */
     487           0 :     for (const auto &srcDataSet : aosSrcDatasets)
     488             :     {
     489             : 
     490           0 :         char *fileNameToWrite = nullptr;
     491             :         VSIStatBuf sStatBuf;
     492             : 
     493           0 :         if (bWriteAbsolutePath && CPLIsFilenameRelative(srcDataSet.c_str()) &&
     494           0 :             VSIStat(srcDataSet.c_str(), &sStatBuf) == 0)
     495             :         {
     496           0 :             fileNameToWrite = CPLStrdup(CPLProjectRelativeFilenameSafe(
     497             :                                             pszCurrentPath, srcDataSet.c_str())
     498             :                                             .c_str());
     499             :         }
     500             :         else
     501             :         {
     502           0 :             fileNameToWrite = CPLStrdup(srcDataSet.c_str());
     503             :         }
     504             : 
     505           0 :         GDALDataset *poDS = GDALDataset::FromHandle(
     506           0 :             OGROpen(srcDataSet.c_str(), FALSE, nullptr));
     507             : 
     508           0 :         if (poDS == nullptr)
     509             :         {
     510           0 :             fprintf(stderr, "Failed to open dataset %s, skipping.\n",
     511             :                     srcDataSet.c_str());
     512           0 :             CPLFree(fileNameToWrite);
     513           0 :             continue;
     514             :         }
     515             : 
     516             :         /* ----------------------------------------------------------------- */
     517             :         /*      Check all layers, and see if they match requests.            */
     518             :         /* ----------------------------------------------------------------- */
     519             : 
     520           0 :         for (int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++)
     521             :         {
     522           0 :             bool bRequested = bLayersWildcarded;
     523           0 :             OGRLayer *poLayer = poDS->GetLayer(iLayer);
     524             : 
     525           0 :             if (!bRequested)
     526             :             {
     527           0 :                 if (std::find(anLayerNumbers.cbegin(), anLayerNumbers.cend(),
     528           0 :                               iLayer) != anLayerNumbers.cend())
     529           0 :                     bRequested = true;
     530           0 :                 else if (std::find(aosLayerNames.cbegin(), aosLayerNames.cend(),
     531           0 :                                    poLayer->GetLayerDefn()->GetName()) !=
     532           0 :                          aosLayerNames.cend())
     533           0 :                     bRequested = true;
     534             :             }
     535             : 
     536           0 :             if (!bRequested)
     537           0 :                 continue;
     538             : 
     539             :             // Checks that the layer is not already in tileindex.
     540           0 :             int i = 0;  // Used after for.
     541           0 :             for (; i < nExistingLayers; i++)
     542             :             {
     543             :                 // TODO(schwehr): Move this off of the stack.
     544           0 :                 char szLocation[5000] = {};
     545           0 :                 snprintf(szLocation, sizeof(szLocation), "%s,%d",
     546             :                          fileNameToWrite, iLayer);
     547           0 :                 if (EQUAL(szLocation, existingLayersTab[i]))
     548             :                 {
     549           0 :                     fprintf(stderr,
     550             :                             "Layer %d of %s is already in tileindex. "
     551             :                             "Skipping it.\n",
     552             :                             iLayer, srcDataSet.c_str());
     553           0 :                     break;
     554             :                 }
     555             :             }
     556           0 :             if (i != nExistingLayers)
     557             :             {
     558           0 :                 continue;
     559             :             }
     560             : 
     561           0 :             OGRSpatialReference *spatialRef = poLayer->GetSpatialRef();
     562             :             // If not set target srs, test that the current file uses same
     563             :             // projection as others.
     564           0 :             if (!bSetTargetSRS)
     565             :             {
     566           0 :                 if (alreadyExistingSpatialRefValid)
     567             :                 {
     568           0 :                     if ((spatialRef != nullptr &&
     569           0 :                          alreadyExistingSpatialRef != nullptr &&
     570           0 :                          spatialRef->IsSame(alreadyExistingSpatialRef) ==
     571           0 :                              FALSE) ||
     572           0 :                         ((spatialRef != nullptr) !=
     573           0 :                          (alreadyExistingSpatialRef != nullptr)))
     574             :                     {
     575           0 :                         fprintf(
     576             :                             stderr,
     577             :                             "Warning : layer %d of %s is not using the same "
     578             :                             "projection system as other files in the "
     579             :                             "tileindex. This may cause problems when using it "
     580             :                             "in MapServer for example.%s\n",
     581             :                             iLayer, srcDataSet.c_str(),
     582             :                             bSkipDifferentProjection ? " Skipping it" : "");
     583           0 :                         if (bSkipDifferentProjection)
     584             :                         {
     585           0 :                             continue;
     586             :                         }
     587             :                     }
     588             :                 }
     589             :                 else
     590             :                 {
     591           0 :                     alreadyExistingSpatialRefValid = true;
     592           0 :                     alreadyExistingSpatialRef =
     593           0 :                         spatialRef ? spatialRef->Clone() : nullptr;
     594             :                 }
     595             :             }
     596             : 
     597             :             /* ------------------------------------------------------------------ */
     598             :             /* Check if all layers in dataset have the same attributes schema.    */
     599             :             /* ------------------------------------------------------------------ */
     600             : 
     601           0 :             if (poFeatureDefn == nullptr)
     602             :             {
     603           0 :                 poFeatureDefn = poLayer->GetLayerDefn()->Clone();
     604             :             }
     605           0 :             else if (!bAcceptDifferentSchemas)
     606             :             {
     607           0 :                 OGRFeatureDefn *poFeatureDefnCur = poLayer->GetLayerDefn();
     608           0 :                 assert(nullptr != poFeatureDefnCur);
     609             : 
     610           0 :                 const int fieldCount = poFeatureDefnCur->GetFieldCount();
     611             : 
     612           0 :                 if (fieldCount != poFeatureDefn->GetFieldCount())
     613             :                 {
     614           0 :                     fprintf(stderr,
     615             :                             "Number of attributes of layer %s of %s "
     616             :                             "does not match ... skipping it.\n",
     617           0 :                             poLayer->GetLayerDefn()->GetName(),
     618             :                             srcDataSet.c_str());
     619           0 :                     if (bFirstWarningForNonMatchingAttributes)
     620             :                     {
     621           0 :                         fprintf(
     622             :                             stderr,
     623             :                             "Note : you can override this "
     624             :                             "behavior with -accept_different_schemas option\n"
     625             :                             "but this may result in a tileindex incompatible "
     626             :                             "with MapServer\n");
     627           0 :                         bFirstWarningForNonMatchingAttributes = false;
     628             :                     }
     629           0 :                     continue;
     630             :                 }
     631             : 
     632           0 :                 bool bSkip = false;
     633           0 :                 for (int fn = 0; fn < poFeatureDefnCur->GetFieldCount(); fn++)
     634             :                 {
     635           0 :                     OGRFieldDefn *poField = poFeatureDefn->GetFieldDefn(fn);
     636             :                     OGRFieldDefn *poFieldCur =
     637           0 :                         poFeatureDefnCur->GetFieldDefn(fn);
     638             : 
     639             :                     // XXX - Should those pointers be checked against NULL?
     640           0 :                     assert(nullptr != poField);
     641           0 :                     assert(nullptr != poFieldCur);
     642             : 
     643           0 :                     if (poField->GetType() != poFieldCur->GetType() ||
     644           0 :                         poField->GetWidth() != poFieldCur->GetWidth() ||
     645           0 :                         poField->GetPrecision() != poFieldCur->GetPrecision() ||
     646           0 :                         !EQUAL(poField->GetNameRef(), poFieldCur->GetNameRef()))
     647             :                     {
     648           0 :                         fprintf(stderr,
     649             :                                 "Schema of attributes of layer %s of %s "
     650             :                                 "does not match. Skipping it.\n",
     651           0 :                                 poLayer->GetLayerDefn()->GetName(),
     652             :                                 srcDataSet.c_str());
     653           0 :                         if (bFirstWarningForNonMatchingAttributes)
     654             :                         {
     655           0 :                             fprintf(
     656             :                                 stderr,
     657             :                                 "Note : you can override this "
     658             :                                 "behavior with -accept_different_schemas "
     659             :                                 "option,\nbut this may result in a tileindex "
     660             :                                 "incompatible with MapServer\n");
     661           0 :                             bFirstWarningForNonMatchingAttributes = false;
     662             :                         }
     663           0 :                         bSkip = true;
     664           0 :                         break;
     665             :                     }
     666             :                 }
     667             : 
     668           0 :                 if (bSkip)
     669           0 :                     continue;
     670             :             }
     671             : 
     672             :             /* ----------------------------------------------------------------- */
     673             :             /*      Get layer extents, and create a corresponding polygon        */
     674             :             /*      geometry.                                                    */
     675             :             /* ----------------------------------------------------------------- */
     676           0 :             OGREnvelope sExtents;
     677             : 
     678           0 :             if (poLayer->GetExtent(&sExtents, TRUE) != OGRERR_NONE)
     679             :             {
     680           0 :                 fprintf(stderr,
     681             :                         "GetExtent() failed on layer %s of %s, skipping.\n",
     682           0 :                         poLayer->GetLayerDefn()->GetName(), srcDataSet.c_str());
     683           0 :                 continue;
     684             :             }
     685             : 
     686           0 :             OGRLinearRing oRing;
     687           0 :             oRing.addPoint(sExtents.MinX, sExtents.MinY);
     688           0 :             oRing.addPoint(sExtents.MinX, sExtents.MaxY);
     689           0 :             oRing.addPoint(sExtents.MaxX, sExtents.MaxY);
     690           0 :             oRing.addPoint(sExtents.MaxX, sExtents.MinY);
     691           0 :             oRing.addPoint(sExtents.MinX, sExtents.MinY);
     692             : 
     693           0 :             OGRPolygon oRegion;
     694           0 :             oRegion.addRing(&oRing);
     695             : 
     696             :             // If set target srs, do the forward transformation of all points.
     697           0 :             if (bSetTargetSRS && spatialRef != nullptr)
     698             :             {
     699           0 :                 if (!spatialRef->IsSame(poTargetSRS))
     700             :                 {
     701             :                     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     702             :                         OGRCreateCoordinateTransformation(spatialRef,
     703           0 :                                                           poTargetSRS));
     704           0 :                     if (poCT == nullptr ||
     705           0 :                         oRegion.transform(poCT.get()) == OGRERR_FAILURE)
     706             :                     {
     707           0 :                         char *pszSourceWKT = nullptr;
     708           0 :                         spatialRef->exportToWkt(&pszSourceWKT);
     709           0 :                         fprintf(
     710             :                             stderr,
     711             :                             "Warning : unable to transform points from source "
     712             :                             "SRS `%s' to target SRS `%s'\n"
     713             :                             "for file `%s' - file skipped\n",
     714             :                             pszSourceWKT, osTargetSRS.c_str(),
     715             :                             srcDataSet.c_str());
     716           0 :                         CPLFree(pszSourceWKT);
     717           0 :                         continue;
     718             :                     }
     719             :                 }
     720             :             }
     721             : 
     722             :             /* ---------------------------------------------------------------- */
     723             :             /*      Add layer to tileindex.                                     */
     724             :             /* ---------------------------------------------------------------- */
     725           0 :             OGRFeature oTileFeat(poDstLayer->GetLayerDefn());
     726             : 
     727             :             // TODO(schwehr): Move this off of the stack.
     728           0 :             char szLocation[5000] = {};
     729           0 :             snprintf(szLocation, sizeof(szLocation), "%s,%d", fileNameToWrite,
     730             :                      iLayer);
     731           0 :             oTileFeat.SetGeometry(&oRegion);
     732           0 :             oTileFeat.SetField(iTileIndexField, szLocation);
     733             : 
     734           0 :             if (i_SrcSRSName >= 0 && spatialRef != nullptr)
     735             :             {
     736             :                 const char *pszAuthorityCode =
     737           0 :                     spatialRef->GetAuthorityCode(nullptr);
     738             :                 const char *pszAuthorityName =
     739           0 :                     spatialRef->GetAuthorityName(nullptr);
     740           0 :                 char *pszWKT = nullptr;
     741           0 :                 spatialRef->exportToWkt(&pszWKT);
     742           0 :                 if (eSrcSRSFormat == FORMAT_AUTO)
     743             :                 {
     744           0 :                     if (pszAuthorityName != nullptr &&
     745             :                         pszAuthorityCode != nullptr)
     746             :                     {
     747           0 :                         oTileFeat.SetField(i_SrcSRSName,
     748             :                                            CPLSPrintf("%s:%s", pszAuthorityName,
     749             :                                                       pszAuthorityCode));
     750             :                     }
     751           0 :                     else if (nMaxFieldSize == 0 ||
     752           0 :                              strlen(pszWKT) <= nMaxFieldSize)
     753             :                     {
     754           0 :                         oTileFeat.SetField(i_SrcSRSName, pszWKT);
     755             :                     }
     756             :                     else
     757             :                     {
     758           0 :                         char *pszProj4 = nullptr;
     759           0 :                         if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
     760             :                         {
     761           0 :                             oTileFeat.SetField(i_SrcSRSName, pszProj4);
     762           0 :                             CPLFree(pszProj4);
     763             :                         }
     764             :                         else
     765             :                         {
     766           0 :                             oTileFeat.SetField(i_SrcSRSName, pszWKT);
     767             :                         }
     768             :                     }
     769             :                 }
     770           0 :                 else if (eSrcSRSFormat == FORMAT_WKT)
     771             :                 {
     772           0 :                     if (nMaxFieldSize == 0 || strlen(pszWKT) <= nMaxFieldSize)
     773             :                     {
     774           0 :                         oTileFeat.SetField(i_SrcSRSName, pszWKT);
     775             :                     }
     776             :                     else
     777             :                     {
     778           0 :                         fprintf(
     779             :                             stderr,
     780             :                             "Cannot write WKT for file %s as it is too long!\n",
     781             :                             fileNameToWrite);
     782             :                     }
     783             :                 }
     784           0 :                 else if (eSrcSRSFormat == FORMAT_PROJ)
     785             :                 {
     786           0 :                     char *pszProj4 = nullptr;
     787           0 :                     if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
     788             :                     {
     789           0 :                         oTileFeat.SetField(i_SrcSRSName, pszProj4);
     790           0 :                         CPLFree(pszProj4);
     791             :                     }
     792             :                 }
     793           0 :                 else if (eSrcSRSFormat == FORMAT_EPSG)
     794             :                 {
     795           0 :                     if (pszAuthorityName != nullptr &&
     796             :                         pszAuthorityCode != nullptr)
     797           0 :                         oTileFeat.SetField(i_SrcSRSName,
     798             :                                            CPLSPrintf("%s:%s", pszAuthorityName,
     799             :                                                       pszAuthorityCode));
     800             :                 }
     801           0 :                 CPLFree(pszWKT);
     802             :             }
     803           0 :             if (poDstLayer->CreateFeature(&oTileFeat) != OGRERR_NONE)
     804             :             {
     805           0 :                 fprintf(stderr, "Failed to create feature on tile index. "
     806             :                                 "Terminating.");
     807           0 :                 GDALClose(poDstDS);
     808           0 :                 exit(1);
     809             :             }
     810             :         }
     811             : 
     812             :         /* ---------------------------------------------------------------- */
     813             :         /*      Cleanup this data source.                                   */
     814             :         /* ---------------------------------------------------------------- */
     815           0 :         CPLFree(fileNameToWrite);
     816           0 :         GDALClose(poDS);
     817             :     }
     818             : 
     819             :     /* -------------------------------------------------------------------- */
     820             :     /*      Close tile index and clear buffers.                             */
     821             :     /* -------------------------------------------------------------------- */
     822           0 :     int nRetCode = 0;
     823           0 :     if (GDALClose(poDstDS) != CE_None)
     824           0 :         nRetCode = 1;
     825           0 :     OGRFeatureDefn::DestroyFeatureDefn(poFeatureDefn);
     826             : 
     827           0 :     if (alreadyExistingSpatialRef != nullptr)
     828           0 :         alreadyExistingSpatialRef->Release();
     829           0 :     delete poTargetSRS;
     830             : 
     831           0 :     CPLFree(pszCurrentPath);
     832             : 
     833           0 :     if (nExistingLayers)
     834             :     {
     835           0 :         for (int i = 0; i < nExistingLayers; i++)
     836             :         {
     837           0 :             CPLFree(existingLayersTab[i]);
     838             :         }
     839           0 :         CPLFree(existingLayersTab);
     840             :     }
     841             : 
     842           0 :     GDALDestroy();
     843             : 
     844           0 :     return nRetCode;
     845             : }
     846             : 
     847           0 : MAIN_END

Generated by: LCOV version 1.14