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