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