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