Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Virtual GDAL Datasets
4 : * Purpose: Implementation of VRTRawRasterBand
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "rawdataset.h"
16 : #include "vrtdataset.h"
17 :
18 : #include <cerrno>
19 : #include <cstdio>
20 : #include <cstdlib>
21 : #include <cstring>
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_error.h"
25 : #include "cpl_hash_set.h"
26 : #include "cpl_minixml.h"
27 : #include "cpl_string.h"
28 : #include "cpl_vsi.h"
29 : #include "gdal.h"
30 : #include "gdal_priv.h"
31 :
32 : /*! @cond Doxygen_Suppress */
33 :
34 : /************************************************************************/
35 : /* ==================================================================== */
36 : /* VRTRawRasterBand */
37 : /* ==================================================================== */
38 : /************************************************************************/
39 :
40 : /************************************************************************/
41 : /* VRTRawRasterBand() */
42 : /************************************************************************/
43 :
44 38 : VRTRawRasterBand::VRTRawRasterBand(GDALDataset *poDSIn, int nBandIn,
45 38 : GDALDataType eType)
46 : : m_poRawRaster(nullptr), m_pszSourceFilename(nullptr),
47 38 : m_bRelativeToVRT(FALSE)
48 : {
49 38 : if (!VRTDataset::IsRawRasterBandEnabled())
50 : {
51 : // Safety belt. Not supposed to happen, hence CE_Fatal
52 0 : CPLError(CE_Fatal, CPLE_NotSupported,
53 : "Crashing process: VRTRawRasterBand constructor called "
54 : "whereas not authorized");
55 0 : return;
56 : }
57 :
58 38 : Initialize(poDSIn->GetRasterXSize(), poDSIn->GetRasterYSize());
59 :
60 : // Declared in GDALRasterBand.
61 38 : poDS = poDSIn;
62 38 : nBand = nBandIn;
63 :
64 38 : if (eType != GDT_Unknown)
65 6 : eDataType = eType;
66 : }
67 :
68 : /************************************************************************/
69 : /* ~VRTRawRasterBand() */
70 : /************************************************************************/
71 :
72 76 : VRTRawRasterBand::~VRTRawRasterBand()
73 :
74 : {
75 38 : FlushCache(true);
76 38 : ClearRawLink();
77 76 : }
78 :
79 : /************************************************************************/
80 : /* IRasterIO() */
81 : /************************************************************************/
82 :
83 265 : CPLErr VRTRawRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
84 : int nXSize, int nYSize, void *pData,
85 : int nBufXSize, int nBufYSize,
86 : GDALDataType eBufType, GSpacing nPixelSpace,
87 : GSpacing nLineSpace,
88 : GDALRasterIOExtraArg *psExtraArg)
89 : {
90 265 : if (m_poRawRaster == nullptr)
91 : {
92 0 : CPLError(CE_Failure, CPLE_AppDefined,
93 : "No raw raster band configured on VRTRawRasterBand.");
94 0 : return CE_Failure;
95 : }
96 :
97 265 : if (eRWFlag == GF_Write && eAccess == GA_ReadOnly)
98 : {
99 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
100 : "Attempt to write to read only dataset in"
101 : "VRTRawRasterBand::IRasterIO().");
102 :
103 0 : return CE_Failure;
104 : }
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Do we have overviews that would be appropriate to satisfy */
108 : /* this request? */
109 : /* -------------------------------------------------------------------- */
110 265 : if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
111 : {
112 0 : if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
113 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
114 0 : nLineSpace, psExtraArg) == CE_None)
115 0 : return CE_None;
116 : }
117 :
118 265 : m_poRawRaster->SetAccess(eAccess);
119 :
120 265 : return m_poRawRaster->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
121 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
122 265 : nLineSpace, psExtraArg);
123 : }
124 :
125 : /************************************************************************/
126 : /* IReadBlock() */
127 : /************************************************************************/
128 :
129 70 : CPLErr VRTRawRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
130 : void *pImage)
131 :
132 : {
133 70 : if (m_poRawRaster == nullptr)
134 : {
135 0 : CPLError(CE_Failure, CPLE_AppDefined,
136 : "No raw raster band configured on VRTRawRasterBand.");
137 0 : return CE_Failure;
138 : }
139 :
140 70 : return m_poRawRaster->ReadBlock(nBlockXOff, nBlockYOff, pImage);
141 : }
142 :
143 : /************************************************************************/
144 : /* IWriteBlock() */
145 : /************************************************************************/
146 :
147 0 : CPLErr VRTRawRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
148 : void *pImage)
149 :
150 : {
151 0 : if (m_poRawRaster == nullptr)
152 : {
153 0 : CPLError(CE_Failure, CPLE_AppDefined,
154 : "No raw raster band configured on VRTRawRasterBand.");
155 0 : return CE_Failure;
156 : }
157 :
158 0 : m_poRawRaster->SetAccess(eAccess);
159 :
160 0 : return m_poRawRaster->WriteBlock(nBlockXOff, nBlockYOff, pImage);
161 : }
162 :
163 : /************************************************************************/
164 : /* SetRawLink() */
165 : /************************************************************************/
166 :
167 38 : CPLErr VRTRawRasterBand::SetRawLink(const char *pszFilename,
168 : const char *pszVRTPath,
169 : int bRelativeToVRTIn,
170 : vsi_l_offset nImageOffset, int nPixelOffset,
171 : int nLineOffset, const char *pszByteOrder)
172 :
173 : {
174 38 : ClearRawLink();
175 :
176 38 : static_cast<VRTDataset *>(poDS)->SetNeedsFlush();
177 :
178 : /* -------------------------------------------------------------------- */
179 : /* Prepare filename. */
180 : /* -------------------------------------------------------------------- */
181 38 : if (pszFilename == nullptr)
182 : {
183 0 : CPLError(CE_Warning, CPLE_AppDefined,
184 : "Missing <SourceFilename> element in VRTRasterBand.");
185 0 : return CE_Failure;
186 : }
187 :
188 : const std::string osExpandedFilename =
189 28 : (pszVRTPath && bRelativeToVRTIn)
190 38 : ? CPLProjectRelativeFilenameSafe(pszVRTPath, pszFilename)
191 132 : : pszFilename;
192 :
193 : const char *pszAllowedPaths =
194 38 : CPLGetConfigOption("GDAL_VRT_RAWRASTERBAND_ALLOWED_SOURCE", nullptr);
195 38 : if (pszAllowedPaths == nullptr ||
196 12 : EQUAL(pszAllowedPaths, "SIBLING_OR_CHILD_OF_VRT_PATH"))
197 : {
198 28 : const char *pszErrorMsgPart =
199 : pszAllowedPaths
200 28 : ? "GDAL_VRT_RAWRASTERBAND_ALLOWED_SOURCE=SIBLING_OR_CHILD_OF_"
201 : "VRT_PATH"
202 : : "the GDAL_VRT_RAWRASTERBAND_ALLOWED_SOURCE configuration "
203 : "option is not set (and thus defaults to "
204 : "SIBLING_OR_CHILD_OF_VRT_PATH. Consult "
205 : "https://gdal.org/drivers/raster/"
206 : "vrt.html#vrtrawrasterband_restricted_access for more "
207 : "details)";
208 28 : if (!bRelativeToVRTIn)
209 : {
210 1 : CPLError(CE_Failure, CPLE_AppDefined,
211 : "'%s' is invalid because the relativeToVRT flag is not "
212 : "set and %s",
213 : pszFilename, pszErrorMsgPart);
214 1 : return CE_Failure;
215 : }
216 27 : if (!CPLIsFilenameRelative(pszFilename))
217 : {
218 1 : CPLError(CE_Failure, CPLE_AppDefined,
219 : "'%s' is invalid because it is not relative to the VRT "
220 : "path and %s",
221 : pszFilename, pszErrorMsgPart);
222 1 : return CE_Failure;
223 : }
224 26 : if (strstr(pszFilename, "../") || strstr(pszFilename, "..\\"))
225 : {
226 1 : CPLError(CE_Failure, CPLE_AppDefined,
227 : "'%s' is invalid because it may not be a sibling or "
228 : "child of the VRT path and %s",
229 : pszFilename, pszErrorMsgPart);
230 1 : return CE_Failure;
231 25 : }
232 : }
233 10 : else if (EQUAL(pszAllowedPaths, "ALL"))
234 : {
235 : // ok
236 : }
237 6 : else if (EQUAL(pszAllowedPaths, "ONLY_REMOTE"))
238 : {
239 2 : if (VSIIsLocal(pszFilename))
240 : {
241 1 : CPLError(CE_Failure, CPLE_AppDefined,
242 : "'%s' is a local file, whereas "
243 : "GDAL_VRT_RAWRASTERBAND_ALLOWED_SOURCE=ONLY_REMOTE is set",
244 : pszFilename);
245 1 : return CE_Failure;
246 : }
247 : }
248 : else
249 : {
250 4 : if (strstr(pszFilename, "../") || strstr(pszFilename, "..\\"))
251 : {
252 1 : CPLError(CE_Failure, CPLE_AppDefined,
253 : "'%s' is invalid because the presence of ../ in it may "
254 : "escape from the allowed path(s)",
255 : pszFilename);
256 3 : return CE_Failure;
257 : }
258 : #ifdef _WIN32
259 : constexpr const char *pszSep = ";";
260 : #else
261 3 : constexpr const char *pszSep = ":";
262 : #endif
263 3 : bool bOK = false;
264 : const CPLStringList aosPaths(
265 3 : CSLTokenizeString2(pszAllowedPaths, pszSep, 0));
266 4 : for (const char *pszPath : aosPaths)
267 : {
268 3 : if (CPLIsFilenameRelative(pszPath))
269 : {
270 1 : CPLError(
271 : CE_Failure, CPLE_AppDefined,
272 : "Invalid value for GDAL_VRT_RAWRASTERBAND_ALLOWED_SOURCE. "
273 : "'%s' is not an absolute path",
274 : pszPath);
275 1 : return CE_Failure;
276 : }
277 2 : if (STARTS_WITH(osExpandedFilename.c_str(), pszPath))
278 : {
279 1 : bOK = true;
280 1 : break;
281 : }
282 : }
283 2 : if (!bOK)
284 : {
285 1 : CPLError(CE_Failure, CPLE_AppDefined,
286 : "'%s' is invalid because it is not contained in one of "
287 : "the allowed path(s)",
288 : pszFilename);
289 1 : return CE_Failure;
290 : }
291 : }
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Try and open the file. We always use the large file API. */
295 : /* -------------------------------------------------------------------- */
296 31 : CPLPushErrorHandler(CPLQuietErrorHandler);
297 31 : FILE *fp = CPLOpenShared(osExpandedFilename.c_str(), "rb+", TRUE);
298 :
299 31 : if (fp == nullptr)
300 5 : fp = CPLOpenShared(osExpandedFilename.c_str(), "rb", TRUE);
301 :
302 35 : if (fp == nullptr &&
303 4 : static_cast<VRTDataset *>(poDS)->GetAccess() == GA_Update)
304 : {
305 3 : fp = CPLOpenShared(osExpandedFilename.c_str(), "wb+", TRUE);
306 : }
307 31 : CPLPopErrorHandler();
308 31 : CPLErrorReset();
309 :
310 31 : if (fp == nullptr)
311 : {
312 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Unable to open %s.%s",
313 1 : osExpandedFilename.c_str(), VSIStrerror(errno));
314 :
315 1 : return CE_Failure;
316 : }
317 :
318 30 : if (!RAWDatasetCheckMemoryUsage(
319 : nRasterXSize, nRasterYSize, 1,
320 : GDALGetDataTypeSizeBytes(GetRasterDataType()), nPixelOffset,
321 : nLineOffset, nImageOffset, 0, reinterpret_cast<VSILFILE *>(fp)))
322 : {
323 2 : CPLCloseShared(fp);
324 2 : return CE_Failure;
325 : }
326 :
327 28 : m_pszSourceFilename = CPLStrdup(pszFilename);
328 28 : m_bRelativeToVRT = bRelativeToVRTIn;
329 :
330 : /* -------------------------------------------------------------------- */
331 : /* Work out if we are in native mode or not. */
332 : /* -------------------------------------------------------------------- */
333 28 : RawRasterBand::ByteOrder eByteOrder =
334 : #if CPL_IS_LSB
335 : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
336 : #else
337 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
338 : #endif
339 :
340 28 : if (pszByteOrder != nullptr)
341 : {
342 26 : if (EQUAL(pszByteOrder, "LSB"))
343 14 : eByteOrder = RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
344 12 : else if (EQUAL(pszByteOrder, "MSB"))
345 7 : eByteOrder = RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
346 5 : else if (EQUAL(pszByteOrder, "VAX"))
347 4 : eByteOrder = RawRasterBand::ByteOrder::ORDER_VAX;
348 : else
349 : {
350 1 : CPLError(CE_Failure, CPLE_AppDefined,
351 : "Illegal ByteOrder value '%s', should be LSB, MSB or VAX.",
352 : pszByteOrder);
353 1 : CPLCloseShared(fp);
354 1 : return CE_Failure;
355 : }
356 : }
357 :
358 : /* -------------------------------------------------------------------- */
359 : /* Create a corresponding RawRasterBand. */
360 : /* -------------------------------------------------------------------- */
361 27 : m_poRawRaster =
362 54 : RawRasterBand::Create(reinterpret_cast<VSILFILE *>(fp), nImageOffset,
363 : nPixelOffset, nLineOffset, GetRasterDataType(),
364 : eByteOrder, GetXSize(), GetYSize(),
365 : RawRasterBand::OwnFP::NO)
366 27 : .release();
367 27 : if (!m_poRawRaster)
368 : {
369 0 : CPLCloseShared(fp);
370 0 : return CE_Failure;
371 : }
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Reset block size to match the raw raster. */
375 : /* -------------------------------------------------------------------- */
376 27 : m_poRawRaster->GetBlockSize(&nBlockXSize, &nBlockYSize);
377 :
378 27 : return CE_None;
379 : }
380 :
381 : /************************************************************************/
382 : /* ClearRawLink() */
383 : /************************************************************************/
384 :
385 76 : void VRTRawRasterBand::ClearRawLink()
386 :
387 : {
388 76 : if (m_poRawRaster != nullptr)
389 : {
390 27 : VSILFILE *fp = m_poRawRaster->GetFPL();
391 27 : delete m_poRawRaster;
392 27 : m_poRawRaster = nullptr;
393 : // We close the file after deleting the raster band
394 : // since data can be flushed in the destructor.
395 27 : if (fp != nullptr)
396 : {
397 27 : CPLCloseShared(reinterpret_cast<FILE *>(fp));
398 : }
399 : }
400 76 : CPLFree(m_pszSourceFilename);
401 76 : m_pszSourceFilename = nullptr;
402 76 : }
403 :
404 : /************************************************************************/
405 : /* GetVirtualMemAuto() */
406 : /************************************************************************/
407 :
408 0 : CPLVirtualMem *VRTRawRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
409 : int *pnPixelSpace,
410 : GIntBig *pnLineSpace,
411 : char **papszOptions)
412 :
413 : {
414 : // check the pointer to RawRasterBand
415 0 : if (m_poRawRaster == nullptr)
416 : {
417 : // use the super class method
418 0 : return VRTRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
419 0 : pnLineSpace, papszOptions);
420 : }
421 : // if available, use the RawRasterBand method (use mmap if available)
422 0 : return m_poRawRaster->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
423 0 : papszOptions);
424 : }
425 :
426 : /************************************************************************/
427 : /* XMLInit() */
428 : /************************************************************************/
429 :
430 32 : CPLErr VRTRawRasterBand::XMLInit(const CPLXMLNode *psTree,
431 : const char *pszVRTPath,
432 : VRTMapSharedResources &oMapSharedSources)
433 :
434 : {
435 : const CPLErr eErr =
436 32 : VRTRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources);
437 32 : if (eErr != CE_None)
438 0 : return eErr;
439 :
440 : /* -------------------------------------------------------------------- */
441 : /* Validate a bit. */
442 : /* -------------------------------------------------------------------- */
443 32 : if (psTree == nullptr || psTree->eType != CXT_Element ||
444 96 : !EQUAL(psTree->pszValue, "VRTRasterBand") ||
445 32 : !EQUAL(CPLGetXMLValue(psTree, "subClass", ""), "VRTRawRasterBand"))
446 : {
447 0 : CPLError(CE_Failure, CPLE_AppDefined,
448 : "Invalid node passed to VRTRawRasterBand::XMLInit().");
449 0 : return CE_Failure;
450 : }
451 :
452 : /* -------------------------------------------------------------------- */
453 : /* Prepare filename. */
454 : /* -------------------------------------------------------------------- */
455 32 : const char *pszFilename = CPLGetXMLValue(psTree, "SourceFilename", nullptr);
456 :
457 32 : if (pszFilename == nullptr)
458 : {
459 0 : CPLError(CE_Warning, CPLE_AppDefined,
460 : "Missing <SourceFilename> element in VRTRasterBand.");
461 0 : return CE_Failure;
462 : }
463 :
464 32 : const bool l_bRelativeToVRT = CPLTestBool(
465 : CPLGetXMLValue(psTree, "SourceFilename.relativeToVRT", "1"));
466 :
467 : /* -------------------------------------------------------------------- */
468 : /* Collect layout information. */
469 : /* -------------------------------------------------------------------- */
470 32 : int nWordDataSize = GDALGetDataTypeSizeBytes(GetRasterDataType());
471 :
472 32 : const char *pszImageOffset = CPLGetXMLValue(psTree, "ImageOffset", "0");
473 64 : const vsi_l_offset nImageOffset = CPLScanUIntBig(
474 32 : pszImageOffset, static_cast<int>(strlen(pszImageOffset)));
475 :
476 32 : int nPixelOffset = nWordDataSize;
477 32 : const char *pszPixelOffset = CPLGetXMLValue(psTree, "PixelOffset", nullptr);
478 32 : if (pszPixelOffset != nullptr)
479 : {
480 24 : nPixelOffset = atoi(pszPixelOffset);
481 : }
482 32 : if (nPixelOffset <= 0)
483 : {
484 0 : CPLError(CE_Failure, CPLE_AppDefined,
485 : "Invalid value for <PixelOffset> element : %d", nPixelOffset);
486 0 : return CE_Failure;
487 : }
488 :
489 32 : int nLineOffset = 0;
490 32 : const char *pszLineOffset = CPLGetXMLValue(psTree, "LineOffset", nullptr);
491 32 : if (pszLineOffset == nullptr)
492 : {
493 8 : if (nPixelOffset > INT_MAX / GetXSize())
494 : {
495 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
496 0 : return CE_Failure;
497 : }
498 8 : nLineOffset = nPixelOffset * GetXSize();
499 : }
500 : else
501 24 : nLineOffset = atoi(pszLineOffset);
502 :
503 32 : const char *pszByteOrder = CPLGetXMLValue(psTree, "ByteOrder", nullptr);
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Open the file, and setup the raw layer access to the data. */
507 : /* -------------------------------------------------------------------- */
508 32 : return SetRawLink(pszFilename, pszVRTPath, l_bRelativeToVRT, nImageOffset,
509 32 : nPixelOffset, nLineOffset, pszByteOrder);
510 : }
511 :
512 : /************************************************************************/
513 : /* SerializeToXML() */
514 : /************************************************************************/
515 :
516 7 : CPLXMLNode *VRTRawRasterBand::SerializeToXML(const char *pszVRTPath,
517 : bool &bHasWarnedAboutRAMUsage,
518 : size_t &nAccRAMUsage)
519 :
520 : {
521 :
522 : /* -------------------------------------------------------------------- */
523 : /* We can't set the layout if there is no open rawband. */
524 : /* -------------------------------------------------------------------- */
525 7 : if (m_poRawRaster == nullptr)
526 : {
527 0 : CPLError(CE_Failure, CPLE_AppDefined,
528 : "VRTRawRasterBand::SerializeToXML() fails because "
529 : "m_poRawRaster is NULL.");
530 0 : return nullptr;
531 : }
532 :
533 7 : CPLXMLNode *psTree = VRTRasterBand::SerializeToXML(
534 : pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
535 :
536 : /* -------------------------------------------------------------------- */
537 : /* Set subclass. */
538 : /* -------------------------------------------------------------------- */
539 7 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"),
540 : CXT_Text, "VRTRawRasterBand");
541 :
542 : /* -------------------------------------------------------------------- */
543 : /* Setup the filename with relative flag. */
544 : /* -------------------------------------------------------------------- */
545 14 : CPLXMLNode *psNode = CPLCreateXMLElementAndValue(psTree, "SourceFilename",
546 7 : m_pszSourceFilename);
547 :
548 7 : CPLCreateXMLNode(CPLCreateXMLNode(psNode, CXT_Attribute, "relativeToVRT"),
549 7 : CXT_Text, m_bRelativeToVRT ? "1" : "0");
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* Set other layout information. */
553 : /* -------------------------------------------------------------------- */
554 :
555 7 : CPLCreateXMLElementAndValue(
556 : psTree, "ImageOffset",
557 7 : CPLSPrintf(CPL_FRMT_GUIB, m_poRawRaster->GetImgOffset()));
558 :
559 7 : CPLCreateXMLElementAndValue(
560 : psTree, "PixelOffset",
561 7 : CPLSPrintf("%d", m_poRawRaster->GetPixelOffset()));
562 :
563 7 : CPLCreateXMLElementAndValue(
564 7 : psTree, "LineOffset", CPLSPrintf("%d", m_poRawRaster->GetLineOffset()));
565 :
566 7 : switch (m_poRawRaster->GetByteOrder())
567 : {
568 3 : case RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN:
569 3 : CPLCreateXMLElementAndValue(psTree, "ByteOrder", "LSB");
570 3 : break;
571 4 : case RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN:
572 4 : CPLCreateXMLElementAndValue(psTree, "ByteOrder", "MSB");
573 4 : break;
574 0 : case RawRasterBand::ByteOrder::ORDER_VAX:
575 0 : CPLCreateXMLElementAndValue(psTree, "ByteOrder", "VAX");
576 0 : break;
577 : }
578 :
579 7 : return psTree;
580 : }
581 :
582 : /************************************************************************/
583 : /* GetFileList() */
584 : /************************************************************************/
585 :
586 3 : void VRTRawRasterBand::GetFileList(char ***ppapszFileList, int *pnSize,
587 : int *pnMaxSize, CPLHashSet *hSetFiles)
588 : {
589 3 : if (m_pszSourceFilename == nullptr)
590 1 : return;
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Is it already in the list ? */
594 : /* -------------------------------------------------------------------- */
595 3 : CPLString osSourceFilename;
596 3 : if (m_bRelativeToVRT && strlen(poDS->GetDescription()) > 0)
597 3 : osSourceFilename = CPLFormFilenameSafe(
598 6 : CPLGetDirnameSafe(poDS->GetDescription()).c_str(),
599 6 : m_pszSourceFilename, nullptr);
600 : else
601 0 : osSourceFilename = m_pszSourceFilename;
602 :
603 3 : if (CPLHashSetLookup(hSetFiles, osSourceFilename) != nullptr)
604 1 : return;
605 :
606 : /* -------------------------------------------------------------------- */
607 : /* Grow array if necessary */
608 : /* -------------------------------------------------------------------- */
609 2 : if (*pnSize + 1 >= *pnMaxSize)
610 : {
611 2 : *pnMaxSize = 2 + 2 * (*pnMaxSize);
612 2 : *ppapszFileList = static_cast<char **>(
613 2 : CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
614 : }
615 :
616 : /* -------------------------------------------------------------------- */
617 : /* Add the string to the list */
618 : /* -------------------------------------------------------------------- */
619 2 : (*ppapszFileList)[*pnSize] = CPLStrdup(osSourceFilename);
620 2 : (*ppapszFileList)[(*pnSize + 1)] = nullptr;
621 2 : CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
622 :
623 2 : (*pnSize)++;
624 :
625 2 : VRTRasterBand::GetFileList(ppapszFileList, pnSize, pnMaxSize, hSetFiles);
626 : }
627 :
628 : /*! @endcond */
|