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 307962 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
37 :
38 : {
39 307962 : if (m_poGDS->m_poBaseDS != nullptr)
40 52 : return m_poRAT.get();
41 :
42 307910 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
43 :
44 : // RAT from PAM has priority over RAT in GDAL_METADATA TIFF tag
45 307910 : if (!m_bRATTriedReadingFromPAM)
46 : {
47 305763 : m_bRATTriedReadingFromPAM = true;
48 305763 : auto poRAT = GDALPamRasterBand::GetDefaultRAT();
49 305763 : 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 307908 : if (m_bRATSet)
58 2164 : return m_poRAT.get();
59 :
60 305744 : m_bRATSet = true;
61 :
62 : // Try reading from a .vat.dbf side car file
63 305744 : if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_osFilename.c_str()))
64 0 : return nullptr;
65 611488 : const std::string osVATDBF = m_poGDS->m_osFilename + ".vat.dbf";
66 305744 : CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
67 611451 : if (papszSiblingFiles &&
68 : // cppcheck-suppress knownConditionTrueFalse
69 305707 : GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
70 : {
71 : int iSibling =
72 305707 : CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
73 305707 : 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 305707 : 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_UInt8 || 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 : 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 904 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
655 : int nYSize, int nMaskFlagStop,
656 : double *pdfDataPct)
657 : {
658 904 : if (eAccess == GA_Update)
659 95 : m_poGDS->FlushCache(false);
660 :
661 904 : const int iXBlockStart = nXOff / nBlockXSize;
662 904 : const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
663 904 : const int iYBlockStart = nYOff / nBlockYSize;
664 904 : const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
665 904 : int nStatus = 0;
666 904 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
667 904 : GIntBig nPixelsData = 0;
668 2502 : for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
669 : {
670 4312 : for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
671 : {
672 2714 : const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
673 2714 : int nBlockId = nBlockIdBand0;
674 2714 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
675 136 : nBlockId =
676 136 : nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
677 2714 : vsi_l_offset nOffset = 0;
678 2714 : vsi_l_offset nLength = 0;
679 2714 : bool bHasData = false;
680 2714 : bool bError = false;
681 2714 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
682 : &bError))
683 : {
684 1866 : if (bError)
685 842 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
686 1866 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
687 : }
688 : else
689 : {
690 848 : if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
691 737 : m_poGDS->eAccess == GA_ReadOnly &&
692 695 : ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
693 695 : !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 695 : VSIFGetRangeStatusL(fp, nOffset, nLength);
700 695 : if (eStatus == VSI_RANGE_STATUS_HOLE)
701 : {
702 0 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
703 : }
704 : else
705 : {
706 695 : bHasData = true;
707 695 : }
708 : }
709 : else
710 : {
711 153 : bHasData = true;
712 : }
713 : }
714 2714 : if (bHasData)
715 : {
716 848 : const int nXBlockRight =
717 848 : (iX * nBlockXSize > INT_MAX - nBlockXSize)
718 848 : ? INT_MAX
719 848 : : (iX + 1) * nBlockXSize;
720 848 : const int nYBlockBottom =
721 848 : (iY * nBlockYSize > INT_MAX - nBlockYSize)
722 848 : ? INT_MAX
723 848 : : (iY + 1) * nBlockYSize;
724 :
725 1696 : nPixelsData += (static_cast<GIntBig>(
726 848 : std::min(nXBlockRight, nXOff + nXSize)) -
727 848 : std::max(iX * nBlockXSize, nXOff)) *
728 848 : (std::min(nYBlockBottom, nYOff + nYSize) -
729 848 : std::max(iY * nBlockYSize, nYOff));
730 848 : nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
731 : }
732 2714 : if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
733 : {
734 842 : if (pdfDataPct)
735 0 : *pdfDataPct = -1.0;
736 842 : 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 2318530 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
751 :
752 : {
753 2318530 : m_poGDS->Crystalize();
754 :
755 2318530 : GPtrDiff_t nBlockBufSize = 0;
756 2318530 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
757 : {
758 58194 : nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
759 : }
760 : else
761 : {
762 2260340 : CPLAssert(nBlockXOff == 0);
763 : nBlockBufSize =
764 2260340 : static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
765 : }
766 :
767 2318530 : 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 2318530 : auto nBlockReqSize = nBlockBufSize;
775 :
776 2318530 : if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
777 : {
778 6463 : nBlockReqSize =
779 6463 : (nBlockBufSize / nBlockYSize) *
780 6463 : (nBlockYSize -
781 : static_cast<int>(
782 6463 : (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
783 6463 : 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 2318530 : vsi_l_offset nOffset = 0;
791 2318530 : bool bErrOccurred = false;
792 4504090 : if (nBlockId != m_poGDS->m_nLoadedBlock &&
793 2185560 : !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
794 : {
795 52879 : NullBlock(pImage);
796 52879 : if (bErrOccurred)
797 1 : return CE_Failure;
798 52878 : return CE_None;
799 : }
800 :
801 2265650 : 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 2264650 : CPLErr eErr = CE_None;
822 2264650 : if (m_poGDS->nBands == 1 ||
823 209030 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
824 : {
825 2081000 : if (nBlockReqSize < nBlockBufSize)
826 3024 : memset(pImage, 0, nBlockBufSize);
827 :
828 2081000 : if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
829 : {
830 81 : memset(pImage, 0, nBlockBufSize);
831 81 : return CE_Failure;
832 : }
833 : }
834 : else
835 : {
836 : /* --------------------------------------------------------------------
837 : */
838 : /* Load desired block */
839 : /* --------------------------------------------------------------------
840 : */
841 183656 : eErr = m_poGDS->LoadBlockBuf(nBlockId);
842 183656 : 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 183630 : bool bDoCopyWords = true;
851 52169 : if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
852 46470 : eAccess == GA_ReadOnly &&
853 37202 : (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
854 36417 : ((eDataType == GDT_UInt8 && m_poGDS->m_nBitsPerSample == 8) ||
855 436 : (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
856 236069 : (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
857 72508 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
858 36254 : GDALGetDataTypeSizeBytes(eDataType) <
859 36254 : GDALGetCacheMax64() / m_poGDS->nBands)
860 : {
861 36254 : bDoCopyWords = false;
862 : void *ppDestBuffers[4];
863 36254 : GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
864 : nullptr};
865 156159 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
866 : {
867 119905 : if (iBand == nBand)
868 : {
869 36254 : ppDestBuffers[iBand - 1] = pImage;
870 : }
871 : else
872 : {
873 : GDALRasterBlock *poBlock =
874 83651 : m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
875 83651 : nBlockXOff, nBlockYOff, true);
876 83651 : if (poBlock == nullptr)
877 : {
878 0 : bDoCopyWords = true;
879 0 : break;
880 : }
881 83651 : ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
882 83651 : apoLockedBlocks[iBand - 1] = poBlock;
883 : }
884 : }
885 36254 : if (!bDoCopyWords)
886 : {
887 36254 : GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
888 36254 : m_poGDS->nBands, ppDestBuffers, eDataType,
889 36254 : static_cast<size_t>(nBlockXSize) *
890 36254 : nBlockYSize);
891 : }
892 156159 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
893 : {
894 119905 : if (apoLockedBlocks[iBand - 1])
895 : {
896 83651 : apoLockedBlocks[iBand - 1]->DropLock();
897 : }
898 : }
899 : }
900 :
901 183630 : if (bDoCopyWords)
902 : {
903 147376 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
904 147376 : GByte *pabyImage =
905 147376 : m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
906 :
907 147376 : GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
908 : pImage, eDataType, nWordBytes,
909 147376 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
910 :
911 147376 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
912 : }
913 : }
914 :
915 2264550 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
916 :
917 2264550 : return eErr;
918 : }
919 :
920 : /************************************************************************/
921 : /* CacheMaskForBlock() */
922 : /************************************************************************/
923 :
924 2266930 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
925 :
926 : {
927 : // Preload mask data if layout compatible and we have cached ranges
928 2267040 : 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 2266930 : }
943 :
944 : /************************************************************************/
945 : /* FillCacheForOtherBands() */
946 : /************************************************************************/
947 :
948 147590 : 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 147590 : CPLErr eErr = CE_None;
968 442770 : if (m_poGDS->nBands != 1 &&
969 147590 : m_poGDS->nBands <
970 49156 : 128 && // avoid caching for datasets with too many bands
971 308108 : !m_poGDS->m_bLoadingOtherBands &&
972 25856 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
973 12928 : GDALGetDataTypeSizeBytes(eDataType) <
974 12928 : GDALGetCacheMax64() / m_poGDS->nBands)
975 : {
976 12928 : m_poGDS->m_bLoadingOtherBands = true;
977 :
978 53048 : for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
979 : {
980 40120 : if (iOtherBand == nBand)
981 12928 : continue;
982 :
983 : GDALRasterBlock *poBlock =
984 27192 : m_poGDS->GetRasterBand(iOtherBand)
985 27192 : ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
986 27192 : if (poBlock == nullptr)
987 : {
988 0 : eErr = CE_Failure;
989 0 : break;
990 : }
991 27192 : poBlock->DropLock();
992 : }
993 :
994 12928 : m_poGDS->m_bLoadingOtherBands = false;
995 : }
996 :
997 147590 : return eErr;
998 : }
999 :
1000 : /************************************************************************/
1001 : /* GetDescription() */
1002 : /************************************************************************/
1003 :
1004 310910 : const char *GTiffRasterBand::GetDescription() const
1005 : {
1006 310910 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1007 :
1008 310910 : return m_osDescription;
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GetOffset() */
1013 : /************************************************************************/
1014 :
1015 316377 : double GTiffRasterBand::GetOffset(int *pbSuccess)
1016 :
1017 : {
1018 316377 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1019 :
1020 316377 : if (pbSuccess)
1021 7763 : *pbSuccess = m_bHaveOffsetScale;
1022 316377 : return m_dfOffset;
1023 : }
1024 :
1025 : /************************************************************************/
1026 : /* GetScale() */
1027 : /************************************************************************/
1028 :
1029 316380 : double GTiffRasterBand::GetScale(int *pbSuccess)
1030 :
1031 : {
1032 316380 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1033 :
1034 316380 : if (pbSuccess)
1035 7766 : *pbSuccess = m_bHaveOffsetScale;
1036 316380 : return m_dfScale;
1037 : }
1038 :
1039 : /************************************************************************/
1040 : /* GetUnitType() */
1041 : /************************************************************************/
1042 :
1043 307349 : const char *GTiffRasterBand::GetUnitType()
1044 :
1045 : {
1046 307349 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1047 307349 : if (m_osUnitType.empty())
1048 : {
1049 307148 : m_poGDS->LookForProjection();
1050 307148 : if (m_poGDS->m_pszVertUnit)
1051 9 : return m_poGDS->m_pszVertUnit;
1052 : }
1053 :
1054 307340 : 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 20093 : CSLConstList GTiffRasterBand::GetMetadata(const char *pszDomain)
1075 :
1076 : {
1077 20093 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1078 : {
1079 19905 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1080 :
1081 19905 : m_poGDS->LoadENVIHdrIfNeeded();
1082 : }
1083 188 : else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1084 : {
1085 0 : m_poGDS->LoadENVIHdrIfNeeded();
1086 : }
1087 :
1088 20093 : return m_oGTiffMDMD.GetMetadata(pszDomain);
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* GetMetadataItem() */
1093 : /************************************************************************/
1094 :
1095 23961 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1096 : const char *pszDomain)
1097 :
1098 : {
1099 23961 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1100 : {
1101 9259 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1102 :
1103 9259 : m_poGDS->LoadENVIHdrIfNeeded();
1104 : }
1105 14702 : else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1106 : {
1107 0 : m_poGDS->LoadENVIHdrIfNeeded();
1108 : }
1109 :
1110 23961 : if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1111 : {
1112 5242 : int nBlockXOff = 0;
1113 5242 : int nBlockYOff = 0;
1114 :
1115 5242 : if (EQUAL(pszName, "JPEGTABLES"))
1116 : {
1117 11 : uint32_t nJPEGTableSize = 0;
1118 11 : void *pJPEGTable = nullptr;
1119 11 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1120 11 : &nJPEGTableSize, &pJPEGTable) != 1 ||
1121 11 : pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1122 : {
1123 0 : return nullptr;
1124 : }
1125 11 : char *const pszHex = CPLBinaryToHex(
1126 : nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1127 11 : const char *pszReturn = CPLSPrintf("%s", pszHex);
1128 11 : CPLFree(pszHex);
1129 :
1130 11 : return pszReturn;
1131 : }
1132 :
1133 5231 : if (EQUAL(pszName, "IFD_OFFSET"))
1134 : {
1135 178 : return CPLSPrintf(CPL_FRMT_GUIB,
1136 89 : static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1137 : }
1138 :
1139 5142 : if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1140 : 2)
1141 : {
1142 4422 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1143 4421 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1144 19 : return nullptr;
1145 :
1146 4403 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1147 4403 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1148 : {
1149 3592 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1150 : }
1151 :
1152 4403 : vsi_l_offset nOffset = 0;
1153 4403 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1154 : nullptr))
1155 : {
1156 185 : return nullptr;
1157 : }
1158 :
1159 4218 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1160 : }
1161 :
1162 720 : if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1163 : {
1164 720 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1165 719 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1166 2 : return nullptr;
1167 :
1168 718 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1169 718 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1170 : {
1171 244 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1172 : }
1173 :
1174 718 : vsi_l_offset nByteCount = 0;
1175 718 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1176 : nullptr))
1177 : {
1178 87 : return nullptr;
1179 : }
1180 :
1181 631 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1182 0 : }
1183 : }
1184 18719 : else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1185 : {
1186 131 : if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1187 131 : return HasBlockCache() ? "1" : "0";
1188 : }
1189 :
1190 18588 : const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1191 :
1192 18588 : if (pszRet == nullptr && eDataType == GDT_UInt8 && pszName && pszDomain &&
1193 15962 : EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1194 : {
1195 : // to get a chance of emitting the warning about this legacy usage
1196 3716 : pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1197 : }
1198 18588 : return pszRet;
1199 : }
1200 :
1201 : /************************************************************************/
1202 : /* GetColorInterpretation() */
1203 : /************************************************************************/
1204 :
1205 461680 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1206 :
1207 : {
1208 461680 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1209 :
1210 461680 : return m_eBandInterp;
1211 : }
1212 :
1213 : /************************************************************************/
1214 : /* GetColorTable() */
1215 : /************************************************************************/
1216 :
1217 12531 : GDALColorTable *GTiffRasterBand::GetColorTable()
1218 :
1219 : {
1220 12531 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1221 :
1222 12531 : if (nBand == 1)
1223 10545 : return m_poGDS->m_poColorTable.get();
1224 :
1225 1986 : return nullptr;
1226 : }
1227 :
1228 : /************************************************************************/
1229 : /* GetNoDataValue() */
1230 : /************************************************************************/
1231 :
1232 957144 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1233 :
1234 : {
1235 957144 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1236 :
1237 957144 : int bSuccess = FALSE;
1238 957144 : double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1239 957144 : if (bSuccess)
1240 : {
1241 4 : if (pbSuccess)
1242 4 : *pbSuccess = TRUE;
1243 :
1244 4 : return dfNoDataValue;
1245 : }
1246 :
1247 957140 : if (m_bNoDataSet)
1248 : {
1249 4999 : if (pbSuccess)
1250 4952 : *pbSuccess = TRUE;
1251 :
1252 4999 : return m_dfNoDataValue;
1253 : }
1254 :
1255 952141 : if (m_poGDS->m_bNoDataSet)
1256 : {
1257 423522 : if (pbSuccess)
1258 423296 : *pbSuccess = TRUE;
1259 :
1260 423522 : return m_poGDS->m_dfNoDataValue;
1261 : }
1262 :
1263 528619 : if (m_bNoDataSetAsInt64)
1264 : {
1265 0 : if (pbSuccess)
1266 0 : *pbSuccess = TRUE;
1267 :
1268 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1269 : }
1270 :
1271 528619 : if (m_poGDS->m_bNoDataSetAsInt64)
1272 : {
1273 0 : if (pbSuccess)
1274 0 : *pbSuccess = TRUE;
1275 :
1276 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1277 : }
1278 :
1279 528619 : if (m_bNoDataSetAsUInt64)
1280 : {
1281 0 : if (pbSuccess)
1282 0 : *pbSuccess = TRUE;
1283 :
1284 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1285 : }
1286 :
1287 528619 : if (m_poGDS->m_bNoDataSetAsUInt64)
1288 : {
1289 0 : if (pbSuccess)
1290 0 : *pbSuccess = TRUE;
1291 :
1292 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1293 : }
1294 :
1295 528619 : if (pbSuccess)
1296 528479 : *pbSuccess = FALSE;
1297 528619 : return dfNoDataValue;
1298 : }
1299 :
1300 : /************************************************************************/
1301 : /* GetNoDataValueAsInt64() */
1302 : /************************************************************************/
1303 :
1304 64 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1305 :
1306 : {
1307 64 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1308 :
1309 64 : if (eDataType == GDT_UInt64)
1310 : {
1311 0 : CPLError(CE_Failure, CPLE_AppDefined,
1312 : "GetNoDataValueAsUInt64() should be called instead");
1313 0 : if (pbSuccess)
1314 0 : *pbSuccess = FALSE;
1315 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1316 : }
1317 64 : if (eDataType != GDT_Int64)
1318 : {
1319 0 : CPLError(CE_Failure, CPLE_AppDefined,
1320 : "GetNoDataValue() should be called instead");
1321 0 : if (pbSuccess)
1322 0 : *pbSuccess = FALSE;
1323 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1324 : }
1325 :
1326 64 : int bSuccess = FALSE;
1327 : const auto nNoDataValue =
1328 64 : GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1329 64 : if (bSuccess)
1330 : {
1331 0 : if (pbSuccess)
1332 0 : *pbSuccess = TRUE;
1333 :
1334 0 : return nNoDataValue;
1335 : }
1336 :
1337 64 : if (m_bNoDataSetAsInt64)
1338 : {
1339 2 : if (pbSuccess)
1340 2 : *pbSuccess = TRUE;
1341 :
1342 2 : return m_nNoDataValueInt64;
1343 : }
1344 :
1345 62 : if (m_poGDS->m_bNoDataSetAsInt64)
1346 : {
1347 11 : if (pbSuccess)
1348 10 : *pbSuccess = TRUE;
1349 :
1350 11 : return m_poGDS->m_nNoDataValueInt64;
1351 : }
1352 :
1353 51 : if (pbSuccess)
1354 51 : *pbSuccess = FALSE;
1355 51 : return nNoDataValue;
1356 : }
1357 :
1358 : /************************************************************************/
1359 : /* GetNoDataValueAsUInt64() */
1360 : /************************************************************************/
1361 :
1362 46 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1363 :
1364 : {
1365 46 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1366 :
1367 46 : if (eDataType == GDT_Int64)
1368 : {
1369 0 : CPLError(CE_Failure, CPLE_AppDefined,
1370 : "GetNoDataValueAsInt64() should be called instead");
1371 0 : if (pbSuccess)
1372 0 : *pbSuccess = FALSE;
1373 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1374 : }
1375 46 : if (eDataType != GDT_UInt64)
1376 : {
1377 0 : CPLError(CE_Failure, CPLE_AppDefined,
1378 : "GetNoDataValue() should be called instead");
1379 0 : if (pbSuccess)
1380 0 : *pbSuccess = FALSE;
1381 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1382 : }
1383 :
1384 46 : int bSuccess = FALSE;
1385 : const auto nNoDataValue =
1386 46 : GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1387 46 : if (bSuccess)
1388 : {
1389 0 : if (pbSuccess)
1390 0 : *pbSuccess = TRUE;
1391 :
1392 0 : return nNoDataValue;
1393 : }
1394 :
1395 46 : if (m_bNoDataSetAsUInt64)
1396 : {
1397 4 : if (pbSuccess)
1398 4 : *pbSuccess = TRUE;
1399 :
1400 4 : return m_nNoDataValueUInt64;
1401 : }
1402 :
1403 42 : if (m_poGDS->m_bNoDataSetAsUInt64)
1404 : {
1405 7 : if (pbSuccess)
1406 6 : *pbSuccess = TRUE;
1407 :
1408 7 : return m_poGDS->m_nNoDataValueUInt64;
1409 : }
1410 :
1411 35 : if (pbSuccess)
1412 35 : *pbSuccess = FALSE;
1413 35 : return nNoDataValue;
1414 : }
1415 :
1416 : /************************************************************************/
1417 : /* GetOverviewCount() */
1418 : /************************************************************************/
1419 :
1420 1320040 : int GTiffRasterBand::GetOverviewCount()
1421 :
1422 : {
1423 1320040 : if (!m_poGDS->AreOverviewsEnabled())
1424 30 : return 0;
1425 :
1426 1320010 : m_poGDS->ScanDirectories();
1427 :
1428 1320010 : if (!m_poGDS->m_apoOverviewDS.empty())
1429 : {
1430 267339 : return static_cast<int>(m_poGDS->m_apoOverviewDS.size());
1431 : }
1432 :
1433 1052670 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1434 1052670 : if (nOverviewCount > 0)
1435 391 : return nOverviewCount;
1436 :
1437 : // Implicit JPEG overviews are normally hidden, except when doing
1438 : // IRasterIO() operations.
1439 1052280 : if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1440 1044190 : return m_poGDS->GetJPEGOverviewCount();
1441 :
1442 8092 : return 0;
1443 : }
1444 :
1445 : /************************************************************************/
1446 : /* GetOverview() */
1447 : /************************************************************************/
1448 :
1449 74187 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1450 :
1451 : {
1452 74187 : m_poGDS->ScanDirectories();
1453 :
1454 74187 : if (!m_poGDS->m_apoOverviewDS.empty())
1455 : {
1456 : // Do we have internal overviews?
1457 73591 : if (i < 0 || static_cast<size_t>(i) >= m_poGDS->m_apoOverviewDS.size())
1458 8 : return nullptr;
1459 :
1460 73583 : return m_poGDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
1461 : }
1462 :
1463 596 : GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1464 596 : if (poOvrBand != nullptr)
1465 391 : return poOvrBand;
1466 :
1467 : // For consistency with GetOverviewCount(), we should also test
1468 : // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1469 : // to query them for testing purposes.
1470 205 : if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1471 164 : return m_poGDS->m_apoJPEGOverviewDS[i]->GetRasterBand(nBand);
1472 :
1473 41 : return nullptr;
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* GetMaskFlags() */
1478 : /************************************************************************/
1479 :
1480 22590 : int GTiffRasterBand::GetMaskFlags()
1481 : {
1482 22590 : m_poGDS->ScanDirectories();
1483 :
1484 22590 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1485 : {
1486 0 : return GMF_PER_DATASET;
1487 : }
1488 :
1489 22590 : if (m_poGDS->m_poMaskDS != nullptr)
1490 : {
1491 222 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1492 : {
1493 214 : return GMF_PER_DATASET;
1494 : }
1495 :
1496 8 : return 0;
1497 : }
1498 :
1499 22368 : if (m_poGDS->m_bIsOverview)
1500 : {
1501 444 : return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1502 : }
1503 :
1504 21924 : return GDALPamRasterBand::GetMaskFlags();
1505 : }
1506 :
1507 : /************************************************************************/
1508 : /* GetMaskBand() */
1509 : /************************************************************************/
1510 :
1511 117846 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1512 : {
1513 117846 : m_poGDS->ScanDirectories();
1514 :
1515 117846 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1516 : {
1517 31 : return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1518 : }
1519 :
1520 117815 : if (m_poGDS->m_poMaskDS != nullptr)
1521 : {
1522 691 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1523 674 : return m_poGDS->m_poMaskDS->GetRasterBand(1);
1524 :
1525 17 : return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1526 : }
1527 :
1528 117124 : if (m_poGDS->m_bIsOverview)
1529 : {
1530 : GDALRasterBand *poBaseMask =
1531 119 : m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1532 119 : if (poBaseMask)
1533 : {
1534 119 : const int nOverviews = poBaseMask->GetOverviewCount();
1535 164 : for (int i = 0; i < nOverviews; i++)
1536 : {
1537 93 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1538 141 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1539 48 : poOvr->GetYSize() == GetYSize())
1540 : {
1541 48 : return poOvr;
1542 : }
1543 : }
1544 : }
1545 : }
1546 :
1547 117076 : return GDALPamRasterBand::GetMaskBand();
1548 : }
1549 :
1550 : /************************************************************************/
1551 : /* IsMaskBand() */
1552 : /************************************************************************/
1553 :
1554 1039 : bool GTiffRasterBand::IsMaskBand() const
1555 : {
1556 1071 : return (m_poGDS->m_poImageryDS != nullptr &&
1557 32 : m_poGDS->m_poImageryDS->m_poMaskDS.get() == m_poGDS) ||
1558 2023 : m_eBandInterp == GCI_AlphaBand ||
1559 1991 : m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1560 : }
1561 :
1562 : /************************************************************************/
1563 : /* GetMaskValueRange() */
1564 : /************************************************************************/
1565 :
1566 0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1567 : {
1568 0 : if (!IsMaskBand())
1569 0 : return GMVR_UNKNOWN;
1570 0 : if (m_poGDS->m_nBitsPerSample == 1)
1571 0 : return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1572 0 : : GMVR_0_AND_1_ONLY;
1573 0 : return GMVR_UNKNOWN;
1574 : }
|