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