Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of GDALDriver class (and C wrappers)
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2000, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "gdal.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_rat.h"
18 : #include "gdalalgorithm.h"
19 : #include "gdal_known_connection_prefixes.h"
20 :
21 : #include <algorithm>
22 : #include <cerrno>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <set>
26 : #include <sys/stat.h>
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_error.h"
30 : #include "cpl_minixml.h"
31 : #include "cpl_progress.h"
32 : #include "cpl_string.h"
33 : #include "cpl_vsi.h"
34 : #include "ograpispy.h"
35 : #include "ogr_core.h"
36 : #include "ogrsf_frmts.h"
37 :
38 : /************************************************************************/
39 : /* GDALDriver() */
40 : /************************************************************************/
41 :
42 : GDALDriver::GDALDriver() = default;
43 :
44 : /************************************************************************/
45 : /* ~GDALDriver() */
46 : /************************************************************************/
47 :
48 455737 : GDALDriver::~GDALDriver()
49 :
50 : {
51 257040 : if (pfnUnloadDriver != nullptr)
52 9385 : pfnUnloadDriver(this);
53 455737 : }
54 :
55 : /************************************************************************/
56 : /* GDALCreateDriver() */
57 : /************************************************************************/
58 :
59 : /**
60 : * \brief Create a GDALDriver.
61 : *
62 : * Creates a driver in the GDAL heap.
63 : */
64 :
65 225 : GDALDriverH CPL_STDCALL GDALCreateDriver()
66 : {
67 225 : return new GDALDriver();
68 : }
69 :
70 : /************************************************************************/
71 : /* GDALDestroyDriver() */
72 : /************************************************************************/
73 :
74 : /**
75 : * \brief Destroy a GDALDriver.
76 : *
77 : * This is roughly equivalent to deleting the driver, but is guaranteed
78 : * to take place in the GDAL heap. It is important this that function
79 : * not be called on a driver that is registered with the GDALDriverManager.
80 : *
81 : * @param hDriver the driver to destroy.
82 : */
83 :
84 0 : void CPL_STDCALL GDALDestroyDriver(GDALDriverH hDriver)
85 :
86 : {
87 0 : if (hDriver != nullptr)
88 0 : delete GDALDriver::FromHandle(hDriver);
89 0 : }
90 :
91 : /************************************************************************/
92 : /* Open() */
93 : /************************************************************************/
94 :
95 : //! @cond Doxygen_Suppress
96 :
97 451325 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
98 : {
99 :
100 451325 : GDALDataset *poDS = nullptr;
101 451325 : pfnOpen = GetOpenCallback();
102 451121 : if (pfnOpen != nullptr)
103 : {
104 451300 : poDS = pfnOpen(poOpenInfo);
105 : }
106 0 : else if (pfnOpenWithDriverArg != nullptr)
107 : {
108 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
109 : }
110 :
111 451551 : if (poDS)
112 : {
113 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
114 : // poDS->nOpenFlags
115 56308 : int nOpenFlags = poOpenInfo->nOpenFlags &
116 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
117 56308 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
118 909 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
119 56308 : poDS->nOpenFlags = nOpenFlags;
120 :
121 56308 : if (strlen(poDS->GetDescription()) == 0)
122 11740 : poDS->SetDescription(poOpenInfo->pszFilename);
123 :
124 56336 : if (poDS->poDriver == nullptr)
125 52229 : poDS->poDriver = this;
126 :
127 56336 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
128 : {
129 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
130 : }
131 :
132 56336 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
133 : {
134 45946 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
135 6 : CPLDebug(
136 : "GDAL",
137 : "GDALOpen(%s, this=%p) succeeds as "
138 : "%s (pid=%d, responsiblePID=%d).",
139 5 : poOpenInfo->pszFilename, poDS, GetDescription(),
140 5 : static_cast<int>(CPLGetPID()),
141 5 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
142 : else
143 45976 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
144 46025 : poOpenInfo->pszFilename, poDS, GetDescription());
145 :
146 46240 : poDS->AddToDatasetOpenList();
147 : }
148 : }
149 :
150 451596 : return poDS;
151 : }
152 :
153 : //! @endcond
154 :
155 : /************************************************************************/
156 : /* Create() */
157 : /************************************************************************/
158 :
159 : /**
160 : * \brief Create a new dataset with this driver.
161 : *
162 : * What argument values are legal for particular drivers is driver specific,
163 : * and there is no way to query in advance to establish legal values.
164 : *
165 : * That function will try to validate the creation option list passed to the
166 : * driver with the GDALValidateCreationOptions() method. This check can be
167 : * disabled by defining the configuration option
168 : * GDAL_VALIDATE_CREATION_OPTIONS=NO.
169 : *
170 : * After you have finished working with the returned dataset, it is
171 : * <b>required</b> to close it with GDALClose(). This does not only close the
172 : * file handle, but also ensures that all the data and metadata has been written
173 : * to the dataset (GDALFlushCache() is not sufficient for that purpose).
174 : *
175 : * In GDAL 2, the arguments nXSize, nYSize and nBands can be passed to 0 when
176 : * creating a vector-only dataset for a compatible driver.
177 : *
178 : * Equivalent of the C function GDALCreate().
179 : *
180 : * @param pszFilename the name of the dataset to create. UTF-8 encoded.
181 : * @param nXSize width of created raster in pixels.
182 : * @param nYSize height of created raster in pixels.
183 : * @param nBands number of bands.
184 : * @param eType type of raster.
185 : * @param papszOptions list of driver specific control parameters.
186 : * The APPEND_SUBDATASET=YES option can be
187 : * specified to avoid prior destruction of existing dataset.
188 : *
189 : * @return NULL on failure, or a new GDALDataset.
190 : */
191 :
192 23165 : GDALDataset *GDALDriver::Create(const char *pszFilename, int nXSize, int nYSize,
193 : int nBands, GDALDataType eType,
194 : CSLConstList papszOptions)
195 :
196 : {
197 : /* -------------------------------------------------------------------- */
198 : /* Does this format support creation. */
199 : /* -------------------------------------------------------------------- */
200 23165 : pfnCreate = GetCreateCallback();
201 23165 : if (CPL_UNLIKELY(pfnCreate == nullptr && pfnCreateEx == nullptr &&
202 : pfnCreateVectorOnly == nullptr))
203 : {
204 1 : CPLError(CE_Failure, CPLE_NotSupported,
205 : "GDALDriver::Create() ... no create method implemented"
206 : " for this format.");
207 :
208 1 : return nullptr;
209 : }
210 : /* -------------------------------------------------------------------- */
211 : /* Do some rudimentary argument checking. */
212 : /* -------------------------------------------------------------------- */
213 23164 : if (CPL_UNLIKELY(nBands < 0))
214 : {
215 1 : CPLError(CE_Failure, CPLE_AppDefined,
216 : "Attempt to create dataset with %d bands is illegal,"
217 : "Must be >= 0.",
218 : nBands);
219 1 : return nullptr;
220 : }
221 :
222 23163 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
223 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
224 23163 : (nXSize < 1 || nYSize < 1)))
225 : {
226 1 : CPLError(CE_Failure, CPLE_AppDefined,
227 : "Attempt to create %dx%d dataset is illegal,"
228 : "sizes must be larger than zero.",
229 : nXSize, nYSize);
230 1 : return nullptr;
231 : }
232 :
233 23162 : if (CPL_UNLIKELY(nBands != 0 &&
234 : (eType == GDT_Unknown || eType == GDT_TypeCount)))
235 : {
236 1 : CPLError(CE_Failure, CPLE_IllegalArg,
237 : "Illegal GDT_Unknown/GDT_TypeCount argument");
238 1 : return nullptr;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* Make sure we cleanup if there is an existing dataset of this */
243 : /* name. But even if that seems to fail we will continue since */
244 : /* it might just be a corrupt file or something. */
245 : /* -------------------------------------------------------------------- */
246 23161 : if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
247 : {
248 : // Someone issuing Create("foo.tif") on a
249 : // memory driver doesn't expect files with those names to be deleted
250 : // on a file system...
251 : // This is somewhat messy. Ideally there should be a way for the
252 : // driver to overload the default behavior
253 23142 : if (!EQUAL(GetDescription(), "MEM") &&
254 36117 : !EQUAL(GetDescription(), "Memory") &&
255 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
256 : // PostgisRaster driver which is undesirable
257 12975 : !EQUAL(GetDescription(), "PostgreSQL"))
258 : {
259 12973 : QuietDelete(pszFilename);
260 : }
261 : }
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Validate creation options. */
265 : /* -------------------------------------------------------------------- */
266 23161 : if (CPLTestBool(
267 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
268 23161 : GDALValidateCreationOptions(this, papszOptions);
269 :
270 : /* -------------------------------------------------------------------- */
271 : /* Proceed with creation. */
272 : /* -------------------------------------------------------------------- */
273 46321 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
274 23161 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
275 : GDALGetDataTypeName(eType), papszOptions);
276 :
277 23161 : GDALDataset *poDS = nullptr;
278 23161 : if (pfnCreateEx != nullptr)
279 : {
280 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
281 : const_cast<char **>(papszOptions));
282 : }
283 23161 : else if (pfnCreate != nullptr)
284 : {
285 23161 : poDS = pfnCreate(pszFilename, nXSize, nYSize, nBands, eType,
286 : const_cast<char **>(papszOptions));
287 : }
288 0 : else if (nBands < 1)
289 : {
290 0 : poDS = pfnCreateVectorOnly(this, pszFilename,
291 : const_cast<char **>(papszOptions));
292 : }
293 :
294 23161 : if (poDS != nullptr)
295 : {
296 43728 : if (poDS->GetDescription() == nullptr ||
297 21864 : strlen(poDS->GetDescription()) == 0)
298 19234 : poDS->SetDescription(pszFilename);
299 :
300 21864 : if (poDS->poDriver == nullptr)
301 21204 : poDS->poDriver = this;
302 :
303 21864 : poDS->AddToDatasetOpenList();
304 : }
305 :
306 23161 : return poDS;
307 : }
308 :
309 : /************************************************************************/
310 : /* GDALCreate() */
311 : /************************************************************************/
312 :
313 : /**
314 : * \brief Create a new dataset with this driver.
315 : *
316 : * @see GDALDriver::Create()
317 : */
318 :
319 19257 : GDALDatasetH CPL_DLL CPL_STDCALL GDALCreate(GDALDriverH hDriver,
320 : const char *pszFilename, int nXSize,
321 : int nYSize, int nBands,
322 : GDALDataType eBandType,
323 : CSLConstList papszOptions)
324 :
325 : {
326 19257 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
327 :
328 19257 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
329 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
330 :
331 : #ifdef OGRAPISPY_ENABLED
332 19257 : if (nBands < 1)
333 : {
334 3407 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
335 : const_cast<char **>(papszOptions), hDS);
336 : }
337 : #endif
338 :
339 19257 : return hDS;
340 : }
341 :
342 : /************************************************************************/
343 : /* CreateMultiDimensional() */
344 : /************************************************************************/
345 :
346 : /**
347 : * \brief Create a new multidimensional dataset with this driver.
348 : *
349 : * Only drivers that advertise the GDAL_DCAP_MULTIDIM_RASTER capability and
350 : * implement the pfnCreateMultiDimensional method might return a non nullptr
351 : * GDALDataset.
352 : *
353 : * This is the same as the C function GDALCreateMultiDimensional().
354 : *
355 : * @param pszFilename the name of the dataset to create. UTF-8 encoded.
356 : * @param papszRootGroupOptions driver specific options regarding the creation
357 : * of the root group. Might be nullptr.
358 : * @param papszOptions driver specific options regarding the creation
359 : * of the dataset. Might be nullptr.
360 : * @return a new dataset, or nullptr in case of failure.
361 : *
362 : * @since GDAL 3.1
363 : */
364 :
365 : GDALDataset *
366 472 : GDALDriver::CreateMultiDimensional(const char *pszFilename,
367 : CSLConstList papszRootGroupOptions,
368 : CSLConstList papszOptions)
369 :
370 : {
371 : /* -------------------------------------------------------------------- */
372 : /* Does this format support creation. */
373 : /* -------------------------------------------------------------------- */
374 472 : pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
375 472 : if (pfnCreateMultiDimensional == nullptr)
376 : {
377 0 : CPLError(CE_Failure, CPLE_NotSupported,
378 : "GDALDriver::CreateMultiDimensional() ... "
379 : "no CreateMultiDimensional method implemented "
380 : "for this format.");
381 :
382 0 : return nullptr;
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Validate creation options. */
387 : /* -------------------------------------------------------------------- */
388 472 : if (CPLTestBool(
389 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
390 : {
391 : const char *pszOptionList =
392 472 : GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
393 944 : CPLString osDriver;
394 472 : osDriver.Printf("driver %s", GetDescription());
395 472 : GDALValidateOptions(pszOptionList, papszOptions, "creation option",
396 : osDriver);
397 : }
398 :
399 472 : auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
400 : papszOptions);
401 :
402 472 : if (poDstDS != nullptr)
403 : {
404 940 : if (poDstDS->GetDescription() == nullptr ||
405 470 : strlen(poDstDS->GetDescription()) == 0)
406 93 : poDstDS->SetDescription(pszFilename);
407 :
408 470 : if (poDstDS->poDriver == nullptr)
409 468 : poDstDS->poDriver = this;
410 : }
411 :
412 472 : return poDstDS;
413 : }
414 :
415 : /************************************************************************/
416 : /* GDALCreateMultiDimensional() */
417 : /************************************************************************/
418 :
419 : /** \brief Create a new multidimensional dataset with this driver.
420 : *
421 : * This is the same as the C++ method GDALDriver::CreateMultiDimensional().
422 : */
423 429 : GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
424 : const char *pszName,
425 : CSLConstList papszRootGroupOptions,
426 : CSLConstList papszOptions)
427 : {
428 429 : VALIDATE_POINTER1(hDriver, __func__, nullptr);
429 429 : VALIDATE_POINTER1(pszName, __func__, nullptr);
430 429 : return GDALDataset::ToHandle(
431 : GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
432 429 : pszName, papszRootGroupOptions, papszOptions));
433 : }
434 :
435 : /************************************************************************/
436 : /* DefaultCreateCopyMultiDimensional() */
437 : /************************************************************************/
438 :
439 : //! @cond Doxygen_Suppress
440 :
441 20 : CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
442 : GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
443 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
444 : void *pProgressData)
445 : {
446 20 : if (pfnProgress == nullptr)
447 2 : pfnProgress = GDALDummyProgress;
448 :
449 40 : auto poSrcRG = poSrcDS->GetRootGroup();
450 20 : if (!poSrcRG)
451 0 : return CE_Failure;
452 40 : auto poDstRG = poDstDS->GetRootGroup();
453 20 : if (!poDstRG)
454 0 : return CE_Failure;
455 20 : GUInt64 nCurCost = 0;
456 40 : return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
457 : poSrcRG->GetTotalCopyCost(), pfnProgress,
458 20 : pProgressData, papszOptions)
459 20 : ? CE_None
460 20 : : CE_Failure;
461 : }
462 :
463 : //! @endcond
464 :
465 : /************************************************************************/
466 : /* DefaultCopyMasks() */
467 : /************************************************************************/
468 :
469 : //! @cond Doxygen_Suppress
470 6134 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
471 : int bStrict)
472 :
473 : {
474 6134 : return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
475 6134 : nullptr);
476 : }
477 :
478 8106 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
479 : int bStrict, CSLConstList /*papszOptions*/,
480 : GDALProgressFunc pfnProgress,
481 : void *pProgressData)
482 :
483 : {
484 8106 : if (pfnProgress == nullptr)
485 6134 : pfnProgress = GDALDummyProgress;
486 :
487 8106 : int nBands = poSrcDS->GetRasterCount();
488 8106 : if (nBands == 0)
489 0 : return CE_None;
490 :
491 : /* -------------------------------------------------------------------- */
492 : /* Try to copy mask if it seems appropriate. */
493 : /* -------------------------------------------------------------------- */
494 8106 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
495 8106 : CPLErr eErr = CE_None;
496 :
497 8106 : int nTotalBandsWithMask = 0;
498 28179 : for (int iBand = 0; iBand < nBands; ++iBand)
499 : {
500 20073 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
501 :
502 20073 : int nMaskFlags = poSrcBand->GetMaskFlags();
503 20073 : if (!(nMaskFlags &
504 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
505 : {
506 8 : nTotalBandsWithMask++;
507 : }
508 : }
509 :
510 8106 : int iBandWithMask = 0;
511 28179 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
512 : {
513 20073 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
514 :
515 20073 : int nMaskFlags = poSrcBand->GetMaskFlags();
516 20073 : if (eErr == CE_None && !(nMaskFlags & (GMF_ALL_VALID | GMF_PER_DATASET |
517 : GMF_ALPHA | GMF_NODATA)))
518 : {
519 8 : GDALRasterBand *poDstBand = poDstDS->GetRasterBand(iBand + 1);
520 8 : if (poDstBand != nullptr)
521 : {
522 8 : eErr = poDstBand->CreateMaskBand(nMaskFlags);
523 8 : if (eErr == CE_None)
524 : {
525 24 : void *pScaledData = GDALCreateScaledProgress(
526 8 : double(iBandWithMask) /
527 8 : std::max(1, nTotalBandsWithMask),
528 8 : double(iBandWithMask + 1) /
529 8 : std::max(1, nTotalBandsWithMask),
530 : pfnProgress, pProgressData);
531 16 : eErr = GDALRasterBandCopyWholeRaster(
532 8 : poSrcBand->GetMaskBand(), poDstBand->GetMaskBand(),
533 : papszOptions, GDALScaledProgress, pScaledData);
534 8 : GDALDestroyScaledProgress(pScaledData);
535 : }
536 0 : else if (!bStrict)
537 : {
538 0 : eErr = CE_None;
539 : }
540 : }
541 : }
542 : }
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Try to copy a per-dataset mask if we have one. */
546 : /* -------------------------------------------------------------------- */
547 8106 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
548 8106 : if (eErr == CE_None &&
549 8106 : !(nMaskFlags & (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) &&
550 13 : (nMaskFlags & GMF_PER_DATASET))
551 : {
552 8 : eErr = poDstDS->CreateMaskBand(nMaskFlags);
553 8 : if (eErr == CE_None)
554 : {
555 8 : eErr = GDALRasterBandCopyWholeRaster(
556 8 : poSrcDS->GetRasterBand(1)->GetMaskBand(),
557 8 : poDstDS->GetRasterBand(1)->GetMaskBand(), papszOptions,
558 : pfnProgress, pProgressData);
559 : }
560 0 : else if (!bStrict)
561 : {
562 0 : eErr = CE_None;
563 : }
564 : }
565 :
566 8106 : return eErr;
567 : }
568 :
569 : /************************************************************************/
570 : /* DefaultCreateCopy() */
571 : /************************************************************************/
572 :
573 1389 : GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
574 : GDALDataset *poSrcDS, int bStrict,
575 : CSLConstList papszOptions,
576 : GDALProgressFunc pfnProgress,
577 : void *pProgressData)
578 :
579 : {
580 1389 : if (pfnProgress == nullptr)
581 0 : pfnProgress = GDALDummyProgress;
582 :
583 1389 : CPLErrorReset();
584 :
585 : /* -------------------------------------------------------------------- */
586 : /* Use multidimensional raster API if available. */
587 : /* -------------------------------------------------------------------- */
588 2778 : auto poSrcGroup = poSrcDS->GetRootGroup();
589 1389 : if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
590 : {
591 36 : CPLStringList aosDatasetCO;
592 25 : for (const char *pszOption : cpl::Iterate(papszOptions))
593 : {
594 7 : if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
595 0 : aosDatasetCO.AddString(pszOption);
596 : }
597 : auto poDstDS = std::unique_ptr<GDALDataset>(
598 36 : CreateMultiDimensional(pszFilename, nullptr, aosDatasetCO.List()));
599 18 : if (!poDstDS)
600 0 : return nullptr;
601 36 : auto poDstGroup = poDstDS->GetRootGroup();
602 18 : if (!poDstGroup)
603 0 : return nullptr;
604 18 : if (DefaultCreateCopyMultiDimensional(
605 18 : poSrcDS, poDstDS.get(), CPL_TO_BOOL(bStrict), papszOptions,
606 18 : pfnProgress, pProgressData) != CE_None)
607 0 : return nullptr;
608 18 : return poDstDS.release();
609 : }
610 :
611 : /* -------------------------------------------------------------------- */
612 : /* Validate that we can create the output as requested. */
613 : /* -------------------------------------------------------------------- */
614 1371 : const int nXSize = poSrcDS->GetRasterXSize();
615 1371 : const int nYSize = poSrcDS->GetRasterYSize();
616 1371 : const int nBands = poSrcDS->GetRasterCount();
617 :
618 1371 : CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
619 :
620 1371 : const int nLayerCount = poSrcDS->GetLayerCount();
621 1395 : if (nBands == 0 && nLayerCount == 0 &&
622 24 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
623 : {
624 17 : CPLError(CE_Failure, CPLE_NotSupported,
625 : "GDALDriver::DefaultCreateCopy does not support zero band");
626 17 : return nullptr;
627 : }
628 1354 : if (poSrcDS->GetDriver() != nullptr &&
629 1324 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
630 1317 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
631 2681 : GetMetadataItem(GDAL_DCAP_RASTER) == nullptr &&
632 3 : GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)
633 : {
634 3 : CPLError(CE_Failure, CPLE_NotSupported,
635 : "Source driver is raster-only whereas output driver is "
636 : "vector-only");
637 3 : return nullptr;
638 : }
639 1351 : else if (poSrcDS->GetDriver() != nullptr &&
640 1321 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
641 7 : nullptr &&
642 7 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
643 7 : nullptr &&
644 2672 : GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
645 0 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
646 : {
647 0 : CPLError(CE_Failure, CPLE_NotSupported,
648 : "Source driver is vector-only whereas output driver is "
649 : "raster-only");
650 0 : return nullptr;
651 : }
652 :
653 1351 : if (!pfnProgress(0.0, nullptr, pProgressData))
654 : {
655 2 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
656 2 : return nullptr;
657 : }
658 :
659 : /* -------------------------------------------------------------------- */
660 : /* Propagate some specific structural metadata as options if it */
661 : /* appears to be supported by the target driver and the caller */
662 : /* didn't provide values. */
663 : /* -------------------------------------------------------------------- */
664 1349 : char **papszCreateOptions = CSLDuplicate(papszOptions);
665 1349 : const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
666 : "IMAGE_STRUCTURE", nullptr};
667 :
668 4015 : for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
669 2666 : iOptItem += 2)
670 : {
671 : // does the source have this metadata item on the first band?
672 2666 : auto poBand = poSrcDS->GetRasterBand(1);
673 2666 : poBand->EnablePixelTypeSignedByteWarning(false);
674 5332 : const char *pszValue = poBand->GetMetadataItem(
675 2666 : apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
676 2666 : poBand->EnablePixelTypeSignedByteWarning(true);
677 :
678 2666 : if (pszValue == nullptr)
679 2665 : continue;
680 :
681 : // Do not override provided value.
682 1 : if (CSLFetchNameValue(papszCreateOptions, pszValue) != nullptr)
683 0 : continue;
684 :
685 : // Does this appear to be a supported creation option on this driver?
686 : const char *pszOptionList =
687 1 : GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
688 :
689 1 : if (pszOptionList == nullptr ||
690 1 : strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
691 0 : continue;
692 :
693 1 : papszCreateOptions = CSLSetNameValue(papszCreateOptions,
694 1 : apszOptItems[iOptItem], pszValue);
695 : }
696 :
697 : /* -------------------------------------------------------------------- */
698 : /* Create destination dataset. */
699 : /* -------------------------------------------------------------------- */
700 1349 : GDALDataType eType = GDT_Unknown;
701 :
702 1349 : if (nBands > 0)
703 1333 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
704 : GDALDataset *poDstDS =
705 1349 : Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
706 :
707 1349 : CSLDestroy(papszCreateOptions);
708 :
709 1349 : if (poDstDS == nullptr)
710 326 : return nullptr;
711 :
712 1023 : int nDstBands = poDstDS->GetRasterCount();
713 1023 : CPLErr eErr = CE_None;
714 1023 : if (nDstBands != nBands)
715 : {
716 0 : if (GetMetadataItem(GDAL_DCAP_RASTER) != nullptr)
717 : {
718 : // Should not happen for a well-behaved driver.
719 0 : CPLError(
720 : CE_Failure, CPLE_AppDefined,
721 : "Output driver created only %d bands whereas %d were expected",
722 : nDstBands, nBands);
723 0 : eErr = CE_Failure;
724 : }
725 0 : nDstBands = 0;
726 : }
727 :
728 : /* -------------------------------------------------------------------- */
729 : /* Try setting the projection and geotransform if it seems */
730 : /* suitable. */
731 : /* -------------------------------------------------------------------- */
732 1023 : if (nDstBands == 0 && !bStrict)
733 4 : CPLTurnFailureIntoWarning(true);
734 :
735 1023 : GDALGeoTransform gt;
736 1934 : if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
737 1934 : gt != GDALGeoTransform())
738 : {
739 908 : eErr = poDstDS->SetGeoTransform(gt);
740 908 : if (!bStrict)
741 558 : eErr = CE_None;
742 : }
743 :
744 1023 : if (eErr == CE_None)
745 : {
746 1014 : const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
747 1014 : if (poSrcSRS && !poSrcSRS->IsEmpty())
748 : {
749 846 : eErr = poDstDS->SetSpatialRef(poSrcSRS);
750 846 : if (!bStrict)
751 528 : eErr = CE_None;
752 : }
753 : }
754 :
755 : /* -------------------------------------------------------------------- */
756 : /* Copy GCPs. */
757 : /* -------------------------------------------------------------------- */
758 1023 : if (poSrcDS->GetGCPCount() > 0 && eErr == CE_None)
759 : {
760 2 : eErr = poDstDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
761 : poSrcDS->GetGCPProjection());
762 2 : if (!bStrict)
763 1 : eErr = CE_None;
764 : }
765 :
766 1023 : if (nDstBands == 0 && !bStrict)
767 4 : CPLTurnFailureIntoWarning(false);
768 :
769 : /* -------------------------------------------------------------------- */
770 : /* Copy metadata. */
771 : /* -------------------------------------------------------------------- */
772 1023 : DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Loop copying bands. */
776 : /* -------------------------------------------------------------------- */
777 2602 : for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
778 : {
779 1579 : GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
780 1579 : GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
781 :
782 : /* --------------------------------------------------------------------
783 : */
784 : /* Do we need to copy a colortable. */
785 : /* --------------------------------------------------------------------
786 : */
787 1579 : GDALColorTable *const poCT = poSrcBand->GetColorTable();
788 1579 : if (poCT != nullptr)
789 29 : poDstBand->SetColorTable(poCT);
790 :
791 : /* --------------------------------------------------------------------
792 : */
793 : /* Do we need to copy other metadata? Most of this is */
794 : /* non-critical, so lets not bother folks if it fails are we */
795 : /* are not in strict mode. */
796 : /* --------------------------------------------------------------------
797 : */
798 1579 : if (!bStrict)
799 962 : CPLTurnFailureIntoWarning(true);
800 :
801 1579 : if (strlen(poSrcBand->GetDescription()) > 0)
802 52 : poDstBand->SetDescription(poSrcBand->GetDescription());
803 :
804 1579 : if (CSLCount(poSrcBand->GetMetadata()) > 0)
805 114 : poDstBand->SetMetadata(poSrcBand->GetMetadata());
806 :
807 1579 : int bSuccess = FALSE;
808 1579 : double dfValue = poSrcBand->GetOffset(&bSuccess);
809 1579 : if (bSuccess && dfValue != 0.0)
810 5 : poDstBand->SetOffset(dfValue);
811 :
812 1579 : dfValue = poSrcBand->GetScale(&bSuccess);
813 1579 : if (bSuccess && dfValue != 1.0)
814 4 : poDstBand->SetScale(dfValue);
815 :
816 1579 : GDALCopyNoDataValue(poDstBand, poSrcBand);
817 :
818 2606 : if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
819 1027 : poSrcBand->GetColorInterpretation() !=
820 1027 : poDstBand->GetColorInterpretation())
821 810 : poDstBand->SetColorInterpretation(
822 810 : poSrcBand->GetColorInterpretation());
823 :
824 1579 : char **papszCatNames = poSrcBand->GetCategoryNames();
825 1579 : if (nullptr != papszCatNames)
826 1 : poDstBand->SetCategoryNames(papszCatNames);
827 :
828 : // Only copy RAT if it is of reasonable size to fit in memory
829 1579 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
830 1581 : if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
831 2 : poRAT->GetRowCount() <
832 : 1024 * 1024)
833 : {
834 2 : poDstBand->SetDefaultRAT(poRAT);
835 : }
836 :
837 1579 : if (!bStrict)
838 : {
839 962 : CPLTurnFailureIntoWarning(false);
840 : }
841 : else
842 : {
843 617 : eErr = CPLGetLastErrorType();
844 : }
845 : }
846 :
847 : /* -------------------------------------------------------------------- */
848 : /* Copy image data. */
849 : /* -------------------------------------------------------------------- */
850 1023 : if (eErr == CE_None && nDstBands > 0)
851 : {
852 978 : const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
853 : nullptr};
854 978 : const bool bSkipHoles = CPLTestBool(
855 : CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
856 978 : eErr = GDALDatasetCopyWholeRaster(
857 : poSrcDS, poDstDS,
858 : bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
859 : pProgressData);
860 : }
861 :
862 : /* -------------------------------------------------------------------- */
863 : /* Should we copy some masks over? */
864 : /* -------------------------------------------------------------------- */
865 1023 : if (eErr == CE_None && nDstBands > 0)
866 961 : eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Copy vector layers */
870 : /* -------------------------------------------------------------------- */
871 1023 : if (eErr == CE_None)
872 : {
873 974 : if (nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer))
874 : {
875 20 : for (int iLayer = 0; iLayer < nLayerCount; ++iLayer)
876 : {
877 10 : OGRLayer *poLayer = poSrcDS->GetLayer(iLayer);
878 :
879 10 : if (poLayer == nullptr)
880 0 : continue;
881 :
882 10 : poDstDS->CopyLayer(poLayer, poLayer->GetName(), nullptr);
883 : }
884 : }
885 : }
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Try to cleanup the output dataset if the translation failed. */
889 : /* -------------------------------------------------------------------- */
890 1023 : if (eErr != CE_None)
891 : {
892 49 : delete poDstDS;
893 49 : if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
894 : {
895 : // Only delete if creating a new file
896 49 : Delete(pszFilename);
897 : }
898 49 : return nullptr;
899 : }
900 : else
901 : {
902 974 : CPLErrorReset();
903 : }
904 :
905 974 : return poDstDS;
906 : }
907 :
908 : /************************************************************************/
909 : /* DefaultCopyMetadata() */
910 : /************************************************************************/
911 :
912 5384 : void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
913 : CSLConstList papszOptions,
914 : CSLConstList papszExcludedDomains)
915 : {
916 : const char *pszCopySrcMDD =
917 5384 : CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
918 5384 : char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
919 5384 : if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
920 : papszSrcMDD)
921 : {
922 4 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
923 2 : CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
924 10610 : CSLFindString(papszExcludedDomains, "") < 0 &&
925 5224 : CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
926 : {
927 5224 : if (poSrcDS->GetMetadata() != nullptr)
928 824 : poDstDS->SetMetadata(poSrcDS->GetMetadata());
929 : }
930 :
931 : /* -------------------------------------------------------------------- */
932 : /* Copy transportable special domain metadata. */
933 : /* It would be nice to copy geolocation, but it is pretty fragile. */
934 : /* -------------------------------------------------------------------- */
935 5382 : constexpr const char *apszDefaultDomains[] = {
936 : "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
937 26910 : for (const char *pszDomain : apszDefaultDomains)
938 : {
939 43040 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
940 21512 : CSLFindString(papszExcludedDomains, pszDomain) < 0)
941 : {
942 21512 : char **papszMD = poSrcDS->GetMetadata(pszDomain);
943 21512 : if (papszMD)
944 5 : poDstDS->SetMetadata(papszMD, pszDomain);
945 : }
946 : }
947 :
948 5382 : if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
949 : papszSrcMDD)
950 : {
951 24 : for (const char *pszDomain :
952 30 : CPLStringList(poSrcDS->GetMetadataDomainList()))
953 : {
954 36 : if (pszDomain[0] != 0 &&
955 12 : (!papszSrcMDD ||
956 12 : CSLFindString(papszSrcMDD, pszDomain) >= 0))
957 : {
958 10 : bool bCanCopy = true;
959 10 : if (CSLFindString(papszExcludedDomains, pszDomain) >= 0)
960 : {
961 0 : bCanCopy = false;
962 : }
963 : else
964 : {
965 50 : for (const char *pszOtherDomain : apszDefaultDomains)
966 : {
967 40 : if (EQUAL(pszDomain, pszOtherDomain))
968 : {
969 0 : bCanCopy = false;
970 0 : break;
971 : }
972 : }
973 10 : if (!papszSrcMDD)
974 : {
975 6 : constexpr const char *const apszReservedDomains[] =
976 : {"IMAGE_STRUCTURE", "DERIVED_SUBDATASETS"};
977 6 : for (const char *pszOtherDomain :
978 12 : apszReservedDomains)
979 : {
980 10 : if (EQUAL(pszDomain, pszOtherDomain))
981 : {
982 4 : bCanCopy = false;
983 4 : break;
984 : }
985 : }
986 : }
987 : }
988 10 : if (bCanCopy)
989 : {
990 6 : poDstDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
991 6 : pszDomain);
992 : }
993 : }
994 : }
995 : }
996 : }
997 5384 : CSLDestroy(papszSrcMDD);
998 5384 : }
999 :
1000 : /************************************************************************/
1001 : /* QuietDeleteForCreateCopy() */
1002 : /************************************************************************/
1003 :
1004 11504 : CPLErr GDALDriver::QuietDeleteForCreateCopy(const char *pszFilename,
1005 : GDALDataset *poSrcDS)
1006 : {
1007 : // Someone issuing CreateCopy("foo.tif") on a
1008 : // memory driver doesn't expect files with those names to be deleted
1009 : // on a file system...
1010 : // This is somewhat messy. Ideally there should be a way for the
1011 : // driver to overload the default behavior
1012 22453 : if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1013 : // Also exclude database formats for which there's no file list
1014 : // and whose opening might be slow (GeoRaster in particular)
1015 33402 : !EQUAL(GetDescription(), "GeoRaster") &&
1016 10949 : !EQUAL(GetDescription(), "PostGISRaster"))
1017 : {
1018 : /* --------------------------------------------------------------------
1019 : */
1020 : /* Establish list of files of output dataset if it already
1021 : * exists. */
1022 : /* --------------------------------------------------------------------
1023 : */
1024 21862 : std::set<std::string> oSetExistingDestFiles;
1025 : {
1026 21862 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1027 10931 : const char *const apszAllowedDrivers[] = {GetDescription(),
1028 10931 : nullptr};
1029 : auto poExistingOutputDS =
1030 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1031 21862 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1032 10931 : if (poExistingOutputDS)
1033 : {
1034 674 : for (const char *pszFileInList :
1035 640 : CPLStringList(poExistingOutputDS->GetFileList()))
1036 : {
1037 : oSetExistingDestFiles.insert(
1038 337 : CPLString(pszFileInList).replaceAll('\\', '/'));
1039 : }
1040 : }
1041 : }
1042 :
1043 : /* --------------------------------------------------------------------
1044 : */
1045 : /* Check if the source dataset shares some files with the dest
1046 : * one.*/
1047 : /* --------------------------------------------------------------------
1048 : */
1049 21862 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1050 10931 : if (!oSetExistingDestFiles.empty())
1051 : {
1052 606 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1053 : // We need to reopen in a temporary dataset for the particular
1054 : // case of overwritten a .tif.ovr file from a .tif
1055 : // If we probe the file list of the .tif, it will then open the
1056 : // .tif.ovr !
1057 303 : const char *const apszAllowedDrivers[] = {
1058 303 : poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1059 : : nullptr,
1060 303 : nullptr};
1061 : auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1062 303 : poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1063 606 : poSrcDS->papszOpenOptions));
1064 303 : if (poSrcDSTmp)
1065 : {
1066 206 : for (const char *pszFileInList :
1067 400 : CPLStringList(poSrcDSTmp->GetFileList()))
1068 : {
1069 412 : CPLString osFilename(pszFileInList);
1070 206 : osFilename.replaceAll('\\', '/');
1071 206 : if (cpl::contains(oSetExistingDestFiles, osFilename))
1072 : {
1073 : oSetExistingDestFilesFoundInSource.insert(
1074 16 : std::move(osFilename));
1075 : }
1076 : }
1077 : }
1078 : }
1079 :
1080 : // If the source file(s) and the dest one share some files in
1081 : // common, only remove the files that are *not* in common
1082 10931 : if (!oSetExistingDestFilesFoundInSource.empty())
1083 : {
1084 36 : for (const std::string &osFilename : oSetExistingDestFiles)
1085 : {
1086 21 : if (!cpl::contains(oSetExistingDestFilesFoundInSource,
1087 : osFilename))
1088 : {
1089 5 : VSIUnlink(osFilename.c_str());
1090 : }
1091 : }
1092 : }
1093 :
1094 10931 : QuietDelete(pszFilename);
1095 : }
1096 :
1097 11504 : return CE_None;
1098 : }
1099 :
1100 : //! @endcond
1101 :
1102 : /************************************************************************/
1103 : /* CreateCopy() */
1104 : /************************************************************************/
1105 :
1106 : /**
1107 : * \brief Create a copy of a dataset.
1108 : *
1109 : * This method will attempt to create a copy of a raster dataset with the
1110 : * indicated filename, and in this drivers format. Band number, size,
1111 : * type, projection, geotransform and so forth are all to be copied from
1112 : * the provided template dataset.
1113 : *
1114 : * Note that many sequential write once formats (such as JPEG and PNG) don't
1115 : * implement the Create() method but do implement this CreateCopy() method.
1116 : * If the driver doesn't implement CreateCopy(), but does implement Create()
1117 : * then the default CreateCopy() mechanism built on calling Create() will
1118 : * be used.
1119 : * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1120 : * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1121 : *
1122 : * It is intended that CreateCopy() will often be used with a source dataset
1123 : * which is a virtual dataset allowing configuration of band types, and other
1124 : * information without actually duplicating raster data (see the VRT driver).
1125 : * This is what is done by the gdal_translate utility for example.
1126 : *
1127 : * That function will try to validate the creation option list passed to the
1128 : * driver with the GDALValidateCreationOptions() method. This check can be
1129 : * disabled by defining the configuration option
1130 : * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1131 : *
1132 : * This function copy all metadata from the default domain ("")
1133 : *
1134 : * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1135 : * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1136 : * controlled by the papszOptions creation options, and may differ from the
1137 : * poSrcDS src dataset.
1138 : * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1139 : * been specified in papszOptions, and if the driver supports equivalent
1140 : * interleaving as the src dataset, the CreateCopy() will internally add the
1141 : * proper creation option to get the same data interleaving.
1142 : *
1143 : * After you have finished working with the returned dataset, it is
1144 : * <b>required</b> to close it with GDALClose(). This does not only close the
1145 : * file handle, but also ensures that all the data and metadata has been written
1146 : * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1147 : *
1148 : * For multidimensional datasets, papszOptions can contain array creation
1149 : * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1150 : * documentation for further details regarding such options.
1151 : *
1152 : * @param pszFilename the name for the new dataset. UTF-8 encoded.
1153 : * @param poSrcDS the dataset being duplicated.
1154 : * @param bStrict TRUE if the copy must be strictly equivalent, or more
1155 : * normally FALSE indicating that the copy may adapt as needed for the
1156 : * output format.
1157 : * @param papszOptions additional format dependent options controlling
1158 : * creation of the output file.
1159 : * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1160 : * of existing dataset.
1161 : * Starting with GDAL 3.8.0, the following options are recognized by the
1162 : * GTiff, COG, VRT, PNG au JPEG drivers:
1163 : * <ul>
1164 : * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1165 : * should be copied to the destination dataset. In the default AUTO mode, only
1166 : * "safe" domains will be copied, which include the default metadata domain
1167 : * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1168 : * setting YES, all domains will be copied (but a few reserved ones like
1169 : * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1170 : * will be copied.
1171 : * </li>
1172 : *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1173 : * This option restricts the list of source metadata domains to be copied
1174 : * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1175 : * as many times as they are source domains. The default metadata domain is the
1176 : * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1177 : * </li>
1178 : * </ul>
1179 : * @param pfnProgress a function to be used to report progress of the copy.
1180 : * @param pProgressData application data passed into progress function.
1181 : *
1182 : * @return a pointer to the newly created dataset (may be read-only access).
1183 : */
1184 :
1185 11076 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1186 : GDALDataset *poSrcDS, int bStrict,
1187 : CSLConstList papszOptions,
1188 : GDALProgressFunc pfnProgress,
1189 : void *pProgressData)
1190 :
1191 : {
1192 11076 : if (pfnProgress == nullptr)
1193 8544 : pfnProgress = GDALDummyProgress;
1194 :
1195 11076 : const int nBandCount = poSrcDS->GetRasterCount();
1196 :
1197 : /* -------------------------------------------------------------------- */
1198 : /* If no INTERLEAVE creation option is given, we will try to add */
1199 : /* one that matches the current srcDS interleaving */
1200 : /* -------------------------------------------------------------------- */
1201 11076 : char **papszOptionsToDelete = nullptr;
1202 : const char *srcInterleave =
1203 11076 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1204 6674 : if (nBandCount > 1 && srcInterleave != nullptr &&
1205 24052 : CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1206 6302 : EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1207 : {
1208 :
1209 : // look for INTERLEAVE values of the driver
1210 6148 : char **interleavesCSL = nullptr;
1211 : const char *pszOptionList =
1212 6148 : this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1213 : CPLXMLNode *xmlNode =
1214 6148 : !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1215 6148 : for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1216 125251 : child != nullptr; child = child->psNext)
1217 : {
1218 119103 : if ((child->eType == CXT_Element) &&
1219 119103 : EQUAL(child->pszValue, "Option"))
1220 : {
1221 : const char *nameAttribute =
1222 119103 : CPLGetXMLValue(child, "name", nullptr);
1223 119103 : const bool isInterleaveAttribute =
1224 119103 : nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1225 119103 : if (isInterleaveAttribute)
1226 : {
1227 1140 : for (CPLXMLNode *optionChild = child->psChild;
1228 6908 : optionChild != nullptr;
1229 5768 : optionChild = optionChild->psNext)
1230 : {
1231 5768 : if ((optionChild->eType == CXT_Element) &&
1232 2333 : EQUAL(optionChild->pszValue, "Value"))
1233 : {
1234 2333 : CPLXMLNode *optionChildValue = optionChild->psChild;
1235 2333 : if (optionChildValue &&
1236 2333 : (optionChildValue->eType == CXT_Text))
1237 : {
1238 2333 : interleavesCSL = CSLAddString(
1239 2333 : interleavesCSL, optionChildValue->pszValue);
1240 : }
1241 : }
1242 : }
1243 : }
1244 : }
1245 : }
1246 6148 : CPLDestroyXMLNode(xmlNode);
1247 :
1248 : const char *dstInterleaveBand =
1249 11180 : (CSLFindString(interleavesCSL, "BAND") >= 0) ? "BAND"
1250 5032 : : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1251 6148 : : nullptr;
1252 : const char *dstInterleaveLine =
1253 12296 : (CSLFindString(interleavesCSL, "LINE") >= 0) ? "LINE"
1254 6148 : : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1255 6148 : : nullptr;
1256 : const char *dstInterleavePixel =
1257 11180 : (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1258 5032 : : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1259 6148 : : nullptr;
1260 6148 : const char *dstInterleave =
1261 6431 : EQUAL(srcInterleave, "BAND") ? dstInterleaveBand
1262 564 : : EQUAL(srcInterleave, "LINE") ? dstInterleaveLine
1263 281 : : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1264 : : nullptr;
1265 6148 : CSLDestroy(interleavesCSL);
1266 :
1267 6148 : if (dstInterleave != nullptr)
1268 : {
1269 1140 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1270 1140 : papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1271 : "INTERLEAVE", dstInterleave);
1272 1140 : papszOptionsToDelete = CSLSetNameValue(
1273 : papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1274 1140 : papszOptions = papszOptionsToDelete;
1275 : }
1276 : }
1277 :
1278 : /* -------------------------------------------------------------------- */
1279 : /* Make sure we cleanup if there is an existing dataset of this */
1280 : /* name. But even if that seems to fail we will continue since */
1281 : /* it might just be a corrupt file or something. */
1282 : /* -------------------------------------------------------------------- */
1283 : const bool bAppendSubdataset =
1284 11076 : CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
1285 : // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1286 : // driver when writing a .kmz file. Also by GDALTranslate() if it has
1287 : // already done a similar job.
1288 22132 : if (!bAppendSubdataset &&
1289 11056 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1290 : {
1291 8696 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1292 : }
1293 :
1294 : int iIdxQuietDeleteOnCreateCopy =
1295 11076 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1296 11076 : if (iIdxQuietDeleteOnCreateCopy >= 0)
1297 : {
1298 2360 : if (papszOptionsToDelete == nullptr)
1299 1357 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1300 2360 : papszOptionsToDelete = CSLRemoveStrings(
1301 : papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1302 2360 : papszOptions = papszOptionsToDelete;
1303 : }
1304 :
1305 : /* -------------------------------------------------------------------- */
1306 : /* If _INTERNAL_DATASET=YES, the returned dataset will not be */
1307 : /* registered in the global list of open datasets. */
1308 : /* -------------------------------------------------------------------- */
1309 : const int iIdxInternalDataset =
1310 11076 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1311 11076 : bool bInternalDataset = false;
1312 11076 : if (iIdxInternalDataset >= 0)
1313 : {
1314 : bInternalDataset =
1315 4165 : CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1316 4165 : if (papszOptionsToDelete == nullptr)
1317 4165 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1318 4165 : papszOptionsToDelete = CSLRemoveStrings(
1319 : papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1320 4165 : papszOptions = papszOptionsToDelete;
1321 : }
1322 :
1323 : /* -------------------------------------------------------------------- */
1324 : /* Validate creation options. */
1325 : /* -------------------------------------------------------------------- */
1326 11076 : if (CPLTestBool(
1327 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1328 : {
1329 22152 : auto poSrcGroup = poSrcDS->GetRootGroup();
1330 11076 : if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1331 : {
1332 194 : CPLStringList aosDatasetCO;
1333 104 : for (const char *pszOption : cpl::Iterate(papszOptions))
1334 : {
1335 7 : if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
1336 0 : aosDatasetCO.AddString(pszOption);
1337 : }
1338 97 : GDALValidateCreationOptions(this, aosDatasetCO.List());
1339 : }
1340 : else
1341 : {
1342 10979 : GDALValidateCreationOptions(this, papszOptions);
1343 : }
1344 : }
1345 :
1346 : /* -------------------------------------------------------------------- */
1347 : /* Advise the source raster that we are going to read it completely */
1348 : /* -------------------------------------------------------------------- */
1349 :
1350 11076 : const int nXSize = poSrcDS->GetRasterXSize();
1351 11076 : const int nYSize = poSrcDS->GetRasterYSize();
1352 11076 : GDALDataType eDT = GDT_Unknown;
1353 11076 : if (nBandCount > 0)
1354 : {
1355 10864 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1356 10864 : if (poSrcBand)
1357 10864 : eDT = poSrcBand->GetRasterDataType();
1358 : }
1359 11076 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1360 11076 : nullptr, nullptr);
1361 :
1362 : /* -------------------------------------------------------------------- */
1363 : /* If the format provides a CreateCopy() method use that, */
1364 : /* otherwise fallback to the internal implementation using the */
1365 : /* Create() method. */
1366 : /* -------------------------------------------------------------------- */
1367 11076 : GDALDataset *poDstDS = nullptr;
1368 11076 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1369 21061 : if (l_pfnCreateCopy != nullptr &&
1370 9985 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1371 : {
1372 9985 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1373 : const_cast<char **>(papszOptions),
1374 : pfnProgress, pProgressData);
1375 9985 : if (poDstDS != nullptr)
1376 : {
1377 17750 : if (poDstDS->GetDescription() == nullptr ||
1378 8875 : strlen(poDstDS->GetDescription()) == 0)
1379 383 : poDstDS->SetDescription(pszFilename);
1380 :
1381 8875 : if (poDstDS->poDriver == nullptr)
1382 7836 : poDstDS->poDriver = this;
1383 :
1384 8875 : if (!bInternalDataset)
1385 4710 : poDstDS->AddToDatasetOpenList();
1386 : }
1387 : }
1388 : else
1389 : {
1390 1091 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1391 : pfnProgress, pProgressData);
1392 : }
1393 :
1394 11076 : CSLDestroy(papszOptionsToDelete);
1395 11076 : return poDstDS;
1396 : }
1397 :
1398 : /************************************************************************/
1399 : /* GDALCreateCopy() */
1400 : /************************************************************************/
1401 :
1402 : /**
1403 : * \brief Create a copy of a dataset.
1404 : *
1405 : * @see GDALDriver::CreateCopy()
1406 : */
1407 :
1408 6323 : GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
1409 : const char *pszFilename,
1410 : GDALDatasetH hSrcDS, int bStrict,
1411 : CSLConstList papszOptions,
1412 : GDALProgressFunc pfnProgress,
1413 : void *pProgressData)
1414 :
1415 : {
1416 6323 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1417 6323 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1418 :
1419 6323 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1420 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1421 6323 : pfnProgress, pProgressData);
1422 : }
1423 :
1424 : /************************************************************************/
1425 : /* CanVectorTranslateFrom() */
1426 : /************************************************************************/
1427 :
1428 : /** Returns whether the driver can translate from a vector dataset,
1429 : * using the arguments passed to GDALVectorTranslate() stored in
1430 : * papszVectorTranslateArguments.
1431 : *
1432 : * This is used to determine if the driver supports the VectorTranslateFrom()
1433 : * operation.
1434 : *
1435 : * @param pszDestName Target dataset name
1436 : * @param poSourceDS Source dataset
1437 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1438 : * GDALVectorTranslate() (may be nullptr)
1439 : * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1440 : * array of strings to record the reason(s) for the impossibility.
1441 : * @return true if VectorTranslateFrom() can be called with the same arguments.
1442 : * @since GDAL 3.8
1443 : */
1444 811 : bool GDALDriver::CanVectorTranslateFrom(
1445 : const char *pszDestName, GDALDataset *poSourceDS,
1446 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1447 :
1448 : {
1449 811 : if (ppapszFailureReasons)
1450 : {
1451 0 : *ppapszFailureReasons = nullptr;
1452 : }
1453 :
1454 811 : if (!pfnCanVectorTranslateFrom)
1455 : {
1456 805 : if (ppapszFailureReasons)
1457 : {
1458 0 : *ppapszFailureReasons = CSLAddString(
1459 : nullptr,
1460 : "CanVectorTranslateFrom() not implemented for this driver");
1461 : }
1462 805 : return false;
1463 : }
1464 :
1465 6 : char **papszFailureReasons = nullptr;
1466 6 : bool bRet = pfnCanVectorTranslateFrom(
1467 : pszDestName, poSourceDS, papszVectorTranslateArguments,
1468 : ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1469 6 : if (!ppapszFailureReasons)
1470 : {
1471 2 : for (const char *pszReason :
1472 10 : cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
1473 : {
1474 2 : CPLDebug("GDAL", "%s", pszReason);
1475 : }
1476 6 : CSLDestroy(papszFailureReasons);
1477 : }
1478 6 : return bRet;
1479 : }
1480 :
1481 193 : bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1482 : {
1483 193 : if (pszOpenOptionName == nullptr)
1484 0 : return false;
1485 :
1486 : // Const cast is safe here since we are only reading the metadata
1487 386 : auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1488 193 : GDAL_DMD_OPENOPTIONLIST)};
1489 193 : if (pszOOMd == nullptr)
1490 74 : return false;
1491 :
1492 238 : const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1493 1074 : for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1494 955 : option = option->psNext)
1495 : {
1496 956 : if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1497 : pszOpenOptionName))
1498 1 : return true;
1499 : }
1500 118 : return false;
1501 : }
1502 :
1503 : /************************************************************************/
1504 : /* VectorTranslateFrom() */
1505 : /************************************************************************/
1506 :
1507 : /** Create a copy of a vector dataset, using the arguments passed to
1508 : * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1509 : *
1510 : * This may be implemented by some drivers that can convert from an existing
1511 : * dataset in an optimized way.
1512 : *
1513 : * This is for example used by the PMTiles to convert from MBTiles.
1514 : *
1515 : * @param pszDestName Target dataset name
1516 : * @param poSourceDS Source dataset
1517 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1518 : * GDALVectorTranslate() (may be nullptr)
1519 : * @param pfnProgress a function to be used to report progress of the copy.
1520 : * @param pProgressData application data passed into progress function.
1521 : * @return a new dataset in case of success, or nullptr in case of error.
1522 : * @since GDAL 3.8
1523 : */
1524 4 : GDALDataset *GDALDriver::VectorTranslateFrom(
1525 : const char *pszDestName, GDALDataset *poSourceDS,
1526 : CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1527 : void *pProgressData)
1528 :
1529 : {
1530 4 : if (!pfnVectorTranslateFrom)
1531 : {
1532 0 : CPLError(CE_Failure, CPLE_AppDefined,
1533 : "VectorTranslateFrom() not implemented for this driver");
1534 0 : return nullptr;
1535 : }
1536 :
1537 4 : return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1538 : papszVectorTranslateArguments, pfnProgress,
1539 4 : pProgressData);
1540 : }
1541 :
1542 : /************************************************************************/
1543 : /* QuietDelete() */
1544 : /************************************************************************/
1545 :
1546 : /**
1547 : * \brief Delete dataset if found.
1548 : *
1549 : * This is a helper method primarily used by Create() and
1550 : * CreateCopy() to predelete any dataset of the name soon to be
1551 : * created. It will attempt to delete the named dataset if
1552 : * one is found, otherwise it does nothing. An error is only
1553 : * returned if the dataset is found but the delete fails.
1554 : *
1555 : * This is a static method and it doesn't matter what driver instance
1556 : * it is invoked on. It will attempt to discover the correct driver
1557 : * using Identify().
1558 : *
1559 : * @param pszName the dataset name to try and delete.
1560 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1561 : * terminated list of strings with the driver short names that must be
1562 : * considered. (Note: implemented only starting with GDAL 3.4.1)
1563 : * @return CE_None if the dataset does not exist, or is deleted without issues.
1564 : */
1565 :
1566 23936 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1567 : CSLConstList papszAllowedDrivers)
1568 :
1569 : {
1570 : VSIStatBufL sStat;
1571 : const bool bExists =
1572 23936 : VSIStatExL(pszName, &sStat,
1573 23936 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1574 :
1575 : #ifdef S_ISFIFO
1576 23936 : if (bExists && S_ISFIFO(sStat.st_mode))
1577 0 : return CE_None;
1578 : #endif
1579 :
1580 23936 : GDALDriver *poDriver = nullptr;
1581 23936 : if (papszAllowedDrivers)
1582 : {
1583 64 : GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1584 32 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1585 : {
1586 : GDALDriver *poTmpDriver =
1587 32 : GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1588 32 : if (poTmpDriver)
1589 : {
1590 : const bool bIdentifyRes =
1591 32 : poTmpDriver->pfnIdentifyEx
1592 64 : ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1593 : 0
1594 64 : : poTmpDriver->pfnIdentify &&
1595 32 : poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1596 32 : if (bIdentifyRes)
1597 : {
1598 32 : poDriver = poTmpDriver;
1599 32 : break;
1600 : }
1601 : }
1602 : }
1603 : }
1604 : else
1605 : {
1606 47808 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1607 23904 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1608 : }
1609 :
1610 23936 : if (poDriver == nullptr)
1611 22983 : return CE_None;
1612 :
1613 997 : if (bExists && VSI_ISDIR(sStat.st_mode) &&
1614 44 : (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1615 44 : EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1616 : {
1617 : // Those drivers are a bit special and handle directories as container
1618 : // of layers, but it is quite common to found other files too, and
1619 : // removing the directory might be non-desirable.
1620 42 : return CE_None;
1621 : }
1622 :
1623 911 : CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1624 :
1625 911 : poDriver->pfnDelete = poDriver->GetDeleteCallback();
1626 949 : const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1627 38 : poDriver->pfnDeleteDataSource == nullptr;
1628 911 : if (bQuiet)
1629 : {
1630 76 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1631 38 : return poDriver->Delete(pszName);
1632 : }
1633 : else
1634 : {
1635 873 : return poDriver->Delete(pszName);
1636 : }
1637 : }
1638 :
1639 : /************************************************************************/
1640 : /* Delete() */
1641 : /************************************************************************/
1642 :
1643 : /**
1644 : * \brief Delete named dataset.
1645 : *
1646 : * The driver will attempt to delete the named dataset in a driver specific
1647 : * fashion. Full featured drivers will delete all associated files,
1648 : * database objects, or whatever is appropriate. The default behavior when
1649 : * no driver specific behavior is provided is to attempt to delete all the
1650 : * files that are returned by GDALGetFileList() on the dataset handle.
1651 : *
1652 : * It is unwise to have open dataset handles on this dataset when it is
1653 : * deleted.
1654 : *
1655 : * Equivalent of the C function GDALDeleteDataset().
1656 : *
1657 : * @param pszFilename name of dataset to delete.
1658 : *
1659 : * @return CE_None on success, or CE_Failure if the operation fails.
1660 : */
1661 :
1662 4478 : CPLErr GDALDriver::Delete(const char *pszFilename)
1663 :
1664 : {
1665 4478 : pfnDelete = GetDeleteCallback();
1666 4478 : if (pfnDelete != nullptr)
1667 1073 : return pfnDelete(pszFilename);
1668 3405 : else if (pfnDeleteDataSource != nullptr)
1669 0 : return pfnDeleteDataSource(this, pszFilename);
1670 :
1671 : /* -------------------------------------------------------------------- */
1672 : /* Collect file list. */
1673 : /* -------------------------------------------------------------------- */
1674 3405 : GDALDatasetH hDS = GDALOpenEx(pszFilename, 0, nullptr, nullptr, nullptr);
1675 :
1676 3405 : if (hDS == nullptr)
1677 : {
1678 239 : if (CPLGetLastErrorNo() == 0)
1679 212 : CPLError(CE_Failure, CPLE_OpenFailed,
1680 : "Unable to open %s to obtain file list.", pszFilename);
1681 :
1682 239 : return CE_Failure;
1683 : }
1684 :
1685 6332 : const CPLStringList aosFileList(GDALGetFileList(hDS));
1686 :
1687 3166 : GDALClose(hDS);
1688 3166 : hDS = nullptr;
1689 :
1690 3166 : if (aosFileList.empty())
1691 : {
1692 0 : CPLError(CE_Failure, CPLE_NotSupported,
1693 : "Unable to determine files associated with %s, "
1694 : "delete fails.",
1695 : pszFilename);
1696 0 : return CE_Failure;
1697 : }
1698 :
1699 3166 : return Delete(nullptr, aosFileList.List());
1700 : }
1701 :
1702 : /************************************************************************/
1703 : /* Delete() */
1704 : /************************************************************************/
1705 :
1706 : /**
1707 : * \brief Delete a currently opened dataset
1708 : *
1709 : * The driver will attempt to delete the passed dataset in a driver specific
1710 : * fashion. Full featured drivers will delete all associated files,
1711 : * database objects, or whatever is appropriate. The default behavior when
1712 : * no driver specific behavior is provided is to attempt to delete all the
1713 : * files that are returned by GDALGetFileList() on the dataset handle.
1714 : *
1715 : * Note that this will generally not work on Windows systems that don't accept
1716 : * deleting opened files.
1717 : *
1718 : * At least one of poDS or papszFileList must not be NULL
1719 : *
1720 : * @param poDS dataset to delete, or NULL
1721 : * @param papszFileList File list to delete, typically obtained with
1722 : * poDS->GetFileList(), or NULL
1723 : *
1724 : * @return CE_None on success, or CE_Failure if the operation fails.
1725 : *
1726 : * @since 3.12
1727 : */
1728 :
1729 3177 : CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1730 :
1731 : {
1732 3177 : if (poDS)
1733 : {
1734 10 : pfnDelete = GetDeleteCallback();
1735 10 : if (pfnDelete != nullptr)
1736 6 : return pfnDelete(poDS->GetDescription());
1737 4 : else if (pfnDeleteDataSource != nullptr)
1738 0 : return pfnDeleteDataSource(this, poDS->GetDescription());
1739 : }
1740 :
1741 : /* -------------------------------------------------------------------- */
1742 : /* Delete all files. */
1743 : /* -------------------------------------------------------------------- */
1744 3171 : CPLErr eErr = CE_None;
1745 7003 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
1746 : {
1747 3832 : if (VSIUnlink(papszFileList[i]) != 0)
1748 : {
1749 4 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1750 2 : papszFileList[i], VSIStrerror(errno));
1751 2 : eErr = CE_Failure;
1752 : }
1753 : }
1754 :
1755 3171 : return eErr;
1756 : }
1757 :
1758 : /************************************************************************/
1759 : /* GDALDeleteDataset() */
1760 : /************************************************************************/
1761 :
1762 : /**
1763 : * \brief Delete named dataset.
1764 : *
1765 : * @see GDALDriver::Delete()
1766 : */
1767 :
1768 2444 : CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1769 : const char *pszFilename)
1770 :
1771 : {
1772 2444 : if (hDriver == nullptr)
1773 10 : hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1774 :
1775 2444 : if (hDriver == nullptr)
1776 : {
1777 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1778 : pszFilename);
1779 1 : return CE_Failure;
1780 : }
1781 :
1782 : #ifdef OGRAPISPY_ENABLED
1783 2443 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1784 : {
1785 454 : OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1786 : }
1787 : #endif
1788 :
1789 2443 : return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1790 : }
1791 :
1792 : /************************************************************************/
1793 : /* DefaultRename() */
1794 : /* */
1795 : /* The generic implementation based on the file list used when */
1796 : /* there is no format specific implementation. */
1797 : /************************************************************************/
1798 :
1799 : //! @cond Doxygen_Suppress
1800 173 : CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1801 :
1802 : {
1803 : /* -------------------------------------------------------------------- */
1804 : /* Collect file list. */
1805 : /* -------------------------------------------------------------------- */
1806 173 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1807 :
1808 173 : if (hDS == nullptr)
1809 : {
1810 0 : if (CPLGetLastErrorNo() == 0)
1811 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1812 : "Unable to open %s to obtain file list.", pszOldName);
1813 :
1814 0 : return CE_Failure;
1815 : }
1816 :
1817 173 : char **papszFileList = GDALGetFileList(hDS);
1818 :
1819 173 : GDALClose(hDS);
1820 :
1821 173 : if (CSLCount(papszFileList) == 0)
1822 : {
1823 0 : CPLError(CE_Failure, CPLE_NotSupported,
1824 : "Unable to determine files associated with %s,\n"
1825 : "rename fails.",
1826 : pszOldName);
1827 :
1828 0 : return CE_Failure;
1829 : }
1830 :
1831 : /* -------------------------------------------------------------------- */
1832 : /* Produce a list of new filenames that correspond to the old */
1833 : /* names. */
1834 : /* -------------------------------------------------------------------- */
1835 173 : CPLErr eErr = CE_None;
1836 : char **papszNewFileList =
1837 173 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1838 :
1839 173 : if (papszNewFileList == nullptr)
1840 0 : return CE_Failure;
1841 :
1842 353 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1843 : {
1844 180 : if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
1845 : {
1846 0 : eErr = CE_Failure;
1847 : // Try to put the ones we moved back.
1848 0 : for (--i; i >= 0; i--)
1849 : {
1850 : // Nothing we can do if the moving back doesn't work...
1851 0 : CPL_IGNORE_RET_VAL(
1852 0 : CPLMoveFile(papszFileList[i], papszNewFileList[i]));
1853 : }
1854 0 : break;
1855 : }
1856 : }
1857 :
1858 173 : CSLDestroy(papszNewFileList);
1859 173 : CSLDestroy(papszFileList);
1860 :
1861 173 : return eErr;
1862 : }
1863 :
1864 : //! @endcond
1865 :
1866 : /************************************************************************/
1867 : /* Rename() */
1868 : /************************************************************************/
1869 :
1870 : /**
1871 : * \brief Rename a dataset.
1872 : *
1873 : * Rename a dataset. This may including moving the dataset to a new directory
1874 : * or even a new filesystem.
1875 : *
1876 : * It is unwise to have open dataset handles on this dataset when it is
1877 : * being renamed.
1878 : *
1879 : * Equivalent of the C function GDALRenameDataset().
1880 : *
1881 : * @param pszNewName new name for the dataset.
1882 : * @param pszOldName old name for the dataset.
1883 : *
1884 : * @return CE_None on success, or CE_Failure if the operation fails.
1885 : */
1886 :
1887 175 : CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1888 :
1889 : {
1890 175 : pfnRename = GetRenameCallback();
1891 175 : if (pfnRename != nullptr)
1892 3 : return pfnRename(pszNewName, pszOldName);
1893 :
1894 172 : return DefaultRename(pszNewName, pszOldName);
1895 : }
1896 :
1897 : /************************************************************************/
1898 : /* GDALRenameDataset() */
1899 : /************************************************************************/
1900 :
1901 : /**
1902 : * \brief Rename a dataset.
1903 : *
1904 : * @see GDALDriver::Rename()
1905 : */
1906 :
1907 176 : CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1908 : const char *pszNewName,
1909 : const char *pszOldName)
1910 :
1911 : {
1912 176 : if (hDriver == nullptr)
1913 3 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1914 :
1915 176 : if (hDriver == nullptr)
1916 : {
1917 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1918 : pszOldName);
1919 1 : return CE_Failure;
1920 : }
1921 :
1922 175 : return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1923 : }
1924 :
1925 : /************************************************************************/
1926 : /* DefaultCopyFiles() */
1927 : /* */
1928 : /* The default implementation based on file lists used when */
1929 : /* there is no format specific implementation. */
1930 : /************************************************************************/
1931 :
1932 : //! @cond Doxygen_Suppress
1933 10 : CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1934 : const char *pszOldName)
1935 :
1936 : {
1937 : /* -------------------------------------------------------------------- */
1938 : /* Collect file list. */
1939 : /* -------------------------------------------------------------------- */
1940 10 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1941 :
1942 10 : if (hDS == nullptr)
1943 : {
1944 0 : if (CPLGetLastErrorNo() == 0)
1945 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1946 : "Unable to open %s to obtain file list.", pszOldName);
1947 :
1948 0 : return CE_Failure;
1949 : }
1950 :
1951 10 : char **papszFileList = GDALGetFileList(hDS);
1952 :
1953 10 : GDALClose(hDS);
1954 10 : hDS = nullptr;
1955 :
1956 10 : if (CSLCount(papszFileList) == 0)
1957 : {
1958 0 : CPLError(CE_Failure, CPLE_NotSupported,
1959 : "Unable to determine files associated with %s,\n"
1960 : "rename fails.",
1961 : pszOldName);
1962 :
1963 0 : return CE_Failure;
1964 : }
1965 :
1966 : /* -------------------------------------------------------------------- */
1967 : /* Produce a list of new filenames that correspond to the old */
1968 : /* names. */
1969 : /* -------------------------------------------------------------------- */
1970 10 : CPLErr eErr = CE_None;
1971 : char **papszNewFileList =
1972 10 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1973 :
1974 10 : if (papszNewFileList == nullptr)
1975 0 : return CE_Failure;
1976 :
1977 28 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1978 : {
1979 18 : if (CPLCopyFile(papszNewFileList[i], papszFileList[i]) != 0)
1980 : {
1981 0 : eErr = CE_Failure;
1982 : // Try to put the ones we moved back.
1983 0 : for (--i; i >= 0; --i)
1984 0 : VSIUnlink(papszNewFileList[i]);
1985 0 : break;
1986 : }
1987 : }
1988 :
1989 10 : CSLDestroy(papszNewFileList);
1990 10 : CSLDestroy(papszFileList);
1991 :
1992 10 : return eErr;
1993 : }
1994 :
1995 : //! @endcond
1996 :
1997 : /************************************************************************/
1998 : /* CopyFiles() */
1999 : /************************************************************************/
2000 :
2001 : /**
2002 : * \brief Copy the files of a dataset.
2003 : *
2004 : * Copy all the files associated with a dataset.
2005 : *
2006 : * Equivalent of the C function GDALCopyDatasetFiles().
2007 : *
2008 : * @param pszNewName new name for the dataset.
2009 : * @param pszOldName old name for the dataset.
2010 : *
2011 : * @return CE_None on success, or CE_Failure if the operation fails.
2012 : */
2013 :
2014 12 : CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2015 :
2016 : {
2017 12 : pfnCopyFiles = GetCopyFilesCallback();
2018 12 : if (pfnCopyFiles != nullptr)
2019 3 : return pfnCopyFiles(pszNewName, pszOldName);
2020 :
2021 9 : return DefaultCopyFiles(pszNewName, pszOldName);
2022 : }
2023 :
2024 : /************************************************************************/
2025 : /* GDALCopyDatasetFiles() */
2026 : /************************************************************************/
2027 :
2028 : /**
2029 : * \brief Copy the files of a dataset.
2030 : *
2031 : * @see GDALDriver::CopyFiles()
2032 : */
2033 :
2034 13 : CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2035 : const char *pszNewName,
2036 : const char *pszOldName)
2037 :
2038 : {
2039 13 : if (hDriver == nullptr)
2040 8 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2041 :
2042 13 : if (hDriver == nullptr)
2043 : {
2044 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2045 : pszOldName);
2046 1 : return CE_Failure;
2047 : }
2048 :
2049 12 : return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2050 : }
2051 :
2052 : /************************************************************************/
2053 : /* GDALDriverHasOpenOption() */
2054 : /************************************************************************/
2055 :
2056 : /**
2057 : * \brief Returns TRUE if the given open option is supported by the driver.
2058 : * @param hDriver the handle of the driver
2059 : * @param pszOpenOptionName name of the open option to be checked
2060 : * @return TRUE if the driver supports the open option
2061 : * @since GDAL 3.11
2062 : */
2063 2 : bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2064 : {
2065 2 : VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2066 2 : return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2067 : }
2068 :
2069 : /************************************************************************/
2070 : /* GDALGetDriverShortName() */
2071 : /************************************************************************/
2072 :
2073 : /**
2074 : * \brief Return the short name of a driver
2075 : *
2076 : * This is the string that can be
2077 : * passed to the GDALGetDriverByName() function.
2078 : *
2079 : * For the GeoTIFF driver, this is "GTiff"
2080 : *
2081 : * @param hDriver the handle of the driver
2082 : * @return the short name of the driver. The
2083 : * returned string should not be freed and is owned by the driver.
2084 : */
2085 :
2086 3693630 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2087 :
2088 : {
2089 3693630 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2090 :
2091 3693630 : return GDALDriver::FromHandle(hDriver)->GetDescription();
2092 : }
2093 :
2094 : /************************************************************************/
2095 : /* GDALGetDriverLongName() */
2096 : /************************************************************************/
2097 :
2098 : /**
2099 : * \brief Return the long name of a driver
2100 : *
2101 : * For the GeoTIFF driver, this is "GeoTIFF"
2102 : *
2103 : * @param hDriver the handle of the driver
2104 : * @return the long name of the driver or empty string. The
2105 : * returned string should not be freed and is owned by the driver.
2106 : */
2107 :
2108 491 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2109 :
2110 : {
2111 491 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2112 :
2113 : const char *pszLongName =
2114 491 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2115 :
2116 491 : if (pszLongName == nullptr)
2117 0 : return "";
2118 :
2119 491 : return pszLongName;
2120 : }
2121 :
2122 : /************************************************************************/
2123 : /* GDALGetDriverHelpTopic() */
2124 : /************************************************************************/
2125 :
2126 : /**
2127 : * \brief Return the URL to the help that describes the driver
2128 : *
2129 : * That URL is relative to the GDAL documentation directory.
2130 : *
2131 : * For the GeoTIFF driver, this is "frmt_gtiff.html"
2132 : *
2133 : * @param hDriver the handle of the driver
2134 : * @return the URL to the help that describes the driver or NULL. The
2135 : * returned string should not be freed and is owned by the driver.
2136 : */
2137 :
2138 0 : const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2139 :
2140 : {
2141 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2142 :
2143 0 : return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2144 : }
2145 :
2146 : /************************************************************************/
2147 : /* GDALGetDriverCreationOptionList() */
2148 : /************************************************************************/
2149 :
2150 : /**
2151 : * \brief Return the list of creation options of the driver
2152 : *
2153 : * Return the list of creation options of the driver used by Create() and
2154 : * CreateCopy() as an XML string
2155 : *
2156 : * @param hDriver the handle of the driver
2157 : * @return an XML string that describes the list of creation options or
2158 : * empty string. The returned string should not be freed and is
2159 : * owned by the driver.
2160 : */
2161 :
2162 0 : const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2163 :
2164 : {
2165 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2166 :
2167 : const char *pszOptionList =
2168 0 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2169 0 : GDAL_DMD_CREATIONOPTIONLIST);
2170 :
2171 0 : if (pszOptionList == nullptr)
2172 0 : return "";
2173 :
2174 0 : return pszOptionList;
2175 : }
2176 :
2177 : /************************************************************************/
2178 : /* GDALValidateCreationOptions() */
2179 : /************************************************************************/
2180 :
2181 : /**
2182 : * \brief Validate the list of creation options that are handled by a driver
2183 : *
2184 : * This is a helper method primarily used by Create() and
2185 : * CreateCopy() to validate that the passed in list of creation options
2186 : * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2187 : * by some drivers. @see GDALGetDriverCreationOptionList()
2188 : *
2189 : * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2190 : * function will return TRUE. Otherwise it will check that the keys and values
2191 : * in the list of creation options are compatible with the capabilities declared
2192 : * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2193 : * a (non fatal) warning will be emitted and FALSE will be returned.
2194 : *
2195 : * @param hDriver the handle of the driver with whom the lists of creation
2196 : * option must be validated
2197 : * @param papszCreationOptions the list of creation options. An array of
2198 : * strings, whose last element is a NULL pointer
2199 : * @return TRUE if the list of creation options is compatible with the Create()
2200 : * and CreateCopy() method of the driver, FALSE otherwise.
2201 : */
2202 :
2203 34400 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2204 : CSLConstList papszCreationOptions)
2205 : {
2206 34400 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2207 : const char *pszOptionList =
2208 34400 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2209 34400 : GDAL_DMD_CREATIONOPTIONLIST);
2210 34400 : CPLString osDriver;
2211 : osDriver.Printf("driver %s",
2212 34400 : GDALDriver::FromHandle(hDriver)->GetDescription());
2213 34400 : bool bFoundOptionToRemove = false;
2214 34400 : constexpr const char *const apszExcludedOptions[] = {
2215 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2216 50290 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2217 : {
2218 80075 : for (const char *pszExcludedOptions : apszExcludedOptions)
2219 : {
2220 64185 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2221 196 : pszCO[strlen(pszExcludedOptions)] == '=')
2222 : {
2223 196 : bFoundOptionToRemove = true;
2224 196 : break;
2225 : }
2226 : }
2227 16086 : if (bFoundOptionToRemove)
2228 196 : break;
2229 : }
2230 34400 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2231 34400 : char **papszOptionsToFree = nullptr;
2232 34400 : if (bFoundOptionToRemove)
2233 : {
2234 596 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2235 : {
2236 400 : bool bMatch = false;
2237 1625 : for (const char *pszExcludedOptions : apszExcludedOptions)
2238 : {
2239 1434 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2240 209 : pszCO[strlen(pszExcludedOptions)] == '=')
2241 : {
2242 209 : bMatch = true;
2243 209 : break;
2244 : }
2245 : }
2246 400 : if (!bMatch)
2247 191 : papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2248 : }
2249 196 : papszOptionsToValidate = papszOptionsToFree;
2250 : }
2251 :
2252 34400 : const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2253 : pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2254 34400 : CSLDestroy(papszOptionsToFree);
2255 34400 : return bRet;
2256 : }
2257 :
2258 : /************************************************************************/
2259 : /* GDALValidateOpenOptions() */
2260 : /************************************************************************/
2261 :
2262 57305 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2263 : const char *const *papszOpenOptions)
2264 : {
2265 57305 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2266 : const char *pszOptionList =
2267 57305 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2268 57257 : GDAL_DMD_OPENOPTIONLIST);
2269 114467 : CPLString osDriver;
2270 : osDriver.Printf("driver %s",
2271 57213 : GDALDriver::FromHandle(hDriver)->GetDescription());
2272 57247 : return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2273 57184 : osDriver);
2274 : }
2275 :
2276 : /************************************************************************/
2277 : /* GDALValidateOptions() */
2278 : /************************************************************************/
2279 :
2280 104523 : int GDALValidateOptions(const char *pszOptionList,
2281 : const char *const *papszOptionsToValidate,
2282 : const char *pszErrorMessageOptionType,
2283 : const char *pszErrorMessageContainerName)
2284 : {
2285 104523 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2286 87998 : return TRUE;
2287 16525 : if (pszOptionList == nullptr)
2288 175 : return TRUE;
2289 :
2290 16350 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2291 16350 : if (psNode == nullptr)
2292 : {
2293 0 : CPLError(CE_Warning, CPLE_AppDefined,
2294 : "Could not parse %s list of %s. Assuming options are valid.",
2295 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2296 0 : return TRUE;
2297 : }
2298 :
2299 16350 : bool bRet = true;
2300 44292 : while (*papszOptionsToValidate)
2301 : {
2302 27942 : char *pszKey = nullptr;
2303 : const char *pszValue =
2304 27942 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2305 27941 : if (pszKey == nullptr)
2306 : {
2307 1 : CPLError(CE_Warning, CPLE_NotSupported,
2308 : "%s '%s' is not formatted with the key=value format",
2309 : pszErrorMessageOptionType, *papszOptionsToValidate);
2310 1 : bRet = false;
2311 :
2312 1 : ++papszOptionsToValidate;
2313 2124 : continue;
2314 : }
2315 :
2316 27940 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2317 : {
2318 0 : ++papszOptionsToValidate;
2319 0 : CPLFree(pszKey);
2320 0 : continue;
2321 : }
2322 :
2323 : // Must we be forgiving in case of missing option ?
2324 27940 : bool bWarnIfMissingKey = true;
2325 27940 : if (pszKey[0] == '@')
2326 : {
2327 2107 : bWarnIfMissingKey = false;
2328 2107 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2329 : }
2330 :
2331 27940 : CPLXMLNode *psChildNode = psNode->psChild;
2332 274171 : while (psChildNode)
2333 : {
2334 272048 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2335 : {
2336 : const char *pszOptionName =
2337 272048 : CPLGetXMLValue(psChildNode, "name", "");
2338 : /* For option names terminated by wildcard (NITF BLOCKA option
2339 : * names for example) */
2340 272048 : if (strlen(pszOptionName) > 0 &&
2341 272049 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2342 378 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2343 : {
2344 216 : break;
2345 : }
2346 :
2347 : /* For option names beginning by a wildcard */
2348 271832 : if (pszOptionName[0] == '*' &&
2349 57 : strlen(pszKey) > strlen(pszOptionName) &&
2350 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2351 : pszOptionName + 1))
2352 : {
2353 2 : break;
2354 : }
2355 :
2356 : // For options names with * in the middle
2357 271830 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2358 271830 : if (pszStarInOptionName &&
2359 183 : pszStarInOptionName != pszOptionName &&
2360 : pszStarInOptionName !=
2361 183 : pszOptionName + strlen(pszOptionName) - 1 &&
2362 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2363 12 : pszOptionName) &&
2364 12 : EQUALN(pszKey, pszOptionName,
2365 : static_cast<size_t>(pszStarInOptionName -
2366 12 : pszOptionName)) &&
2367 12 : EQUAL(pszKey +
2368 : static_cast<size_t>(pszStarInOptionName -
2369 : pszOptionName) +
2370 : 1,
2371 : pszStarInOptionName + 1))
2372 : {
2373 6 : break;
2374 : }
2375 :
2376 271824 : if (EQUAL(pszOptionName, pszKey))
2377 : {
2378 25546 : break;
2379 : }
2380 246278 : const char *pszAlias = CPLGetXMLValue(
2381 : psChildNode, "alias",
2382 : CPLGetXMLValue(psChildNode, "deprecated_alias", ""));
2383 246279 : if (EQUAL(pszAlias, pszKey))
2384 : {
2385 48 : CPLDebug("GDAL",
2386 : "Using deprecated alias '%s'. New name is '%s'",
2387 : pszAlias, pszOptionName);
2388 48 : break;
2389 : }
2390 : }
2391 246231 : psChildNode = psChildNode->psNext;
2392 : }
2393 27941 : if (psChildNode == nullptr)
2394 : {
2395 2145 : if (bWarnIfMissingKey &&
2396 22 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2397 0 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2398 : true)))
2399 : {
2400 22 : CPLError(CE_Warning, CPLE_NotSupported,
2401 : "%s does not support %s %s",
2402 : pszErrorMessageContainerName,
2403 : pszErrorMessageOptionType, pszKey);
2404 22 : bRet = false;
2405 : }
2406 :
2407 2123 : CPLFree(pszKey);
2408 2123 : ++papszOptionsToValidate;
2409 2123 : continue;
2410 : }
2411 :
2412 : #ifdef DEBUG
2413 25818 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2414 153605 : while (psChildSubNode)
2415 : {
2416 127789 : if (psChildSubNode->eType == CXT_Attribute)
2417 : {
2418 89603 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2419 63784 : EQUAL(psChildSubNode->pszValue, "alias") ||
2420 63661 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2421 63580 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2422 63563 : EQUAL(psChildSubNode->pszValue, "description") ||
2423 41896 : EQUAL(psChildSubNode->pszValue, "type") ||
2424 16078 : EQUAL(psChildSubNode->pszValue, "min") ||
2425 15788 : EQUAL(psChildSubNode->pszValue, "max") ||
2426 15432 : EQUAL(psChildSubNode->pszValue, "default") ||
2427 1020 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2428 995 : EQUAL(psChildSubNode->pszValue, "required") ||
2429 940 : EQUAL(psChildSubNode->pszValue, "scope")))
2430 : {
2431 : /* Driver error */
2432 0 : CPLError(CE_Warning, CPLE_NotSupported,
2433 : "%s : unhandled attribute '%s' for %s %s.",
2434 : pszErrorMessageContainerName,
2435 : psChildSubNode->pszValue, pszKey,
2436 : pszErrorMessageOptionType);
2437 : }
2438 : }
2439 127787 : psChildSubNode = psChildSubNode->psNext;
2440 : }
2441 : #endif
2442 :
2443 25816 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2444 25816 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2445 25817 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2446 25818 : if (pszType != nullptr)
2447 : {
2448 25817 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2449 : {
2450 8613 : const char *pszValueIter = pszValue;
2451 22008 : while (*pszValueIter)
2452 : {
2453 13397 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2454 20 : *pszValueIter == '+' || *pszValueIter == '-'))
2455 : {
2456 2 : CPLError(CE_Warning, CPLE_NotSupported,
2457 : "'%s' is an unexpected value for %s %s of "
2458 : "type int.",
2459 : pszValue, pszKey, pszErrorMessageOptionType);
2460 2 : bRet = false;
2461 2 : break;
2462 : }
2463 13395 : ++pszValueIter;
2464 : }
2465 8613 : if (*pszValueIter == '\0')
2466 : {
2467 8611 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2468 : {
2469 10 : CPLError(CE_Warning, CPLE_NotSupported,
2470 : "'%s' is an unexpected value for %s %s that "
2471 : "should be >= %s.",
2472 : pszValue, pszKey, pszErrorMessageOptionType,
2473 : pszMin);
2474 10 : bRet = false;
2475 : }
2476 8611 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2477 : {
2478 12 : CPLError(CE_Warning, CPLE_NotSupported,
2479 : "'%s' is an unexpected value for %s %s that "
2480 : "should be <= %s.",
2481 : pszValue, pszKey, pszErrorMessageOptionType,
2482 : pszMax);
2483 12 : bRet = false;
2484 : }
2485 8613 : }
2486 : }
2487 17204 : else if (EQUAL(pszType, "UNSIGNED INT"))
2488 : {
2489 3 : const char *pszValueIter = pszValue;
2490 10 : while (*pszValueIter)
2491 : {
2492 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2493 0 : *pszValueIter == '+'))
2494 : {
2495 0 : CPLError(CE_Warning, CPLE_NotSupported,
2496 : "'%s' is an unexpected value for %s %s of "
2497 : "type unsigned int.",
2498 : pszValue, pszKey, pszErrorMessageOptionType);
2499 0 : bRet = false;
2500 0 : break;
2501 : }
2502 7 : ++pszValueIter;
2503 : }
2504 3 : if (*pszValueIter == '\0')
2505 : {
2506 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2507 : {
2508 0 : CPLError(CE_Warning, CPLE_NotSupported,
2509 : "'%s' is an unexpected value for %s %s that "
2510 : "should be >= %s.",
2511 : pszValue, pszKey, pszErrorMessageOptionType,
2512 : pszMin);
2513 0 : bRet = false;
2514 : }
2515 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2516 : {
2517 0 : CPLError(CE_Warning, CPLE_NotSupported,
2518 : "'%s' is an unexpected value for %s %s that "
2519 : "should be <= %s.",
2520 : pszValue, pszKey, pszErrorMessageOptionType,
2521 : pszMax);
2522 0 : bRet = false;
2523 : }
2524 : }
2525 : }
2526 17201 : else if (EQUAL(pszType, "FLOAT"))
2527 : {
2528 683 : char *endPtr = nullptr;
2529 683 : double dfVal = CPLStrtod(pszValue, &endPtr);
2530 683 : if (!(endPtr == nullptr || *endPtr == '\0'))
2531 : {
2532 0 : CPLError(
2533 : CE_Warning, CPLE_NotSupported,
2534 : "'%s' is an unexpected value for %s %s of type float.",
2535 : pszValue, pszKey, pszErrorMessageOptionType);
2536 0 : bRet = false;
2537 : }
2538 : else
2539 : {
2540 683 : if (pszMin && dfVal < CPLAtof(pszMin))
2541 : {
2542 2 : CPLError(CE_Warning, CPLE_NotSupported,
2543 : "'%s' is an unexpected value for %s %s that "
2544 : "should be >= %s.",
2545 : pszValue, pszKey, pszErrorMessageOptionType,
2546 : pszMin);
2547 2 : bRet = false;
2548 : }
2549 683 : if (pszMax && dfVal > CPLAtof(pszMax))
2550 : {
2551 0 : CPLError(CE_Warning, CPLE_NotSupported,
2552 : "'%s' is an unexpected value for %s %s that "
2553 : "should be <= %s.",
2554 : pszValue, pszKey, pszErrorMessageOptionType,
2555 : pszMax);
2556 0 : bRet = false;
2557 : }
2558 : }
2559 : }
2560 16518 : else if (EQUAL(pszType, "BOOLEAN"))
2561 : {
2562 3731 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2563 3675 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2564 427 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2565 : {
2566 0 : CPLError(CE_Warning, CPLE_NotSupported,
2567 : "'%s' is an unexpected value for %s %s of type "
2568 : "boolean.",
2569 : pszValue, pszKey, pszErrorMessageOptionType);
2570 0 : bRet = false;
2571 : }
2572 : }
2573 12787 : else if (EQUAL(pszType, "STRING-SELECT"))
2574 : {
2575 6613 : bool bMatchFound = false;
2576 6613 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2577 41050 : while (psStringSelect)
2578 : {
2579 41014 : if (psStringSelect->eType == CXT_Element &&
2580 20039 : EQUAL(psStringSelect->pszValue, "Value"))
2581 : {
2582 20039 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2583 33803 : while (psOptionNode)
2584 : {
2585 20341 : if (psOptionNode->eType == CXT_Text &&
2586 20025 : EQUAL(psOptionNode->pszValue, pszValue))
2587 : {
2588 6567 : bMatchFound = true;
2589 6567 : break;
2590 : }
2591 13774 : if (psOptionNode->eType == CXT_Attribute &&
2592 312 : (EQUAL(psOptionNode->pszValue, "alias") ||
2593 15 : EQUAL(psOptionNode->pszValue,
2594 297 : "deprecated_alias")) &&
2595 297 : EQUAL(psOptionNode->psChild->pszValue,
2596 : pszValue))
2597 : {
2598 10 : bMatchFound = true;
2599 10 : break;
2600 : }
2601 13764 : psOptionNode = psOptionNode->psNext;
2602 : }
2603 20039 : if (bMatchFound)
2604 6577 : break;
2605 : }
2606 34437 : psStringSelect = psStringSelect->psNext;
2607 : }
2608 6613 : if (!bMatchFound)
2609 : {
2610 37 : CPLError(CE_Warning, CPLE_NotSupported,
2611 : "'%s' is an unexpected value for %s %s of type "
2612 : "string-select.",
2613 : pszValue, pszKey, pszErrorMessageOptionType);
2614 37 : bRet = false;
2615 : }
2616 : }
2617 6174 : else if (EQUAL(pszType, "STRING"))
2618 : {
2619 : const char *pszMaxSize =
2620 6173 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2621 6173 : if (pszMaxSize != nullptr)
2622 : {
2623 25 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2624 : {
2625 1 : CPLError(CE_Warning, CPLE_NotSupported,
2626 : "'%s' is of size %d, whereas maximum size for "
2627 : "%s %s is %d.",
2628 1 : pszValue, static_cast<int>(strlen(pszValue)),
2629 : pszKey, pszErrorMessageOptionType,
2630 : atoi(pszMaxSize));
2631 1 : bRet = false;
2632 : }
2633 : }
2634 : }
2635 : else
2636 : {
2637 : /* Driver error */
2638 1 : CPLError(CE_Warning, CPLE_NotSupported,
2639 : "%s : type '%s' for %s %s is not recognized.",
2640 : pszErrorMessageContainerName, pszType, pszKey,
2641 : pszErrorMessageOptionType);
2642 : }
2643 : }
2644 : else
2645 : {
2646 : /* Driver error */
2647 1 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2648 : pszErrorMessageContainerName, pszKey,
2649 : pszErrorMessageOptionType);
2650 : }
2651 25818 : CPLFree(pszKey);
2652 25818 : ++papszOptionsToValidate;
2653 : }
2654 :
2655 16350 : CPLDestroyXMLNode(psNode);
2656 16350 : return bRet ? TRUE : FALSE;
2657 : }
2658 :
2659 : /************************************************************************/
2660 : /* GDALIdentifyDriver() */
2661 : /************************************************************************/
2662 :
2663 : /**
2664 : * \brief Identify the driver that can open a dataset.
2665 : *
2666 : * This function will try to identify the driver that can open the passed file
2667 : * name by invoking the Identify method of each registered GDALDriver in turn.
2668 : * The first driver that successfully identifies the file name will be returned.
2669 : * If all drivers fail then NULL is returned.
2670 : *
2671 : * In order to reduce the need for such searches to touch the operating system
2672 : * file system machinery, it is possible to give an optional list of files.
2673 : * This is the list of all files at the same level in the file system as the
2674 : * target file, including the target file. The filenames will not include any
2675 : * path components, and are essentially just the output of VSIReadDir() on the
2676 : * parent directory. If the target object does not have filesystem semantics
2677 : * then the file list should be NULL.
2678 : *
2679 : * @param pszFilename the name of the file to access. In the case of
2680 : * exotic drivers this may not refer to a physical file, but instead contain
2681 : * information for the driver on how to access a dataset.
2682 : *
2683 : * @param papszFileList an array of strings, whose last element is the NULL
2684 : * pointer. These strings are filenames that are auxiliary to the main
2685 : * filename. The passed value may be NULL.
2686 : *
2687 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2688 : * this handle can be cast to a GDALDriver *.
2689 : */
2690 :
2691 25188 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2692 : CSLConstList papszFileList)
2693 :
2694 : {
2695 25188 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2696 : }
2697 :
2698 : /************************************************************************/
2699 : /* GDALIdentifyDriverEx() */
2700 : /************************************************************************/
2701 :
2702 : /**
2703 : * \brief Identify the driver that can open a dataset.
2704 : *
2705 : * This function will try to identify the driver that can open the passed file
2706 : * name by invoking the Identify method of each registered GDALDriver in turn.
2707 : * The first driver that successfully identifies the file name will be returned.
2708 : * If all drivers fail then NULL is returned.
2709 : *
2710 : * In order to reduce the need for such searches to touch the operating system
2711 : * file system machinery, it is possible to give an optional list of files.
2712 : * This is the list of all files at the same level in the file system as the
2713 : * target file, including the target file. The filenames will not include any
2714 : * path components, and are essentially just the output of VSIReadDir() on the
2715 : * parent directory. If the target object does not have filesystem semantics
2716 : * then the file list should be NULL.
2717 : *
2718 : * @param pszFilename the name of the file to access. In the case of
2719 : * exotic drivers this may not refer to a physical file, but instead contain
2720 : * information for the driver on how to access a dataset.
2721 : *
2722 : * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2723 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2724 : * both kinds are implied.
2725 : *
2726 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2727 : * terminated list of strings with the driver short names that must be
2728 : * considered.
2729 : *
2730 : * @param papszFileList an array of strings, whose last element is the NULL
2731 : * pointer. These strings are filenames that are auxiliary to the main
2732 : * filename. The passed value may be NULL.
2733 : *
2734 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2735 : * this handle can be cast to a GDALDriver *.
2736 : *
2737 : * @since GDAL 2.2
2738 : */
2739 :
2740 25278 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2741 : const char *pszFilename, unsigned int nIdentifyFlags,
2742 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2743 : {
2744 25278 : GDALDriverManager *poDM = GetGDALDriverManager();
2745 25278 : CPLAssert(nullptr != poDM);
2746 :
2747 : // If no driver kind is specified, assume all are to be probed.
2748 25278 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2749 25235 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2750 :
2751 50555 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2752 25278 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2753 :
2754 50556 : CPLErrorStateBackuper oBackuper;
2755 25278 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2756 :
2757 25278 : const int nDriverCount = poDM->GetDriverCount();
2758 :
2759 : // First pass: only use drivers that have a pfnIdentify implementation.
2760 50556 : std::vector<GDALDriver *> apoSecondPassDrivers;
2761 5482350 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2762 : {
2763 5458370 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2764 5465700 : if (papszAllowedDrivers != nullptr &&
2765 7327 : CSLFindString(papszAllowedDrivers,
2766 : GDALGetDriverShortName(poDriver)) == -1)
2767 : {
2768 1031310 : continue;
2769 : }
2770 :
2771 5452380 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2772 :
2773 5451080 : if (poDriver->pfnIdentify == nullptr &&
2774 1020230 : poDriver->pfnIdentifyEx == nullptr)
2775 : {
2776 1020230 : continue;
2777 : }
2778 :
2779 4430900 : if (papszAllowedDrivers != nullptr &&
2780 44 : CSLFindString(papszAllowedDrivers,
2781 : GDALGetDriverShortName(poDriver)) == -1)
2782 0 : continue;
2783 13287800 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2784 4431360 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2785 505 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2786 141 : continue;
2787 13295400 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2788 4435590 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2789 4876 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2790 3657 : continue;
2791 :
2792 4427050 : if (poDriver->pfnIdentifyEx)
2793 : {
2794 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2795 0 : return poDriver;
2796 : }
2797 : else
2798 : {
2799 4427050 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2800 4427050 : if (nIdentifyRes > 0)
2801 1295 : return poDriver;
2802 4450750 : if (nIdentifyRes < 0 &&
2803 24996 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2804 : {
2805 : // Not loaded plugin
2806 36 : apoSecondPassDrivers.push_back(poDriver);
2807 : }
2808 : }
2809 : }
2810 :
2811 : // second pass: try loading plugin drivers
2812 24016 : for (auto poDriver : apoSecondPassDrivers)
2813 : {
2814 : // Force plugin driver loading
2815 34 : poDriver->GetMetadata();
2816 34 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2817 1 : return poDriver;
2818 : }
2819 :
2820 : // third pass: slow method.
2821 5381840 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2822 : {
2823 5357950 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2824 5361760 : if (papszAllowedDrivers != nullptr &&
2825 3807 : CSLFindString(papszAllowedDrivers,
2826 : GDALGetDriverShortName(poDriver)) == -1)
2827 : {
2828 3790 : continue;
2829 : }
2830 :
2831 5354160 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2832 :
2833 16061000 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2834 5354600 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2835 446 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2836 137 : continue;
2837 16062700 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2838 5355580 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2839 1563 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2840 946 : continue;
2841 :
2842 5353080 : if (poDriver->pfnIdentifyEx != nullptr)
2843 : {
2844 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2845 0 : continue;
2846 : }
2847 5353080 : else if (poDriver->pfnIdentify != nullptr)
2848 : {
2849 4350840 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2850 4326310 : continue;
2851 : }
2852 :
2853 : GDALDataset *poDS;
2854 1026760 : if (poDriver->pfnOpen != nullptr)
2855 : {
2856 978914 : poDS = poDriver->pfnOpen(&oOpenInfo);
2857 978914 : if (poDS != nullptr)
2858 : {
2859 91 : delete poDS;
2860 91 : return GDALDriver::ToHandle(poDriver);
2861 : }
2862 :
2863 978823 : if (CPLGetLastErrorType() != CE_None)
2864 0 : return nullptr;
2865 : }
2866 47847 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2867 : {
2868 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2869 0 : if (poDS != nullptr)
2870 : {
2871 0 : delete poDS;
2872 0 : return GDALDriver::ToHandle(poDriver);
2873 : }
2874 :
2875 0 : if (CPLGetLastErrorType() != CE_None)
2876 0 : return nullptr;
2877 : }
2878 : }
2879 :
2880 23891 : return nullptr;
2881 : }
2882 :
2883 : /************************************************************************/
2884 : /* GetMetadataItem() */
2885 : /************************************************************************/
2886 :
2887 11910900 : const char *GDALDriver::GetMetadataItem(const char *pszName,
2888 : const char *pszDomain)
2889 : {
2890 11910900 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2891 : {
2892 11911300 : if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
2893 : {
2894 2154 : const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
2895 2154 : if (pszVal)
2896 1933 : return pszVal;
2897 221 : if (GetMetadataItem(GDAL_DCAP_RASTER))
2898 : {
2899 152 : auto poDM = GetGDALDriverManager();
2900 152 : auto poGTiffDrv = poDM->GetDriverByName("GTiff");
2901 152 : if (poGTiffDrv)
2902 : {
2903 : const char *pszXML =
2904 152 : poGTiffDrv->GetMetadataItem(pszName, "");
2905 152 : if (pszXML)
2906 : {
2907 304 : CPLString osXML(pszXML);
2908 152 : osXML.replaceAll("<Value>INTERNAL</Value>", "");
2909 152 : return CPLSPrintf("%s", osXML.c_str());
2910 : }
2911 : }
2912 : }
2913 : }
2914 : }
2915 11908800 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
2916 : }
2917 :
2918 : /************************************************************************/
2919 : /* SetMetadataItem() */
2920 : /************************************************************************/
2921 :
2922 4380670 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
2923 : const char *pszDomain)
2924 :
2925 : {
2926 4380670 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2927 : {
2928 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2929 4571150 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
2930 195722 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
2931 : {
2932 195722 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
2933 : }
2934 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2935 8436790 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
2936 4186680 : strchr(pszValue, ' ') == nullptr &&
2937 6976 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
2938 : nullptr)
2939 : {
2940 6976 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
2941 : }
2942 : }
2943 4380670 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
2944 : }
2945 :
2946 : /************************************************************************/
2947 : /* InstantiateAlgorithm() */
2948 : /************************************************************************/
2949 :
2950 : //! @cond Doxygen_Suppress
2951 :
2952 : GDALAlgorithm *
2953 56 : GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
2954 : {
2955 56 : pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
2956 56 : if (pfnInstantiateAlgorithm)
2957 56 : return pfnInstantiateAlgorithm(aosPath);
2958 0 : return nullptr;
2959 : }
2960 :
2961 : /************************************************************************/
2962 : /* DeclareAlgorithm() */
2963 : /************************************************************************/
2964 :
2965 6980 : void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
2966 : {
2967 13960 : const std::string osDriverName = GetDescription();
2968 6980 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
2969 :
2970 13960 : if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
2971 : {
2972 3082 : singleton.DeclareAlgorithm(
2973 : {"driver"},
2974 41 : []() -> std::unique_ptr<GDALAlgorithm>
2975 : {
2976 82 : return std::make_unique<GDALContainerAlgorithm>(
2977 41 : "driver", "Command for driver specific operations.");
2978 1541 : });
2979 : }
2980 :
2981 : std::vector<std::string> path = {"driver",
2982 41880 : CPLString(osDriverName).tolower()};
2983 6980 : if (!singleton.HasDeclaredSubAlgorithm(path))
2984 : {
2985 137 : auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
2986 : {
2987 : auto poDriver =
2988 137 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
2989 137 : if (poDriver)
2990 : {
2991 : const char *pszHelpTopic =
2992 137 : poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2993 274 : return std::make_unique<GDALContainerAlgorithm>(
2994 274 : CPLString(osDriverName).tolower(),
2995 274 : std::string("Command for ")
2996 137 : .append(osDriverName)
2997 : .append(" driver specific operations."),
2998 274 : pszHelpTopic ? std::string("/").append(pszHelpTopic)
2999 137 : : std::string());
3000 : }
3001 0 : return nullptr;
3002 6164 : };
3003 6164 : singleton.DeclareAlgorithm(path, std::move(lambda));
3004 : }
3005 :
3006 6980 : path.insert(path.end(), aosPath.begin(), aosPath.end());
3007 :
3008 56 : auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3009 : {
3010 : auto poDriver =
3011 56 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3012 56 : if (poDriver)
3013 : return std::unique_ptr<GDALAlgorithm>(
3014 56 : poDriver->InstantiateAlgorithm(aosPath));
3015 0 : return nullptr;
3016 13960 : };
3017 :
3018 6980 : singleton.DeclareAlgorithm(path, std::move(lambda));
3019 :
3020 6980 : CPL_IGNORE_RET_VAL(osDriverName);
3021 6980 : }
3022 :
3023 : //! @endcond
3024 :
3025 : /************************************************************************/
3026 : /* DoesDriverHandleExtension() */
3027 : /************************************************************************/
3028 :
3029 174349 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3030 : {
3031 174349 : bool bRet = false;
3032 : const char *pszDriverExtensions =
3033 174349 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3034 174349 : if (pszDriverExtensions)
3035 : {
3036 289714 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3037 144857 : const int nTokens = aosTokens.size();
3038 324313 : for (int j = 0; j < nTokens; ++j)
3039 : {
3040 183854 : if (EQUAL(pszExt, aosTokens[j]))
3041 : {
3042 4398 : bRet = true;
3043 4398 : break;
3044 : }
3045 : }
3046 : }
3047 174349 : return bRet;
3048 : }
3049 :
3050 : /************************************************************************/
3051 : /* IsOnlyExpectedGDBDrivers() */
3052 : /************************************************************************/
3053 :
3054 1 : static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3055 : {
3056 3 : for (const char *pszDrvName : aosDriverNames)
3057 : {
3058 2 : if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3059 1 : !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3060 : {
3061 0 : return false;
3062 : }
3063 : }
3064 1 : return true;
3065 : }
3066 :
3067 : /************************************************************************/
3068 : /* GDALGetOutputDriversForDatasetName() */
3069 : /************************************************************************/
3070 :
3071 : /** Return a list of driver short names that are likely candidates for the
3072 : * provided output file name.
3073 : *
3074 : * @param pszDestDataset Output dataset name (might not exist).
3075 : * @param nFlagRasterVector GDAL_OF_RASTER, GDAL_OF_VECTOR or
3076 : * binary-or'ed combination of both
3077 : * @param bSingleMatch Whether a single match is desired, that is to say the
3078 : * returned list will contain at most one item, which will
3079 : * be the first driver in the order they are registered to
3080 : * match the output dataset name. Note that in this mode, if
3081 : * nFlagRasterVector==GDAL_OF_RASTER and pszDestDataset has
3082 : * no extension, GTiff will be selected.
3083 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3084 : * true and there are more than 2 candidates.
3085 : * @return NULL terminated list of driver short names.
3086 : * To be freed with CSLDestroy()
3087 : * @since 3.9
3088 : */
3089 2559 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3090 : int nFlagRasterVector,
3091 : bool bSingleMatch, bool bEmitWarning)
3092 : {
3093 5118 : CPLStringList aosDriverNames;
3094 5118 : CPLStringList aosMissingDriverNames;
3095 :
3096 5118 : std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3097 2559 : if (EQUAL(osExt.c_str(), "zip"))
3098 : {
3099 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3100 1 : if (osLower.endsWith(".shp.zip"))
3101 : {
3102 1 : osExt = "shp.zip";
3103 : }
3104 0 : else if (osLower.endsWith(".gpkg.zip"))
3105 : {
3106 0 : osExt = "gpkg.zip";
3107 : }
3108 : }
3109 2558 : else if (EQUAL(osExt.c_str(), "json"))
3110 : {
3111 1 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3112 1 : if (osLower.endsWith(".gdalg.json"))
3113 0 : return nullptr;
3114 : }
3115 :
3116 2559 : auto poDM = GetGDALDriverManager();
3117 2559 : const int nDriverCount = poDM->GetDriverCount(true);
3118 2559 : GDALDriver *poMissingPluginDriver = nullptr;
3119 5118 : std::string osMatchingPrefix;
3120 575382 : for (int i = 0; i < nDriverCount; i++)
3121 : {
3122 572823 : GDALDriver *poDriver = poDM->GetDriver(i, true);
3123 572823 : bool bOk = false;
3124 572823 : if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3125 350193 : poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3126 1145650 : poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3127 291723 : (((nFlagRasterVector & GDAL_OF_RASTER) &&
3128 237689 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3129 141604 : ((nFlagRasterVector & GDAL_OF_VECTOR) &&
3130 54034 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)))
3131 : {
3132 176661 : bOk = true;
3133 : }
3134 400332 : else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3135 4170 : (nFlagRasterVector & GDAL_OF_VECTOR) != 0)
3136 : {
3137 0 : bOk = true;
3138 : }
3139 572823 : if (bOk)
3140 : {
3141 351010 : if (!osExt.empty() &&
3142 174349 : DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3143 : osExt.c_str()))
3144 : {
3145 4398 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3146 : {
3147 0 : poMissingPluginDriver = poDriver;
3148 0 : aosMissingDriverNames.AddString(poDriver->GetDescription());
3149 : }
3150 : else
3151 4398 : aosDriverNames.AddString(poDriver->GetDescription());
3152 : }
3153 : else
3154 : {
3155 : const char *pszPrefix =
3156 172263 : poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3157 172263 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3158 : {
3159 9 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3160 : {
3161 0 : osMatchingPrefix = pszPrefix;
3162 0 : poMissingPluginDriver = poDriver;
3163 : aosMissingDriverNames.AddString(
3164 0 : poDriver->GetDescription());
3165 : }
3166 : else
3167 9 : aosDriverNames.AddString(poDriver->GetDescription());
3168 : }
3169 : }
3170 : }
3171 : }
3172 :
3173 : // GMT is registered before netCDF for opening reasons, but we want
3174 : // netCDF to be used by default for output.
3175 2561 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3176 2561 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3177 : {
3178 0 : aosDriverNames.Clear();
3179 0 : aosDriverNames.AddString("netCDF");
3180 0 : aosDriverNames.AddString("GMT");
3181 : }
3182 :
3183 2559 : if (bSingleMatch)
3184 : {
3185 2491 : if (nFlagRasterVector == GDAL_OF_RASTER)
3186 : {
3187 2085 : if (aosDriverNames.empty())
3188 : {
3189 12 : if (osExt.empty())
3190 : {
3191 8 : aosDriverNames.AddString("GTiff");
3192 : }
3193 : }
3194 2073 : else if (aosDriverNames.size() >= 2)
3195 : {
3196 3766 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3197 1883 : EQUAL(aosDriverNames[1], "COG")))
3198 : {
3199 0 : CPLError(CE_Warning, CPLE_AppDefined,
3200 : "Several drivers matching %s extension. Using %s",
3201 : osExt.c_str(), aosDriverNames[0]);
3202 : }
3203 3766 : const std::string osDrvName = aosDriverNames[0];
3204 1883 : aosDriverNames.Clear();
3205 1883 : aosDriverNames.AddString(osDrvName.c_str());
3206 : }
3207 : }
3208 407 : else if (EQUAL(osExt.c_str(), "gdb") &&
3209 1 : IsOnlyExpectedGDBDrivers(aosDriverNames))
3210 : {
3211 : // Do not warn about that case given that FileGDB write support
3212 : // forwards to OpenFileGDB one. And also consider GPSBabel as too
3213 : // marginal to deserve the warning.
3214 1 : aosDriverNames.Clear();
3215 1 : aosDriverNames.AddString("OpenFileGDB");
3216 : }
3217 405 : else if (aosDriverNames.size() >= 2)
3218 : {
3219 0 : if (bEmitWarning)
3220 : {
3221 0 : CPLError(CE_Warning, CPLE_AppDefined,
3222 : "Several drivers matching %s %s. Using %s",
3223 0 : osMatchingPrefix.empty() ? osExt.c_str()
3224 0 : : osMatchingPrefix.c_str(),
3225 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3226 : aosDriverNames[0]);
3227 : }
3228 0 : const std::string osDrvName = aosDriverNames[0];
3229 0 : aosDriverNames.Clear();
3230 0 : aosDriverNames.AddString(osDrvName.c_str());
3231 : }
3232 : }
3233 :
3234 2588 : if (aosDriverNames.empty() && bEmitWarning &&
3235 2588 : aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3236 : {
3237 0 : CPLError(CE_Failure, CPLE_AppDefined,
3238 : "No installed driver matching %s %s, but %s driver is "
3239 : "known. However plugin %s",
3240 0 : osMatchingPrefix.empty() ? osExt.c_str()
3241 0 : : osMatchingPrefix.c_str(),
3242 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3243 0 : poMissingPluginDriver->GetDescription(),
3244 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3245 : .c_str());
3246 : }
3247 2587 : else if (aosDriverNames.empty() && bEmitWarning &&
3248 28 : aosMissingDriverNames.empty())
3249 : {
3250 771 : for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3251 : {
3252 744 : if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3253 : {
3254 1 : CPLError(CE_Failure, CPLE_AppDefined,
3255 : "Filename %s starts with the connection prefix of "
3256 : "driver %s, which is not enabled in this GDAL build. "
3257 : "If that filename is really intended, explicitly "
3258 : "specify its output format.",
3259 1 : pszDestDataset, sConnectionPrefix.pszDriverName);
3260 1 : break;
3261 : }
3262 : }
3263 : }
3264 :
3265 2559 : return aosDriverNames.StealList();
3266 : }
3267 :
3268 : /************************************************************************/
3269 : /* GDALGetMessageAboutMissingPluginDriver() */
3270 : /************************************************************************/
3271 :
3272 : std::string
3273 0 : GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3274 : {
3275 : std::string osMsg =
3276 0 : poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3277 : osMsg += " is not available in your "
3278 0 : "installation.";
3279 0 : if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3280 0 : GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3281 : {
3282 0 : osMsg += " ";
3283 0 : osMsg += pszInstallationMsg;
3284 : }
3285 :
3286 : VSIStatBuf sStat;
3287 0 : if (const char *pszGDALDriverPath =
3288 0 : CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3289 : {
3290 0 : if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3291 : {
3292 0 : if (osMsg.back() != '.')
3293 0 : osMsg += ".";
3294 0 : osMsg += " Directory '";
3295 0 : osMsg += pszGDALDriverPath;
3296 0 : osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3297 : }
3298 : }
3299 : else
3300 : {
3301 0 : if (osMsg.back() != '.')
3302 0 : osMsg += ".";
3303 : #ifdef INSTALL_PLUGIN_FULL_DIR
3304 : if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3305 : {
3306 : osMsg += " Directory '";
3307 : osMsg += INSTALL_PLUGIN_FULL_DIR;
3308 : osMsg += "' hardcoded in the GDAL library does not "
3309 : "exist and the GDAL_DRIVER_PATH "
3310 : "configuration option is not set.";
3311 : }
3312 : else
3313 : #endif
3314 : {
3315 : osMsg += " The GDAL_DRIVER_PATH configuration "
3316 0 : "option is not set.";
3317 : }
3318 : }
3319 0 : return osMsg;
3320 : }
|