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

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

Generated by: LCOV version 1.14