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