/src/gdal/frmts/vrt/vrtrawrasterband.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | VRTRawRasterBand::VRTRawRasterBand(GDALDataset *poDSIn, int nBandIn, |
45 | | GDALDataType eType) |
46 | 0 | : m_poRawRaster(nullptr), m_pszSourceFilename(nullptr), |
47 | 0 | m_bRelativeToVRT(FALSE) |
48 | 0 | { |
49 | 0 | Initialize(poDSIn->GetRasterXSize(), poDSIn->GetRasterYSize()); |
50 | | |
51 | | // Declared in GDALRasterBand. |
52 | 0 | poDS = poDSIn; |
53 | 0 | nBand = nBandIn; |
54 | |
|
55 | 0 | if (eType != GDT_Unknown) |
56 | 0 | eDataType = eType; |
57 | 0 | } |
58 | | |
59 | | /************************************************************************/ |
60 | | /* ~VRTRawRasterBand() */ |
61 | | /************************************************************************/ |
62 | | |
63 | | VRTRawRasterBand::~VRTRawRasterBand() |
64 | | |
65 | 0 | { |
66 | 0 | FlushCache(true); |
67 | 0 | ClearRawLink(); |
68 | 0 | } |
69 | | |
70 | | /************************************************************************/ |
71 | | /* IRasterIO() */ |
72 | | /************************************************************************/ |
73 | | |
74 | | CPLErr VRTRawRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, |
75 | | int nXSize, int nYSize, void *pData, |
76 | | int nBufXSize, int nBufYSize, |
77 | | GDALDataType eBufType, GSpacing nPixelSpace, |
78 | | GSpacing nLineSpace, |
79 | | GDALRasterIOExtraArg *psExtraArg) |
80 | 0 | { |
81 | 0 | if (m_poRawRaster == nullptr) |
82 | 0 | { |
83 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
84 | 0 | "No raw raster band configured on VRTRawRasterBand."); |
85 | 0 | return CE_Failure; |
86 | 0 | } |
87 | | |
88 | 0 | if (eRWFlag == GF_Write && eAccess == GA_ReadOnly) |
89 | 0 | { |
90 | 0 | CPLError(CE_Failure, CPLE_NoWriteAccess, |
91 | 0 | "Attempt to write to read only dataset in" |
92 | 0 | "VRTRawRasterBand::IRasterIO()."); |
93 | |
|
94 | 0 | return CE_Failure; |
95 | 0 | } |
96 | | |
97 | | /* -------------------------------------------------------------------- */ |
98 | | /* Do we have overviews that would be appropriate to satisfy */ |
99 | | /* this request? */ |
100 | | /* -------------------------------------------------------------------- */ |
101 | 0 | if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0) |
102 | 0 | { |
103 | 0 | if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, |
104 | 0 | nBufXSize, nBufYSize, eBufType, nPixelSpace, |
105 | 0 | nLineSpace, psExtraArg) == CE_None) |
106 | 0 | return CE_None; |
107 | 0 | } |
108 | | |
109 | 0 | m_poRawRaster->SetAccess(eAccess); |
110 | |
|
111 | 0 | return m_poRawRaster->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, |
112 | 0 | nBufXSize, nBufYSize, eBufType, nPixelSpace, |
113 | 0 | nLineSpace, psExtraArg); |
114 | 0 | } |
115 | | |
116 | | /************************************************************************/ |
117 | | /* IReadBlock() */ |
118 | | /************************************************************************/ |
119 | | |
120 | | CPLErr VRTRawRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, |
121 | | void *pImage) |
122 | | |
123 | 0 | { |
124 | 0 | if (m_poRawRaster == nullptr) |
125 | 0 | { |
126 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
127 | 0 | "No raw raster band configured on VRTRawRasterBand."); |
128 | 0 | return CE_Failure; |
129 | 0 | } |
130 | | |
131 | 0 | return m_poRawRaster->ReadBlock(nBlockXOff, nBlockYOff, pImage); |
132 | 0 | } |
133 | | |
134 | | /************************************************************************/ |
135 | | /* IWriteBlock() */ |
136 | | /************************************************************************/ |
137 | | |
138 | | CPLErr VRTRawRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, |
139 | | void *pImage) |
140 | | |
141 | 0 | { |
142 | 0 | if (m_poRawRaster == nullptr) |
143 | 0 | { |
144 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
145 | 0 | "No raw raster band configured on VRTRawRasterBand."); |
146 | 0 | return CE_Failure; |
147 | 0 | } |
148 | | |
149 | 0 | m_poRawRaster->SetAccess(eAccess); |
150 | |
|
151 | 0 | return m_poRawRaster->WriteBlock(nBlockXOff, nBlockYOff, pImage); |
152 | 0 | } |
153 | | |
154 | | /************************************************************************/ |
155 | | /* SetRawLink() */ |
156 | | /************************************************************************/ |
157 | | |
158 | | CPLErr VRTRawRasterBand::SetRawLink(const char *pszFilename, |
159 | | const char *pszVRTPath, |
160 | | int bRelativeToVRTIn, |
161 | | vsi_l_offset nImageOffset, int nPixelOffset, |
162 | | int nLineOffset, const char *pszByteOrder) |
163 | | |
164 | 0 | { |
165 | 0 | ClearRawLink(); |
166 | |
|
167 | 0 | static_cast<VRTDataset *>(poDS)->SetNeedsFlush(); |
168 | | |
169 | | /* -------------------------------------------------------------------- */ |
170 | | /* Prepare filename. */ |
171 | | /* -------------------------------------------------------------------- */ |
172 | 0 | if (pszFilename == nullptr) |
173 | 0 | { |
174 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
175 | 0 | "Missing <SourceFilename> element in VRTRasterBand."); |
176 | 0 | return CE_Failure; |
177 | 0 | } |
178 | | |
179 | 0 | char *pszExpandedFilename = nullptr; |
180 | 0 | if (pszVRTPath != nullptr && bRelativeToVRTIn) |
181 | 0 | { |
182 | 0 | pszExpandedFilename = CPLStrdup( |
183 | 0 | CPLProjectRelativeFilenameSafe(pszVRTPath, pszFilename).c_str()); |
184 | 0 | } |
185 | 0 | else |
186 | 0 | { |
187 | 0 | pszExpandedFilename = CPLStrdup(pszFilename); |
188 | 0 | } |
189 | | |
190 | | /* -------------------------------------------------------------------- */ |
191 | | /* Try and open the file. We always use the large file API. */ |
192 | | /* -------------------------------------------------------------------- */ |
193 | 0 | CPLPushErrorHandler(CPLQuietErrorHandler); |
194 | 0 | FILE *fp = CPLOpenShared(pszExpandedFilename, "rb+", TRUE); |
195 | |
|
196 | 0 | if (fp == nullptr) |
197 | 0 | fp = CPLOpenShared(pszExpandedFilename, "rb", TRUE); |
198 | |
|
199 | 0 | if (fp == nullptr && |
200 | 0 | static_cast<VRTDataset *>(poDS)->GetAccess() == GA_Update) |
201 | 0 | { |
202 | 0 | fp = CPLOpenShared(pszExpandedFilename, "wb+", TRUE); |
203 | 0 | } |
204 | 0 | CPLPopErrorHandler(); |
205 | 0 | CPLErrorReset(); |
206 | |
|
207 | 0 | if (fp == nullptr) |
208 | 0 | { |
209 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, "Unable to open %s.%s", |
210 | 0 | pszExpandedFilename, VSIStrerror(errno)); |
211 | |
|
212 | 0 | CPLFree(pszExpandedFilename); |
213 | 0 | return CE_Failure; |
214 | 0 | } |
215 | | |
216 | 0 | CPLFree(pszExpandedFilename); |
217 | |
|
218 | 0 | if (!RAWDatasetCheckMemoryUsage( |
219 | 0 | nRasterXSize, nRasterYSize, 1, |
220 | 0 | GDALGetDataTypeSizeBytes(GetRasterDataType()), nPixelOffset, |
221 | 0 | nLineOffset, nImageOffset, 0, reinterpret_cast<VSILFILE *>(fp))) |
222 | 0 | { |
223 | 0 | CPLCloseShared(fp); |
224 | 0 | return CE_Failure; |
225 | 0 | } |
226 | | |
227 | 0 | m_pszSourceFilename = CPLStrdup(pszFilename); |
228 | 0 | m_bRelativeToVRT = bRelativeToVRTIn; |
229 | | |
230 | | /* -------------------------------------------------------------------- */ |
231 | | /* Work out if we are in native mode or not. */ |
232 | | /* -------------------------------------------------------------------- */ |
233 | 0 | RawRasterBand::ByteOrder eByteOrder = |
234 | 0 | #if CPL_IS_LSB |
235 | 0 | RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN; |
236 | | #else |
237 | | RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN; |
238 | | #endif |
239 | |
|
240 | 0 | if (pszByteOrder != nullptr) |
241 | 0 | { |
242 | 0 | if (EQUAL(pszByteOrder, "LSB")) |
243 | 0 | eByteOrder = RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN; |
244 | 0 | else if (EQUAL(pszByteOrder, "MSB")) |
245 | 0 | eByteOrder = RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN; |
246 | 0 | else if (EQUAL(pszByteOrder, "VAX")) |
247 | 0 | eByteOrder = RawRasterBand::ByteOrder::ORDER_VAX; |
248 | 0 | else |
249 | 0 | { |
250 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
251 | 0 | "Illegal ByteOrder value '%s', should be LSB, MSB or VAX.", |
252 | 0 | pszByteOrder); |
253 | 0 | CPLCloseShared(fp); |
254 | 0 | return CE_Failure; |
255 | 0 | } |
256 | 0 | } |
257 | | |
258 | | /* -------------------------------------------------------------------- */ |
259 | | /* Create a corresponding RawRasterBand. */ |
260 | | /* -------------------------------------------------------------------- */ |
261 | 0 | m_poRawRaster = |
262 | 0 | RawRasterBand::Create(reinterpret_cast<VSILFILE *>(fp), nImageOffset, |
263 | 0 | nPixelOffset, nLineOffset, GetRasterDataType(), |
264 | 0 | eByteOrder, GetXSize(), GetYSize(), |
265 | 0 | RawRasterBand::OwnFP::NO) |
266 | 0 | .release(); |
267 | 0 | if (!m_poRawRaster) |
268 | 0 | { |
269 | 0 | CPLCloseShared(fp); |
270 | 0 | return CE_Failure; |
271 | 0 | } |
272 | | |
273 | | /* -------------------------------------------------------------------- */ |
274 | | /* Reset block size to match the raw raster. */ |
275 | | /* -------------------------------------------------------------------- */ |
276 | 0 | m_poRawRaster->GetBlockSize(&nBlockXSize, &nBlockYSize); |
277 | |
|
278 | 0 | return CE_None; |
279 | 0 | } |
280 | | |
281 | | /************************************************************************/ |
282 | | /* ClearRawLink() */ |
283 | | /************************************************************************/ |
284 | | |
285 | | void VRTRawRasterBand::ClearRawLink() |
286 | | |
287 | 0 | { |
288 | 0 | if (m_poRawRaster != nullptr) |
289 | 0 | { |
290 | 0 | VSILFILE *fp = m_poRawRaster->GetFPL(); |
291 | 0 | delete m_poRawRaster; |
292 | 0 | m_poRawRaster = nullptr; |
293 | | // We close the file after deleting the raster band |
294 | | // since data can be flushed in the destructor. |
295 | 0 | if (fp != nullptr) |
296 | 0 | { |
297 | 0 | CPLCloseShared(reinterpret_cast<FILE *>(fp)); |
298 | 0 | } |
299 | 0 | } |
300 | 0 | CPLFree(m_pszSourceFilename); |
301 | 0 | m_pszSourceFilename = nullptr; |
302 | 0 | } |
303 | | |
304 | | /************************************************************************/ |
305 | | /* GetVirtualMemAuto() */ |
306 | | /************************************************************************/ |
307 | | |
308 | | CPLVirtualMem *VRTRawRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag, |
309 | | int *pnPixelSpace, |
310 | | GIntBig *pnLineSpace, |
311 | | char **papszOptions) |
312 | | |
313 | 0 | { |
314 | | // check the pointer to RawRasterBand |
315 | 0 | if (m_poRawRaster == nullptr) |
316 | 0 | { |
317 | | // use the super class method |
318 | 0 | return VRTRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, |
319 | 0 | pnLineSpace, papszOptions); |
320 | 0 | } |
321 | | // if available, use the RawRasterBand method (use mmap if available) |
322 | 0 | return m_poRawRaster->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace, |
323 | 0 | papszOptions); |
324 | 0 | } |
325 | | |
326 | | /************************************************************************/ |
327 | | /* XMLInit() */ |
328 | | /************************************************************************/ |
329 | | |
330 | | CPLErr VRTRawRasterBand::XMLInit(const CPLXMLNode *psTree, |
331 | | const char *pszVRTPath, |
332 | | VRTMapSharedResources &oMapSharedSources) |
333 | | |
334 | 0 | { |
335 | 0 | const CPLErr eErr = |
336 | 0 | VRTRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources); |
337 | 0 | if (eErr != CE_None) |
338 | 0 | return eErr; |
339 | | |
340 | | /* -------------------------------------------------------------------- */ |
341 | | /* Validate a bit. */ |
342 | | /* -------------------------------------------------------------------- */ |
343 | 0 | if (psTree == nullptr || psTree->eType != CXT_Element || |
344 | 0 | !EQUAL(psTree->pszValue, "VRTRasterBand") || |
345 | 0 | !EQUAL(CPLGetXMLValue(psTree, "subClass", ""), "VRTRawRasterBand")) |
346 | 0 | { |
347 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
348 | 0 | "Invalid node passed to VRTRawRasterBand::XMLInit()."); |
349 | 0 | return CE_Failure; |
350 | 0 | } |
351 | | |
352 | | /* -------------------------------------------------------------------- */ |
353 | | /* Prepare filename. */ |
354 | | /* -------------------------------------------------------------------- */ |
355 | 0 | const char *pszFilename = CPLGetXMLValue(psTree, "SourceFilename", nullptr); |
356 | |
|
357 | 0 | if (pszFilename == nullptr) |
358 | 0 | { |
359 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
360 | 0 | "Missing <SourceFilename> element in VRTRasterBand."); |
361 | 0 | return CE_Failure; |
362 | 0 | } |
363 | | |
364 | 0 | const bool l_bRelativeToVRT = CPLTestBool( |
365 | 0 | CPLGetXMLValue(psTree, "SourceFilename.relativeToVRT", "1")); |
366 | | |
367 | | /* -------------------------------------------------------------------- */ |
368 | | /* Collect layout information. */ |
369 | | /* -------------------------------------------------------------------- */ |
370 | 0 | int nWordDataSize = GDALGetDataTypeSizeBytes(GetRasterDataType()); |
371 | |
|
372 | 0 | const char *pszImageOffset = CPLGetXMLValue(psTree, "ImageOffset", "0"); |
373 | 0 | const vsi_l_offset nImageOffset = CPLScanUIntBig( |
374 | 0 | pszImageOffset, static_cast<int>(strlen(pszImageOffset))); |
375 | |
|
376 | 0 | int nPixelOffset = nWordDataSize; |
377 | 0 | const char *pszPixelOffset = CPLGetXMLValue(psTree, "PixelOffset", nullptr); |
378 | 0 | if (pszPixelOffset != nullptr) |
379 | 0 | { |
380 | 0 | nPixelOffset = atoi(pszPixelOffset); |
381 | 0 | } |
382 | 0 | if (nPixelOffset <= 0) |
383 | 0 | { |
384 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
385 | 0 | "Invalid value for <PixelOffset> element : %d", nPixelOffset); |
386 | 0 | return CE_Failure; |
387 | 0 | } |
388 | | |
389 | 0 | int nLineOffset = 0; |
390 | 0 | const char *pszLineOffset = CPLGetXMLValue(psTree, "LineOffset", nullptr); |
391 | 0 | if (pszLineOffset == nullptr) |
392 | 0 | { |
393 | 0 | if (nPixelOffset > INT_MAX / GetXSize()) |
394 | 0 | { |
395 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Int overflow"); |
396 | 0 | return CE_Failure; |
397 | 0 | } |
398 | 0 | nLineOffset = nPixelOffset * GetXSize(); |
399 | 0 | } |
400 | 0 | else |
401 | 0 | nLineOffset = atoi(pszLineOffset); |
402 | | |
403 | 0 | const char *pszByteOrder = CPLGetXMLValue(psTree, "ByteOrder", nullptr); |
404 | | |
405 | | /* -------------------------------------------------------------------- */ |
406 | | /* Open the file, and setup the raw layer access to the data. */ |
407 | | /* -------------------------------------------------------------------- */ |
408 | 0 | return SetRawLink(pszFilename, pszVRTPath, l_bRelativeToVRT, nImageOffset, |
409 | 0 | nPixelOffset, nLineOffset, pszByteOrder); |
410 | 0 | } |
411 | | |
412 | | /************************************************************************/ |
413 | | /* SerializeToXML() */ |
414 | | /************************************************************************/ |
415 | | |
416 | | CPLXMLNode *VRTRawRasterBand::SerializeToXML(const char *pszVRTPath, |
417 | | bool &bHasWarnedAboutRAMUsage, |
418 | | size_t &nAccRAMUsage) |
419 | | |
420 | 0 | { |
421 | | |
422 | | /* -------------------------------------------------------------------- */ |
423 | | /* We can't set the layout if there is no open rawband. */ |
424 | | /* -------------------------------------------------------------------- */ |
425 | 0 | if (m_poRawRaster == nullptr) |
426 | 0 | { |
427 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
428 | 0 | "VRTRawRasterBand::SerializeToXML() fails because " |
429 | 0 | "m_poRawRaster is NULL."); |
430 | 0 | return nullptr; |
431 | 0 | } |
432 | | |
433 | 0 | CPLXMLNode *psTree = VRTRasterBand::SerializeToXML( |
434 | 0 | pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage); |
435 | | |
436 | | /* -------------------------------------------------------------------- */ |
437 | | /* Set subclass. */ |
438 | | /* -------------------------------------------------------------------- */ |
439 | 0 | CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"), |
440 | 0 | CXT_Text, "VRTRawRasterBand"); |
441 | | |
442 | | /* -------------------------------------------------------------------- */ |
443 | | /* Setup the filename with relative flag. */ |
444 | | /* -------------------------------------------------------------------- */ |
445 | 0 | CPLXMLNode *psNode = CPLCreateXMLElementAndValue(psTree, "SourceFilename", |
446 | 0 | m_pszSourceFilename); |
447 | |
|
448 | 0 | CPLCreateXMLNode(CPLCreateXMLNode(psNode, CXT_Attribute, "relativeToVRT"), |
449 | 0 | CXT_Text, m_bRelativeToVRT ? "1" : "0"); |
450 | | |
451 | | /* -------------------------------------------------------------------- */ |
452 | | /* Set other layout information. */ |
453 | | /* -------------------------------------------------------------------- */ |
454 | |
|
455 | 0 | CPLCreateXMLElementAndValue( |
456 | 0 | psTree, "ImageOffset", |
457 | 0 | CPLSPrintf(CPL_FRMT_GUIB, m_poRawRaster->GetImgOffset())); |
458 | |
|
459 | 0 | CPLCreateXMLElementAndValue( |
460 | 0 | psTree, "PixelOffset", |
461 | 0 | CPLSPrintf("%d", m_poRawRaster->GetPixelOffset())); |
462 | |
|
463 | 0 | CPLCreateXMLElementAndValue( |
464 | 0 | psTree, "LineOffset", CPLSPrintf("%d", m_poRawRaster->GetLineOffset())); |
465 | |
|
466 | 0 | switch (m_poRawRaster->GetByteOrder()) |
467 | 0 | { |
468 | 0 | case RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN: |
469 | 0 | CPLCreateXMLElementAndValue(psTree, "ByteOrder", "LSB"); |
470 | 0 | break; |
471 | 0 | case RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN: |
472 | 0 | CPLCreateXMLElementAndValue(psTree, "ByteOrder", "MSB"); |
473 | 0 | break; |
474 | 0 | case RawRasterBand::ByteOrder::ORDER_VAX: |
475 | 0 | CPLCreateXMLElementAndValue(psTree, "ByteOrder", "VAX"); |
476 | 0 | break; |
477 | 0 | } |
478 | | |
479 | 0 | return psTree; |
480 | 0 | } |
481 | | |
482 | | /************************************************************************/ |
483 | | /* GetFileList() */ |
484 | | /************************************************************************/ |
485 | | |
486 | | void VRTRawRasterBand::GetFileList(char ***ppapszFileList, int *pnSize, |
487 | | int *pnMaxSize, CPLHashSet *hSetFiles) |
488 | 0 | { |
489 | 0 | if (m_pszSourceFilename == nullptr) |
490 | 0 | return; |
491 | | |
492 | | /* -------------------------------------------------------------------- */ |
493 | | /* Is it already in the list ? */ |
494 | | /* -------------------------------------------------------------------- */ |
495 | 0 | CPLString osSourceFilename; |
496 | 0 | if (m_bRelativeToVRT && strlen(poDS->GetDescription()) > 0) |
497 | 0 | osSourceFilename = CPLFormFilenameSafe( |
498 | 0 | CPLGetDirnameSafe(poDS->GetDescription()).c_str(), |
499 | 0 | m_pszSourceFilename, nullptr); |
500 | 0 | else |
501 | 0 | osSourceFilename = m_pszSourceFilename; |
502 | |
|
503 | 0 | if (CPLHashSetLookup(hSetFiles, osSourceFilename) != nullptr) |
504 | 0 | return; |
505 | | |
506 | | /* -------------------------------------------------------------------- */ |
507 | | /* Grow array if necessary */ |
508 | | /* -------------------------------------------------------------------- */ |
509 | 0 | if (*pnSize + 1 >= *pnMaxSize) |
510 | 0 | { |
511 | 0 | *pnMaxSize = 2 + 2 * (*pnMaxSize); |
512 | 0 | *ppapszFileList = static_cast<char **>( |
513 | 0 | CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize))); |
514 | 0 | } |
515 | | |
516 | | /* -------------------------------------------------------------------- */ |
517 | | /* Add the string to the list */ |
518 | | /* -------------------------------------------------------------------- */ |
519 | 0 | (*ppapszFileList)[*pnSize] = CPLStrdup(osSourceFilename); |
520 | 0 | (*ppapszFileList)[(*pnSize + 1)] = nullptr; |
521 | 0 | CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]); |
522 | |
|
523 | 0 | (*pnSize)++; |
524 | |
|
525 | 0 | VRTRasterBand::GetFileList(ppapszFileList, pnSize, pnMaxSize, hSetFiles); |
526 | 0 | } |
527 | | |
528 | | /*! @endcond */ |