LCOV - code coverage report
Current view: top level - apps - ogrtindex.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 253 389 65.0 %
Date: 2024-11-21 22:18:42 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           0 : static void GDALExit(int nCode)
      42             : {
      43           0 :     GDALDestroy();
      44           0 :     exit(nCode);
      45             : }
      46             : 
      47             : /************************************************************************/
      48             : /*                                main()                                */
      49             : /************************************************************************/
      50             : 
      51           8 : MAIN_START(nArgc, papszArgv)
      52             : 
      53             : {
      54             : 
      55             :     // Check strict compilation and runtime library version as we use C++ API.
      56           8 :     if (!GDAL_CHECK_VERSION(papszArgv[0]))
      57           0 :         GDALExit(1);
      58             : 
      59           8 :     EarlySetConfigOptions(nArgc, papszArgv);
      60             : 
      61             :     /* -------------------------------------------------------------------- */
      62             :     /*      Processing command line arguments.                              */
      63             :     /* -------------------------------------------------------------------- */
      64           8 :     bool bLayersWildcarded = true;
      65          15 :     std::string osOutputFormat;
      66          15 :     std::string osTileIndexField;
      67          15 :     std::string osOutputName;
      68           8 :     bool bWriteAbsolutePath{false};
      69           8 :     bool bSkipDifferentProjection{false};
      70           8 :     char *pszCurrentPath = nullptr;
      71           8 :     bool bAcceptDifferentSchemas{false};
      72           8 :     bool bFirstWarningForNonMatchingAttributes = true;
      73          15 :     std::string osTargetSRS;
      74           8 :     bool bSetTargetSRS = false;
      75          15 :     std::string osSrcSRSName;
      76           8 :     int i_SrcSRSName = -1;
      77           8 :     SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
      78           8 :     size_t nMaxFieldSize = 254;
      79          15 :     std::vector<std::string> aosSrcDatasets;
      80          15 :     std::vector<std::string> aosLayerNames;
      81          15 :     std::vector<int> anLayerNumbers;
      82             : 
      83          23 :     GDALArgumentParser argParser{"ogrtindex", true};
      84             : 
      85             :     argParser.add_description(
      86             :         _("Program to generate a UMN MapServer compatible "
      87           8 :           "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           8 :           "at\nhttps://gdal.org/programs/ogrtindex.html"));
      92             : 
      93           8 :     argParser.add_argument("-lnum")
      94          16 :         .metavar("<n>")
      95           8 :         .append()
      96           8 :         .scan<'i', int>()
      97           8 :         .store_into(anLayerNumbers)
      98             :         .help(
      99           8 :             _("Add layer number <n> from each source file in the tile index."));
     100             : 
     101           8 :     argParser.add_argument("-lname")
     102          16 :         .metavar("<name>")
     103           8 :         .append()
     104           8 :         .store_into(aosLayerNames)
     105             :         .help(_(
     106           8 :             "Add layer named <name> from each source file in the tile index."));
     107             : 
     108           8 :     argParser.add_output_format_argument(osOutputFormat);
     109             : 
     110           8 :     argParser.add_argument("-tileindex")
     111          16 :         .metavar("<tileindex>")
     112           8 :         .default_value("LOCATION")
     113           8 :         .nargs(1)
     114           8 :         .store_into(osTileIndexField)
     115           8 :         .help(_("Name to use for the dataset name."));
     116             : 
     117           8 :     argParser.add_argument("-write_absolute_path")
     118           8 :         .flag()
     119           8 :         .store_into(bWriteAbsolutePath)
     120           8 :         .help(_("Write absolute path of the source file in the tile index."));
     121             : 
     122           8 :     argParser.add_argument("-skip_different_projection")
     123           8 :         .flag()
     124           8 :         .store_into(bSkipDifferentProjection)
     125             :         .help(_("Skip layers that are not in the same projection as the first "
     126           8 :                 "layer."));
     127             : 
     128           8 :     argParser.add_argument("-t_srs")
     129          16 :         .metavar("<srs_def>")
     130           8 :         .store_into(osTargetSRS)
     131             :         .help(
     132             :             _("Extent of input files will be transformed to the desired target "
     133           8 :               "coordinate reference system."));
     134             : 
     135           8 :     argParser.add_argument("-src_srs_name")
     136          16 :         .metavar("<field_name>")
     137           8 :         .store_into(osSrcSRSName)
     138           8 :         .help(_("Name of the field to store the SRS of each tile."));
     139             : 
     140           8 :     argParser.add_argument("-src_srs_format")
     141          16 :         .metavar("{AUTO|WKT|EPSG|PROJ}")
     142           8 :         .choices("AUTO", "WKT", "EPSG", "PROJ")
     143             :         .action(
     144           8 :             [&eSrcSRSFormat](const auto &f)
     145             :             {
     146           4 :                 if (f == "WKT")
     147           1 :                     eSrcSRSFormat = FORMAT_WKT;
     148           3 :                 else if (f == "EPSG")
     149           1 :                     eSrcSRSFormat = FORMAT_EPSG;
     150           2 :                 else if (f == "PROJ")
     151           1 :                     eSrcSRSFormat = FORMAT_PROJ;
     152             :                 else
     153           1 :                     eSrcSRSFormat = FORMAT_AUTO;
     154           8 :             })
     155           8 :         .help(_("Format of the source SRS to store in the tile index file."));
     156             : 
     157           8 :     argParser.add_argument("-accept_different_schemas")
     158           8 :         .flag()
     159           8 :         .store_into(bAcceptDifferentSchemas)
     160             :         .help(_(
     161           8 :             "Disable check for identical schemas for layers in input files."));
     162             : 
     163           8 :     argParser.add_argument("output_dataset")
     164          16 :         .metavar("<output_dataset>")
     165           8 :         .store_into(osOutputName)
     166           8 :         .help(_("Name of the output dataset."));
     167             : 
     168           8 :     argParser.add_argument("src_dataset")
     169          16 :         .metavar("<src_dataset>")
     170           8 :         .nargs(nargs_pattern::at_least_one)
     171           8 :         .store_into(aosSrcDatasets)
     172           8 :         .help(_("Name of the source dataset(s)."));
     173             : 
     174           8 :     CPLStringList aosArgv;
     175             : 
     176          74 :     for (int i = 0; i < nArgc; i++)
     177             :     {
     178          66 :         aosArgv.AddString(papszArgv[i]);
     179             :     }
     180             : 
     181             :     try
     182             :     {
     183           8 :         argParser.parse_args(aosArgv);
     184             :     }
     185           0 :     catch (const std::exception &e)
     186             :     {
     187           0 :         argParser.display_error_and_usage(e);
     188           0 :         GDALExit(1);
     189             :     }
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      Validate input                                                  */
     193             :     /* -------------------------------------------------------------------- */
     194             : 
     195             :     //srs_name must be specified when srs_format is specified.
     196          11 :     if (argParser.is_used("-src_srs_format") &&
     197          11 :         !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           7 :     bLayersWildcarded = aosLayerNames.empty() && anLayerNumbers.empty();
     205             : 
     206             :     /* -------------------------------------------------------------------- */
     207             :     /*      Register format(s).                                             */
     208             :     /* -------------------------------------------------------------------- */
     209           7 :     OGRRegisterAll();
     210             : 
     211             :     /* -------------------------------------------------------------------- */
     212             :     /*      Create and validate target SRS if given.                        */
     213             :     /* -------------------------------------------------------------------- */
     214             : 
     215           7 :     OGRSpatialReference *poTargetSRS = nullptr;
     216             : 
     217           7 :     if (!osTargetSRS.empty())
     218             :     {
     219           5 :         if (bSkipDifferentProjection)
     220             :         {
     221           0 :             fprintf(stderr,
     222             :                     "Warning : -skip_different_projection does not apply "
     223             :                     "when -t_srs is requested.\n");
     224             :         }
     225           5 :         poTargetSRS = new OGRSpatialReference();
     226           5 :         poTargetSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     227             :         // coverity[tainted_data]
     228           5 :         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           5 :         bSetTargetSRS = true;
     235             :     }
     236             : 
     237             :     /* -------------------------------------------------------------------- */
     238             :     /*      Try to open as an existing dataset for update access.           */
     239             :     /* -------------------------------------------------------------------- */
     240             :     GDALDataset *poDstDS =
     241           7 :         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           7 :     OGRLayer *poDstLayer = nullptr;
     247             : 
     248           7 :     if (poDstDS == nullptr)
     249             :     {
     250          14 :         CPLString osFormat;
     251           7 :         if (osOutputFormat.empty())
     252             :         {
     253             :             const auto aoDrivers =
     254          12 :                 GetOutputDriversFor(osOutputName.c_str(), GDAL_OF_VECTOR);
     255           6 :             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           6 :                 if (aoDrivers.size() > 1)
     264             :                 {
     265           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     266             :                              "Several drivers matching %s extension. Using %s",
     267             :                              CPLGetExtension(osOutputName.c_str()),
     268           0 :                              aoDrivers[0].c_str());
     269             :                 }
     270           6 :                 osFormat = aoDrivers[0];
     271             :             }
     272             :         }
     273             :         else
     274             :         {
     275           1 :             osFormat = osOutputFormat;
     276             :         }
     277             : 
     278           7 :         if (!EQUAL(osFormat, "ESRI Shapefile"))
     279           1 :             nMaxFieldSize = 0;
     280             : 
     281           7 :         GDALDriverH hDriver = GDALGetDriverByName(osFormat.c_str());
     282           7 :         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           7 :         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           7 :         poDstDS = GDALDataset::FromHandle(GDALCreate(
     320             :             hDriver, osOutputName.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
     321           7 :         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           7 :         if (poDstDS->GetLayerCount() == 0)
     329             :         {
     330             : 
     331           7 :             OGRSpatialReference *poSrcSpatialRef = nullptr;
     332           7 :             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           5 :                 poSrcSpatialRef = poTargetSRS->Clone();
     338             :             }
     339           2 :             else if (!aosSrcDatasets.empty())
     340             :             {
     341           2 :                 GDALDataset *poDS = GDALDataset::FromHandle(
     342           2 :                     OGROpen(aosSrcDatasets.front().c_str(), FALSE, nullptr));
     343           2 :                 if (poDS != nullptr)
     344             :                 {
     345           2 :                     for (int iLayer = 0; iLayer < poDS->GetLayerCount();
     346             :                          iLayer++)
     347             :                     {
     348           2 :                         bool bRequested = bLayersWildcarded;
     349           2 :                         OGRLayer *poLayer = poDS->GetLayer(iLayer);
     350             : 
     351           2 :                         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           2 :                         if (!bRequested)
     366           0 :                             continue;
     367             : 
     368           2 :                         if (poLayer->GetSpatialRef())
     369           1 :                             poSrcSpatialRef = poLayer->GetSpatialRef()->Clone();
     370           2 :                         break;
     371             :                     }
     372             :                 }
     373             : 
     374           2 :                 GDALClose(poDS);
     375             :             }
     376             : 
     377           7 :             poDstLayer = poDstDS->CreateLayer("tileindex", poSrcSpatialRef);
     378             : 
     379          14 :             OGRFieldDefn oLocation(osTileIndexField.c_str(), OFTString);
     380           7 :             oLocation.SetWidth(200);
     381           7 :             poDstLayer->CreateField(&oLocation);
     382             : 
     383           7 :             if (!osSrcSRSName.empty())
     384             :             {
     385          10 :                 OGRFieldDefn oSrcSRSNameField(osSrcSRSName.c_str(), OFTString);
     386           5 :                 poDstLayer->CreateField(&oSrcSRSNameField);
     387             :             }
     388             : 
     389           7 :             if (poSrcSpatialRef)
     390           6 :                 poSrcSpatialRef->Release();
     391             :         }
     392             :     }
     393             : 
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      Identify target layer and field.                                */
     396             :     /* -------------------------------------------------------------------- */
     397             : 
     398           7 :     poDstLayer = poDstDS->GetLayer(0);
     399           7 :     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           7 :         poDstLayer->GetLayerDefn()->GetFieldIndex(osTileIndexField.c_str());
     407           7 :     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           7 :     if (!osSrcSRSName.empty())
     415             :         i_SrcSRSName =
     416           5 :             poDstLayer->GetLayerDefn()->GetFieldIndex(osSrcSRSName.c_str());
     417             : 
     418           7 :     OGRFeatureDefn *poFeatureDefn = nullptr;
     419             : 
     420             :     // Load in memory existing file names in SHP.
     421           7 :     char **existingLayersTab = nullptr;
     422           7 :     OGRSpatialReference *alreadyExistingSpatialRef = nullptr;
     423           7 :     bool alreadyExistingSpatialRefValid = false;
     424           7 :     const int nExistingLayers = static_cast<int>(poDstLayer->GetFeatureCount());
     425           7 :     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           7 :     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          25 :     for (const auto &srcDataSet : aosSrcDatasets)
     488             :     {
     489             : 
     490          18 :         char *fileNameToWrite = nullptr;
     491             :         VSIStatBuf sStatBuf;
     492             : 
     493          18 :         if (bWriteAbsolutePath && CPLIsFilenameRelative(srcDataSet.c_str()) &&
     494           0 :             VSIStat(srcDataSet.c_str(), &sStatBuf) == 0)
     495             :         {
     496           0 :             fileNameToWrite = CPLStrdup(
     497             :                 CPLProjectRelativeFilename(pszCurrentPath, srcDataSet.c_str()));
     498             :         }
     499             :         else
     500             :         {
     501          18 :             fileNameToWrite = CPLStrdup(srcDataSet.c_str());
     502             :         }
     503             : 
     504          18 :         GDALDataset *poDS = GDALDataset::FromHandle(
     505          18 :             OGROpen(srcDataSet.c_str(), FALSE, nullptr));
     506             : 
     507          18 :         if (poDS == nullptr)
     508             :         {
     509           0 :             fprintf(stderr, "Failed to open dataset %s, skipping.\n",
     510             :                     srcDataSet.c_str());
     511           0 :             CPLFree(fileNameToWrite);
     512           0 :             continue;
     513             :         }
     514             : 
     515             :         /* ----------------------------------------------------------------- */
     516             :         /*      Check all layers, and see if they match requests.            */
     517             :         /* ----------------------------------------------------------------- */
     518             : 
     519          36 :         for (int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++)
     520             :         {
     521          18 :             bool bRequested = bLayersWildcarded;
     522          18 :             OGRLayer *poLayer = poDS->GetLayer(iLayer);
     523             : 
     524          18 :             if (!bRequested)
     525             :             {
     526           0 :                 if (std::find(anLayerNumbers.cbegin(), anLayerNumbers.cend(),
     527           0 :                               iLayer) != anLayerNumbers.cend())
     528           0 :                     bRequested = true;
     529           0 :                 else if (std::find(aosLayerNames.cbegin(), aosLayerNames.cend(),
     530           0 :                                    poLayer->GetLayerDefn()->GetName()) !=
     531           0 :                          aosLayerNames.cend())
     532           0 :                     bRequested = true;
     533             :             }
     534             : 
     535          18 :             if (!bRequested)
     536           0 :                 continue;
     537             : 
     538             :             // Checks that the layer is not already in tileindex.
     539          18 :             int i = 0;  // Used after for.
     540          18 :             for (; i < nExistingLayers; i++)
     541             :             {
     542             :                 // TODO(schwehr): Move this off of the stack.
     543           0 :                 char szLocation[5000] = {};
     544           0 :                 snprintf(szLocation, sizeof(szLocation), "%s,%d",
     545             :                          fileNameToWrite, iLayer);
     546           0 :                 if (EQUAL(szLocation, existingLayersTab[i]))
     547             :                 {
     548           0 :                     fprintf(stderr,
     549             :                             "Layer %d of %s is already in tileindex. "
     550             :                             "Skipping it.\n",
     551             :                             iLayer, srcDataSet.c_str());
     552           0 :                     break;
     553             :                 }
     554             :             }
     555          18 :             if (i != nExistingLayers)
     556             :             {
     557           0 :                 continue;
     558             :             }
     559             : 
     560          18 :             OGRSpatialReference *spatialRef = poLayer->GetSpatialRef();
     561             :             // If not set target srs, test that the current file uses same
     562             :             // projection as others.
     563          18 :             if (!bSetTargetSRS)
     564             :             {
     565           8 :                 if (alreadyExistingSpatialRefValid)
     566             :                 {
     567           3 :                     if ((spatialRef != nullptr &&
     568           3 :                          alreadyExistingSpatialRef != nullptr &&
     569           3 :                          spatialRef->IsSame(alreadyExistingSpatialRef) ==
     570          12 :                              FALSE) ||
     571           6 :                         ((spatialRef != nullptr) !=
     572           6 :                          (alreadyExistingSpatialRef != nullptr)))
     573             :                     {
     574           0 :                         fprintf(
     575             :                             stderr,
     576             :                             "Warning : layer %d of %s is not using the same "
     577             :                             "projection system as other files in the "
     578             :                             "tileindex. This may cause problems when using it "
     579             :                             "in MapServer for example.%s\n",
     580             :                             iLayer, srcDataSet.c_str(),
     581             :                             bSkipDifferentProjection ? " Skipping it" : "");
     582           0 :                         if (bSkipDifferentProjection)
     583             :                         {
     584           0 :                             continue;
     585             :                         }
     586             :                     }
     587             :                 }
     588             :                 else
     589             :                 {
     590           2 :                     alreadyExistingSpatialRefValid = true;
     591           2 :                     alreadyExistingSpatialRef =
     592           2 :                         spatialRef ? spatialRef->Clone() : nullptr;
     593             :                 }
     594             :             }
     595             : 
     596             :             /* ------------------------------------------------------------------ */
     597             :             /* Check if all layers in dataset have the same attributes schema.    */
     598             :             /* ------------------------------------------------------------------ */
     599             : 
     600          18 :             if (poFeatureDefn == nullptr)
     601             :             {
     602           7 :                 poFeatureDefn = poLayer->GetLayerDefn()->Clone();
     603             :             }
     604          11 :             else if (!bAcceptDifferentSchemas)
     605             :             {
     606          11 :                 OGRFeatureDefn *poFeatureDefnCur = poLayer->GetLayerDefn();
     607          11 :                 assert(nullptr != poFeatureDefnCur);
     608             : 
     609          11 :                 const int fieldCount = poFeatureDefnCur->GetFieldCount();
     610             : 
     611          11 :                 if (fieldCount != poFeatureDefn->GetFieldCount())
     612             :                 {
     613           0 :                     fprintf(stderr,
     614             :                             "Number of attributes of layer %s of %s "
     615             :                             "does not match ... skipping it.\n",
     616           0 :                             poLayer->GetLayerDefn()->GetName(),
     617             :                             srcDataSet.c_str());
     618           0 :                     if (bFirstWarningForNonMatchingAttributes)
     619             :                     {
     620           0 :                         fprintf(
     621             :                             stderr,
     622             :                             "Note : you can override this "
     623             :                             "behavior with -accept_different_schemas option\n"
     624             :                             "but this may result in a tileindex incompatible "
     625             :                             "with MapServer\n");
     626           0 :                         bFirstWarningForNonMatchingAttributes = false;
     627             :                     }
     628           0 :                     continue;
     629             :                 }
     630             : 
     631          11 :                 bool bSkip = false;
     632          22 :                 for (int fn = 0; fn < poFeatureDefnCur->GetFieldCount(); fn++)
     633             :                 {
     634          11 :                     OGRFieldDefn *poField = poFeatureDefn->GetFieldDefn(fn);
     635             :                     OGRFieldDefn *poFieldCur =
     636          11 :                         poFeatureDefnCur->GetFieldDefn(fn);
     637             : 
     638             :                     // XXX - Should those pointers be checked against NULL?
     639          11 :                     assert(nullptr != poField);
     640          11 :                     assert(nullptr != poFieldCur);
     641             : 
     642          22 :                     if (poField->GetType() != poFieldCur->GetType() ||
     643          22 :                         poField->GetWidth() != poFieldCur->GetWidth() ||
     644          33 :                         poField->GetPrecision() != poFieldCur->GetPrecision() ||
     645          11 :                         !EQUAL(poField->GetNameRef(), poFieldCur->GetNameRef()))
     646             :                     {
     647           0 :                         fprintf(stderr,
     648             :                                 "Schema of attributes of layer %s of %s "
     649             :                                 "does not match. Skipping it.\n",
     650           0 :                                 poLayer->GetLayerDefn()->GetName(),
     651             :                                 srcDataSet.c_str());
     652           0 :                         if (bFirstWarningForNonMatchingAttributes)
     653             :                         {
     654           0 :                             fprintf(
     655             :                                 stderr,
     656             :                                 "Note : you can override this "
     657             :                                 "behavior with -accept_different_schemas "
     658             :                                 "option,\nbut this may result in a tileindex "
     659             :                                 "incompatible with MapServer\n");
     660           0 :                             bFirstWarningForNonMatchingAttributes = false;
     661             :                         }
     662           0 :                         bSkip = true;
     663           0 :                         break;
     664             :                     }
     665             :                 }
     666             : 
     667          11 :                 if (bSkip)
     668           0 :                     continue;
     669             :             }
     670             : 
     671             :             /* ----------------------------------------------------------------- */
     672             :             /*      Get layer extents, and create a corresponding polygon        */
     673             :             /*      geometry.                                                    */
     674             :             /* ----------------------------------------------------------------- */
     675          18 :             OGREnvelope sExtents;
     676             : 
     677          18 :             if (poLayer->GetExtent(&sExtents, TRUE) != OGRERR_NONE)
     678             :             {
     679           0 :                 fprintf(stderr,
     680             :                         "GetExtent() failed on layer %s of %s, skipping.\n",
     681           0 :                         poLayer->GetLayerDefn()->GetName(), srcDataSet.c_str());
     682           0 :                 continue;
     683             :             }
     684             : 
     685          18 :             OGRLinearRing oRing;
     686          18 :             oRing.addPoint(sExtents.MinX, sExtents.MinY);
     687          18 :             oRing.addPoint(sExtents.MinX, sExtents.MaxY);
     688          18 :             oRing.addPoint(sExtents.MaxX, sExtents.MaxY);
     689          18 :             oRing.addPoint(sExtents.MaxX, sExtents.MinY);
     690          18 :             oRing.addPoint(sExtents.MinX, sExtents.MinY);
     691             : 
     692          18 :             OGRPolygon oRegion;
     693          18 :             oRegion.addRing(&oRing);
     694             : 
     695             :             // If set target srs, do the forward transformation of all points.
     696          18 :             if (bSetTargetSRS && spatialRef != nullptr)
     697             :             {
     698          10 :                 if (!spatialRef->IsSame(poTargetSRS))
     699             :                 {
     700             :                     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
     701             :                         OGRCreateCoordinateTransformation(spatialRef,
     702           5 :                                                           poTargetSRS));
     703          10 :                     if (poCT == nullptr ||
     704           5 :                         oRegion.transform(poCT.get()) == OGRERR_FAILURE)
     705             :                     {
     706           0 :                         char *pszSourceWKT = nullptr;
     707           0 :                         spatialRef->exportToWkt(&pszSourceWKT);
     708           0 :                         fprintf(
     709             :                             stderr,
     710             :                             "Warning : unable to transform points from source "
     711             :                             "SRS `%s' to target SRS `%s'\n"
     712             :                             "for file `%s' - file skipped\n",
     713             :                             pszSourceWKT, osTargetSRS.c_str(),
     714             :                             srcDataSet.c_str());
     715           0 :                         CPLFree(pszSourceWKT);
     716           0 :                         continue;
     717             :                     }
     718             :                 }
     719             :             }
     720             : 
     721             :             /* ---------------------------------------------------------------- */
     722             :             /*      Add layer to tileindex.                                     */
     723             :             /* ---------------------------------------------------------------- */
     724          36 :             OGRFeature oTileFeat(poDstLayer->GetLayerDefn());
     725             : 
     726             :             // TODO(schwehr): Move this off of the stack.
     727          18 :             char szLocation[5000] = {};
     728          18 :             snprintf(szLocation, sizeof(szLocation), "%s,%d", fileNameToWrite,
     729             :                      iLayer);
     730          18 :             oTileFeat.SetGeometry(&oRegion);
     731          18 :             oTileFeat.SetField(iTileIndexField, szLocation);
     732             : 
     733          18 :             if (i_SrcSRSName >= 0 && spatialRef != nullptr)
     734             :             {
     735             :                 const char *pszAuthorityCode =
     736          10 :                     spatialRef->GetAuthorityCode(nullptr);
     737             :                 const char *pszAuthorityName =
     738          10 :                     spatialRef->GetAuthorityName(nullptr);
     739          10 :                 char *pszWKT = nullptr;
     740          10 :                 spatialRef->exportToWkt(&pszWKT);
     741          10 :                 if (eSrcSRSFormat == FORMAT_AUTO)
     742             :                 {
     743           4 :                     if (pszAuthorityName != nullptr &&
     744             :                         pszAuthorityCode != nullptr)
     745             :                     {
     746           4 :                         oTileFeat.SetField(i_SrcSRSName,
     747             :                                            CPLSPrintf("%s:%s", pszAuthorityName,
     748             :                                                       pszAuthorityCode));
     749             :                     }
     750           0 :                     else if (nMaxFieldSize == 0 ||
     751           0 :                              strlen(pszWKT) <= nMaxFieldSize)
     752             :                     {
     753           0 :                         oTileFeat.SetField(i_SrcSRSName, pszWKT);
     754             :                     }
     755             :                     else
     756             :                     {
     757           0 :                         char *pszProj4 = nullptr;
     758           0 :                         if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
     759             :                         {
     760           0 :                             oTileFeat.SetField(i_SrcSRSName, pszProj4);
     761           0 :                             CPLFree(pszProj4);
     762             :                         }
     763             :                         else
     764             :                         {
     765           0 :                             oTileFeat.SetField(i_SrcSRSName, pszWKT);
     766             :                         }
     767             :                     }
     768             :                 }
     769           6 :                 else if (eSrcSRSFormat == FORMAT_WKT)
     770             :                 {
     771           2 :                     if (nMaxFieldSize == 0 || strlen(pszWKT) <= nMaxFieldSize)
     772             :                     {
     773           2 :                         oTileFeat.SetField(i_SrcSRSName, pszWKT);
     774             :                     }
     775             :                     else
     776             :                     {
     777           0 :                         fprintf(
     778             :                             stderr,
     779             :                             "Cannot write WKT for file %s as it is too long!\n",
     780             :                             fileNameToWrite);
     781             :                     }
     782             :                 }
     783           4 :                 else if (eSrcSRSFormat == FORMAT_PROJ)
     784             :                 {
     785           2 :                     char *pszProj4 = nullptr;
     786           2 :                     if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
     787             :                     {
     788           2 :                         oTileFeat.SetField(i_SrcSRSName, pszProj4);
     789           2 :                         CPLFree(pszProj4);
     790             :                     }
     791             :                 }
     792           2 :                 else if (eSrcSRSFormat == FORMAT_EPSG)
     793             :                 {
     794           2 :                     if (pszAuthorityName != nullptr &&
     795             :                         pszAuthorityCode != nullptr)
     796           2 :                         oTileFeat.SetField(i_SrcSRSName,
     797             :                                            CPLSPrintf("%s:%s", pszAuthorityName,
     798             :                                                       pszAuthorityCode));
     799             :                 }
     800          10 :                 CPLFree(pszWKT);
     801             :             }
     802          18 :             if (poDstLayer->CreateFeature(&oTileFeat) != OGRERR_NONE)
     803             :             {
     804           0 :                 fprintf(stderr, "Failed to create feature on tile index. "
     805             :                                 "Terminating.");
     806           0 :                 GDALClose(poDstDS);
     807           0 :                 exit(1);
     808             :             }
     809             :         }
     810             : 
     811             :         /* ---------------------------------------------------------------- */
     812             :         /*      Cleanup this data source.                                   */
     813             :         /* ---------------------------------------------------------------- */
     814          18 :         CPLFree(fileNameToWrite);
     815          18 :         GDALClose(poDS);
     816             :     }
     817             : 
     818             :     /* -------------------------------------------------------------------- */
     819             :     /*      Close tile index and clear buffers.                             */
     820             :     /* -------------------------------------------------------------------- */
     821           7 :     int nRetCode = 0;
     822           7 :     if (GDALClose(poDstDS) != CE_None)
     823           0 :         nRetCode = 1;
     824           7 :     OGRFeatureDefn::DestroyFeatureDefn(poFeatureDefn);
     825             : 
     826           7 :     if (alreadyExistingSpatialRef != nullptr)
     827           1 :         alreadyExistingSpatialRef->Release();
     828           7 :     delete poTargetSRS;
     829             : 
     830           7 :     CPLFree(pszCurrentPath);
     831             : 
     832           7 :     if (nExistingLayers)
     833             :     {
     834           0 :         for (int i = 0; i < nExistingLayers; i++)
     835             :         {
     836           0 :             CPLFree(existingLayersTab[i]);
     837             :         }
     838           0 :         CPLFree(existingLayersTab);
     839             :     }
     840             : 
     841           7 :     GDALDestroy();
     842             : 
     843           7 :     return nRetCode;
     844             : }
     845             : 
     846           0 : MAIN_END

Generated by: LCOV version 1.14