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 "gdal_priv.h"
28 : #include "gdal_mdreader.h"
29 : #include "gtiff.h"
30 : #include "tifvsi.h"
31 :
32 : /************************************************************************/
33 : /* GetDefaultRAT() */
34 : /************************************************************************/
35 :
36 307428 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
37 :
38 : {
39 307428 : if (m_poGDS->m_poBaseDS != nullptr)
40 52 : return m_poRAT.get();
41 :
42 307376 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
43 :
44 : // RAT from PAM has priority over RAT in GDAL_METADATA TIFF tag
45 307376 : if (!m_bRATTriedReadingFromPAM)
46 : {
47 305430 : m_bRATTriedReadingFromPAM = true;
48 305430 : auto poRAT = GDALPamRasterBand::GetDefaultRAT();
49 305430 : if (poRAT)
50 : {
51 2 : m_bRATSet = true;
52 2 : m_poRAT.reset(poRAT->Clone());
53 2 : return m_poRAT.get();
54 : }
55 : }
56 :
57 307374 : if (m_bRATSet)
58 1956 : return m_poRAT.get();
59 :
60 305418 : m_bRATSet = true;
61 :
62 : // Try reading from a .vat.dbf side car file
63 305418 : if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_osFilename.c_str()))
64 0 : return nullptr;
65 610836 : const std::string osVATDBF = m_poGDS->m_osFilename + ".vat.dbf";
66 305418 : CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
67 610799 : if (papszSiblingFiles &&
68 : // cppcheck-suppress knownConditionTrueFalse
69 305381 : GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
70 : {
71 : int iSibling =
72 305381 : CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
73 305381 : if (iSibling >= 0)
74 : {
75 3 : CPLString osFilename = m_poGDS->m_osFilename;
76 3 : osFilename.resize(
77 3 : m_poGDS->m_osFilename.size() -
78 3 : strlen(CPLGetFilename(m_poGDS->m_osFilename.c_str())));
79 3 : osFilename += papszSiblingFiles[iSibling];
80 3 : m_poRAT = GDALLoadVATDBF(osFilename.c_str());
81 : }
82 305381 : return m_poRAT.get();
83 : }
84 : VSIStatBufL sStatBuf;
85 37 : if (VSIStatL(osVATDBF.c_str(), &sStatBuf) == 0)
86 1 : m_poRAT = GDALLoadVATDBF(osVATDBF.c_str());
87 37 : return m_poRAT.get();
88 : }
89 :
90 : /************************************************************************/
91 : /* GetHistogram() */
92 : /************************************************************************/
93 :
94 24 : CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
95 : GUIntBig *panHistogram,
96 : int bIncludeOutOfRange, int bApproxOK,
97 : GDALProgressFunc pfnProgress,
98 : void *pProgressData)
99 : {
100 24 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
101 24 : return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
102 : bIncludeOutOfRange, bApproxOK,
103 24 : pfnProgress, pProgressData);
104 : }
105 :
106 : /************************************************************************/
107 : /* GetDefaultHistogram() */
108 : /************************************************************************/
109 :
110 22 : CPLErr GTiffRasterBand::GetDefaultHistogram(
111 : double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
112 : int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
113 : {
114 22 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
115 22 : return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
116 : ppanHistogram, bForce,
117 22 : pfnProgress, pProgressData);
118 : }
119 :
120 : /************************************************************************/
121 : /* DirectIO() */
122 : /************************************************************************/
123 :
124 : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
125 : // block reading. Restricted to simple TIFF configurations
126 : // (uncompressed data, standard data types). Particularly useful to extract
127 : // sub-windows of data on a large /vsicurl dataset).
128 : // Returns -1 if DirectIO() can't be supported on that file.
129 :
130 2522 : int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
131 : int nXSize, int nYSize, void *pData,
132 : int nBufXSize, int nBufYSize,
133 : GDALDataType eBufType, GSpacing nPixelSpace,
134 : GSpacing nLineSpace,
135 : GDALRasterIOExtraArg *psExtraArg)
136 : {
137 2522 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
138 5044 : if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
139 2522 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
140 795 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
141 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
142 2522 : IsBaseGTiffClass()))
143 : {
144 0 : return -1;
145 : }
146 2522 : m_poGDS->Crystalize();
147 :
148 : // Only know how to deal with nearest neighbour in this optimized routine.
149 2522 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
150 607 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
151 : {
152 66 : return -1;
153 : }
154 :
155 : #if DEBUG_VERBOSE
156 : CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
157 : nYSize, nBufXSize, nBufYSize);
158 : #endif
159 :
160 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
161 2456 : if (m_poGDS->GetAccess() == GA_Update)
162 : {
163 0 : m_poGDS->FlushCache(false);
164 0 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
165 : }
166 :
167 2456 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
168 : {
169 716 : const int nDTSize = nDTSizeBits / 8;
170 716 : const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
171 1432 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
172 716 : (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
173 : : 1));
174 716 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
175 : {
176 28 : m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
177 14 : VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
178 14 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
179 0 : return CE_Failure;
180 : }
181 :
182 716 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
183 : FetchBufferDirectIO oFetcher(fp,
184 716 : m_poGDS->m_pTempBufferForCommonDirectIO,
185 716 : nTempBufferForCommonDirectIOSize);
186 :
187 1432 : return m_poGDS->CommonDirectIOClassic(
188 : oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
189 716 : eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
190 : }
191 :
192 : // Get strip offsets.
193 1740 : toff_t *panTIFFOffsets = nullptr;
194 1740 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
195 3480 : &panTIFFOffsets) ||
196 1740 : panTIFFOffsets == nullptr)
197 : {
198 0 : return CE_Failure;
199 : }
200 :
201 : // Sub-sampling or over-sampling can only be done at last stage.
202 1740 : int nReqXSize = nXSize;
203 : // Can do sub-sampling at the extraction stage.
204 1740 : const int nReqYSize = std::min(nBufYSize, nYSize);
205 : // TODO(schwehr): Make ppData be GByte**.
206 : void **ppData =
207 1740 : static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
208 : vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
209 1740 : VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
210 : size_t *panSizes =
211 1740 : static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
212 1740 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
213 1740 : void *pTmpBuffer = nullptr;
214 1740 : int eErr = CE_None;
215 1740 : int nContigBands =
216 1740 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
217 1740 : int nSrcPixelSize = nDTSize * nContigBands;
218 :
219 1740 : if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
220 0 : eErr = CE_Failure;
221 1427 : else if (nXSize != nBufXSize || nYSize != nBufYSize ||
222 1427 : eBufType != eDataType ||
223 3167 : nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
224 : nContigBands > 1)
225 : {
226 : // We need a temporary buffer for over-sampling/sub-sampling
227 : // and/or data type conversion.
228 1534 : pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
229 1534 : if (pTmpBuffer == nullptr)
230 0 : eErr = CE_Failure;
231 : }
232 :
233 : // Prepare data extraction.
234 1740 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
235 :
236 58549 : for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
237 : {
238 56809 : if (pTmpBuffer == nullptr)
239 17766 : ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
240 : else
241 39043 : ppData[iLine] =
242 39043 : static_cast<GByte *>(pTmpBuffer) +
243 39043 : static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
244 56809 : int nSrcLine = 0;
245 56809 : if (nBufYSize < nYSize) // Sub-sampling in y.
246 3720 : nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
247 : else
248 53089 : nSrcLine = nYOff + iLine;
249 :
250 56809 : const int nBlockXOff = 0;
251 56809 : const int nBlockYOff = nSrcLine / nBlockYSize;
252 56809 : const int nYOffsetInBlock = nSrcLine % nBlockYSize;
253 56809 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
254 :
255 56809 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
256 56809 : if (panOffsets[iLine] == 0) // We don't support sparse files.
257 1047 : eErr = -1;
258 :
259 56809 : panOffsets[iLine] +=
260 56809 : (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
261 56809 : nSrcPixelSize;
262 56809 : panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
263 : }
264 :
265 : // Extract data from the file.
266 1740 : if (eErr == CE_None)
267 : {
268 693 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
269 : const int nRet =
270 693 : VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
271 693 : if (nRet != 0)
272 16 : eErr = CE_Failure;
273 : }
274 :
275 : // Byte-swap if necessary.
276 1740 : if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
277 : {
278 20878 : for (int iLine = 0; iLine < nReqYSize; ++iLine)
279 : {
280 20620 : if (GDALDataTypeIsComplex(eDataType))
281 10315 : GDALSwapWords(ppData[iLine], nDTSize / 2,
282 10315 : 2 * nReqXSize * nContigBands, nDTSize / 2);
283 : else
284 10305 : GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
285 : nDTSize);
286 : }
287 : }
288 :
289 : // Over-sampling/sub-sampling and/or data type conversion.
290 1740 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
291 1740 : if (eErr == CE_None && pTmpBuffer != nullptr)
292 : {
293 508 : const bool bOneByteCopy =
294 904 : (eDataType == eBufType &&
295 396 : (eDataType == GDT_Byte || eDataType == GDT_Int8));
296 150707 : for (int iY = 0; iY < nBufYSize; ++iY)
297 : {
298 300398 : const int iSrcY = nBufYSize <= nYSize
299 150199 : ? iY
300 120528 : : static_cast<int>((iY + 0.5) * dfSrcYInc);
301 :
302 300398 : GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
303 150199 : (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
304 150199 : GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
305 150199 : if (nBufXSize == nXSize)
306 : {
307 25952 : GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
308 : pabyDstData, eBufType,
309 : static_cast<int>(nPixelSpace), nBufXSize);
310 : }
311 : else
312 : {
313 124247 : if (bOneByteCopy)
314 : {
315 25435 : double dfSrcX = 0.5 * dfSrcXInc;
316 2147110 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
317 : {
318 2121670 : const int iSrcX = static_cast<int>(dfSrcX);
319 2121670 : pabyDstData[iX * nPixelSpace] =
320 2121670 : pabySrcData[iSrcX * nSrcPixelSize];
321 : }
322 : }
323 : else
324 : {
325 98812 : double dfSrcX = 0.5 * dfSrcXInc;
326 7730840 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
327 : {
328 7632030 : const int iSrcX = static_cast<int>(dfSrcX);
329 7632030 : GDALCopyWords(
330 7632030 : pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
331 7632030 : pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
332 : }
333 : }
334 : }
335 : }
336 : }
337 :
338 : // Cleanup.
339 1740 : CPLFree(pTmpBuffer);
340 1740 : CPLFree(ppData);
341 1740 : CPLFree(panOffsets);
342 1740 : CPLFree(panSizes);
343 :
344 1740 : return eErr;
345 : }
346 :
347 : /************************************************************************/
348 : /* GetVirtualMemAuto() */
349 : /************************************************************************/
350 :
351 17 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
352 : int *pnPixelSpace,
353 : GIntBig *pnLineSpace,
354 : char **papszOptions)
355 : {
356 17 : const char *pszImpl = CSLFetchNameValueDef(
357 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
358 17 : if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
359 16 : EQUAL(pszImpl, "TRUE"))
360 : {
361 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
362 1 : pnLineSpace, papszOptions);
363 : }
364 :
365 16 : CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
366 : pnLineSpace, papszOptions);
367 16 : if (psRet != nullptr)
368 : {
369 14 : CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
370 14 : return psRet;
371 : }
372 :
373 2 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
374 1 : EQUAL(pszImpl, "FALSE"))
375 : {
376 1 : return nullptr;
377 : }
378 :
379 1 : CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
380 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
381 1 : papszOptions);
382 : }
383 :
384 : /************************************************************************/
385 : /* DropReferenceVirtualMem() */
386 : /************************************************************************/
387 :
388 8 : void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
389 : {
390 : // This function may also be called when the dataset and rasterband
391 : // objects have been destroyed.
392 : // If they are still alive, it updates the reference counter of the
393 : // base mapping to invalidate the pointer to it if needed.
394 :
395 8 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
396 8 : GTiffRasterBand *poSelf = *ppoSelf;
397 :
398 8 : if (poSelf != nullptr)
399 : {
400 8 : if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
401 : {
402 4 : poSelf->m_poGDS->m_pBaseMapping = nullptr;
403 : }
404 8 : poSelf->m_aSetPSelf.erase(ppoSelf);
405 : }
406 8 : CPLFree(pUserData);
407 8 : }
408 :
409 : /************************************************************************/
410 : /* GetVirtualMemAutoInternal() */
411 : /************************************************************************/
412 :
413 20 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(GDALRWFlag eRWFlag,
414 : int *pnPixelSpace,
415 : GIntBig *pnLineSpace,
416 : char **papszOptions)
417 : {
418 20 : int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
419 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
420 14 : nLineSize *= m_poGDS->nBands;
421 :
422 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
423 : {
424 : // In case of a pixel interleaved file, we save virtual memory space
425 : // by reusing a base mapping that embraces the whole imagery.
426 14 : if (m_poGDS->m_pBaseMapping != nullptr)
427 : {
428 : // Offset between the base mapping and the requested mapping.
429 8 : vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
430 8 : GDALGetDataTypeSizeBytes(eDataType);
431 :
432 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
433 8 : CPLCalloc(1, sizeof(GTiffRasterBand *)));
434 8 : *ppoSelf = this;
435 :
436 24 : CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
437 8 : m_poGDS->m_pBaseMapping, nOffset,
438 8 : CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
439 : GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
440 8 : if (pVMem == nullptr)
441 : {
442 0 : CPLFree(ppoSelf);
443 0 : return nullptr;
444 : }
445 :
446 : // Mechanism used so that the memory mapping object can be
447 : // destroyed after the raster band.
448 8 : m_aSetPSelf.insert(ppoSelf);
449 8 : ++m_poGDS->m_nRefBaseMapping;
450 8 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
451 8 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
452 8 : *pnPixelSpace *= m_poGDS->nBands;
453 8 : *pnLineSpace = nLineSize;
454 8 : return pVMem;
455 : }
456 : }
457 :
458 12 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
459 :
460 12 : vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
461 :
462 24 : if (!(CPLIsVirtualMemFileMapAvailable() &&
463 12 : VSIFGetNativeFileDescriptorL(fp) != nullptr &&
464 : #if SIZEOF_VOIDP == 4
465 : nLength == static_cast<size_t>(nLength) &&
466 : #endif
467 10 : m_poGDS->m_nCompression == COMPRESSION_NONE &&
468 10 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
469 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
470 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
471 10 : m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
472 10 : !TIFFIsTiled(m_poGDS->m_hTIFF) &&
473 10 : !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
474 : {
475 2 : return nullptr;
476 : }
477 :
478 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
479 10 : if (m_poGDS->GetAccess() == GA_Update)
480 : {
481 7 : m_poGDS->FlushCache(false);
482 7 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
483 : }
484 :
485 : // Get strip offsets.
486 10 : toff_t *panTIFFOffsets = nullptr;
487 10 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
488 20 : &panTIFFOffsets) ||
489 10 : panTIFFOffsets == nullptr)
490 : {
491 0 : return nullptr;
492 : }
493 :
494 10 : GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
495 10 : GDALGetDataTypeSizeBytes(eDataType);
496 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
497 4 : nBlockSize *= m_poGDS->nBands;
498 :
499 10 : int nBlocks = m_poGDS->m_nBlocksPerBand;
500 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
501 6 : nBlocks *= m_poGDS->nBands;
502 10 : int i = 0; // Used after for.
503 103 : for (; i < nBlocks; ++i)
504 : {
505 100 : if (panTIFFOffsets[i] != 0)
506 7 : break;
507 : }
508 10 : if (i == nBlocks)
509 : {
510 : // All zeroes.
511 3 : if (m_poGDS->eAccess == GA_Update)
512 : {
513 : // Initialize the file with empty blocks so that the file has
514 : // the appropriate size.
515 :
516 3 : toff_t *panByteCounts = nullptr;
517 3 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
518 6 : &panByteCounts) ||
519 3 : panByteCounts == nullptr)
520 : {
521 0 : return nullptr;
522 : }
523 3 : if (VSIFSeekL(fp, 0, SEEK_END) != 0)
524 0 : return nullptr;
525 3 : vsi_l_offset nBaseOffset = VSIFTellL(fp);
526 :
527 : // Just write one tile with libtiff to put it in appropriate state.
528 : GByte *pabyData =
529 3 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
530 3 : if (pabyData == nullptr)
531 : {
532 0 : return nullptr;
533 : }
534 3 : const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
535 : pabyData, nBlockSize);
536 3 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
537 3 : VSIFree(pabyData);
538 3 : if (ret != nBlockSize)
539 : {
540 0 : return nullptr;
541 : }
542 3 : CPLAssert(panTIFFOffsets[0] == nBaseOffset);
543 3 : CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
544 :
545 : // Now simulate the writing of other blocks.
546 3 : assert(nBlocks > 0);
547 3 : assert(static_cast<vsi_l_offset>(nBlockSize) <
548 : std::numeric_limits<vsi_l_offset>::max() / nBlocks);
549 3 : const vsi_l_offset nDataSize =
550 3 : static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
551 3 : if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
552 0 : return nullptr;
553 :
554 93 : for (i = 1; i < nBlocks; ++i)
555 : {
556 90 : panTIFFOffsets[i] =
557 90 : nBaseOffset + i * static_cast<toff_t>(nBlockSize);
558 90 : panByteCounts[i] = nBlockSize;
559 : }
560 : }
561 : else
562 : {
563 0 : CPLDebug("GTiff", "Sparse files not supported in file mapping");
564 0 : return nullptr;
565 : }
566 : }
567 :
568 10 : GIntBig nBlockSpacing = 0;
569 10 : bool bCompatibleSpacing = true;
570 10 : toff_t nPrevOffset = 0;
571 229 : for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
572 : {
573 219 : toff_t nCurOffset = 0;
574 219 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
575 96 : nCurOffset =
576 96 : panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
577 : else
578 123 : nCurOffset = panTIFFOffsets[i];
579 219 : if (nCurOffset == 0)
580 : {
581 0 : bCompatibleSpacing = false;
582 0 : break;
583 : }
584 219 : if (i > 0)
585 : {
586 209 : const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
587 209 : if (i == 1)
588 : {
589 10 : if (nCurSpacing !=
590 10 : static_cast<GIntBig>(nBlockYSize) * nLineSize)
591 : {
592 0 : bCompatibleSpacing = false;
593 0 : break;
594 : }
595 10 : nBlockSpacing = nCurSpacing;
596 : }
597 199 : else if (nBlockSpacing != nCurSpacing)
598 : {
599 0 : bCompatibleSpacing = false;
600 0 : break;
601 : }
602 : }
603 219 : nPrevOffset = nCurOffset;
604 : }
605 :
606 10 : if (!bCompatibleSpacing)
607 : {
608 0 : return nullptr;
609 : }
610 :
611 10 : vsi_l_offset nOffset = 0;
612 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
613 : {
614 4 : CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
615 4 : nOffset = panTIFFOffsets[0];
616 : }
617 : else
618 : {
619 6 : nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
620 : }
621 10 : CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
622 : fp, nOffset, nLength,
623 : eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
624 : nullptr, nullptr);
625 10 : if (pVMem == nullptr)
626 : {
627 0 : return nullptr;
628 : }
629 :
630 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
631 : {
632 : // TODO(schwehr): Revisit this block.
633 4 : m_poGDS->m_pBaseMapping = pVMem;
634 4 : pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
635 : papszOptions);
636 : // Drop ref on base mapping.
637 4 : CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
638 4 : if (pVMem == nullptr)
639 0 : m_poGDS->m_pBaseMapping = nullptr;
640 : }
641 : else
642 : {
643 6 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
644 6 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
645 0 : *pnPixelSpace *= m_poGDS->nBands;
646 6 : *pnLineSpace = nLineSize;
647 : }
648 10 : return pVMem;
649 : }
650 :
651 : /************************************************************************/
652 : /* IGetDataCoverageStatus() */
653 : /************************************************************************/
654 :
655 900 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
656 : int nYSize, int nMaskFlagStop,
657 : double *pdfDataPct)
658 : {
659 900 : if (eAccess == GA_Update)
660 95 : m_poGDS->FlushCache(false);
661 :
662 900 : const int iXBlockStart = nXOff / nBlockXSize;
663 900 : const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
664 900 : const int iYBlockStart = nYOff / nBlockYSize;
665 900 : const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
666 900 : int nStatus = 0;
667 900 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
668 900 : GIntBig nPixelsData = 0;
669 2498 : for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
670 : {
671 4308 : for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
672 : {
673 2710 : const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
674 2710 : int nBlockId = nBlockIdBand0;
675 2710 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
676 136 : nBlockId =
677 136 : nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
678 2710 : vsi_l_offset nOffset = 0;
679 2710 : vsi_l_offset nLength = 0;
680 2710 : bool bHasData = false;
681 2710 : bool bError = false;
682 2710 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
683 : &bError))
684 : {
685 1866 : if (bError)
686 838 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
687 1866 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
688 : }
689 : else
690 : {
691 844 : if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
692 733 : m_poGDS->eAccess == GA_ReadOnly &&
693 691 : ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
694 691 : !m_bNoDataSetAsUInt64) ||
695 0 : (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
696 0 : (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
697 0 : (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
698 : {
699 : VSIRangeStatus eStatus =
700 691 : VSIFGetRangeStatusL(fp, nOffset, nLength);
701 691 : if (eStatus == VSI_RANGE_STATUS_HOLE)
702 : {
703 0 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
704 : }
705 : else
706 : {
707 691 : bHasData = true;
708 691 : }
709 : }
710 : else
711 : {
712 153 : bHasData = true;
713 : }
714 : }
715 2710 : if (bHasData)
716 : {
717 844 : const int nXBlockRight =
718 844 : (iX * nBlockXSize > INT_MAX - nBlockXSize)
719 844 : ? INT_MAX
720 844 : : (iX + 1) * nBlockXSize;
721 844 : const int nYBlockBottom =
722 844 : (iY * nBlockYSize > INT_MAX - nBlockYSize)
723 844 : ? INT_MAX
724 844 : : (iY + 1) * nBlockYSize;
725 :
726 1688 : nPixelsData += (static_cast<GIntBig>(
727 844 : std::min(nXBlockRight, nXOff + nXSize)) -
728 844 : std::max(iX * nBlockXSize, nXOff)) *
729 844 : (std::min(nYBlockBottom, nYOff + nYSize) -
730 844 : std::max(iY * nBlockYSize, nYOff));
731 844 : nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
732 : }
733 2710 : if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
734 : {
735 838 : if (pdfDataPct)
736 0 : *pdfDataPct = -1.0;
737 838 : return nStatus;
738 : }
739 : }
740 : }
741 62 : if (pdfDataPct)
742 8 : *pdfDataPct =
743 8 : 100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
744 62 : return nStatus;
745 : }
746 :
747 : /************************************************************************/
748 : /* IReadBlock() */
749 : /************************************************************************/
750 :
751 2310940 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
752 :
753 : {
754 2310940 : m_poGDS->Crystalize();
755 :
756 2310930 : GPtrDiff_t nBlockBufSize = 0;
757 2310930 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
758 : {
759 57905 : nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
760 : }
761 : else
762 : {
763 2253020 : CPLAssert(nBlockXOff == 0);
764 : nBlockBufSize =
765 2253020 : static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
766 : }
767 :
768 2310920 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* The bottom most partial tiles and strips are sometimes only */
772 : /* partially encoded. This code reduces the requested data so */
773 : /* an error won't be reported in this case. (#1179) */
774 : /* -------------------------------------------------------------------- */
775 2310920 : auto nBlockReqSize = nBlockBufSize;
776 :
777 2310920 : if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
778 : {
779 6307 : nBlockReqSize =
780 6307 : (nBlockBufSize / nBlockYSize) *
781 6307 : (nBlockYSize -
782 : static_cast<int>(
783 6307 : (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
784 6307 : nRasterYSize));
785 : }
786 :
787 : /* -------------------------------------------------------------------- */
788 : /* Handle the case of a strip or tile that doesn't exist yet. */
789 : /* Just set to zeros and return. */
790 : /* -------------------------------------------------------------------- */
791 2310920 : vsi_l_offset nOffset = 0;
792 2310920 : bool bErrOccurred = false;
793 4488940 : if (nBlockId != m_poGDS->m_nLoadedBlock &&
794 2178010 : !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
795 : {
796 50229 : NullBlock(pImage);
797 50229 : if (bErrOccurred)
798 1 : return CE_Failure;
799 50228 : return CE_None;
800 : }
801 :
802 2260700 : if (m_poGDS->m_bStreamingIn &&
803 10936 : !(m_poGDS->nBands > 1 &&
804 10423 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
805 10048 : nBlockId == m_poGDS->m_nLoadedBlock))
806 : {
807 3436 : if (nOffset < VSIFTellL(m_poGDS->m_fpL))
808 : {
809 2000 : ReportError(CE_Failure, CPLE_NotSupported,
810 : "Trying to load block %d at offset " CPL_FRMT_GUIB
811 : " whereas current pos is " CPL_FRMT_GUIB
812 : " (backward read not supported)",
813 : nBlockId, static_cast<GUIntBig>(nOffset),
814 1000 : static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
815 1000 : return CE_Failure;
816 : }
817 : }
818 :
819 : /* -------------------------------------------------------------------- */
820 : /* Handle simple case (separate, onesampleperpixel) */
821 : /* -------------------------------------------------------------------- */
822 2259700 : CPLErr eErr = CE_None;
823 2259700 : if (m_poGDS->nBands == 1 ||
824 208268 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
825 : {
826 2076190 : if (nBlockReqSize < nBlockBufSize)
827 2964 : memset(pImage, 0, nBlockBufSize);
828 :
829 2076190 : if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
830 : {
831 81 : memset(pImage, 0, nBlockBufSize);
832 81 : return CE_Failure;
833 : }
834 : }
835 : else
836 : {
837 : /* --------------------------------------------------------------------
838 : */
839 : /* Load desired block */
840 : /* --------------------------------------------------------------------
841 : */
842 183504 : eErr = m_poGDS->LoadBlockBuf(nBlockId);
843 183505 : if (eErr != CE_None)
844 : {
845 25 : memset(pImage, 0,
846 50 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
847 25 : GDALGetDataTypeSizeBytes(eDataType));
848 25 : return eErr;
849 : }
850 :
851 183480 : bool bDoCopyWords = true;
852 52077 : if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
853 46384 : eAccess == GA_ReadOnly &&
854 37125 : (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
855 36355 : ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
856 432 : (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
857 235827 : (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
858 72392 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
859 36196 : GDALGetDataTypeSizeBytes(eDataType) <
860 36196 : GDALGetCacheMax64() / m_poGDS->nBands)
861 : {
862 36196 : bDoCopyWords = false;
863 : void *ppDestBuffers[4];
864 36196 : GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
865 : nullptr};
866 155901 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
867 : {
868 119705 : if (iBand == nBand)
869 : {
870 36196 : ppDestBuffers[iBand - 1] = pImage;
871 : }
872 : else
873 : {
874 : GDALRasterBlock *poBlock =
875 83509 : m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
876 83509 : nBlockXOff, nBlockYOff, true);
877 83509 : if (poBlock == nullptr)
878 : {
879 0 : bDoCopyWords = true;
880 0 : break;
881 : }
882 83509 : ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
883 83509 : apoLockedBlocks[iBand - 1] = poBlock;
884 : }
885 : }
886 36196 : if (!bDoCopyWords)
887 : {
888 36196 : GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
889 36196 : m_poGDS->nBands, ppDestBuffers, eDataType,
890 36196 : static_cast<size_t>(nBlockXSize) *
891 36196 : nBlockYSize);
892 : }
893 155901 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
894 : {
895 119705 : if (apoLockedBlocks[iBand - 1])
896 : {
897 83509 : apoLockedBlocks[iBand - 1]->DropLock();
898 : }
899 : }
900 : }
901 :
902 183480 : if (bDoCopyWords)
903 : {
904 147284 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
905 147284 : GByte *pabyImage =
906 147284 : m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
907 :
908 147284 : GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
909 : pImage, eDataType, nWordBytes,
910 147284 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
911 :
912 147284 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
913 : }
914 : }
915 :
916 2259590 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
917 :
918 2259600 : return eErr;
919 : }
920 :
921 : /************************************************************************/
922 : /* CacheMaskForBlock() */
923 : /************************************************************************/
924 :
925 2261980 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
926 :
927 : {
928 : // Preload mask data if layout compatible and we have cached ranges
929 2262080 : if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
930 108 : VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
931 : {
932 97 : auto poBand = cpl::down_cast<GTiffRasterBand *>(
933 97 : m_poGDS->m_poMaskDS->GetRasterBand(1));
934 291 : if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
935 97 : poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
936 : {
937 : GDALRasterBlock *poBlock =
938 93 : poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
939 93 : if (poBlock)
940 93 : poBlock->DropLock();
941 : }
942 : }
943 2261970 : }
944 :
945 : /************************************************************************/
946 : /* FillCacheForOtherBands() */
947 : /************************************************************************/
948 :
949 147498 : CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
950 :
951 : {
952 : /* -------------------------------------------------------------------- */
953 : /* In the fairly common case of pixel interleaved 8bit data */
954 : /* that is multi-band, lets push the rest of the data into the */
955 : /* block cache too, to avoid (hopefully) having to redecode it. */
956 : /* */
957 : /* Our following logic actually depends on the fact that the */
958 : /* this block is already loaded, so subsequent calls will end */
959 : /* up back in this method and pull from the loaded block. */
960 : /* */
961 : /* Be careful not entering this portion of code from */
962 : /* the other bands, otherwise we'll get very deep nested calls */
963 : /* and O(nBands^2) performance ! */
964 : /* */
965 : /* If there are many bands and the block cache size is not big */
966 : /* enough to accommodate the size of all the blocks, don't enter */
967 : /* -------------------------------------------------------------------- */
968 147498 : CPLErr eErr = CE_None;
969 442494 : if (m_poGDS->nBands != 1 &&
970 147498 : m_poGDS->nBands <
971 49064 : 128 && // avoid caching for datasets with too many bands
972 307891 : !m_poGDS->m_bLoadingOtherBands &&
973 25790 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
974 12895 : GDALGetDataTypeSizeBytes(eDataType) <
975 12895 : GDALGetCacheMax64() / m_poGDS->nBands)
976 : {
977 12895 : m_poGDS->m_bLoadingOtherBands = true;
978 :
979 52923 : for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
980 : {
981 40028 : if (iOtherBand == nBand)
982 12895 : continue;
983 :
984 : GDALRasterBlock *poBlock =
985 27133 : m_poGDS->GetRasterBand(iOtherBand)
986 27133 : ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
987 27133 : if (poBlock == nullptr)
988 : {
989 0 : eErr = CE_Failure;
990 0 : break;
991 : }
992 27133 : poBlock->DropLock();
993 : }
994 :
995 12895 : m_poGDS->m_bLoadingOtherBands = false;
996 : }
997 :
998 147498 : return eErr;
999 : }
1000 :
1001 : /************************************************************************/
1002 : /* GetDescription() */
1003 : /************************************************************************/
1004 :
1005 308056 : const char *GTiffRasterBand::GetDescription() const
1006 : {
1007 308056 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1008 :
1009 308056 : return m_osDescription;
1010 : }
1011 :
1012 : /************************************************************************/
1013 : /* GetOffset() */
1014 : /************************************************************************/
1015 :
1016 315688 : double GTiffRasterBand::GetOffset(int *pbSuccess)
1017 :
1018 : {
1019 315688 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1020 :
1021 315688 : if (pbSuccess)
1022 7524 : *pbSuccess = m_bHaveOffsetScale;
1023 315688 : return m_dfOffset;
1024 : }
1025 :
1026 : /************************************************************************/
1027 : /* GetScale() */
1028 : /************************************************************************/
1029 :
1030 315691 : double GTiffRasterBand::GetScale(int *pbSuccess)
1031 :
1032 : {
1033 315691 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1034 :
1035 315691 : if (pbSuccess)
1036 7527 : *pbSuccess = m_bHaveOffsetScale;
1037 315691 : return m_dfScale;
1038 : }
1039 :
1040 : /************************************************************************/
1041 : /* GetUnitType() */
1042 : /************************************************************************/
1043 :
1044 306868 : const char *GTiffRasterBand::GetUnitType()
1045 :
1046 : {
1047 306868 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1048 306868 : if (m_osUnitType.empty())
1049 : {
1050 306675 : m_poGDS->LookForProjection();
1051 306675 : if (m_poGDS->m_pszVertUnit)
1052 9 : return m_poGDS->m_pszVertUnit;
1053 : }
1054 :
1055 306859 : return m_osUnitType.c_str();
1056 : }
1057 :
1058 : /************************************************************************/
1059 : /* GetMetadataDomainList() */
1060 : /************************************************************************/
1061 :
1062 13 : char **GTiffRasterBand::GetMetadataDomainList()
1063 : {
1064 13 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1065 :
1066 13 : m_poGDS->LoadENVIHdrIfNeeded();
1067 :
1068 13 : return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1069 : }
1070 :
1071 : /************************************************************************/
1072 : /* GetMetadata() */
1073 : /************************************************************************/
1074 :
1075 17259 : char **GTiffRasterBand::GetMetadata(const char *pszDomain)
1076 :
1077 : {
1078 17259 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1079 : {
1080 17075 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1081 :
1082 17075 : m_poGDS->LoadENVIHdrIfNeeded();
1083 : }
1084 184 : else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1085 : {
1086 0 : m_poGDS->LoadENVIHdrIfNeeded();
1087 : }
1088 :
1089 17259 : return m_oGTiffMDMD.GetMetadata(pszDomain);
1090 : }
1091 :
1092 : /************************************************************************/
1093 : /* GetMetadataItem() */
1094 : /************************************************************************/
1095 :
1096 23446 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1097 : const char *pszDomain)
1098 :
1099 : {
1100 23446 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1101 : {
1102 9039 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1103 :
1104 9039 : m_poGDS->LoadENVIHdrIfNeeded();
1105 : }
1106 14407 : else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1107 : {
1108 0 : m_poGDS->LoadENVIHdrIfNeeded();
1109 : }
1110 :
1111 23446 : if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1112 : {
1113 5240 : int nBlockXOff = 0;
1114 5240 : int nBlockYOff = 0;
1115 :
1116 5240 : if (EQUAL(pszName, "JPEGTABLES"))
1117 : {
1118 11 : uint32_t nJPEGTableSize = 0;
1119 11 : void *pJPEGTable = nullptr;
1120 11 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1121 11 : &nJPEGTableSize, &pJPEGTable) != 1 ||
1122 11 : pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1123 : {
1124 0 : return nullptr;
1125 : }
1126 11 : char *const pszHex = CPLBinaryToHex(
1127 : nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1128 11 : const char *pszReturn = CPLSPrintf("%s", pszHex);
1129 11 : CPLFree(pszHex);
1130 :
1131 11 : return pszReturn;
1132 : }
1133 :
1134 5229 : if (EQUAL(pszName, "IFD_OFFSET"))
1135 : {
1136 178 : return CPLSPrintf(CPL_FRMT_GUIB,
1137 89 : static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1138 : }
1139 :
1140 5140 : if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1141 : 2)
1142 : {
1143 4421 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1144 4420 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1145 19 : return nullptr;
1146 :
1147 4402 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1148 4402 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1149 : {
1150 3592 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1151 : }
1152 :
1153 4402 : vsi_l_offset nOffset = 0;
1154 4402 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1155 : nullptr))
1156 : {
1157 184 : return nullptr;
1158 : }
1159 :
1160 4218 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1161 : }
1162 :
1163 719 : if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1164 : {
1165 719 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1166 718 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1167 2 : return nullptr;
1168 :
1169 717 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1170 717 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1171 : {
1172 244 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1173 : }
1174 :
1175 717 : vsi_l_offset nByteCount = 0;
1176 717 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1177 : nullptr))
1178 : {
1179 86 : return nullptr;
1180 : }
1181 :
1182 631 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1183 0 : }
1184 : }
1185 18206 : else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1186 : {
1187 131 : if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1188 131 : return HasBlockCache() ? "1" : "0";
1189 : }
1190 :
1191 18075 : const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1192 :
1193 18075 : if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
1194 15574 : EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1195 : {
1196 : // to get a chance of emitting the warning about this legacy usage
1197 3620 : pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1198 : }
1199 18075 : return pszRet;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* GetColorInterpretation() */
1204 : /************************************************************************/
1205 :
1206 460646 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1207 :
1208 : {
1209 460646 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1210 :
1211 460646 : return m_eBandInterp;
1212 : }
1213 :
1214 : /************************************************************************/
1215 : /* GetColorTable() */
1216 : /************************************************************************/
1217 :
1218 12265 : GDALColorTable *GTiffRasterBand::GetColorTable()
1219 :
1220 : {
1221 12265 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1222 :
1223 12265 : if (nBand == 1)
1224 10348 : return m_poGDS->m_poColorTable.get();
1225 :
1226 1917 : return nullptr;
1227 : }
1228 :
1229 : /************************************************************************/
1230 : /* GetNoDataValue() */
1231 : /************************************************************************/
1232 :
1233 953297 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1234 :
1235 : {
1236 953297 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1237 :
1238 953297 : int bSuccess = FALSE;
1239 953297 : double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1240 953292 : if (bSuccess)
1241 : {
1242 4 : if (pbSuccess)
1243 4 : *pbSuccess = TRUE;
1244 :
1245 4 : return dfNoDataValue;
1246 : }
1247 :
1248 953288 : if (m_bNoDataSet)
1249 : {
1250 2751 : if (pbSuccess)
1251 2711 : *pbSuccess = TRUE;
1252 :
1253 2751 : return m_dfNoDataValue;
1254 : }
1255 :
1256 950537 : if (m_poGDS->m_bNoDataSet)
1257 : {
1258 423452 : if (pbSuccess)
1259 423229 : *pbSuccess = TRUE;
1260 :
1261 423452 : return m_poGDS->m_dfNoDataValue;
1262 : }
1263 :
1264 527085 : if (m_bNoDataSetAsInt64)
1265 : {
1266 0 : if (pbSuccess)
1267 0 : *pbSuccess = TRUE;
1268 :
1269 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1270 : }
1271 :
1272 527085 : if (m_poGDS->m_bNoDataSetAsInt64)
1273 : {
1274 0 : if (pbSuccess)
1275 0 : *pbSuccess = TRUE;
1276 :
1277 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1278 : }
1279 :
1280 527085 : if (m_bNoDataSetAsUInt64)
1281 : {
1282 0 : if (pbSuccess)
1283 0 : *pbSuccess = TRUE;
1284 :
1285 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1286 : }
1287 :
1288 527085 : if (m_poGDS->m_bNoDataSetAsUInt64)
1289 : {
1290 0 : if (pbSuccess)
1291 0 : *pbSuccess = TRUE;
1292 :
1293 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1294 : }
1295 :
1296 527085 : if (pbSuccess)
1297 527089 : *pbSuccess = FALSE;
1298 527085 : return dfNoDataValue;
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* GetNoDataValueAsInt64() */
1303 : /************************************************************************/
1304 :
1305 35 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1306 :
1307 : {
1308 35 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1309 :
1310 35 : if (eDataType == GDT_UInt64)
1311 : {
1312 0 : CPLError(CE_Failure, CPLE_AppDefined,
1313 : "GetNoDataValueAsUInt64() should be called instead");
1314 0 : if (pbSuccess)
1315 0 : *pbSuccess = FALSE;
1316 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1317 : }
1318 35 : if (eDataType != GDT_Int64)
1319 : {
1320 0 : CPLError(CE_Failure, CPLE_AppDefined,
1321 : "GetNoDataValue() should be called instead");
1322 0 : if (pbSuccess)
1323 0 : *pbSuccess = FALSE;
1324 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1325 : }
1326 :
1327 35 : int bSuccess = FALSE;
1328 : const auto nNoDataValue =
1329 35 : GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1330 35 : if (bSuccess)
1331 : {
1332 0 : if (pbSuccess)
1333 0 : *pbSuccess = TRUE;
1334 :
1335 0 : return nNoDataValue;
1336 : }
1337 :
1338 35 : if (m_bNoDataSetAsInt64)
1339 : {
1340 2 : if (pbSuccess)
1341 2 : *pbSuccess = TRUE;
1342 :
1343 2 : return m_nNoDataValueInt64;
1344 : }
1345 :
1346 33 : if (m_poGDS->m_bNoDataSetAsInt64)
1347 : {
1348 7 : if (pbSuccess)
1349 6 : *pbSuccess = TRUE;
1350 :
1351 7 : return m_poGDS->m_nNoDataValueInt64;
1352 : }
1353 :
1354 26 : if (pbSuccess)
1355 26 : *pbSuccess = FALSE;
1356 26 : return nNoDataValue;
1357 : }
1358 :
1359 : /************************************************************************/
1360 : /* GetNoDataValueAsUInt64() */
1361 : /************************************************************************/
1362 :
1363 21 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1364 :
1365 : {
1366 21 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1367 :
1368 21 : if (eDataType == GDT_Int64)
1369 : {
1370 0 : CPLError(CE_Failure, CPLE_AppDefined,
1371 : "GetNoDataValueAsInt64() should be called instead");
1372 0 : if (pbSuccess)
1373 0 : *pbSuccess = FALSE;
1374 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1375 : }
1376 21 : if (eDataType != GDT_UInt64)
1377 : {
1378 0 : CPLError(CE_Failure, CPLE_AppDefined,
1379 : "GetNoDataValue() should be called instead");
1380 0 : if (pbSuccess)
1381 0 : *pbSuccess = FALSE;
1382 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1383 : }
1384 :
1385 21 : int bSuccess = FALSE;
1386 : const auto nNoDataValue =
1387 21 : GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1388 21 : if (bSuccess)
1389 : {
1390 0 : if (pbSuccess)
1391 0 : *pbSuccess = TRUE;
1392 :
1393 0 : return nNoDataValue;
1394 : }
1395 :
1396 21 : if (m_bNoDataSetAsUInt64)
1397 : {
1398 0 : if (pbSuccess)
1399 0 : *pbSuccess = TRUE;
1400 :
1401 0 : return m_nNoDataValueUInt64;
1402 : }
1403 :
1404 21 : if (m_poGDS->m_bNoDataSetAsUInt64)
1405 : {
1406 7 : if (pbSuccess)
1407 6 : *pbSuccess = TRUE;
1408 :
1409 7 : return m_poGDS->m_nNoDataValueUInt64;
1410 : }
1411 :
1412 14 : if (pbSuccess)
1413 14 : *pbSuccess = FALSE;
1414 14 : return nNoDataValue;
1415 : }
1416 :
1417 : /************************************************************************/
1418 : /* GetOverviewCount() */
1419 : /************************************************************************/
1420 :
1421 1319810 : int GTiffRasterBand::GetOverviewCount()
1422 :
1423 : {
1424 1319810 : if (!m_poGDS->AreOverviewsEnabled())
1425 30 : return 0;
1426 :
1427 1319780 : m_poGDS->ScanDirectories();
1428 :
1429 1319780 : if (m_poGDS->m_nOverviewCount > 0)
1430 : {
1431 267311 : return m_poGDS->m_nOverviewCount;
1432 : }
1433 :
1434 1052460 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1435 1052460 : if (nOverviewCount > 0)
1436 391 : return nOverviewCount;
1437 :
1438 : // Implicit JPEG overviews are normally hidden, except when doing
1439 : // IRasterIO() operations.
1440 1052070 : if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1441 1044190 : return m_poGDS->GetJPEGOverviewCount();
1442 :
1443 7887 : return 0;
1444 : }
1445 :
1446 : /************************************************************************/
1447 : /* GetOverview() */
1448 : /************************************************************************/
1449 :
1450 74178 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1451 :
1452 : {
1453 74178 : m_poGDS->ScanDirectories();
1454 :
1455 74178 : if (m_poGDS->m_nOverviewCount > 0)
1456 : {
1457 : // Do we have internal overviews?
1458 73582 : if (i < 0 || i >= m_poGDS->m_nOverviewCount)
1459 8 : return nullptr;
1460 :
1461 73574 : return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
1462 : }
1463 :
1464 596 : GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1465 596 : if (poOvrBand != nullptr)
1466 391 : return poOvrBand;
1467 :
1468 : // For consistency with GetOverviewCount(), we should also test
1469 : // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1470 : // to query them for testing purposes.
1471 205 : if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1472 164 : return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
1473 :
1474 41 : return nullptr;
1475 : }
1476 :
1477 : /************************************************************************/
1478 : /* GetMaskFlags() */
1479 : /************************************************************************/
1480 :
1481 21714 : int GTiffRasterBand::GetMaskFlags()
1482 : {
1483 21714 : m_poGDS->ScanDirectories();
1484 :
1485 21714 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1486 : {
1487 0 : return GMF_PER_DATASET;
1488 : }
1489 :
1490 21714 : if (m_poGDS->m_poMaskDS != nullptr)
1491 : {
1492 215 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1493 : {
1494 207 : return GMF_PER_DATASET;
1495 : }
1496 :
1497 8 : return 0;
1498 : }
1499 :
1500 21499 : if (m_poGDS->m_bIsOverview)
1501 : {
1502 441 : return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1503 : }
1504 :
1505 21058 : return GDALPamRasterBand::GetMaskFlags();
1506 : }
1507 :
1508 : /************************************************************************/
1509 : /* GetMaskBand() */
1510 : /************************************************************************/
1511 :
1512 117431 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1513 : {
1514 117431 : m_poGDS->ScanDirectories();
1515 :
1516 117432 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1517 : {
1518 51 : return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1519 : }
1520 :
1521 117381 : if (m_poGDS->m_poMaskDS != nullptr)
1522 : {
1523 691 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1524 674 : return m_poGDS->m_poMaskDS->GetRasterBand(1);
1525 :
1526 17 : return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1527 : }
1528 :
1529 116690 : if (m_poGDS->m_bIsOverview)
1530 : {
1531 : GDALRasterBand *poBaseMask =
1532 119 : m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1533 119 : if (poBaseMask)
1534 : {
1535 119 : const int nOverviews = poBaseMask->GetOverviewCount();
1536 164 : for (int i = 0; i < nOverviews; i++)
1537 : {
1538 93 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1539 141 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1540 48 : poOvr->GetYSize() == GetYSize())
1541 : {
1542 48 : return poOvr;
1543 : }
1544 : }
1545 : }
1546 : }
1547 :
1548 116642 : return GDALPamRasterBand::GetMaskBand();
1549 : }
1550 :
1551 : /************************************************************************/
1552 : /* IsMaskBand() */
1553 : /************************************************************************/
1554 :
1555 1035 : bool GTiffRasterBand::IsMaskBand() const
1556 : {
1557 1067 : return (m_poGDS->m_poImageryDS != nullptr &&
1558 32 : m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
1559 2015 : m_eBandInterp == GCI_AlphaBand ||
1560 1983 : m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1561 : }
1562 :
1563 : /************************************************************************/
1564 : /* GetMaskValueRange() */
1565 : /************************************************************************/
1566 :
1567 0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1568 : {
1569 0 : if (!IsMaskBand())
1570 0 : return GMVR_UNKNOWN;
1571 0 : if (m_poGDS->m_nBitsPerSample == 1)
1572 0 : return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1573 0 : : GMVR_0_AND_1_ONLY;
1574 0 : return GMVR_UNKNOWN;
1575 : }
|