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 5497 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
37 :
38 : {
39 5497 : if (m_poGDS->m_poBaseDS != nullptr)
40 47 : return m_poRAT.get();
41 :
42 5450 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
43 :
44 : // RAT from PAM has priority over RAT in GDAL_METADATA TIFF tag
45 5450 : if (!m_bRATTriedReadingFromPAM)
46 : {
47 3733 : m_bRATTriedReadingFromPAM = true;
48 3733 : auto poRAT = GDALPamRasterBand::GetDefaultRAT();
49 3733 : 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 5448 : if (m_bRATSet)
58 1735 : return m_poRAT.get();
59 :
60 3713 : m_bRATSet = true;
61 :
62 : // Try reading from a .vat.dbf side car file
63 3713 : if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_osFilename.c_str()))
64 0 : return nullptr;
65 7426 : const std::string osVATDBF = m_poGDS->m_osFilename + ".vat.dbf";
66 3713 : CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
67 6999 : if (papszSiblingFiles &&
68 : // cppcheck-suppress knownConditionTrueFalse
69 3286 : GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
70 : {
71 : int iSibling =
72 3286 : CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
73 3286 : 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 3286 : return m_poRAT.get();
83 : }
84 : VSIStatBufL sStatBuf;
85 427 : if (VSIStatL(osVATDBF.c_str(), &sStatBuf) == 0)
86 1 : m_poRAT = GDALLoadVATDBF(osVATDBF.c_str());
87 427 : 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 2523 : 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 2523 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
138 5046 : if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
139 2523 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
140 795 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
141 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
142 2523 : IsBaseGTiffClass()))
143 : {
144 0 : return -1;
145 : }
146 2523 : m_poGDS->Crystalize();
147 :
148 : // Only know how to deal with nearest neighbour in this optimized routine.
149 2523 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
150 608 : 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 2457 : 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 2457 : 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 1741 : toff_t *panTIFFOffsets = nullptr;
194 1741 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
195 3482 : &panTIFFOffsets) ||
196 1741 : panTIFFOffsets == nullptr)
197 : {
198 0 : return CE_Failure;
199 : }
200 :
201 : // Sub-sampling or over-sampling can only be done at last stage.
202 1741 : int nReqXSize = nXSize;
203 : // Can do sub-sampling at the extraction stage.
204 1741 : const int nReqYSize = std::min(nBufYSize, nYSize);
205 : // TODO(schwehr): Make ppData be GByte**.
206 : void **ppData =
207 1741 : static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
208 : vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
209 1741 : VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
210 : size_t *panSizes =
211 1741 : static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
212 1741 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
213 1741 : void *pTmpBuffer = nullptr;
214 1741 : int eErr = CE_None;
215 1741 : int nContigBands =
216 1741 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
217 1741 : int nSrcPixelSize = nDTSize * nContigBands;
218 :
219 1741 : 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 3168 : 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 1535 : pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
229 1535 : if (pTmpBuffer == nullptr)
230 0 : eErr = CE_Failure;
231 : }
232 :
233 : // Prepare data extraction.
234 1741 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
235 :
236 58554 : for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
237 : {
238 56813 : if (pTmpBuffer == nullptr)
239 17766 : ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
240 : else
241 39047 : ppData[iLine] =
242 39047 : static_cast<GByte *>(pTmpBuffer) +
243 39047 : static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
244 56813 : int nSrcLine = 0;
245 56813 : if (nBufYSize < nYSize) // Sub-sampling in y.
246 3724 : nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
247 : else
248 53089 : nSrcLine = nYOff + iLine;
249 :
250 56813 : const int nBlockXOff = 0;
251 56813 : const int nBlockYOff = nSrcLine / nBlockYSize;
252 56813 : const int nYOffsetInBlock = nSrcLine % nBlockYSize;
253 56813 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
254 :
255 56813 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
256 56813 : if (panOffsets[iLine] == 0) // We don't support sparse files.
257 1047 : eErr = -1;
258 :
259 56813 : panOffsets[iLine] +=
260 56813 : (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
261 56813 : nSrcPixelSize;
262 56813 : panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
263 : }
264 :
265 : // Extract data from the file.
266 1741 : if (eErr == CE_None)
267 : {
268 694 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
269 : const int nRet =
270 694 : VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
271 694 : if (nRet != 0)
272 16 : eErr = CE_Failure;
273 : }
274 :
275 : // Byte-swap if necessary.
276 1741 : 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 1741 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
291 1741 : if (eErr == CE_None && pTmpBuffer != nullptr)
292 : {
293 509 : const bool bOneByteCopy =
294 906 : (eDataType == eBufType &&
295 397 : (eDataType == GDT_UInt8 || eDataType == GDT_Int8));
296 150712 : for (int iY = 0; iY < nBufYSize; ++iY)
297 : {
298 300406 : const int iSrcY = nBufYSize <= nYSize
299 150203 : ? iY
300 120528 : : static_cast<int>((iY + 0.5) * dfSrcYInc);
301 :
302 300406 : GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
303 150203 : (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
304 150203 : GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
305 150203 : if (nBufXSize == nXSize)
306 : {
307 25952 : GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
308 : pabyDstData, eBufType,
309 : static_cast<int>(nPixelSpace), nBufXSize);
310 : }
311 : else
312 : {
313 124251 : if (bOneByteCopy)
314 : {
315 25439 : double dfSrcX = 0.5 * dfSrcXInc;
316 2147620 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
317 : {
318 2122180 : const int iSrcX = static_cast<int>(dfSrcX);
319 2122180 : pabyDstData[iX * nPixelSpace] =
320 2122180 : 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 1741 : CPLFree(pTmpBuffer);
340 1741 : CPLFree(ppData);
341 1741 : CPLFree(panOffsets);
342 1741 : CPLFree(panSizes);
343 :
344 1741 : return eErr;
345 : }
346 :
347 : /************************************************************************/
348 : /* GetVirtualMemAuto() */
349 : /************************************************************************/
350 :
351 17 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
352 : int *pnPixelSpace,
353 : GIntBig *pnLineSpace,
354 : CSLConstList 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(
414 : GDALRWFlag eRWFlag, int *pnPixelSpace, GIntBig *pnLineSpace,
415 : CSLConstList papszOptions)
416 : {
417 20 : int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
418 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
419 14 : nLineSize *= m_poGDS->nBands;
420 :
421 20 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
422 : {
423 : // In case of a pixel interleaved file, we save virtual memory space
424 : // by reusing a base mapping that embraces the whole imagery.
425 14 : if (m_poGDS->m_pBaseMapping != nullptr)
426 : {
427 : // Offset between the base mapping and the requested mapping.
428 8 : vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
429 8 : GDALGetDataTypeSizeBytes(eDataType);
430 :
431 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
432 8 : CPLCalloc(1, sizeof(GTiffRasterBand *)));
433 8 : *ppoSelf = this;
434 :
435 24 : CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
436 8 : m_poGDS->m_pBaseMapping, nOffset,
437 8 : CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
438 : GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
439 8 : if (pVMem == nullptr)
440 : {
441 0 : CPLFree(ppoSelf);
442 0 : return nullptr;
443 : }
444 :
445 : // Mechanism used so that the memory mapping object can be
446 : // destroyed after the raster band.
447 8 : m_aSetPSelf.insert(ppoSelf);
448 8 : ++m_poGDS->m_nRefBaseMapping;
449 8 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
450 8 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
451 8 : *pnPixelSpace *= m_poGDS->nBands;
452 8 : *pnLineSpace = nLineSize;
453 8 : return pVMem;
454 : }
455 : }
456 :
457 12 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
458 :
459 12 : vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
460 :
461 24 : if (!(CPLIsVirtualMemFileMapAvailable() &&
462 12 : VSIFGetNativeFileDescriptorL(fp) != nullptr &&
463 : #if SIZEOF_VOIDP == 4
464 : nLength == static_cast<size_t>(nLength) &&
465 : #endif
466 10 : m_poGDS->m_nCompression == COMPRESSION_NONE &&
467 10 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
468 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
469 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
470 10 : m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
471 10 : !TIFFIsTiled(m_poGDS->m_hTIFF) &&
472 10 : !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
473 : {
474 2 : return nullptr;
475 : }
476 :
477 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
478 10 : if (m_poGDS->GetAccess() == GA_Update)
479 : {
480 7 : m_poGDS->FlushCache(false);
481 7 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
482 : }
483 :
484 : // Get strip offsets.
485 10 : toff_t *panTIFFOffsets = nullptr;
486 10 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
487 20 : &panTIFFOffsets) ||
488 10 : panTIFFOffsets == nullptr)
489 : {
490 0 : return nullptr;
491 : }
492 :
493 10 : GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
494 10 : GDALGetDataTypeSizeBytes(eDataType);
495 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
496 4 : nBlockSize *= m_poGDS->nBands;
497 :
498 10 : int nBlocks = m_poGDS->m_nBlocksPerBand;
499 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
500 6 : nBlocks *= m_poGDS->nBands;
501 10 : int i = 0; // Used after for.
502 103 : for (; i < nBlocks; ++i)
503 : {
504 100 : if (panTIFFOffsets[i] != 0)
505 7 : break;
506 : }
507 10 : if (i == nBlocks)
508 : {
509 : // All zeroes.
510 3 : if (m_poGDS->eAccess == GA_Update)
511 : {
512 : // Initialize the file with empty blocks so that the file has
513 : // the appropriate size.
514 :
515 3 : toff_t *panByteCounts = nullptr;
516 3 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
517 6 : &panByteCounts) ||
518 3 : panByteCounts == nullptr)
519 : {
520 0 : return nullptr;
521 : }
522 3 : if (VSIFSeekL(fp, 0, SEEK_END) != 0)
523 0 : return nullptr;
524 3 : vsi_l_offset nBaseOffset = VSIFTellL(fp);
525 :
526 : // Just write one tile with libtiff to put it in appropriate state.
527 : GByte *pabyData =
528 3 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
529 3 : if (pabyData == nullptr)
530 : {
531 0 : return nullptr;
532 : }
533 3 : const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
534 : pabyData, nBlockSize);
535 3 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
536 3 : VSIFree(pabyData);
537 3 : if (ret != nBlockSize)
538 : {
539 0 : return nullptr;
540 : }
541 3 : CPLAssert(panTIFFOffsets[0] == nBaseOffset);
542 3 : CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
543 :
544 : // Now simulate the writing of other blocks.
545 3 : assert(nBlocks > 0);
546 3 : assert(static_cast<vsi_l_offset>(nBlockSize) <
547 : std::numeric_limits<vsi_l_offset>::max() / nBlocks);
548 3 : const vsi_l_offset nDataSize =
549 3 : static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
550 3 : if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
551 0 : return nullptr;
552 :
553 93 : for (i = 1; i < nBlocks; ++i)
554 : {
555 90 : panTIFFOffsets[i] =
556 90 : nBaseOffset + i * static_cast<toff_t>(nBlockSize);
557 90 : panByteCounts[i] = nBlockSize;
558 : }
559 : }
560 : else
561 : {
562 0 : CPLDebug("GTiff", "Sparse files not supported in file mapping");
563 0 : return nullptr;
564 : }
565 : }
566 :
567 10 : GIntBig nBlockSpacing = 0;
568 10 : bool bCompatibleSpacing = true;
569 10 : toff_t nPrevOffset = 0;
570 229 : for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
571 : {
572 219 : toff_t nCurOffset = 0;
573 219 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
574 96 : nCurOffset =
575 96 : panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
576 : else
577 123 : nCurOffset = panTIFFOffsets[i];
578 219 : if (nCurOffset == 0)
579 : {
580 0 : bCompatibleSpacing = false;
581 0 : break;
582 : }
583 219 : if (i > 0)
584 : {
585 209 : const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
586 209 : if (i == 1)
587 : {
588 10 : if (nCurSpacing !=
589 10 : static_cast<GIntBig>(nBlockYSize) * nLineSize)
590 : {
591 0 : bCompatibleSpacing = false;
592 0 : break;
593 : }
594 10 : nBlockSpacing = nCurSpacing;
595 : }
596 199 : else if (nBlockSpacing != nCurSpacing)
597 : {
598 0 : bCompatibleSpacing = false;
599 0 : break;
600 : }
601 : }
602 219 : nPrevOffset = nCurOffset;
603 : }
604 :
605 10 : if (!bCompatibleSpacing)
606 : {
607 0 : return nullptr;
608 : }
609 :
610 10 : vsi_l_offset nOffset = 0;
611 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
612 : {
613 4 : CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
614 4 : nOffset = panTIFFOffsets[0];
615 : }
616 : else
617 : {
618 6 : nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
619 : }
620 10 : CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
621 : fp, nOffset, nLength,
622 : eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
623 : nullptr, nullptr);
624 10 : if (pVMem == nullptr)
625 : {
626 0 : return nullptr;
627 : }
628 :
629 10 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
630 : {
631 : // TODO(schwehr): Revisit this block.
632 4 : m_poGDS->m_pBaseMapping = pVMem;
633 4 : pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
634 : papszOptions);
635 : // Drop ref on base mapping.
636 4 : CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
637 4 : if (pVMem == nullptr)
638 0 : m_poGDS->m_pBaseMapping = nullptr;
639 : }
640 : else
641 : {
642 6 : *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
643 6 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
644 0 : *pnPixelSpace *= m_poGDS->nBands;
645 6 : *pnLineSpace = nLineSize;
646 : }
647 10 : return pVMem;
648 : }
649 :
650 : /************************************************************************/
651 : /* IGetDataCoverageStatus() */
652 : /************************************************************************/
653 :
654 935 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
655 : int nYSize, int nMaskFlagStop,
656 : double *pdfDataPct)
657 : {
658 935 : if (eAccess == GA_Update)
659 95 : m_poGDS->FlushCache(false);
660 :
661 935 : const int iXBlockStart = nXOff / nBlockXSize;
662 935 : const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
663 935 : const int iYBlockStart = nYOff / nBlockYSize;
664 935 : const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
665 935 : int nStatus = 0;
666 935 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
667 935 : GIntBig nPixelsData = 0;
668 2533 : for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
669 : {
670 4343 : for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
671 : {
672 2745 : const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
673 2745 : int nBlockId = nBlockIdBand0;
674 2745 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
675 144 : nBlockId =
676 144 : nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
677 2745 : vsi_l_offset nOffset = 0;
678 2745 : vsi_l_offset nLength = 0;
679 2745 : bool bHasData = false;
680 2745 : bool bError = false;
681 2745 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
682 : &bError))
683 : {
684 1866 : if (bError)
685 873 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
686 1866 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
687 : }
688 : else
689 : {
690 879 : if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
691 766 : m_poGDS->eAccess == GA_ReadOnly &&
692 724 : ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
693 724 : !m_bNoDataSetAsUInt64) ||
694 0 : (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
695 0 : (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
696 0 : (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
697 : {
698 : VSIRangeStatus eStatus =
699 724 : VSIFGetRangeStatusL(fp, nOffset, nLength);
700 724 : if (eStatus == VSI_RANGE_STATUS_HOLE)
701 : {
702 0 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
703 : }
704 : else
705 : {
706 724 : bHasData = true;
707 724 : }
708 : }
709 : else
710 : {
711 155 : bHasData = true;
712 : }
713 : }
714 2745 : if (bHasData)
715 : {
716 879 : const int nXBlockRight =
717 879 : (iX * nBlockXSize > INT_MAX - nBlockXSize)
718 879 : ? INT_MAX
719 879 : : (iX + 1) * nBlockXSize;
720 879 : const int nYBlockBottom =
721 879 : (iY * nBlockYSize > INT_MAX - nBlockYSize)
722 879 : ? INT_MAX
723 879 : : (iY + 1) * nBlockYSize;
724 :
725 1758 : nPixelsData += (static_cast<GIntBig>(
726 879 : std::min(nXBlockRight, nXOff + nXSize)) -
727 879 : std::max(iX * nBlockXSize, nXOff)) *
728 879 : (std::min(nYBlockBottom, nYOff + nYSize) -
729 879 : std::max(iY * nBlockYSize, nYOff));
730 879 : nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
731 : }
732 2745 : if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
733 : {
734 873 : if (pdfDataPct)
735 0 : *pdfDataPct = -1.0;
736 873 : return nStatus;
737 : }
738 : }
739 : }
740 62 : if (pdfDataPct)
741 8 : *pdfDataPct =
742 8 : 100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
743 62 : return nStatus;
744 : }
745 :
746 : /************************************************************************/
747 : /* IReadBlock() */
748 : /************************************************************************/
749 :
750 2322550 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
751 :
752 : {
753 2322550 : m_poGDS->Crystalize();
754 :
755 2322550 : GPtrDiff_t nBlockBufSize = 0;
756 2322550 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
757 : {
758 60508 : nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
759 : }
760 : else
761 : {
762 2262050 : CPLAssert(nBlockXOff == 0);
763 : nBlockBufSize =
764 2262050 : static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
765 : }
766 :
767 2322550 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
768 :
769 : /* -------------------------------------------------------------------- */
770 : /* The bottom most partial tiles and strips are sometimes only */
771 : /* partially encoded. This code reduces the requested data so */
772 : /* an error won't be reported in this case. (#1179) */
773 : /* -------------------------------------------------------------------- */
774 2322550 : auto nBlockReqSize = nBlockBufSize;
775 :
776 2322550 : if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
777 : {
778 6605 : nBlockReqSize =
779 6605 : (nBlockBufSize / nBlockYSize) *
780 6605 : (nBlockYSize -
781 : static_cast<int>(
782 6605 : (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
783 6605 : nRasterYSize));
784 : }
785 :
786 : /* -------------------------------------------------------------------- */
787 : /* Handle the case of a strip or tile that doesn't exist yet. */
788 : /* Just set to zeros and return. */
789 : /* -------------------------------------------------------------------- */
790 2322550 : vsi_l_offset nOffset = 0;
791 2322550 : bool bErrOccurred = false;
792 4512140 : if (nBlockId != m_poGDS->m_nLoadedBlock &&
793 2189590 : !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
794 : {
795 55290 : NullBlock(pImage);
796 55290 : if (bErrOccurred)
797 1 : return CE_Failure;
798 55289 : return CE_None;
799 : }
800 :
801 2267260 : if (m_poGDS->m_bStreamingIn &&
802 10936 : !(m_poGDS->nBands > 1 &&
803 10423 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
804 10048 : nBlockId == m_poGDS->m_nLoadedBlock))
805 : {
806 3436 : if (nOffset < VSIFTellL(m_poGDS->m_fpL))
807 : {
808 2000 : ReportError(CE_Failure, CPLE_NotSupported,
809 : "Trying to load block %d at offset " CPL_FRMT_GUIB
810 : " whereas current pos is " CPL_FRMT_GUIB
811 : " (backward read not supported)",
812 : nBlockId, static_cast<GUIntBig>(nOffset),
813 1000 : static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
814 1000 : return CE_Failure;
815 : }
816 : }
817 :
818 : /* -------------------------------------------------------------------- */
819 : /* Handle simple case (separate, onesampleperpixel) */
820 : /* -------------------------------------------------------------------- */
821 2266260 : CPLErr eErr = CE_None;
822 2266260 : if (m_poGDS->nBands == 1 ||
823 210122 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
824 : {
825 2082510 : if (nBlockReqSize < nBlockBufSize)
826 3049 : memset(pImage, 0, nBlockBufSize);
827 :
828 2082510 : if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
829 : {
830 83 : memset(pImage, 0, nBlockBufSize);
831 83 : return CE_Failure;
832 : }
833 : }
834 : else
835 : {
836 : /* --------------------------------------------------------------------
837 : */
838 : /* Load desired block */
839 : /* --------------------------------------------------------------------
840 : */
841 183751 : eErr = m_poGDS->LoadBlockBuf(nBlockId);
842 183751 : if (eErr != CE_None)
843 : {
844 26 : memset(pImage, 0,
845 52 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
846 26 : GDALGetDataTypeSizeBytes(eDataType));
847 26 : return eErr;
848 : }
849 :
850 183725 : bool bDoCopyWords = true;
851 52275 : if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
852 46672 : eAccess == GA_ReadOnly &&
853 37267 : (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
854 36476 : ((eDataType == GDT_UInt8 && m_poGDS->m_nBitsPerSample == 8) ||
855 436 : (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
856 236270 : (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
857 72626 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
858 36313 : GDALGetDataTypeSizeBytes(eDataType) <
859 36313 : GDALGetCacheMax64() / m_poGDS->nBands)
860 : {
861 36313 : bDoCopyWords = false;
862 : void *ppDestBuffers[4];
863 36313 : GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
864 : nullptr};
865 156487 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
866 : {
867 120174 : if (iBand == nBand)
868 : {
869 36313 : ppDestBuffers[iBand - 1] = pImage;
870 : }
871 : else
872 : {
873 : GDALRasterBlock *poBlock =
874 83861 : m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
875 83861 : nBlockXOff, nBlockYOff, true);
876 83861 : if (poBlock == nullptr)
877 : {
878 0 : bDoCopyWords = true;
879 0 : break;
880 : }
881 83861 : ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
882 83861 : apoLockedBlocks[iBand - 1] = poBlock;
883 : }
884 : }
885 36313 : if (!bDoCopyWords)
886 : {
887 36313 : GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
888 36313 : m_poGDS->nBands, ppDestBuffers, eDataType,
889 36313 : static_cast<size_t>(nBlockXSize) *
890 36313 : nBlockYSize);
891 : }
892 156487 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
893 : {
894 120174 : if (apoLockedBlocks[iBand - 1])
895 : {
896 83861 : apoLockedBlocks[iBand - 1]->DropLock();
897 : }
898 : }
899 : }
900 :
901 183725 : if (bDoCopyWords)
902 : {
903 147412 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
904 147412 : GByte *pabyImage =
905 147412 : m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
906 :
907 147412 : GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
908 : pImage, eDataType, nWordBytes,
909 147412 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
910 :
911 147412 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
912 : }
913 : }
914 :
915 2266160 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
916 :
917 2266160 : return eErr;
918 : }
919 :
920 : /************************************************************************/
921 : /* CacheMaskForBlock() */
922 : /************************************************************************/
923 :
924 2268560 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
925 :
926 : {
927 : // Preload mask data if layout compatible and we have cached ranges
928 2268670 : if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
929 108 : VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
930 : {
931 97 : auto poBand = cpl::down_cast<GTiffRasterBand *>(
932 97 : m_poGDS->m_poMaskDS->GetRasterBand(1));
933 97 : if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
934 97 : poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
935 : {
936 : GDALRasterBlock *poBlock =
937 93 : poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
938 93 : if (poBlock)
939 93 : poBlock->DropLock();
940 : }
941 : }
942 2268560 : }
943 :
944 : /************************************************************************/
945 : /* FillCacheForOtherBands() */
946 : /************************************************************************/
947 :
948 147626 : CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
949 :
950 : {
951 : /* -------------------------------------------------------------------- */
952 : /* In the fairly common case of pixel interleaved 8bit data */
953 : /* that is multi-band, lets push the rest of the data into the */
954 : /* block cache too, to avoid (hopefully) having to redecode it. */
955 : /* */
956 : /* Our following logic actually depends on the fact that the */
957 : /* this block is already loaded, so subsequent calls will end */
958 : /* up back in this method and pull from the loaded block. */
959 : /* */
960 : /* Be careful not entering this portion of code from */
961 : /* the other bands, otherwise we'll get very deep nested calls */
962 : /* and O(nBands^2) performance ! */
963 : /* */
964 : /* If there are many bands and the block cache size is not big */
965 : /* enough to accommodate the size of all the blocks, don't enter */
966 : /* -------------------------------------------------------------------- */
967 147626 : CPLErr eErr = CE_None;
968 442878 : if (m_poGDS->nBands != 1 &&
969 147626 : m_poGDS->nBands <
970 49192 : 128 && // avoid caching for datasets with too many bands
971 308227 : !m_poGDS->m_bLoadingOtherBands &&
972 25950 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
973 12975 : GDALGetDataTypeSizeBytes(eDataType) <
974 12975 : GDALGetCacheMax64() / m_poGDS->nBands)
975 : {
976 12975 : m_poGDS->m_bLoadingOtherBands = true;
977 :
978 53131 : for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
979 : {
980 40156 : if (iOtherBand == nBand)
981 12975 : continue;
982 :
983 : GDALRasterBlock *poBlock =
984 27181 : m_poGDS->GetRasterBand(iOtherBand)
985 27181 : ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
986 27181 : if (poBlock == nullptr)
987 : {
988 0 : eErr = CE_Failure;
989 0 : break;
990 : }
991 27181 : poBlock->DropLock();
992 : }
993 :
994 12975 : m_poGDS->m_bLoadingOtherBands = false;
995 : }
996 :
997 147626 : return eErr;
998 : }
999 :
1000 : /************************************************************************/
1001 : /* GetDescription() */
1002 : /************************************************************************/
1003 :
1004 311382 : const char *GTiffRasterBand::GetDescription() const
1005 : {
1006 311382 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1007 :
1008 311382 : return m_osDescription;
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GetOffset() */
1013 : /************************************************************************/
1014 :
1015 316965 : double GTiffRasterBand::GetOffset(int *pbSuccess)
1016 :
1017 : {
1018 316965 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1019 :
1020 316965 : if (pbSuccess)
1021 8003 : *pbSuccess = m_bHaveOffsetScale;
1022 316965 : return m_dfOffset;
1023 : }
1024 :
1025 : /************************************************************************/
1026 : /* GetScale() */
1027 : /************************************************************************/
1028 :
1029 316968 : double GTiffRasterBand::GetScale(int *pbSuccess)
1030 :
1031 : {
1032 316968 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1033 :
1034 316968 : if (pbSuccess)
1035 8006 : *pbSuccess = m_bHaveOffsetScale;
1036 316968 : return m_dfScale;
1037 : }
1038 :
1039 : /************************************************************************/
1040 : /* GetUnitType() */
1041 : /************************************************************************/
1042 :
1043 307670 : const char *GTiffRasterBand::GetUnitType()
1044 :
1045 : {
1046 307670 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1047 307670 : if (m_osUnitType.empty())
1048 : {
1049 307469 : m_poGDS->LookForProjection();
1050 307469 : if (m_poGDS->m_pszVertUnit)
1051 10 : return m_poGDS->m_pszVertUnit;
1052 : }
1053 :
1054 307660 : return m_osUnitType.c_str();
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* GetMetadataDomainList() */
1059 : /************************************************************************/
1060 :
1061 13 : char **GTiffRasterBand::GetMetadataDomainList()
1062 : {
1063 13 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1064 :
1065 13 : m_poGDS->LoadENVIHdrIfNeeded();
1066 :
1067 13 : return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* GetMetadata() */
1072 : /************************************************************************/
1073 :
1074 20587 : CSLConstList GTiffRasterBand::GetMetadata(const char *pszDomain)
1075 :
1076 : {
1077 20587 : if (pszDomain == nullptr || !EQUAL(pszDomain, GDAL_MDD_IMAGE_STRUCTURE))
1078 : {
1079 20396 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1080 :
1081 20396 : m_poGDS->LoadENVIHdrIfNeeded();
1082 : }
1083 191 : else if (EQUAL(pszDomain, GDAL_MDD_IMAGERY))
1084 : {
1085 0 : m_poGDS->LoadENVIHdrIfNeeded();
1086 : }
1087 :
1088 20587 : return m_oGTiffMDMD.GetMetadata(pszDomain);
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* GetMetadataItem() */
1093 : /************************************************************************/
1094 :
1095 24780 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1096 : const char *pszDomain)
1097 :
1098 : {
1099 24780 : if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1100 : {
1101 5253 : int nBlockXOff = 0;
1102 5253 : int nBlockYOff = 0;
1103 :
1104 5253 : if (EQUAL(pszName, "JPEGTABLES"))
1105 : {
1106 11 : uint32_t nJPEGTableSize = 0;
1107 11 : void *pJPEGTable = nullptr;
1108 11 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1109 11 : &nJPEGTableSize, &pJPEGTable) != 1 ||
1110 11 : pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1111 : {
1112 0 : return nullptr;
1113 : }
1114 11 : char *const pszHex = CPLBinaryToHex(
1115 : nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1116 11 : const char *pszReturn = CPLSPrintf("%s", pszHex);
1117 11 : CPLFree(pszHex);
1118 :
1119 11 : return pszReturn;
1120 : }
1121 :
1122 5242 : if (EQUAL(pszName, "IFD_OFFSET"))
1123 : {
1124 186 : return CPLSPrintf(CPL_FRMT_GUIB,
1125 93 : static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1126 : }
1127 :
1128 5149 : if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1129 : 2)
1130 : {
1131 4427 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1132 4426 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1133 19 : return nullptr;
1134 :
1135 4408 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1136 4408 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1137 : {
1138 3592 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1139 : }
1140 :
1141 4408 : vsi_l_offset nOffset = 0;
1142 4408 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1143 : nullptr))
1144 : {
1145 185 : return nullptr;
1146 : }
1147 :
1148 4223 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1149 : }
1150 :
1151 722 : if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1152 : {
1153 722 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1154 721 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1155 2 : return nullptr;
1156 :
1157 720 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1158 720 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1159 : {
1160 244 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1161 : }
1162 :
1163 720 : vsi_l_offset nByteCount = 0;
1164 720 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1165 : nullptr))
1166 : {
1167 87 : return nullptr;
1168 : }
1169 :
1170 633 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1171 0 : }
1172 : }
1173 19527 : else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1174 : {
1175 131 : if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1176 131 : return HasBlockCache() ? "1" : "0";
1177 : }
1178 19396 : else if (pszDomain == nullptr ||
1179 19396 : !EQUAL(pszDomain, GDAL_MDD_IMAGE_STRUCTURE))
1180 : {
1181 4142 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1182 :
1183 4142 : m_poGDS->LoadENVIHdrIfNeeded();
1184 : }
1185 15254 : else if (EQUAL(pszDomain, GDAL_MDD_IMAGERY))
1186 : {
1187 0 : m_poGDS->LoadENVIHdrIfNeeded();
1188 : }
1189 :
1190 19396 : const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1191 :
1192 19396 : if (pszRet == nullptr && eDataType == GDT_UInt8 && pszName && pszDomain &&
1193 16723 : EQUAL(pszDomain, GDAL_MDD_IMAGE_STRUCTURE) &&
1194 13815 : EQUAL(pszName, "PIXELTYPE"))
1195 : {
1196 : // to get a chance of emitting the warning about this legacy usage
1197 3870 : pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1198 : }
1199 19396 : return pszRet;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* GetColorInterpretation() */
1204 : /************************************************************************/
1205 :
1206 463114 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1207 :
1208 : {
1209 463114 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1210 :
1211 463114 : return m_eBandInterp;
1212 : }
1213 :
1214 : /************************************************************************/
1215 : /* GetColorTable() */
1216 : /************************************************************************/
1217 :
1218 12975 : GDALColorTable *GTiffRasterBand::GetColorTable()
1219 :
1220 : {
1221 12975 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1222 :
1223 12975 : if (nBand == 1)
1224 10886 : return m_poGDS->m_poColorTable.get();
1225 :
1226 2089 : return nullptr;
1227 : }
1228 :
1229 : /************************************************************************/
1230 : /* GetNoDataValue() */
1231 : /************************************************************************/
1232 :
1233 973125 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1234 :
1235 : {
1236 973125 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1237 :
1238 973125 : int bSuccess = FALSE;
1239 973125 : double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1240 973125 : if (bSuccess)
1241 : {
1242 4 : if (pbSuccess)
1243 4 : *pbSuccess = TRUE;
1244 :
1245 4 : return dfNoDataValue;
1246 : }
1247 :
1248 973121 : if (m_bNoDataSet)
1249 : {
1250 5054 : if (pbSuccess)
1251 5005 : *pbSuccess = TRUE;
1252 :
1253 5054 : return m_dfNoDataValue;
1254 : }
1255 :
1256 968067 : if (m_poGDS->m_bNoDataSet)
1257 : {
1258 424354 : if (pbSuccess)
1259 424124 : *pbSuccess = TRUE;
1260 :
1261 424354 : return m_poGDS->m_dfNoDataValue;
1262 : }
1263 :
1264 543713 : if (m_bNoDataSetAsInt64)
1265 : {
1266 0 : if (pbSuccess)
1267 0 : *pbSuccess = TRUE;
1268 :
1269 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1270 : }
1271 :
1272 543713 : 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 543713 : if (m_bNoDataSetAsUInt64)
1281 : {
1282 0 : if (pbSuccess)
1283 0 : *pbSuccess = TRUE;
1284 :
1285 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1286 : }
1287 :
1288 543713 : 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 543713 : if (pbSuccess)
1297 543573 : *pbSuccess = FALSE;
1298 543713 : return dfNoDataValue;
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* GetNoDataValueAsInt64() */
1303 : /************************************************************************/
1304 :
1305 65 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1306 :
1307 : {
1308 65 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1309 :
1310 65 : 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 65 : 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 65 : int bSuccess = FALSE;
1328 : const auto nNoDataValue =
1329 65 : GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1330 65 : if (bSuccess)
1331 : {
1332 0 : if (pbSuccess)
1333 0 : *pbSuccess = TRUE;
1334 :
1335 0 : return nNoDataValue;
1336 : }
1337 :
1338 65 : if (m_bNoDataSetAsInt64)
1339 : {
1340 2 : if (pbSuccess)
1341 2 : *pbSuccess = TRUE;
1342 :
1343 2 : return m_nNoDataValueInt64;
1344 : }
1345 :
1346 63 : if (m_poGDS->m_bNoDataSetAsInt64)
1347 : {
1348 11 : if (pbSuccess)
1349 10 : *pbSuccess = TRUE;
1350 :
1351 11 : return m_poGDS->m_nNoDataValueInt64;
1352 : }
1353 :
1354 52 : if (pbSuccess)
1355 52 : *pbSuccess = FALSE;
1356 52 : return nNoDataValue;
1357 : }
1358 :
1359 : /************************************************************************/
1360 : /* GetNoDataValueAsUInt64() */
1361 : /************************************************************************/
1362 :
1363 47 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1364 :
1365 : {
1366 47 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1367 :
1368 47 : 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 47 : 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 47 : int bSuccess = FALSE;
1386 : const auto nNoDataValue =
1387 47 : GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1388 47 : if (bSuccess)
1389 : {
1390 0 : if (pbSuccess)
1391 0 : *pbSuccess = TRUE;
1392 :
1393 0 : return nNoDataValue;
1394 : }
1395 :
1396 47 : if (m_bNoDataSetAsUInt64)
1397 : {
1398 4 : if (pbSuccess)
1399 4 : *pbSuccess = TRUE;
1400 :
1401 4 : return m_nNoDataValueUInt64;
1402 : }
1403 :
1404 43 : 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 36 : if (pbSuccess)
1413 36 : *pbSuccess = FALSE;
1414 36 : return nNoDataValue;
1415 : }
1416 :
1417 : /************************************************************************/
1418 : /* GetOverviewCount() */
1419 : /************************************************************************/
1420 :
1421 1320690 : int GTiffRasterBand::GetOverviewCount()
1422 :
1423 : {
1424 1320690 : if (!m_poGDS->AreOverviewsEnabled())
1425 30 : return 0;
1426 :
1427 1320660 : m_poGDS->ScanDirectories();
1428 :
1429 1320660 : if (!m_poGDS->m_apoOverviewDS.empty())
1430 : {
1431 267459 : return static_cast<int>(m_poGDS->m_apoOverviewDS.size());
1432 : }
1433 :
1434 1053200 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1435 1053200 : if (nOverviewCount > 0)
1436 415 : return nOverviewCount;
1437 :
1438 : // Implicit JPEG overviews are normally hidden, except when doing
1439 : // IRasterIO() operations.
1440 1052780 : if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1441 1044210 : return m_poGDS->GetJPEGOverviewCount();
1442 :
1443 : // Deal with a GeoTIFF file with internal mask, but with external .ovr
1444 8557 : if (!m_poGDS->m_bIsOverview && m_poGDS->m_poBaseDS &&
1445 17156 : m_poGDS->m_poBaseDS->m_poMaskDS.get() == m_poGDS &&
1446 21 : m_poGDS->m_poBaseDS->m_apoOverviewDS.empty())
1447 : {
1448 7 : auto poMainBand = m_poGDS->m_poBaseDS->GetRasterBand(1);
1449 7 : int nCount = 0;
1450 7 : const int nMainBandOvrCount = poMainBand->GetOverviewCount();
1451 14 : for (int i = 0; i < nMainBandOvrCount; ++i)
1452 : {
1453 7 : const auto poMainBandOvr = poMainBand->GetOverview(i);
1454 14 : if (poMainBandOvr &&
1455 7 : poMainBandOvr->GetMaskFlags() == GMF_PER_DATASET)
1456 7 : ++nCount;
1457 : }
1458 7 : return nCount;
1459 : }
1460 :
1461 8571 : return 0;
1462 : }
1463 :
1464 : /************************************************************************/
1465 : /* GetOverview() */
1466 : /************************************************************************/
1467 :
1468 74453 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1469 :
1470 : {
1471 74453 : m_poGDS->ScanDirectories();
1472 :
1473 74453 : if (!m_poGDS->m_apoOverviewDS.empty())
1474 : {
1475 : // Do we have internal overviews?
1476 73813 : if (i < 0 || static_cast<size_t>(i) >= m_poGDS->m_apoOverviewDS.size())
1477 8 : return nullptr;
1478 :
1479 73805 : return m_poGDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
1480 : }
1481 :
1482 640 : GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1483 640 : if (poOvrBand != nullptr)
1484 410 : return poOvrBand;
1485 :
1486 : // For consistency with GetOverviewCount(), we should also test
1487 : // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1488 : // to query them for testing purposes.
1489 230 : if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1490 180 : return m_poGDS->m_apoJPEGOverviewDS[i]->GetRasterBand(nBand);
1491 :
1492 : // Deal with a GeoTIFF file with internal mask, but with external .ovr
1493 50 : if (!m_poGDS->m_bIsOverview && m_poGDS->m_poBaseDS &&
1494 107 : m_poGDS->m_poBaseDS->m_poMaskDS.get() == m_poGDS &&
1495 7 : m_poGDS->m_poBaseDS->m_apoOverviewDS.empty())
1496 : {
1497 7 : auto poMainBand = m_poGDS->m_poBaseDS->GetRasterBand(1);
1498 7 : int nCount = 0;
1499 7 : const int nMainBandOvrCount = poMainBand->GetOverviewCount();
1500 9 : for (int iIter = 0; iIter < nMainBandOvrCount; ++iIter)
1501 : {
1502 9 : const auto poMainBandOvr = poMainBand->GetOverview(iIter);
1503 18 : if (poMainBandOvr &&
1504 9 : poMainBandOvr->GetMaskFlags() == GMF_PER_DATASET)
1505 : {
1506 9 : if (nCount == i)
1507 : {
1508 7 : return poMainBandOvr->GetMaskBand();
1509 : }
1510 2 : ++nCount;
1511 : }
1512 : }
1513 : }
1514 :
1515 43 : return nullptr;
1516 : }
1517 :
1518 : /************************************************************************/
1519 : /* GetMaskFlags() */
1520 : /************************************************************************/
1521 :
1522 23687 : int GTiffRasterBand::GetMaskFlags()
1523 : {
1524 23687 : m_poGDS->ScanDirectories();
1525 :
1526 23687 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1527 : {
1528 0 : return GMF_PER_DATASET;
1529 : }
1530 :
1531 23687 : if (m_poGDS->m_poMaskDS != nullptr)
1532 : {
1533 283 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1534 : {
1535 275 : return GMF_PER_DATASET;
1536 : }
1537 :
1538 8 : return 0;
1539 : }
1540 :
1541 23404 : if (m_poGDS->m_bIsOverview)
1542 : {
1543 457 : auto poMainBand = m_poGDS->m_poBaseDS->GetRasterBand(nBand);
1544 457 : if (poMainBand->GetMaskFlags() == GMF_PER_DATASET)
1545 : {
1546 13 : GDALRasterBand *poBaseMask = poMainBand->GetMaskBand();
1547 13 : if (poBaseMask)
1548 : {
1549 13 : const int nOverviews = poBaseMask->GetOverviewCount();
1550 13 : for (int i = 0; i < nOverviews; i++)
1551 : {
1552 2 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1553 4 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1554 2 : poOvr->GetYSize() == GetYSize())
1555 : {
1556 2 : return GMF_PER_DATASET;
1557 : }
1558 : }
1559 : }
1560 : }
1561 : }
1562 :
1563 23402 : return GDALPamRasterBand::GetMaskFlags();
1564 : }
1565 :
1566 : /************************************************************************/
1567 : /* GetMaskBand() */
1568 : /************************************************************************/
1569 :
1570 118672 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1571 : {
1572 118672 : m_poGDS->ScanDirectories();
1573 :
1574 118672 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1575 : {
1576 31 : return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1577 : }
1578 :
1579 118641 : if (m_poGDS->m_poMaskDS != nullptr)
1580 : {
1581 759 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1582 742 : return m_poGDS->m_poMaskDS->GetRasterBand(1);
1583 :
1584 17 : return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1585 : }
1586 :
1587 117882 : if (m_poGDS->m_bIsOverview)
1588 : {
1589 : GDALRasterBand *poBaseMask =
1590 285 : m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1591 285 : if (poBaseMask)
1592 : {
1593 285 : const int nOverviews = poBaseMask->GetOverviewCount();
1594 375 : for (int i = 0; i < nOverviews; i++)
1595 : {
1596 171 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1597 252 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1598 81 : poOvr->GetYSize() == GetYSize())
1599 : {
1600 81 : return poOvr;
1601 : }
1602 : }
1603 : }
1604 : }
1605 :
1606 117801 : return GDALPamRasterBand::GetMaskBand();
1607 : }
1608 :
1609 : /************************************************************************/
1610 : /* IsMaskBand() */
1611 : /************************************************************************/
1612 :
1613 1066 : bool GTiffRasterBand::IsMaskBand() const
1614 : {
1615 1098 : return (m_poGDS->m_poImageryDS != nullptr &&
1616 32 : m_poGDS->m_poImageryDS->m_poMaskDS.get() == m_poGDS) ||
1617 2068 : m_eBandInterp == GCI_AlphaBand ||
1618 2036 : m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1619 : }
1620 :
1621 : /************************************************************************/
1622 : /* GetMaskValueRange() */
1623 : /************************************************************************/
1624 :
1625 0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1626 : {
1627 0 : if (!IsMaskBand())
1628 0 : return GMVR_UNKNOWN;
1629 0 : if (m_poGDS->m_nBitsPerSample == 1)
1630 0 : return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1631 0 : : GMVR_0_AND_1_ONLY;
1632 0 : return GMVR_UNKNOWN;
1633 : }
|