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