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 395676 : GDALDriver::~GDALDriver()
46 :
47 : {
48 222586 : if (pfnUnloadDriver != nullptr)
49 5718 : pfnUnloadDriver(this);
50 395676 : }
51 :
52 : /************************************************************************/
53 : /* GDALCreateDriver() */
54 : /************************************************************************/
55 :
56 : /**
57 : * \brief Create a GDALDriver.
58 : *
59 : * Creates a driver in the GDAL heap.
60 : */
61 :
62 225 : GDALDriverH CPL_STDCALL GDALCreateDriver()
63 : {
64 225 : 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 535471 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
95 : {
96 :
97 535471 : GDALDataset *poDS = nullptr;
98 535471 : pfnOpen = GetOpenCallback();
99 535146 : if (pfnOpen != nullptr)
100 : {
101 535219 : poDS = pfnOpen(poOpenInfo);
102 : }
103 0 : else if (pfnOpenWithDriverArg != nullptr)
104 : {
105 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
106 : }
107 :
108 535693 : if (poDS)
109 : {
110 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
111 : // poDS->nOpenFlags
112 48022 : int nOpenFlags = poOpenInfo->nOpenFlags &
113 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
114 48022 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
115 1 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
116 48022 : poDS->nOpenFlags = nOpenFlags;
117 :
118 48022 : if (strlen(poDS->GetDescription()) == 0)
119 9965 : poDS->SetDescription(poOpenInfo->pszFilename);
120 :
121 47930 : if (poDS->poDriver == nullptr)
122 45204 : poDS->poDriver = this;
123 :
124 47930 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
125 : {
126 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
127 : }
128 :
129 47930 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
130 : {
131 39502 : 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 39499 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
141 39487 : poOpenInfo->pszFilename, poDS, GetDescription());
142 :
143 39612 : poDS->AddToDatasetOpenList();
144 : }
145 : }
146 :
147 535647 : 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 19700 : 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 19700 : pfnCreate = GetCreateCallback();
198 19700 : 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 19699 : 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 19698 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
220 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
221 19698 : (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 19697 : 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 19696 : 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 19678 : if (!EQUAL(GetDescription(), "MEM") &&
251 30469 : !EQUAL(GetDescription(), "Memory") &&
252 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
253 : // PostgisRaster driver which is undesirable
254 10791 : !EQUAL(GetDescription(), "PostgreSQL"))
255 : {
256 10789 : QuietDelete(pszFilename);
257 : }
258 : }
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* Validate creation options. */
262 : /* -------------------------------------------------------------------- */
263 19696 : if (CPLTestBool(
264 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
265 19696 : GDALValidateCreationOptions(this, papszOptions);
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* Proceed with creation. */
269 : /* -------------------------------------------------------------------- */
270 39392 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
271 19696 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
272 : GDALGetDataTypeName(eType), papszOptions);
273 :
274 19696 : GDALDataset *poDS = nullptr;
275 19696 : if (pfnCreateEx != nullptr)
276 : {
277 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
278 : const_cast<char **>(papszOptions));
279 : }
280 19696 : else if (pfnCreate != nullptr)
281 : {
282 19696 : 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 19696 : if (poDS != nullptr)
292 : {
293 35856 : if (poDS->GetDescription() == nullptr ||
294 17928 : strlen(poDS->GetDescription()) == 0)
295 15041 : poDS->SetDescription(pszFilename);
296 :
297 17928 : if (poDS->poDriver == nullptr)
298 17169 : poDS->poDriver = this;
299 :
300 17928 : poDS->AddToDatasetOpenList();
301 : }
302 :
303 19696 : 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 15463 : 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 15463 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
324 :
325 15463 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
326 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
327 :
328 : #ifdef OGRAPISPY_ENABLED
329 15463 : if (nBands < 1)
330 : {
331 2889 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
332 : const_cast<char **>(papszOptions), hDS);
333 : }
334 : #endif
335 :
336 15463 : 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 458 : GDALDriver::CreateMultiDimensional(const char *pszFilename,
364 : CSLConstList papszRootGroupOptions,
365 : CSLConstList papszOptions)
366 :
367 : {
368 : /* -------------------------------------------------------------------- */
369 : /* Does this format support creation. */
370 : /* -------------------------------------------------------------------- */
371 458 : pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
372 458 : 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 458 : if (CPLTestBool(
386 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
387 : {
388 : const char *pszOptionList =
389 458 : GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
390 916 : CPLString osDriver;
391 458 : osDriver.Printf("driver %s", GetDescription());
392 458 : GDALValidateOptions(pszOptionList, papszOptions, "creation option",
393 : osDriver);
394 : }
395 :
396 458 : auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
397 : papszOptions);
398 :
399 458 : if (poDstDS != nullptr)
400 : {
401 912 : if (poDstDS->GetDescription() == nullptr ||
402 456 : strlen(poDstDS->GetDescription()) == 0)
403 94 : poDstDS->SetDescription(pszFilename);
404 :
405 456 : if (poDstDS->poDriver == nullptr)
406 454 : poDstDS->poDriver = this;
407 : }
408 :
409 458 : 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 413 : GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
421 : const char *pszName,
422 : CSLConstList papszRootGroupOptions,
423 : CSLConstList papszOptions)
424 : {
425 413 : VALIDATE_POINTER1(hDriver, __func__, nullptr);
426 413 : VALIDATE_POINTER1(pszName, __func__, nullptr);
427 413 : return GDALDataset::ToHandle(
428 : GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
429 413 : 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 5920 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
468 : int bStrict)
469 :
470 : {
471 5920 : return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
472 5920 : nullptr);
473 : }
474 :
475 7723 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
476 : int bStrict, CSLConstList /*papszOptions*/,
477 : GDALProgressFunc pfnProgress,
478 : void *pProgressData)
479 :
480 : {
481 7723 : if (pfnProgress == nullptr)
482 5920 : pfnProgress = GDALDummyProgress;
483 :
484 7723 : int nBands = poSrcDS->GetRasterCount();
485 7723 : if (nBands == 0)
486 0 : return CE_None;
487 :
488 : /* -------------------------------------------------------------------- */
489 : /* Try to copy mask if it seems appropriate. */
490 : /* -------------------------------------------------------------------- */
491 7723 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
492 7723 : CPLErr eErr = CE_None;
493 :
494 7723 : int nTotalBandsWithMask = 0;
495 27331 : for (int iBand = 0; iBand < nBands; ++iBand)
496 : {
497 19608 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
498 :
499 19608 : int nMaskFlags = poSrcBand->GetMaskFlags();
500 19608 : if (!(nMaskFlags &
501 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
502 : {
503 7 : nTotalBandsWithMask++;
504 : }
505 : }
506 :
507 7723 : int iBandWithMask = 0;
508 27331 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
509 : {
510 19608 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
511 :
512 19608 : int nMaskFlags = poSrcBand->GetMaskFlags();
513 19608 : 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 7723 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
544 7723 : if (eErr == CE_None &&
545 7723 : !(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 7723 : return eErr;
563 : }
564 :
565 : /************************************************************************/
566 : /* DefaultCreateCopy() */
567 : /************************************************************************/
568 :
569 1352 : GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
570 : GDALDataset *poSrcDS, int bStrict,
571 : CSLConstList papszOptions,
572 : GDALProgressFunc pfnProgress,
573 : void *pProgressData)
574 :
575 : {
576 1352 : if (pfnProgress == nullptr)
577 0 : pfnProgress = GDALDummyProgress;
578 :
579 1352 : CPLErrorReset();
580 :
581 : /* -------------------------------------------------------------------- */
582 : /* Use multidimensional raster API if available. */
583 : /* -------------------------------------------------------------------- */
584 2704 : auto poSrcGroup = poSrcDS->GetRootGroup();
585 1352 : 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 1336 : const int nXSize = poSrcDS->GetRasterXSize();
611 1336 : const int nYSize = poSrcDS->GetRasterYSize();
612 1336 : const int nBands = poSrcDS->GetRasterCount();
613 :
614 1336 : CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
615 :
616 1336 : const int nLayerCount = poSrcDS->GetLayerCount();
617 1369 : 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 1309 : if (poSrcDS->GetDriver() != nullptr &&
625 1308 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
626 1301 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
627 2620 : 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 1306 : else if (poSrcDS->GetDriver() != nullptr &&
636 1305 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
637 7 : nullptr &&
638 7 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
639 7 : nullptr &&
640 2611 : 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 1306 : 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 1304 : char **papszCreateOptions = CSLDuplicate(papszOptions);
661 1304 : const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
662 : "IMAGE_STRUCTURE", nullptr};
663 :
664 3882 : for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
665 2578 : iOptItem += 2)
666 : {
667 : // does the source have this metadata item on the first band?
668 2578 : auto poBand = poSrcDS->GetRasterBand(1);
669 2578 : poBand->EnablePixelTypeSignedByteWarning(false);
670 5156 : const char *pszValue = poBand->GetMetadataItem(
671 2578 : apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
672 2578 : poBand->EnablePixelTypeSignedByteWarning(true);
673 :
674 2578 : if (pszValue == nullptr)
675 2577 : 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 1304 : GDALDataType eType = GDT_Unknown;
697 :
698 1304 : if (nBands > 0)
699 1289 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
700 : GDALDataset *poDstDS =
701 1304 : Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
702 :
703 1304 : CSLDestroy(papszCreateOptions);
704 :
705 1304 : if (poDstDS == nullptr)
706 500 : return nullptr;
707 :
708 804 : int nDstBands = poDstDS->GetRasterCount();
709 804 : CPLErr eErr = CE_None;
710 804 : 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 804 : double adfGeoTransform[6] = {};
729 :
730 804 : if (nDstBands == 0 && !bStrict)
731 4 : CPLTurnFailureIntoWarning(true);
732 :
733 1603 : if (eErr == CE_None &&
734 799 : poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None
735 : // TODO(schwehr): The default value check should be a function.
736 1605 : && (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 742 : eErr = poDstDS->SetGeoTransform(adfGeoTransform);
741 742 : if (!bStrict)
742 362 : eErr = CE_None;
743 : }
744 :
745 804 : if (eErr == CE_None)
746 : {
747 798 : const auto poSrcSRS = poSrcDS->GetSpatialRef();
748 798 : if (poSrcSRS && !poSrcSRS->IsEmpty())
749 : {
750 698 : eErr = poDstDS->SetSpatialRef(poSrcSRS);
751 698 : if (!bStrict)
752 342 : eErr = CE_None;
753 : }
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Copy GCPs. */
758 : /* -------------------------------------------------------------------- */
759 804 : 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 804 : if (nDstBands == 0 && !bStrict)
768 4 : CPLTurnFailureIntoWarning(false);
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* Copy metadata. */
772 : /* -------------------------------------------------------------------- */
773 804 : DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Loop copying bands. */
777 : /* -------------------------------------------------------------------- */
778 2162 : for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
779 : {
780 1358 : GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
781 1358 : GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
782 :
783 : /* --------------------------------------------------------------------
784 : */
785 : /* Do we need to copy a colortable. */
786 : /* --------------------------------------------------------------------
787 : */
788 1358 : GDALColorTable *const poCT = poSrcBand->GetColorTable();
789 1358 : 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 1358 : if (!bStrict)
800 645 : CPLTurnFailureIntoWarning(true);
801 :
802 1358 : if (strlen(poSrcBand->GetDescription()) > 0)
803 68 : poDstBand->SetDescription(poSrcBand->GetDescription());
804 :
805 1358 : if (CSLCount(poSrcBand->GetMetadata()) > 0)
806 121 : poDstBand->SetMetadata(poSrcBand->GetMetadata());
807 :
808 1358 : int bSuccess = FALSE;
809 1358 : double dfValue = poSrcBand->GetOffset(&bSuccess);
810 1358 : if (bSuccess && dfValue != 0.0)
811 5 : poDstBand->SetOffset(dfValue);
812 :
813 1358 : dfValue = poSrcBand->GetScale(&bSuccess);
814 1358 : if (bSuccess && dfValue != 1.0)
815 5 : poDstBand->SetScale(dfValue);
816 :
817 1358 : GDALCopyNoDataValue(poDstBand, poSrcBand);
818 :
819 2154 : if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
820 796 : poSrcBand->GetColorInterpretation() !=
821 796 : poDstBand->GetColorInterpretation())
822 585 : poDstBand->SetColorInterpretation(
823 585 : poSrcBand->GetColorInterpretation());
824 :
825 1358 : char **papszCatNames = poSrcBand->GetCategoryNames();
826 1358 : if (nullptr != papszCatNames)
827 1 : poDstBand->SetCategoryNames(papszCatNames);
828 :
829 : // Only copy RAT if it is of reasonable size to fit in memory
830 1358 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
831 1360 : if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
832 2 : poRAT->GetRowCount() <
833 : 1024 * 1024)
834 : {
835 2 : poDstBand->SetDefaultRAT(poRAT);
836 : }
837 :
838 1358 : if (!bStrict)
839 : {
840 645 : CPLTurnFailureIntoWarning(false);
841 : }
842 : else
843 : {
844 713 : eErr = CPLGetLastErrorType();
845 : }
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Copy image data. */
850 : /* -------------------------------------------------------------------- */
851 804 : if (eErr == CE_None && nDstBands > 0)
852 : {
853 756 : const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
854 : nullptr};
855 756 : const bool bSkipHoles = CPLTestBool(
856 : CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857 756 : eErr = GDALDatasetCopyWholeRaster(
858 : poSrcDS, poDstDS,
859 : bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860 : pProgressData);
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Should we copy some masks over? */
865 : /* -------------------------------------------------------------------- */
866 804 : if (eErr == CE_None && nDstBands > 0)
867 738 : eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Copy vector layers */
871 : /* -------------------------------------------------------------------- */
872 804 : if (eErr == CE_None)
873 : {
874 750 : 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 804 : 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 750 : CPLErrorReset();
904 : }
905 :
906 750 : return poDstDS;
907 : }
908 :
909 : /************************************************************************/
910 : /* DefaultCopyMetadata() */
911 : /************************************************************************/
912 :
913 5129 : void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
914 : CSLConstList papszOptions,
915 : CSLConstList papszExcludedDomains)
916 : {
917 : const char *pszCopySrcMDD =
918 5129 : CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
919 5129 : char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
920 5129 : if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
921 : papszSrcMDD)
922 : {
923 4 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
924 2 : CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
925 10101 : CSLFindString(papszExcludedDomains, "") < 0 &&
926 4970 : CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
927 : {
928 4970 : if (poSrcDS->GetMetadata() != nullptr)
929 710 : 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 5127 : constexpr const char *apszDefaultDomains[] = {
937 : "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938 25635 : for (const char *pszDomain : apszDefaultDomains)
939 : {
940 41000 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
941 20492 : CSLFindString(papszExcludedDomains, pszDomain) < 0)
942 : {
943 20492 : char **papszMD = poSrcDS->GetMetadata(pszDomain);
944 20492 : if (papszMD)
945 5 : poDstDS->SetMetadata(papszMD, pszDomain);
946 : }
947 : }
948 :
949 5127 : 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 5129 : CSLDestroy(papszSrcMDD);
999 5129 : }
1000 :
1001 : /************************************************************************/
1002 : /* QuietDeleteForCreateCopy() */
1003 : /************************************************************************/
1004 :
1005 11034 : 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 21757 : 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 32480 : !EQUAL(GetDescription(), "GeoRaster") &&
1017 10723 : !EQUAL(GetDescription(), "PostGISRaster"))
1018 : {
1019 : /* --------------------------------------------------------------------
1020 : */
1021 : /* Establish list of files of output dataset if it already
1022 : * exists. */
1023 : /* --------------------------------------------------------------------
1024 : */
1025 21410 : std::set<std::string> oSetExistingDestFiles;
1026 : {
1027 21410 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1028 10705 : const char *const apszAllowedDrivers[] = {GetDescription(),
1029 10705 : nullptr};
1030 : auto poExistingOutputDS =
1031 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1032 21410 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1033 10705 : if (poExistingOutputDS)
1034 : {
1035 670 : for (const char *pszFileInList :
1036 638 : CPLStringList(poExistingOutputDS->GetFileList()))
1037 : {
1038 : oSetExistingDestFiles.insert(
1039 335 : 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 21410 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1051 10705 : if (!oSetExistingDestFiles.empty())
1052 : {
1053 606 : 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 303 : const char *const apszAllowedDrivers[] = {
1059 303 : poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1060 : : nullptr,
1061 303 : nullptr};
1062 : auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1063 303 : poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1064 606 : poSrcDS->papszOpenOptions));
1065 303 : if (poSrcDSTmp)
1066 : {
1067 203 : for (const char *pszFileInList :
1068 394 : CPLStringList(poSrcDSTmp->GetFileList()))
1069 : {
1070 406 : CPLString osFilename(pszFileInList);
1071 203 : osFilename.replaceAll('\\', '/');
1072 203 : 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 10705 : 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 10705 : QuietDelete(pszFilename);
1095 : }
1096 :
1097 11034 : 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 10800 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1186 : GDALDataset *poSrcDS, int bStrict,
1187 : CSLConstList papszOptions,
1188 : GDALProgressFunc pfnProgress,
1189 : void *pProgressData)
1190 :
1191 : {
1192 10800 : if (pfnProgress == nullptr)
1193 8560 : pfnProgress = GDALDummyProgress;
1194 :
1195 10800 : 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 10800 : char **papszOptionsToDelete = nullptr;
1202 : const char *srcInterleave =
1203 10800 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1204 6460 : if (nBandCount > 1 && srcInterleave != nullptr &&
1205 17878 : CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1206 618 : EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1207 : {
1208 :
1209 : // look for INTERLEAVE values of the driver
1210 425 : char **interleavesCSL = nullptr;
1211 : const char *pszOptionList =
1212 425 : this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1213 : CPLXMLNode *xmlNode =
1214 425 : !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1215 425 : for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1216 9327 : child != nullptr; child = child->psNext)
1217 : {
1218 8902 : if ((child->eType == CXT_Element) &&
1219 8902 : EQUAL(child->pszValue, "Option"))
1220 : {
1221 : const char *nameAttribute =
1222 8902 : CPLGetXMLValue(child, "name", nullptr);
1223 8902 : const bool isInterleaveAttribute =
1224 8902 : nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1225 8902 : if (isInterleaveAttribute)
1226 : {
1227 179 : for (CPLXMLNode *optionChild = child->psChild;
1228 1086 : optionChild != nullptr;
1229 907 : optionChild = optionChild->psNext)
1230 : {
1231 907 : if ((optionChild->eType == CXT_Element) &&
1232 365 : EQUAL(optionChild->pszValue, "Value"))
1233 : {
1234 365 : CPLXMLNode *optionChildValue = optionChild->psChild;
1235 365 : if (optionChildValue &&
1236 365 : (optionChildValue->eType == CXT_Text))
1237 : {
1238 365 : interleavesCSL = CSLAddString(
1239 365 : interleavesCSL, optionChildValue->pszValue);
1240 : }
1241 : }
1242 : }
1243 : }
1244 : }
1245 : }
1246 425 : CPLDestroyXMLNode(xmlNode);
1247 :
1248 : const char *dstInterleaveBand =
1249 677 : (CSLFindString(interleavesCSL, "BAND") >= 0) ? "BAND"
1250 252 : : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1251 425 : : nullptr;
1252 : const char *dstInterleaveLine =
1253 850 : (CSLFindString(interleavesCSL, "LINE") >= 0) ? "LINE"
1254 425 : : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1255 425 : : nullptr;
1256 : const char *dstInterleavePixel =
1257 677 : (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1258 252 : : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1259 425 : : nullptr;
1260 425 : const char *dstInterleave =
1261 680 : EQUAL(srcInterleave, "BAND") ? dstInterleaveBand
1262 508 : : EQUAL(srcInterleave, "LINE") ? dstInterleaveLine
1263 253 : : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1264 : : nullptr;
1265 425 : CSLDestroy(interleavesCSL);
1266 :
1267 425 : if (dstInterleave != nullptr)
1268 : {
1269 179 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1270 179 : papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1271 : "INTERLEAVE", dstInterleave);
1272 179 : papszOptionsToDelete = CSLSetNameValue(
1273 : papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1274 179 : 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 10800 : 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 21579 : if (!bAppendSubdataset &&
1289 10779 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1290 : {
1291 8853 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1292 : }
1293 :
1294 : int iIdxQuietDeleteOnCreateCopy =
1295 10800 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1296 10800 : if (iIdxQuietDeleteOnCreateCopy >= 0)
1297 : {
1298 1926 : if (papszOptionsToDelete == nullptr)
1299 1803 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1300 1926 : papszOptionsToDelete = CSLRemoveStrings(
1301 : papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1302 1926 : 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 10800 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1311 10800 : bool bInternalDataset = false;
1312 10800 : if (iIdxInternalDataset >= 0)
1313 : {
1314 : bInternalDataset =
1315 4148 : CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1316 4148 : if (papszOptionsToDelete == nullptr)
1317 4148 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1318 4148 : papszOptionsToDelete = CSLRemoveStrings(
1319 : papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1320 4148 : papszOptions = papszOptionsToDelete;
1321 : }
1322 :
1323 : /* -------------------------------------------------------------------- */
1324 : /* Validate creation options. */
1325 : /* -------------------------------------------------------------------- */
1326 10800 : if (CPLTestBool(
1327 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1328 : {
1329 21600 : auto poSrcGroup = poSrcDS->GetRootGroup();
1330 10800 : 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 10711 : GDALValidateCreationOptions(this, papszOptions);
1343 : }
1344 : }
1345 :
1346 : /* -------------------------------------------------------------------- */
1347 : /* Advise the source raster that we are going to read it completely */
1348 : /* -------------------------------------------------------------------- */
1349 :
1350 10800 : const int nXSize = poSrcDS->GetRasterXSize();
1351 10800 : const int nYSize = poSrcDS->GetRasterYSize();
1352 10800 : GDALDataType eDT = GDT_Unknown;
1353 10800 : if (nBandCount > 0)
1354 : {
1355 10580 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1356 10580 : if (poSrcBand)
1357 10580 : eDT = poSrcBand->GetRasterDataType();
1358 : }
1359 10800 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1360 10800 : 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 10800 : GDALDataset *poDstDS = nullptr;
1368 10800 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1369 20479 : if (l_pfnCreateCopy != nullptr &&
1370 9679 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1371 : {
1372 9679 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1373 : const_cast<char **>(papszOptions),
1374 : pfnProgress, pProgressData);
1375 9679 : if (poDstDS != nullptr)
1376 : {
1377 16942 : if (poDstDS->GetDescription() == nullptr ||
1378 8471 : strlen(poDstDS->GetDescription()) == 0)
1379 186 : poDstDS->SetDescription(pszFilename);
1380 :
1381 8471 : if (poDstDS->poDriver == nullptr)
1382 7497 : poDstDS->poDriver = this;
1383 :
1384 8471 : if (!bInternalDataset)
1385 4323 : poDstDS->AddToDatasetOpenList();
1386 : }
1387 : }
1388 : else
1389 : {
1390 1121 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1391 : pfnProgress, pProgressData);
1392 : }
1393 :
1394 10800 : CSLDestroy(papszOptionsToDelete);
1395 10800 : 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 6268 : 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 6268 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1417 6268 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1418 :
1419 6268 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1420 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1421 6268 : 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 649 : bool GDALDriver::CanVectorTranslateFrom(
1445 : const char *pszDestName, GDALDataset *poSourceDS,
1446 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1447 :
1448 : {
1449 649 : if (ppapszFailureReasons)
1450 : {
1451 0 : *ppapszFailureReasons = nullptr;
1452 : }
1453 :
1454 649 : if (!pfnCanVectorTranslateFrom)
1455 : {
1456 646 : if (ppapszFailureReasons)
1457 : {
1458 0 : *ppapszFailureReasons = CSLAddString(
1459 : nullptr,
1460 : "CanVectorTranslateFrom() not implemented for this driver");
1461 : }
1462 646 : 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 : /************************************************************************/
1482 : /* VectorTranslateFrom() */
1483 : /************************************************************************/
1484 :
1485 : /** Create a copy of a vector dataset, using the arguments passed to
1486 : * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1487 : *
1488 : * This may be implemented by some drivers that can convert from an existing
1489 : * dataset in an optimized way.
1490 : *
1491 : * This is for example used by the PMTiles to convert from MBTiles.
1492 : *
1493 : * @param pszDestName Target dataset name
1494 : * @param poSourceDS Source dataset
1495 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1496 : * GDALVectorTranslate() (may be nullptr)
1497 : * @param pfnProgress a function to be used to report progress of the copy.
1498 : * @param pProgressData application data passed into progress function.
1499 : * @return a new dataset in case of success, or nullptr in case of error.
1500 : * @since GDAL 3.8
1501 : */
1502 2 : GDALDataset *GDALDriver::VectorTranslateFrom(
1503 : const char *pszDestName, GDALDataset *poSourceDS,
1504 : CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1505 : void *pProgressData)
1506 :
1507 : {
1508 2 : if (!pfnVectorTranslateFrom)
1509 : {
1510 0 : CPLError(CE_Failure, CPLE_AppDefined,
1511 : "VectorTranslateFrom() not implemented for this driver");
1512 0 : return nullptr;
1513 : }
1514 :
1515 2 : return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1516 : papszVectorTranslateArguments, pfnProgress,
1517 2 : pProgressData);
1518 : }
1519 :
1520 : /************************************************************************/
1521 : /* QuietDelete() */
1522 : /************************************************************************/
1523 :
1524 : /**
1525 : * \brief Delete dataset if found.
1526 : *
1527 : * This is a helper method primarily used by Create() and
1528 : * CreateCopy() to predelete any dataset of the name soon to be
1529 : * created. It will attempt to delete the named dataset if
1530 : * one is found, otherwise it does nothing. An error is only
1531 : * returned if the dataset is found but the delete fails.
1532 : *
1533 : * This is a static method and it doesn't matter what driver instance
1534 : * it is invoked on. It will attempt to discover the correct driver
1535 : * using Identify().
1536 : *
1537 : * @param pszName the dataset name to try and delete.
1538 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1539 : * terminated list of strings with the driver short names that must be
1540 : * considered. (Note: implemented only starting with GDAL 3.4.1)
1541 : * @return CE_None if the dataset does not exist, or is deleted without issues.
1542 : */
1543 :
1544 21494 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1545 : CSLConstList papszAllowedDrivers)
1546 :
1547 : {
1548 : VSIStatBufL sStat;
1549 : const bool bExists =
1550 21494 : VSIStatExL(pszName, &sStat,
1551 21494 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1552 :
1553 : #ifdef S_ISFIFO
1554 21494 : if (bExists && S_ISFIFO(sStat.st_mode))
1555 0 : return CE_None;
1556 : #endif
1557 :
1558 21494 : if (bExists && VSI_ISDIR(sStat.st_mode))
1559 : {
1560 : // It is not desirable to remove directories quietly. Necessary to
1561 : // avoid ogr_mitab_12 to destroy file created at ogr_mitab_7.
1562 104 : return CE_None;
1563 : }
1564 :
1565 21390 : GDALDriver *poDriver = nullptr;
1566 21390 : if (papszAllowedDrivers)
1567 : {
1568 0 : GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1569 0 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1570 : {
1571 : GDALDriver *poTmpDriver =
1572 0 : GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1573 0 : if (poTmpDriver)
1574 : {
1575 : const bool bIdentifyRes =
1576 0 : poTmpDriver->pfnIdentifyEx
1577 0 : ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1578 : 0
1579 0 : : poTmpDriver->pfnIdentify &&
1580 0 : poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1581 0 : if (bIdentifyRes)
1582 : {
1583 0 : poDriver = poTmpDriver;
1584 0 : break;
1585 : }
1586 : }
1587 : }
1588 : }
1589 : else
1590 : {
1591 42780 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1592 21390 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1593 : }
1594 :
1595 21390 : if (poDriver == nullptr)
1596 20526 : return CE_None;
1597 :
1598 864 : CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1599 :
1600 864 : poDriver->pfnDelete = poDriver->GetDeleteCallback();
1601 902 : const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1602 38 : poDriver->pfnDeleteDataSource == nullptr;
1603 864 : if (bQuiet)
1604 : {
1605 76 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1606 38 : return poDriver->Delete(pszName);
1607 : }
1608 : else
1609 : {
1610 826 : return poDriver->Delete(pszName);
1611 : }
1612 : }
1613 :
1614 : /************************************************************************/
1615 : /* Delete() */
1616 : /************************************************************************/
1617 :
1618 : /**
1619 : * \brief Delete named dataset.
1620 : *
1621 : * The driver will attempt to delete the named dataset in a driver specific
1622 : * fashion. Full featured drivers will delete all associated files,
1623 : * database objects, or whatever is appropriate. The default behavior when
1624 : * no driver specific behavior is provided is to attempt to delete all the
1625 : * files that are returned by GDALGetFileList() on the dataset handle.
1626 : *
1627 : * It is unwise to have open dataset handles on this dataset when it is
1628 : * deleted.
1629 : *
1630 : * Equivalent of the C function GDALDeleteDataset().
1631 : *
1632 : * @param pszFilename name of dataset to delete.
1633 : *
1634 : * @return CE_None on success, or CE_Failure if the operation fails.
1635 : */
1636 :
1637 4577 : CPLErr GDALDriver::Delete(const char *pszFilename)
1638 :
1639 : {
1640 4577 : pfnDelete = GetDeleteCallback();
1641 4577 : if (pfnDelete != nullptr)
1642 1088 : return pfnDelete(pszFilename);
1643 3489 : else if (pfnDeleteDataSource != nullptr)
1644 0 : return pfnDeleteDataSource(this, pszFilename);
1645 :
1646 : /* -------------------------------------------------------------------- */
1647 : /* Collect file list. */
1648 : /* -------------------------------------------------------------------- */
1649 3489 : GDALDatasetH hDS = GDALOpenEx(pszFilename, 0, nullptr, nullptr, nullptr);
1650 :
1651 3489 : if (hDS == nullptr)
1652 : {
1653 234 : if (CPLGetLastErrorNo() == 0)
1654 207 : CPLError(CE_Failure, CPLE_OpenFailed,
1655 : "Unable to open %s to obtain file list.", pszFilename);
1656 :
1657 234 : return CE_Failure;
1658 : }
1659 :
1660 3255 : char **papszFileList = GDALGetFileList(hDS);
1661 :
1662 3255 : GDALClose(hDS);
1663 3255 : hDS = nullptr;
1664 :
1665 3255 : if (CSLCount(papszFileList) == 0)
1666 : {
1667 0 : CPLError(CE_Failure, CPLE_NotSupported,
1668 : "Unable to determine files associated with %s, "
1669 : "delete fails.",
1670 : pszFilename);
1671 0 : CSLDestroy(papszFileList);
1672 0 : return CE_Failure;
1673 : }
1674 :
1675 : /* -------------------------------------------------------------------- */
1676 : /* Delete all files. */
1677 : /* -------------------------------------------------------------------- */
1678 3255 : CPLErr eErr = CE_None;
1679 7212 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1680 : {
1681 3957 : if (VSIUnlink(papszFileList[i]) != 0)
1682 : {
1683 0 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1684 0 : papszFileList[i], VSIStrerror(errno));
1685 0 : eErr = CE_Failure;
1686 : }
1687 : }
1688 :
1689 3255 : CSLDestroy(papszFileList);
1690 :
1691 3255 : return eErr;
1692 : }
1693 :
1694 : /************************************************************************/
1695 : /* GDALDeleteDataset() */
1696 : /************************************************************************/
1697 :
1698 : /**
1699 : * \brief Delete named dataset.
1700 : *
1701 : * @see GDALDriver::Delete()
1702 : */
1703 :
1704 2552 : CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1705 : const char *pszFilename)
1706 :
1707 : {
1708 2552 : if (hDriver == nullptr)
1709 8 : hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1710 :
1711 2552 : if (hDriver == nullptr)
1712 : {
1713 0 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1714 : pszFilename);
1715 0 : return CE_Failure;
1716 : }
1717 :
1718 : #ifdef OGRAPISPY_ENABLED
1719 2552 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1720 : {
1721 499 : OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1722 : }
1723 : #endif
1724 :
1725 2552 : return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1726 : }
1727 :
1728 : /************************************************************************/
1729 : /* DefaultRename() */
1730 : /* */
1731 : /* The generic implementation based on the file list used when */
1732 : /* there is no format specific implementation. */
1733 : /************************************************************************/
1734 :
1735 : //! @cond Doxygen_Suppress
1736 172 : CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1737 :
1738 : {
1739 : /* -------------------------------------------------------------------- */
1740 : /* Collect file list. */
1741 : /* -------------------------------------------------------------------- */
1742 172 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1743 :
1744 172 : if (hDS == nullptr)
1745 : {
1746 0 : if (CPLGetLastErrorNo() == 0)
1747 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1748 : "Unable to open %s to obtain file list.", pszOldName);
1749 :
1750 0 : return CE_Failure;
1751 : }
1752 :
1753 172 : char **papszFileList = GDALGetFileList(hDS);
1754 :
1755 172 : GDALClose(hDS);
1756 :
1757 172 : if (CSLCount(papszFileList) == 0)
1758 : {
1759 0 : CPLError(CE_Failure, CPLE_NotSupported,
1760 : "Unable to determine files associated with %s,\n"
1761 : "rename fails.",
1762 : pszOldName);
1763 :
1764 0 : return CE_Failure;
1765 : }
1766 :
1767 : /* -------------------------------------------------------------------- */
1768 : /* Produce a list of new filenames that correspond to the old */
1769 : /* names. */
1770 : /* -------------------------------------------------------------------- */
1771 172 : CPLErr eErr = CE_None;
1772 : char **papszNewFileList =
1773 172 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1774 :
1775 172 : if (papszNewFileList == nullptr)
1776 0 : return CE_Failure;
1777 :
1778 351 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1779 : {
1780 179 : if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
1781 : {
1782 0 : eErr = CE_Failure;
1783 : // Try to put the ones we moved back.
1784 0 : for (--i; i >= 0; i--)
1785 : {
1786 : // Nothing we can do if the moving back doesn't work...
1787 0 : CPL_IGNORE_RET_VAL(
1788 0 : CPLMoveFile(papszFileList[i], papszNewFileList[i]));
1789 : }
1790 0 : break;
1791 : }
1792 : }
1793 :
1794 172 : CSLDestroy(papszNewFileList);
1795 172 : CSLDestroy(papszFileList);
1796 :
1797 172 : return eErr;
1798 : }
1799 :
1800 : //! @endcond
1801 :
1802 : /************************************************************************/
1803 : /* Rename() */
1804 : /************************************************************************/
1805 :
1806 : /**
1807 : * \brief Rename a dataset.
1808 : *
1809 : * Rename a dataset. This may including moving the dataset to a new directory
1810 : * or even a new filesystem.
1811 : *
1812 : * It is unwise to have open dataset handles on this dataset when it is
1813 : * being renamed.
1814 : *
1815 : * Equivalent of the C function GDALRenameDataset().
1816 : *
1817 : * @param pszNewName new name for the dataset.
1818 : * @param pszOldName old name for the dataset.
1819 : *
1820 : * @return CE_None on success, or CE_Failure if the operation fails.
1821 : */
1822 :
1823 174 : CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1824 :
1825 : {
1826 174 : pfnRename = GetRenameCallback();
1827 174 : if (pfnRename != nullptr)
1828 3 : return pfnRename(pszNewName, pszOldName);
1829 :
1830 171 : return DefaultRename(pszNewName, pszOldName);
1831 : }
1832 :
1833 : /************************************************************************/
1834 : /* GDALRenameDataset() */
1835 : /************************************************************************/
1836 :
1837 : /**
1838 : * \brief Rename a dataset.
1839 : *
1840 : * @see GDALDriver::Rename()
1841 : */
1842 :
1843 174 : CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1844 : const char *pszNewName,
1845 : const char *pszOldName)
1846 :
1847 : {
1848 174 : if (hDriver == nullptr)
1849 1 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1850 :
1851 174 : if (hDriver == nullptr)
1852 : {
1853 0 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1854 : pszOldName);
1855 0 : return CE_Failure;
1856 : }
1857 :
1858 174 : return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1859 : }
1860 :
1861 : /************************************************************************/
1862 : /* DefaultCopyFiles() */
1863 : /* */
1864 : /* The default implementation based on file lists used when */
1865 : /* there is no format specific implementation. */
1866 : /************************************************************************/
1867 :
1868 : //! @cond Doxygen_Suppress
1869 7 : CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1870 : const char *pszOldName)
1871 :
1872 : {
1873 : /* -------------------------------------------------------------------- */
1874 : /* Collect file list. */
1875 : /* -------------------------------------------------------------------- */
1876 7 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1877 :
1878 7 : if (hDS == nullptr)
1879 : {
1880 0 : if (CPLGetLastErrorNo() == 0)
1881 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1882 : "Unable to open %s to obtain file list.", pszOldName);
1883 :
1884 0 : return CE_Failure;
1885 : }
1886 :
1887 7 : char **papszFileList = GDALGetFileList(hDS);
1888 :
1889 7 : GDALClose(hDS);
1890 7 : hDS = nullptr;
1891 :
1892 7 : if (CSLCount(papszFileList) == 0)
1893 : {
1894 0 : CPLError(CE_Failure, CPLE_NotSupported,
1895 : "Unable to determine files associated with %s,\n"
1896 : "rename fails.",
1897 : pszOldName);
1898 :
1899 0 : return CE_Failure;
1900 : }
1901 :
1902 : /* -------------------------------------------------------------------- */
1903 : /* Produce a list of new filenames that correspond to the old */
1904 : /* names. */
1905 : /* -------------------------------------------------------------------- */
1906 7 : CPLErr eErr = CE_None;
1907 : char **papszNewFileList =
1908 7 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1909 :
1910 7 : if (papszNewFileList == nullptr)
1911 0 : return CE_Failure;
1912 :
1913 22 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1914 : {
1915 15 : if (CPLCopyFile(papszNewFileList[i], papszFileList[i]) != 0)
1916 : {
1917 0 : eErr = CE_Failure;
1918 : // Try to put the ones we moved back.
1919 0 : for (--i; i >= 0; --i)
1920 0 : VSIUnlink(papszNewFileList[i]);
1921 0 : break;
1922 : }
1923 : }
1924 :
1925 7 : CSLDestroy(papszNewFileList);
1926 7 : CSLDestroy(papszFileList);
1927 :
1928 7 : return eErr;
1929 : }
1930 :
1931 : //! @endcond
1932 :
1933 : /************************************************************************/
1934 : /* CopyFiles() */
1935 : /************************************************************************/
1936 :
1937 : /**
1938 : * \brief Copy the files of a dataset.
1939 : *
1940 : * Copy all the files associated with a dataset.
1941 : *
1942 : * Equivalent of the C function GDALCopyDatasetFiles().
1943 : *
1944 : * @param pszNewName new name for the dataset.
1945 : * @param pszOldName old name for the dataset.
1946 : *
1947 : * @return CE_None on success, or CE_Failure if the operation fails.
1948 : */
1949 :
1950 9 : CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
1951 :
1952 : {
1953 9 : pfnCopyFiles = GetCopyFilesCallback();
1954 9 : if (pfnCopyFiles != nullptr)
1955 3 : return pfnCopyFiles(pszNewName, pszOldName);
1956 :
1957 6 : return DefaultCopyFiles(pszNewName, pszOldName);
1958 : }
1959 :
1960 : /************************************************************************/
1961 : /* GDALCopyDatasetFiles() */
1962 : /************************************************************************/
1963 :
1964 : /**
1965 : * \brief Copy the files of a dataset.
1966 : *
1967 : * @see GDALDriver::CopyFiles()
1968 : */
1969 :
1970 9 : CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
1971 : const char *pszNewName,
1972 : const char *pszOldName)
1973 :
1974 : {
1975 9 : if (hDriver == nullptr)
1976 5 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1977 :
1978 9 : if (hDriver == nullptr)
1979 : {
1980 0 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1981 : pszOldName);
1982 0 : return CE_Failure;
1983 : }
1984 :
1985 9 : return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
1986 : }
1987 :
1988 : /************************************************************************/
1989 : /* GDALGetDriverShortName() */
1990 : /************************************************************************/
1991 :
1992 : /**
1993 : * \brief Return the short name of a driver
1994 : *
1995 : * This is the string that can be
1996 : * passed to the GDALGetDriverByName() function.
1997 : *
1998 : * For the GeoTIFF driver, this is "GTiff"
1999 : *
2000 : * @param hDriver the handle of the driver
2001 : * @return the short name of the driver. The
2002 : * returned string should not be freed and is owned by the driver.
2003 : */
2004 :
2005 3644900 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2006 :
2007 : {
2008 3644900 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2009 :
2010 3644900 : return GDALDriver::FromHandle(hDriver)->GetDescription();
2011 : }
2012 :
2013 : /************************************************************************/
2014 : /* GDALGetDriverLongName() */
2015 : /************************************************************************/
2016 :
2017 : /**
2018 : * \brief Return the long name of a driver
2019 : *
2020 : * For the GeoTIFF driver, this is "GeoTIFF"
2021 : *
2022 : * @param hDriver the handle of the driver
2023 : * @return the long name of the driver or empty string. The
2024 : * returned string should not be freed and is owned by the driver.
2025 : */
2026 :
2027 473 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2028 :
2029 : {
2030 473 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2031 :
2032 : const char *pszLongName =
2033 473 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2034 :
2035 473 : if (pszLongName == nullptr)
2036 0 : return "";
2037 :
2038 473 : return pszLongName;
2039 : }
2040 :
2041 : /************************************************************************/
2042 : /* GDALGetDriverHelpTopic() */
2043 : /************************************************************************/
2044 :
2045 : /**
2046 : * \brief Return the URL to the help that describes the driver
2047 : *
2048 : * That URL is relative to the GDAL documentation directory.
2049 : *
2050 : * For the GeoTIFF driver, this is "frmt_gtiff.html"
2051 : *
2052 : * @param hDriver the handle of the driver
2053 : * @return the URL to the help that describes the driver or NULL. The
2054 : * returned string should not be freed and is owned by the driver.
2055 : */
2056 :
2057 0 : const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2058 :
2059 : {
2060 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2061 :
2062 0 : return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2063 : }
2064 :
2065 : /************************************************************************/
2066 : /* GDALGetDriverCreationOptionList() */
2067 : /************************************************************************/
2068 :
2069 : /**
2070 : * \brief Return the list of creation options of the driver
2071 : *
2072 : * Return the list of creation options of the driver used by Create() and
2073 : * CreateCopy() as an XML string
2074 : *
2075 : * @param hDriver the handle of the driver
2076 : * @return an XML string that describes the list of creation options or
2077 : * empty string. The returned string should not be freed and is
2078 : * owned by the driver.
2079 : */
2080 :
2081 0 : const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2082 :
2083 : {
2084 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2085 :
2086 : const char *pszOptionList =
2087 0 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2088 0 : GDAL_DMD_CREATIONOPTIONLIST);
2089 :
2090 0 : if (pszOptionList == nullptr)
2091 0 : return "";
2092 :
2093 0 : return pszOptionList;
2094 : }
2095 :
2096 : /************************************************************************/
2097 : /* GDALValidateCreationOptions() */
2098 : /************************************************************************/
2099 :
2100 : /**
2101 : * \brief Validate the list of creation options that are handled by a driver
2102 : *
2103 : * This is a helper method primarily used by Create() and
2104 : * CreateCopy() to validate that the passed in list of creation options
2105 : * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2106 : * by some drivers. @see GDALGetDriverCreationOptionList()
2107 : *
2108 : * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2109 : * function will return TRUE. Otherwise it will check that the keys and values
2110 : * in the list of creation options are compatible with the capabilities declared
2111 : * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2112 : * a (non fatal) warning will be emitted and FALSE will be returned.
2113 : *
2114 : * @param hDriver the handle of the driver with whom the lists of creation
2115 : * option must be validated
2116 : * @param papszCreationOptions the list of creation options. An array of
2117 : * strings, whose last element is a NULL pointer
2118 : * @return TRUE if the list of creation options is compatible with the Create()
2119 : * and CreateCopy() method of the driver, FALSE otherwise.
2120 : */
2121 :
2122 30660 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2123 : CSLConstList papszCreationOptions)
2124 : {
2125 30660 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2126 : const char *pszOptionList =
2127 30660 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2128 30660 : GDAL_DMD_CREATIONOPTIONLIST);
2129 30660 : CPLString osDriver;
2130 : osDriver.Printf("driver %s",
2131 30660 : GDALDriver::FromHandle(hDriver)->GetDescription());
2132 30660 : bool bFoundOptionToRemove = false;
2133 30660 : constexpr const char *const apszExcludedOptions[] = {
2134 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2135 43304 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2136 : {
2137 63765 : for (const char *pszExcludedOptions : apszExcludedOptions)
2138 : {
2139 51121 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2140 176 : pszCO[strlen(pszExcludedOptions)] == '=')
2141 : {
2142 176 : bFoundOptionToRemove = true;
2143 176 : break;
2144 : }
2145 : }
2146 12820 : if (bFoundOptionToRemove)
2147 176 : break;
2148 : }
2149 30660 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2150 30660 : char **papszOptionsToFree = nullptr;
2151 30660 : if (bFoundOptionToRemove)
2152 : {
2153 541 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2154 : {
2155 365 : bool bMatch = false;
2156 1471 : for (const char *pszExcludedOptions : apszExcludedOptions)
2157 : {
2158 1294 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2159 188 : pszCO[strlen(pszExcludedOptions)] == '=')
2160 : {
2161 188 : bMatch = true;
2162 188 : break;
2163 : }
2164 : }
2165 365 : if (!bMatch)
2166 177 : papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2167 : }
2168 176 : papszOptionsToValidate = papszOptionsToFree;
2169 : }
2170 :
2171 30660 : const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2172 : pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2173 30660 : CSLDestroy(papszOptionsToFree);
2174 30660 : return bRet;
2175 : }
2176 :
2177 : /************************************************************************/
2178 : /* GDALValidateOpenOptions() */
2179 : /************************************************************************/
2180 :
2181 48255 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2182 : const char *const *papszOpenOptions)
2183 : {
2184 48255 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2185 : const char *pszOptionList =
2186 48255 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2187 48229 : GDAL_DMD_OPENOPTIONLIST);
2188 96437 : CPLString osDriver;
2189 : osDriver.Printf("driver %s",
2190 48216 : GDALDriver::FromHandle(hDriver)->GetDescription());
2191 48232 : return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2192 48194 : osDriver);
2193 : }
2194 :
2195 : /************************************************************************/
2196 : /* GDALValidateOptions() */
2197 : /************************************************************************/
2198 :
2199 87881 : int GDALValidateOptions(const char *pszOptionList,
2200 : const char *const *papszOptionsToValidate,
2201 : const char *pszErrorMessageOptionType,
2202 : const char *pszErrorMessageContainerName)
2203 : {
2204 87881 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2205 75874 : return TRUE;
2206 12007 : if (pszOptionList == nullptr)
2207 139 : return TRUE;
2208 :
2209 11868 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2210 11868 : if (psNode == nullptr)
2211 : {
2212 0 : CPLError(CE_Warning, CPLE_AppDefined,
2213 : "Could not parse %s list of %s. Assuming options are valid.",
2214 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2215 0 : return TRUE;
2216 : }
2217 :
2218 11868 : bool bRet = true;
2219 32000 : while (*papszOptionsToValidate)
2220 : {
2221 20132 : char *pszKey = nullptr;
2222 : const char *pszValue =
2223 20132 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2224 20132 : if (pszKey == nullptr)
2225 : {
2226 1 : CPLError(CE_Warning, CPLE_NotSupported,
2227 : "%s '%s' is not formatted with the key=value format",
2228 : pszErrorMessageOptionType, *papszOptionsToValidate);
2229 1 : bRet = false;
2230 :
2231 1 : ++papszOptionsToValidate;
2232 620 : continue;
2233 : }
2234 :
2235 20131 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2236 : {
2237 0 : ++papszOptionsToValidate;
2238 0 : CPLFree(pszKey);
2239 0 : continue;
2240 : }
2241 :
2242 : // Must we be forgiving in case of missing option ?
2243 20131 : bool bWarnIfMissingKey = true;
2244 20131 : if (pszKey[0] == '@')
2245 : {
2246 610 : bWarnIfMissingKey = false;
2247 610 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2248 : }
2249 :
2250 20131 : CPLXMLNode *psChildNode = psNode->psChild;
2251 166159 : while (psChildNode)
2252 : {
2253 165540 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2254 : {
2255 : const char *pszOptionName =
2256 165540 : CPLGetXMLValue(psChildNode, "name", "");
2257 : /* For option names terminated by wildcard (NITF BLOCKA option
2258 : * names for example) */
2259 165540 : if (strlen(pszOptionName) > 0 &&
2260 165540 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2261 373 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2262 : {
2263 216 : break;
2264 : }
2265 :
2266 : /* For option names beginning by a wildcard */
2267 165324 : if (pszOptionName[0] == '*' &&
2268 57 : strlen(pszKey) > strlen(pszOptionName) &&
2269 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2270 : pszOptionName + 1))
2271 : {
2272 2 : break;
2273 : }
2274 :
2275 : // For options names with * in the middle
2276 165322 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2277 165322 : if (pszStarInOptionName &&
2278 178 : pszStarInOptionName != pszOptionName &&
2279 : pszStarInOptionName !=
2280 178 : pszOptionName + strlen(pszOptionName) - 1 &&
2281 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2282 12 : pszOptionName) &&
2283 12 : EQUALN(pszKey, pszOptionName,
2284 : static_cast<size_t>(pszStarInOptionName -
2285 12 : pszOptionName)) &&
2286 12 : EQUAL(pszKey +
2287 : static_cast<size_t>(pszStarInOptionName -
2288 : pszOptionName) +
2289 : 1,
2290 : pszStarInOptionName + 1))
2291 : {
2292 6 : break;
2293 : }
2294 :
2295 165316 : if (EQUAL(pszOptionName, pszKey))
2296 : {
2297 19283 : break;
2298 : }
2299 146033 : const char *pszAlias = CPLGetXMLValue(
2300 : psChildNode, "alias",
2301 : CPLGetXMLValue(psChildNode, "deprecated_alias", ""));
2302 146033 : if (EQUAL(pszAlias, pszKey))
2303 : {
2304 5 : CPLDebug("GDAL",
2305 : "Using deprecated alias '%s'. New name is '%s'",
2306 : pszAlias, pszOptionName);
2307 5 : break;
2308 : }
2309 : }
2310 146028 : psChildNode = psChildNode->psNext;
2311 : }
2312 20131 : if (psChildNode == nullptr)
2313 : {
2314 634 : if (bWarnIfMissingKey &&
2315 15 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2316 0 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2317 : true)))
2318 : {
2319 15 : CPLError(CE_Warning, CPLE_NotSupported,
2320 : "%s does not support %s %s",
2321 : pszErrorMessageContainerName,
2322 : pszErrorMessageOptionType, pszKey);
2323 15 : bRet = false;
2324 : }
2325 :
2326 619 : CPLFree(pszKey);
2327 619 : ++papszOptionsToValidate;
2328 619 : continue;
2329 : }
2330 :
2331 : #ifdef DEBUG
2332 19512 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2333 117817 : while (psChildSubNode)
2334 : {
2335 98305 : if (psChildSubNode->eType == CXT_Attribute)
2336 : {
2337 67279 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2338 47767 : EQUAL(psChildSubNode->pszValue, "alias") ||
2339 47734 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2340 47692 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2341 47659 : EQUAL(psChildSubNode->pszValue, "description") ||
2342 30744 : EQUAL(psChildSubNode->pszValue, "type") ||
2343 11232 : EQUAL(psChildSubNode->pszValue, "min") ||
2344 11070 : EQUAL(psChildSubNode->pszValue, "max") ||
2345 10832 : EQUAL(psChildSubNode->pszValue, "default") ||
2346 992 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2347 967 : EQUAL(psChildSubNode->pszValue, "required") ||
2348 912 : EQUAL(psChildSubNode->pszValue, "scope")))
2349 : {
2350 : /* Driver error */
2351 0 : CPLError(CE_Warning, CPLE_NotSupported,
2352 : "%s : unhandled attribute '%s' for %s %s.",
2353 : pszErrorMessageContainerName,
2354 : psChildSubNode->pszValue, pszKey,
2355 : pszErrorMessageOptionType);
2356 : }
2357 : }
2358 98305 : psChildSubNode = psChildSubNode->psNext;
2359 : }
2360 : #endif
2361 :
2362 19512 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2363 19512 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2364 19512 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2365 19512 : if (pszType != nullptr)
2366 : {
2367 19512 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2368 : {
2369 8375 : const char *pszValueIter = pszValue;
2370 21290 : while (*pszValueIter)
2371 : {
2372 12917 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2373 19 : *pszValueIter == '+' || *pszValueIter == '-'))
2374 : {
2375 2 : CPLError(CE_Warning, CPLE_NotSupported,
2376 : "'%s' is an unexpected value for %s %s of "
2377 : "type int.",
2378 : pszValue, pszKey, pszErrorMessageOptionType);
2379 2 : bRet = false;
2380 2 : break;
2381 : }
2382 12915 : ++pszValueIter;
2383 : }
2384 8375 : if (*pszValueIter == '\0')
2385 : {
2386 8373 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2387 : {
2388 6 : CPLError(CE_Warning, CPLE_NotSupported,
2389 : "'%s' is an unexpected value for %s %s that "
2390 : "should be >= %s.",
2391 : pszValue, pszKey, pszErrorMessageOptionType,
2392 : pszMin);
2393 6 : bRet = false;
2394 : }
2395 8373 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2396 : {
2397 12 : CPLError(CE_Warning, CPLE_NotSupported,
2398 : "'%s' is an unexpected value for %s %s that "
2399 : "should be <= %s.",
2400 : pszValue, pszKey, pszErrorMessageOptionType,
2401 : pszMax);
2402 12 : bRet = false;
2403 : }
2404 8375 : }
2405 : }
2406 11137 : else if (EQUAL(pszType, "UNSIGNED INT"))
2407 : {
2408 3 : const char *pszValueIter = pszValue;
2409 10 : while (*pszValueIter)
2410 : {
2411 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2412 0 : *pszValueIter == '+'))
2413 : {
2414 0 : CPLError(CE_Warning, CPLE_NotSupported,
2415 : "'%s' is an unexpected value for %s %s of "
2416 : "type unsigned int.",
2417 : pszValue, pszKey, pszErrorMessageOptionType);
2418 0 : bRet = false;
2419 0 : break;
2420 : }
2421 7 : ++pszValueIter;
2422 : }
2423 3 : if (*pszValueIter == '\0')
2424 : {
2425 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2426 : {
2427 0 : 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 0 : bRet = false;
2433 : }
2434 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2435 : {
2436 0 : 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 0 : bRet = false;
2442 : }
2443 : }
2444 : }
2445 11134 : else if (EQUAL(pszType, "FLOAT"))
2446 : {
2447 582 : char *endPtr = nullptr;
2448 582 : double dfVal = CPLStrtod(pszValue, &endPtr);
2449 582 : if (!(endPtr == nullptr || *endPtr == '\0'))
2450 : {
2451 0 : CPLError(
2452 : CE_Warning, CPLE_NotSupported,
2453 : "'%s' is an unexpected value for %s %s of type float.",
2454 : pszValue, pszKey, pszErrorMessageOptionType);
2455 0 : bRet = false;
2456 : }
2457 : else
2458 : {
2459 582 : if (pszMin && dfVal < CPLAtof(pszMin))
2460 : {
2461 2 : CPLError(CE_Warning, CPLE_NotSupported,
2462 : "'%s' is an unexpected value for %s %s that "
2463 : "should be >= %s.",
2464 : pszValue, pszKey, pszErrorMessageOptionType,
2465 : pszMin);
2466 2 : bRet = false;
2467 : }
2468 582 : if (pszMax && dfVal > CPLAtof(pszMax))
2469 : {
2470 0 : CPLError(CE_Warning, CPLE_NotSupported,
2471 : "'%s' is an unexpected value for %s %s that "
2472 : "should be <= %s.",
2473 : pszValue, pszKey, pszErrorMessageOptionType,
2474 : pszMax);
2475 0 : bRet = false;
2476 : }
2477 : }
2478 : }
2479 10552 : else if (EQUAL(pszType, "BOOLEAN"))
2480 : {
2481 2493 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2482 2447 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2483 438 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2484 : {
2485 0 : CPLError(CE_Warning, CPLE_NotSupported,
2486 : "'%s' is an unexpected value for %s %s of type "
2487 : "boolean.",
2488 : pszValue, pszKey, pszErrorMessageOptionType);
2489 0 : bRet = false;
2490 : }
2491 : }
2492 8059 : else if (EQUAL(pszType, "STRING-SELECT"))
2493 : {
2494 4684 : bool bMatchFound = false;
2495 4684 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2496 30885 : while (psStringSelect)
2497 : {
2498 30852 : if (psStringSelect->eType == CXT_Element &&
2499 16180 : EQUAL(psStringSelect->pszValue, "Value"))
2500 : {
2501 16180 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2502 27983 : while (psOptionNode)
2503 : {
2504 16454 : if (psOptionNode->eType == CXT_Text &&
2505 16172 : EQUAL(psOptionNode->pszValue, pszValue))
2506 : {
2507 4643 : bMatchFound = true;
2508 4643 : break;
2509 : }
2510 11811 : if (psOptionNode->eType == CXT_Attribute &&
2511 282 : (EQUAL(psOptionNode->pszValue, "alias") ||
2512 13 : EQUAL(psOptionNode->pszValue,
2513 269 : "deprecated_alias")) &&
2514 269 : EQUAL(psOptionNode->psChild->pszValue,
2515 : pszValue))
2516 : {
2517 8 : bMatchFound = true;
2518 8 : break;
2519 : }
2520 11803 : psOptionNode = psOptionNode->psNext;
2521 : }
2522 16180 : if (bMatchFound)
2523 4651 : break;
2524 : }
2525 26201 : psStringSelect = psStringSelect->psNext;
2526 : }
2527 4684 : if (!bMatchFound)
2528 : {
2529 33 : CPLError(CE_Warning, CPLE_NotSupported,
2530 : "'%s' is an unexpected value for %s %s of type "
2531 : "string-select.",
2532 : pszValue, pszKey, pszErrorMessageOptionType);
2533 33 : bRet = false;
2534 : }
2535 : }
2536 3375 : else if (EQUAL(pszType, "STRING"))
2537 : {
2538 : const char *pszMaxSize =
2539 3375 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2540 3375 : if (pszMaxSize != nullptr)
2541 : {
2542 25 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2543 : {
2544 1 : CPLError(CE_Warning, CPLE_NotSupported,
2545 : "'%s' is of size %d, whereas maximum size for "
2546 : "%s %s is %d.",
2547 1 : pszValue, static_cast<int>(strlen(pszValue)),
2548 : pszKey, pszErrorMessageOptionType,
2549 : atoi(pszMaxSize));
2550 1 : bRet = false;
2551 : }
2552 : }
2553 : }
2554 : else
2555 : {
2556 : /* Driver error */
2557 0 : CPLError(CE_Warning, CPLE_NotSupported,
2558 : "%s : type '%s' for %s %s is not recognized.",
2559 : pszErrorMessageContainerName, pszType, pszKey,
2560 : pszErrorMessageOptionType);
2561 : }
2562 : }
2563 : else
2564 : {
2565 : /* Driver error */
2566 0 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2567 : pszErrorMessageContainerName, pszKey,
2568 : pszErrorMessageOptionType);
2569 : }
2570 19512 : CPLFree(pszKey);
2571 19512 : ++papszOptionsToValidate;
2572 : }
2573 :
2574 11868 : CPLDestroyXMLNode(psNode);
2575 11868 : return bRet ? TRUE : FALSE;
2576 : }
2577 :
2578 : /************************************************************************/
2579 : /* GDALIdentifyDriver() */
2580 : /************************************************************************/
2581 :
2582 : /**
2583 : * \brief Identify the driver that can open a dataset.
2584 : *
2585 : * This function will try to identify the driver that can open the passed file
2586 : * name by invoking the Identify method of each registered GDALDriver in turn.
2587 : * The first driver that successfully identifies the file name will be returned.
2588 : * If all drivers fail then NULL is returned.
2589 : *
2590 : * In order to reduce the need for such searches to touch the operating system
2591 : * file system machinery, it is possible to give an optional list of files.
2592 : * This is the list of all files at the same level in the file system as the
2593 : * target file, including the target file. The filenames will not include any
2594 : * path components, and are essentially just the output of VSIReadDir() on the
2595 : * parent directory. If the target object does not have filesystem semantics
2596 : * then the file list should be NULL.
2597 : *
2598 : * @param pszFilename the name of the file to access. In the case of
2599 : * exotic drivers this may not refer to a physical file, but instead contain
2600 : * information for the driver on how to access a dataset.
2601 : *
2602 : * @param papszFileList an array of strings, whose last element is the NULL
2603 : * pointer. These strings are filenames that are auxiliary to the main
2604 : * filename. The passed value may be NULL.
2605 : *
2606 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2607 : * this handle can be cast to a GDALDriver *.
2608 : */
2609 :
2610 21708 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2611 : CSLConstList papszFileList)
2612 :
2613 : {
2614 21708 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2615 : }
2616 :
2617 : /************************************************************************/
2618 : /* GDALIdentifyDriverEx() */
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 nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2642 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2643 : * both kinds are implied.
2644 : *
2645 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2646 : * terminated list of strings with the driver short names that must be
2647 : * considered.
2648 : *
2649 : * @param papszFileList an array of strings, whose last element is the NULL
2650 : * pointer. These strings are filenames that are auxiliary to the main
2651 : * filename. The passed value may be NULL.
2652 : *
2653 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2654 : * this handle can be cast to a GDALDriver *.
2655 : *
2656 : * @since GDAL 2.2
2657 : */
2658 :
2659 21798 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2660 : const char *pszFilename, unsigned int nIdentifyFlags,
2661 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2662 : {
2663 21798 : GDALDriverManager *poDM = GetGDALDriverManager();
2664 21798 : CPLAssert(nullptr != poDM);
2665 :
2666 : // If no driver kind is specified, assume all are to be probed.
2667 21798 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2668 21755 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2669 :
2670 43596 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2671 21798 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2672 :
2673 43596 : CPLErrorStateBackuper oBackuper;
2674 21798 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2675 :
2676 21798 : const int nDriverCount = poDM->GetDriverCount();
2677 :
2678 : // First pass: only use drivers that have a pfnIdentify implementation.
2679 43596 : std::vector<GDALDriver *> apoSecondPassDrivers;
2680 5040310 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2681 : {
2682 5019640 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2683 5027500 : if (papszAllowedDrivers != nullptr &&
2684 7852 : CSLFindString(papszAllowedDrivers,
2685 : GDALGetDriverShortName(poDriver)) == -1)
2686 : {
2687 1121290 : continue;
2688 : }
2689 :
2690 5012960 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2691 :
2692 5011840 : if (poDriver->pfnIdentify == nullptr &&
2693 1109470 : poDriver->pfnIdentifyEx == nullptr)
2694 : {
2695 1109470 : continue;
2696 : }
2697 :
2698 3902410 : if (papszAllowedDrivers != nullptr &&
2699 44 : CSLFindString(papszAllowedDrivers,
2700 : GDALGetDriverShortName(poDriver)) == -1)
2701 0 : continue;
2702 11702200 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2703 3902880 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2704 519 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2705 143 : continue;
2706 11710200 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2707 3907240 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2708 5021 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2709 3866 : continue;
2710 :
2711 3898360 : if (poDriver->pfnIdentifyEx)
2712 : {
2713 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2714 0 : return poDriver;
2715 : }
2716 : else
2717 : {
2718 3898360 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2719 3898360 : if (nIdentifyRes > 0)
2720 1128 : return poDriver;
2721 3918040 : if (nIdentifyRes < 0 &&
2722 20812 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2723 : {
2724 : // Not loaded plugin
2725 18 : apoSecondPassDrivers.push_back(poDriver);
2726 : }
2727 : }
2728 : }
2729 :
2730 : // second pass: try loading plugin drivers
2731 20685 : for (auto poDriver : apoSecondPassDrivers)
2732 : {
2733 : // Force plugin driver loading
2734 16 : poDriver->GetMetadata();
2735 16 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2736 1 : return poDriver;
2737 : }
2738 :
2739 : // third pass: slow method.
2740 4949610 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2741 : {
2742 4928990 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2743 4933050 : if (papszAllowedDrivers != nullptr &&
2744 4062 : CSLFindString(papszAllowedDrivers,
2745 : GDALGetDriverShortName(poDriver)) == -1)
2746 : {
2747 4045 : continue;
2748 : }
2749 :
2750 4924950 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2751 :
2752 14773300 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2753 4925420 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2754 476 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2755 151 : continue;
2756 14775100 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2757 4926460 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2758 1668 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2759 1016 : continue;
2760 :
2761 4923780 : if (poDriver->pfnIdentifyEx != nullptr)
2762 : {
2763 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2764 0 : continue;
2765 : }
2766 4923780 : else if (poDriver->pfnIdentify != nullptr)
2767 : {
2768 3833200 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2769 3812520 : continue;
2770 : }
2771 :
2772 : GDALDataset *poDS;
2773 1111260 : if (poDriver->pfnOpen != nullptr)
2774 : {
2775 1070040 : poDS = poDriver->pfnOpen(&oOpenInfo);
2776 1070040 : if (poDS != nullptr)
2777 : {
2778 47 : delete poDS;
2779 47 : return GDALDriver::ToHandle(poDriver);
2780 : }
2781 :
2782 1069990 : if (CPLGetLastErrorType() != CE_None)
2783 0 : return nullptr;
2784 : }
2785 41224 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2786 : {
2787 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2788 0 : if (poDS != nullptr)
2789 : {
2790 0 : delete poDS;
2791 0 : return GDALDriver::ToHandle(poDriver);
2792 : }
2793 :
2794 0 : if (CPLGetLastErrorType() != CE_None)
2795 0 : return nullptr;
2796 : }
2797 : }
2798 :
2799 20622 : return nullptr;
2800 : }
2801 :
2802 : /************************************************************************/
2803 : /* SetMetadataItem() */
2804 : /************************************************************************/
2805 :
2806 3238890 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
2807 : const char *pszDomain)
2808 :
2809 : {
2810 3238890 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2811 : {
2812 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2813 3390530 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
2814 151654 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
2815 : {
2816 151654 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
2817 : }
2818 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2819 6228830 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
2820 3091110 : strchr(pszValue, ' ') == nullptr &&
2821 3890 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
2822 : nullptr)
2823 : {
2824 3890 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
2825 : }
2826 : }
2827 3238890 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
2828 : }
2829 :
2830 : /************************************************************************/
2831 : /* DoesDriverHandleExtension() */
2832 : /************************************************************************/
2833 :
2834 182256 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
2835 : {
2836 182256 : bool bRet = false;
2837 : const char *pszDriverExtensions =
2838 182256 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
2839 182256 : if (pszDriverExtensions)
2840 : {
2841 288894 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
2842 144447 : const int nTokens = aosTokens.size();
2843 320538 : for (int j = 0; j < nTokens; ++j)
2844 : {
2845 179938 : if (EQUAL(pszExt, aosTokens[j]))
2846 : {
2847 3847 : bRet = true;
2848 3847 : break;
2849 : }
2850 : }
2851 : }
2852 182256 : return bRet;
2853 : }
2854 :
2855 : /************************************************************************/
2856 : /* GDALGetOutputDriversForDatasetName() */
2857 : /************************************************************************/
2858 :
2859 : /** Return a list of driver short names that are likely candidates for the
2860 : * provided output file name.
2861 : *
2862 : * @param pszDestDataset Output dataset name (might not exist).
2863 : * @param nFlagRasterVector GDAL_OF_RASTER, GDAL_OF_VECTOR or
2864 : * binary-or'ed combination of both
2865 : * @param bSingleMatch Whether a single match is desired, that is to say the
2866 : * returned list will contain at most one item, which will
2867 : * be the first driver in the order they are registered to
2868 : * match the output dataset name. Note that in this mode, if
2869 : * nFlagRasterVector==GDAL_OF_RASTER and pszDestDataset has
2870 : * no extension, GTiff will be selected.
2871 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
2872 : * true and there are more than 2 candidates.
2873 : * @return NULL terminated list of driver short names.
2874 : * To be freed with CSLDestroy()
2875 : * @since 3.9
2876 : */
2877 2189 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
2878 : int nFlagRasterVector,
2879 : bool bSingleMatch, bool bEmitWarning)
2880 : {
2881 4378 : CPLStringList aosDriverNames;
2882 :
2883 4378 : std::string osExt = CPLGetExtension(pszDestDataset);
2884 2189 : if (EQUAL(osExt.c_str(), "zip"))
2885 : {
2886 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
2887 1 : if (osLower.endsWith(".shp.zip"))
2888 : {
2889 1 : osExt = "shp.zip";
2890 : }
2891 0 : else if (osLower.endsWith(".gpkg.zip"))
2892 : {
2893 0 : osExt = "gpkg.zip";
2894 : }
2895 : }
2896 :
2897 2189 : const int nDriverCount = GDALGetDriverCount();
2898 524960 : for (int i = 0; i < nDriverCount; i++)
2899 : {
2900 522771 : GDALDriverH hDriver = GDALGetDriver(i);
2901 522771 : bool bOk = false;
2902 522771 : if ((GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
2903 299495 : nullptr ||
2904 299495 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) !=
2905 1045540 : nullptr) &&
2906 295513 : (((nFlagRasterVector & GDAL_OF_RASTER) &&
2907 249884 : GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
2908 130775 : nullptr) ||
2909 130775 : ((nFlagRasterVector & GDAL_OF_VECTOR) &&
2910 45629 : GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr) !=
2911 : nullptr)))
2912 : {
2913 184679 : bOk = true;
2914 : }
2915 338092 : else if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR_TRANSLATE_FROM,
2916 339943 : nullptr) &&
2917 1851 : (nFlagRasterVector & GDAL_OF_VECTOR) != 0)
2918 : {
2919 0 : bOk = true;
2920 : }
2921 522771 : if (bOk)
2922 : {
2923 366935 : if (!osExt.empty() &&
2924 182256 : DoesDriverHandleExtension(hDriver, osExt.c_str()))
2925 : {
2926 3847 : aosDriverNames.AddString(GDALGetDriverShortName(hDriver));
2927 : }
2928 : else
2929 : {
2930 180832 : const char *pszPrefix = GDALGetMetadataItem(
2931 : hDriver, GDAL_DMD_CONNECTION_PREFIX, nullptr);
2932 180832 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
2933 : {
2934 9 : aosDriverNames.AddString(GDALGetDriverShortName(hDriver));
2935 : }
2936 : }
2937 : }
2938 : }
2939 :
2940 : // GMT is registered before netCDF for opening reasons, but we want
2941 : // netCDF to be used by default for output.
2942 2191 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
2943 2191 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
2944 : {
2945 0 : aosDriverNames.Clear();
2946 0 : aosDriverNames.AddString("netCDF");
2947 0 : aosDriverNames.AddString("GMT");
2948 : }
2949 :
2950 2189 : if (bSingleMatch)
2951 : {
2952 1851 : if (nFlagRasterVector == GDAL_OF_RASTER)
2953 : {
2954 1851 : if (aosDriverNames.empty())
2955 : {
2956 8 : if (osExt.empty())
2957 : {
2958 8 : aosDriverNames.AddString("GTiff");
2959 : }
2960 : }
2961 1843 : else if (aosDriverNames.size() >= 2)
2962 : {
2963 3388 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
2964 1694 : EQUAL(aosDriverNames[1], "COG")))
2965 : {
2966 0 : CPLError(CE_Warning, CPLE_AppDefined,
2967 : "Several drivers matching %s extension. Using %s",
2968 : osExt.c_str(), aosDriverNames[0]);
2969 : }
2970 3388 : const std::string osDrvName = aosDriverNames[0];
2971 1694 : aosDriverNames.Clear();
2972 1694 : aosDriverNames.AddString(osDrvName.c_str());
2973 : }
2974 : }
2975 0 : else if (aosDriverNames.size() >= 2)
2976 : {
2977 0 : if (bEmitWarning)
2978 : {
2979 0 : CPLError(CE_Warning, CPLE_AppDefined,
2980 : "Several drivers matching %s extension. Using %s",
2981 : osExt.c_str(), aosDriverNames[0]);
2982 : }
2983 0 : const std::string osDrvName = aosDriverNames[0];
2984 0 : aosDriverNames.Clear();
2985 0 : aosDriverNames.AddString(osDrvName.c_str());
2986 : }
2987 : }
2988 :
2989 4378 : return aosDriverNames.StealList();
2990 : }
|