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