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