Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoTIFF Driver
4 : * Purpose: Read/get operations on GTiffRasterBand
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "gtiffrasterband.h"
15 : #include "gtiffdataset.h"
16 : #include "gtiffjpegoverviewds.h"
17 :
18 : #include <algorithm>
19 : #include <cassert>
20 : #include <limits>
21 : #include <map>
22 : #include <set>
23 : #include <utility>
24 :
25 : #include "cpl_vsi_virtual.h"
26 : #include "fetchbufferdirectio.h"
27 : #include "gtiff.h"
28 : #include "tifvsi.h"
29 :
30 : /************************************************************************/
31 : /* GetDefaultRAT() */
32 : /************************************************************************/
33 :
34 3279 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
35 :
36 : {
37 3279 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
38 3279 : return GDALPamRasterBand::GetDefaultRAT();
39 : }
40 :
41 : /************************************************************************/
42 : /* GetHistogram() */
43 : /************************************************************************/
44 :
45 20 : CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
46 : GUIntBig *panHistogram,
47 : int bIncludeOutOfRange, int bApproxOK,
48 : GDALProgressFunc pfnProgress,
49 : void *pProgressData)
50 : {
51 20 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
52 20 : return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
53 : bIncludeOutOfRange, bApproxOK,
54 20 : pfnProgress, pProgressData);
55 : }
56 :
57 : /************************************************************************/
58 : /* GetDefaultHistogram() */
59 : /************************************************************************/
60 :
61 21 : CPLErr GTiffRasterBand::GetDefaultHistogram(
62 : double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
63 : int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
64 : {
65 21 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
66 21 : return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
67 : ppanHistogram, bForce,
68 21 : pfnProgress, pProgressData);
69 : }
70 :
71 : /************************************************************************/
72 : /* DirectIO() */
73 : /************************************************************************/
74 :
75 : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
76 : // block reading. Restricted to simple TIFF configurations
77 : // (uncompressed data, standard data types). Particularly useful to extract
78 : // sub-windows of data on a large /vsicurl dataset).
79 : // Returns -1 if DirectIO() can't be supported on that file.
80 :
81 2098 : int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
82 : int nXSize, int nYSize, void *pData,
83 : int nBufXSize, int nBufYSize,
84 : GDALDataType eBufType, GSpacing nPixelSpace,
85 : GSpacing nLineSpace,
86 : GDALRasterIOExtraArg *psExtraArg)
87 : {
88 2098 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
89 4196 : if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
90 2098 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
91 795 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
92 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
93 2098 : IsBaseGTiffClass()))
94 : {
95 0 : return -1;
96 : }
97 2098 : m_poGDS->Crystalize();
98 :
99 : // Only know how to deal with nearest neighbour in this optimized routine.
100 2098 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
101 447 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
102 : {
103 66 : return -1;
104 : }
105 :
106 : #if DEBUG_VERBOSE
107 : CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
108 : nYSize, nBufXSize, nBufYSize);
109 : #endif
110 :
111 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
112 2032 : if (m_poGDS->GetAccess() == GA_Update)
113 : {
114 0 : m_poGDS->FlushCache(false);
115 0 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
116 : }
117 :
118 2032 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
119 : {
120 504 : const int nDTSize = nDTSizeBits / 8;
121 504 : const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
122 1008 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
123 504 : (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
124 : : 1));
125 504 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
126 : {
127 28 : m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
128 14 : VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
129 14 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
130 0 : return CE_Failure;
131 : }
132 :
133 504 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
134 : FetchBufferDirectIO oFetcher(fp,
135 504 : m_poGDS->m_pTempBufferForCommonDirectIO,
136 504 : nTempBufferForCommonDirectIOSize);
137 :
138 1008 : return m_poGDS->CommonDirectIOClassic(
139 : oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
140 504 : eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
141 : }
142 :
143 : // Get strip offsets.
144 1528 : toff_t *panTIFFOffsets = nullptr;
145 1528 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
146 3056 : &panTIFFOffsets) ||
147 1528 : panTIFFOffsets == nullptr)
148 : {
149 0 : return CE_Failure;
150 : }
151 :
152 : // Sub-sampling or over-sampling can only be done at last stage.
153 1528 : int nReqXSize = nXSize;
154 : // Can do sub-sampling at the extraction stage.
155 1528 : const int nReqYSize = std::min(nBufYSize, nYSize);
156 : // TODO(schwehr): Make ppData be GByte**.
157 : void **ppData =
158 1528 : static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
159 : vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
160 1528 : VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
161 : size_t *panSizes =
162 1528 : static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
163 1528 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
164 1528 : void *pTmpBuffer = nullptr;
165 1528 : int eErr = CE_None;
166 1528 : int nContigBands =
167 1528 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
168 1528 : int nSrcPixelSize = nDTSize * nContigBands;
169 :
170 1528 : if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
171 0 : eErr = CE_Failure;
172 1295 : else if (nXSize != nBufXSize || nYSize != nBufYSize ||
173 1295 : eBufType != eDataType ||
174 2823 : nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
175 : nContigBands > 1)
176 : {
177 : // We need a temporary buffer for over-sampling/sub-sampling
178 : // and/or data type conversion.
179 1388 : pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
180 1388 : if (pTmpBuffer == nullptr)
181 0 : eErr = CE_Failure;
182 : }
183 :
184 : // Prepare data extraction.
185 1528 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
186 :
187 41509 : for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
188 : {
189 39981 : if (pTmpBuffer == nullptr)
190 10980 : ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
191 : else
192 29001 : ppData[iLine] =
193 29001 : static_cast<GByte *>(pTmpBuffer) +
194 29001 : static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
195 39981 : int nSrcLine = 0;
196 39981 : if (nBufYSize < nYSize) // Sub-sampling in y.
197 2440 : nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
198 : else
199 37541 : nSrcLine = nYOff + iLine;
200 :
201 39981 : const int nBlockXOff = 0;
202 39981 : const int nBlockYOff = nSrcLine / nBlockYSize;
203 39981 : const int nYOffsetInBlock = nSrcLine % nBlockYSize;
204 39981 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
205 :
206 39981 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
207 39981 : if (panOffsets[iLine] == 0) // We don't support sparse files.
208 1047 : eErr = -1;
209 :
210 39981 : panOffsets[iLine] +=
211 39981 : (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
212 39981 : nSrcPixelSize;
213 39981 : panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
214 : }
215 :
216 : // Extract data from the file.
217 1528 : if (eErr == CE_None)
218 : {
219 481 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
220 : const int nRet =
221 481 : VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
222 481 : if (nRet != 0)
223 12 : eErr = CE_Failure;
224 : }
225 :
226 : // Byte-swap if necessary.
227 1528 : if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
228 : {
229 4144 : for (int iLine = 0; iLine < nReqYSize; ++iLine)
230 : {
231 4094 : if (GDALDataTypeIsComplex(eDataType))
232 2396 : GDALSwapWords(ppData[iLine], nDTSize / 2,
233 2396 : 2 * nReqXSize * nContigBands, nDTSize / 2);
234 : else
235 1698 : GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
236 : nDTSize);
237 : }
238 : }
239 :
240 : // Over-sampling/sub-sampling and/or data type conversion.
241 1528 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
242 1528 : if (eErr == CE_None && pTmpBuffer != nullptr)
243 : {
244 364 : const bool bOneByteCopy =
245 656 : (eDataType == eBufType &&
246 292 : (eDataType == GDT_Byte || eDataType == GDT_Int8));
247 96459 : for (int iY = 0; iY < nBufYSize; ++iY)
248 : {
249 192190 : const int iSrcY = nBufYSize <= nYSize
250 96095 : ? iY
251 73872 : : static_cast<int>((iY + 0.5) * dfSrcYInc);
252 :
253 192190 : GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
254 96095 : (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
255 96095 : GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
256 96095 : if (nBufXSize == nXSize)
257 : {
258 19798 : GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
259 : pabyDstData, eBufType,
260 : static_cast<int>(nPixelSpace), nBufXSize);
261 : }
262 : else
263 : {
264 76297 : if (bOneByteCopy)
265 : {
266 25435 : double dfSrcX = 0.5 * dfSrcXInc;
267 2147110 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
268 : {
269 2121670 : const int iSrcX = static_cast<int>(dfSrcX);
270 2121670 : pabyDstData[iX * nPixelSpace] =
271 2121670 : pabySrcData[iSrcX * nSrcPixelSize];
272 : }
273 : }
274 : else
275 : {
276 50862 : double dfSrcX = 0.5 * dfSrcXInc;
277 4293180 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
278 : {
279 4242320 : const int iSrcX = static_cast<int>(dfSrcX);
280 4242320 : GDALCopyWords(
281 4242320 : pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
282 4242320 : pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
283 : }
284 : }
285 : }
286 : }
287 : }
288 :
289 : // Cleanup.
290 1528 : CPLFree(pTmpBuffer);
291 1528 : CPLFree(ppData);
292 1528 : CPLFree(panOffsets);
293 1528 : CPLFree(panSizes);
294 :
295 1528 : return eErr;
296 : }
297 :
298 : /************************************************************************/
299 : /* GetVirtualMemAuto() */
300 : /************************************************************************/
301 :
302 17 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
303 : int *pnPixelSpace,
304 : GIntBig *pnLineSpace,
305 : char **papszOptions)
306 : {
307 17 : const char *pszImpl = CSLFetchNameValueDef(
308 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
309 17 : if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
310 16 : EQUAL(pszImpl, "TRUE"))
311 : {
312 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
313 1 : pnLineSpace, papszOptions);
314 : }
315 :
316 16 : CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
317 : pnLineSpace, papszOptions);
318 16 : if (psRet != nullptr)
319 : {
320 14 : CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
321 14 : return psRet;
322 : }
323 :
324 2 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
325 1 : EQUAL(pszImpl, "FALSE"))
326 : {
327 1 : return nullptr;
328 : }
329 :
330 1 : CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
331 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
332 1 : papszOptions);
333 : }
334 :
335 : /************************************************************************/
336 : /* DropReferenceVirtualMem() */
337 : /************************************************************************/
338 :
339 8 : void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
340 : {
341 : // This function may also be called when the dataset and rasterband
342 : // objects have been destroyed.
343 : // If they are still alive, it updates the reference counter of the
344 : // base mapping to invalidate the pointer to it if needed.
345 :
346 8 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
347 8 : GTiffRasterBand *poSelf = *ppoSelf;
348 :
349 8 : if (poSelf != nullptr)
350 : {
351 8 : if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
352 : {
353 4 : poSelf->m_poGDS->m_pBaseMapping = nullptr;
354 : }
355 8 : poSelf->m_aSetPSelf.erase(ppoSelf);
356 : }
357 8 : CPLFree(pUserData);
358 8 : }
359 :
360 : /************************************************************************/
361 : /* GetVirtualMemAutoInternal() */
362 : /************************************************************************/
363 :
364 20 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(GDALRWFlag eRWFlag,
365 : int *pnPixelSpace,
366 : GIntBig *pnLineSpace,
367 : char **papszOptions)
368 : {
369 20 : int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
370 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
371 14 : nLineSize *= m_poGDS->nBands;
372 :
373 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
374 : {
375 : // In case of a pixel interleaved file, we save virtual memory space
376 : // by reusing a base mapping that embraces the whole imagery.
377 14 : if (m_poGDS->m_pBaseMapping != nullptr)
378 : {
379 : // Offset between the base mapping and the requested mapping.
380 8 : vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
381 8 : GDALGetDataTypeSizeBytes(eDataType);
382 :
383 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
384 8 : CPLCalloc(1, sizeof(GTiffRasterBand *)));
385 8 : *ppoSelf = this;
386 :
387 24 : CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
388 8 : m_poGDS->m_pBaseMapping, nOffset,
389 8 : CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
390 : GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
391 8 : if (pVMem == nullptr)
392 : {
393 0 : CPLFree(ppoSelf);
394 0 : return nullptr;
395 : }
396 :
397 : // Mechanism used so that the memory mapping object can be
398 : // destroyed after the raster band.
399 8 : m_aSetPSelf.insert(ppoSelf);
400 8 : ++m_poGDS->m_nRefBaseMapping;
401 8 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
402 8 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
403 8 : *pnPixelSpace *= m_poGDS->nBands;
404 8 : *pnLineSpace = nLineSize;
405 8 : return pVMem;
406 : }
407 : }
408 :
409 12 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
410 :
411 12 : vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
412 :
413 24 : if (!(CPLIsVirtualMemFileMapAvailable() &&
414 12 : VSIFGetNativeFileDescriptorL(fp) != nullptr &&
415 : #if SIZEOF_VOIDP == 4
416 : nLength == static_cast<size_t>(nLength) &&
417 : #endif
418 10 : m_poGDS->m_nCompression == COMPRESSION_NONE &&
419 10 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
420 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
421 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
422 10 : m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
423 10 : !TIFFIsTiled(m_poGDS->m_hTIFF) &&
424 10 : !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
425 : {
426 2 : return nullptr;
427 : }
428 :
429 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
430 10 : if (m_poGDS->GetAccess() == GA_Update)
431 : {
432 7 : m_poGDS->FlushCache(false);
433 7 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
434 : }
435 :
436 : // Get strip offsets.
437 10 : toff_t *panTIFFOffsets = nullptr;
438 10 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
439 20 : &panTIFFOffsets) ||
440 10 : panTIFFOffsets == nullptr)
441 : {
442 0 : return nullptr;
443 : }
444 :
445 10 : GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
446 10 : GDALGetDataTypeSizeBytes(eDataType);
447 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
448 4 : nBlockSize *= m_poGDS->nBands;
449 :
450 10 : int nBlocks = m_poGDS->m_nBlocksPerBand;
451 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
452 6 : nBlocks *= m_poGDS->nBands;
453 10 : int i = 0; // Used after for.
454 103 : for (; i < nBlocks; ++i)
455 : {
456 100 : if (panTIFFOffsets[i] != 0)
457 7 : break;
458 : }
459 10 : if (i == nBlocks)
460 : {
461 : // All zeroes.
462 3 : if (m_poGDS->eAccess == GA_Update)
463 : {
464 : // Initialize the file with empty blocks so that the file has
465 : // the appropriate size.
466 :
467 3 : toff_t *panByteCounts = nullptr;
468 3 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
469 6 : &panByteCounts) ||
470 3 : panByteCounts == nullptr)
471 : {
472 0 : return nullptr;
473 : }
474 3 : if (VSIFSeekL(fp, 0, SEEK_END) != 0)
475 0 : return nullptr;
476 3 : vsi_l_offset nBaseOffset = VSIFTellL(fp);
477 :
478 : // Just write one tile with libtiff to put it in appropriate state.
479 : GByte *pabyData =
480 3 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
481 3 : if (pabyData == nullptr)
482 : {
483 0 : return nullptr;
484 : }
485 3 : const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
486 : pabyData, nBlockSize);
487 3 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
488 3 : VSIFree(pabyData);
489 3 : if (ret != nBlockSize)
490 : {
491 0 : return nullptr;
492 : }
493 3 : CPLAssert(panTIFFOffsets[0] == nBaseOffset);
494 3 : CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
495 :
496 : // Now simulate the writing of other blocks.
497 3 : assert(nBlocks > 0);
498 3 : assert(static_cast<vsi_l_offset>(nBlockSize) <
499 : std::numeric_limits<vsi_l_offset>::max() / nBlocks);
500 3 : const vsi_l_offset nDataSize =
501 3 : static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
502 3 : if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
503 0 : return nullptr;
504 :
505 93 : for (i = 1; i < nBlocks; ++i)
506 : {
507 90 : panTIFFOffsets[i] =
508 90 : nBaseOffset + i * static_cast<toff_t>(nBlockSize);
509 90 : panByteCounts[i] = nBlockSize;
510 : }
511 : }
512 : else
513 : {
514 0 : CPLDebug("GTiff", "Sparse files not supported in file mapping");
515 0 : return nullptr;
516 : }
517 : }
518 :
519 10 : GIntBig nBlockSpacing = 0;
520 10 : bool bCompatibleSpacing = true;
521 10 : toff_t nPrevOffset = 0;
522 229 : for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
523 : {
524 219 : toff_t nCurOffset = 0;
525 219 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
526 96 : nCurOffset =
527 96 : panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
528 : else
529 123 : nCurOffset = panTIFFOffsets[i];
530 219 : if (nCurOffset == 0)
531 : {
532 0 : bCompatibleSpacing = false;
533 0 : break;
534 : }
535 219 : if (i > 0)
536 : {
537 209 : const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
538 209 : if (i == 1)
539 : {
540 10 : if (nCurSpacing !=
541 10 : static_cast<GIntBig>(nBlockYSize) * nLineSize)
542 : {
543 0 : bCompatibleSpacing = false;
544 0 : break;
545 : }
546 10 : nBlockSpacing = nCurSpacing;
547 : }
548 199 : else if (nBlockSpacing != nCurSpacing)
549 : {
550 0 : bCompatibleSpacing = false;
551 0 : break;
552 : }
553 : }
554 219 : nPrevOffset = nCurOffset;
555 : }
556 :
557 10 : if (!bCompatibleSpacing)
558 : {
559 0 : return nullptr;
560 : }
561 :
562 10 : vsi_l_offset nOffset = 0;
563 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
564 : {
565 4 : CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
566 4 : nOffset = panTIFFOffsets[0];
567 : }
568 : else
569 : {
570 6 : nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
571 : }
572 10 : CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
573 : fp, nOffset, nLength,
574 : eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
575 : nullptr, nullptr);
576 10 : if (pVMem == nullptr)
577 : {
578 0 : return nullptr;
579 : }
580 :
581 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
582 : {
583 : // TODO(schwehr): Revisit this block.
584 4 : m_poGDS->m_pBaseMapping = pVMem;
585 4 : pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
586 : papszOptions);
587 : // Drop ref on base mapping.
588 4 : CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
589 4 : if (pVMem == nullptr)
590 0 : m_poGDS->m_pBaseMapping = nullptr;
591 : }
592 : else
593 : {
594 6 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
595 6 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
596 0 : *pnPixelSpace *= m_poGDS->nBands;
597 6 : *pnLineSpace = nLineSize;
598 : }
599 10 : return pVMem;
600 : }
601 :
602 : /************************************************************************/
603 : /* CacheMultiRange() */
604 : /************************************************************************/
605 :
606 234 : static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
607 : {
608 : GByte abyTrailer[4];
609 234 : memcpy(abyTrailer, strileData + nStrileSize, 4);
610 234 : GByte abyLastBytes[4] = {};
611 234 : if (nStrileSize >= 4)
612 234 : memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
613 : else
614 : {
615 : // The last bytes will be zero due to the above {} initialization,
616 : // and that's what should be in abyTrailer too when the trailer is
617 : // correct.
618 0 : memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
619 : }
620 234 : return memcmp(abyTrailer, abyLastBytes, 4) == 0;
621 : }
622 :
623 262 : void *GTiffRasterBand::CacheMultiRange(int nXOff, int nYOff, int nXSize,
624 : int nYSize, int nBufXSize, int nBufYSize,
625 : GDALRasterIOExtraArg *psExtraArg)
626 : {
627 262 : void *pBufferedData = nullptr;
628 : // Same logic as in GDALRasterBand::IRasterIO()
629 262 : double dfXOff = nXOff;
630 262 : double dfYOff = nYOff;
631 262 : double dfXSize = nXSize;
632 262 : double dfYSize = nYSize;
633 262 : if (psExtraArg->bFloatingPointWindowValidity)
634 : {
635 48 : dfXOff = psExtraArg->dfXOff;
636 48 : dfYOff = psExtraArg->dfYOff;
637 48 : dfXSize = psExtraArg->dfXSize;
638 48 : dfYSize = psExtraArg->dfYSize;
639 : }
640 262 : const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
641 262 : const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
642 262 : const double EPS = 1e-10;
643 : const int nBlockX1 =
644 262 : static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
645 262 : nBlockXSize;
646 : const int nBlockY1 =
647 262 : static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
648 262 : nBlockYSize;
649 : const int nBlockX2 =
650 262 : static_cast<int>(
651 524 : std::min(static_cast<double>(nRasterXSize - 1),
652 262 : (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
653 262 : nBlockXSize;
654 : const int nBlockY2 =
655 262 : static_cast<int>(
656 524 : std::min(static_cast<double>(nRasterYSize - 1),
657 262 : (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
658 262 : nBlockYSize;
659 :
660 262 : const int nBlockCount = nBlocksPerRow * nBlocksPerColumn;
661 :
662 : struct StrileData
663 : {
664 : vsi_l_offset nOffset;
665 : vsi_l_offset nByteCount;
666 : bool bTryMask;
667 : };
668 :
669 524 : std::map<int, StrileData> oMapStrileToOffsetByteCount;
670 :
671 : // Dedicated method to retrieved the offset and size in an efficient way
672 : // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
673 : // met.
674 : // Except for the last block, we just read the offset from the TIFF offset
675 : // array, and retrieve the size in the leader 4 bytes that come before the
676 : // payload.
677 : auto OptimizedRetrievalOfOffsetSize =
678 195 : [&](int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
679 : size_t nTotalSize, size_t nMaxRawBlockCacheSize)
680 : {
681 438 : bool bTryMask = m_poGDS->m_bMaskInterleavedWithImagery;
682 195 : nOffset = TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId);
683 195 : if (nOffset >= 4)
684 : {
685 132 : if (nBlockId == nBlockCount - 1)
686 : {
687 : // Special case for the last block. As there is no next block
688 : // from which to retrieve an offset, use the good old method
689 : // that consists in reading the ByteCount array.
690 49 : if (bTryMask && m_poGDS->GetRasterBand(1)->GetMaskBand() &&
691 23 : m_poGDS->m_poMaskDS)
692 : {
693 46 : auto nMaskOffset = TIFFGetStrileOffset(
694 23 : m_poGDS->m_poMaskDS->m_hTIFF, nBlockId);
695 23 : if (nMaskOffset)
696 : {
697 23 : nSize = nMaskOffset +
698 46 : TIFFGetStrileByteCount(
699 23 : m_poGDS->m_poMaskDS->m_hTIFF, nBlockId) -
700 23 : nOffset;
701 : }
702 : else
703 : {
704 0 : bTryMask = false;
705 : }
706 : }
707 26 : if (nSize == 0)
708 : {
709 3 : nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
710 : }
711 26 : if (nSize && m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
712 : {
713 26 : nSize += 4;
714 : }
715 : }
716 : else
717 : {
718 : auto nOffsetNext =
719 106 : TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId + 1);
720 106 : if (nOffsetNext > nOffset)
721 : {
722 98 : nSize = nOffsetNext - nOffset;
723 : }
724 : else
725 : {
726 : // Shouldn't happen for a compliant file
727 8 : if (nOffsetNext != 0)
728 : {
729 0 : CPLDebug("GTiff", "Tile %d is not located after %d",
730 : nBlockId + 1, nBlockId);
731 : }
732 8 : bTryMask = false;
733 8 : nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
734 8 : if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
735 8 : nSize += 4;
736 : }
737 : }
738 132 : if (nSize)
739 : {
740 132 : nOffset -= 4;
741 132 : nSize += 4;
742 132 : if (nTotalSize + nSize < nMaxRawBlockCacheSize)
743 : {
744 : StrileData data;
745 132 : data.nOffset = nOffset;
746 132 : data.nByteCount = nSize;
747 132 : data.bTryMask = bTryMask;
748 132 : oMapStrileToOffsetByteCount[nBlockId] = data;
749 : }
750 : }
751 : }
752 : else
753 : {
754 : // Sparse tile
755 : StrileData data;
756 63 : data.nOffset = 0;
757 63 : data.nByteCount = 0;
758 63 : data.bTryMask = false;
759 63 : oMapStrileToOffsetByteCount[nBlockId] = data;
760 : }
761 195 : };
762 :
763 : // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
764 : // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
765 : // mask) from the temporary oMapStrileToOffsetByteCount.
766 : auto FillCacheStrileToOffsetByteCount =
767 36 : [&](const std::vector<vsi_l_offset> &anOffsets,
768 : const std::vector<size_t> &anSizes,
769 : const std::vector<void *> &apData)
770 : {
771 36 : CPLAssert(m_poGDS->m_bLeaderSizeAsUInt4);
772 36 : size_t i = 0;
773 36 : vsi_l_offset nLastOffset = 0;
774 191 : for (const auto &entry : oMapStrileToOffsetByteCount)
775 : {
776 155 : const auto nBlockId = entry.first;
777 155 : const auto nOffset = entry.second.nOffset;
778 155 : const auto nSize = entry.second.nByteCount;
779 155 : if (nOffset == 0)
780 : {
781 : // Sparse tile
782 23 : m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
783 23 : nBlockId, std::pair(0, 0));
784 53 : continue;
785 : }
786 :
787 132 : if (nOffset < nLastOffset)
788 : {
789 : // shouldn't happen normally if tiles are sorted
790 0 : i = 0;
791 : }
792 132 : nLastOffset = nOffset;
793 272 : while (i < anOffsets.size() &&
794 136 : !(nOffset >= anOffsets[i] &&
795 136 : nOffset + nSize <= anOffsets[i] + anSizes[i]))
796 : {
797 4 : i++;
798 : }
799 132 : CPLAssert(i < anOffsets.size());
800 132 : CPLAssert(nOffset >= anOffsets[i]);
801 132 : CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
802 : GUInt32 nSizeFromLeader;
803 132 : memcpy(&nSizeFromLeader,
804 : // cppcheck-suppress containerOutOfBounds
805 132 : static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
806 : sizeof(nSizeFromLeader));
807 132 : CPL_LSBPTR32(&nSizeFromLeader);
808 132 : bool bOK = true;
809 132 : constexpr int nLeaderSize = 4;
810 132 : const int nTrailerSize =
811 132 : (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
812 132 : if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
813 : {
814 0 : CPLDebug("GTiff",
815 : "Inconsistent block size from in leader of block %d",
816 : nBlockId);
817 0 : bOK = false;
818 : }
819 132 : else if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
820 : {
821 : // Check trailer consistency
822 132 : const GByte *strileData = static_cast<GByte *>(apData[i]) +
823 132 : nOffset - anOffsets[i] + nLeaderSize;
824 132 : if (!CheckTrailer(strileData, nSizeFromLeader))
825 : {
826 0 : CPLDebug("GTiff", "Inconsistent trailer of block %d",
827 : nBlockId);
828 0 : bOK = false;
829 : }
830 : }
831 132 : if (!bOK)
832 : {
833 0 : return false;
834 : }
835 :
836 : {
837 132 : const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
838 132 : const vsi_l_offset nRealSize = nSizeFromLeader;
839 : #ifdef DEBUG_VERBOSE
840 : CPLDebug("GTiff",
841 : "Block %d found at offset " CPL_FRMT_GUIB
842 : " with size " CPL_FRMT_GUIB,
843 : nBlockId, nRealOffset, nRealSize);
844 : #endif
845 132 : m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
846 132 : nBlockId, std::pair(nRealOffset, nRealSize));
847 : }
848 :
849 : // Processing of mask
850 234 : if (!(entry.second.bTryMask &&
851 102 : m_poGDS->m_bMaskInterleavedWithImagery &&
852 102 : m_poGDS->GetRasterBand(1)->GetMaskBand() &&
853 102 : m_poGDS->m_poMaskDS))
854 : {
855 30 : continue;
856 : }
857 :
858 102 : bOK = false;
859 102 : const vsi_l_offset nMaskOffsetWithLeader =
860 102 : nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
861 204 : if (nMaskOffsetWithLeader + nLeaderSize <=
862 102 : anOffsets[i] + anSizes[i])
863 : {
864 : GUInt32 nMaskSizeFromLeader;
865 102 : memcpy(&nMaskSizeFromLeader,
866 102 : static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
867 102 : anOffsets[i],
868 : sizeof(nMaskSizeFromLeader));
869 102 : CPL_LSBPTR32(&nMaskSizeFromLeader);
870 204 : if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
871 204 : nTrailerSize <=
872 102 : anOffsets[i] + anSizes[i])
873 : {
874 102 : bOK = true;
875 102 : if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
876 : {
877 : // Check trailer consistency
878 : const GByte *strileMaskData =
879 102 : static_cast<GByte *>(apData[i]) + nOffset -
880 204 : anOffsets[i] + nLeaderSize + nSizeFromLeader +
881 102 : nTrailerSize + nLeaderSize;
882 102 : if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
883 : {
884 0 : CPLDebug("GTiff",
885 : "Inconsistent trailer of mask of block %d",
886 : nBlockId);
887 0 : bOK = false;
888 : }
889 : }
890 : }
891 102 : if (bOK)
892 : {
893 102 : const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
894 102 : nSizeFromLeader +
895 102 : nTrailerSize + nLeaderSize;
896 102 : const vsi_l_offset nRealSize = nMaskSizeFromLeader;
897 : #ifdef DEBUG_VERBOSE
898 : CPLDebug("GTiff",
899 : "Mask of block %d found at offset " CPL_FRMT_GUIB
900 : " with size " CPL_FRMT_GUIB,
901 : nBlockId, nRealOffset, nRealSize);
902 : #endif
903 :
904 102 : m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
905 102 : nBlockId, std::pair(nRealOffset, nRealSize));
906 : }
907 : }
908 102 : if (!bOK)
909 : {
910 0 : CPLDebug("GTiff",
911 : "Mask for block %d is not properly interleaved with "
912 : "imagery block",
913 : nBlockId);
914 : }
915 : }
916 36 : return true;
917 262 : };
918 :
919 262 : thandle_t th = TIFFClientdata(m_poGDS->m_hTIFF);
920 262 : if (!VSI_TIFFHasCachedRanges(th))
921 : {
922 234 : std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
923 234 : size_t nTotalSize = 0;
924 234 : const unsigned int nMaxRawBlockCacheSize = atoi(
925 234 : CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
926 234 : bool bGoOn = true;
927 543 : for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
928 : {
929 1010 : for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
930 : {
931 701 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(iX, iY);
932 701 : if (poBlock != nullptr)
933 : {
934 300 : poBlock->DropLock();
935 300 : continue;
936 : }
937 401 : int nBlockId = iX + iY * nBlocksPerRow;
938 401 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
939 0 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
940 401 : vsi_l_offset nOffset = 0;
941 401 : vsi_l_offset nSize = 0;
942 :
943 401 : if ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ||
944 0 : m_poGDS->nBands == 1) &&
945 401 : !m_poGDS->m_bStreamingIn &&
946 401 : m_poGDS->m_bBlockOrderRowMajor &&
947 195 : m_poGDS->m_bLeaderSizeAsUInt4)
948 : {
949 195 : OptimizedRetrievalOfOffsetSize(nBlockId, nOffset, nSize,
950 : nTotalSize,
951 : nMaxRawBlockCacheSize);
952 : }
953 : else
954 : {
955 206 : CPL_IGNORE_RET_VAL(
956 206 : m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nSize));
957 : }
958 401 : if (nSize)
959 : {
960 143 : if (nTotalSize + nSize < nMaxRawBlockCacheSize)
961 : {
962 : #ifdef DEBUG_VERBOSE
963 : CPLDebug("GTiff",
964 : "Precaching for block (%d, %d), " CPL_FRMT_GUIB
965 : "-" CPL_FRMT_GUIB,
966 : iX, iY, nOffset,
967 : nOffset + static_cast<size_t>(nSize) - 1);
968 : #endif
969 143 : aOffsetSize.push_back(
970 143 : std::pair(nOffset, static_cast<size_t>(nSize)));
971 143 : nTotalSize += static_cast<size_t>(nSize);
972 : }
973 : else
974 : {
975 0 : bGoOn = false;
976 : }
977 : }
978 : }
979 : }
980 :
981 234 : std::sort(aOffsetSize.begin(), aOffsetSize.end());
982 :
983 234 : if (nTotalSize > 0)
984 : {
985 41 : pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
986 41 : if (pBufferedData)
987 : {
988 41 : std::vector<vsi_l_offset> anOffsets;
989 41 : std::vector<size_t> anSizes;
990 41 : std::vector<void *> apData;
991 41 : anOffsets.push_back(aOffsetSize[0].first);
992 41 : apData.push_back(static_cast<GByte *>(pBufferedData));
993 41 : size_t nChunkSize = aOffsetSize[0].second;
994 41 : size_t nAccOffset = 0;
995 : // Try to merge contiguous or slightly overlapping ranges
996 143 : for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
997 : {
998 204 : if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
999 102 : aOffsetSize[i].first + aOffsetSize[i].second >=
1000 102 : aOffsetSize[i + 1].first)
1001 : {
1002 98 : const auto overlap = aOffsetSize[i].first +
1003 98 : aOffsetSize[i].second -
1004 98 : aOffsetSize[i + 1].first;
1005 : // That should always be the case for well behaved
1006 : // TIFF files.
1007 98 : if (aOffsetSize[i + 1].second > overlap)
1008 : {
1009 98 : nChunkSize += static_cast<size_t>(
1010 98 : aOffsetSize[i + 1].second - overlap);
1011 : }
1012 : }
1013 : else
1014 : {
1015 : // terminate current block
1016 4 : anSizes.push_back(nChunkSize);
1017 : #ifdef DEBUG_VERBOSE
1018 : CPLDebug("GTiff",
1019 : "Requesting range [" CPL_FRMT_GUIB
1020 : "-" CPL_FRMT_GUIB "]",
1021 : anOffsets.back(),
1022 : anOffsets.back() + anSizes.back() - 1);
1023 : #endif
1024 4 : nAccOffset += nChunkSize;
1025 : // start a new range
1026 4 : anOffsets.push_back(aOffsetSize[i + 1].first);
1027 4 : apData.push_back(static_cast<GByte *>(pBufferedData) +
1028 : nAccOffset);
1029 4 : nChunkSize = aOffsetSize[i + 1].second;
1030 : }
1031 : }
1032 : // terminate last block
1033 41 : anSizes.push_back(nChunkSize);
1034 : #ifdef DEBUG_VERBOSE
1035 : CPLDebug(
1036 : "GTiff",
1037 : "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
1038 : anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
1039 : #endif
1040 :
1041 41 : VSILFILE *fp = VSI_TIFFGetVSILFile(th);
1042 :
1043 41 : if (VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
1044 41 : &apData[0], &anOffsets[0], &anSizes[0],
1045 41 : fp) == 0)
1046 : {
1047 77 : if (!oMapStrileToOffsetByteCount.empty() &&
1048 36 : !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
1049 : apData))
1050 : {
1051 : // Retry without optimization
1052 0 : CPLFree(pBufferedData);
1053 0 : m_poGDS->m_bLeaderSizeAsUInt4 = false;
1054 : void *pRet =
1055 0 : CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
1056 : nBufXSize, nBufYSize, psExtraArg);
1057 0 : m_poGDS->m_bLeaderSizeAsUInt4 = true;
1058 0 : return pRet;
1059 : }
1060 :
1061 41 : VSI_TIFFSetCachedRanges(
1062 41 : th, static_cast<int>(anSizes.size()), &apData[0],
1063 41 : &anOffsets[0], &anSizes[0]);
1064 : }
1065 : }
1066 : }
1067 : }
1068 262 : return pBufferedData;
1069 : }
1070 :
1071 : /************************************************************************/
1072 : /* IGetDataCoverageStatus() */
1073 : /************************************************************************/
1074 :
1075 779 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
1076 : int nYSize, int nMaskFlagStop,
1077 : double *pdfDataPct)
1078 : {
1079 779 : if (eAccess == GA_Update)
1080 89 : m_poGDS->FlushCache(false);
1081 :
1082 779 : const int iXBlockStart = nXOff / nBlockXSize;
1083 779 : const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
1084 779 : const int iYBlockStart = nYOff / nBlockYSize;
1085 779 : const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
1086 779 : int nStatus = 0;
1087 779 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
1088 779 : GIntBig nPixelsData = 0;
1089 2377 : for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
1090 : {
1091 4187 : for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
1092 : {
1093 2589 : const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
1094 2589 : int nBlockId = nBlockIdBand0;
1095 2589 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1096 112 : nBlockId =
1097 112 : nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1098 2589 : vsi_l_offset nOffset = 0;
1099 2589 : vsi_l_offset nLength = 0;
1100 2589 : bool bHasData = false;
1101 2589 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength))
1102 : {
1103 1866 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
1104 : }
1105 : else
1106 : {
1107 723 : if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
1108 635 : m_poGDS->eAccess == GA_ReadOnly &&
1109 599 : ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
1110 599 : !m_bNoDataSetAsUInt64) ||
1111 0 : (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
1112 0 : (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
1113 0 : (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
1114 : {
1115 : VSIRangeStatus eStatus =
1116 599 : VSIFGetRangeStatusL(fp, nOffset, nLength);
1117 599 : if (eStatus == VSI_RANGE_STATUS_HOLE)
1118 : {
1119 0 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
1120 : }
1121 : else
1122 : {
1123 599 : bHasData = true;
1124 599 : }
1125 : }
1126 : else
1127 : {
1128 124 : bHasData = true;
1129 : }
1130 : }
1131 2589 : if (bHasData)
1132 : {
1133 723 : const int nXBlockRight =
1134 723 : (iX * nBlockXSize > INT_MAX - nBlockXSize)
1135 723 : ? INT_MAX
1136 723 : : (iX + 1) * nBlockXSize;
1137 723 : const int nYBlockBottom =
1138 723 : (iY * nBlockYSize > INT_MAX - nBlockYSize)
1139 723 : ? INT_MAX
1140 723 : : (iY + 1) * nBlockYSize;
1141 :
1142 1446 : nPixelsData += (static_cast<GIntBig>(
1143 723 : std::min(nXBlockRight, nXOff + nXSize)) -
1144 723 : std::max(iX * nBlockXSize, nXOff)) *
1145 723 : (std::min(nYBlockBottom, nYOff + nYSize) -
1146 723 : std::max(iY * nBlockYSize, nYOff));
1147 723 : nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
1148 : }
1149 2589 : if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
1150 : {
1151 717 : if (pdfDataPct)
1152 0 : *pdfDataPct = -1.0;
1153 717 : return nStatus;
1154 : }
1155 : }
1156 : }
1157 62 : if (pdfDataPct)
1158 8 : *pdfDataPct =
1159 8 : 100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
1160 62 : return nStatus;
1161 : }
1162 :
1163 : /************************************************************************/
1164 : /* IReadBlock() */
1165 : /************************************************************************/
1166 :
1167 2197610 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
1168 :
1169 : {
1170 2197610 : m_poGDS->Crystalize();
1171 :
1172 2197580 : GPtrDiff_t nBlockBufSize = 0;
1173 2197580 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
1174 : {
1175 55647 : nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
1176 : }
1177 : else
1178 : {
1179 2141960 : CPLAssert(nBlockXOff == 0);
1180 : nBlockBufSize =
1181 2141960 : static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
1182 : }
1183 :
1184 2197580 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
1185 :
1186 : /* -------------------------------------------------------------------- */
1187 : /* The bottom most partial tiles and strips are sometimes only */
1188 : /* partially encoded. This code reduces the requested data so */
1189 : /* an error won't be reported in this case. (#1179) */
1190 : /* -------------------------------------------------------------------- */
1191 2197590 : auto nBlockReqSize = nBlockBufSize;
1192 :
1193 2197590 : if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
1194 : {
1195 5950 : nBlockReqSize =
1196 5950 : (nBlockBufSize / nBlockYSize) *
1197 5950 : (nBlockYSize -
1198 : static_cast<int>(
1199 5950 : (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
1200 5950 : nRasterYSize));
1201 : }
1202 :
1203 : /* -------------------------------------------------------------------- */
1204 : /* Handle the case of a strip or tile that doesn't exist yet. */
1205 : /* Just set to zeros and return. */
1206 : /* -------------------------------------------------------------------- */
1207 2197590 : vsi_l_offset nOffset = 0;
1208 2197590 : bool bErrOccurred = false;
1209 4361910 : if (nBlockId != m_poGDS->m_nLoadedBlock &&
1210 2164310 : !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
1211 : {
1212 49284 : NullBlock(pImage);
1213 49284 : if (bErrOccurred)
1214 1 : return CE_Failure;
1215 49283 : return CE_None;
1216 : }
1217 :
1218 2148320 : if (m_poGDS->m_bStreamingIn &&
1219 10936 : !(m_poGDS->nBands > 1 &&
1220 10423 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
1221 10048 : nBlockId == m_poGDS->m_nLoadedBlock))
1222 : {
1223 3436 : if (nOffset < VSIFTellL(m_poGDS->m_fpL))
1224 : {
1225 2000 : ReportError(CE_Failure, CPLE_NotSupported,
1226 : "Trying to load block %d at offset " CPL_FRMT_GUIB
1227 : " whereas current pos is " CPL_FRMT_GUIB
1228 : " (backward read not supported)",
1229 : nBlockId, static_cast<GUIntBig>(nOffset),
1230 1000 : static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
1231 1000 : return CE_Failure;
1232 : }
1233 : }
1234 :
1235 : /* -------------------------------------------------------------------- */
1236 : /* Handle simple case (separate, onesampleperpixel) */
1237 : /* -------------------------------------------------------------------- */
1238 2147320 : CPLErr eErr = CE_None;
1239 2147320 : if (m_poGDS->nBands == 1 ||
1240 104378 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1241 : {
1242 2054440 : if (nBlockReqSize < nBlockBufSize)
1243 2306 : memset(pImage, 0, nBlockBufSize);
1244 :
1245 2054440 : if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
1246 : {
1247 61 : memset(pImage, 0, nBlockBufSize);
1248 61 : return CE_Failure;
1249 : }
1250 : }
1251 : else
1252 : {
1253 : /* --------------------------------------------------------------------
1254 : */
1255 : /* Load desired block */
1256 : /* --------------------------------------------------------------------
1257 : */
1258 92877 : eErr = m_poGDS->LoadBlockBuf(nBlockId);
1259 92960 : if (eErr != CE_None)
1260 : {
1261 38 : memset(pImage, 0,
1262 76 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
1263 38 : GDALGetDataTypeSizeBytes(eDataType));
1264 38 : return eErr;
1265 : }
1266 :
1267 92922 : bool bDoCopyWords = true;
1268 61142 : if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
1269 55679 : eAccess == GA_ReadOnly &&
1270 47124 : (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
1271 46774 : ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
1272 1289 : (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
1273 154337 : (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
1274 92395 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
1275 46222 : GDALGetDataTypeSizeBytes(eDataType) <
1276 46173 : GDALGetCacheMax64() / m_poGDS->nBands)
1277 : {
1278 46153 : bDoCopyWords = false;
1279 : void *ppDestBuffers[4];
1280 46153 : GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
1281 : nullptr};
1282 195914 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
1283 : {
1284 149683 : if (iBand == nBand)
1285 : {
1286 46142 : ppDestBuffers[iBand - 1] = pImage;
1287 : }
1288 : else
1289 : {
1290 : GDALRasterBlock *poBlock =
1291 103541 : m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
1292 103581 : nBlockXOff, nBlockYOff, true);
1293 103624 : if (poBlock == nullptr)
1294 : {
1295 0 : bDoCopyWords = true;
1296 0 : break;
1297 : }
1298 103624 : ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
1299 103619 : apoLockedBlocks[iBand - 1] = poBlock;
1300 : }
1301 : }
1302 46231 : if (!bDoCopyWords)
1303 : {
1304 46197 : GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
1305 46197 : m_poGDS->nBands, ppDestBuffers, eDataType,
1306 46197 : static_cast<size_t>(nBlockXSize) *
1307 46197 : nBlockYSize);
1308 : }
1309 196055 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
1310 : {
1311 149853 : if (apoLockedBlocks[iBand - 1])
1312 : {
1313 103653 : apoLockedBlocks[iBand - 1]->DropLock();
1314 : }
1315 : }
1316 : }
1317 :
1318 92923 : if (bDoCopyWords)
1319 : {
1320 46725 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
1321 46725 : GByte *pabyImage =
1322 46725 : m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
1323 :
1324 46725 : GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
1325 : pImage, eDataType, nWordBytes,
1326 46725 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
1327 :
1328 46725 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
1329 : }
1330 : }
1331 :
1332 2147260 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
1333 :
1334 2147260 : return eErr;
1335 : }
1336 :
1337 : /************************************************************************/
1338 : /* CacheMaskForBlock() */
1339 : /************************************************************************/
1340 :
1341 2148150 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
1342 :
1343 : {
1344 : // Preload mask data if layout compatible and we have cached ranges
1345 2148260 : if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
1346 109 : VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
1347 : {
1348 98 : auto poBand = cpl::down_cast<GTiffRasterBand *>(
1349 98 : m_poGDS->m_poMaskDS->GetRasterBand(1));
1350 294 : if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
1351 98 : poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
1352 : {
1353 : GDALRasterBlock *poBlock =
1354 94 : poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
1355 94 : if (poBlock)
1356 94 : poBlock->DropLock();
1357 : }
1358 : }
1359 2148150 : }
1360 :
1361 : /************************************************************************/
1362 : /* FillCacheForOtherBands() */
1363 : /************************************************************************/
1364 :
1365 46939 : CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
1366 :
1367 : {
1368 : /* -------------------------------------------------------------------- */
1369 : /* In the fairly common case of pixel interleaved 8bit data */
1370 : /* that is multi-band, lets push the rest of the data into the */
1371 : /* block cache too, to avoid (hopefully) having to redecode it. */
1372 : /* */
1373 : /* Our following logic actually depends on the fact that the */
1374 : /* this block is already loaded, so subsequent calls will end */
1375 : /* up back in this method and pull from the loaded block. */
1376 : /* */
1377 : /* Be careful not entering this portion of code from */
1378 : /* the other bands, otherwise we'll get very deep nested calls */
1379 : /* and O(nBands^2) performance ! */
1380 : /* */
1381 : /* If there are many bands and the block cache size is not big */
1382 : /* enough to accommodate the size of all the blocks, don't enter */
1383 : /* -------------------------------------------------------------------- */
1384 46939 : CPLErr eErr = CE_None;
1385 140817 : if (m_poGDS->nBands != 1 &&
1386 46939 : m_poGDS->nBands <
1387 46937 : 128 && // avoid caching for datasets with too many bands
1388 105850 : !m_poGDS->m_bLoadingOtherBands &&
1389 23944 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
1390 11972 : GDALGetDataTypeSizeBytes(eDataType) <
1391 11972 : GDALGetCacheMax64() / m_poGDS->nBands)
1392 : {
1393 11972 : m_poGDS->m_bLoadingOtherBands = true;
1394 :
1395 49873 : for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
1396 : {
1397 37901 : if (iOtherBand == nBand)
1398 11972 : continue;
1399 :
1400 : GDALRasterBlock *poBlock =
1401 25929 : m_poGDS->GetRasterBand(iOtherBand)
1402 25929 : ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
1403 25929 : if (poBlock == nullptr)
1404 : {
1405 0 : eErr = CE_Failure;
1406 0 : break;
1407 : }
1408 25929 : poBlock->DropLock();
1409 : }
1410 :
1411 11972 : m_poGDS->m_bLoadingOtherBands = false;
1412 : }
1413 :
1414 46939 : return eErr;
1415 : }
1416 :
1417 : /************************************************************************/
1418 : /* GetDescription() */
1419 : /************************************************************************/
1420 :
1421 205594 : const char *GTiffRasterBand::GetDescription() const
1422 : {
1423 205594 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1424 :
1425 205594 : return m_osDescription;
1426 : }
1427 :
1428 : /************************************************************************/
1429 : /* GetOffset() */
1430 : /************************************************************************/
1431 :
1432 212599 : double GTiffRasterBand::GetOffset(int *pbSuccess)
1433 :
1434 : {
1435 212599 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1436 :
1437 212599 : if (pbSuccess)
1438 6486 : *pbSuccess = m_bHaveOffsetScale;
1439 212599 : return m_dfOffset;
1440 : }
1441 :
1442 : /************************************************************************/
1443 : /* GetScale() */
1444 : /************************************************************************/
1445 :
1446 212600 : double GTiffRasterBand::GetScale(int *pbSuccess)
1447 :
1448 : {
1449 212600 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1450 :
1451 212600 : if (pbSuccess)
1452 6487 : *pbSuccess = m_bHaveOffsetScale;
1453 212600 : return m_dfScale;
1454 : }
1455 :
1456 : /************************************************************************/
1457 : /* GetUnitType() */
1458 : /************************************************************************/
1459 :
1460 204836 : const char *GTiffRasterBand::GetUnitType()
1461 :
1462 : {
1463 204836 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1464 204836 : if (m_osUnitType.empty())
1465 : {
1466 204757 : m_poGDS->LookForProjection();
1467 204757 : if (m_poGDS->m_pszVertUnit)
1468 9 : return m_poGDS->m_pszVertUnit;
1469 : }
1470 :
1471 204827 : return m_osUnitType.c_str();
1472 : }
1473 :
1474 : /************************************************************************/
1475 : /* GetMetadataDomainList() */
1476 : /************************************************************************/
1477 :
1478 12 : char **GTiffRasterBand::GetMetadataDomainList()
1479 : {
1480 12 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1481 :
1482 12 : return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1483 : }
1484 :
1485 : /************************************************************************/
1486 : /* GetMetadata() */
1487 : /************************************************************************/
1488 :
1489 15573 : char **GTiffRasterBand::GetMetadata(const char *pszDomain)
1490 :
1491 : {
1492 15573 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1493 : {
1494 15416 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1495 : }
1496 :
1497 15573 : return m_oGTiffMDMD.GetMetadata(pszDomain);
1498 : }
1499 :
1500 : /************************************************************************/
1501 : /* GetMetadataItem() */
1502 : /************************************************************************/
1503 :
1504 29850 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1505 : const char *pszDomain)
1506 :
1507 : {
1508 29850 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1509 : {
1510 7036 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1511 : }
1512 :
1513 29850 : if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1514 : {
1515 4196 : int nBlockXOff = 0;
1516 4196 : int nBlockYOff = 0;
1517 :
1518 4196 : if (EQUAL(pszName, "JPEGTABLES"))
1519 : {
1520 11 : uint32_t nJPEGTableSize = 0;
1521 11 : void *pJPEGTable = nullptr;
1522 11 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1523 11 : &nJPEGTableSize, &pJPEGTable) != 1 ||
1524 11 : pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1525 : {
1526 0 : return nullptr;
1527 : }
1528 11 : char *const pszHex = CPLBinaryToHex(
1529 : nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1530 11 : const char *pszReturn = CPLSPrintf("%s", pszHex);
1531 11 : CPLFree(pszHex);
1532 :
1533 11 : return pszReturn;
1534 : }
1535 :
1536 4185 : if (EQUAL(pszName, "IFD_OFFSET"))
1537 : {
1538 158 : return CPLSPrintf(CPL_FRMT_GUIB,
1539 79 : static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1540 : }
1541 :
1542 4106 : if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1543 : 2)
1544 : {
1545 3687 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1546 3686 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1547 19 : return nullptr;
1548 :
1549 3668 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1550 3668 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1551 : {
1552 2870 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1553 : }
1554 :
1555 3668 : vsi_l_offset nOffset = 0;
1556 3668 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset))
1557 : {
1558 190 : return nullptr;
1559 : }
1560 :
1561 3478 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1562 : }
1563 :
1564 419 : if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1565 : {
1566 419 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1567 418 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1568 2 : return nullptr;
1569 :
1570 417 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1571 417 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1572 : {
1573 1 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1574 : }
1575 :
1576 417 : vsi_l_offset nByteCount = 0;
1577 417 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount))
1578 : {
1579 89 : return nullptr;
1580 : }
1581 :
1582 328 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1583 0 : }
1584 : }
1585 25654 : else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1586 : {
1587 131 : if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1588 131 : return HasBlockCache() ? "1" : "0";
1589 : }
1590 :
1591 25523 : const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1592 :
1593 25523 : if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
1594 23312 : EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1595 : {
1596 : // to get a chance of emitting the warning about this legacy usage
1597 5158 : pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1598 : }
1599 25523 : return pszRet;
1600 : }
1601 :
1602 : /************************************************************************/
1603 : /* GetColorInterpretation() */
1604 : /************************************************************************/
1605 :
1606 225081 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1607 :
1608 : {
1609 225081 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1610 :
1611 225081 : return m_eBandInterp;
1612 : }
1613 :
1614 : /************************************************************************/
1615 : /* GetColorTable() */
1616 : /************************************************************************/
1617 :
1618 11282 : GDALColorTable *GTiffRasterBand::GetColorTable()
1619 :
1620 : {
1621 11282 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1622 :
1623 11282 : if (nBand == 1)
1624 9579 : return m_poGDS->m_poColorTable.get();
1625 :
1626 1703 : return nullptr;
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* GetNoDataValue() */
1631 : /************************************************************************/
1632 :
1633 815278 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1634 :
1635 : {
1636 815278 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1637 :
1638 815310 : int bSuccess = FALSE;
1639 815310 : double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1640 813504 : if (bSuccess)
1641 : {
1642 4 : if (pbSuccess)
1643 4 : *pbSuccess = TRUE;
1644 :
1645 4 : return dfNoDataValue;
1646 : }
1647 :
1648 813500 : if (m_bNoDataSet)
1649 : {
1650 2243 : if (pbSuccess)
1651 2210 : *pbSuccess = TRUE;
1652 :
1653 2243 : return m_dfNoDataValue;
1654 : }
1655 :
1656 811257 : if (m_poGDS->m_bNoDataSet)
1657 : {
1658 422828 : if (pbSuccess)
1659 422690 : *pbSuccess = TRUE;
1660 :
1661 422828 : return m_poGDS->m_dfNoDataValue;
1662 : }
1663 :
1664 388429 : if (m_bNoDataSetAsInt64)
1665 : {
1666 0 : if (pbSuccess)
1667 0 : *pbSuccess = TRUE;
1668 :
1669 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1670 : }
1671 :
1672 388429 : if (m_poGDS->m_bNoDataSetAsInt64)
1673 : {
1674 0 : if (pbSuccess)
1675 0 : *pbSuccess = TRUE;
1676 :
1677 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1678 : }
1679 :
1680 388429 : if (m_bNoDataSetAsUInt64)
1681 : {
1682 0 : if (pbSuccess)
1683 0 : *pbSuccess = TRUE;
1684 :
1685 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1686 : }
1687 :
1688 388429 : if (m_poGDS->m_bNoDataSetAsUInt64)
1689 : {
1690 0 : if (pbSuccess)
1691 0 : *pbSuccess = TRUE;
1692 :
1693 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1694 : }
1695 :
1696 388429 : if (pbSuccess)
1697 389848 : *pbSuccess = FALSE;
1698 388429 : return dfNoDataValue;
1699 : }
1700 :
1701 : /************************************************************************/
1702 : /* GetNoDataValueAsInt64() */
1703 : /************************************************************************/
1704 :
1705 25 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1706 :
1707 : {
1708 25 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1709 :
1710 25 : if (eDataType == GDT_UInt64)
1711 : {
1712 0 : CPLError(CE_Failure, CPLE_AppDefined,
1713 : "GetNoDataValueAsUInt64() should be called instead");
1714 0 : if (pbSuccess)
1715 0 : *pbSuccess = FALSE;
1716 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1717 : }
1718 25 : if (eDataType != GDT_Int64)
1719 : {
1720 0 : CPLError(CE_Failure, CPLE_AppDefined,
1721 : "GetNoDataValue() should be called instead");
1722 0 : if (pbSuccess)
1723 0 : *pbSuccess = FALSE;
1724 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1725 : }
1726 :
1727 25 : int bSuccess = FALSE;
1728 : const auto nNoDataValue =
1729 25 : GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1730 25 : if (bSuccess)
1731 : {
1732 0 : if (pbSuccess)
1733 0 : *pbSuccess = TRUE;
1734 :
1735 0 : return nNoDataValue;
1736 : }
1737 :
1738 25 : if (m_bNoDataSetAsInt64)
1739 : {
1740 2 : if (pbSuccess)
1741 2 : *pbSuccess = TRUE;
1742 :
1743 2 : return m_nNoDataValueInt64;
1744 : }
1745 :
1746 23 : if (m_poGDS->m_bNoDataSetAsInt64)
1747 : {
1748 7 : if (pbSuccess)
1749 6 : *pbSuccess = TRUE;
1750 :
1751 7 : return m_poGDS->m_nNoDataValueInt64;
1752 : }
1753 :
1754 16 : if (pbSuccess)
1755 16 : *pbSuccess = FALSE;
1756 16 : return nNoDataValue;
1757 : }
1758 :
1759 : /************************************************************************/
1760 : /* GetNoDataValueAsUInt64() */
1761 : /************************************************************************/
1762 :
1763 16 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1764 :
1765 : {
1766 16 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1767 :
1768 16 : if (eDataType == GDT_Int64)
1769 : {
1770 0 : CPLError(CE_Failure, CPLE_AppDefined,
1771 : "GetNoDataValueAsInt64() should be called instead");
1772 0 : if (pbSuccess)
1773 0 : *pbSuccess = FALSE;
1774 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1775 : }
1776 16 : if (eDataType != GDT_UInt64)
1777 : {
1778 0 : CPLError(CE_Failure, CPLE_AppDefined,
1779 : "GetNoDataValue() should be called instead");
1780 0 : if (pbSuccess)
1781 0 : *pbSuccess = FALSE;
1782 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1783 : }
1784 :
1785 16 : int bSuccess = FALSE;
1786 : const auto nNoDataValue =
1787 16 : GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1788 16 : if (bSuccess)
1789 : {
1790 0 : if (pbSuccess)
1791 0 : *pbSuccess = TRUE;
1792 :
1793 0 : return nNoDataValue;
1794 : }
1795 :
1796 16 : if (m_bNoDataSetAsUInt64)
1797 : {
1798 0 : if (pbSuccess)
1799 0 : *pbSuccess = TRUE;
1800 :
1801 0 : return m_nNoDataValueUInt64;
1802 : }
1803 :
1804 16 : if (m_poGDS->m_bNoDataSetAsUInt64)
1805 : {
1806 7 : if (pbSuccess)
1807 6 : *pbSuccess = TRUE;
1808 :
1809 7 : return m_poGDS->m_nNoDataValueUInt64;
1810 : }
1811 :
1812 9 : if (pbSuccess)
1813 9 : *pbSuccess = FALSE;
1814 9 : return nNoDataValue;
1815 : }
1816 :
1817 : /************************************************************************/
1818 : /* GetOverviewCount() */
1819 : /************************************************************************/
1820 :
1821 655192 : int GTiffRasterBand::GetOverviewCount()
1822 :
1823 : {
1824 655192 : if (!m_poGDS->AreOverviewsEnabled())
1825 30 : return 0;
1826 :
1827 655162 : m_poGDS->ScanDirectories();
1828 :
1829 655162 : if (m_poGDS->m_nOverviewCount > 0)
1830 : {
1831 4751 : return m_poGDS->m_nOverviewCount;
1832 : }
1833 :
1834 650411 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1835 650411 : if (nOverviewCount > 0)
1836 368 : return nOverviewCount;
1837 :
1838 : // Implicit JPEG overviews are normally hidden, except when doing
1839 : // IRasterIO() operations.
1840 650043 : if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1841 643415 : return m_poGDS->GetJPEGOverviewCount();
1842 :
1843 6628 : return 0;
1844 : }
1845 :
1846 : /************************************************************************/
1847 : /* GetOverview() */
1848 : /************************************************************************/
1849 :
1850 8305 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1851 :
1852 : {
1853 8305 : m_poGDS->ScanDirectories();
1854 :
1855 8305 : if (m_poGDS->m_nOverviewCount > 0)
1856 : {
1857 : // Do we have internal overviews?
1858 7736 : if (i < 0 || i >= m_poGDS->m_nOverviewCount)
1859 8 : return nullptr;
1860 :
1861 7728 : return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
1862 : }
1863 :
1864 569 : GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1865 569 : if (poOvrBand != nullptr)
1866 366 : return poOvrBand;
1867 :
1868 : // For consistency with GetOverviewCount(), we should also test
1869 : // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1870 : // to query them for testing purposes.
1871 203 : if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1872 164 : return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
1873 :
1874 39 : return nullptr;
1875 : }
1876 :
1877 : /************************************************************************/
1878 : /* GetMaskFlags() */
1879 : /************************************************************************/
1880 :
1881 17985 : int GTiffRasterBand::GetMaskFlags()
1882 : {
1883 17985 : m_poGDS->ScanDirectories();
1884 :
1885 17985 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1886 : {
1887 0 : return GMF_PER_DATASET;
1888 : }
1889 :
1890 17985 : if (m_poGDS->m_poMaskDS != nullptr)
1891 : {
1892 163 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1893 : {
1894 156 : return GMF_PER_DATASET;
1895 : }
1896 :
1897 7 : return 0;
1898 : }
1899 :
1900 17822 : if (m_poGDS->m_bIsOverview)
1901 : {
1902 379 : return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1903 : }
1904 :
1905 17443 : return GDALPamRasterBand::GetMaskFlags();
1906 : }
1907 :
1908 : /************************************************************************/
1909 : /* GetMaskBand() */
1910 : /************************************************************************/
1911 :
1912 119604 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1913 : {
1914 119604 : m_poGDS->ScanDirectories();
1915 :
1916 119644 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1917 : {
1918 2842 : return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1919 : }
1920 :
1921 116802 : if (m_poGDS->m_poMaskDS != nullptr)
1922 : {
1923 555 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1924 541 : return m_poGDS->m_poMaskDS->GetRasterBand(1);
1925 :
1926 14 : return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1927 : }
1928 :
1929 116247 : if (m_poGDS->m_bIsOverview)
1930 : {
1931 : GDALRasterBand *poBaseMask =
1932 114 : m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1933 114 : if (poBaseMask)
1934 : {
1935 114 : const int nOverviews = poBaseMask->GetOverviewCount();
1936 159 : for (int i = 0; i < nOverviews; i++)
1937 : {
1938 93 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1939 141 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1940 48 : poOvr->GetYSize() == GetYSize())
1941 : {
1942 48 : return poOvr;
1943 : }
1944 : }
1945 : }
1946 : }
1947 :
1948 116199 : return GDALPamRasterBand::GetMaskBand();
1949 : }
1950 :
1951 : /************************************************************************/
1952 : /* IsMaskBand() */
1953 : /************************************************************************/
1954 :
1955 9078 : bool GTiffRasterBand::IsMaskBand() const
1956 : {
1957 9109 : return (m_poGDS->m_poImageryDS != nullptr &&
1958 31 : m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
1959 16077 : m_eBandInterp == GCI_AlphaBand ||
1960 16046 : m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1961 : }
1962 :
1963 : /************************************************************************/
1964 : /* GetMaskValueRange() */
1965 : /************************************************************************/
1966 :
1967 0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1968 : {
1969 0 : if (!IsMaskBand())
1970 0 : return GMVR_UNKNOWN;
1971 0 : if (m_poGDS->m_nBitsPerSample == 1)
1972 0 : return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1973 0 : : GMVR_0_AND_1_ONLY;
1974 0 : return GMVR_UNKNOWN;
1975 : }
|