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