Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Generic Raw Binary Driver
4 : * Purpose: Implementation of RawDataset and RawRasterBand classes.
5 : * Author: Frank Warmerdam, warmerda@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "cpl_vax.h"
16 : #include "rawdataset.h"
17 :
18 : #include <climits>
19 : #include <cmath>
20 : #include <cstddef>
21 : #include <cstdint>
22 : #include <cstdlib>
23 : #include <cstring>
24 : #if HAVE_FCNTL_H
25 : #include <fcntl.h>
26 : #endif
27 : #include <algorithm>
28 : #include <limits>
29 : #include <vector>
30 :
31 : #include "cpl_conv.h"
32 : #include "cpl_error.h"
33 : #include "cpl_progress.h"
34 : #include "cpl_string.h"
35 : #include "cpl_virtualmem.h"
36 : #include "cpl_vsi.h"
37 : #include "cpl_safemaths.hpp"
38 : #include "gdal.h"
39 : #include "gdal_priv.h"
40 :
41 : /************************************************************************/
42 : /* RawRasterBand() */
43 : /************************************************************************/
44 :
45 1099 : RawRasterBand::RawRasterBand(GDALDataset *poDSIn, int nBandIn,
46 : VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
47 : int nPixelOffsetIn, int nLineOffsetIn,
48 : GDALDataType eDataTypeIn, int bNativeOrderIn,
49 1099 : OwnFP bOwnsFPIn)
50 : : RawRasterBand(poDSIn, nBandIn, fpRawLIn, nImgOffsetIn, nPixelOffsetIn,
51 : nLineOffsetIn, eDataTypeIn,
52 : #ifdef CPL_LSB
53 1099 : bNativeOrderIn ? ByteOrder::ORDER_LITTLE_ENDIAN
54 : : ByteOrder::ORDER_BIG_ENDIAN,
55 : #else
56 : bNativeOrderIn ? ByteOrder::ORDER_BIG_ENDIAN
57 : : ByteOrder::ORDER_LITTLE_ENDIAN,
58 : #endif
59 1099 : bOwnsFPIn)
60 : {
61 1099 : }
62 :
63 : /************************************************************************/
64 : /* RawRasterBand() */
65 : /************************************************************************/
66 :
67 4517 : RawRasterBand::RawRasterBand(GDALDataset *poDSIn, int nBandIn,
68 : VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
69 : int nPixelOffsetIn, int nLineOffsetIn,
70 : GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
71 4517 : OwnFP bOwnsFPIn)
72 : : fpRawL(fpRawLIn), nImgOffset(nImgOffsetIn), nPixelOffset(nPixelOffsetIn),
73 : nLineOffset(nLineOffsetIn), eByteOrder(eByteOrderIn),
74 4517 : bOwnsFP(bOwnsFPIn == OwnFP::YES)
75 : {
76 4517 : poDS = poDSIn;
77 4517 : nBand = nBandIn;
78 4517 : eDataType = eDataTypeIn;
79 4517 : nRasterXSize = poDSIn->GetRasterXSize();
80 4517 : nRasterYSize = poDSIn->GetRasterYSize();
81 :
82 9034 : CPLDebug("GDALRaw",
83 : "RawRasterBand(%p,%d,%p,\n"
84 : " Off=%d,PixOff=%d,LineOff=%d,%s,%d)",
85 4517 : poDS, nBand, fpRawL, static_cast<unsigned int>(nImgOffset),
86 : nPixelOffset, nLineOffset, GDALGetDataTypeName(eDataType),
87 4517 : static_cast<int>(eByteOrder));
88 :
89 : // Treat one scanline as the block size.
90 4517 : nBlockXSize = poDS->GetRasterXSize();
91 4517 : nBlockYSize = 1;
92 :
93 : // Initialize other fields, and setup the line buffer.
94 4517 : Initialize();
95 4517 : }
96 :
97 : /************************************************************************/
98 : /* RawRasterBand::Create() */
99 : /************************************************************************/
100 :
101 : std::unique_ptr<RawRasterBand>
102 1518 : RawRasterBand::Create(GDALDataset *poDSIn, int nBandIn, VSILFILE *fpRawLIn,
103 : vsi_l_offset nImgOffsetIn, int nPixelOffsetIn,
104 : int nLineOffsetIn, GDALDataType eDataTypeIn,
105 : ByteOrder eByteOrderIn, OwnFP bOwnsFPIn)
106 : {
107 : auto poBand = std::make_unique<RawRasterBand>(
108 : poDSIn, nBandIn, fpRawLIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn,
109 3036 : eDataTypeIn, eByteOrderIn, bOwnsFPIn);
110 1518 : if (!poBand->IsValid())
111 0 : return nullptr;
112 1518 : return poBand;
113 : }
114 :
115 : /************************************************************************/
116 : /* RawRasterBand() */
117 : /************************************************************************/
118 :
119 9 : RawRasterBand::RawRasterBand(VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
120 : int nPixelOffsetIn, int nLineOffsetIn,
121 : GDALDataType eDataTypeIn, int bNativeOrderIn,
122 9 : int nXSize, int nYSize, OwnFP bOwnsFPIn)
123 : : RawRasterBand(fpRawLIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn,
124 : eDataTypeIn,
125 : #ifdef CPL_LSB
126 9 : bNativeOrderIn ? ByteOrder::ORDER_LITTLE_ENDIAN
127 : : ByteOrder::ORDER_BIG_ENDIAN,
128 : #else
129 : bNativeOrderIn ? ByteOrder::ORDER_BIG_ENDIAN
130 : : ByteOrder::ORDER_LITTLE_ENDIAN,
131 : #endif
132 9 : nXSize, nYSize, bOwnsFPIn)
133 : {
134 9 : }
135 :
136 : /************************************************************************/
137 : /* RawRasterBand::Create() */
138 : /************************************************************************/
139 :
140 : std::unique_ptr<RawRasterBand>
141 25 : RawRasterBand::Create(VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
142 : int nPixelOffsetIn, int nLineOffsetIn,
143 : GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
144 : int nXSizeIn, int nYSizeIn, OwnFP bOwnsFPIn)
145 : {
146 : auto poBand = std::make_unique<RawRasterBand>(
147 : fpRawIn, nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn, eDataTypeIn,
148 50 : eByteOrderIn, nXSizeIn, nYSizeIn, bOwnsFPIn);
149 25 : if (!poBand->IsValid())
150 0 : return nullptr;
151 25 : return poBand;
152 : }
153 :
154 : /************************************************************************/
155 : /* RawRasterBand() */
156 : /************************************************************************/
157 :
158 34 : RawRasterBand::RawRasterBand(VSILFILE *fpRawLIn, vsi_l_offset nImgOffsetIn,
159 : int nPixelOffsetIn, int nLineOffsetIn,
160 : GDALDataType eDataTypeIn, ByteOrder eByteOrderIn,
161 34 : int nXSize, int nYSize, OwnFP bOwnsFPIn)
162 : : fpRawL(fpRawLIn), nImgOffset(nImgOffsetIn), nPixelOffset(nPixelOffsetIn),
163 : nLineOffset(nLineOffsetIn), eByteOrder(eByteOrderIn),
164 34 : bOwnsFP(bOwnsFPIn == OwnFP::YES)
165 : {
166 34 : poDS = nullptr;
167 34 : nBand = 1;
168 34 : eDataType = eDataTypeIn;
169 :
170 68 : CPLDebug("GDALRaw",
171 : "RawRasterBand(floating,Off=%d,PixOff=%d,LineOff=%d,%s,%d)",
172 34 : static_cast<unsigned int>(nImgOffset), nPixelOffset, nLineOffset,
173 34 : GDALGetDataTypeName(eDataType), static_cast<int>(eByteOrder));
174 :
175 : // Treat one scanline as the block size.
176 34 : nBlockXSize = nXSize;
177 34 : nBlockYSize = 1;
178 34 : nRasterXSize = nXSize;
179 34 : nRasterYSize = nYSize;
180 34 : if (!GDALCheckDatasetDimensions(nXSize, nYSize))
181 : {
182 0 : return;
183 : }
184 :
185 : // Initialize other fields, and setup the line buffer.
186 34 : Initialize();
187 : }
188 :
189 : /************************************************************************/
190 : /* Initialize() */
191 : /************************************************************************/
192 :
193 4551 : void RawRasterBand::Initialize()
194 :
195 : {
196 4551 : vsi_l_offset nSmallestOffset = nImgOffset;
197 4551 : vsi_l_offset nLargestOffset = nImgOffset;
198 4551 : if (nLineOffset < 0)
199 : {
200 159 : const auto nDelta =
201 159 : static_cast<vsi_l_offset>(-static_cast<GIntBig>(nLineOffset)) *
202 159 : (nRasterYSize - 1);
203 159 : if (nDelta > nImgOffset)
204 : {
205 0 : CPLError(CE_Failure, CPLE_AppDefined,
206 : "Inconsistent nLineOffset, nRasterYSize and nImgOffset");
207 0 : return;
208 : }
209 159 : nSmallestOffset -= nDelta;
210 : }
211 : else
212 : {
213 8784 : if (nImgOffset >
214 4392 : std::numeric_limits<vsi_l_offset>::max() -
215 4392 : static_cast<vsi_l_offset>(nLineOffset) * (nRasterYSize - 1))
216 : {
217 0 : CPLError(CE_Failure, CPLE_AppDefined,
218 : "Inconsistent nLineOffset, nRasterYSize and nImgOffset");
219 0 : return;
220 : }
221 4392 : nLargestOffset +=
222 4392 : static_cast<vsi_l_offset>(nLineOffset) * (nRasterYSize - 1);
223 : }
224 4551 : if (nPixelOffset < 0)
225 : {
226 89 : if (static_cast<vsi_l_offset>(-static_cast<GIntBig>(nPixelOffset)) *
227 89 : (nRasterXSize - 1) >
228 : nSmallestOffset)
229 : {
230 0 : CPLError(CE_Failure, CPLE_AppDefined,
231 : "Inconsistent nPixelOffset, nRasterXSize and nImgOffset");
232 0 : return;
233 : }
234 : }
235 : else
236 : {
237 4462 : if (nLargestOffset >
238 4462 : std::numeric_limits<vsi_l_offset>::max() -
239 4462 : static_cast<vsi_l_offset>(nPixelOffset) * (nRasterXSize - 1))
240 : {
241 0 : CPLError(CE_Failure, CPLE_AppDefined,
242 : "Inconsistent nPixelOffset, nRasterXSize and nImgOffset");
243 0 : return;
244 : }
245 4462 : nLargestOffset +=
246 4462 : static_cast<vsi_l_offset>(nPixelOffset) * (nRasterXSize - 1);
247 : }
248 4551 : if (nLargestOffset > static_cast<vsi_l_offset>(GINTBIG_MAX))
249 : {
250 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too big largest offset");
251 0 : return;
252 : }
253 :
254 4551 : const int nDTSize = GDALGetDataTypeSizeBytes(GetRasterDataType());
255 :
256 : // Allocate working scanline.
257 4551 : const bool bIsBIP = IsBIP();
258 4551 : if (bIsBIP)
259 : {
260 1322 : if (nBand == 1)
261 : {
262 209 : nLineSize = nPixelOffset * nBlockXSize;
263 209 : pLineBuffer = VSIMalloc(nLineSize);
264 : }
265 : else
266 : {
267 : // Band > 1 : share the same buffer as band 1
268 1113 : pLineBuffer = nullptr;
269 : const auto poFirstBand =
270 1113 : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
271 1113 : if (poFirstBand->pLineBuffer != nullptr)
272 1113 : pLineStart = static_cast<char *>(poFirstBand->pLineBuffer) +
273 1113 : (nBand - 1) * nDTSize;
274 1113 : return;
275 : }
276 : }
277 9687 : else if (nBlockXSize <= 0 ||
278 3229 : (nBlockXSize > 1 &&
279 2733 : std::abs(nPixelOffset) >
280 9191 : std::numeric_limits<int>::max() / (nBlockXSize - 1)) ||
281 3229 : std::abs(nPixelOffset) * (nBlockXSize - 1) >
282 3229 : std::numeric_limits<int>::max() - nDTSize)
283 : {
284 0 : nLineSize = 0;
285 0 : pLineBuffer = nullptr;
286 : }
287 : else
288 : {
289 3229 : nLineSize = std::abs(nPixelOffset) * (nBlockXSize - 1) + nDTSize;
290 3229 : pLineBuffer = VSIMalloc(nLineSize);
291 : }
292 :
293 3438 : if (pLineBuffer == nullptr)
294 : {
295 0 : nLineSize = 0;
296 0 : CPLError(CE_Failure, CPLE_AppDefined,
297 : "Could not allocate line buffer: "
298 : "nPixelOffset=%d, nBlockXSize=%d",
299 : nPixelOffset, nBlockXSize);
300 0 : return;
301 : }
302 :
303 3438 : if (nPixelOffset >= 0)
304 3349 : pLineStart = pLineBuffer;
305 : else
306 89 : pLineStart = static_cast<char *>(pLineBuffer) +
307 89 : static_cast<std::ptrdiff_t>(std::abs(nPixelOffset)) *
308 89 : (nBlockXSize - 1);
309 : }
310 :
311 : /************************************************************************/
312 : /* ~RawRasterBand() */
313 : /************************************************************************/
314 :
315 6098 : RawRasterBand::~RawRasterBand()
316 :
317 : {
318 4551 : if (poCT)
319 4 : delete poCT;
320 :
321 4551 : CSLDestroy(papszCategoryNames);
322 :
323 4551 : RawRasterBand::FlushCache(true);
324 :
325 4551 : if (bOwnsFP)
326 : {
327 67 : if (VSIFCloseL(fpRawL) != 0)
328 : {
329 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
330 : }
331 : }
332 :
333 4551 : CPLFree(pLineBuffer);
334 6098 : }
335 :
336 : /************************************************************************/
337 : /* IsBIP() */
338 : /************************************************************************/
339 :
340 25252 : bool RawRasterBand::IsBIP() const
341 : {
342 25252 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
343 25252 : const bool bIsRawDataset = dynamic_cast<RawDataset *>(poDS) != nullptr;
344 25252 : if (bIsRawDataset && nPixelOffset > nDTSize &&
345 6931 : nLineOffset == static_cast<int64_t>(nPixelOffset) * nRasterXSize)
346 : {
347 6913 : if (nBand == 1)
348 : {
349 732 : return true;
350 : }
351 : const auto poFirstBand =
352 6181 : dynamic_cast<RawRasterBand *>(poDS->GetRasterBand(1));
353 6181 : if (poFirstBand && eDataType == poFirstBand->eDataType &&
354 6181 : eByteOrder == poFirstBand->eByteOrder &&
355 6181 : nPixelOffset == poFirstBand->nPixelOffset &&
356 6181 : nLineOffset == poFirstBand->nLineOffset &&
357 6181 : nImgOffset == poFirstBand->nImgOffset +
358 6181 : static_cast<vsi_l_offset>(nBand - 1) * nDTSize)
359 : {
360 6181 : return true;
361 : }
362 : }
363 18339 : return false;
364 : }
365 :
366 : /************************************************************************/
367 : /* SetAccess() */
368 : /************************************************************************/
369 :
370 256 : void RawRasterBand::SetAccess(GDALAccess eAccessIn)
371 : {
372 256 : eAccess = eAccessIn;
373 256 : }
374 :
375 : /************************************************************************/
376 : /* FlushCache() */
377 : /* */
378 : /* We override this so we have the opportunity to call */
379 : /* fflush(). We don't want to do this all the time in the */
380 : /* write block function as it is kind of expensive. */
381 : /************************************************************************/
382 :
383 9629 : CPLErr RawRasterBand::FlushCache(bool bAtClosing)
384 :
385 : {
386 9629 : CPLErr eErr = GDALRasterBand::FlushCache(bAtClosing);
387 9629 : if (eErr != CE_None)
388 : {
389 0 : bNeedFileFlush = false;
390 0 : return eErr;
391 : }
392 :
393 9629 : RawRasterBand *masterBand = this;
394 9629 : if (nBand > 1 && poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
395 : {
396 : // can't be null as IsBIP() checks that the first band is not null,
397 : // which could happen during dataset destruction.
398 1253 : masterBand = cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
399 : }
400 :
401 9629 : if (!masterBand->FlushCurrentLine(false))
402 : {
403 0 : masterBand->bNeedFileFlush = false;
404 0 : bNeedFileFlush = false;
405 0 : return CE_Failure;
406 : }
407 :
408 : // If we have unflushed raw, flush it to disk now.
409 9629 : if (masterBand->bNeedFileFlush)
410 : {
411 429 : int nRet = VSIFFlushL(fpRawL);
412 :
413 429 : masterBand->bNeedFileFlush = false;
414 429 : bNeedFileFlush = false;
415 429 : if (nRet < 0)
416 0 : return CE_Failure;
417 : }
418 :
419 9629 : bNeedFileFlush = false;
420 :
421 9629 : return CE_None;
422 : }
423 :
424 : /************************************************************************/
425 : /* NeedsByteOrderChange() */
426 : /************************************************************************/
427 :
428 77471 : bool RawRasterBand::NeedsByteOrderChange() const
429 : {
430 : #ifdef CPL_LSB
431 87867 : return eDataType != GDT_Byte &&
432 87867 : eByteOrder != RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
433 : #else
434 : return eDataType != GDT_Byte &&
435 : eByteOrder != RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
436 : #endif
437 : }
438 :
439 : /************************************************************************/
440 : /* DoByteSwap() */
441 : /************************************************************************/
442 :
443 6347 : void RawRasterBand::DoByteSwap(void *pBuffer, size_t nValues, int nByteSkip,
444 : bool bDiskToCPU) const
445 : {
446 6347 : if (eByteOrder != RawRasterBand::ByteOrder::ORDER_VAX)
447 : {
448 6317 : if (GDALDataTypeIsComplex(eDataType))
449 : {
450 0 : const int nWordSize = GDALGetDataTypeSize(eDataType) / 16;
451 0 : GDALSwapWordsEx(pBuffer, nWordSize, nValues, nByteSkip);
452 0 : GDALSwapWordsEx(static_cast<GByte *>(pBuffer) + nWordSize,
453 : nWordSize, nValues, nByteSkip);
454 : }
455 : else
456 : {
457 6317 : GDALSwapWordsEx(pBuffer, GDALGetDataTypeSizeBytes(eDataType),
458 : nValues, nByteSkip);
459 : }
460 : }
461 30 : else if (eDataType == GDT_Float16 || eDataType == GDT_CFloat16)
462 : {
463 : // No VAX support for GFloat16
464 0 : std::abort();
465 : }
466 30 : else if (eDataType == GDT_Float32 || eDataType == GDT_CFloat32)
467 : {
468 21 : GByte *pPtr = static_cast<GByte *>(pBuffer);
469 30 : for (int k = 0; k < 2; k++)
470 : {
471 30 : if (bDiskToCPU)
472 : {
473 183 : for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
474 : {
475 156 : CPLVaxToIEEEFloat(pPtr);
476 : }
477 : }
478 : else
479 : {
480 39 : for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
481 : {
482 36 : CPLIEEEToVaxFloat(pPtr);
483 : }
484 : }
485 30 : if (k == 0 && eDataType == GDT_CFloat32)
486 9 : pPtr = static_cast<GByte *>(pBuffer) + sizeof(float);
487 : else
488 : break;
489 21 : }
490 : }
491 9 : else if (eDataType == GDT_Float64 || eDataType == GDT_CFloat64)
492 : {
493 9 : GByte *pPtr = static_cast<GByte *>(pBuffer);
494 9 : for (int k = 0; k < 2; k++)
495 : {
496 9 : if (bDiskToCPU)
497 : {
498 56 : for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
499 : {
500 48 : CPLVaxToIEEEDouble(pPtr);
501 : }
502 : }
503 : else
504 : {
505 13 : for (size_t i = 0; i < nValues; i++, pPtr += nByteSkip)
506 : {
507 12 : CPLIEEEToVaxDouble(pPtr);
508 : }
509 : }
510 9 : if (k == 0 && eDataType == GDT_CFloat64)
511 0 : pPtr = static_cast<GByte *>(pBuffer) + sizeof(double);
512 : else
513 : break;
514 : }
515 : }
516 6347 : }
517 :
518 : /************************************************************************/
519 : /* ComputeFileOffset() */
520 : /************************************************************************/
521 :
522 46977 : vsi_l_offset RawRasterBand::ComputeFileOffset(int iLine) const
523 : {
524 : // Write formulas such that unsigned int overflow doesn't occur
525 46977 : vsi_l_offset nOffset = nImgOffset;
526 46977 : if (nLineOffset >= 0)
527 : {
528 45340 : nOffset += static_cast<GUIntBig>(nLineOffset) * iLine;
529 : }
530 : else
531 : {
532 1637 : nOffset -=
533 1637 : static_cast<GUIntBig>(-static_cast<GIntBig>(nLineOffset)) * iLine;
534 : }
535 46977 : if (nPixelOffset < 0)
536 : {
537 130 : const GUIntBig nPixelOffsetToSubtract =
538 130 : static_cast<GUIntBig>(-static_cast<GIntBig>(nPixelOffset)) *
539 130 : (nBlockXSize - 1);
540 130 : nOffset -= nPixelOffsetToSubtract;
541 : }
542 46977 : return nOffset;
543 : }
544 :
545 : /************************************************************************/
546 : /* AccessLine() */
547 : /************************************************************************/
548 :
549 29857 : CPLErr RawRasterBand::AccessLine(int iLine)
550 :
551 : {
552 29857 : if (pLineBuffer == nullptr)
553 : {
554 300 : if (nBand > 1 && pLineStart != nullptr)
555 : {
556 : // BIP interleaved
557 : auto poFirstBand =
558 300 : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
559 300 : CPLAssert(poFirstBand);
560 300 : return poFirstBand->AccessLine(iLine);
561 : }
562 0 : return CE_Failure;
563 : }
564 :
565 29557 : if (nLoadedScanline == iLine)
566 : {
567 0 : return CE_None;
568 : }
569 :
570 29557 : if (!FlushCurrentLine(false))
571 : {
572 0 : return CE_Failure;
573 : }
574 :
575 : // Figure out where to start reading.
576 29557 : const vsi_l_offset nReadStart = ComputeFileOffset(iLine);
577 :
578 : // Seek to the correct line.
579 29557 : if (Seek(nReadStart, SEEK_SET) == -1)
580 : {
581 0 : if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly)
582 : {
583 0 : CPLError(CE_Failure, CPLE_FileIO,
584 : "Failed to seek to scanline %d @ " CPL_FRMT_GUIB ".",
585 : iLine, nReadStart);
586 0 : return CE_Failure;
587 : }
588 : else
589 : {
590 0 : memset(pLineBuffer, 0, nLineSize);
591 0 : nLoadedScanline = iLine;
592 0 : return CE_None;
593 : }
594 : }
595 :
596 : // Read the line. Take care not to request any more bytes than
597 : // are needed, and not to lose a partially successful scanline read.
598 29557 : const size_t nBytesToRead = nLineSize;
599 29557 : const size_t nBytesActuallyRead = Read(pLineBuffer, 1, nBytesToRead);
600 29557 : if (nBytesActuallyRead < nBytesToRead)
601 : {
602 6244 : if (poDS != nullptr && poDS->GetAccess() == GA_ReadOnly &&
603 : // ENVI datasets might be sparse (see #915)
604 5 : poDS->GetMetadata("ENVI") == nullptr)
605 : {
606 5 : CPLError(CE_Failure, CPLE_FileIO, "Failed to read scanline %d.",
607 : iLine);
608 5 : return CE_Failure;
609 : }
610 : else
611 : {
612 6234 : memset(static_cast<GByte *>(pLineBuffer) + nBytesActuallyRead, 0,
613 : nBytesToRead - nBytesActuallyRead);
614 : }
615 : }
616 :
617 : // Byte swap the interesting data, if required.
618 29552 : if (NeedsByteOrderChange())
619 : {
620 2431 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
621 : {
622 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
623 0 : DoByteSwap(pLineBuffer,
624 0 : static_cast<size_t>(nBlockXSize) *
625 0 : poDS->GetRasterCount(),
626 : nDTSize, true);
627 : }
628 : else
629 2431 : DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), true);
630 : }
631 :
632 29552 : nLoadedScanline = iLine;
633 :
634 29552 : return CE_None;
635 : }
636 :
637 : /************************************************************************/
638 : /* IReadBlock() */
639 : /************************************************************************/
640 :
641 26467 : CPLErr RawRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
642 : void *pImage)
643 : {
644 26467 : CPLAssert(nBlockXOff == 0);
645 :
646 26467 : const CPLErr eErr = AccessLine(nBlockYOff);
647 26467 : if (eErr == CE_Failure)
648 5 : return eErr;
649 :
650 : // Copy data from disk buffer to user block buffer.
651 26462 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
652 26462 : GDALCopyWords64(pLineStart, eDataType, nPixelOffset, pImage, eDataType,
653 26462 : nDTSize, nBlockXSize);
654 :
655 : // Pre-cache block cache of other bands
656 26462 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
657 : {
658 4262 : for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
659 : {
660 3439 : if (iBand != nBand)
661 : {
662 : auto poOtherBand =
663 2616 : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(iBand));
664 : GDALRasterBlock *poBlock =
665 2616 : poOtherBand->TryGetLockedBlockRef(0, nBlockYOff);
666 2616 : if (poBlock != nullptr)
667 : {
668 0 : poBlock->DropLock();
669 0 : continue;
670 : }
671 2616 : poBlock = poOtherBand->GetLockedBlockRef(0, nBlockYOff, true);
672 2616 : if (poBlock != nullptr)
673 : {
674 2616 : GDALCopyWords64(poOtherBand->pLineStart, eDataType,
675 : nPixelOffset, poBlock->GetDataRef(),
676 2616 : eDataType, nDTSize, nBlockXSize);
677 2616 : poBlock->DropLock();
678 : }
679 : }
680 : }
681 : }
682 :
683 26462 : return eErr;
684 : }
685 :
686 : /************************************************************************/
687 : /* BIPWriteBlock() */
688 : /************************************************************************/
689 :
690 2014 : CPLErr RawRasterBand::BIPWriteBlock(int nBlockYOff, int nCallingBand,
691 : const void *pImage)
692 : {
693 2014 : if (nLoadedScanline != nBlockYOff)
694 : {
695 2014 : if (!FlushCurrentLine(false))
696 0 : return CE_Failure;
697 : }
698 :
699 2014 : const int nBands = poDS->GetRasterCount();
700 4028 : std::vector<GDALRasterBlock *> apoBlocks(nBands);
701 2014 : bool bAllBlocksDirty = true;
702 2014 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
703 :
704 : /* -------------------------------------------------------------------- */
705 : /* If all blocks are cached and dirty then we do not need to reload */
706 : /* the scanline from disk */
707 : /* -------------------------------------------------------------------- */
708 104086 : for (int iBand = 0; iBand < nBands; ++iBand)
709 : {
710 102072 : if (iBand + 1 != nCallingBand)
711 : {
712 200116 : apoBlocks[iBand] =
713 100058 : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(iBand + 1))
714 100058 : ->TryGetLockedBlockRef(0, nBlockYOff);
715 :
716 100058 : if (apoBlocks[iBand] == nullptr)
717 : {
718 99034 : bAllBlocksDirty = false;
719 : }
720 1024 : else if (!apoBlocks[iBand]->GetDirty())
721 : {
722 0 : apoBlocks[iBand]->DropLock();
723 0 : apoBlocks[iBand] = nullptr;
724 0 : bAllBlocksDirty = false;
725 : }
726 : }
727 : else
728 2014 : apoBlocks[iBand] = nullptr;
729 : }
730 :
731 2014 : if (!bAllBlocksDirty)
732 : {
733 : // We only to read the scanline if we don't have data for all bands.
734 2014 : if (AccessLine(nBlockYOff) != CE_None)
735 : {
736 0 : for (int iBand = 0; iBand < nBands; ++iBand)
737 : {
738 0 : if (apoBlocks[iBand] != nullptr)
739 0 : apoBlocks[iBand]->DropLock();
740 : }
741 0 : return CE_Failure;
742 : }
743 : }
744 :
745 104086 : for (int iBand = 0; iBand < nBands; ++iBand)
746 : {
747 102072 : const GByte *pabyThisImage = nullptr;
748 102072 : GDALRasterBlock *poBlock = nullptr;
749 :
750 102072 : if (iBand + 1 == nCallingBand)
751 : {
752 2014 : pabyThisImage = static_cast<const GByte *>(pImage);
753 : }
754 : else
755 : {
756 100058 : poBlock = apoBlocks[iBand];
757 100058 : if (poBlock == nullptr)
758 99034 : continue;
759 :
760 1024 : if (!poBlock->GetDirty())
761 : {
762 0 : poBlock->DropLock();
763 0 : continue;
764 : }
765 :
766 1024 : pabyThisImage = static_cast<const GByte *>(poBlock->GetDataRef());
767 : }
768 :
769 3038 : GByte *pabyOut = static_cast<GByte *>(pLineStart) + iBand * nDTSize;
770 :
771 3038 : GDALCopyWords64(pabyThisImage, eDataType, nDTSize, pabyOut, eDataType,
772 3038 : nPixelOffset, nBlockXSize);
773 :
774 3038 : if (poBlock != nullptr)
775 : {
776 1024 : poBlock->MarkClean();
777 1024 : poBlock->DropLock();
778 : }
779 : }
780 :
781 2014 : nLoadedScanline = nBlockYOff;
782 2014 : bLoadedScanlineDirty = true;
783 :
784 2014 : if (bAllBlocksDirty)
785 : {
786 0 : return FlushCurrentLine(true) ? CE_None : CE_Failure;
787 : }
788 :
789 2014 : bNeedFileFlush = true;
790 2014 : return CE_None;
791 : }
792 :
793 : /************************************************************************/
794 : /* IWriteBlock() */
795 : /************************************************************************/
796 :
797 17420 : CPLErr RawRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
798 : void *pImage)
799 : {
800 17420 : CPLAssert(nBlockXOff == 0);
801 :
802 17420 : if (pLineBuffer == nullptr)
803 : {
804 2014 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
805 : {
806 : auto poFirstBand =
807 2014 : (nBand == 1)
808 2014 : ? this
809 2014 : : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
810 2014 : CPLAssert(poFirstBand);
811 2014 : return poFirstBand->BIPWriteBlock(nBlockYOff, nBand, pImage);
812 : }
813 :
814 0 : return CE_Failure;
815 : }
816 :
817 15406 : if (nLoadedScanline != nBlockYOff)
818 : {
819 15403 : if (!FlushCurrentLine(false))
820 0 : return CE_Failure;
821 : }
822 :
823 : // If the data for this band is completely contiguous, we don't
824 : // have to worry about pre-reading from disk.
825 15406 : CPLErr eErr = CE_None;
826 15406 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
827 15406 : if (std::abs(nPixelOffset) > nDTSize)
828 1076 : eErr = AccessLine(nBlockYOff);
829 :
830 : // Copy data from user buffer into disk buffer.
831 15406 : GDALCopyWords64(pImage, eDataType, nDTSize, pLineStart, eDataType,
832 15406 : nPixelOffset, nBlockXSize);
833 :
834 15406 : nLoadedScanline = nBlockYOff;
835 15406 : bLoadedScanlineDirty = true;
836 :
837 15406 : return eErr == CE_None && FlushCurrentLine(true) ? CE_None : CE_Failure;
838 : }
839 :
840 : /************************************************************************/
841 : /* FlushCurrentLine() */
842 : /************************************************************************/
843 :
844 72009 : bool RawRasterBand::FlushCurrentLine(bool bNeedUsableBufferAfter)
845 : {
846 72009 : if (!bLoadedScanlineDirty)
847 54589 : return true;
848 :
849 17420 : bLoadedScanlineDirty = false;
850 :
851 17420 : bool ok = true;
852 :
853 : // Byte swap (if necessary) back into disk order before writing.
854 17420 : if (NeedsByteOrderChange())
855 : {
856 1522 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
857 : {
858 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
859 0 : DoByteSwap(pLineBuffer,
860 0 : static_cast<size_t>(nBlockXSize) *
861 0 : poDS->GetRasterCount(),
862 : nDTSize, false);
863 : }
864 : else
865 1522 : DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), false);
866 : }
867 :
868 : // Figure out where to start reading.
869 17420 : const vsi_l_offset nWriteStart = ComputeFileOffset(nLoadedScanline);
870 :
871 : // Seek to correct location.
872 17420 : if (Seek(nWriteStart, SEEK_SET) == -1)
873 : {
874 0 : CPLError(CE_Failure, CPLE_FileIO,
875 : "Failed to seek to scanline %d @ " CPL_FRMT_GUIB
876 : " to write to file.",
877 : nLoadedScanline, nWriteStart);
878 :
879 0 : ok = false;
880 : }
881 :
882 : // Write data buffer.
883 17420 : const int nBytesToWrite = nLineSize;
884 34840 : if (ok && Write(pLineBuffer, 1, nBytesToWrite) <
885 17420 : static_cast<size_t>(nBytesToWrite))
886 : {
887 0 : CPLError(CE_Failure, CPLE_FileIO,
888 : "Failed to write scanline %d to file.", nLoadedScanline);
889 :
890 0 : ok = false;
891 : }
892 :
893 : // Byte swap (if necessary) back into machine order so the
894 : // buffer is still usable for reading purposes, unless this is not needed.
895 17420 : if (bNeedUsableBufferAfter && NeedsByteOrderChange())
896 : {
897 1522 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
898 : {
899 0 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
900 0 : DoByteSwap(pLineBuffer,
901 0 : static_cast<size_t>(nBlockXSize) *
902 0 : poDS->GetRasterCount(),
903 : nDTSize, true);
904 : }
905 : else
906 1522 : DoByteSwap(pLineBuffer, nBlockXSize, std::abs(nPixelOffset), true);
907 : }
908 :
909 17420 : bNeedFileFlush = true;
910 :
911 17420 : return ok;
912 : }
913 :
914 : /************************************************************************/
915 : /* AccessBlock() */
916 : /************************************************************************/
917 :
918 8585 : CPLErr RawRasterBand::AccessBlock(vsi_l_offset nBlockOff, size_t nBlockSize,
919 : void *pData, size_t nValues)
920 : {
921 : // Seek to the correct block.
922 8585 : if (Seek(nBlockOff, SEEK_SET) == -1)
923 : {
924 0 : memset(pData, 0, nBlockSize);
925 0 : return CE_None;
926 : }
927 :
928 : // Read the block.
929 8585 : const size_t nBytesActuallyRead = Read(pData, 1, nBlockSize);
930 8585 : if (nBytesActuallyRead < nBlockSize)
931 : {
932 :
933 512 : memset(static_cast<GByte *>(pData) + nBytesActuallyRead, 0,
934 : nBlockSize - nBytesActuallyRead);
935 : }
936 :
937 : // Byte swap the interesting data, if required.
938 8585 : if (NeedsByteOrderChange())
939 : {
940 792 : DoByteSwap(pData, nValues, std::abs(nPixelOffset), true);
941 : }
942 :
943 8585 : return CE_None;
944 : }
945 :
946 : /************************************************************************/
947 : /* IsSignificantNumberOfLinesLoaded() */
948 : /* */
949 : /* Check if there is a significant number of scanlines (>20%) from the */
950 : /* specified block of lines already cached. */
951 : /************************************************************************/
952 :
953 0 : int RawRasterBand::IsSignificantNumberOfLinesLoaded(int nLineOff, int nLines)
954 : {
955 0 : int nCountLoaded = 0;
956 :
957 0 : for (int iLine = nLineOff; iLine < nLineOff + nLines; iLine++)
958 : {
959 0 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(0, iLine);
960 0 : if (poBlock != nullptr)
961 : {
962 0 : poBlock->DropLock();
963 0 : nCountLoaded++;
964 0 : if (nCountLoaded > nLines / 20)
965 : {
966 0 : return TRUE;
967 : }
968 : }
969 : }
970 :
971 0 : return FALSE;
972 : }
973 :
974 : /************************************************************************/
975 : /* CanUseDirectIO() */
976 : /************************************************************************/
977 :
978 13228 : int RawRasterBand::CanUseDirectIO(int /* nXOff */, int nYOff, int nXSize,
979 : int nYSize, GDALDataType /* eBufType*/,
980 : GDALRasterIOExtraArg *psExtraArg)
981 : {
982 13228 : bool result = FALSE;
983 :
984 : // Use direct IO without caching if:
985 : //
986 : // GDAL_ONE_BIG_READ is enabled
987 : //
988 : // or
989 : //
990 : // the raster width is so small that the cost of a GDALRasterBlock is
991 : // significant
992 : //
993 : // or
994 : //
995 : // the length of a scanline on disk is more than 50000 bytes, and the
996 : // width of the requested chunk is less than 40% of the whole scanline and
997 : // no significant number of requested scanlines are already in the cache.
998 :
999 13228 : if (nPixelOffset < 0 || psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
1000 : {
1001 53 : return FALSE;
1002 : }
1003 :
1004 13175 : RawDataset *rawDataset = dynamic_cast<RawDataset *>(this->GetDataset());
1005 13175 : int oldCachedCPLOneBigReadOption = 0;
1006 13175 : if (rawDataset != nullptr)
1007 : {
1008 12678 : oldCachedCPLOneBigReadOption = rawDataset->cachedCPLOneBigReadOption;
1009 : }
1010 :
1011 : const char *pszGDAL_ONE_BIG_READ =
1012 13175 : !(oldCachedCPLOneBigReadOption & 0xff) // Test valid
1013 24861 : ? CPLGetConfigOption("GDAL_ONE_BIG_READ", nullptr)
1014 23372 : : (((oldCachedCPLOneBigReadOption >> 8) & 0xff) == 0) ? "0"
1015 11686 : : (((oldCachedCPLOneBigReadOption >> 8) & 0xff) == 1) ? "1"
1016 13175 : : nullptr;
1017 13175 : if (pszGDAL_ONE_BIG_READ == nullptr)
1018 : {
1019 13109 : const int newCachedCPLOneBigReadOption = (0xff << 8) | 1;
1020 13109 : if (rawDataset != nullptr)
1021 : {
1022 12612 : rawDataset->cachedCPLOneBigReadOption.compare_exchange_strong(
1023 : oldCachedCPLOneBigReadOption, newCachedCPLOneBigReadOption);
1024 : }
1025 :
1026 13109 : if (nRasterXSize <= 64)
1027 : {
1028 6740 : return TRUE;
1029 : }
1030 :
1031 6369 : if (nLineSize < 50000 || nXSize > nLineSize / nPixelOffset / 5 * 2 ||
1032 0 : IsSignificantNumberOfLinesLoaded(nYOff, nYSize))
1033 : {
1034 6369 : return FALSE;
1035 : }
1036 0 : return TRUE;
1037 : }
1038 :
1039 66 : result = CPLTestBool(pszGDAL_ONE_BIG_READ);
1040 :
1041 66 : const int newCachedCPLOneBigReadOption = (result ? 1 : 0) << 8 | 1;
1042 66 : if (rawDataset != nullptr)
1043 : {
1044 66 : rawDataset->cachedCPLOneBigReadOption.compare_exchange_strong(
1045 : oldCachedCPLOneBigReadOption, newCachedCPLOneBigReadOption);
1046 : }
1047 :
1048 66 : return result;
1049 : }
1050 :
1051 : /************************************************************************/
1052 : /* IRasterIO() */
1053 : /************************************************************************/
1054 :
1055 13157 : CPLErr RawRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1056 : int nXSize, int nYSize, void *pData,
1057 : int nBufXSize, int nBufYSize,
1058 : GDALDataType eBufType, GSpacing nPixelSpace,
1059 : GSpacing nLineSpace,
1060 : GDALRasterIOExtraArg *psExtraArg)
1061 :
1062 : {
1063 13157 : const int nBandDataSize = GDALGetDataTypeSizeBytes(eDataType);
1064 : #ifdef DEBUG
1065 : // Otherwise Coverity thinks that a divide by zero is possible in
1066 : // AccessBlock() in the complex data type wapping case.
1067 13157 : if (nBandDataSize == 0)
1068 0 : return CE_Failure;
1069 : #endif
1070 13157 : const int nBufDataSize = GDALGetDataTypeSizeBytes(eBufType);
1071 :
1072 13157 : if (!CanUseDirectIO(nXOff, nYOff, nXSize, nYSize, eBufType, psExtraArg))
1073 : {
1074 6422 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1075 : pData, nBufXSize, nBufYSize, eBufType,
1076 6422 : nPixelSpace, nLineSpace, psExtraArg);
1077 : }
1078 :
1079 6735 : CPLDebug("RAW", "Using direct IO implementation");
1080 :
1081 6735 : if (pLineBuffer == nullptr)
1082 : {
1083 1501 : if (poDS != nullptr && poDS->GetRasterCount() > 1 && IsBIP())
1084 : {
1085 : auto poFirstBand =
1086 1501 : (nBand == 1)
1087 1501 : ? this
1088 1501 : : cpl::down_cast<RawRasterBand *>(poDS->GetRasterBand(1));
1089 1501 : CPLAssert(poFirstBand);
1090 1501 : if (poFirstBand->bNeedFileFlush)
1091 21 : RawRasterBand::FlushCache(false);
1092 : }
1093 : }
1094 6735 : if (bNeedFileFlush)
1095 130 : RawRasterBand::FlushCache(false);
1096 :
1097 : // Needed for ICC fast math approximations
1098 6735 : constexpr double EPS = 1e-10;
1099 :
1100 : // Read data.
1101 6735 : if (eRWFlag == GF_Read)
1102 : {
1103 : // Do we have overviews that are appropriate to satisfy this request?
1104 5823 : if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
1105 2 : GetOverviewCount() > 0)
1106 : {
1107 0 : if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1108 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
1109 0 : nLineSpace, psExtraArg) == CE_None)
1110 0 : return CE_None;
1111 : }
1112 :
1113 : // 1. Simplest case when we should get contiguous block
1114 : // of uninterleaved pixels.
1115 11636 : if (nXSize == GetXSize() && nXSize == nBufXSize &&
1116 5813 : nYSize == nBufYSize && eBufType == eDataType &&
1117 593 : nPixelOffset == nBandDataSize && nPixelSpace == nBufDataSize &&
1118 12201 : nLineSpace == nPixelSpace * nXSize &&
1119 565 : nLineOffset == nPixelOffset * nXSize)
1120 : {
1121 533 : vsi_l_offset nOffset = nImgOffset;
1122 533 : if (nLineOffset >= 0)
1123 533 : nOffset += nYOff * static_cast<vsi_l_offset>(nLineOffset);
1124 : else
1125 0 : nOffset -= nYOff * static_cast<vsi_l_offset>(-nLineOffset);
1126 :
1127 533 : const size_t nValues = static_cast<size_t>(nXSize) * nYSize;
1128 533 : const size_t nBytesToRead = nValues * nBandDataSize;
1129 533 : AccessBlock(nOffset, nBytesToRead, pData, nValues);
1130 : }
1131 : // 2. Case when we need deinterleave and/or subsample data.
1132 : else
1133 : {
1134 5288 : const double dfSrcXInc = static_cast<double>(nXSize) / nBufXSize;
1135 5288 : const double dfSrcYInc = static_cast<double>(nYSize) / nBufYSize;
1136 :
1137 : const size_t nBytesToRW =
1138 5288 : static_cast<size_t>(nPixelOffset) * (nXSize - 1) +
1139 5288 : GDALGetDataTypeSizeBytes(eDataType);
1140 : GByte *pabyData =
1141 5288 : static_cast<GByte *>(VSI_MALLOC_VERBOSE(nBytesToRW));
1142 5288 : if (pabyData == nullptr)
1143 0 : return CE_Failure;
1144 :
1145 11827 : for (int iLine = 0; iLine < nBufYSize; iLine++)
1146 : {
1147 6539 : const vsi_l_offset nLine =
1148 6539 : static_cast<vsi_l_offset>(nYOff) +
1149 6539 : static_cast<vsi_l_offset>(iLine * dfSrcYInc + EPS);
1150 6539 : vsi_l_offset nOffset = nImgOffset;
1151 6539 : if (nLineOffset >= 0)
1152 6380 : nOffset += nLine * nLineOffset;
1153 : else
1154 159 : nOffset -= nLine * static_cast<vsi_l_offset>(-nLineOffset);
1155 6539 : if (nPixelOffset >= 0)
1156 6539 : nOffset += nXOff * static_cast<vsi_l_offset>(nPixelOffset);
1157 : else
1158 0 : nOffset -= nXOff * static_cast<vsi_l_offset>(-nPixelOffset);
1159 6539 : AccessBlock(nOffset, nBytesToRW, pabyData, nXSize);
1160 : // Copy data from disk buffer to user block buffer and
1161 : // subsample, if needed.
1162 6539 : if (nXSize == nBufXSize && nYSize == nBufYSize)
1163 : {
1164 6519 : GDALCopyWords64(
1165 : pabyData, eDataType, nPixelOffset,
1166 6519 : static_cast<GByte *>(pData) + iLine * nLineSpace,
1167 : eBufType, static_cast<int>(nPixelSpace), nXSize);
1168 : }
1169 : else
1170 : {
1171 220 : for (int iPixel = 0; iPixel < nBufXSize; iPixel++)
1172 : {
1173 200 : GDALCopyWords64(
1174 200 : pabyData + static_cast<vsi_l_offset>(
1175 200 : iPixel * dfSrcXInc + EPS) *
1176 200 : nPixelOffset,
1177 : eDataType, nPixelOffset,
1178 200 : static_cast<GByte *>(pData) + iLine * nLineSpace +
1179 200 : iPixel * nPixelSpace,
1180 : eBufType, static_cast<int>(nPixelSpace), 1);
1181 : }
1182 : }
1183 :
1184 7007 : if (psExtraArg->pfnProgress != nullptr &&
1185 468 : !psExtraArg->pfnProgress(1.0 * (iLine + 1) / nBufYSize, "",
1186 : psExtraArg->pProgressData))
1187 : {
1188 0 : CPLFree(pabyData);
1189 0 : return CE_Failure;
1190 : }
1191 : }
1192 :
1193 5288 : CPLFree(pabyData);
1194 : }
1195 : }
1196 : // Write data.
1197 : else
1198 : {
1199 : // 1. Simplest case when we should write contiguous block of
1200 : // uninterleaved pixels.
1201 1828 : if (nXSize == GetXSize() && nXSize == nBufXSize &&
1202 912 : nYSize == nBufYSize && eBufType == eDataType &&
1203 911 : nPixelOffset == nBandDataSize && nPixelSpace == nBufDataSize &&
1204 2543 : nLineSpace == nPixelSpace * nXSize &&
1205 715 : nLineOffset == nPixelOffset * nXSize)
1206 : {
1207 627 : const size_t nValues = static_cast<size_t>(nXSize) * nYSize;
1208 :
1209 : // Byte swap the data buffer, if required.
1210 627 : if (NeedsByteOrderChange())
1211 : {
1212 13 : DoByteSwap(pData, nValues, std::abs(nPixelOffset), false);
1213 : }
1214 :
1215 : // Seek to the correct block.
1216 627 : vsi_l_offset nOffset = nImgOffset;
1217 627 : if (nLineOffset >= 0)
1218 627 : nOffset += nYOff * static_cast<vsi_l_offset>(nLineOffset);
1219 : else
1220 0 : nOffset -= nYOff * static_cast<vsi_l_offset>(-nLineOffset);
1221 :
1222 627 : if (Seek(nOffset, SEEK_SET) == -1)
1223 : {
1224 0 : CPLError(CE_Failure, CPLE_FileIO,
1225 : "Failed to seek to " CPL_FRMT_GUIB " to write data.",
1226 : nOffset);
1227 :
1228 0 : return CE_Failure;
1229 : }
1230 :
1231 : // Write the block.
1232 627 : const size_t nBytesToRW = nValues * nBandDataSize;
1233 :
1234 627 : const size_t nBytesActuallyWritten = Write(pData, 1, nBytesToRW);
1235 627 : if (nBytesActuallyWritten < nBytesToRW)
1236 : {
1237 23 : CPLError(CE_Failure, CPLE_FileIO,
1238 : "Failed to write " CPL_FRMT_GUIB
1239 : " bytes to file. " CPL_FRMT_GUIB " bytes written",
1240 : static_cast<GUIntBig>(nBytesToRW),
1241 : static_cast<GUIntBig>(nBytesActuallyWritten));
1242 :
1243 23 : return CE_Failure;
1244 : }
1245 :
1246 : // Byte swap (if necessary) back into machine order so the
1247 : // buffer is still usable for reading purposes.
1248 604 : if (NeedsByteOrderChange())
1249 : {
1250 13 : DoByteSwap(pData, nValues, std::abs(nPixelOffset), true);
1251 : }
1252 : }
1253 : // 2. Case when we need deinterleave and/or subsample data.
1254 : else
1255 : {
1256 287 : const double dfSrcXInc = static_cast<double>(nXSize) / nBufXSize;
1257 287 : const double dfSrcYInc = static_cast<double>(nYSize) / nBufYSize;
1258 :
1259 : const size_t nBytesToRW =
1260 287 : static_cast<size_t>(nPixelOffset) * (nXSize - 1) +
1261 287 : GDALGetDataTypeSizeBytes(eDataType);
1262 : GByte *pabyData =
1263 287 : static_cast<GByte *>(VSI_MALLOC_VERBOSE(nBytesToRW));
1264 287 : if (pabyData == nullptr)
1265 0 : return CE_Failure;
1266 :
1267 2916 : for (int iLine = 0; iLine < nBufYSize; iLine++)
1268 : {
1269 2638 : const vsi_l_offset nLine =
1270 2638 : static_cast<vsi_l_offset>(nYOff) +
1271 2638 : static_cast<vsi_l_offset>(iLine * dfSrcYInc + EPS);
1272 2638 : vsi_l_offset nOffset = nImgOffset;
1273 2638 : if (nLineOffset >= 0)
1274 2619 : nOffset += nLine * static_cast<vsi_l_offset>(nLineOffset);
1275 : else
1276 19 : nOffset -= nLine * static_cast<vsi_l_offset>(-nLineOffset);
1277 2638 : if (nPixelOffset >= 0)
1278 2638 : nOffset += nXOff * static_cast<vsi_l_offset>(nPixelOffset);
1279 : else
1280 0 : nOffset -= nXOff * static_cast<vsi_l_offset>(-nPixelOffset);
1281 :
1282 : // If the data for this band is completely contiguous we don't
1283 : // have to worry about pre-reading from disk.
1284 2638 : if (nPixelOffset > nBandDataSize)
1285 1513 : AccessBlock(nOffset, nBytesToRW, pabyData, nXSize);
1286 :
1287 : // Copy data from user block buffer to disk buffer and
1288 : // subsample, if needed.
1289 2638 : if (nXSize == nBufXSize && nYSize == nBufYSize)
1290 : {
1291 2598 : GDALCopyWords64(static_cast<GByte *>(pData) +
1292 2598 : iLine * nLineSpace,
1293 : eBufType, static_cast<int>(nPixelSpace),
1294 : pabyData, eDataType, nPixelOffset, nXSize);
1295 : }
1296 : else
1297 : {
1298 840 : for (int iPixel = 0; iPixel < nBufXSize; iPixel++)
1299 : {
1300 800 : GDALCopyWords64(
1301 800 : static_cast<GByte *>(pData) + iLine * nLineSpace +
1302 800 : iPixel * nPixelSpace,
1303 : eBufType, static_cast<int>(nPixelSpace),
1304 800 : pabyData + static_cast<vsi_l_offset>(
1305 800 : iPixel * dfSrcXInc + EPS) *
1306 800 : nPixelOffset,
1307 : eDataType, nPixelOffset, 1);
1308 : }
1309 : }
1310 :
1311 : // Byte swap the data buffer, if required.
1312 2638 : if (NeedsByteOrderChange())
1313 : {
1314 204 : if (GDALDataTypeIsComplex(eDataType))
1315 : {
1316 : const int nWordSize =
1317 0 : GDALGetDataTypeSize(eDataType) / 16;
1318 0 : GDALSwapWords(pabyData, nWordSize, nXSize,
1319 : nPixelOffset);
1320 0 : GDALSwapWords(static_cast<GByte *>(pabyData) +
1321 0 : nWordSize,
1322 : nWordSize, nXSize, nPixelOffset);
1323 : }
1324 : else
1325 : {
1326 204 : GDALSwapWords(pabyData, nBandDataSize, nXSize,
1327 : nPixelOffset);
1328 : }
1329 : }
1330 :
1331 : // Seek to the right line in block.
1332 2638 : if (Seek(nOffset, SEEK_SET) == -1)
1333 : {
1334 0 : CPLError(CE_Failure, CPLE_FileIO,
1335 : "Failed to seek to " CPL_FRMT_GUIB " to read.",
1336 : nOffset);
1337 0 : CPLFree(pabyData);
1338 0 : return CE_Failure;
1339 : }
1340 :
1341 : // Write the line of block.
1342 : const size_t nBytesActuallyWritten =
1343 2638 : Write(pabyData, 1, nBytesToRW);
1344 2638 : if (nBytesActuallyWritten < nBytesToRW)
1345 : {
1346 9 : CPLError(CE_Failure, CPLE_FileIO,
1347 : "Failed to write " CPL_FRMT_GUIB
1348 : " bytes to file. " CPL_FRMT_GUIB " bytes written",
1349 : static_cast<GUIntBig>(nBytesToRW),
1350 : static_cast<GUIntBig>(nBytesActuallyWritten));
1351 9 : CPLFree(pabyData);
1352 9 : return CE_Failure;
1353 : }
1354 :
1355 : // Byte swap (if necessary) back into machine order so the
1356 : // buffer is still usable for reading purposes.
1357 2629 : if (NeedsByteOrderChange())
1358 : {
1359 195 : if (GDALDataTypeIsComplex(eDataType))
1360 : {
1361 : const int nWordSize =
1362 0 : GDALGetDataTypeSize(eDataType) / 16;
1363 0 : GDALSwapWords(pabyData, nWordSize, nXSize,
1364 : nPixelOffset);
1365 0 : GDALSwapWords(static_cast<GByte *>(pabyData) +
1366 0 : nWordSize,
1367 : nWordSize, nXSize, nPixelOffset);
1368 : }
1369 : else
1370 : {
1371 195 : GDALSwapWords(pabyData, nBandDataSize, nXSize,
1372 : nPixelOffset);
1373 : }
1374 : }
1375 : }
1376 :
1377 278 : bNeedFileFlush = TRUE;
1378 278 : CPLFree(pabyData);
1379 : }
1380 : }
1381 :
1382 6703 : return CE_None;
1383 : }
1384 :
1385 : /************************************************************************/
1386 : /* Seek() */
1387 : /************************************************************************/
1388 :
1389 58827 : int RawRasterBand::Seek(vsi_l_offset nOffset, int nSeekMode)
1390 :
1391 : {
1392 58827 : return VSIFSeekL(fpRawL, nOffset, nSeekMode);
1393 : }
1394 :
1395 : /************************************************************************/
1396 : /* Read() */
1397 : /************************************************************************/
1398 :
1399 38142 : size_t RawRasterBand::Read(void *pBuffer, size_t nSize, size_t nCount)
1400 :
1401 : {
1402 38142 : return VSIFReadL(pBuffer, nSize, nCount, fpRawL);
1403 : }
1404 :
1405 : /************************************************************************/
1406 : /* Write() */
1407 : /************************************************************************/
1408 :
1409 20685 : size_t RawRasterBand::Write(void *pBuffer, size_t nSize, size_t nCount)
1410 :
1411 : {
1412 20685 : return VSIFWriteL(pBuffer, nSize, nCount, fpRawL);
1413 : }
1414 :
1415 : /************************************************************************/
1416 : /* StoreNoDataValue() */
1417 : /* */
1418 : /* This is a helper function for datasets to associate a no */
1419 : /* data value with this band, it isn't intended to be called by */
1420 : /* applications. */
1421 : /************************************************************************/
1422 :
1423 0 : void RawRasterBand::StoreNoDataValue(double dfValue)
1424 :
1425 : {
1426 0 : SetNoDataValue(dfValue);
1427 0 : }
1428 :
1429 : /************************************************************************/
1430 : /* GetCategoryNames() */
1431 : /************************************************************************/
1432 :
1433 292 : char **RawRasterBand::GetCategoryNames()
1434 : {
1435 292 : return papszCategoryNames;
1436 : }
1437 :
1438 : /************************************************************************/
1439 : /* SetCategoryNames() */
1440 : /************************************************************************/
1441 :
1442 4 : CPLErr RawRasterBand::SetCategoryNames(char **papszNewNames)
1443 :
1444 : {
1445 4 : CSLDestroy(papszCategoryNames);
1446 4 : papszCategoryNames = CSLDuplicate(papszNewNames);
1447 :
1448 4 : return CE_None;
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* SetColorTable() */
1453 : /************************************************************************/
1454 :
1455 4 : CPLErr RawRasterBand::SetColorTable(GDALColorTable *poNewCT)
1456 :
1457 : {
1458 4 : if (poCT)
1459 0 : delete poCT;
1460 4 : if (poNewCT == nullptr)
1461 0 : poCT = nullptr;
1462 : else
1463 4 : poCT = poNewCT->Clone();
1464 :
1465 4 : return CE_None;
1466 : }
1467 :
1468 : /************************************************************************/
1469 : /* GetColorTable() */
1470 : /************************************************************************/
1471 :
1472 73 : GDALColorTable *RawRasterBand::GetColorTable()
1473 : {
1474 73 : return poCT;
1475 : }
1476 :
1477 : /************************************************************************/
1478 : /* SetColorInterpretation() */
1479 : /************************************************************************/
1480 :
1481 302 : CPLErr RawRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
1482 :
1483 : {
1484 302 : eInterp = eNewInterp;
1485 :
1486 302 : return CE_None;
1487 : }
1488 :
1489 : /************************************************************************/
1490 : /* GetColorInterpretation() */
1491 : /************************************************************************/
1492 :
1493 619 : GDALColorInterp RawRasterBand::GetColorInterpretation()
1494 : {
1495 619 : return eInterp;
1496 : }
1497 :
1498 : /************************************************************************/
1499 : /* GetVirtualMemAuto() */
1500 : /************************************************************************/
1501 :
1502 13 : CPLVirtualMem *RawRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
1503 : int *pnPixelSpace,
1504 : GIntBig *pnLineSpace,
1505 : char **papszOptions)
1506 : {
1507 13 : CPLAssert(pnPixelSpace);
1508 13 : CPLAssert(pnLineSpace);
1509 :
1510 : const vsi_l_offset nSize =
1511 13 : static_cast<vsi_l_offset>(nRasterYSize - 1) * nLineOffset +
1512 13 : static_cast<vsi_l_offset>(nRasterXSize - 1) * nPixelOffset +
1513 13 : GDALGetDataTypeSizeBytes(eDataType);
1514 :
1515 13 : const char *pszImpl = CSLFetchNameValueDef(
1516 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
1517 13 : if (VSIFGetNativeFileDescriptorL(fpRawL) == nullptr ||
1518 6 : !CPLIsVirtualMemFileMapAvailable() || NeedsByteOrderChange() ||
1519 6 : static_cast<size_t>(nSize) != nSize || nPixelOffset < 0 ||
1520 6 : nLineOffset < 0 || EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") ||
1521 19 : EQUAL(pszImpl, "1") || EQUAL(pszImpl, "TRUE"))
1522 : {
1523 7 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
1524 7 : pnLineSpace, papszOptions);
1525 : }
1526 :
1527 6 : FlushCache(false);
1528 :
1529 6 : CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
1530 : fpRawL, nImgOffset, nSize,
1531 : (eRWFlag == GF_Write) ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
1532 : nullptr, nullptr);
1533 6 : if (pVMem == nullptr)
1534 : {
1535 0 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") ||
1536 0 : EQUAL(pszImpl, "0") || EQUAL(pszImpl, "FALSE"))
1537 : {
1538 0 : return nullptr;
1539 : }
1540 0 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
1541 0 : pnLineSpace, papszOptions);
1542 : }
1543 :
1544 6 : *pnPixelSpace = nPixelOffset;
1545 6 : *pnLineSpace = nLineOffset;
1546 6 : return pVMem;
1547 : }
1548 :
1549 : /************************************************************************/
1550 : /* ==================================================================== */
1551 : /* RawDataset */
1552 : /* ==================================================================== */
1553 : /************************************************************************/
1554 :
1555 : /************************************************************************/
1556 : /* RawDataset() */
1557 : /************************************************************************/
1558 :
1559 2182 : RawDataset::RawDataset()
1560 : {
1561 2182 : }
1562 :
1563 : /************************************************************************/
1564 : /* ~RawDataset() */
1565 : /************************************************************************/
1566 :
1567 : // It's pure virtual function but must be defined, even if empty.
1568 2182 : RawDataset::~RawDataset()
1569 : {
1570 2182 : }
1571 :
1572 : /************************************************************************/
1573 : /* IRasterIO() */
1574 : /* */
1575 : /* Multi-band raster io handler. */
1576 : /************************************************************************/
1577 :
1578 753 : CPLErr RawDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1579 : int nXSize, int nYSize, void *pData, int nBufXSize,
1580 : int nBufYSize, GDALDataType eBufType,
1581 : int nBandCount, BANDMAP_TYPE panBandMap,
1582 : GSpacing nPixelSpace, GSpacing nLineSpace,
1583 : GSpacing nBandSpace,
1584 : GDALRasterIOExtraArg *psExtraArg)
1585 :
1586 : {
1587 753 : const char *pszInterleave = nullptr;
1588 :
1589 753 : this->ClearCachedConfigOption();
1590 :
1591 : // The default GDALDataset::IRasterIO() implementation would go to
1592 : // BlockBasedRasterIO if the dataset is interleaved. However if the
1593 : // access pattern is compatible with DirectIO() we don't want to go
1594 : // BlockBasedRasterIO, but rather used our optimized path in
1595 : // RawRasterBand::IRasterIO().
1596 753 : if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount > 1 &&
1597 49 : (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
1598 1506 : nullptr &&
1599 30 : EQUAL(pszInterleave, "PIXEL"))
1600 : {
1601 24 : RawRasterBand *poFirstBand = nullptr;
1602 24 : bool bCanDirectAccessToBIPDataset =
1603 24 : eRWFlag == GF_Read && nBandCount == nBands;
1604 24 : bool bCanUseDirectIO = true;
1605 95 : for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
1606 : {
1607 0 : RawRasterBand *poBand = dynamic_cast<RawRasterBand *>(
1608 72 : GetRasterBand(panBandMap[iBandIndex]));
1609 72 : if (poBand == nullptr)
1610 : {
1611 1 : bCanDirectAccessToBIPDataset = false;
1612 1 : bCanUseDirectIO = false;
1613 1 : break;
1614 : }
1615 71 : else if (!poBand->CanUseDirectIO(nXOff, nYOff, nXSize, nYSize,
1616 : eBufType, psExtraArg))
1617 : {
1618 0 : bCanUseDirectIO = false;
1619 0 : if (!bCanDirectAccessToBIPDataset)
1620 0 : break;
1621 : }
1622 71 : if (bCanDirectAccessToBIPDataset)
1623 : {
1624 18 : const auto eDT = poBand->GetRasterDataType();
1625 18 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1626 34 : if (poBand->bNeedFileFlush || poBand->bLoadedScanlineDirty ||
1627 17 : poBand->HasDirtyBlocks() ||
1628 52 : panBandMap[iBandIndex] != iBandIndex + 1 ||
1629 17 : nPixelSpace != poBand->nPixelOffset)
1630 : {
1631 5 : bCanDirectAccessToBIPDataset = false;
1632 : }
1633 : else
1634 : {
1635 13 : if (poFirstBand == nullptr)
1636 : {
1637 5 : poFirstBand = poBand;
1638 5 : bCanDirectAccessToBIPDataset =
1639 10 : eDT == eBufType && nBandSpace == nDTSize &&
1640 5 : poFirstBand->nPixelOffset ==
1641 5 : cpl::fits_on<int>(nBands * nDTSize);
1642 : }
1643 : else
1644 : {
1645 8 : bCanDirectAccessToBIPDataset =
1646 8 : eDT == poFirstBand->GetRasterDataType() &&
1647 8 : poBand->fpRawL == poFirstBand->fpRawL &&
1648 8 : poBand->nImgOffset ==
1649 16 : poFirstBand->nImgOffset +
1650 8 : cpl::fits_on<int>(iBandIndex * nDTSize) &&
1651 8 : poBand->nPixelOffset == poFirstBand->nPixelOffset &&
1652 24 : poBand->nLineOffset == poFirstBand->nLineOffset &&
1653 8 : poBand->eByteOrder == poFirstBand->eByteOrder;
1654 : }
1655 : }
1656 : }
1657 : }
1658 24 : if (bCanDirectAccessToBIPDataset)
1659 : {
1660 4 : CPLDebugOnly("GDALRaw", "Direct access to BIP dataset");
1661 4 : const auto eDT = poFirstBand->GetRasterDataType();
1662 4 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1663 : const bool bNeedsByteOrderChange =
1664 4 : poFirstBand->NeedsByteOrderChange();
1665 112 : for (int iY = 0; iY < nYSize; ++iY)
1666 : {
1667 108 : GByte *pabyOut = static_cast<GByte *>(pData) + iY * nLineSpace;
1668 108 : VSIFSeekL(poFirstBand->fpRawL,
1669 108 : poFirstBand->nImgOffset +
1670 108 : static_cast<vsi_l_offset>(nYOff + iY) *
1671 108 : poFirstBand->nLineOffset +
1672 108 : static_cast<vsi_l_offset>(nXOff) *
1673 108 : poFirstBand->nPixelOffset,
1674 : SEEK_SET);
1675 216 : if (VSIFReadL(pabyOut,
1676 108 : static_cast<size_t>(nXSize * nPixelSpace), 1,
1677 108 : poFirstBand->fpRawL) != 1)
1678 : {
1679 0 : return CE_Failure;
1680 : }
1681 108 : if (bNeedsByteOrderChange)
1682 : {
1683 54 : poFirstBand->DoByteSwap(
1684 54 : pabyOut, static_cast<size_t>(nXSize) * nBands, nDTSize,
1685 : true);
1686 : }
1687 : }
1688 4 : return CE_None;
1689 : }
1690 20 : else if (bCanUseDirectIO)
1691 : {
1692 19 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
1693 19 : void *pProgressDataGlobal = psExtraArg->pProgressData;
1694 :
1695 19 : CPLErr eErr = CE_None;
1696 78 : for (int iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
1697 : iBandIndex++)
1698 : {
1699 59 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
1700 :
1701 59 : if (poBand == nullptr)
1702 : {
1703 0 : eErr = CE_Failure;
1704 0 : break;
1705 : }
1706 :
1707 59 : GByte *pabyBandData =
1708 59 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
1709 :
1710 59 : psExtraArg->pfnProgress = GDALScaledProgress;
1711 118 : psExtraArg->pProgressData = GDALCreateScaledProgress(
1712 : 1.0 * iBandIndex / nBandCount,
1713 59 : 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
1714 : pProgressDataGlobal);
1715 :
1716 59 : eErr = poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1717 : static_cast<void *>(pabyBandData),
1718 : nBufXSize, nBufYSize, eBufType,
1719 : nPixelSpace, nLineSpace, psExtraArg);
1720 :
1721 59 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
1722 : }
1723 :
1724 19 : psExtraArg->pfnProgress = pfnProgressGlobal;
1725 19 : psExtraArg->pProgressData = pProgressDataGlobal;
1726 :
1727 19 : return eErr;
1728 : }
1729 : }
1730 :
1731 730 : return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1732 : nBufXSize, nBufYSize, eBufType, nBandCount,
1733 : panBandMap, nPixelSpace, nLineSpace,
1734 730 : nBandSpace, psExtraArg);
1735 : }
1736 :
1737 : /************************************************************************/
1738 : /* RAWDatasetCheckMemoryUsage() */
1739 : /************************************************************************/
1740 :
1741 457 : bool RAWDatasetCheckMemoryUsage(int nXSize, int nYSize, int nBands, int nDTSize,
1742 : int nPixelOffset, int nLineOffset,
1743 : vsi_l_offset nHeaderSize,
1744 : vsi_l_offset nBandOffset, VSILFILE *fp)
1745 : {
1746 457 : const GIntBig nTotalBufferSize =
1747 457 : nPixelOffset == static_cast<GIntBig>(nDTSize) * nBands
1748 457 : ? // BIP ?
1749 345 : static_cast<GIntBig>(nPixelOffset) * nXSize
1750 112 : : static_cast<GIntBig>(std::abs(nPixelOffset)) * nXSize * nBands;
1751 :
1752 : // Currently each RawRasterBand allocates nPixelOffset * nRasterXSize bytes
1753 : // so for a pixel interleaved scheme, this will allocate lots of memory!
1754 : // Actually this is quadratic in the number of bands!
1755 : // Do a few sanity checks to avoid excessive memory allocation on
1756 : // small files.
1757 : // But ultimately we should fix RawRasterBand to have a shared buffer
1758 : // among bands.
1759 457 : const char *pszCheck = CPLGetConfigOption("RAW_CHECK_FILE_SIZE", nullptr);
1760 454 : if ((nBands > 10 || nTotalBufferSize > 20000 ||
1761 914 : (pszCheck && CPLTestBool(pszCheck))) &&
1762 3 : !(pszCheck && !CPLTestBool(pszCheck)))
1763 : {
1764 : vsi_l_offset nExpectedFileSize;
1765 : try
1766 : {
1767 : nExpectedFileSize =
1768 6 : (CPLSM(static_cast<uint64_t>(nHeaderSize)) +
1769 6 : CPLSM(static_cast<uint64_t>(nBandOffset)) *
1770 18 : CPLSM(static_cast<uint64_t>(nBands - 1)) +
1771 : (nLineOffset >= 0
1772 12 : ? CPLSM(static_cast<uint64_t>(nYSize - 1)) *
1773 12 : CPLSM(static_cast<uint64_t>(nLineOffset))
1774 6 : : CPLSM(static_cast<uint64_t>(0))) +
1775 : (nPixelOffset >= 0
1776 12 : ? CPLSM(static_cast<uint64_t>(nXSize - 1)) *
1777 12 : CPLSM(static_cast<uint64_t>(nPixelOffset))
1778 6 : : CPLSM(static_cast<uint64_t>(0))))
1779 6 : .v();
1780 : }
1781 0 : catch (...)
1782 : {
1783 0 : CPLError(CE_Failure, CPLE_AppDefined, "Image file is too small");
1784 0 : return false;
1785 : }
1786 6 : CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_END));
1787 6 : vsi_l_offset nFileSize = VSIFTellL(fp);
1788 : // Do not strictly compare against nExpectedFileSize, but use an
1789 : // arbitrary 50% margin, since some raw formats such as ENVI allow for
1790 : // sparse files (see https://github.com/OSGeo/gdal/issues/915)
1791 6 : if (nFileSize < nExpectedFileSize / 2)
1792 : {
1793 2 : CPLError(CE_Failure, CPLE_AppDefined, "Image file is too small");
1794 2 : return false;
1795 : }
1796 : }
1797 :
1798 : #if SIZEOF_VOIDP == 8
1799 455 : const char *pszDefault = "1024";
1800 : #else
1801 : const char *pszDefault = "512";
1802 : #endif
1803 455 : constexpr int MB_IN_BYTES = 1024 * 1024;
1804 : const GIntBig nMAX_BUFFER_MEM =
1805 455 : static_cast<GIntBig>(
1806 455 : atoi(CPLGetConfigOption("RAW_MEM_ALLOC_LIMIT_MB", pszDefault))) *
1807 455 : MB_IN_BYTES;
1808 455 : if (nTotalBufferSize > nMAX_BUFFER_MEM)
1809 : {
1810 0 : CPLError(
1811 : CE_Failure, CPLE_OutOfMemory,
1812 : CPL_FRMT_GIB
1813 : " MB of RAM would be needed to open the dataset. If you are "
1814 : "comfortable with this, you can set the RAW_MEM_ALLOC_LIMIT_MB "
1815 : "configuration option to that value or above",
1816 0 : (nTotalBufferSize + MB_IN_BYTES - 1) / MB_IN_BYTES);
1817 0 : return false;
1818 : }
1819 :
1820 455 : return true;
1821 : }
1822 :
1823 : /************************************************************************/
1824 : /* GetRawBinaryLayout() */
1825 : /************************************************************************/
1826 :
1827 9 : bool RawDataset::GetRawBinaryLayout(GDALDataset::RawBinaryLayout &sLayout)
1828 : {
1829 9 : vsi_l_offset nImgOffset = 0;
1830 9 : GIntBig nBandOffset = 0;
1831 9 : int nPixelOffset = 0;
1832 9 : int nLineOffset = 0;
1833 9 : RawRasterBand::ByteOrder eByteOrder =
1834 : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
1835 9 : GDALDataType eDT = GDT_Unknown;
1836 26 : for (int i = 1; i <= nBands; i++)
1837 : {
1838 17 : auto poBand = dynamic_cast<RawRasterBand *>(GetRasterBand(i));
1839 17 : if (poBand == nullptr)
1840 0 : return false;
1841 17 : if (i == 1)
1842 : {
1843 9 : nImgOffset = poBand->nImgOffset;
1844 9 : nPixelOffset = poBand->nPixelOffset;
1845 9 : nLineOffset = poBand->nLineOffset;
1846 9 : eByteOrder = poBand->eByteOrder;
1847 9 : if (eByteOrder == RawRasterBand::ByteOrder::ORDER_VAX)
1848 0 : return false;
1849 9 : eDT = poBand->GetRasterDataType();
1850 : }
1851 24 : else if (nPixelOffset != poBand->nPixelOffset ||
1852 8 : nLineOffset != poBand->nLineOffset ||
1853 24 : eByteOrder != poBand->eByteOrder ||
1854 8 : eDT != poBand->GetRasterDataType())
1855 : {
1856 0 : return false;
1857 : }
1858 8 : else if (i == 2)
1859 : {
1860 4 : nBandOffset = static_cast<GIntBig>(poBand->nImgOffset) -
1861 4 : static_cast<GIntBig>(nImgOffset);
1862 : }
1863 4 : else if (nBandOffset * (i - 1) !=
1864 4 : static_cast<GIntBig>(poBand->nImgOffset) -
1865 4 : static_cast<GIntBig>(nImgOffset))
1866 : {
1867 0 : return false;
1868 : }
1869 : }
1870 :
1871 9 : sLayout.eInterleaving = RawBinaryLayout::Interleaving::UNKNOWN;
1872 9 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1873 9 : if (nBands > 1)
1874 : {
1875 4 : if (nPixelOffset == nBands * nDTSize &&
1876 2 : nLineOffset == nPixelOffset * nRasterXSize &&
1877 2 : nBandOffset == nDTSize)
1878 : {
1879 2 : sLayout.eInterleaving = RawBinaryLayout::Interleaving::BIP;
1880 : }
1881 2 : else if (nPixelOffset == nDTSize &&
1882 2 : nLineOffset == nDTSize * nBands * nRasterXSize &&
1883 1 : nBandOffset == static_cast<GIntBig>(nDTSize) * nRasterXSize)
1884 : {
1885 1 : sLayout.eInterleaving = RawBinaryLayout::Interleaving::BIL;
1886 : }
1887 1 : else if (nPixelOffset == nDTSize &&
1888 1 : nLineOffset == nDTSize * nRasterXSize &&
1889 : nBandOffset ==
1890 1 : static_cast<GIntBig>(nLineOffset) * nRasterYSize)
1891 : {
1892 1 : sLayout.eInterleaving = RawBinaryLayout::Interleaving::BSQ;
1893 : }
1894 : }
1895 :
1896 9 : sLayout.eDataType = eDT;
1897 9 : sLayout.bLittleEndianOrder =
1898 9 : eByteOrder == RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN;
1899 9 : sLayout.nImageOffset = nImgOffset;
1900 9 : sLayout.nPixelOffset = nPixelOffset;
1901 9 : sLayout.nLineOffset = nLineOffset;
1902 9 : sLayout.nBandOffset = nBandOffset;
1903 :
1904 9 : return true;
1905 : }
1906 :
1907 : /************************************************************************/
1908 : /* ClearCachedConfigOption() */
1909 : /************************************************************************/
1910 :
1911 753 : void RawDataset::ClearCachedConfigOption(void)
1912 : {
1913 753 : cachedCPLOneBigReadOption = 0;
1914 753 : }
|