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