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 "gtiff.h"
29 : #include "tifvsi.h"
30 :
31 : /************************************************************************/
32 : /* GetDefaultRAT() */
33 : /************************************************************************/
34 :
35 307428 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
36 :
37 : {
38 307428 : if (m_poGDS->m_poBaseDS != nullptr)
39 52 : return m_poRAT.get();
40 :
41 307376 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
42 :
43 : // RAT from PAM has priority over RAT in GDAL_METADATA TIFF tag
44 307376 : if (!m_bRATTriedReadingFromPAM)
45 : {
46 305430 : m_bRATTriedReadingFromPAM = true;
47 305430 : auto poRAT = GDALPamRasterBand::GetDefaultRAT();
48 305430 : if (poRAT)
49 : {
50 2 : m_bRATSet = true;
51 2 : m_poRAT.reset(poRAT->Clone());
52 2 : return m_poRAT.get();
53 : }
54 : }
55 :
56 307374 : if (m_bRATSet)
57 1956 : return m_poRAT.get();
58 :
59 305418 : m_bRATSet = true;
60 :
61 : // Try reading from a .vat.dbf side car file
62 305418 : if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_osFilename.c_str()))
63 0 : return nullptr;
64 610836 : const std::string osVATDBF = m_poGDS->m_osFilename + ".vat.dbf";
65 305418 : CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
66 610799 : if (papszSiblingFiles &&
67 : // cppcheck-suppress knownConditionTrueFalse
68 305381 : GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
69 : {
70 : int iSibling =
71 305381 : CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
72 305381 : if (iSibling >= 0)
73 : {
74 3 : CPLString osFilename = m_poGDS->m_osFilename;
75 3 : osFilename.resize(
76 3 : m_poGDS->m_osFilename.size() -
77 3 : strlen(CPLGetFilename(m_poGDS->m_osFilename.c_str())));
78 3 : osFilename += papszSiblingFiles[iSibling];
79 3 : m_poRAT = GDALLoadVATDBF(osFilename.c_str());
80 : }
81 305381 : return m_poRAT.get();
82 : }
83 : VSIStatBufL sStatBuf;
84 37 : if (VSIStatL(osVATDBF.c_str(), &sStatBuf) == 0)
85 1 : m_poRAT = GDALLoadVATDBF(osVATDBF.c_str());
86 37 : return m_poRAT.get();
87 : }
88 :
89 : /************************************************************************/
90 : /* GetHistogram() */
91 : /************************************************************************/
92 :
93 24 : CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
94 : GUIntBig *panHistogram,
95 : int bIncludeOutOfRange, int bApproxOK,
96 : GDALProgressFunc pfnProgress,
97 : void *pProgressData)
98 : {
99 24 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
100 24 : return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
101 : bIncludeOutOfRange, bApproxOK,
102 24 : pfnProgress, pProgressData);
103 : }
104 :
105 : /************************************************************************/
106 : /* GetDefaultHistogram() */
107 : /************************************************************************/
108 :
109 22 : CPLErr GTiffRasterBand::GetDefaultHistogram(
110 : double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
111 : int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
112 : {
113 22 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
114 22 : return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
115 : ppanHistogram, bForce,
116 22 : pfnProgress, pProgressData);
117 : }
118 :
119 : /************************************************************************/
120 : /* DirectIO() */
121 : /************************************************************************/
122 :
123 : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
124 : // block reading. Restricted to simple TIFF configurations
125 : // (uncompressed data, standard data types). Particularly useful to extract
126 : // sub-windows of data on a large /vsicurl dataset).
127 : // Returns -1 if DirectIO() can't be supported on that file.
128 :
129 2522 : int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
130 : int nXSize, int nYSize, void *pData,
131 : int nBufXSize, int nBufYSize,
132 : GDALDataType eBufType, GSpacing nPixelSpace,
133 : GSpacing nLineSpace,
134 : GDALRasterIOExtraArg *psExtraArg)
135 : {
136 2522 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
137 5044 : if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
138 2522 : (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
139 795 : m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
140 0 : m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
141 2522 : IsBaseGTiffClass()))
142 : {
143 0 : return -1;
144 : }
145 2522 : m_poGDS->Crystalize();
146 :
147 : // Only know how to deal with nearest neighbour in this optimized routine.
148 2522 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
149 607 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
150 : {
151 66 : return -1;
152 : }
153 :
154 : #if DEBUG_VERBOSE
155 : CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
156 : nYSize, nBufXSize, nBufYSize);
157 : #endif
158 :
159 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
160 2456 : if (m_poGDS->GetAccess() == GA_Update)
161 : {
162 0 : m_poGDS->FlushCache(false);
163 0 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
164 : }
165 :
166 2456 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
167 : {
168 716 : const int nDTSize = nDTSizeBits / 8;
169 716 : const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
170 1432 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
171 716 : (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
172 : : 1));
173 716 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
174 : {
175 28 : m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
176 14 : VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
177 14 : if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
178 0 : return CE_Failure;
179 : }
180 :
181 716 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
182 : FetchBufferDirectIO oFetcher(fp,
183 716 : m_poGDS->m_pTempBufferForCommonDirectIO,
184 716 : nTempBufferForCommonDirectIOSize);
185 :
186 1432 : return m_poGDS->CommonDirectIOClassic(
187 : oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
188 716 : eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
189 : }
190 :
191 : // Get strip offsets.
192 1740 : toff_t *panTIFFOffsets = nullptr;
193 1740 : if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
194 3480 : &panTIFFOffsets) ||
195 1740 : panTIFFOffsets == nullptr)
196 : {
197 0 : return CE_Failure;
198 : }
199 :
200 : // Sub-sampling or over-sampling can only be done at last stage.
201 1740 : int nReqXSize = nXSize;
202 : // Can do sub-sampling at the extraction stage.
203 1740 : const int nReqYSize = std::min(nBufYSize, nYSize);
204 : // TODO(schwehr): Make ppData be GByte**.
205 : void **ppData =
206 1740 : static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
207 : vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
208 1740 : VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
209 : size_t *panSizes =
210 1740 : static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
211 1740 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
212 1740 : void *pTmpBuffer = nullptr;
213 1740 : int eErr = CE_None;
214 1740 : int nContigBands =
215 1740 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
216 1740 : int nSrcPixelSize = nDTSize * nContigBands;
217 :
218 1740 : if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
219 0 : eErr = CE_Failure;
220 1427 : else if (nXSize != nBufXSize || nYSize != nBufYSize ||
221 1427 : eBufType != eDataType ||
222 3167 : nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
223 : nContigBands > 1)
224 : {
225 : // We need a temporary buffer for over-sampling/sub-sampling
226 : // and/or data type conversion.
227 1534 : pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
228 1534 : if (pTmpBuffer == nullptr)
229 0 : eErr = CE_Failure;
230 : }
231 :
232 : // Prepare data extraction.
233 1740 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
234 :
235 58549 : for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
236 : {
237 56809 : if (pTmpBuffer == nullptr)
238 17766 : ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
239 : else
240 39043 : ppData[iLine] =
241 39043 : static_cast<GByte *>(pTmpBuffer) +
242 39043 : static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
243 56809 : int nSrcLine = 0;
244 56809 : if (nBufYSize < nYSize) // Sub-sampling in y.
245 3720 : nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
246 : else
247 53089 : nSrcLine = nYOff + iLine;
248 :
249 56809 : const int nBlockXOff = 0;
250 56809 : const int nBlockYOff = nSrcLine / nBlockYSize;
251 56809 : const int nYOffsetInBlock = nSrcLine % nBlockYSize;
252 56809 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
253 :
254 56809 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
255 56809 : if (panOffsets[iLine] == 0) // We don't support sparse files.
256 1047 : eErr = -1;
257 :
258 56809 : panOffsets[iLine] +=
259 56809 : (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
260 56809 : nSrcPixelSize;
261 56809 : panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
262 : }
263 :
264 : // Extract data from the file.
265 1740 : if (eErr == CE_None)
266 : {
267 693 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
268 : const int nRet =
269 693 : VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
270 693 : if (nRet != 0)
271 16 : eErr = CE_Failure;
272 : }
273 :
274 : // Byte-swap if necessary.
275 1740 : if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
276 : {
277 20878 : for (int iLine = 0; iLine < nReqYSize; ++iLine)
278 : {
279 20620 : if (GDALDataTypeIsComplex(eDataType))
280 10315 : GDALSwapWords(ppData[iLine], nDTSize / 2,
281 10315 : 2 * nReqXSize * nContigBands, nDTSize / 2);
282 : else
283 10305 : GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
284 : nDTSize);
285 : }
286 : }
287 :
288 : // Over-sampling/sub-sampling and/or data type conversion.
289 1740 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
290 1740 : if (eErr == CE_None && pTmpBuffer != nullptr)
291 : {
292 508 : const bool bOneByteCopy =
293 904 : (eDataType == eBufType &&
294 396 : (eDataType == GDT_Byte || eDataType == GDT_Int8));
295 150707 : for (int iY = 0; iY < nBufYSize; ++iY)
296 : {
297 300398 : const int iSrcY = nBufYSize <= nYSize
298 150199 : ? iY
299 120528 : : static_cast<int>((iY + 0.5) * dfSrcYInc);
300 :
301 300398 : GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
302 150199 : (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
303 150199 : GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
304 150199 : if (nBufXSize == nXSize)
305 : {
306 25952 : GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
307 : pabyDstData, eBufType,
308 : static_cast<int>(nPixelSpace), nBufXSize);
309 : }
310 : else
311 : {
312 124247 : if (bOneByteCopy)
313 : {
314 25435 : double dfSrcX = 0.5 * dfSrcXInc;
315 2147110 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
316 : {
317 2121670 : const int iSrcX = static_cast<int>(dfSrcX);
318 2121670 : pabyDstData[iX * nPixelSpace] =
319 2121670 : pabySrcData[iSrcX * nSrcPixelSize];
320 : }
321 : }
322 : else
323 : {
324 98812 : double dfSrcX = 0.5 * dfSrcXInc;
325 7730840 : for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
326 : {
327 7632030 : const int iSrcX = static_cast<int>(dfSrcX);
328 7632030 : GDALCopyWords(
329 7632030 : pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
330 7632030 : pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
331 : }
332 : }
333 : }
334 : }
335 : }
336 :
337 : // Cleanup.
338 1740 : CPLFree(pTmpBuffer);
339 1740 : CPLFree(ppData);
340 1740 : CPLFree(panOffsets);
341 1740 : CPLFree(panSizes);
342 :
343 1740 : return eErr;
344 : }
345 :
346 : /************************************************************************/
347 : /* GetVirtualMemAuto() */
348 : /************************************************************************/
349 :
350 17 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
351 : int *pnPixelSpace,
352 : GIntBig *pnLineSpace,
353 : char **papszOptions)
354 : {
355 17 : const char *pszImpl = CSLFetchNameValueDef(
356 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
357 17 : if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
358 16 : EQUAL(pszImpl, "TRUE"))
359 : {
360 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
361 1 : pnLineSpace, papszOptions);
362 : }
363 :
364 16 : CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
365 : pnLineSpace, papszOptions);
366 16 : if (psRet != nullptr)
367 : {
368 14 : CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
369 14 : return psRet;
370 : }
371 :
372 2 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
373 1 : EQUAL(pszImpl, "FALSE"))
374 : {
375 1 : return nullptr;
376 : }
377 :
378 1 : CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
379 1 : return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
380 1 : papszOptions);
381 : }
382 :
383 : /************************************************************************/
384 : /* DropReferenceVirtualMem() */
385 : /************************************************************************/
386 :
387 8 : void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
388 : {
389 : // This function may also be called when the dataset and rasterband
390 : // objects have been destroyed.
391 : // If they are still alive, it updates the reference counter of the
392 : // base mapping to invalidate the pointer to it if needed.
393 :
394 8 : GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
395 8 : GTiffRasterBand *poSelf = *ppoSelf;
396 :
397 8 : if (poSelf != nullptr)
398 : {
399 8 : if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
400 : {
401 4 : poSelf->m_poGDS->m_pBaseMapping = nullptr;
402 : }
403 8 : poSelf->m_aSetPSelf.erase(ppoSelf);
404 : }
405 8 : CPLFree(pUserData);
406 8 : }
407 :
408 : /************************************************************************/
409 : /* GetVirtualMemAutoInternal() */
410 : /************************************************************************/
411 :
412 20 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(GDALRWFlag eRWFlag,
413 : int *pnPixelSpace,
414 : GIntBig *pnLineSpace,
415 : char **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 898 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
655 : int nYSize, int nMaskFlagStop,
656 : double *pdfDataPct)
657 : {
658 898 : if (eAccess == GA_Update)
659 95 : m_poGDS->FlushCache(false);
660 :
661 898 : const int iXBlockStart = nXOff / nBlockXSize;
662 898 : const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
663 898 : const int iYBlockStart = nYOff / nBlockYSize;
664 898 : const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
665 898 : int nStatus = 0;
666 898 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
667 898 : GIntBig nPixelsData = 0;
668 2496 : for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
669 : {
670 4306 : for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
671 : {
672 2708 : const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
673 2708 : int nBlockId = nBlockIdBand0;
674 2708 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
675 136 : nBlockId =
676 136 : nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
677 2708 : vsi_l_offset nOffset = 0;
678 2708 : vsi_l_offset nLength = 0;
679 2708 : bool bHasData = false;
680 2708 : bool bError = false;
681 2708 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
682 : &bError))
683 : {
684 1866 : if (bError)
685 836 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
686 1866 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
687 : }
688 : else
689 : {
690 842 : if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
691 733 : m_poGDS->eAccess == GA_ReadOnly &&
692 691 : ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
693 691 : !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 691 : VSIFGetRangeStatusL(fp, nOffset, nLength);
700 691 : if (eStatus == VSI_RANGE_STATUS_HOLE)
701 : {
702 0 : nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
703 : }
704 : else
705 : {
706 691 : bHasData = true;
707 691 : }
708 : }
709 : else
710 : {
711 151 : bHasData = true;
712 : }
713 : }
714 2708 : if (bHasData)
715 : {
716 842 : const int nXBlockRight =
717 842 : (iX * nBlockXSize > INT_MAX - nBlockXSize)
718 842 : ? INT_MAX
719 842 : : (iX + 1) * nBlockXSize;
720 842 : const int nYBlockBottom =
721 842 : (iY * nBlockYSize > INT_MAX - nBlockYSize)
722 842 : ? INT_MAX
723 842 : : (iY + 1) * nBlockYSize;
724 :
725 1684 : nPixelsData += (static_cast<GIntBig>(
726 842 : std::min(nXBlockRight, nXOff + nXSize)) -
727 842 : std::max(iX * nBlockXSize, nXOff)) *
728 842 : (std::min(nYBlockBottom, nYOff + nYSize) -
729 842 : std::max(iY * nBlockYSize, nYOff));
730 842 : nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
731 : }
732 2708 : if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
733 : {
734 836 : if (pdfDataPct)
735 0 : *pdfDataPct = -1.0;
736 836 : 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 2310550 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
751 :
752 : {
753 2310550 : m_poGDS->Crystalize();
754 :
755 2310220 : GPtrDiff_t nBlockBufSize = 0;
756 2310220 : if (TIFFIsTiled(m_poGDS->m_hTIFF))
757 : {
758 57886 : nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
759 : }
760 : else
761 : {
762 2252350 : CPLAssert(nBlockXOff == 0);
763 : nBlockBufSize =
764 2252350 : static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
765 : }
766 :
767 2310270 : 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 2310380 : auto nBlockReqSize = nBlockBufSize;
775 :
776 2310380 : if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
777 : {
778 6223 : nBlockReqSize =
779 6223 : (nBlockBufSize / nBlockYSize) *
780 6223 : (nBlockYSize -
781 : static_cast<int>(
782 6223 : (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
783 6223 : 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 2310380 : vsi_l_offset nOffset = 0;
791 2310380 : bool bErrOccurred = false;
792 4488000 : if (nBlockId != m_poGDS->m_nLoadedBlock &&
793 2177400 : !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
794 : {
795 50229 : NullBlock(pImage);
796 50229 : if (bErrOccurred)
797 1 : return CE_Failure;
798 50228 : return CE_None;
799 : }
800 :
801 2260370 : 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 2259370 : CPLErr eErr = CE_None;
822 2259370 : if (m_poGDS->nBands == 1 ||
823 208243 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
824 : {
825 2075900 : if (nBlockReqSize < nBlockBufSize)
826 2879 : memset(pImage, 0, nBlockBufSize);
827 :
828 2075900 : 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 183471 : eErr = m_poGDS->LoadBlockBuf(nBlockId);
842 183470 : if (eErr != CE_None)
843 : {
844 25 : memset(pImage, 0,
845 50 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
846 25 : GDALGetDataTypeSizeBytes(eDataType));
847 25 : return eErr;
848 : }
849 :
850 183445 : bool bDoCopyWords = true;
851 52051 : if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
852 46366 : eAccess == GA_ReadOnly &&
853 37106 : (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
854 36336 : ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
855 432 : (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
856 235766 : (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
857 72352 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
858 36175 : GDALGetDataTypeSizeBytes(eDataType) <
859 36177 : GDALGetCacheMax64() / m_poGDS->nBands)
860 : {
861 36177 : bDoCopyWords = false;
862 : void *ppDestBuffers[4];
863 36177 : GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
864 : nullptr};
865 155847 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
866 : {
867 119670 : if (iBand == nBand)
868 : {
869 36177 : ppDestBuffers[iBand - 1] = pImage;
870 : }
871 : else
872 : {
873 : GDALRasterBlock *poBlock =
874 83493 : m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
875 83493 : nBlockXOff, nBlockYOff, true);
876 83493 : if (poBlock == nullptr)
877 : {
878 0 : bDoCopyWords = true;
879 0 : break;
880 : }
881 83493 : ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
882 83493 : apoLockedBlocks[iBand - 1] = poBlock;
883 : }
884 : }
885 36177 : if (!bDoCopyWords)
886 : {
887 36177 : GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
888 36177 : m_poGDS->nBands, ppDestBuffers, eDataType,
889 36177 : static_cast<size_t>(nBlockXSize) *
890 36177 : nBlockYSize);
891 : }
892 155847 : for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
893 : {
894 119670 : if (apoLockedBlocks[iBand - 1])
895 : {
896 83493 : apoLockedBlocks[iBand - 1]->DropLock();
897 : }
898 : }
899 : }
900 :
901 183447 : if (bDoCopyWords)
902 : {
903 147268 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
904 147268 : GByte *pabyImage =
905 147268 : m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
906 :
907 147268 : GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
908 : pImage, eDataType, nWordBytes,
909 147268 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
910 :
911 147283 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
912 : }
913 : }
914 :
915 2259090 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
916 :
917 2259240 : return eErr;
918 : }
919 :
920 : /************************************************************************/
921 : /* CacheMaskForBlock() */
922 : /************************************************************************/
923 :
924 2261580 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
925 :
926 : {
927 : // Preload mask data if layout compatible and we have cached ranges
928 2261590 : 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 291 : 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 2261480 : }
943 :
944 : /************************************************************************/
945 : /* FillCacheForOtherBands() */
946 : /************************************************************************/
947 :
948 147496 : 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 147496 : CPLErr eErr = CE_None;
968 442484 : if (m_poGDS->nBands != 1 &&
969 147494 : m_poGDS->nBands <
970 49061 : 128 && // avoid caching for datasets with too many bands
971 307881 : !m_poGDS->m_bLoadingOtherBands &&
972 25787 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
973 12893 : GDALGetDataTypeSizeBytes(eDataType) <
974 12894 : GDALGetCacheMax64() / m_poGDS->nBands)
975 : {
976 12892 : m_poGDS->m_bLoadingOtherBands = true;
977 :
978 52910 : for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
979 : {
980 40014 : if (iOtherBand == nBand)
981 12892 : continue;
982 :
983 : GDALRasterBlock *poBlock =
984 27122 : m_poGDS->GetRasterBand(iOtherBand)
985 27123 : ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
986 27127 : if (poBlock == nullptr)
987 : {
988 0 : eErr = CE_Failure;
989 0 : break;
990 : }
991 27127 : poBlock->DropLock();
992 : }
993 :
994 12896 : m_poGDS->m_bLoadingOtherBands = false;
995 : }
996 :
997 147498 : return eErr;
998 : }
999 :
1000 : /************************************************************************/
1001 : /* GetDescription() */
1002 : /************************************************************************/
1003 :
1004 308056 : const char *GTiffRasterBand::GetDescription() const
1005 : {
1006 308056 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1007 :
1008 308056 : return m_osDescription;
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GetOffset() */
1013 : /************************************************************************/
1014 :
1015 315688 : double GTiffRasterBand::GetOffset(int *pbSuccess)
1016 :
1017 : {
1018 315688 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1019 :
1020 315688 : if (pbSuccess)
1021 7524 : *pbSuccess = m_bHaveOffsetScale;
1022 315688 : return m_dfOffset;
1023 : }
1024 :
1025 : /************************************************************************/
1026 : /* GetScale() */
1027 : /************************************************************************/
1028 :
1029 315691 : double GTiffRasterBand::GetScale(int *pbSuccess)
1030 :
1031 : {
1032 315691 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1033 :
1034 315691 : if (pbSuccess)
1035 7527 : *pbSuccess = m_bHaveOffsetScale;
1036 315691 : return m_dfScale;
1037 : }
1038 :
1039 : /************************************************************************/
1040 : /* GetUnitType() */
1041 : /************************************************************************/
1042 :
1043 306868 : const char *GTiffRasterBand::GetUnitType()
1044 :
1045 : {
1046 306868 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1047 306868 : if (m_osUnitType.empty())
1048 : {
1049 306675 : m_poGDS->LookForProjection();
1050 306675 : if (m_poGDS->m_pszVertUnit)
1051 9 : return m_poGDS->m_pszVertUnit;
1052 : }
1053 :
1054 306859 : return m_osUnitType.c_str();
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* GetMetadataDomainList() */
1059 : /************************************************************************/
1060 :
1061 12 : char **GTiffRasterBand::GetMetadataDomainList()
1062 : {
1063 12 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1064 :
1065 12 : return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1066 : }
1067 :
1068 : /************************************************************************/
1069 : /* GetMetadata() */
1070 : /************************************************************************/
1071 :
1072 17257 : char **GTiffRasterBand::GetMetadata(const char *pszDomain)
1073 :
1074 : {
1075 17257 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1076 : {
1077 17073 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1078 : }
1079 :
1080 17257 : return m_oGTiffMDMD.GetMetadata(pszDomain);
1081 : }
1082 :
1083 : /************************************************************************/
1084 : /* GetMetadataItem() */
1085 : /************************************************************************/
1086 :
1087 23444 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1088 : const char *pszDomain)
1089 :
1090 : {
1091 23444 : if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1092 : {
1093 9037 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1094 : }
1095 :
1096 23444 : if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1097 : {
1098 5240 : int nBlockXOff = 0;
1099 5240 : int nBlockYOff = 0;
1100 :
1101 5240 : if (EQUAL(pszName, "JPEGTABLES"))
1102 : {
1103 11 : uint32_t nJPEGTableSize = 0;
1104 11 : void *pJPEGTable = nullptr;
1105 11 : if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1106 11 : &nJPEGTableSize, &pJPEGTable) != 1 ||
1107 11 : pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1108 : {
1109 0 : return nullptr;
1110 : }
1111 11 : char *const pszHex = CPLBinaryToHex(
1112 : nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1113 11 : const char *pszReturn = CPLSPrintf("%s", pszHex);
1114 11 : CPLFree(pszHex);
1115 :
1116 11 : return pszReturn;
1117 : }
1118 :
1119 5229 : if (EQUAL(pszName, "IFD_OFFSET"))
1120 : {
1121 178 : return CPLSPrintf(CPL_FRMT_GUIB,
1122 89 : static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1123 : }
1124 :
1125 5140 : if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1126 : 2)
1127 : {
1128 4421 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1129 4420 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1130 19 : return nullptr;
1131 :
1132 4402 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1133 4402 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1134 : {
1135 3592 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1136 : }
1137 :
1138 4402 : vsi_l_offset nOffset = 0;
1139 4402 : if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1140 : nullptr))
1141 : {
1142 184 : return nullptr;
1143 : }
1144 :
1145 4218 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1146 : }
1147 :
1148 719 : if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1149 : {
1150 719 : if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1151 718 : nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1152 2 : return nullptr;
1153 :
1154 717 : int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1155 717 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1156 : {
1157 244 : nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1158 : }
1159 :
1160 717 : vsi_l_offset nByteCount = 0;
1161 717 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1162 : nullptr))
1163 : {
1164 86 : return nullptr;
1165 : }
1166 :
1167 631 : return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1168 0 : }
1169 : }
1170 18204 : else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1171 : {
1172 131 : if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1173 131 : return HasBlockCache() ? "1" : "0";
1174 : }
1175 :
1176 18073 : const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1177 :
1178 18073 : if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
1179 15574 : EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1180 : {
1181 : // to get a chance of emitting the warning about this legacy usage
1182 3620 : pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1183 : }
1184 18073 : return pszRet;
1185 : }
1186 :
1187 : /************************************************************************/
1188 : /* GetColorInterpretation() */
1189 : /************************************************************************/
1190 :
1191 460641 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1192 :
1193 : {
1194 460641 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1195 :
1196 460642 : return m_eBandInterp;
1197 : }
1198 :
1199 : /************************************************************************/
1200 : /* GetColorTable() */
1201 : /************************************************************************/
1202 :
1203 12265 : GDALColorTable *GTiffRasterBand::GetColorTable()
1204 :
1205 : {
1206 12265 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1207 :
1208 12265 : if (nBand == 1)
1209 10348 : return m_poGDS->m_poColorTable.get();
1210 :
1211 1917 : return nullptr;
1212 : }
1213 :
1214 : /************************************************************************/
1215 : /* GetNoDataValue() */
1216 : /************************************************************************/
1217 :
1218 952629 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1219 :
1220 : {
1221 952629 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1222 :
1223 952963 : int bSuccess = FALSE;
1224 952963 : double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1225 951654 : if (bSuccess)
1226 : {
1227 4 : if (pbSuccess)
1228 4 : *pbSuccess = TRUE;
1229 :
1230 4 : return dfNoDataValue;
1231 : }
1232 :
1233 951650 : if (m_bNoDataSet)
1234 : {
1235 2751 : if (pbSuccess)
1236 2711 : *pbSuccess = TRUE;
1237 :
1238 2751 : return m_dfNoDataValue;
1239 : }
1240 :
1241 948899 : if (m_poGDS->m_bNoDataSet)
1242 : {
1243 423452 : if (pbSuccess)
1244 423229 : *pbSuccess = TRUE;
1245 :
1246 423452 : return m_poGDS->m_dfNoDataValue;
1247 : }
1248 :
1249 525447 : if (m_bNoDataSetAsInt64)
1250 : {
1251 0 : if (pbSuccess)
1252 0 : *pbSuccess = TRUE;
1253 :
1254 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1255 : }
1256 :
1257 525447 : if (m_poGDS->m_bNoDataSetAsInt64)
1258 : {
1259 0 : if (pbSuccess)
1260 0 : *pbSuccess = TRUE;
1261 :
1262 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1263 : }
1264 :
1265 525447 : if (m_bNoDataSetAsUInt64)
1266 : {
1267 0 : if (pbSuccess)
1268 0 : *pbSuccess = TRUE;
1269 :
1270 0 : return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1271 : }
1272 :
1273 525447 : if (m_poGDS->m_bNoDataSetAsUInt64)
1274 : {
1275 0 : if (pbSuccess)
1276 0 : *pbSuccess = TRUE;
1277 :
1278 0 : return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1279 : }
1280 :
1281 525447 : if (pbSuccess)
1282 525987 : *pbSuccess = FALSE;
1283 525447 : return dfNoDataValue;
1284 : }
1285 :
1286 : /************************************************************************/
1287 : /* GetNoDataValueAsInt64() */
1288 : /************************************************************************/
1289 :
1290 35 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1291 :
1292 : {
1293 35 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1294 :
1295 35 : if (eDataType == GDT_UInt64)
1296 : {
1297 0 : CPLError(CE_Failure, CPLE_AppDefined,
1298 : "GetNoDataValueAsUInt64() should be called instead");
1299 0 : if (pbSuccess)
1300 0 : *pbSuccess = FALSE;
1301 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1302 : }
1303 35 : if (eDataType != GDT_Int64)
1304 : {
1305 0 : CPLError(CE_Failure, CPLE_AppDefined,
1306 : "GetNoDataValue() should be called instead");
1307 0 : if (pbSuccess)
1308 0 : *pbSuccess = FALSE;
1309 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1310 : }
1311 :
1312 35 : int bSuccess = FALSE;
1313 : const auto nNoDataValue =
1314 35 : GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1315 35 : if (bSuccess)
1316 : {
1317 0 : if (pbSuccess)
1318 0 : *pbSuccess = TRUE;
1319 :
1320 0 : return nNoDataValue;
1321 : }
1322 :
1323 35 : if (m_bNoDataSetAsInt64)
1324 : {
1325 2 : if (pbSuccess)
1326 2 : *pbSuccess = TRUE;
1327 :
1328 2 : return m_nNoDataValueInt64;
1329 : }
1330 :
1331 33 : if (m_poGDS->m_bNoDataSetAsInt64)
1332 : {
1333 7 : if (pbSuccess)
1334 6 : *pbSuccess = TRUE;
1335 :
1336 7 : return m_poGDS->m_nNoDataValueInt64;
1337 : }
1338 :
1339 26 : if (pbSuccess)
1340 26 : *pbSuccess = FALSE;
1341 26 : return nNoDataValue;
1342 : }
1343 :
1344 : /************************************************************************/
1345 : /* GetNoDataValueAsUInt64() */
1346 : /************************************************************************/
1347 :
1348 21 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1349 :
1350 : {
1351 21 : m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1352 :
1353 21 : if (eDataType == GDT_Int64)
1354 : {
1355 0 : CPLError(CE_Failure, CPLE_AppDefined,
1356 : "GetNoDataValueAsInt64() should be called instead");
1357 0 : if (pbSuccess)
1358 0 : *pbSuccess = FALSE;
1359 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1360 : }
1361 21 : if (eDataType != GDT_UInt64)
1362 : {
1363 0 : CPLError(CE_Failure, CPLE_AppDefined,
1364 : "GetNoDataValue() should be called instead");
1365 0 : if (pbSuccess)
1366 0 : *pbSuccess = FALSE;
1367 0 : return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1368 : }
1369 :
1370 21 : int bSuccess = FALSE;
1371 : const auto nNoDataValue =
1372 21 : GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1373 21 : if (bSuccess)
1374 : {
1375 0 : if (pbSuccess)
1376 0 : *pbSuccess = TRUE;
1377 :
1378 0 : return nNoDataValue;
1379 : }
1380 :
1381 21 : if (m_bNoDataSetAsUInt64)
1382 : {
1383 0 : if (pbSuccess)
1384 0 : *pbSuccess = TRUE;
1385 :
1386 0 : return m_nNoDataValueUInt64;
1387 : }
1388 :
1389 21 : if (m_poGDS->m_bNoDataSetAsUInt64)
1390 : {
1391 7 : if (pbSuccess)
1392 6 : *pbSuccess = TRUE;
1393 :
1394 7 : return m_poGDS->m_nNoDataValueUInt64;
1395 : }
1396 :
1397 14 : if (pbSuccess)
1398 14 : *pbSuccess = FALSE;
1399 14 : return nNoDataValue;
1400 : }
1401 :
1402 : /************************************************************************/
1403 : /* GetOverviewCount() */
1404 : /************************************************************************/
1405 :
1406 1319800 : int GTiffRasterBand::GetOverviewCount()
1407 :
1408 : {
1409 1319800 : if (!m_poGDS->AreOverviewsEnabled())
1410 30 : return 0;
1411 :
1412 1319770 : m_poGDS->ScanDirectories();
1413 :
1414 1319770 : if (m_poGDS->m_nOverviewCount > 0)
1415 : {
1416 267308 : return m_poGDS->m_nOverviewCount;
1417 : }
1418 :
1419 1052470 : const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1420 1052470 : if (nOverviewCount > 0)
1421 391 : return nOverviewCount;
1422 :
1423 : // Implicit JPEG overviews are normally hidden, except when doing
1424 : // IRasterIO() operations.
1425 1052080 : if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1426 1044190 : return m_poGDS->GetJPEGOverviewCount();
1427 :
1428 7888 : return 0;
1429 : }
1430 :
1431 : /************************************************************************/
1432 : /* GetOverview() */
1433 : /************************************************************************/
1434 :
1435 74176 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1436 :
1437 : {
1438 74176 : m_poGDS->ScanDirectories();
1439 :
1440 74176 : if (m_poGDS->m_nOverviewCount > 0)
1441 : {
1442 : // Do we have internal overviews?
1443 73580 : if (i < 0 || i >= m_poGDS->m_nOverviewCount)
1444 8 : return nullptr;
1445 :
1446 73572 : return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
1447 : }
1448 :
1449 596 : GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1450 596 : if (poOvrBand != nullptr)
1451 391 : return poOvrBand;
1452 :
1453 : // For consistency with GetOverviewCount(), we should also test
1454 : // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1455 : // to query them for testing purposes.
1456 205 : if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1457 164 : return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
1458 :
1459 41 : return nullptr;
1460 : }
1461 :
1462 : /************************************************************************/
1463 : /* GetMaskFlags() */
1464 : /************************************************************************/
1465 :
1466 21714 : int GTiffRasterBand::GetMaskFlags()
1467 : {
1468 21714 : m_poGDS->ScanDirectories();
1469 :
1470 21714 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1471 : {
1472 0 : return GMF_PER_DATASET;
1473 : }
1474 :
1475 21714 : if (m_poGDS->m_poMaskDS != nullptr)
1476 : {
1477 215 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1478 : {
1479 207 : return GMF_PER_DATASET;
1480 : }
1481 :
1482 8 : return 0;
1483 : }
1484 :
1485 21499 : if (m_poGDS->m_bIsOverview)
1486 : {
1487 441 : return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1488 : }
1489 :
1490 21058 : return GDALPamRasterBand::GetMaskFlags();
1491 : }
1492 :
1493 : /************************************************************************/
1494 : /* GetMaskBand() */
1495 : /************************************************************************/
1496 :
1497 113800 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1498 : {
1499 113800 : m_poGDS->ScanDirectories();
1500 :
1501 115982 : if (m_poGDS->m_poExternalMaskDS != nullptr)
1502 : {
1503 1178 : return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1504 : }
1505 :
1506 114804 : if (m_poGDS->m_poMaskDS != nullptr)
1507 : {
1508 691 : if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1509 674 : return m_poGDS->m_poMaskDS->GetRasterBand(1);
1510 :
1511 17 : return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1512 : }
1513 :
1514 114113 : if (m_poGDS->m_bIsOverview)
1515 : {
1516 : GDALRasterBand *poBaseMask =
1517 119 : m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1518 119 : if (poBaseMask)
1519 : {
1520 119 : const int nOverviews = poBaseMask->GetOverviewCount();
1521 164 : for (int i = 0; i < nOverviews; i++)
1522 : {
1523 93 : GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1524 141 : if (poOvr && poOvr->GetXSize() == GetXSize() &&
1525 48 : poOvr->GetYSize() == GetYSize())
1526 : {
1527 48 : return poOvr;
1528 : }
1529 : }
1530 : }
1531 : }
1532 :
1533 114065 : return GDALPamRasterBand::GetMaskBand();
1534 : }
1535 :
1536 : /************************************************************************/
1537 : /* IsMaskBand() */
1538 : /************************************************************************/
1539 :
1540 1035 : bool GTiffRasterBand::IsMaskBand() const
1541 : {
1542 1067 : return (m_poGDS->m_poImageryDS != nullptr &&
1543 32 : m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
1544 2015 : m_eBandInterp == GCI_AlphaBand ||
1545 1983 : m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1546 : }
1547 :
1548 : /************************************************************************/
1549 : /* GetMaskValueRange() */
1550 : /************************************************************************/
1551 :
1552 0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1553 : {
1554 0 : if (!IsMaskBand())
1555 0 : return GMVR_UNKNOWN;
1556 0 : if (m_poGDS->m_nBitsPerSample == 1)
1557 0 : return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1558 0 : : GMVR_0_AND_1_ONLY;
1559 0 : return GMVR_UNKNOWN;
1560 : }
|