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
|