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