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

Generated by: LCOV version 1.14