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