Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoTIFF Driver
4 : * Purpose: Read/get operations on GTiffDataset
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 "gtiffdataset.h"
15 : #include "gtiffrasterband.h"
16 : #include "gtiffjpegoverviewds.h"
17 : #include "gtiffrgbaband.h"
18 : #include "gtiffbitmapband.h"
19 : #include "gtiffsplitband.h"
20 : #include "gtiffsplitbitmapband.h"
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 : #include <limits>
25 : #include <memory>
26 : #include <mutex>
27 : #include <set>
28 : #include <string>
29 : #include <queue>
30 : #include <tuple>
31 : #include <utility>
32 :
33 : #include "cpl_error.h"
34 : #include "cpl_error_internal.h" // CPLErrorHandlerAccumulatorStruct
35 : #include "cpl_vsi.h"
36 : #include "cpl_vsi_virtual.h"
37 : #include "cpl_worker_thread_pool.h"
38 : #include "fetchbufferdirectio.h"
39 : #include "gdal_mdreader.h" // MD_DOMAIN_RPC
40 : #include "gdal_priv.h"
41 : #include "geovalues.h" // RasterPixelIsPoint
42 : #include "gt_wkt_srs_priv.h" // GDALGTIFKeyGetSHORT()
43 : #include "tif_jxl.h"
44 : #include "tifvsi.h"
45 : #include "xtiffio.h"
46 :
47 : #include "tiff_common.h"
48 :
49 : /************************************************************************/
50 : /* GetJPEGOverviewCount() */
51 : /************************************************************************/
52 :
53 1044380 : int GTiffDataset::GetJPEGOverviewCount()
54 : {
55 1044380 : if (!m_apoJPEGOverviewDS.empty())
56 170 : return static_cast<int>(m_apoJPEGOverviewDS.size());
57 :
58 643494 : if (m_poBaseDS || eAccess != GA_ReadOnly ||
59 28830 : m_nCompression != COMPRESSION_JPEG ||
60 22 : (nRasterXSize < 256 && nRasterYSize < 256) ||
61 1687730 : !CPLTestBool(CPLGetConfigOption("GTIFF_IMPLICIT_JPEG_OVR", "YES")) ||
62 22 : GDALGetDriverByName("JPEG") == nullptr)
63 : {
64 1044190 : return 0;
65 : }
66 : const char *pszSourceColorSpace =
67 22 : m_oGTiffMDMD.GetMetadataItem("SOURCE_COLOR_SPACE", "IMAGE_STRUCTURE");
68 22 : if (pszSourceColorSpace != nullptr && EQUAL(pszSourceColorSpace, "CMYK"))
69 : {
70 : // We cannot handle implicit overviews on JPEG CMYK datasets converted
71 : // to RGBA This would imply doing the conversion in
72 : // GTiffJPEGOverviewBand.
73 1 : return 0;
74 : }
75 :
76 : // libjpeg-6b only supports 2, 4 and 8 scale denominators.
77 : // TODO: Later versions support more.
78 21 : int nJPEGOverviewCount = 0;
79 24 : for (signed char i = 2; i >= 0; i--)
80 : {
81 24 : if (nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i))
82 : {
83 21 : nJPEGOverviewCount = i + 1;
84 21 : break;
85 : }
86 : }
87 21 : if (nJPEGOverviewCount == 0)
88 0 : return 0;
89 :
90 : // Get JPEG tables.
91 21 : uint32_t nJPEGTableSize = 0;
92 21 : void *pJPEGTable = nullptr;
93 21 : GByte abyFFD8[] = {0xFF, 0xD8};
94 21 : if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable))
95 : {
96 20 : if (pJPEGTable == nullptr || nJPEGTableSize < 2 ||
97 20 : nJPEGTableSize > INT_MAX ||
98 20 : static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] != 0xD9)
99 : {
100 0 : return 0;
101 : }
102 20 : nJPEGTableSize--; // Remove final 0xD9.
103 : }
104 : else
105 : {
106 1 : pJPEGTable = abyFFD8;
107 1 : nJPEGTableSize = 2;
108 : }
109 :
110 81 : for (int i = 0; i < nJPEGOverviewCount; ++i)
111 : {
112 60 : m_apoJPEGOverviewDS.emplace_back(std::make_unique<GTiffJPEGOverviewDS>(
113 120 : this, i + 1, pJPEGTable, static_cast<int>(nJPEGTableSize)));
114 : }
115 :
116 21 : return nJPEGOverviewCount;
117 : }
118 :
119 : /************************************************************************/
120 : /* GetCompressionFormats() */
121 : /************************************************************************/
122 :
123 6 : CPLStringList GTiffDataset::GetCompressionFormats(int nXOff, int nYOff,
124 : int nXSize, int nYSize,
125 : int nBandCount,
126 : const int *panBandList)
127 : {
128 18 : if (m_nCompression != COMPRESSION_NONE &&
129 11 : IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
130 3 : ((nBandCount == 1 && (panBandList || nBands == 1) &&
131 3 : m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
132 5 : (IsAllBands(nBandCount, panBandList) &&
133 3 : m_nPlanarConfig == PLANARCONFIG_CONTIG)))
134 : {
135 6 : CPLStringList aosList;
136 3 : int nBlockId =
137 3 : (nXOff / m_nBlockXSize) + (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
138 3 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE && panBandList != nullptr)
139 0 : nBlockId += panBandList[0] * m_nBlocksPerBand;
140 :
141 3 : vsi_l_offset nOffset = 0;
142 3 : vsi_l_offset nSize = 0;
143 6 : if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
144 3 : nSize <
145 3 : static_cast<vsi_l_offset>(std::numeric_limits<tmsize_t>::max()))
146 : {
147 3 : switch (m_nCompression)
148 : {
149 3 : case COMPRESSION_JPEG:
150 : {
151 3 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands == 4 &&
152 7 : m_nPhotometric == PHOTOMETRIC_RGB &&
153 1 : GetRasterBand(4)->GetColorInterpretation() ==
154 : GCI_AlphaBand)
155 : {
156 : // as a hint for the JPEG and JPEGXL drivers to not use it!
157 1 : aosList.AddString("JPEG;colorspace=RGBA");
158 : }
159 : else
160 : {
161 2 : aosList.AddString("JPEG");
162 : }
163 3 : break;
164 : }
165 :
166 0 : case COMPRESSION_WEBP:
167 0 : aosList.AddString("WEBP");
168 0 : break;
169 :
170 0 : case COMPRESSION_JXL:
171 0 : aosList.AddString("JXL");
172 0 : break;
173 :
174 0 : default:
175 0 : break;
176 : }
177 : }
178 3 : return aosList;
179 : }
180 3 : return CPLStringList();
181 : }
182 :
183 : /************************************************************************/
184 : /* ReadCompressedData() */
185 : /************************************************************************/
186 :
187 80 : CPLErr GTiffDataset::ReadCompressedData(const char *pszFormat, int nXOff,
188 : int nYOff, int nXSize, int nYSize,
189 : int nBandCount, const int *panBandList,
190 : void **ppBuffer, size_t *pnBufferSize,
191 : char **ppszDetailedFormat)
192 : {
193 185 : if (m_nCompression != COMPRESSION_NONE &&
194 104 : IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
195 8 : ((nBandCount == 1 && (panBandList != nullptr || nBands == 1) &&
196 8 : m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
197 24 : (IsAllBands(nBandCount, panBandList) &&
198 24 : m_nPlanarConfig == PLANARCONFIG_CONTIG)))
199 : {
200 12 : const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
201 12 : if (aosTokens.size() != 1)
202 0 : return CE_Failure;
203 :
204 : // We don't want to handle CMYK JPEG for now
205 35 : if ((m_nCompression == COMPRESSION_JPEG &&
206 11 : EQUAL(aosTokens[0], "JPEG") &&
207 10 : (m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
208 10 : m_nPhotometric != PHOTOMETRIC_SEPARATED)) ||
209 2 : (m_nCompression == COMPRESSION_WEBP &&
210 24 : EQUAL(aosTokens[0], "WEBP")) ||
211 2 : ((m_nCompression == COMPRESSION_JXL ||
212 2 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
213 1 : EQUAL(aosTokens[0], "JXL")))
214 : {
215 11 : std::string osDetailedFormat = aosTokens[0];
216 :
217 11 : int nBlockId = (nXOff / m_nBlockXSize) +
218 11 : (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
219 11 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
220 : panBandList != nullptr)
221 0 : nBlockId += panBandList[0] * m_nBlocksPerBand;
222 :
223 11 : vsi_l_offset nOffset = 0;
224 11 : vsi_l_offset nSize = 0;
225 22 : if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
226 11 : nSize < static_cast<vsi_l_offset>(
227 11 : std::numeric_limits<tmsize_t>::max()))
228 : {
229 11 : uint32_t nJPEGTableSize = 0;
230 11 : void *pJPEGTable = nullptr;
231 11 : if (m_nCompression == COMPRESSION_JPEG)
232 : {
233 10 : if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES,
234 10 : &nJPEGTableSize, &pJPEGTable) &&
235 10 : pJPEGTable != nullptr && nJPEGTableSize > 4 &&
236 10 : static_cast<GByte *>(pJPEGTable)[0] == 0xFF &&
237 10 : static_cast<GByte *>(pJPEGTable)[1] == 0xD8 &&
238 10 : static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 2] ==
239 20 : 0xFF &&
240 10 : static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] ==
241 : 0xD9)
242 : {
243 10 : pJPEGTable = static_cast<GByte *>(pJPEGTable) + 2;
244 10 : nJPEGTableSize -= 4;
245 : }
246 : else
247 : {
248 0 : nJPEGTableSize = 0;
249 : }
250 : }
251 :
252 11 : size_t nSizeSize = static_cast<size_t>(nSize + nJPEGTableSize);
253 11 : if (ppBuffer)
254 : {
255 9 : if (!pnBufferSize)
256 1 : return CE_Failure;
257 8 : bool bFreeOnError = false;
258 8 : if (*ppBuffer)
259 : {
260 3 : if (*pnBufferSize < nSizeSize)
261 1 : return CE_Failure;
262 : }
263 : else
264 : {
265 5 : *ppBuffer = VSI_MALLOC_VERBOSE(nSizeSize);
266 5 : if (*ppBuffer == nullptr)
267 0 : return CE_Failure;
268 5 : bFreeOnError = true;
269 : }
270 7 : const auto nTileSize = static_cast<tmsize_t>(nSize);
271 : bool bOK;
272 7 : if (TIFFIsTiled(m_hTIFF))
273 : {
274 3 : bOK = TIFFReadRawTile(m_hTIFF, nBlockId, *ppBuffer,
275 : nTileSize) == nTileSize;
276 : }
277 : else
278 : {
279 4 : bOK = TIFFReadRawStrip(m_hTIFF, nBlockId, *ppBuffer,
280 : nTileSize) == nTileSize;
281 : }
282 7 : if (!bOK)
283 : {
284 0 : if (bFreeOnError)
285 : {
286 0 : VSIFree(*ppBuffer);
287 0 : *ppBuffer = nullptr;
288 : }
289 0 : return CE_Failure;
290 : }
291 7 : if (nJPEGTableSize > 0)
292 : {
293 6 : GByte *pabyBuffer = static_cast<GByte *>(*ppBuffer);
294 6 : memmove(pabyBuffer + 2 + nJPEGTableSize, pabyBuffer + 2,
295 6 : static_cast<size_t>(nSize) - 2);
296 6 : memcpy(pabyBuffer + 2, pJPEGTable, nJPEGTableSize);
297 : }
298 :
299 7 : if (m_nCompression == COMPRESSION_JPEG)
300 : {
301 12 : osDetailedFormat = GDALGetCompressionFormatForJPEG(
302 6 : *ppBuffer, nSizeSize);
303 : const CPLStringList aosTokens2(CSLTokenizeString2(
304 12 : osDetailedFormat.c_str(), ";", 0));
305 18 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
306 7 : nBands == 4 && m_nPhotometric == PHOTOMETRIC_RGB &&
307 1 : GetRasterBand(4)->GetColorInterpretation() ==
308 : GCI_AlphaBand)
309 : {
310 1 : osDetailedFormat = aosTokens2[0];
311 5 : for (int i = 1; i < aosTokens2.size(); ++i)
312 : {
313 4 : if (!STARTS_WITH_CI(aosTokens2[i],
314 : "colorspace="))
315 : {
316 3 : osDetailedFormat += ';';
317 3 : osDetailedFormat += aosTokens2[i];
318 : }
319 : }
320 1 : osDetailedFormat += ";colorspace=RGBA";
321 : }
322 : }
323 : }
324 9 : if (ppszDetailedFormat)
325 3 : *ppszDetailedFormat = VSIStrdup(osDetailedFormat.c_str());
326 9 : if (pnBufferSize)
327 8 : *pnBufferSize = nSizeSize;
328 9 : return CE_None;
329 : }
330 : }
331 : }
332 69 : return CE_Failure;
333 : }
334 :
335 : struct GTiffDecompressContext
336 : {
337 : // The mutex must be recursive because ThreadDecompressionFuncErrorHandler()
338 : // which acquires the mutex can be called from a section where the mutex is
339 : // already acquired.
340 : std::recursive_mutex oMutex{};
341 : bool bSuccess = true;
342 : CPLErrorAccumulator oErrorAccumulator{};
343 :
344 : VSIVirtualHandle *poHandle = nullptr;
345 : GTiffDataset *poDS = nullptr;
346 : GDALDataType eDT = GDT_Unknown;
347 : int nXOff = 0;
348 : int nYOff = 0;
349 : int nXSize = 0;
350 : int nYSize = 0;
351 : int nBlockXStart = 0;
352 : int nBlockYStart = 0;
353 : int nBlockXEnd = 0;
354 : int nBlockYEnd = 0;
355 : GByte *pabyData = nullptr;
356 : GDALDataType eBufType = GDT_Unknown;
357 : int nBufDTSize = 0;
358 : int nBandCount = 0;
359 : const int *panBandMap = nullptr;
360 : GSpacing nPixelSpace = 0;
361 : GSpacing nLineSpace = 0;
362 : GSpacing nBandSpace = 0;
363 : bool bHasPRead = false;
364 : bool bCacheAllBands = false;
365 : bool bSkipBlockCache = false;
366 : bool bUseBIPOptim = false;
367 : bool bUseDeinterleaveOptimNoBlockCache = false;
368 : bool bUseDeinterleaveOptimBlockCache = false;
369 : bool bIsTiled = false;
370 : bool bTIFFIsBigEndian = false;
371 : int nBlocksPerRow = 0;
372 :
373 : uint16_t nPredictor = 0;
374 :
375 : uint32_t nJPEGTableSize = 0;
376 : void *pJPEGTable = nullptr;
377 : uint16_t nYCrbCrSubSampling0 = 2;
378 : uint16_t nYCrbCrSubSampling1 = 2;
379 :
380 : uint16_t *pExtraSamples = nullptr;
381 : uint16_t nExtraSampleCount = 0;
382 : };
383 :
384 : struct GTiffDecompressJob
385 : {
386 : GTiffDecompressContext *psContext = nullptr;
387 : int iSrcBandIdxSeparate =
388 : 0; // in [0, GetRasterCount()-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
389 : int iDstBandIdxSeparate =
390 : 0; // in [0, nBandCount-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
391 : int nXBlock = 0;
392 : int nYBlock = 0;
393 : vsi_l_offset nOffset = 0;
394 : vsi_l_offset nSize = 0;
395 : };
396 :
397 : /************************************************************************/
398 : /* ThreadDecompressionFunc() */
399 : /************************************************************************/
400 :
401 3836 : /* static */ void GTiffDataset::ThreadDecompressionFunc(void *pData)
402 : {
403 3836 : const auto psJob = static_cast<const GTiffDecompressJob *>(pData);
404 3836 : auto psContext = psJob->psContext;
405 3836 : auto poDS = psContext->poDS;
406 :
407 3836 : auto oAccumulator = psContext->oErrorAccumulator.InstallForCurrentScope();
408 :
409 3836 : const int nBandsPerStrile =
410 3836 : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? poDS->nBands : 1;
411 7672 : const int nBandsToWrite = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
412 3836 : ? psContext->nBandCount
413 : : 1;
414 :
415 7672 : const int nXOffsetInBlock = psJob->nXBlock == psContext->nBlockXStart
416 3836 : ? psContext->nXOff % poDS->m_nBlockXSize
417 : : 0;
418 3836 : const int nXOffsetInData =
419 3836 : psJob->nXBlock == psContext->nBlockXStart
420 3836 : ? 0
421 2457 : : (psJob->nXBlock - psContext->nBlockXStart) * poDS->m_nBlockXSize -
422 2457 : (psContext->nXOff % poDS->m_nBlockXSize);
423 3836 : const int nXSize =
424 3836 : psJob->nXBlock == psContext->nBlockXStart
425 7672 : ? (psJob->nXBlock == psContext->nBlockXEnd
426 1379 : ? psContext->nXSize
427 477 : : poDS->m_nBlockXSize -
428 477 : (psContext->nXOff % poDS->m_nBlockXSize))
429 2457 : : psJob->nXBlock == psContext->nBlockXEnd
430 2934 : ? (((psContext->nXOff + psContext->nXSize) % poDS->m_nBlockXSize) ==
431 : 0
432 477 : ? poDS->m_nBlockXSize
433 406 : : ((psContext->nXOff + psContext->nXSize) %
434 406 : poDS->m_nBlockXSize))
435 1980 : : poDS->m_nBlockXSize;
436 :
437 7672 : const int nYOffsetInBlock = psJob->nYBlock == psContext->nBlockYStart
438 3836 : ? psContext->nYOff % poDS->m_nBlockYSize
439 : : 0;
440 3836 : const int nYOffsetInData =
441 3836 : psJob->nYBlock == psContext->nBlockYStart
442 3836 : ? 0
443 2895 : : (psJob->nYBlock - psContext->nBlockYStart) * poDS->m_nBlockYSize -
444 2895 : (psContext->nYOff % poDS->m_nBlockYSize);
445 3836 : const int nYSize =
446 3836 : psJob->nYBlock == psContext->nBlockYStart
447 7672 : ? (psJob->nYBlock == psContext->nBlockYEnd
448 941 : ? psContext->nYSize
449 917 : : poDS->m_nBlockYSize -
450 917 : (psContext->nYOff % poDS->m_nBlockYSize))
451 2895 : : psJob->nYBlock == psContext->nBlockYEnd
452 3812 : ? (((psContext->nYOff + psContext->nYSize) % poDS->m_nBlockYSize) ==
453 : 0
454 917 : ? poDS->m_nBlockYSize
455 801 : : ((psContext->nYOff + psContext->nYSize) %
456 801 : poDS->m_nBlockYSize))
457 1978 : : poDS->m_nBlockYSize;
458 : #if 0
459 : CPLDebug("GTiff",
460 : "nXBlock = %d, nYBlock = %d, "
461 : "nXOffsetInBlock = %d, nXOffsetInData = %d, nXSize = %d, "
462 : "nYOffsetInBlock = %d, nYOffsetInData = %d, nYSize = %d\n",
463 : psJob->nXBlock, psJob->nYBlock,
464 : nXOffsetInBlock, nXOffsetInData, nXSize,
465 : nYOffsetInBlock, nYOffsetInData, nYSize);
466 : #endif
467 :
468 3836 : if (psJob->nSize == 0)
469 : {
470 : {
471 2 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
472 2 : if (!psContext->bSuccess)
473 0 : return;
474 : }
475 2 : const double dfNoDataValue =
476 2 : poDS->m_bNoDataSet ? poDS->m_dfNoDataValue : 0;
477 102 : for (int y = 0; y < nYSize; ++y)
478 : {
479 200 : for (int i = 0; i < nBandsToWrite; ++i)
480 : {
481 100 : const int iDstBandIdx =
482 100 : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
483 100 : ? i
484 0 : : psJob->iDstBandIdxSeparate;
485 100 : GDALCopyWords64(
486 : &dfNoDataValue, GDT_Float64, 0,
487 100 : psContext->pabyData + iDstBandIdx * psContext->nBandSpace +
488 100 : (y + nYOffsetInData) * psContext->nLineSpace +
489 100 : nXOffsetInData * psContext->nPixelSpace,
490 : psContext->eBufType,
491 100 : static_cast<int>(psContext->nPixelSpace), nXSize);
492 : }
493 : }
494 2 : return;
495 : }
496 :
497 3834 : const int nBandsToCache =
498 3834 : psContext->bCacheAllBands ? poDS->nBands : nBandsToWrite;
499 3834 : std::vector<GDALRasterBlock *> apoBlocks(nBandsToCache);
500 3834 : std::vector<bool> abAlreadyLoadedBlocks(nBandsToCache);
501 3834 : int nAlreadyLoadedBlocks = 0;
502 3834 : std::vector<GByte> abyInput;
503 :
504 : struct FreeBlocks
505 : {
506 : std::vector<GDALRasterBlock *> &m_apoBlocks;
507 :
508 3834 : explicit FreeBlocks(std::vector<GDALRasterBlock *> &apoBlocksIn)
509 3834 : : m_apoBlocks(apoBlocksIn)
510 : {
511 3834 : }
512 :
513 3834 : ~FreeBlocks()
514 3834 : {
515 10510 : for (auto *poBlock : m_apoBlocks)
516 : {
517 6676 : if (poBlock)
518 3992 : poBlock->DropLock();
519 : }
520 3834 : }
521 : };
522 :
523 3834 : FreeBlocks oFreeBlocks(apoBlocks);
524 :
525 1780 : const auto LoadBlocks = [&]()
526 : {
527 5772 : for (int i = 0; i < nBandsToCache; ++i)
528 : {
529 6300 : const int iBand = psContext->bCacheAllBands ? i + 1
530 7340 : : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
531 2308 : ? psContext->panBandMap[i]
532 660 : : psJob->iSrcBandIdxSeparate + 1;
533 7984 : apoBlocks[i] = poDS->GetRasterBand(iBand)->TryGetLockedBlockRef(
534 3992 : psJob->nXBlock, psJob->nYBlock);
535 3992 : if (apoBlocks[i] == nullptr)
536 : {
537 : // Temporary disabling of dirty block flushing, otherwise
538 : // we can be in a deadlock situation, where the
539 : // GTiffDataset::SubmitCompressionJob() method waits for jobs
540 : // to be finished, that can't finish (actually be started)
541 : // because this task and its siblings are taking all the
542 : // available workers allowed by the global thread pool.
543 1040 : GDALRasterBlock::EnterDisableDirtyBlockFlush();
544 2080 : apoBlocks[i] = poDS->GetRasterBand(iBand)->GetLockedBlockRef(
545 1040 : psJob->nXBlock, psJob->nYBlock, TRUE);
546 1040 : GDALRasterBlock::LeaveDisableDirtyBlockFlush();
547 1040 : if (apoBlocks[i] == nullptr)
548 0 : return false;
549 : }
550 : else
551 : {
552 2952 : abAlreadyLoadedBlocks[i] = true;
553 2952 : nAlreadyLoadedBlocks++;
554 : }
555 : }
556 1780 : return true;
557 3834 : };
558 :
559 2608 : const auto AllocInputBuffer = [&]()
560 : {
561 2608 : bool bError = false;
562 : #if SIZEOF_VOIDP == 4
563 : if (psJob->nSize != static_cast<size_t>(psJob->nSize))
564 : {
565 : bError = true;
566 : }
567 : else
568 : #endif
569 : {
570 : try
571 : {
572 2608 : abyInput.resize(static_cast<size_t>(psJob->nSize));
573 : }
574 0 : catch (const std::exception &)
575 : {
576 0 : bError = true;
577 : }
578 : }
579 2608 : if (bError)
580 : {
581 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
582 : "Cannot allocate working buffer of size " CPL_FRMT_GUIB,
583 0 : static_cast<GUIntBig>(psJob->nSize));
584 0 : return false;
585 : }
586 2608 : return true;
587 3834 : };
588 :
589 3834 : if (psContext->bHasPRead)
590 : {
591 : {
592 3834 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
593 3834 : if (!psContext->bSuccess)
594 6 : return;
595 :
596 : // Coverity Scan notices that GDALRasterBlock::Internalize() calls
597 : // CPLSleep() in a debug code path, and warns about that while
598 : // holding the above mutex.
599 : // coverity[sleep]
600 3828 : if (!psContext->bSkipBlockCache && !LoadBlocks())
601 : {
602 0 : psContext->bSuccess = false;
603 0 : return;
604 : }
605 : }
606 3828 : if (nAlreadyLoadedBlocks != nBandsToCache)
607 : {
608 2608 : if (!AllocInputBuffer())
609 : {
610 0 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
611 0 : psContext->bSuccess = false;
612 0 : return;
613 : }
614 2608 : if (psContext->poHandle->PRead(abyInput.data(), abyInput.size(),
615 5216 : psJob->nOffset) != abyInput.size())
616 : {
617 2 : CPLError(CE_Failure, CPLE_AppDefined,
618 : "Cannot read " CPL_FRMT_GUIB
619 : " bytes at offset " CPL_FRMT_GUIB,
620 2 : static_cast<GUIntBig>(psJob->nSize),
621 2 : static_cast<GUIntBig>(psJob->nOffset));
622 :
623 2 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
624 2 : psContext->bSuccess = false;
625 2 : return;
626 : }
627 : }
628 : }
629 : else
630 : {
631 0 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
632 0 : if (!psContext->bSuccess)
633 0 : return;
634 :
635 : // Coverity Scan notices that GDALRasterBlock::Internalize() calls
636 : // CPLSleep() in a debug code path, and warns about that while
637 : // holding the above mutex.
638 : // coverity[sleep]
639 0 : if (!psContext->bSkipBlockCache && !LoadBlocks())
640 : {
641 0 : psContext->bSuccess = false;
642 0 : return;
643 : }
644 :
645 0 : if (nAlreadyLoadedBlocks != nBandsToCache)
646 : {
647 0 : if (!AllocInputBuffer())
648 : {
649 0 : psContext->bSuccess = false;
650 0 : return;
651 : }
652 0 : if (psContext->poHandle->Seek(psJob->nOffset, SEEK_SET) != 0 ||
653 0 : psContext->poHandle->Read(abyInput.data(), abyInput.size(),
654 : 1) != 1)
655 : {
656 0 : CPLError(CE_Failure, CPLE_AppDefined,
657 : "Cannot read " CPL_FRMT_GUIB
658 : " bytes at offset " CPL_FRMT_GUIB,
659 0 : static_cast<GUIntBig>(psJob->nSize),
660 0 : static_cast<GUIntBig>(psJob->nOffset));
661 0 : psContext->bSuccess = false;
662 0 : return;
663 : }
664 : }
665 : }
666 :
667 3826 : const int nDTSize = GDALGetDataTypeSizeBytes(psContext->eDT);
668 3826 : GByte *pDstPtr = psContext->pabyData +
669 3826 : nYOffsetInData * psContext->nLineSpace +
670 3826 : nXOffsetInData * psContext->nPixelSpace;
671 :
672 3826 : if (nAlreadyLoadedBlocks != nBandsToCache)
673 : {
674 : // Generate a dummy in-memory TIFF file that has all the needed tags
675 : // from the original file
676 : const CPLString osTmpFilename(
677 2606 : VSIMemGenerateHiddenFilename("decompress.tif"));
678 2606 : VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb+");
679 : TIFF *hTIFFTmp =
680 2606 : VSI_TIFFOpen(osTmpFilename.c_str(),
681 2606 : psContext->bTIFFIsBigEndian ? "wb+" : "wl+", fpTmp);
682 2606 : CPLAssert(hTIFFTmp != nullptr);
683 2606 : const int nBlockYSize =
684 3072 : (psContext->bIsTiled ||
685 466 : psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
686 3072 : ? poDS->m_nBlockYSize
687 53 : : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
688 53 : ? poDS->m_nBlockYSize
689 42 : : poDS->nRasterYSize % poDS->m_nBlockYSize;
690 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_IMAGEWIDTH, poDS->m_nBlockXSize);
691 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_IMAGELENGTH, nBlockYSize);
692 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_BITSPERSAMPLE, poDS->m_nBitsPerSample);
693 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_COMPRESSION, poDS->m_nCompression);
694 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, poDS->m_nPhotometric);
695 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLEFORMAT, poDS->m_nSampleFormat);
696 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLESPERPIXEL,
697 2606 : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
698 786 : ? poDS->m_nSamplesPerPixel
699 : : 1);
700 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_ROWSPERSTRIP, nBlockYSize);
701 2606 : TIFFSetField(hTIFFTmp, TIFFTAG_PLANARCONFIG, poDS->m_nPlanarConfig);
702 2606 : if (psContext->nPredictor != PREDICTOR_NONE)
703 60 : TIFFSetField(hTIFFTmp, TIFFTAG_PREDICTOR, psContext->nPredictor);
704 2606 : if (poDS->m_nCompression == COMPRESSION_LERC)
705 : {
706 30 : TIFFSetField(hTIFFTmp, TIFFTAG_LERC_PARAMETERS, 2,
707 30 : poDS->m_anLercAddCompressionAndVersion);
708 : }
709 2576 : else if (poDS->m_nCompression == COMPRESSION_JPEG)
710 : {
711 14 : if (psContext->pJPEGTable)
712 : {
713 14 : TIFFSetField(hTIFFTmp, TIFFTAG_JPEGTABLES,
714 : psContext->nJPEGTableSize, psContext->pJPEGTable);
715 : }
716 14 : if (poDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
717 : {
718 7 : TIFFSetField(hTIFFTmp, TIFFTAG_YCBCRSUBSAMPLING,
719 7 : psContext->nYCrbCrSubSampling0,
720 7 : psContext->nYCrbCrSubSampling1);
721 : }
722 : }
723 2606 : if (poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
724 : {
725 786 : if (psContext->pExtraSamples)
726 : {
727 66 : TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
728 66 : psContext->nExtraSampleCount,
729 : psContext->pExtraSamples);
730 : }
731 : else
732 : {
733 720 : const int nSamplesAccountedFor =
734 968 : poDS->m_nPhotometric == PHOTOMETRIC_RGB ? 3
735 248 : : poDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ? 1
736 : : 0;
737 720 : if (nSamplesAccountedFor > 0 &&
738 713 : poDS->m_nSamplesPerPixel > nSamplesAccountedFor)
739 : {
740 : // If the input image is not compliant regarndig ExtraSamples,
741 : // generate a synthetic one to avoid gazillons of warnings
742 0 : const auto nExtraSampleCount = static_cast<uint16_t>(
743 0 : poDS->m_nSamplesPerPixel - nSamplesAccountedFor);
744 : std::vector<uint16_t> anExtraSamples(
745 0 : nExtraSampleCount, EXTRASAMPLE_UNSPECIFIED);
746 0 : TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
747 : nExtraSampleCount, anExtraSamples.data());
748 : }
749 : }
750 : }
751 2606 : TIFFWriteCheck(hTIFFTmp, FALSE, "ThreadDecompressionFunc");
752 2606 : TIFFWriteDirectory(hTIFFTmp);
753 2606 : XTIFFClose(hTIFFTmp);
754 :
755 : // Re-open file
756 2606 : hTIFFTmp = VSI_TIFFOpen(osTmpFilename.c_str(), "r", fpTmp);
757 2606 : CPLAssert(hTIFFTmp != nullptr);
758 2606 : poDS->RestoreVolatileParameters(hTIFFTmp);
759 :
760 2606 : bool bRet = true;
761 : // Request m_nBlockYSize line in the block, except on the bottom-most
762 : // tile/strip.
763 2606 : const int nBlockReqYSize =
764 2606 : (psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
765 3203 : ? poDS->m_nBlockYSize
766 597 : : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
767 597 : ? poDS->m_nBlockYSize
768 554 : : poDS->nRasterYSize % poDS->m_nBlockYSize;
769 :
770 2606 : const size_t nReqSize = static_cast<size_t>(poDS->m_nBlockXSize) *
771 2606 : nBlockReqYSize * nBandsPerStrile * nDTSize;
772 :
773 : GByte *pabyOutput;
774 2606 : std::vector<GByte> abyOutput;
775 5436 : if (poDS->m_nCompression == COMPRESSION_NONE &&
776 2830 : !TIFFIsByteSwapped(poDS->m_hTIFF) && abyInput.size() >= nReqSize &&
777 224 : (psContext->bSkipBlockCache || nBandsPerStrile > 1))
778 : {
779 224 : pabyOutput = abyInput.data();
780 : }
781 : else
782 : {
783 2382 : if (psContext->bSkipBlockCache || nBandsPerStrile > 1)
784 : {
785 2060 : abyOutput.resize(nReqSize);
786 2060 : pabyOutput = abyOutput.data();
787 : }
788 : else
789 : {
790 322 : pabyOutput = static_cast<GByte *>(apoBlocks[0]->GetDataRef());
791 : }
792 2382 : if (!TIFFReadFromUserBuffer(hTIFFTmp, 0, abyInput.data(),
793 2382 : abyInput.size(), pabyOutput,
794 2382 : nReqSize) &&
795 0 : !poDS->m_bIgnoreReadErrors)
796 : {
797 0 : bRet = false;
798 : }
799 : }
800 2606 : XTIFFClose(hTIFFTmp);
801 2606 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
802 2606 : VSIUnlink(osTmpFilename.c_str());
803 :
804 2606 : if (!bRet)
805 : {
806 0 : std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
807 0 : psContext->bSuccess = false;
808 0 : return;
809 : }
810 :
811 2606 : if (!psContext->bSkipBlockCache && nBandsPerStrile > 1)
812 : {
813 : // Copy pixel-interleaved all-band buffer to cached blocks
814 :
815 236 : if (psContext->bUseDeinterleaveOptimBlockCache)
816 : {
817 : // Optimization
818 232 : std::vector<void *> ppDestBuffers(poDS->nBands);
819 464 : for (int i = 0; i < poDS->nBands; ++i)
820 : {
821 348 : ppDestBuffers[i] = apoBlocks[i]->GetDataRef();
822 : }
823 116 : GDALDeinterleave(pabyOutput, psContext->eDT, poDS->nBands,
824 : ppDestBuffers.data(), psContext->eDT,
825 116 : static_cast<size_t>(nBlockReqYSize) *
826 116 : poDS->m_nBlockXSize);
827 : }
828 : else
829 : {
830 : // General case
831 488 : for (int i = 0; i < nBandsToCache; ++i)
832 : {
833 368 : if (!abAlreadyLoadedBlocks[i])
834 : {
835 736 : const int iBand = psContext->bCacheAllBands
836 368 : ? i
837 368 : : psContext->panBandMap[i] - 1;
838 368 : GDALCopyWords64(pabyOutput + iBand * nDTSize,
839 368 : psContext->eDT, nDTSize * poDS->nBands,
840 368 : apoBlocks[i]->GetDataRef(),
841 : psContext->eDT, nDTSize,
842 368 : static_cast<size_t>(nBlockReqYSize) *
843 368 : poDS->m_nBlockXSize);
844 : }
845 : }
846 : }
847 : }
848 :
849 2606 : const GByte *pSrcPtr =
850 : pabyOutput +
851 2606 : (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
852 2606 : nXOffsetInBlock) *
853 2606 : nDTSize * nBandsPerStrile;
854 2606 : const size_t nSrcLineInc = static_cast<size_t>(poDS->m_nBlockXSize) *
855 2606 : nDTSize * nBandsPerStrile;
856 :
857 : // Optimization when writing to BIP buffer.
858 2606 : if (psContext->bUseBIPOptim)
859 : {
860 13593 : for (int y = 0; y < nYSize; ++y)
861 : {
862 13262 : GDALCopyWords64(pSrcPtr, psContext->eDT, nDTSize, pDstPtr,
863 : psContext->eBufType, psContext->nBufDTSize,
864 13262 : static_cast<size_t>(nXSize) * poDS->nBands);
865 13262 : pSrcPtr += nSrcLineInc;
866 13262 : pDstPtr += psContext->nLineSpace;
867 : }
868 331 : return;
869 : }
870 :
871 2275 : if (psContext->bSkipBlockCache)
872 : {
873 : // Copy from pixel-interleaved all-band buffer (or temporary buffer
874 : // for single-band/separate case) into final buffer
875 1759 : if (psContext->bUseDeinterleaveOptimNoBlockCache)
876 : {
877 : // Optimization
878 215 : std::vector<void *> ppDestBuffers(psContext->nBandCount);
879 860 : for (int i = 0; i < psContext->nBandCount; ++i)
880 : {
881 645 : ppDestBuffers[i] =
882 645 : pDstPtr +
883 645 : (psContext->panBandMap[i] - 1) * psContext->nBandSpace;
884 : }
885 12275 : for (int y = 0; y < nYSize; ++y)
886 : {
887 12060 : GDALDeinterleave(
888 : pSrcPtr, psContext->eDT, psContext->nBandCount,
889 : ppDestBuffers.data(), psContext->eDT, nXSize);
890 12060 : pSrcPtr += nSrcLineInc;
891 48240 : for (int i = 0; i < psContext->nBandCount; ++i)
892 : {
893 36180 : ppDestBuffers[i] =
894 36180 : static_cast<GByte *>(ppDestBuffers[i]) +
895 36180 : psContext->nLineSpace;
896 : }
897 : }
898 215 : return;
899 : }
900 :
901 : // General case
902 40244 : for (int y = 0; y < nYSize; ++y)
903 : {
904 78200 : for (int i = 0; i < nBandsToWrite; ++i)
905 : {
906 39500 : const int iSrcBandIdx =
907 39500 : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
908 39500 : ? psContext->panBandMap[i] - 1
909 : : 0;
910 39500 : const int iDstBandIdx =
911 39500 : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
912 39500 : ? i
913 38500 : : psJob->iDstBandIdxSeparate;
914 39500 : GDALCopyWords64(
915 39500 : pSrcPtr + iSrcBandIdx * nDTSize + y * nSrcLineInc,
916 : psContext->eDT, nDTSize * nBandsPerStrile,
917 39500 : pDstPtr + iDstBandIdx * psContext->nBandSpace +
918 39500 : y * psContext->nLineSpace,
919 : psContext->eBufType,
920 39500 : static_cast<int>(psContext->nPixelSpace), nXSize);
921 : }
922 : }
923 1544 : return;
924 : }
925 : }
926 :
927 1736 : CPLAssert(!psContext->bSkipBlockCache);
928 :
929 : // Compose cached blocks into final buffer
930 4548 : for (int i = 0; i < nBandsToWrite; ++i)
931 : {
932 2812 : const int iSrcBandIdx =
933 5076 : psContext->bCacheAllBands ? psContext->panBandMap[i] - 1
934 2264 : : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? i
935 : : 0;
936 2812 : assert(iSrcBandIdx >= 0);
937 5624 : const int iDstBandIdx = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
938 2812 : ? i
939 660 : : psJob->iDstBandIdxSeparate;
940 : const GByte *pSrcPtr =
941 2812 : static_cast<GByte *>(apoBlocks[iSrcBandIdx]->GetDataRef()) +
942 2812 : (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
943 2812 : nXOffsetInBlock) *
944 2812 : nDTSize;
945 68244 : for (int y = 0; y < nYSize; ++y)
946 : {
947 65432 : GDALCopyWords64(pSrcPtr + static_cast<size_t>(y) *
948 65432 : poDS->m_nBlockXSize * nDTSize,
949 : psContext->eDT, nDTSize,
950 65432 : pDstPtr + iDstBandIdx * psContext->nBandSpace +
951 65432 : y * psContext->nLineSpace,
952 : psContext->eBufType,
953 65432 : static_cast<int>(psContext->nPixelSpace), nXSize);
954 : }
955 : }
956 : }
957 :
958 : /************************************************************************/
959 : /* IsMultiThreadedReadCompatible() */
960 : /************************************************************************/
961 :
962 283 : bool GTiffDataset::IsMultiThreadedReadCompatible() const
963 : {
964 283 : return cpl::down_cast<GTiffRasterBand *>(papoBands[0])
965 283 : ->IsBaseGTiffClass() &&
966 564 : !m_bStreamingIn && !m_bStreamingOut &&
967 281 : (m_nCompression == COMPRESSION_NONE ||
968 258 : m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
969 235 : m_nCompression == COMPRESSION_LZW ||
970 86 : m_nCompression == COMPRESSION_PACKBITS ||
971 72 : m_nCompression == COMPRESSION_LZMA ||
972 58 : m_nCompression == COMPRESSION_ZSTD ||
973 44 : m_nCompression == COMPRESSION_LERC ||
974 30 : m_nCompression == COMPRESSION_JXL ||
975 30 : m_nCompression == COMPRESSION_JXL_DNG_1_7 ||
976 16 : m_nCompression == COMPRESSION_WEBP ||
977 285 : m_nCompression == COMPRESSION_JPEG);
978 : }
979 :
980 : /************************************************************************/
981 : /* MultiThreadedRead() */
982 : /************************************************************************/
983 :
984 254 : CPLErr GTiffDataset::MultiThreadedRead(int nXOff, int nYOff, int nXSize,
985 : int nYSize, void *pData,
986 : GDALDataType eBufType, int nBandCount,
987 : const int *panBandMap,
988 : GSpacing nPixelSpace,
989 : GSpacing nLineSpace, GSpacing nBandSpace)
990 : {
991 508 : auto poQueue = m_poThreadPool->CreateJobQueue();
992 254 : if (poQueue == nullptr)
993 : {
994 0 : return CE_Failure;
995 : }
996 :
997 254 : const int nBlockXStart = nXOff / m_nBlockXSize;
998 254 : const int nBlockYStart = nYOff / m_nBlockYSize;
999 254 : const int nBlockXEnd = (nXOff + nXSize - 1) / m_nBlockXSize;
1000 254 : const int nBlockYEnd = (nYOff + nYSize - 1) / m_nBlockYSize;
1001 254 : const int nXBlocks = nBlockXEnd - nBlockXStart + 1;
1002 254 : const int nYBlocks = nBlockYEnd - nBlockYStart + 1;
1003 254 : const int nStrilePerBlock =
1004 254 : m_nPlanarConfig == PLANARCONFIG_CONTIG ? 1 : nBandCount;
1005 254 : const int nBlocks = nXBlocks * nYBlocks * nStrilePerBlock;
1006 :
1007 508 : GTiffDecompressContext sContext;
1008 254 : sContext.poHandle = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
1009 254 : sContext.bHasPRead =
1010 254 : sContext.poHandle->HasPRead()
1011 : #ifdef DEBUG
1012 254 : && CPLTestBool(CPLGetConfigOption("GTIFF_ALLOW_PREAD", "YES"))
1013 : #endif
1014 : ;
1015 254 : sContext.poDS = this;
1016 254 : sContext.eDT = GetRasterBand(1)->GetRasterDataType();
1017 254 : sContext.nXOff = nXOff;
1018 254 : sContext.nYOff = nYOff;
1019 254 : sContext.nXSize = nXSize;
1020 254 : sContext.nYSize = nYSize;
1021 254 : sContext.nBlockXStart = nBlockXStart;
1022 254 : sContext.nBlockXEnd = nBlockXEnd;
1023 254 : sContext.nBlockYStart = nBlockYStart;
1024 254 : sContext.nBlockYEnd = nBlockYEnd;
1025 254 : sContext.pabyData = static_cast<GByte *>(pData);
1026 254 : sContext.eBufType = eBufType;
1027 254 : sContext.nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
1028 254 : sContext.nBandCount = nBandCount;
1029 254 : sContext.panBandMap = panBandMap;
1030 254 : sContext.nPixelSpace = nPixelSpace;
1031 254 : sContext.nLineSpace = nLineSpace;
1032 : // Setting nBandSpace to a dummy value when nBandCount == 1 helps detecting
1033 : // bad computations of target buffer address
1034 : // (https://github.com/rasterio/rasterio/issues/2847)
1035 254 : sContext.nBandSpace = nBandCount == 1 ? 0xDEADBEEF : nBandSpace;
1036 254 : sContext.bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
1037 254 : sContext.bTIFFIsBigEndian = CPL_TO_BOOL(TIFFIsBigEndian(m_hTIFF));
1038 254 : sContext.nPredictor = PREDICTOR_NONE;
1039 254 : sContext.nBlocksPerRow = m_nBlocksPerRow;
1040 :
1041 254 : if (m_bDirectIO)
1042 : {
1043 0 : sContext.bSkipBlockCache = true;
1044 : }
1045 254 : else if (nXOff == 0 && nYOff == 0 && nXSize == nRasterXSize &&
1046 195 : nYSize == nRasterYSize)
1047 : {
1048 190 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1049 : {
1050 40 : sContext.bSkipBlockCache = true;
1051 : }
1052 150 : else if (nBandCount == nBands)
1053 : {
1054 74 : sContext.bSkipBlockCache = true;
1055 208 : for (int i = 0; i < nBands; ++i)
1056 : {
1057 158 : if (panBandMap[i] != i + 1)
1058 : {
1059 24 : sContext.bSkipBlockCache = false;
1060 24 : break;
1061 : }
1062 : }
1063 : }
1064 : }
1065 :
1066 254 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == nBands &&
1067 122 : nPixelSpace == nBands * static_cast<GSpacing>(sContext.nBufDTSize))
1068 : {
1069 44 : sContext.bUseBIPOptim = true;
1070 140 : for (int i = 0; i < nBands; ++i)
1071 : {
1072 96 : if (panBandMap[i] != i + 1)
1073 : {
1074 0 : sContext.bUseBIPOptim = false;
1075 0 : break;
1076 : }
1077 : }
1078 : }
1079 :
1080 254 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
1081 198 : (nBands == 3 || nBands == 4) && nBands == nBandCount &&
1082 94 : (sContext.eDT == GDT_UInt8 || sContext.eDT == GDT_Int16 ||
1083 9 : sContext.eDT == GDT_UInt16))
1084 : {
1085 94 : if (sContext.bSkipBlockCache)
1086 : {
1087 36 : if (sContext.eBufType == sContext.eDT &&
1088 35 : nPixelSpace == sContext.nBufDTSize)
1089 : {
1090 24 : sContext.bUseDeinterleaveOptimNoBlockCache = true;
1091 : }
1092 : }
1093 : else
1094 : {
1095 58 : sContext.bUseDeinterleaveOptimBlockCache = true;
1096 166 : for (int i = 0; i < nBands; ++i)
1097 : {
1098 130 : if (panBandMap[i] != i + 1)
1099 : {
1100 22 : sContext.bUseDeinterleaveOptimBlockCache = false;
1101 22 : break;
1102 : }
1103 : }
1104 : }
1105 : }
1106 :
1107 : // In contig mode, if only one band is requested, check if we have
1108 : // enough cache to cache all bands.
1109 254 : if (!sContext.bSkipBlockCache && nBands != 1 &&
1110 151 : m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == 1)
1111 : {
1112 76 : const GIntBig nRequiredMem = static_cast<GIntBig>(nBands) * nXBlocks *
1113 76 : nYBlocks * m_nBlockXSize * m_nBlockYSize *
1114 76 : GDALGetDataTypeSizeBytes(sContext.eDT);
1115 76 : if (nRequiredMem > GDALGetCacheMax64())
1116 : {
1117 0 : if (!m_bHasWarnedDisableAggressiveBandCaching)
1118 : {
1119 0 : CPLDebug("GTiff",
1120 : "Disable aggressive band caching. "
1121 : "Cache not big enough. "
1122 : "At least " CPL_FRMT_GIB " bytes necessary",
1123 : nRequiredMem);
1124 0 : m_bHasWarnedDisableAggressiveBandCaching = true;
1125 : }
1126 : }
1127 : else
1128 : {
1129 76 : sContext.bCacheAllBands = true;
1130 76 : if ((nBands == 3 || nBands == 4) &&
1131 66 : (sContext.eDT == GDT_UInt8 || sContext.eDT == GDT_Int16 ||
1132 6 : sContext.eDT == GDT_UInt16))
1133 : {
1134 66 : sContext.bUseDeinterleaveOptimBlockCache = true;
1135 : }
1136 : }
1137 : }
1138 :
1139 254 : if (eAccess == GA_Update)
1140 : {
1141 234 : std::vector<int> anBandsToCheck;
1142 234 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
1143 : {
1144 740 : for (int i = 0; i < nBands; ++i)
1145 : {
1146 564 : anBandsToCheck.push_back(i);
1147 176 : }
1148 : }
1149 : else
1150 : {
1151 170 : for (int i = 0; i < nBandCount; ++i)
1152 : {
1153 112 : anBandsToCheck.push_back(panBandMap[i] - 1);
1154 : }
1155 : }
1156 234 : if (!anBandsToCheck.empty())
1157 : {
1158 : // If at least one block in the region of intersest is dirty,
1159 : // fallback to normal reading code path to be able to retrieve
1160 : // content partly from the block cache.
1161 : // An alternative that was implemented in GDAL 3.6 to 3.8.0 was
1162 : // to flush dirty blocks, but this could cause many write&read&write
1163 : // cycles in some gdalwarp scenarios.
1164 : // Cf https://github.com/OSGeo/gdal/issues/8729
1165 234 : bool bUseBaseImplementation = false;
1166 1225 : for (int y = 0; y < nYBlocks; ++y)
1167 : {
1168 3521 : for (int x = 0; x < nXBlocks; ++x)
1169 : {
1170 8912 : for (const int iBand : anBandsToCheck)
1171 : {
1172 6400 : if (m_nLoadedBlock >= 0 && m_bLoadedBlockDirty &&
1173 0 : cpl::down_cast<GTiffRasterBand *>(papoBands[iBand])
1174 0 : ->ComputeBlockId(nBlockXStart + x,
1175 : nBlockYStart + y) ==
1176 0 : m_nLoadedBlock)
1177 : {
1178 0 : bUseBaseImplementation = true;
1179 18 : goto after_loop;
1180 : }
1181 12800 : auto poBlock = papoBands[iBand]->TryGetLockedBlockRef(
1182 6400 : nBlockXStart + x, nBlockYStart + y);
1183 6400 : if (poBlock)
1184 : {
1185 3868 : if (poBlock->GetDirty())
1186 : {
1187 18 : poBlock->DropLock();
1188 18 : bUseBaseImplementation = true;
1189 18 : goto after_loop;
1190 : }
1191 3850 : poBlock->DropLock();
1192 : }
1193 : }
1194 : }
1195 : }
1196 216 : after_loop:
1197 234 : if (bUseBaseImplementation)
1198 : {
1199 18 : ++m_nDisableMultiThreadedRead;
1200 : GDALRasterIOExtraArg sExtraArg;
1201 18 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1202 18 : const CPLErr eErr = GDALDataset::IRasterIO(
1203 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nXSize,
1204 : nYSize, eBufType, nBandCount, const_cast<int *>(panBandMap),
1205 : nPixelSpace, nLineSpace, nBandSpace, &sExtraArg);
1206 18 : --m_nDisableMultiThreadedRead;
1207 18 : return eErr;
1208 : }
1209 : }
1210 :
1211 : // Make sure that all blocks that we are going to read and that are
1212 : // being written by a worker thread are completed.
1213 : // cppcheck-suppress constVariableReference
1214 216 : auto &oQueue =
1215 216 : m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
1216 216 : if (!oQueue.empty())
1217 : {
1218 85 : for (int y = 0; y < nYBlocks; ++y)
1219 : {
1220 192 : for (int x = 0; x < nXBlocks; ++x)
1221 : {
1222 296 : for (int i = 0; i < nStrilePerBlock; ++i)
1223 : {
1224 176 : int nBlockId =
1225 176 : nBlockXStart + x +
1226 176 : (nBlockYStart + y) * sContext.nBlocksPerRow;
1227 176 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1228 84 : nBlockId += (panBandMap[i] - 1) * m_nBlocksPerBand;
1229 :
1230 176 : WaitCompletionForBlock(nBlockId);
1231 : }
1232 : }
1233 : }
1234 : }
1235 :
1236 : // Flush to file, and then to disk if using pread() interface
1237 216 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
1238 216 : if (sContext.bHasPRead)
1239 216 : sContext.poHandle->Flush();
1240 : }
1241 :
1242 236 : if (GTIFFSupportsPredictor(m_nCompression))
1243 : {
1244 155 : TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &sContext.nPredictor);
1245 : }
1246 81 : else if (m_nCompression == COMPRESSION_JPEG)
1247 : {
1248 2 : TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &sContext.nJPEGTableSize,
1249 : &sContext.pJPEGTable);
1250 2 : if (m_nPhotometric == PHOTOMETRIC_YCBCR)
1251 : {
1252 1 : TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
1253 : &sContext.nYCrbCrSubSampling0,
1254 : &sContext.nYCrbCrSubSampling1);
1255 : }
1256 : }
1257 236 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
1258 : {
1259 189 : TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &sContext.nExtraSampleCount,
1260 : &sContext.pExtraSamples);
1261 : }
1262 :
1263 : // Create one job per tile/strip
1264 236 : vsi_l_offset nFileSize = 0;
1265 472 : std::vector<GTiffDecompressJob> asJobs(nBlocks);
1266 472 : std::vector<vsi_l_offset> anOffsets(nBlocks);
1267 472 : std::vector<size_t> anSizes(nBlocks);
1268 236 : int iJob = 0;
1269 236 : int nAdviseReadRanges = 0;
1270 : const size_t nAdviseReadTotalBytesLimit =
1271 236 : sContext.poHandle->GetAdviseReadTotalBytesLimit();
1272 236 : size_t nAdviseReadAccBytes = 0;
1273 8697 : for (int y = 0; y < nYBlocks; ++y)
1274 : {
1275 18491 : for (int x = 0; x < nXBlocks; ++x)
1276 : {
1277 21125 : for (int i = 0; i < nStrilePerBlock; ++i)
1278 : {
1279 11098 : asJobs[iJob].psContext = &sContext;
1280 11098 : asJobs[iJob].iSrcBandIdxSeparate =
1281 11098 : m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1
1282 2200 : : panBandMap[i] - 1;
1283 11098 : asJobs[iJob].iDstBandIdxSeparate =
1284 11098 : m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1 : i;
1285 11098 : asJobs[iJob].nXBlock = nBlockXStart + x;
1286 11098 : asJobs[iJob].nYBlock = nBlockYStart + y;
1287 :
1288 11098 : int nBlockId = asJobs[iJob].nXBlock +
1289 11098 : asJobs[iJob].nYBlock * sContext.nBlocksPerRow;
1290 11098 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1291 2200 : nBlockId +=
1292 2200 : asJobs[iJob].iSrcBandIdxSeparate * m_nBlocksPerBand;
1293 :
1294 11098 : bool bErrorInIsBlockAvailable = false;
1295 11098 : if (!sContext.bHasPRead)
1296 : {
1297 : // Taking the mutex here is only needed when bHasPRead ==
1298 : // false since we could have concurrent uses of the handle,
1299 : // when when reading the TIFF TileOffsets / TileByteCounts
1300 : // array
1301 : std::lock_guard<std::recursive_mutex> oLock(
1302 0 : sContext.oMutex);
1303 :
1304 0 : CPL_IGNORE_RET_VAL(IsBlockAvailable(
1305 0 : nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
1306 : &bErrorInIsBlockAvailable));
1307 : }
1308 : else
1309 : {
1310 11098 : CPL_IGNORE_RET_VAL(IsBlockAvailable(
1311 11098 : nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
1312 : &bErrorInIsBlockAvailable));
1313 : }
1314 11098 : if (bErrorInIsBlockAvailable)
1315 : {
1316 2 : ReportError(CE_Failure, CPLE_AppDefined,
1317 : "Error while getting location of block %d",
1318 : nBlockId);
1319 : std::lock_guard<std::recursive_mutex> oLock(
1320 2 : sContext.oMutex);
1321 2 : sContext.bSuccess = false;
1322 2 : return CE_Failure;
1323 : }
1324 :
1325 : // Sanity check on block size
1326 11096 : if (asJobs[iJob].nSize > 100U * 1024 * 1024)
1327 : {
1328 0 : if (nFileSize == 0)
1329 : {
1330 : std::lock_guard<std::recursive_mutex> oLock(
1331 0 : sContext.oMutex);
1332 0 : sContext.poHandle->Seek(0, SEEK_END);
1333 0 : nFileSize = sContext.poHandle->Tell();
1334 : }
1335 0 : if (asJobs[iJob].nSize > nFileSize)
1336 : {
1337 0 : CPLError(CE_Failure, CPLE_AppDefined,
1338 : "Cannot read " CPL_FRMT_GUIB
1339 : " bytes at offset " CPL_FRMT_GUIB,
1340 0 : static_cast<GUIntBig>(asJobs[iJob].nSize),
1341 0 : static_cast<GUIntBig>(asJobs[iJob].nOffset));
1342 :
1343 : std::lock_guard<std::recursive_mutex> oLock(
1344 0 : sContext.oMutex);
1345 0 : sContext.bSuccess = false;
1346 0 : return CE_Failure;
1347 : }
1348 : }
1349 :
1350 : // Only request in AdviseRead() ranges for blocks we don't
1351 : // have in cache.
1352 11096 : bool bAddToAdviseRead = true;
1353 11096 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1354 : {
1355 : auto poBlock =
1356 2200 : GetRasterBand(panBandMap[i])
1357 2200 : ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
1358 2200 : asJobs[iJob].nYBlock);
1359 2200 : if (poBlock)
1360 : {
1361 968 : poBlock->DropLock();
1362 968 : bAddToAdviseRead = false;
1363 : }
1364 : }
1365 : else
1366 : {
1367 8896 : bool bAllCached = true;
1368 10606 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1369 : {
1370 : auto poBlock =
1371 9676 : GetRasterBand(panBandMap[iBand])
1372 9676 : ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
1373 9676 : asJobs[iJob].nYBlock);
1374 9676 : if (poBlock)
1375 : {
1376 1710 : poBlock->DropLock();
1377 : }
1378 : else
1379 : {
1380 7966 : bAllCached = false;
1381 7966 : break;
1382 : }
1383 : }
1384 8896 : if (bAllCached)
1385 930 : bAddToAdviseRead = false;
1386 : }
1387 :
1388 11096 : if (bAddToAdviseRead)
1389 : {
1390 9198 : anOffsets[nAdviseReadRanges] = asJobs[iJob].nOffset;
1391 18396 : anSizes[nAdviseReadRanges] =
1392 9198 : static_cast<size_t>(std::min<vsi_l_offset>(
1393 27594 : std::numeric_limits<size_t>::max(),
1394 9198 : asJobs[iJob].nSize));
1395 :
1396 : // If the total number of bytes we must read excess the
1397 : // capacity of AdviseRead(), then split the RasterIO()
1398 : // request in 2 halves.
1399 16666 : if (nAdviseReadTotalBytesLimit > 0 &&
1400 7468 : anSizes[nAdviseReadRanges] <
1401 7468 : nAdviseReadTotalBytesLimit &&
1402 7468 : anSizes[nAdviseReadRanges] >
1403 16666 : nAdviseReadTotalBytesLimit - nAdviseReadAccBytes &&
1404 : nYBlocks >= 2)
1405 : {
1406 1 : const int nYOff2 =
1407 1 : (nBlockYStart + nYBlocks / 2) * m_nBlockYSize;
1408 1 : CPLDebugOnly("GTiff",
1409 : "Splitting request (%d,%d,%dx%d) into "
1410 : "(%d,%d,%dx%d) and (%d,%d,%dx%d)",
1411 : nXOff, nYOff, nXSize, nYSize, nXOff, nYOff,
1412 : nXSize, nYOff2 - nYOff, nXOff, nYOff2,
1413 : nXSize, nYOff + nYSize - nYOff2);
1414 :
1415 1 : asJobs.clear();
1416 1 : anOffsets.clear();
1417 1 : anSizes.clear();
1418 1 : poQueue.reset();
1419 :
1420 1 : CPLErr eErr = MultiThreadedRead(
1421 : nXOff, nYOff, nXSize, nYOff2 - nYOff, pData,
1422 : eBufType, nBandCount, panBandMap, nPixelSpace,
1423 : nLineSpace, nBandSpace);
1424 1 : if (eErr == CE_None)
1425 : {
1426 1 : eErr = MultiThreadedRead(
1427 1 : nXOff, nYOff2, nXSize, nYOff + nYSize - nYOff2,
1428 : static_cast<GByte *>(pData) +
1429 1 : (nYOff2 - nYOff) * nLineSpace,
1430 : eBufType, nBandCount, panBandMap, nPixelSpace,
1431 : nLineSpace, nBandSpace);
1432 : }
1433 1 : return eErr;
1434 : }
1435 9197 : nAdviseReadAccBytes += anSizes[nAdviseReadRanges];
1436 :
1437 9197 : ++nAdviseReadRanges;
1438 : }
1439 :
1440 11095 : ++iJob;
1441 : }
1442 : }
1443 : }
1444 :
1445 233 : if (sContext.bSuccess)
1446 : {
1447 : // Potentially start asynchronous fetching of ranges depending on file
1448 : // implementation
1449 233 : if (nAdviseReadRanges > 0)
1450 : {
1451 106 : sContext.poHandle->AdviseRead(nAdviseReadRanges, anOffsets.data(),
1452 106 : anSizes.data());
1453 : }
1454 :
1455 : // We need to do that as threads will access the block cache
1456 233 : TemporarilyDropReadWriteLock();
1457 :
1458 4069 : for (auto &sJob : asJobs)
1459 : {
1460 3836 : poQueue->SubmitJob(ThreadDecompressionFunc, &sJob);
1461 : }
1462 :
1463 : // Wait for all jobs to have been completed
1464 233 : poQueue->WaitCompletion();
1465 :
1466 : // Undo effect of above TemporarilyDropReadWriteLock()
1467 233 : ReacquireReadWriteLock();
1468 :
1469 233 : sContext.oErrorAccumulator.ReplayErrors();
1470 : }
1471 :
1472 233 : return sContext.bSuccess ? CE_None : CE_Failure;
1473 : }
1474 :
1475 : /************************************************************************/
1476 : /* FetchBufferVirtualMemIO */
1477 : /************************************************************************/
1478 :
1479 : class FetchBufferVirtualMemIO final
1480 : {
1481 : const GByte *pabySrcData;
1482 : size_t nMappingSize;
1483 : GByte *pTempBuffer;
1484 :
1485 : public:
1486 971 : FetchBufferVirtualMemIO(const GByte *pabySrcDataIn, size_t nMappingSizeIn,
1487 : GByte *pTempBufferIn)
1488 971 : : pabySrcData(pabySrcDataIn), nMappingSize(nMappingSizeIn),
1489 971 : pTempBuffer(pTempBufferIn)
1490 : {
1491 971 : }
1492 :
1493 897395 : const GByte *FetchBytes(vsi_l_offset nOffset, int nPixels, int nDTSize,
1494 : bool bIsByteSwapped, bool bIsComplex, int nBlockId)
1495 : {
1496 897395 : if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
1497 : {
1498 24 : CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
1499 : nBlockId);
1500 24 : return nullptr;
1501 : }
1502 897371 : if (!bIsByteSwapped)
1503 572847 : return pabySrcData + nOffset;
1504 324524 : memcpy(pTempBuffer, pabySrcData + nOffset,
1505 324524 : static_cast<size_t>(nPixels) * nDTSize);
1506 324524 : if (bIsComplex)
1507 159940 : GDALSwapWords(pTempBuffer, nDTSize / 2, 2 * nPixels, nDTSize / 2);
1508 : else
1509 164584 : GDALSwapWords(pTempBuffer, nDTSize, nPixels, nDTSize);
1510 324524 : return pTempBuffer;
1511 : }
1512 :
1513 115046 : bool FetchBytes(GByte *pabyDstBuffer, vsi_l_offset nOffset, int nPixels,
1514 : int nDTSize, bool bIsByteSwapped, bool bIsComplex,
1515 : int nBlockId)
1516 : {
1517 115046 : if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
1518 : {
1519 11 : CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
1520 : nBlockId);
1521 11 : return false;
1522 : }
1523 115035 : memcpy(pabyDstBuffer, pabySrcData + nOffset,
1524 115035 : static_cast<size_t>(nPixels) * nDTSize);
1525 115035 : if (bIsByteSwapped)
1526 : {
1527 48082 : if (bIsComplex)
1528 26390 : GDALSwapWords(pabyDstBuffer, nDTSize / 2, 2 * nPixels,
1529 : nDTSize / 2);
1530 : else
1531 21692 : GDALSwapWords(pabyDstBuffer, nDTSize, nPixels, nDTSize);
1532 : }
1533 115035 : return true;
1534 : }
1535 :
1536 : // cppcheck-suppress unusedStructMember
1537 : static const bool bMinimizeIO = false;
1538 : };
1539 :
1540 : /************************************************************************/
1541 : /* VirtualMemIO() */
1542 : /************************************************************************/
1543 :
1544 1101 : int GTiffDataset::VirtualMemIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1545 : int nXSize, int nYSize, void *pData,
1546 : int nBufXSize, int nBufYSize,
1547 : GDALDataType eBufType, int nBandCount,
1548 : const int *panBandMap, GSpacing nPixelSpace,
1549 : GSpacing nLineSpace, GSpacing nBandSpace,
1550 : GDALRasterIOExtraArg *psExtraArg)
1551 : {
1552 1101 : if (eAccess == GA_Update || eRWFlag == GF_Write || m_bStreamingIn)
1553 0 : return -1;
1554 :
1555 : // Only know how to deal with nearest neighbour in this optimized routine.
1556 1101 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
1557 417 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
1558 : {
1559 130 : return -1;
1560 : }
1561 :
1562 971 : const GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
1563 971 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
1564 971 : if (!(m_nCompression == COMPRESSION_NONE &&
1565 971 : (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
1566 392 : m_nPhotometric == PHOTOMETRIC_RGB ||
1567 0 : m_nPhotometric == PHOTOMETRIC_PALETTE) &&
1568 971 : m_nBitsPerSample == nDTSizeBits))
1569 : {
1570 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1571 0 : return -1;
1572 : }
1573 :
1574 971 : size_t nMappingSize = 0;
1575 971 : GByte *pabySrcData = nullptr;
1576 971 : if (STARTS_WITH(m_osFilename.c_str(), "/vsimem/"))
1577 : {
1578 708 : vsi_l_offset nDataLength = 0;
1579 : pabySrcData =
1580 708 : VSIGetMemFileBuffer(m_osFilename.c_str(), &nDataLength, FALSE);
1581 708 : nMappingSize = static_cast<size_t>(nDataLength);
1582 708 : if (pabySrcData == nullptr)
1583 0 : return -1;
1584 : }
1585 263 : else if (m_psVirtualMemIOMapping == nullptr)
1586 : {
1587 11 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
1588 22 : if (!CPLIsVirtualMemFileMapAvailable() ||
1589 11 : VSIFGetNativeFileDescriptorL(fp) == nullptr)
1590 : {
1591 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1592 0 : return -1;
1593 : }
1594 11 : if (VSIFSeekL(fp, 0, SEEK_END) != 0)
1595 : {
1596 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1597 0 : return -1;
1598 : }
1599 11 : const vsi_l_offset nLength = VSIFTellL(fp);
1600 : if (static_cast<size_t>(nLength) != nLength)
1601 : {
1602 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1603 : return -1;
1604 : }
1605 11 : if (m_eVirtualMemIOUsage == VirtualMemIOEnum::IF_ENOUGH_RAM)
1606 : {
1607 0 : GIntBig nRAM = CPLGetUsablePhysicalRAM();
1608 0 : if (static_cast<GIntBig>(nLength) > nRAM)
1609 : {
1610 0 : CPLDebug("GTiff",
1611 : "Not enough RAM to map whole file into memory.");
1612 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1613 0 : return -1;
1614 : }
1615 : }
1616 11 : m_psVirtualMemIOMapping = CPLVirtualMemFileMapNew(
1617 : fp, 0, nLength, VIRTUALMEM_READONLY, nullptr, nullptr);
1618 11 : if (m_psVirtualMemIOMapping == nullptr)
1619 : {
1620 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1621 0 : return -1;
1622 : }
1623 11 : m_eVirtualMemIOUsage = VirtualMemIOEnum::YES;
1624 : }
1625 :
1626 971 : if (m_psVirtualMemIOMapping)
1627 : {
1628 : #ifdef DEBUG
1629 263 : CPLDebug("GTiff", "Using VirtualMemIO");
1630 : #endif
1631 263 : nMappingSize = CPLVirtualMemGetSize(m_psVirtualMemIOMapping);
1632 : pabySrcData =
1633 263 : static_cast<GByte *>(CPLVirtualMemGetAddr(m_psVirtualMemIOMapping));
1634 : }
1635 :
1636 971 : if (TIFFIsByteSwapped(m_hTIFF) && m_pTempBufferForCommonDirectIO == nullptr)
1637 : {
1638 12 : const int nDTSize = nDTSizeBits / 8;
1639 12 : size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
1640 24 : m_nBlockXSize * nDTSize *
1641 12 : (m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1));
1642 12 : if (TIFFIsTiled(m_hTIFF))
1643 6 : nTempBufferForCommonDirectIOSize *= m_nBlockYSize;
1644 :
1645 12 : m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
1646 12 : VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
1647 12 : if (m_pTempBufferForCommonDirectIO == nullptr)
1648 0 : return CE_Failure;
1649 : }
1650 : FetchBufferVirtualMemIO oFetcher(pabySrcData, nMappingSize,
1651 971 : m_pTempBufferForCommonDirectIO);
1652 :
1653 971 : return CommonDirectIO(oFetcher, nXOff, nYOff, nXSize, nYSize, pData,
1654 : nBufXSize, nBufYSize, eBufType, nBandCount,
1655 971 : panBandMap, nPixelSpace, nLineSpace, nBandSpace);
1656 : }
1657 :
1658 : /************************************************************************/
1659 : /* CopyContigByteMultiBand() */
1660 : /************************************************************************/
1661 :
1662 2754 : static inline void CopyContigByteMultiBand(const GByte *CPL_RESTRICT pabySrc,
1663 : int nSrcStride,
1664 : GByte *CPL_RESTRICT pabyDest,
1665 : int nDestStride, int nIters,
1666 : int nBandCount)
1667 : {
1668 2754 : if (nBandCount == 3)
1669 : {
1670 1620 : if (nSrcStride == 3 && nDestStride == 4)
1671 : {
1672 2106 : while (nIters >= 8)
1673 : {
1674 1620 : pabyDest[4 * 0 + 0] = pabySrc[3 * 0 + 0];
1675 1620 : pabyDest[4 * 0 + 1] = pabySrc[3 * 0 + 1];
1676 1620 : pabyDest[4 * 0 + 2] = pabySrc[3 * 0 + 2];
1677 1620 : pabyDest[4 * 1 + 0] = pabySrc[3 * 1 + 0];
1678 1620 : pabyDest[4 * 1 + 1] = pabySrc[3 * 1 + 1];
1679 1620 : pabyDest[4 * 1 + 2] = pabySrc[3 * 1 + 2];
1680 1620 : pabyDest[4 * 2 + 0] = pabySrc[3 * 2 + 0];
1681 1620 : pabyDest[4 * 2 + 1] = pabySrc[3 * 2 + 1];
1682 1620 : pabyDest[4 * 2 + 2] = pabySrc[3 * 2 + 2];
1683 1620 : pabyDest[4 * 3 + 0] = pabySrc[3 * 3 + 0];
1684 1620 : pabyDest[4 * 3 + 1] = pabySrc[3 * 3 + 1];
1685 1620 : pabyDest[4 * 3 + 2] = pabySrc[3 * 3 + 2];
1686 1620 : pabyDest[4 * 4 + 0] = pabySrc[3 * 4 + 0];
1687 1620 : pabyDest[4 * 4 + 1] = pabySrc[3 * 4 + 1];
1688 1620 : pabyDest[4 * 4 + 2] = pabySrc[3 * 4 + 2];
1689 1620 : pabyDest[4 * 5 + 0] = pabySrc[3 * 5 + 0];
1690 1620 : pabyDest[4 * 5 + 1] = pabySrc[3 * 5 + 1];
1691 1620 : pabyDest[4 * 5 + 2] = pabySrc[3 * 5 + 2];
1692 1620 : pabyDest[4 * 6 + 0] = pabySrc[3 * 6 + 0];
1693 1620 : pabyDest[4 * 6 + 1] = pabySrc[3 * 6 + 1];
1694 1620 : pabyDest[4 * 6 + 2] = pabySrc[3 * 6 + 2];
1695 1620 : pabyDest[4 * 7 + 0] = pabySrc[3 * 7 + 0];
1696 1620 : pabyDest[4 * 7 + 1] = pabySrc[3 * 7 + 1];
1697 1620 : pabyDest[4 * 7 + 2] = pabySrc[3 * 7 + 2];
1698 1620 : pabySrc += 3 * 8;
1699 1620 : pabyDest += 4 * 8;
1700 1620 : nIters -= 8;
1701 : }
1702 648 : while (nIters-- > 0)
1703 : {
1704 162 : pabyDest[0] = pabySrc[0];
1705 162 : pabyDest[1] = pabySrc[1];
1706 162 : pabyDest[2] = pabySrc[2];
1707 162 : pabySrc += 3;
1708 162 : pabyDest += 4;
1709 : }
1710 : }
1711 : else
1712 : {
1713 53622 : while (nIters-- > 0)
1714 : {
1715 52488 : pabyDest[0] = pabySrc[0];
1716 52488 : pabyDest[1] = pabySrc[1];
1717 52488 : pabyDest[2] = pabySrc[2];
1718 52488 : pabySrc += nSrcStride;
1719 52488 : pabyDest += nDestStride;
1720 : }
1721 : }
1722 : }
1723 : else
1724 : {
1725 53622 : while (nIters-- > 0)
1726 : {
1727 236196 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1728 183708 : pabyDest[iBand] = pabySrc[iBand];
1729 52488 : pabySrc += nSrcStride;
1730 52488 : pabyDest += nDestStride;
1731 : }
1732 : }
1733 2754 : }
1734 :
1735 : /************************************************************************/
1736 : /* CommonDirectIO() */
1737 : /************************************************************************/
1738 :
1739 : // #define DEBUG_REACHED_VIRTUAL_MEM_IO
1740 : #ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
1741 : static int anReachedVirtualMemIO[52] = {0};
1742 : #define REACHED(x) anReachedVirtualMemIO[x] = 1
1743 : #else
1744 : #define REACHED(x)
1745 : #endif
1746 :
1747 : template <class FetchBuffer>
1748 1742 : CPLErr GTiffDataset::CommonDirectIO(FetchBuffer &oFetcher, int nXOff, int nYOff,
1749 : int nXSize, int nYSize, void *pData,
1750 : int nBufXSize, int nBufYSize,
1751 : GDALDataType eBufType, int nBandCount,
1752 : const int *panBandMap, GSpacing nPixelSpace,
1753 : GSpacing nLineSpace, GSpacing nBandSpace)
1754 : {
1755 : const auto poFirstBand =
1756 1742 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(1));
1757 1742 : const GDALDataType eDataType = poFirstBand->GetRasterDataType();
1758 1742 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
1759 1742 : const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
1760 1742 : const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
1761 :
1762 : // Get strip offsets.
1763 1742 : toff_t *panOffsets = nullptr;
1764 1742 : if (!TIFFGetField(m_hTIFF,
1765 1742 : (TIFFIsTiled(m_hTIFF)) ? TIFFTAG_TILEOFFSETS
1766 : : TIFFTAG_STRIPOFFSETS,
1767 3484 : &panOffsets) ||
1768 1742 : panOffsets == nullptr)
1769 : {
1770 0 : return CE_Failure;
1771 : }
1772 :
1773 346 : bool bUseContigImplementation = m_nPlanarConfig == PLANARCONFIG_CONTIG &&
1774 2088 : nBandCount > 1 && nBandSpace == nBufDTSize;
1775 1742 : if (bUseContigImplementation)
1776 : {
1777 470 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1778 : {
1779 370 : const int nBand = panBandMap[iBand];
1780 370 : if (nBand != iBand + 1)
1781 : {
1782 0 : bUseContigImplementation = false;
1783 0 : break;
1784 : }
1785 : }
1786 : }
1787 :
1788 1742 : const int nBandsPerBlock =
1789 1742 : m_nPlanarConfig == PLANARCONFIG_SEPARATE ? 1 : nBands;
1790 1742 : const int nBandsPerBlockDTSize = nBandsPerBlock * nDTSize;
1791 1742 : const bool bNoTypeChange = (eDataType == eBufType);
1792 1742 : const bool bNoXResampling = (nXSize == nBufXSize);
1793 1742 : const bool bNoXResamplingNoTypeChange = (bNoTypeChange && bNoXResampling);
1794 1742 : const bool bByteOnly = (bNoTypeChange && nDTSize == 1);
1795 1742 : const bool bByteNoXResampling = (bByteOnly && bNoXResamplingNoTypeChange);
1796 1742 : const bool bIsByteSwapped = CPL_TO_BOOL(TIFFIsByteSwapped(m_hTIFF));
1797 1742 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
1798 1742 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
1799 :
1800 1742 : int bNoDataSetIn = FALSE;
1801 1742 : double dfNoData = poFirstBand->GetNoDataValue(&bNoDataSetIn);
1802 1742 : GByte abyNoData = 0;
1803 1742 : if (!bNoDataSetIn)
1804 1742 : dfNoData = 0;
1805 0 : else if (dfNoData >= 0 && dfNoData <= 255)
1806 0 : abyNoData = static_cast<GByte>(dfNoData + 0.5);
1807 :
1808 : // cppcheck-suppress knownConditionTrueFalse
1809 1542 : if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) && bNoXResampling &&
1810 1542 : (nYSize == nBufYSize) && m_nPlanarConfig == PLANARCONFIG_CONTIG &&
1811 : nBandCount > 1)
1812 : {
1813 35 : GByte *pabyData = static_cast<GByte *>(pData);
1814 275 : for (int y = 0; y < nBufYSize;)
1815 : {
1816 242 : const int nSrcLine = nYOff + y;
1817 242 : const int nBlockYOff = nSrcLine / m_nBlockYSize;
1818 242 : const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
1819 242 : const int nUsedBlockHeight =
1820 242 : std::min(nBufYSize - y, m_nBlockYSize - nYOffsetInBlock);
1821 :
1822 242 : int nBlockXOff = nXOff / m_nBlockXSize;
1823 242 : int nXOffsetInBlock = nXOff % m_nBlockXSize;
1824 242 : int nBlockId = poFirstBand->ComputeBlockId(nBlockXOff, nBlockYOff);
1825 :
1826 242 : int x = 0;
1827 1200 : while (x < nBufXSize)
1828 : {
1829 960 : const toff_t nCurOffset = panOffsets[nBlockId];
1830 960 : const int nUsedBlockWidth =
1831 960 : std::min(m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
1832 :
1833 960 : if (nCurOffset == 0)
1834 : {
1835 : REACHED(30);
1836 7287 : for (int k = 0; k < nUsedBlockHeight; ++k)
1837 : {
1838 6813 : GByte *pabyLocalData =
1839 6813 : pabyData + (y + k) * nLineSpace + x * nPixelSpace;
1840 33573 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1841 : {
1842 26760 : GByte *pabyLocalDataBand =
1843 26760 : pabyLocalData + iBand * nBandSpace;
1844 :
1845 26760 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
1846 : pabyLocalDataBand, eBufType,
1847 : static_cast<int>(nPixelSpace),
1848 : nUsedBlockWidth);
1849 : }
1850 : }
1851 : }
1852 : else
1853 : {
1854 486 : const int nByteOffsetInBlock =
1855 486 : nYOffsetInBlock * m_nBlockXSize * nBandsPerBlockDTSize;
1856 972 : const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
1857 486 : nCurOffset + nByteOffsetInBlock,
1858 486 : m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
1859 : nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
1860 486 : if (pabyLocalSrcDataK0 == nullptr)
1861 2 : return CE_Failure;
1862 :
1863 7468 : for (int k = 0; k < nUsedBlockHeight; ++k)
1864 : {
1865 6984 : GByte *pabyLocalData =
1866 6984 : pabyData + (y + k) * nLineSpace + x * nPixelSpace;
1867 6984 : const GByte *pabyLocalSrcData =
1868 : pabyLocalSrcDataK0 +
1869 6984 : (k * m_nBlockXSize + nXOffsetInBlock) *
1870 : nBandsPerBlockDTSize;
1871 :
1872 6984 : if (bUseContigImplementation && nBands == nBandCount &&
1873 3234 : nPixelSpace == nBandsPerBlockDTSize)
1874 : {
1875 : REACHED(31);
1876 2262 : GDALCopyWords(pabyLocalSrcData, eDataType, nDTSize,
1877 : pabyLocalData, eBufType, nBufDTSize,
1878 2262 : nUsedBlockWidth * nBands);
1879 : }
1880 : else
1881 : {
1882 : REACHED(32);
1883 22608 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1884 : {
1885 17886 : GByte *pabyLocalDataBand =
1886 17886 : pabyLocalData + iBand * nBandSpace;
1887 17886 : const GByte *pabyLocalSrcDataBand =
1888 : pabyLocalSrcData +
1889 17886 : (panBandMap[iBand] - 1) * nDTSize;
1890 :
1891 17886 : GDALCopyWords(pabyLocalSrcDataBand, eDataType,
1892 : nBandsPerBlockDTSize,
1893 : pabyLocalDataBand, eBufType,
1894 : static_cast<int>(nPixelSpace),
1895 : nUsedBlockWidth);
1896 : }
1897 : }
1898 : }
1899 : }
1900 :
1901 958 : nXOffsetInBlock = 0;
1902 958 : ++nBlockXOff;
1903 958 : ++nBlockId;
1904 958 : x += nUsedBlockWidth;
1905 : }
1906 :
1907 240 : y += nUsedBlockHeight;
1908 : }
1909 : }
1910 : // cppcheck-suppress knownConditionTrueFalse
1911 1472 : else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
1912 1472 : bNoXResampling && (nYSize == nBufYSize))
1913 : // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
1914 : {
1915 967 : for (int iBand = 0; iBand < nBandCount; ++iBand)
1916 : {
1917 488 : GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
1918 488 : const int nBand = panBandMap[iBand];
1919 : auto poCurBand =
1920 488 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
1921 3783 : for (int y = 0; y < nBufYSize;)
1922 : {
1923 3304 : const int nSrcLine = nYOff + y;
1924 3304 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
1925 3304 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
1926 3304 : const int nUsedBlockHeight =
1927 3304 : std::min(nBufYSize - y, m_nBlockYSize - nYOffsetIm_nBlock);
1928 :
1929 3304 : int nBlockXOff = nXOff / m_nBlockXSize;
1930 3304 : int nXOffsetInBlock = nXOff % m_nBlockXSize;
1931 : int nBlockId =
1932 3304 : poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
1933 :
1934 3304 : int x = 0;
1935 16000 : while (x < nBufXSize)
1936 : {
1937 12705 : const toff_t nCurOffset = panOffsets[nBlockId];
1938 12705 : const int nUsedBlockWidth = std::min(
1939 12705 : m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
1940 :
1941 12705 : if (nCurOffset == 0)
1942 : {
1943 : REACHED(35);
1944 42642 : for (int k = 0; k < nUsedBlockHeight; ++k)
1945 : {
1946 39858 : GByte *pabyLocalData = pabyData +
1947 39858 : (y + k) * nLineSpace +
1948 39858 : x * nPixelSpace;
1949 :
1950 39858 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
1951 : pabyLocalData, eBufType,
1952 : static_cast<int>(nPixelSpace),
1953 : nUsedBlockWidth);
1954 : }
1955 : }
1956 : else
1957 : {
1958 9921 : const int nByteOffsetIm_nBlock = nYOffsetIm_nBlock *
1959 9921 : m_nBlockXSize *
1960 : nBandsPerBlockDTSize;
1961 19842 : const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
1962 9921 : nCurOffset + nByteOffsetIm_nBlock,
1963 9921 : m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
1964 : nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
1965 9921 : if (pabyLocalSrcDataK0 == nullptr)
1966 9 : return CE_Failure;
1967 :
1968 9912 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
1969 : {
1970 : REACHED(36);
1971 512 : pabyLocalSrcDataK0 += (nBand - 1) * nDTSize;
1972 : }
1973 : else
1974 : {
1975 : REACHED(37);
1976 : }
1977 :
1978 151464 : for (int k = 0; k < nUsedBlockHeight; ++k)
1979 : {
1980 141552 : GByte *pabyLocalData = pabyData +
1981 141552 : (y + k) * nLineSpace +
1982 141552 : x * nPixelSpace;
1983 141552 : const GByte *pabyLocalSrcData =
1984 : pabyLocalSrcDataK0 +
1985 141552 : (k * m_nBlockXSize + nXOffsetInBlock) *
1986 : nBandsPerBlockDTSize;
1987 :
1988 141552 : GDALCopyWords(
1989 : pabyLocalSrcData, eDataType,
1990 : nBandsPerBlockDTSize, pabyLocalData, eBufType,
1991 : static_cast<int>(nPixelSpace), nUsedBlockWidth);
1992 : }
1993 : }
1994 :
1995 12696 : nXOffsetInBlock = 0;
1996 12696 : ++nBlockXOff;
1997 12696 : ++nBlockId;
1998 12696 : x += nUsedBlockWidth;
1999 : }
2000 :
2001 3295 : y += nUsedBlockHeight;
2002 : }
2003 : }
2004 : }
2005 : // cppcheck-suppress knownConditionTrueFalse
2006 248 : else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
2007 248 : m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount > 1)
2008 : {
2009 20 : GByte *pabyData = static_cast<GByte *>(pData);
2010 20 : int anSrcYOffset[256] = {0};
2011 119 : for (int y = 0; y < nBufYSize;)
2012 : {
2013 100 : const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
2014 100 : const int nSrcLine = static_cast<int>(dfYOffStart);
2015 100 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2016 100 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2017 100 : const int nBaseByteOffsetIm_nBlock =
2018 100 : nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
2019 100 : int ychunk = 1;
2020 100 : int nLastSrcLineK = nSrcLine;
2021 100 : anSrcYOffset[0] = 0;
2022 12064 : for (int k = 1; k < nBufYSize - y; ++k)
2023 : {
2024 12044 : int nSrcLineK =
2025 12044 : nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
2026 12044 : const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
2027 12044 : if (k < 256)
2028 7544 : anSrcYOffset[k] =
2029 7544 : ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
2030 7544 : m_nBlockXSize * nBandsPerBlockDTSize;
2031 12044 : if (nBlockYOffK != m_nBlockYOff)
2032 : {
2033 80 : break;
2034 : }
2035 11964 : ++ychunk;
2036 11964 : nLastSrcLineK = nSrcLineK;
2037 : }
2038 100 : const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
2039 : // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2040 :
2041 100 : double dfSrcX = nXOff + 0.5 * dfSrcXInc;
2042 100 : int nCurBlockXOff = 0;
2043 100 : int nNextBlockXOff = 0;
2044 100 : toff_t nCurOffset = 0;
2045 100 : const GByte *pabyLocalSrcDataStartLine = nullptr;
2046 10843 : for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
2047 : {
2048 10744 : const int nSrcPixel = static_cast<int>(dfSrcX);
2049 10744 : if (nSrcPixel >= nNextBlockXOff)
2050 : {
2051 292 : const int nBlockXOff = nSrcPixel / m_nBlockXSize;
2052 292 : nCurBlockXOff = nBlockXOff * m_nBlockXSize;
2053 292 : nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
2054 : const int nBlockId =
2055 292 : poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2056 292 : nCurOffset = panOffsets[nBlockId];
2057 292 : if (nCurOffset != 0)
2058 : {
2059 292 : pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
2060 146 : nCurOffset + nBaseByteOffsetIm_nBlock,
2061 146 : m_nBlockXSize * nBandsPerBlock * nUsedBlockHeight,
2062 : nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2063 146 : if (pabyLocalSrcDataStartLine == nullptr)
2064 1 : return CE_Failure;
2065 : }
2066 : }
2067 :
2068 10743 : if (nCurOffset == 0)
2069 : {
2070 : REACHED(38);
2071 :
2072 442476 : for (int k = 0; k < ychunk; ++k)
2073 : {
2074 437062 : GByte *const pabyLocalData =
2075 437062 : pabyData + (y + k) * nLineSpace + x * nPixelSpace;
2076 2185310 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2077 : {
2078 1748250 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2079 1748250 : pabyLocalData + nBandSpace * iBand,
2080 : eBufType, 0, 1);
2081 : }
2082 : }
2083 : }
2084 : else
2085 : {
2086 5329 : const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
2087 5329 : double dfYOff = dfYOffStart;
2088 5329 : const GByte *const pabyLocalSrcDataK0 =
2089 : pabyLocalSrcDataStartLine +
2090 5329 : nXOffsetInBlock * nBandsPerBlockDTSize;
2091 5329 : GByte *pabyLocalData =
2092 5329 : pabyData + y * nLineSpace + x * nPixelSpace;
2093 429042 : for (int k = 0; k < ychunk;
2094 423713 : ++k, pabyLocalData += nLineSpace)
2095 : {
2096 423713 : const GByte *pabyLocalSrcData = nullptr;
2097 423713 : if (ychunk <= 256)
2098 : {
2099 : REACHED(39);
2100 231713 : pabyLocalSrcData =
2101 231713 : pabyLocalSrcDataK0 + anSrcYOffset[k];
2102 : }
2103 : else
2104 : {
2105 : REACHED(40);
2106 192000 : const int nYOffsetIm_nBlockK =
2107 192000 : static_cast<int>(dfYOff) % m_nBlockYSize;
2108 : // CPLAssert(
2109 : // nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
2110 : // nUsedBlockHeight);
2111 192000 : pabyLocalSrcData =
2112 : pabyLocalSrcDataK0 +
2113 192000 : (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
2114 192000 : m_nBlockXSize * nBandsPerBlockDTSize;
2115 192000 : dfYOff += dfSrcYInc;
2116 : }
2117 :
2118 423713 : if (bByteOnly)
2119 : {
2120 : REACHED(41);
2121 2118560 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2122 : {
2123 1694850 : GByte *pabyLocalDataBand =
2124 1694850 : pabyLocalData + iBand * nBandSpace;
2125 1694850 : const GByte *pabyLocalSrcDataBand =
2126 1694850 : pabyLocalSrcData + (panBandMap[iBand] - 1);
2127 1694850 : *pabyLocalDataBand = *pabyLocalSrcDataBand;
2128 : }
2129 : }
2130 : else
2131 : {
2132 : REACHED(42);
2133 0 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2134 : {
2135 0 : GByte *pabyLocalDataBand =
2136 0 : pabyLocalData + iBand * nBandSpace;
2137 0 : const GByte *pabyLocalSrcDataBand =
2138 : pabyLocalSrcData +
2139 0 : (panBandMap[iBand] - 1) * nDTSize;
2140 :
2141 0 : GDALCopyWords(pabyLocalSrcDataBand, eDataType,
2142 : 0, pabyLocalDataBand, eBufType, 0,
2143 : 1);
2144 : }
2145 : }
2146 : }
2147 : }
2148 : }
2149 :
2150 99 : y += ychunk;
2151 : }
2152 : }
2153 : // cppcheck-suppress knownConditionTrueFalse
2154 228 : else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
2155 : // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
2156 : {
2157 452 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2158 : {
2159 228 : GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
2160 228 : const int nBand = panBandMap[iBand];
2161 : auto poCurBand =
2162 228 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
2163 228 : int anSrcYOffset[256] = {0};
2164 1392 : for (int y = 0; y < nBufYSize;)
2165 : {
2166 1168 : const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
2167 1168 : const int nSrcLine = static_cast<int>(dfYOffStart);
2168 1168 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2169 1168 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2170 1168 : const int nBaseByteOffsetIm_nBlock =
2171 1168 : nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
2172 1168 : int ychunk = 1;
2173 1168 : int nLastSrcLineK = nSrcLine;
2174 1168 : anSrcYOffset[0] = 0;
2175 125300 : for (int k = 1; k < nBufYSize - y; ++k)
2176 : {
2177 125072 : const int nSrcLineK =
2178 125072 : nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
2179 125072 : const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
2180 125072 : if (k < 256)
2181 80072 : anSrcYOffset[k] =
2182 80072 : ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
2183 80072 : m_nBlockXSize * nBandsPerBlockDTSize;
2184 125072 : if (nBlockYOffK != m_nBlockYOff)
2185 : {
2186 940 : break;
2187 : }
2188 124132 : ++ychunk;
2189 124132 : nLastSrcLineK = nSrcLineK;
2190 : }
2191 1168 : const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
2192 : // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2193 :
2194 1168 : double dfSrcX = nXOff + 0.5 * dfSrcXInc;
2195 1168 : int nCurBlockXOff = 0;
2196 1168 : int nNextBlockXOff = 0;
2197 1168 : toff_t nCurOffset = 0;
2198 1168 : const GByte *pabyLocalSrcDataStartLine = nullptr;
2199 138796 : for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
2200 : {
2201 137632 : int nSrcPixel = static_cast<int>(dfSrcX);
2202 137632 : if (nSrcPixel >= nNextBlockXOff)
2203 : {
2204 3424 : const int nBlockXOff = nSrcPixel / m_nBlockXSize;
2205 3424 : nCurBlockXOff = nBlockXOff * m_nBlockXSize;
2206 3424 : nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
2207 : const int nBlockId =
2208 3424 : poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2209 3424 : nCurOffset = panOffsets[nBlockId];
2210 3424 : if (nCurOffset != 0)
2211 : {
2212 5392 : pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
2213 2696 : nCurOffset + nBaseByteOffsetIm_nBlock,
2214 2696 : m_nBlockXSize * nBandsPerBlock *
2215 : nUsedBlockHeight,
2216 : nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2217 2696 : if (pabyLocalSrcDataStartLine == nullptr)
2218 4 : return CE_Failure;
2219 :
2220 2692 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
2221 : {
2222 : REACHED(45);
2223 72 : pabyLocalSrcDataStartLine +=
2224 72 : (nBand - 1) * nDTSize;
2225 : }
2226 : else
2227 : {
2228 : REACHED(46);
2229 : }
2230 : }
2231 : }
2232 :
2233 137628 : if (nCurOffset == 0)
2234 : {
2235 : REACHED(47);
2236 :
2237 2215820 : for (int k = 0; k < ychunk; ++k)
2238 : {
2239 2185310 : GByte *const pabyLocalData = pabyData +
2240 2185310 : (y + k) * nLineSpace +
2241 2185310 : x * nPixelSpace;
2242 :
2243 2185310 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2244 : pabyLocalData, eBufType, 0, 1);
2245 : }
2246 : }
2247 : else
2248 : {
2249 107116 : const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
2250 107116 : double dfYOff = dfYOffStart;
2251 107116 : const GByte *const pabyLocalSrcDataK0 =
2252 : pabyLocalSrcDataStartLine +
2253 107116 : nXOffsetInBlock * nBandsPerBlockDTSize;
2254 107116 : GByte *pabyLocalData =
2255 107116 : pabyData + y * nLineSpace + x * nPixelSpace;
2256 7952300 : for (int k = 0; k < ychunk;
2257 7845180 : ++k, pabyLocalData += nLineSpace)
2258 : {
2259 7845180 : const GByte *pabyLocalSrcData = nullptr;
2260 7845180 : if (ychunk <= 256)
2261 : {
2262 : REACHED(48);
2263 4773180 : pabyLocalSrcData =
2264 4773180 : pabyLocalSrcDataK0 + anSrcYOffset[k];
2265 : }
2266 : else
2267 : {
2268 : REACHED(49);
2269 3072000 : const int nYOffsetIm_nBlockK =
2270 3072000 : static_cast<int>(dfYOff) % m_nBlockYSize;
2271 : // CPLAssert(
2272 : // nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
2273 : // nUsedBlockHeight);
2274 3072000 : pabyLocalSrcData =
2275 : pabyLocalSrcDataK0 +
2276 3072000 : (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
2277 3072000 : m_nBlockXSize * nBandsPerBlockDTSize;
2278 3072000 : dfYOff += dfSrcYInc;
2279 : }
2280 :
2281 7845180 : if (bByteOnly)
2282 : {
2283 : REACHED(50);
2284 :
2285 2121160 : *pabyLocalData = *pabyLocalSrcData;
2286 : }
2287 : else
2288 : {
2289 : REACHED(51);
2290 :
2291 5724020 : GDALCopyWords(pabyLocalSrcData, eDataType, 0,
2292 : pabyLocalData, eBufType, 0, 1);
2293 : }
2294 : }
2295 : }
2296 : }
2297 :
2298 1164 : y += ychunk;
2299 : }
2300 : }
2301 : }
2302 971 : else if (bUseContigImplementation)
2303 : {
2304 : // cppcheck-suppress knownConditionTrueFalse
2305 72 : if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
2306 : {
2307 37 : GByte *pabyData = static_cast<GByte *>(pData);
2308 2777 : for (int y = 0; y < nBufYSize; ++y)
2309 : {
2310 2742 : const int nSrcLine =
2311 2742 : nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
2312 2742 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2313 2742 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2314 2742 : const int nBaseByteOffsetIm_nBlock =
2315 2742 : nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
2316 :
2317 2742 : if (bNoXResampling)
2318 : {
2319 2535 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2320 2535 : int nBlockXOff = nXOff / m_nBlockXSize;
2321 2535 : int nXOffsetInBlock = nXOff % m_nBlockXSize;
2322 : int nBlockId =
2323 2535 : poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2324 :
2325 2535 : int x = 0;
2326 12372 : while (x < nBufXSize)
2327 : {
2328 9838 : const int nByteOffsetIm_nBlock =
2329 : nBaseByteOffsetIm_nBlock +
2330 9838 : nXOffsetInBlock * nBandsPerBlockDTSize;
2331 9838 : const toff_t nCurOffset = panOffsets[nBlockId];
2332 9838 : const int nUsedBlockWidth = std::min(
2333 9838 : m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
2334 :
2335 9838 : int nIters = nUsedBlockWidth;
2336 9838 : if (nCurOffset == 0)
2337 : {
2338 3768 : if (bByteNoXResampling)
2339 : {
2340 : REACHED(0);
2341 46560 : while (nIters-- > 0)
2342 : {
2343 217886 : for (int iBand = 0; iBand < nBandCount;
2344 : ++iBand)
2345 : {
2346 172964 : pabyLocalData[iBand] = abyNoData;
2347 : }
2348 44922 : pabyLocalData += nPixelSpace;
2349 : }
2350 : }
2351 : else
2352 : {
2353 : REACHED(1);
2354 60500 : while (nIters-- > 0)
2355 : {
2356 58370 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2357 : pabyLocalData, eBufType,
2358 : static_cast<int>(nBandSpace),
2359 : nBandCount);
2360 58370 : pabyLocalData += nPixelSpace;
2361 : }
2362 : }
2363 : }
2364 : else
2365 : {
2366 6070 : if (bNoTypeChange && nBands == nBandCount &&
2367 4612 : nPixelSpace == nBandsPerBlockDTSize)
2368 : {
2369 : REACHED(2);
2370 3397 : if (!oFetcher.FetchBytes(
2371 : pabyLocalData,
2372 3397 : nCurOffset + nByteOffsetIm_nBlock,
2373 : nIters * nBandsPerBlock, nDTSize,
2374 : bIsByteSwapped, bIsComplex, nBlockId))
2375 : {
2376 1 : return CE_Failure;
2377 : }
2378 3396 : pabyLocalData +=
2379 3396 : nIters * nBandsPerBlock * nDTSize;
2380 : }
2381 : else
2382 : {
2383 5346 : const GByte *pabyLocalSrcData =
2384 : oFetcher.FetchBytes(
2385 2673 : nCurOffset + nByteOffsetIm_nBlock,
2386 : nIters * nBandsPerBlock, nDTSize,
2387 : bIsByteSwapped, bIsComplex, nBlockId);
2388 2673 : if (pabyLocalSrcData == nullptr)
2389 0 : return CE_Failure;
2390 2673 : if (bByteNoXResampling)
2391 : {
2392 : REACHED(3);
2393 1944 : CopyContigByteMultiBand(
2394 : pabyLocalSrcData, nBandsPerBlockDTSize,
2395 : pabyLocalData,
2396 : static_cast<int>(nPixelSpace), nIters,
2397 : nBandCount);
2398 1944 : pabyLocalData += nIters * nPixelSpace;
2399 : }
2400 : else
2401 : {
2402 : REACHED(4);
2403 20412 : while (nIters-- > 0)
2404 : {
2405 19683 : GDALCopyWords(
2406 : pabyLocalSrcData, eDataType,
2407 : nDTSize, pabyLocalData, eBufType,
2408 : static_cast<int>(nBandSpace),
2409 : nBandCount);
2410 19683 : pabyLocalSrcData +=
2411 19683 : nBandsPerBlockDTSize;
2412 19683 : pabyLocalData += nPixelSpace;
2413 : }
2414 : }
2415 : }
2416 : }
2417 :
2418 9837 : nXOffsetInBlock = 0;
2419 9837 : ++nBlockXOff;
2420 9837 : ++nBlockId;
2421 9837 : x += nUsedBlockWidth;
2422 : }
2423 : }
2424 : else // Contig, tiled, potential resampling & data type change.
2425 : {
2426 207 : const GByte *pabyLocalSrcDataStartLine = nullptr;
2427 207 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2428 207 : double dfSrcX = nXOff + 0.5 * dfSrcXInc;
2429 207 : int nCurBlockXOff = 0;
2430 207 : int nNextBlockXOff = 0;
2431 207 : toff_t nCurOffset = 0;
2432 8373 : for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
2433 : {
2434 8167 : int nSrcPixel = static_cast<int>(dfSrcX);
2435 8167 : if (nSrcPixel >= nNextBlockXOff)
2436 : {
2437 611 : const int nBlockXOff = nSrcPixel / m_nBlockXSize;
2438 611 : nCurBlockXOff = nBlockXOff * m_nBlockXSize;
2439 611 : nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
2440 611 : const int nBlockId = poFirstBand->ComputeBlockId(
2441 : nBlockXOff, m_nBlockYOff);
2442 611 : nCurOffset = panOffsets[nBlockId];
2443 611 : if (nCurOffset != 0)
2444 : {
2445 726 : pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
2446 363 : nCurOffset + nBaseByteOffsetIm_nBlock,
2447 363 : m_nBlockXSize * nBandsPerBlock, nDTSize,
2448 : bIsByteSwapped, bIsComplex, nBlockId);
2449 363 : if (pabyLocalSrcDataStartLine == nullptr)
2450 1 : return CE_Failure;
2451 : }
2452 : }
2453 8166 : const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
2454 :
2455 8166 : if (nCurOffset == 0)
2456 : {
2457 : REACHED(5);
2458 3364 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2459 : pabyLocalData, eBufType,
2460 : static_cast<int>(nBandSpace),
2461 : nBandCount);
2462 3364 : pabyLocalData += nPixelSpace;
2463 : }
2464 : else
2465 : {
2466 4802 : const GByte *pabyLocalSrcData =
2467 : pabyLocalSrcDataStartLine +
2468 4802 : nXOffsetInBlock * nBandsPerBlockDTSize;
2469 :
2470 : REACHED(6);
2471 4802 : if (bByteOnly)
2472 : {
2473 20809 : for (int iBand = 0; iBand < nBands; ++iBand)
2474 16007 : pabyLocalData[iBand] =
2475 16007 : pabyLocalSrcData[iBand];
2476 : }
2477 : else
2478 : {
2479 0 : GDALCopyWords(pabyLocalSrcData, eDataType,
2480 : nDTSize, pabyLocalData, eBufType,
2481 : static_cast<int>(nBandSpace),
2482 : nBandCount);
2483 : }
2484 4802 : pabyLocalData += nPixelSpace;
2485 : }
2486 : }
2487 : }
2488 : }
2489 : }
2490 : else // Contig, striped organized.
2491 : {
2492 35 : GByte *pabyData = static_cast<GByte *>(pData);
2493 2618 : for (int y = 0; y < nBufYSize; ++y)
2494 : {
2495 2585 : const int nSrcLine =
2496 2585 : nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
2497 2585 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2498 2585 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2499 2585 : const int nBlockId = m_nBlockYOff;
2500 2585 : const toff_t nCurOffset = panOffsets[nBlockId];
2501 2585 : if (nCurOffset == 0)
2502 : {
2503 : REACHED(7);
2504 107696 : for (int x = 0; x < nBufXSize; ++x)
2505 : {
2506 106656 : GDALCopyWords(
2507 : &dfNoData, GDT_Float64, 0,
2508 106656 : pabyData + y * nLineSpace + x * nPixelSpace,
2509 : eBufType, static_cast<int>(nBandSpace), nBandCount);
2510 : }
2511 : }
2512 : else
2513 : {
2514 1545 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2515 1545 : const int nBaseByteOffsetIm_nBlock =
2516 1545 : (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
2517 : nBandsPerBlockDTSize;
2518 :
2519 1545 : if (bNoXResamplingNoTypeChange && nBands == nBandCount &&
2520 936 : nPixelSpace == nBandsPerBlockDTSize)
2521 : {
2522 : REACHED(8);
2523 693 : if (!oFetcher.FetchBytes(
2524 : pabyLocalData,
2525 693 : nCurOffset + nBaseByteOffsetIm_nBlock,
2526 : nXSize * nBandsPerBlock, nDTSize,
2527 : bIsByteSwapped, bIsComplex, nBlockId))
2528 : {
2529 1 : return CE_Failure;
2530 : }
2531 : }
2532 : else
2533 : {
2534 1704 : const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
2535 852 : nCurOffset + nBaseByteOffsetIm_nBlock,
2536 : nXSize * nBandsPerBlock, nDTSize, bIsByteSwapped,
2537 : bIsComplex, nBlockId);
2538 852 : if (pabyLocalSrcData == nullptr)
2539 1 : return CE_Failure;
2540 :
2541 851 : if (bByteNoXResampling)
2542 : {
2543 : REACHED(9);
2544 486 : CopyContigByteMultiBand(
2545 : pabyLocalSrcData, nBandsPerBlockDTSize,
2546 : pabyLocalData, static_cast<int>(nPixelSpace),
2547 : nBufXSize, nBandCount);
2548 : }
2549 365 : else if (bByteOnly)
2550 : {
2551 : REACHED(10);
2552 122 : double dfSrcX = 0.5 * dfSrcXInc;
2553 4924 : for (int x = 0; x < nBufXSize;
2554 : ++x, dfSrcX += dfSrcXInc)
2555 : {
2556 4802 : const int nSrcPixelMinusXOff =
2557 : static_cast<int>(dfSrcX);
2558 24010 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2559 : {
2560 19208 : pabyLocalData[x * nPixelSpace + iBand] =
2561 : pabyLocalSrcData
2562 19208 : [nSrcPixelMinusXOff *
2563 19208 : nBandsPerBlockDTSize +
2564 : iBand];
2565 : }
2566 : }
2567 : }
2568 : else
2569 : {
2570 : REACHED(11);
2571 243 : double dfSrcX = 0.5 * dfSrcXInc;
2572 19926 : for (int x = 0; x < nBufXSize;
2573 : ++x, dfSrcX += dfSrcXInc)
2574 : {
2575 19683 : int nSrcPixelMinusXOff =
2576 : static_cast<int>(dfSrcX);
2577 19683 : GDALCopyWords(
2578 19683 : pabyLocalSrcData + nSrcPixelMinusXOff *
2579 : nBandsPerBlockDTSize,
2580 : eDataType, nDTSize,
2581 19683 : pabyLocalData + x * nPixelSpace, eBufType,
2582 : static_cast<int>(nBandSpace), nBandCount);
2583 : }
2584 : }
2585 : }
2586 : }
2587 : }
2588 : }
2589 : }
2590 : else // Non-contig reading case.
2591 : {
2592 : // cppcheck-suppress knownConditionTrueFalse
2593 899 : if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
2594 : {
2595 1455 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2596 : {
2597 1059 : const int nBand = panBandMap[iBand];
2598 : auto poCurBand =
2599 1059 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
2600 1059 : GByte *const pabyData =
2601 1059 : static_cast<GByte *>(pData) + iBand * nBandSpace;
2602 284551 : for (int y = 0; y < nBufYSize; ++y)
2603 : {
2604 283506 : const int nSrcLine =
2605 283506 : nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
2606 283506 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2607 283506 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2608 :
2609 283506 : int nBaseByteOffsetIm_nBlock = nYOffsetIm_nBlock *
2610 283506 : m_nBlockXSize *
2611 : nBandsPerBlockDTSize;
2612 283506 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
2613 : {
2614 : REACHED(12);
2615 66004 : nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
2616 : }
2617 : else
2618 : {
2619 : REACHED(13);
2620 : }
2621 :
2622 283506 : if (bNoXResampling)
2623 : {
2624 67404 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2625 67404 : int nBlockXOff = nXOff / m_nBlockXSize;
2626 : int nBlockId =
2627 67404 : poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2628 67404 : int nXOffsetInBlock = nXOff % m_nBlockXSize;
2629 :
2630 67404 : int x = 0;
2631 331986 : while (x < nBufXSize)
2632 : {
2633 264592 : const int nByteOffsetIm_nBlock =
2634 : nBaseByteOffsetIm_nBlock +
2635 264592 : nXOffsetInBlock * nBandsPerBlockDTSize;
2636 264592 : const toff_t nCurOffset = panOffsets[nBlockId];
2637 264592 : const int nUsedBlockWidth = std::min(
2638 264592 : m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
2639 264592 : int nIters = nUsedBlockWidth;
2640 :
2641 264592 : if (nCurOffset == 0)
2642 : {
2643 : REACHED(16);
2644 52038 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2645 : pabyLocalData, eBufType,
2646 : static_cast<int>(nPixelSpace),
2647 : nIters);
2648 52038 : pabyLocalData += nIters * nPixelSpace;
2649 : }
2650 : else
2651 : {
2652 212554 : if (bNoTypeChange &&
2653 177871 : nPixelSpace == nBandsPerBlockDTSize)
2654 : {
2655 : REACHED(17);
2656 84112 : if (!oFetcher.FetchBytes(
2657 : pabyLocalData,
2658 84112 : nCurOffset + nByteOffsetIm_nBlock,
2659 84112 : (nIters - 1) * nBandsPerBlock + 1,
2660 : nDTSize, bIsByteSwapped, bIsComplex,
2661 : nBlockId))
2662 : {
2663 4 : return CE_Failure;
2664 : }
2665 84108 : pabyLocalData += nIters * nPixelSpace;
2666 : }
2667 : else
2668 : {
2669 256884 : const GByte *pabyLocalSrcData =
2670 : oFetcher.FetchBytes(
2671 128442 : nCurOffset + nByteOffsetIm_nBlock,
2672 128442 : (nIters - 1) * nBandsPerBlock + 1,
2673 : nDTSize, bIsByteSwapped, bIsComplex,
2674 : nBlockId);
2675 128442 : if (pabyLocalSrcData == nullptr)
2676 6 : return CE_Failure;
2677 :
2678 : REACHED(18);
2679 128436 : GDALCopyWords(pabyLocalSrcData, eDataType,
2680 : nBandsPerBlockDTSize,
2681 : pabyLocalData, eBufType,
2682 : static_cast<int>(nPixelSpace),
2683 : nIters);
2684 128436 : pabyLocalData += nIters * nPixelSpace;
2685 : }
2686 : }
2687 :
2688 264582 : nXOffsetInBlock = 0;
2689 264582 : ++nBlockXOff;
2690 264582 : ++nBlockId;
2691 264582 : x += nUsedBlockWidth;
2692 : }
2693 : }
2694 : else
2695 : {
2696 : // Non-contig reading, tiled, potential resampling and
2697 : // data type change.
2698 :
2699 216102 : const GByte *pabyLocalSrcDataStartLine = nullptr;
2700 216102 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2701 216102 : double dfSrcX = nXOff + 0.5 * dfSrcXInc;
2702 216102 : int nCurBlockXOff = 0;
2703 216102 : int nNextBlockXOff = 0;
2704 216102 : toff_t nCurOffset = 0;
2705 16883500 : for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
2706 : {
2707 16667400 : const int nSrcPixel = static_cast<int>(dfSrcX);
2708 16667400 : if (nSrcPixel >= nNextBlockXOff)
2709 : {
2710 648202 : const int nBlockXOff =
2711 648202 : nSrcPixel / m_nBlockXSize;
2712 648202 : nCurBlockXOff = nBlockXOff * m_nBlockXSize;
2713 648202 : nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
2714 648202 : const int nBlockId = poCurBand->ComputeBlockId(
2715 : nBlockXOff, m_nBlockYOff);
2716 648202 : nCurOffset = panOffsets[nBlockId];
2717 648202 : if (nCurOffset != 0)
2718 : {
2719 998236 : pabyLocalSrcDataStartLine =
2720 : oFetcher.FetchBytes(
2721 499118 : nCurOffset +
2722 499118 : nBaseByteOffsetIm_nBlock,
2723 499118 : m_nBlockXSize * nBandsPerBlock,
2724 : nDTSize, bIsByteSwapped, bIsComplex,
2725 : nBlockId);
2726 499118 : if (pabyLocalSrcDataStartLine == nullptr)
2727 4 : return CE_Failure;
2728 : }
2729 : }
2730 16667400 : const int nXOffsetInBlock =
2731 : nSrcPixel - nCurBlockXOff;
2732 :
2733 16667400 : if (nCurOffset == 0)
2734 : {
2735 : REACHED(21);
2736 3920100 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2737 : pabyLocalData, eBufType, 0, 1);
2738 3920100 : pabyLocalData += nPixelSpace;
2739 : }
2740 : else
2741 : {
2742 12747300 : const GByte *pabyLocalSrcData =
2743 : pabyLocalSrcDataStartLine +
2744 12747300 : nXOffsetInBlock * nBandsPerBlockDTSize;
2745 :
2746 : REACHED(22);
2747 12747300 : if (bByteOnly)
2748 : {
2749 5192440 : *pabyLocalData = *pabyLocalSrcData;
2750 : }
2751 : else
2752 : {
2753 7554900 : GDALCopyWords(pabyLocalSrcData, eDataType,
2754 : 0, pabyLocalData, eBufType, 0,
2755 : 1);
2756 : }
2757 12747300 : pabyLocalData += nPixelSpace;
2758 : }
2759 : }
2760 : }
2761 : }
2762 : }
2763 : }
2764 : else // Non-contig reading, striped.
2765 : {
2766 1796 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2767 : {
2768 1324 : const int nBand = panBandMap[iBand];
2769 1324 : GByte *pabyData =
2770 1324 : static_cast<GByte *>(pData) + iBand * nBandSpace;
2771 356944 : for (int y = 0; y < nBufYSize; ++y)
2772 : {
2773 355637 : const int nSrcLine =
2774 355637 : nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
2775 355637 : const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2776 355637 : const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2777 355637 : int nBlockId = m_nBlockYOff;
2778 355637 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
2779 : {
2780 : REACHED(23);
2781 282397 : nBlockId += m_nBlocksPerBand * (nBand - 1);
2782 : }
2783 : else
2784 : {
2785 : REACHED(24);
2786 : }
2787 355637 : const toff_t nCurOffset = panOffsets[nBlockId];
2788 355637 : if (nCurOffset == 0)
2789 : {
2790 : REACHED(25);
2791 62846 : GDALCopyWords(&dfNoData, GDT_Float64, 0,
2792 62846 : pabyData + y * nLineSpace, eBufType,
2793 : static_cast<int>(nPixelSpace), nBufXSize);
2794 : }
2795 : else
2796 : {
2797 292791 : int nBaseByteOffsetIm_nBlock =
2798 292791 : (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
2799 : nBandsPerBlockDTSize;
2800 292791 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
2801 43815 : nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
2802 :
2803 292791 : GByte *pabyLocalData = pabyData + y * nLineSpace;
2804 292791 : if (bNoXResamplingNoTypeChange &&
2805 56217 : nPixelSpace == nBandsPerBlockDTSize)
2806 : {
2807 : REACHED(26);
2808 26844 : if (!oFetcher.FetchBytes(
2809 : pabyLocalData,
2810 26844 : nCurOffset + nBaseByteOffsetIm_nBlock,
2811 26844 : (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
2812 : bIsByteSwapped, bIsComplex, nBlockId))
2813 : {
2814 5 : return CE_Failure;
2815 : }
2816 : }
2817 : else
2818 : {
2819 531894 : const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
2820 265947 : nCurOffset + nBaseByteOffsetIm_nBlock,
2821 265947 : (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
2822 : bIsByteSwapped, bIsComplex, nBlockId);
2823 265947 : if (pabyLocalSrcData == nullptr)
2824 12 : return CE_Failure;
2825 :
2826 265935 : if (bNoXResamplingNoTypeChange)
2827 : {
2828 : REACHED(27);
2829 29366 : GDALCopyWords(pabyLocalSrcData, eDataType,
2830 : nBandsPerBlockDTSize,
2831 : pabyLocalData, eBufType,
2832 : static_cast<int>(nPixelSpace),
2833 : nBufXSize);
2834 : }
2835 236569 : else if (bByteOnly)
2836 : {
2837 : REACHED(28);
2838 73619 : double dfSrcX = 0.5 * dfSrcXInc;
2839 5778430 : for (int x = 0; x < nBufXSize;
2840 : ++x, dfSrcX += dfSrcXInc)
2841 : {
2842 5704810 : const int nSrcPixelMinusXOff =
2843 : static_cast<int>(dfSrcX);
2844 5704810 : pabyLocalData[x * nPixelSpace] =
2845 5704810 : pabyLocalSrcData[nSrcPixelMinusXOff *
2846 : nBandsPerBlockDTSize];
2847 : }
2848 : }
2849 : else
2850 : {
2851 : REACHED(29);
2852 162950 : double dfSrcX = 0.5 * dfSrcXInc;
2853 12817000 : for (int x = 0; x < nBufXSize;
2854 : ++x, dfSrcX += dfSrcXInc)
2855 : {
2856 12654100 : const int nSrcPixelMinusXOff =
2857 : static_cast<int>(dfSrcX);
2858 12654100 : GDALCopyWords(pabyLocalSrcData +
2859 12654100 : nSrcPixelMinusXOff *
2860 : nBandsPerBlockDTSize,
2861 : eDataType, 0,
2862 12654100 : pabyLocalData +
2863 12654100 : x * nPixelSpace,
2864 : eBufType, 0, 1);
2865 : }
2866 : }
2867 : }
2868 : }
2869 : }
2870 : }
2871 : }
2872 : }
2873 :
2874 1691 : return CE_None;
2875 : }
2876 :
2877 : /************************************************************************/
2878 : /* DirectIO() */
2879 : /************************************************************************/
2880 :
2881 771 : CPLErr GTiffDataset::CommonDirectIOClassic(
2882 : FetchBufferDirectIO &oFetcher, int nXOff, int nYOff, int nXSize, int nYSize,
2883 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2884 : int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2885 : GSpacing nLineSpace, GSpacing nBandSpace)
2886 : {
2887 771 : return CommonDirectIO<FetchBufferDirectIO>(
2888 : oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
2889 771 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace);
2890 : }
2891 :
2892 : /************************************************************************/
2893 : /* DirectIO() */
2894 : /************************************************************************/
2895 :
2896 : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
2897 : // block reading. Restricted to simple TIFF configurations
2898 : // (uncompressed data, standard data types). Particularly useful to extract
2899 : // sub-windows of data on a large /vsicurl dataset).
2900 : // Returns -1 if DirectIO() can't be supported on that file.
2901 :
2902 472 : int GTiffDataset::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
2903 : int nYSize, void *pData, int nBufXSize,
2904 : int nBufYSize, GDALDataType eBufType, int nBandCount,
2905 : const int *panBandMap, GSpacing nPixelSpace,
2906 : GSpacing nLineSpace, GSpacing nBandSpace,
2907 : GDALRasterIOExtraArg *psExtraArg)
2908 : {
2909 472 : auto poProtoBand = cpl::down_cast<GTiffRasterBand *>(papoBands[0]);
2910 472 : const GDALDataType eDataType = poProtoBand->GetRasterDataType();
2911 472 : const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
2912 944 : if (!(eRWFlag == GF_Read && m_nCompression == COMPRESSION_NONE &&
2913 472 : (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
2914 188 : m_nPhotometric == PHOTOMETRIC_RGB ||
2915 0 : m_nPhotometric == PHOTOMETRIC_PALETTE) &&
2916 472 : poProtoBand->IsBaseGTiffClass()))
2917 : {
2918 0 : return -1;
2919 : }
2920 472 : Crystalize();
2921 :
2922 : // Only know how to deal with nearest neighbour in this optimized routine.
2923 472 : if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
2924 182 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
2925 : {
2926 30 : return -1;
2927 : }
2928 :
2929 : // If the file is band interleave or only one band is requested, then
2930 : // fallback to band DirectIO.
2931 442 : bool bUseBandRasterIO = false;
2932 442 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1)
2933 : {
2934 324 : bUseBandRasterIO = true;
2935 : }
2936 : else
2937 : {
2938 : // For simplicity, only deals with "naturally ordered" bands.
2939 546 : for (int iBand = 0; iBand < nBandCount; ++iBand)
2940 : {
2941 436 : if (panBandMap[iBand] != iBand + 1)
2942 : {
2943 8 : bUseBandRasterIO = true;
2944 8 : break;
2945 : }
2946 : }
2947 : }
2948 442 : if (bUseBandRasterIO)
2949 : {
2950 332 : CPLErr eErr = CE_None;
2951 1628 : for (int iBand = 0; eErr == CE_None && iBand < nBandCount; ++iBand)
2952 : {
2953 : eErr =
2954 1296 : GetRasterBand(panBandMap[iBand])
2955 2592 : ->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2956 1296 : static_cast<GByte *>(pData) + iBand * nBandSpace,
2957 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
2958 : nLineSpace, psExtraArg);
2959 : }
2960 332 : return eErr;
2961 : }
2962 :
2963 : #if DEBUG_VERBOSE
2964 : CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
2965 : nYSize, nBufXSize, nBufYSize);
2966 : #endif
2967 :
2968 : // No need to look if overviews can satisfy the request as it has already */
2969 : // been done in GTiffDataset::IRasterIO().
2970 :
2971 : // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
2972 110 : if (eAccess == GA_Update)
2973 : {
2974 0 : FlushCache(false);
2975 0 : VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
2976 : }
2977 :
2978 110 : if (TIFFIsTiled(m_hTIFF))
2979 : {
2980 55 : const int nDTSize = nDTSizeBits / 8;
2981 55 : const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
2982 110 : static_cast<GPtrDiff_t>(m_nBlockXSize) * m_nBlockYSize * nDTSize *
2983 55 : ((m_nPlanarConfig == PLANARCONFIG_CONTIG) ? nBands : 1));
2984 55 : if (m_pTempBufferForCommonDirectIO == nullptr)
2985 : {
2986 0 : m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
2987 0 : VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
2988 0 : if (m_pTempBufferForCommonDirectIO == nullptr)
2989 0 : return CE_Failure;
2990 : }
2991 :
2992 55 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
2993 : FetchBufferDirectIO oFetcher(fp, m_pTempBufferForCommonDirectIO,
2994 55 : nTempBufferForCommonDirectIOSize);
2995 :
2996 55 : return CommonDirectIOClassic(oFetcher, nXOff, nYOff, nXSize, nYSize,
2997 : pData, nBufXSize, nBufYSize, eBufType,
2998 : nBandCount, panBandMap, nPixelSpace,
2999 55 : nLineSpace, nBandSpace);
3000 : }
3001 :
3002 : // Get strip offsets.
3003 55 : toff_t *panTIFFOffsets = nullptr;
3004 110 : if (!TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets) ||
3005 55 : panTIFFOffsets == nullptr)
3006 : {
3007 0 : return CE_Failure;
3008 : }
3009 :
3010 : // Sub-sampling or over-sampling can only be done at last stage.
3011 55 : int nReqXSize = nXSize;
3012 : // Can do sub-sampling at the extraction stage.
3013 55 : const int nReqYSize = std::min(nBufYSize, nYSize);
3014 : void **ppData =
3015 55 : static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
3016 : vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
3017 55 : VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
3018 : size_t *panSizes =
3019 55 : static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
3020 55 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
3021 55 : void *pTmpBuffer = nullptr;
3022 55 : int eErr = CE_None;
3023 55 : int nContigBands = nBands;
3024 55 : const int nSrcPixelSize = nDTSize * nContigBands;
3025 :
3026 55 : if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
3027 : {
3028 0 : eErr = CE_Failure;
3029 : }
3030 : // For now we always allocate a temp buffer as it is easier.
3031 : else
3032 : // if( nXSize != nBufXSize || nYSize != nBufYSize ||
3033 : // eBufType != eDataType ||
3034 : // nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
3035 : // check if the user buffer is large enough )
3036 : {
3037 : // We need a temporary buffer for over-sampling/sub-sampling
3038 : // and/or data type conversion.
3039 55 : pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
3040 55 : if (pTmpBuffer == nullptr)
3041 0 : eErr = CE_Failure;
3042 : }
3043 :
3044 : // Prepare data extraction.
3045 55 : const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
3046 :
3047 2312 : for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
3048 : {
3049 2257 : ppData[iLine] = static_cast<GByte *>(pTmpBuffer) +
3050 2257 : static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
3051 2257 : int nSrcLine = 0;
3052 2257 : if (nBufYSize < nYSize) // Sub-sampling in y.
3053 164 : nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
3054 : else
3055 2093 : nSrcLine = nYOff + iLine;
3056 :
3057 2257 : const int nBlockXOff = 0;
3058 2257 : const int nBlockYOff = nSrcLine / m_nBlockYSize;
3059 2257 : const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
3060 : const int nBlockId =
3061 2257 : poProtoBand->ComputeBlockId(nBlockXOff, nBlockYOff);
3062 :
3063 2257 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
3064 2257 : if (panOffsets[iLine] == 0) // We don't support sparse files.
3065 27 : eErr = -1;
3066 :
3067 2257 : panOffsets[iLine] +=
3068 2257 : (nXOff +
3069 2257 : static_cast<vsi_l_offset>(nYOffsetInBlock) * m_nBlockXSize) *
3070 2257 : nSrcPixelSize;
3071 2257 : panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
3072 : }
3073 :
3074 : // Extract data from the file.
3075 55 : if (eErr == CE_None)
3076 : {
3077 28 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
3078 : const int nRet =
3079 28 : VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
3080 28 : if (nRet != 0)
3081 3 : eErr = CE_Failure;
3082 : }
3083 :
3084 : // Byte-swap if necessary.
3085 55 : if (eErr == CE_None && TIFFIsByteSwapped(m_hTIFF))
3086 : {
3087 0 : for (int iLine = 0; iLine < nReqYSize; ++iLine)
3088 : {
3089 0 : if (GDALDataTypeIsComplex(eDataType))
3090 0 : GDALSwapWords(ppData[iLine], nDTSize / 2,
3091 0 : 2 * nReqXSize * nContigBands, nDTSize / 2);
3092 : else
3093 0 : GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
3094 : nDTSize);
3095 : }
3096 : }
3097 :
3098 : // Over-sampling/sub-sampling and/or data type conversion.
3099 55 : const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
3100 55 : if (eErr == CE_None && pTmpBuffer != nullptr)
3101 : {
3102 7462 : for (int iY = 0; iY < nBufYSize; ++iY)
3103 : {
3104 14874 : const int iSrcY = nBufYSize <= nYSize
3105 7437 : ? iY
3106 5832 : : static_cast<int>((iY + 0.5) * dfSrcYInc);
3107 : // Optimization: no resampling, no data type change, number of
3108 : // bands requested == number of bands and buffer is packed
3109 : // pixel-interleaved.
3110 7437 : if (nBufXSize == nXSize && nContigBands == nBandCount &&
3111 786 : eDataType == eBufType && nBandSpace == nDTSize &&
3112 474 : nPixelSpace == nBandCount * nBandSpace)
3113 : {
3114 312 : memcpy(static_cast<GByte *>(pData) + iY * nLineSpace,
3115 312 : ppData[iSrcY],
3116 312 : static_cast<size_t>(nReqXSize * nPixelSpace));
3117 : }
3118 : // Other optimization: no resampling, no data type change,
3119 : // data type is Byte/Int8.
3120 7125 : else if (nBufXSize == nXSize && eDataType == eBufType &&
3121 0 : (eDataType == GDT_UInt8 || eDataType == GDT_Int8))
3122 : {
3123 808 : GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]);
3124 808 : GByte *pabyDstData =
3125 808 : static_cast<GByte *>(pData) + iY * nLineSpace;
3126 808 : if (nBandSpace == 1 && nPixelSpace > nBandCount)
3127 : {
3128 : // Buffer is pixel-interleaved (with some stridding
3129 : // between pixels).
3130 324 : CopyContigByteMultiBand(
3131 : pabySrcData, nSrcPixelSize, pabyDstData,
3132 : static_cast<int>(nPixelSpace), nBufXSize, nBandCount);
3133 : }
3134 : else
3135 : {
3136 2248 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3137 : {
3138 1764 : GDALCopyWords(
3139 1764 : pabySrcData + iBand, GDT_UInt8, nSrcPixelSize,
3140 1764 : pabyDstData + iBand * nBandSpace, GDT_UInt8,
3141 : static_cast<int>(nPixelSpace), nBufXSize);
3142 : }
3143 808 : }
3144 : }
3145 : else // General case.
3146 : {
3147 31585 : for (int iBand = 0; iBand < nBandCount; ++iBand)
3148 : {
3149 25268 : GByte *pabySrcData =
3150 25268 : static_cast<GByte *>(ppData[iSrcY]) + iBand * nDTSize;
3151 25268 : GByte *pabyDstData = static_cast<GByte *>(pData) +
3152 25268 : iBand * nBandSpace + iY * nLineSpace;
3153 25268 : if ((eDataType == GDT_UInt8 && eBufType == GDT_UInt8) ||
3154 0 : (eDataType == GDT_Int8 && eBufType == GDT_Int8))
3155 : {
3156 23972 : double dfSrcX = 0.5 * dfSrcXInc;
3157 1718820 : for (int iX = 0; iX < nBufXSize;
3158 1694850 : ++iX, dfSrcX += dfSrcXInc)
3159 : {
3160 1694850 : int iSrcX = static_cast<int>(dfSrcX);
3161 1694850 : pabyDstData[iX * nPixelSpace] =
3162 1694850 : pabySrcData[iSrcX * nSrcPixelSize];
3163 23972 : }
3164 : }
3165 : else
3166 : {
3167 1296 : double dfSrcX = 0.5 * dfSrcXInc;
3168 106272 : for (int iX = 0; iX < nBufXSize;
3169 104976 : ++iX, dfSrcX += dfSrcXInc)
3170 : {
3171 104976 : int iSrcX = static_cast<int>(dfSrcX);
3172 104976 : GDALCopyWords(pabySrcData + iSrcX * nSrcPixelSize,
3173 : eDataType, 0,
3174 104976 : pabyDstData + iX * nPixelSpace,
3175 : eBufType, 0, 1);
3176 : }
3177 : }
3178 : }
3179 : }
3180 : }
3181 : }
3182 :
3183 55 : CPLFree(pTmpBuffer);
3184 55 : CPLFree(ppData);
3185 55 : CPLFree(panOffsets);
3186 55 : CPLFree(panSizes);
3187 :
3188 55 : return eErr;
3189 : }
3190 :
3191 : /************************************************************************/
3192 : /* ReadStrile() */
3193 : /************************************************************************/
3194 :
3195 2131080 : bool GTiffDataset::ReadStrile(int nBlockId, void *pOutputBuffer,
3196 : GPtrDiff_t nBlockReqSize)
3197 : {
3198 : // Optimization by which we can save some libtiff buffer copy
3199 2131080 : std::pair<vsi_l_offset, vsi_l_offset> oPair;
3200 2131080 : if (
3201 : #if TIFFLIB_VERSION <= 20220520 && !defined(INTERNAL_LIBTIFF)
3202 : // There's a bug, up to libtiff 4.4.0, in TIFFReadFromUserBuffer()
3203 : // which clears the TIFF_CODERSETUP flag of tif->tif_flags, which
3204 : // causes the codec SetupDecode method to be called for each strile,
3205 : // whereas it should normally be called only for the first decoded one.
3206 : // For JPEG, that causes TIFFjpeg_read_header() to be called. Most
3207 : // of the time, that works. But for some files, at some point, the
3208 : // libjpeg machinery is not in the appropriate state for that.
3209 : m_nCompression != COMPRESSION_JPEG &&
3210 : #endif
3211 2131080 : m_oCacheStrileToOffsetByteCount.tryGet(nBlockId, oPair))
3212 : {
3213 : // For the mask, use the parent TIFF handle to get cached ranges
3214 333 : auto th = TIFFClientdata(m_poImageryDS && m_bMaskInterleavedWithImagery
3215 93 : ? m_poImageryDS->m_hTIFF
3216 : : m_hTIFF);
3217 480 : void *pInputBuffer = VSI_TIFFGetCachedRange(
3218 240 : th, oPair.first, static_cast<size_t>(oPair.second));
3219 480 : if (pInputBuffer &&
3220 240 : TIFFReadFromUserBuffer(m_hTIFF, nBlockId, pInputBuffer,
3221 240 : static_cast<size_t>(oPair.second),
3222 : pOutputBuffer, nBlockReqSize))
3223 : {
3224 240 : return true;
3225 : }
3226 : }
3227 :
3228 : // For debugging
3229 2130840 : if (m_poBaseDS)
3230 3532 : m_poBaseDS->m_bHasUsedReadEncodedAPI = true;
3231 : else
3232 2127310 : m_bHasUsedReadEncodedAPI = true;
3233 :
3234 : #if 0
3235 : // Can be useful to test TIFFReadFromUserBuffer() for local files
3236 : VSILFILE* fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata( m_hTIFF ));
3237 : std::vector<GByte> tmp(TIFFGetStrileByteCount(m_hTIFF, nBlockId));
3238 : VSIFSeekL(fpTIF, TIFFGetStrileOffset(m_hTIFF, nBlockId), SEEK_SET);
3239 : VSIFReadL(&tmp[0], 1, TIFFGetStrileByteCount(m_hTIFF, nBlockId), fpTIF);
3240 : if( !TIFFReadFromUserBuffer( m_hTIFF, nBlockId,
3241 : &tmp[0], tmp.size(),
3242 : pOutputBuffer, nBlockReqSize ) )
3243 : {
3244 : return false;
3245 : }
3246 : #else
3247 : // Set to 1 to allow GTiffErrorHandler to implement limitation on error
3248 : // messages
3249 2130840 : GTIFFGetThreadLocalLibtiffError() = 1;
3250 2130840 : if (TIFFIsTiled(m_hTIFF))
3251 : {
3252 30325 : if (TIFFReadEncodedTile(m_hTIFF, nBlockId, pOutputBuffer,
3253 30359 : nBlockReqSize) == -1 &&
3254 34 : !m_bIgnoreReadErrors)
3255 : {
3256 34 : CPLError(CE_Failure, CPLE_AppDefined,
3257 : "TIFFReadEncodedTile() failed.");
3258 34 : GTIFFGetThreadLocalLibtiffError() = 0;
3259 34 : return false;
3260 : }
3261 : }
3262 : else
3263 : {
3264 2100520 : if (TIFFReadEncodedStrip(m_hTIFF, nBlockId, pOutputBuffer,
3265 2100600 : nBlockReqSize) == -1 &&
3266 76 : !m_bIgnoreReadErrors)
3267 : {
3268 75 : CPLError(CE_Failure, CPLE_AppDefined,
3269 : "TIFFReadEncodedStrip() failed.");
3270 75 : GTIFFGetThreadLocalLibtiffError() = 0;
3271 75 : return false;
3272 : }
3273 : }
3274 2130740 : GTIFFGetThreadLocalLibtiffError() = 0;
3275 : #endif
3276 2130740 : return true;
3277 : }
3278 :
3279 : /************************************************************************/
3280 : /* LoadBlockBuf() */
3281 : /* */
3282 : /* Load working block buffer with request block (tile/strip). */
3283 : /************************************************************************/
3284 :
3285 231316 : CPLErr GTiffDataset::LoadBlockBuf(int nBlockId, bool bReadFromDisk)
3286 :
3287 : {
3288 231316 : if (m_nLoadedBlock == nBlockId && m_pabyBlockBuf != nullptr)
3289 140358 : return CE_None;
3290 :
3291 : /* -------------------------------------------------------------------- */
3292 : /* If we have a dirty loaded block, flush it out first. */
3293 : /* -------------------------------------------------------------------- */
3294 90958 : if (m_nLoadedBlock != -1 && m_bLoadedBlockDirty)
3295 : {
3296 4577 : const CPLErr eErr = FlushBlockBuf();
3297 4577 : if (eErr != CE_None)
3298 0 : return eErr;
3299 : }
3300 :
3301 : /* -------------------------------------------------------------------- */
3302 : /* Get block size. */
3303 : /* -------------------------------------------------------------------- */
3304 90958 : const GPtrDiff_t nBlockBufSize = static_cast<GPtrDiff_t>(
3305 90958 : TIFFIsTiled(m_hTIFF) ? TIFFTileSize(m_hTIFF) : TIFFStripSize(m_hTIFF));
3306 90958 : if (!nBlockBufSize)
3307 : {
3308 0 : ReportError(CE_Failure, CPLE_AppDefined,
3309 : "Bogus block size; unable to allocate a buffer.");
3310 0 : return CE_Failure;
3311 : }
3312 :
3313 : /* -------------------------------------------------------------------- */
3314 : /* Allocate a temporary buffer for this strip. */
3315 : /* -------------------------------------------------------------------- */
3316 90958 : if (m_pabyBlockBuf == nullptr)
3317 : {
3318 7260 : m_pabyBlockBuf =
3319 7260 : static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockBufSize));
3320 7260 : if (m_pabyBlockBuf == nullptr)
3321 : {
3322 1 : return CE_Failure;
3323 : }
3324 : }
3325 :
3326 90957 : if (m_nLoadedBlock == nBlockId)
3327 4830 : return CE_None;
3328 :
3329 : /* -------------------------------------------------------------------- */
3330 : /* When called from ::IWriteBlock in separate cases (or in single band */
3331 : /* geotiffs), the ::IWriteBlock will override the content of the buffer*/
3332 : /* with pImage, so we don't need to read data from disk */
3333 : /* -------------------------------------------------------------------- */
3334 86127 : if (!bReadFromDisk || m_bStreamingOut)
3335 : {
3336 35291 : m_nLoadedBlock = nBlockId;
3337 35291 : return CE_None;
3338 : }
3339 :
3340 : // libtiff 3.X doesn't like mixing read&write of JPEG compressed blocks
3341 : // The below hack is necessary due to another hack that consist in
3342 : // writing zero block to force creation of JPEG tables.
3343 50836 : if (nBlockId == 0 && m_bDontReloadFirstBlock)
3344 : {
3345 0 : m_bDontReloadFirstBlock = false;
3346 0 : memset(m_pabyBlockBuf, 0, nBlockBufSize);
3347 0 : m_nLoadedBlock = nBlockId;
3348 0 : return CE_None;
3349 : }
3350 :
3351 : /* -------------------------------------------------------------------- */
3352 : /* The bottom most partial tiles and strips are sometimes only */
3353 : /* partially encoded. This code reduces the requested data so */
3354 : /* an error won't be reported in this case. (#1179) */
3355 : /* We exclude tiled WEBP, because as it is a new codec, whole tiles*/
3356 : /* are written by libtiff. This helps avoiding creating a temporary*/
3357 : /* decode buffer. */
3358 : /* -------------------------------------------------------------------- */
3359 50836 : auto nBlockReqSize = nBlockBufSize;
3360 50836 : const int nBlockYOff = (nBlockId % m_nBlocksPerBand) / m_nBlocksPerRow;
3361 :
3362 52165 : if (nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize &&
3363 1329 : !(m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF)))
3364 : {
3365 1326 : nBlockReqSize =
3366 1326 : (nBlockBufSize / m_nBlockYSize) *
3367 1326 : (m_nBlockYSize -
3368 : static_cast<int>(
3369 1326 : (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
3370 1326 : nRasterYSize));
3371 1326 : memset(m_pabyBlockBuf, 0, nBlockBufSize);
3372 : }
3373 :
3374 : /* -------------------------------------------------------------------- */
3375 : /* If we don't have this block already loaded, and we know it */
3376 : /* doesn't yet exist on disk, just zero the memory buffer and */
3377 : /* pretend we loaded it. */
3378 : /* -------------------------------------------------------------------- */
3379 50836 : bool bErrOccurred = false;
3380 50836 : if (!IsBlockAvailable(nBlockId, nullptr, nullptr, &bErrOccurred))
3381 : {
3382 797 : memset(m_pabyBlockBuf, 0, nBlockBufSize);
3383 797 : m_nLoadedBlock = nBlockId;
3384 797 : if (bErrOccurred)
3385 0 : return CE_Failure;
3386 797 : return CE_None;
3387 : }
3388 :
3389 : /* -------------------------------------------------------------------- */
3390 : /* Load the block, if it isn't our current block. */
3391 : /* -------------------------------------------------------------------- */
3392 50039 : CPLErr eErr = CE_None;
3393 :
3394 50039 : if (!ReadStrile(nBlockId, m_pabyBlockBuf, nBlockReqSize))
3395 : {
3396 26 : memset(m_pabyBlockBuf, 0, nBlockBufSize);
3397 26 : eErr = CE_Failure;
3398 : }
3399 :
3400 50039 : if (eErr == CE_None)
3401 : {
3402 50823 : if (m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF) &&
3403 810 : nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize)
3404 : {
3405 3 : const auto nValidBytes =
3406 3 : (nBlockBufSize / m_nBlockYSize) *
3407 3 : (m_nBlockYSize -
3408 : static_cast<int>(
3409 3 : (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
3410 3 : nRasterYSize));
3411 : // Zero-out unused area
3412 3 : memset(m_pabyBlockBuf + nValidBytes, 0,
3413 3 : nBlockBufSize - nValidBytes);
3414 : }
3415 :
3416 50013 : m_nLoadedBlock = nBlockId;
3417 : }
3418 : else
3419 : {
3420 26 : m_nLoadedBlock = -1;
3421 : }
3422 50039 : m_bLoadedBlockDirty = false;
3423 :
3424 50039 : return eErr;
3425 : }
3426 :
3427 : /************************************************************************/
3428 : /* Identify() */
3429 : /************************************************************************/
3430 :
3431 121973 : int GTiffDataset::Identify(GDALOpenInfo *poOpenInfo)
3432 :
3433 : {
3434 121973 : const char *pszFilename = poOpenInfo->pszFilename;
3435 121973 : if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
3436 : {
3437 20 : pszFilename += strlen("GTIFF_RAW:");
3438 40 : GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->eAccess);
3439 20 : return Identify(&oOpenInfo);
3440 : }
3441 :
3442 : /* -------------------------------------------------------------------- */
3443 : /* We have a special hook for handling opening a specific */
3444 : /* directory of a TIFF file. */
3445 : /* -------------------------------------------------------------------- */
3446 121953 : if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
3447 60 : return TRUE;
3448 :
3449 : /* -------------------------------------------------------------------- */
3450 : /* First we check to see if the file has the expected header */
3451 : /* bytes. */
3452 : /* -------------------------------------------------------------------- */
3453 121893 : if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 2)
3454 62250 : return FALSE;
3455 :
3456 59643 : if ((poOpenInfo->pabyHeader[0] != 'I' ||
3457 48319 : poOpenInfo->pabyHeader[1] != 'I') &&
3458 11344 : (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
3459 11076 : return FALSE;
3460 :
3461 48567 : if ((poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0) &&
3462 555 : (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0) &&
3463 309 : (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0) &&
3464 22 : (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
3465 0 : return FALSE;
3466 :
3467 48567 : return TRUE;
3468 : }
3469 :
3470 : /************************************************************************/
3471 : /* GTIFFExtendMemoryFile() */
3472 : /************************************************************************/
3473 :
3474 14 : static bool GTIFFExtendMemoryFile(const CPLString &osTmpFilename,
3475 : VSILFILE *fpTemp, VSILFILE *fpL,
3476 : int nNewLength, GByte *&pabyBuffer,
3477 : vsi_l_offset &nDataLength)
3478 : {
3479 14 : if (nNewLength <= static_cast<int>(nDataLength))
3480 10 : return true;
3481 4 : if (VSIFSeekL(fpTemp, nNewLength - 1, SEEK_SET) != 0)
3482 0 : return false;
3483 4 : char ch = 0;
3484 4 : if (VSIFWriteL(&ch, 1, 1, fpTemp) != 1)
3485 0 : return false;
3486 4 : const int nOldDataLength = static_cast<int>(nDataLength);
3487 4 : pabyBuffer = static_cast<GByte *>(
3488 4 : VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
3489 4 : const int nToRead = nNewLength - nOldDataLength;
3490 : const int nRead = static_cast<int>(
3491 4 : VSIFReadL(pabyBuffer + nOldDataLength, 1, nToRead, fpL));
3492 4 : if (nRead != nToRead)
3493 : {
3494 0 : CPLError(CE_Failure, CPLE_FileIO,
3495 : "Needed to read %d bytes. Only %d got", nToRead, nRead);
3496 0 : return false;
3497 : }
3498 4 : return true;
3499 : }
3500 :
3501 : /************************************************************************/
3502 : /* GTIFFMakeBufferedStream() */
3503 : /************************************************************************/
3504 :
3505 9 : static bool GTIFFMakeBufferedStream(GDALOpenInfo *poOpenInfo)
3506 : {
3507 : const CPLString osTmpFilename(
3508 18 : VSIMemGenerateHiddenFilename("GTIFFMakeBufferedStream.tif"));
3509 9 : VSILFILE *fpTemp = VSIFOpenL(osTmpFilename, "wb+");
3510 9 : if (fpTemp == nullptr)
3511 0 : return false;
3512 : // The seek is needed for /vsistdin/ that has some rewind capabilities.
3513 18 : if (VSIFSeekL(poOpenInfo->fpL,
3514 9 : static_cast<vsi_l_offset>(poOpenInfo->nHeaderBytes),
3515 9 : SEEK_SET) != 0)
3516 : {
3517 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3518 0 : return false;
3519 : }
3520 9 : CPLAssert(static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
3521 : poOpenInfo->nHeaderBytes);
3522 9 : if (VSIFWriteL(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes, 1,
3523 9 : fpTemp) != 1)
3524 : {
3525 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3526 0 : return false;
3527 : }
3528 9 : vsi_l_offset nDataLength = 0;
3529 : GByte *pabyBuffer = static_cast<GByte *>(
3530 9 : VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
3531 9 : const bool bLittleEndian = (pabyBuffer[0] == 'I');
3532 9 : const bool bSwap = CPL_IS_LSB ^ bLittleEndian;
3533 9 : const bool bBigTIFF = pabyBuffer[2] == 43 || pabyBuffer[3] == 43;
3534 9 : vsi_l_offset nMaxOffset = 0;
3535 9 : if (bBigTIFF)
3536 : {
3537 2 : GUInt64 nTmp = 0;
3538 2 : memcpy(&nTmp, pabyBuffer + 8, 8);
3539 2 : if (bSwap)
3540 0 : CPL_SWAP64PTR(&nTmp);
3541 2 : if (nTmp != 16)
3542 : {
3543 1 : CPLError(CE_Failure, CPLE_NotSupported,
3544 : "IFD start should be at offset 16 for a streamed BigTIFF");
3545 1 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3546 1 : VSIUnlink(osTmpFilename);
3547 1 : return false;
3548 : }
3549 1 : memcpy(&nTmp, pabyBuffer + 16, 8);
3550 1 : if (bSwap)
3551 0 : CPL_SWAP64PTR(&nTmp);
3552 1 : if (nTmp > 1024)
3553 : {
3554 0 : CPLError(CE_Failure, CPLE_NotSupported,
3555 : "Too many tags : " CPL_FRMT_GIB, nTmp);
3556 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3557 0 : VSIUnlink(osTmpFilename);
3558 0 : return false;
3559 : }
3560 1 : const int nTags = static_cast<int>(nTmp);
3561 1 : const int nSpaceForTags = nTags * 20;
3562 1 : if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
3563 : 24 + nSpaceForTags, pabyBuffer, nDataLength))
3564 : {
3565 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3566 0 : VSIUnlink(osTmpFilename);
3567 0 : return false;
3568 : }
3569 1 : nMaxOffset = 24 + nSpaceForTags + 8;
3570 18 : for (int i = 0; i < nTags; ++i)
3571 : {
3572 17 : GUInt16 nTmp16 = 0;
3573 17 : memcpy(&nTmp16, pabyBuffer + 24 + i * 20, 2);
3574 17 : if (bSwap)
3575 0 : CPL_SWAP16PTR(&nTmp16);
3576 17 : const int nTag = nTmp16;
3577 17 : memcpy(&nTmp16, pabyBuffer + 24 + i * 20 + 2, 2);
3578 17 : if (bSwap)
3579 0 : CPL_SWAP16PTR(&nTmp16);
3580 17 : const int nDataType = nTmp16;
3581 17 : memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 4, 8);
3582 17 : if (bSwap)
3583 0 : CPL_SWAP64PTR(&nTmp);
3584 17 : if (nTmp >= 16 * 1024 * 1024)
3585 : {
3586 0 : CPLError(CE_Failure, CPLE_NotSupported,
3587 : "Too many elements for tag %d : " CPL_FRMT_GUIB, nTag,
3588 : nTmp);
3589 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3590 0 : VSIUnlink(osTmpFilename);
3591 0 : return false;
3592 : }
3593 17 : const GUInt32 nCount = static_cast<GUInt32>(nTmp);
3594 : const GUInt32 nTagSize =
3595 17 : TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
3596 17 : if (nTagSize > 8)
3597 : {
3598 7 : memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 12, 8);
3599 7 : if (bSwap)
3600 0 : CPL_SWAP64PTR(&nTmp);
3601 7 : if (nTmp > GUINT64_MAX - nTagSize)
3602 : {
3603 0 : CPLError(CE_Failure, CPLE_NotSupported,
3604 : "Overflow with tag %d", nTag);
3605 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3606 0 : VSIUnlink(osTmpFilename);
3607 0 : return false;
3608 : }
3609 7 : if (static_cast<vsi_l_offset>(nTmp + nTagSize) > nMaxOffset)
3610 6 : nMaxOffset = nTmp + nTagSize;
3611 : }
3612 : }
3613 : }
3614 : else
3615 : {
3616 7 : GUInt32 nTmp = 0;
3617 7 : memcpy(&nTmp, pabyBuffer + 4, 4);
3618 7 : if (bSwap)
3619 0 : CPL_SWAP32PTR(&nTmp);
3620 7 : if (nTmp != 8)
3621 : {
3622 1 : CPLError(CE_Failure, CPLE_NotSupported,
3623 : "IFD start should be at offset 8 for a streamed TIFF");
3624 1 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3625 1 : VSIUnlink(osTmpFilename);
3626 1 : return false;
3627 : }
3628 6 : GUInt16 nTmp16 = 0;
3629 6 : memcpy(&nTmp16, pabyBuffer + 8, 2);
3630 6 : if (bSwap)
3631 0 : CPL_SWAP16PTR(&nTmp16);
3632 6 : if (nTmp16 > 1024)
3633 : {
3634 0 : CPLError(CE_Failure, CPLE_NotSupported, "Too many tags : %d",
3635 : nTmp16);
3636 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3637 0 : VSIUnlink(osTmpFilename);
3638 0 : return false;
3639 : }
3640 6 : const int nTags = nTmp16;
3641 6 : const int nSpaceForTags = nTags * 12;
3642 6 : if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
3643 : 10 + nSpaceForTags, pabyBuffer, nDataLength))
3644 : {
3645 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3646 0 : VSIUnlink(osTmpFilename);
3647 0 : return false;
3648 : }
3649 6 : nMaxOffset = 10 + nSpaceForTags + 4;
3650 95 : for (int i = 0; i < nTags; ++i)
3651 : {
3652 89 : memcpy(&nTmp16, pabyBuffer + 10 + i * 12, 2);
3653 89 : if (bSwap)
3654 0 : CPL_SWAP16PTR(&nTmp16);
3655 89 : const int nTag = nTmp16;
3656 89 : memcpy(&nTmp16, pabyBuffer + 10 + i * 12 + 2, 2);
3657 89 : if (bSwap)
3658 0 : CPL_SWAP16PTR(&nTmp16);
3659 89 : const int nDataType = nTmp16;
3660 89 : memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 4, 4);
3661 89 : if (bSwap)
3662 0 : CPL_SWAP32PTR(&nTmp);
3663 89 : if (nTmp >= 16 * 1024 * 1024)
3664 : {
3665 0 : CPLError(CE_Failure, CPLE_NotSupported,
3666 : "Too many elements for tag %d : %u", nTag, nTmp);
3667 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3668 0 : VSIUnlink(osTmpFilename);
3669 0 : return false;
3670 : }
3671 89 : const GUInt32 nCount = nTmp;
3672 : const GUInt32 nTagSize =
3673 89 : TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
3674 89 : if (nTagSize > 4)
3675 : {
3676 37 : memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 8, 4);
3677 37 : if (bSwap)
3678 0 : CPL_SWAP32PTR(&nTmp);
3679 37 : if (nTmp > static_cast<GUInt32>(UINT_MAX - nTagSize))
3680 : {
3681 0 : CPLError(CE_Failure, CPLE_NotSupported,
3682 : "Overflow with tag %d", nTag);
3683 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3684 0 : VSIUnlink(osTmpFilename);
3685 0 : return false;
3686 : }
3687 37 : if (nTmp + nTagSize > nMaxOffset)
3688 32 : nMaxOffset = nTmp + nTagSize;
3689 : }
3690 : }
3691 : }
3692 7 : if (nMaxOffset > 10 * 1024 * 1024)
3693 : {
3694 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3695 0 : VSIUnlink(osTmpFilename);
3696 0 : return false;
3697 : }
3698 7 : if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
3699 : static_cast<int>(nMaxOffset), pabyBuffer,
3700 : nDataLength))
3701 : {
3702 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
3703 0 : VSIUnlink(osTmpFilename);
3704 0 : return false;
3705 : }
3706 7 : CPLAssert(nDataLength == VSIFTellL(poOpenInfo->fpL));
3707 7 : poOpenInfo->fpL = VSICreateBufferedReaderHandle(
3708 : poOpenInfo->fpL, pabyBuffer, static_cast<vsi_l_offset>(INT_MAX) << 32);
3709 7 : if (VSIFCloseL(fpTemp) != 0)
3710 0 : return false;
3711 7 : VSIUnlink(osTmpFilename);
3712 :
3713 7 : return true;
3714 : }
3715 :
3716 : /************************************************************************/
3717 : /* AssociateExternalMask() */
3718 : /************************************************************************/
3719 :
3720 : // Used by GTIFFBuildOverviewsEx() for the COG driver
3721 5 : bool GTiffDataset::AssociateExternalMask()
3722 : {
3723 5 : if (m_poMaskExtOvrDS->GetRasterBand(1)->GetOverviewCount() !=
3724 5 : GetRasterBand(1)->GetOverviewCount())
3725 0 : return false;
3726 5 : if (m_apoOverviewDS.empty())
3727 0 : return false;
3728 5 : if (m_poMaskDS)
3729 0 : return false;
3730 10 : if (m_poMaskExtOvrDS->GetRasterXSize() != nRasterXSize ||
3731 5 : m_poMaskExtOvrDS->GetRasterYSize() != nRasterYSize)
3732 0 : return false;
3733 5 : m_poExternalMaskDS = m_poMaskExtOvrDS.get();
3734 5 : int i = 0;
3735 13 : for (auto &poOvrDS : m_apoOverviewDS)
3736 : {
3737 8 : if (poOvrDS->m_poMaskDS)
3738 0 : return false;
3739 16 : poOvrDS->m_poExternalMaskDS =
3740 8 : m_poMaskExtOvrDS->GetRasterBand(1)->GetOverview(i)->GetDataset();
3741 8 : if (!poOvrDS->m_poExternalMaskDS)
3742 0 : return false;
3743 8 : auto poOvrBand = poOvrDS->GetRasterBand(1);
3744 8 : if (poOvrDS->m_poExternalMaskDS->GetRasterXSize() !=
3745 16 : poOvrBand->GetXSize() ||
3746 8 : poOvrDS->m_poExternalMaskDS->GetRasterYSize() !=
3747 8 : poOvrBand->GetYSize())
3748 0 : return false;
3749 8 : ++i;
3750 : }
3751 5 : return true;
3752 : }
3753 :
3754 : /************************************************************************/
3755 : /* Open() */
3756 : /************************************************************************/
3757 :
3758 24029 : GDALDataset *GTiffDataset::Open(GDALOpenInfo *poOpenInfo)
3759 :
3760 : {
3761 24029 : const char *pszFilename = poOpenInfo->pszFilename;
3762 :
3763 : /* -------------------------------------------------------------------- */
3764 : /* Check if it looks like a TIFF file. */
3765 : /* -------------------------------------------------------------------- */
3766 24029 : if (!Identify(poOpenInfo))
3767 0 : return nullptr;
3768 :
3769 24029 : bool bAllowRGBAInterface = true;
3770 24029 : if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
3771 : {
3772 10 : bAllowRGBAInterface = false;
3773 10 : pszFilename += strlen("GTIFF_RAW:");
3774 : }
3775 :
3776 : /* -------------------------------------------------------------------- */
3777 : /* We have a special hook for handling opening a specific */
3778 : /* directory of a TIFF file. */
3779 : /* -------------------------------------------------------------------- */
3780 24029 : if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
3781 30 : return OpenDir(poOpenInfo);
3782 :
3783 23999 : GTiffOneTimeInit();
3784 :
3785 : /* -------------------------------------------------------------------- */
3786 : /* Try opening the dataset. */
3787 : /* -------------------------------------------------------------------- */
3788 23999 : bool bStreaming = false;
3789 : const char *pszReadStreaming =
3790 23999 : CPLGetConfigOption("TIFF_READ_STREAMING", nullptr);
3791 23999 : if (poOpenInfo->fpL == nullptr)
3792 : {
3793 9 : poOpenInfo->fpL = VSIFOpenL(
3794 9 : pszFilename, poOpenInfo->eAccess == GA_ReadOnly ? "rb" : "r+b");
3795 9 : if (poOpenInfo->fpL == nullptr)
3796 0 : return nullptr;
3797 : }
3798 7 : else if (!(pszReadStreaming && !CPLTestBool(pszReadStreaming)) &&
3799 47986 : poOpenInfo->nHeaderBytes >= 24 &&
3800 : // A pipe has no seeking capability, so its position is 0 despite
3801 : // having read bytes.
3802 23989 : (static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
3803 23989 : poOpenInfo->nHeaderBytes ||
3804 23989 : strcmp(pszFilename, "/vsistdin/") == 0 ||
3805 : // STARTS_WITH(pszFilename, "/vsicurl_streaming/") ||
3806 7 : (pszReadStreaming && CPLTestBool(pszReadStreaming))))
3807 : {
3808 9 : bStreaming = true;
3809 9 : if (!GTIFFMakeBufferedStream(poOpenInfo))
3810 2 : return nullptr;
3811 : }
3812 :
3813 : // Store errors/warnings and emit them later.
3814 : TIFF *l_hTIFF;
3815 47994 : CPLErrorAccumulator oErrorAccumulator;
3816 : {
3817 23997 : auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
3818 23997 : CPL_IGNORE_RET_VAL(oAccumulator);
3819 23997 : CPLSetCurrentErrorHandlerCatchDebug(FALSE);
3820 23997 : const bool bDeferStrileLoading = CPLTestBool(
3821 : CPLGetConfigOption("GTIFF_USE_DEFER_STRILE_LOADING", "YES"));
3822 23997 : l_hTIFF = VSI_TIFFOpen(
3823 : pszFilename,
3824 23997 : poOpenInfo->eAccess == GA_ReadOnly
3825 23196 : ? ((bStreaming || !bDeferStrileLoading) ? "rC" : "rDOC")
3826 801 : : (!bDeferStrileLoading ? "r+C" : "r+DC"),
3827 : poOpenInfo->fpL);
3828 : };
3829 :
3830 : // Now emit errors and change their criticality if needed
3831 : // We only emit failures if we didn't manage to open the file.
3832 : // Otherwise it makes Python bindings unhappy (#5616).
3833 24092 : for (const auto &oError : oErrorAccumulator.GetErrors())
3834 : {
3835 190 : ReportError(pszFilename,
3836 1 : (l_hTIFF == nullptr && oError.type == CE_Failure)
3837 : ? CE_Failure
3838 : : CE_Warning,
3839 95 : oError.no, "%s", oError.msg.c_str());
3840 : }
3841 :
3842 23997 : if (l_hTIFF == nullptr)
3843 2 : return nullptr;
3844 :
3845 23995 : uint32_t nXSize = 0;
3846 23995 : TIFFGetField(l_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
3847 23995 : uint32_t nYSize = 0;
3848 23995 : TIFFGetField(l_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
3849 :
3850 23995 : if (nXSize > INT_MAX || nYSize > INT_MAX)
3851 : {
3852 : // GDAL only supports signed 32bit dimensions.
3853 1 : ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
3854 : "Too large image size: %u x %u", nXSize, nYSize);
3855 1 : XTIFFClose(l_hTIFF);
3856 1 : return nullptr;
3857 : }
3858 :
3859 23994 : uint16_t l_nCompression = 0;
3860 23994 : if (!TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(l_nCompression)))
3861 0 : l_nCompression = COMPRESSION_NONE;
3862 :
3863 : /* -------------------------------------------------------------------- */
3864 : /* Create a corresponding GDALDataset. */
3865 : /* -------------------------------------------------------------------- */
3866 47988 : auto poDS = std::make_unique<GTiffDataset>();
3867 23994 : poDS->SetDescription(pszFilename);
3868 23994 : poDS->m_osFilename = pszFilename;
3869 23994 : poDS->m_fpL = poOpenInfo->fpL;
3870 23994 : poOpenInfo->fpL = nullptr;
3871 23994 : poDS->m_bStreamingIn = bStreaming;
3872 23994 : poDS->m_nCompression = l_nCompression;
3873 :
3874 : // Check structural metadata (for COG)
3875 23994 : const int nOffsetOfStructuralMetadata =
3876 23985 : poOpenInfo->nHeaderBytes && ((poOpenInfo->pabyHeader[2] == 0x2B ||
3877 23845 : poOpenInfo->pabyHeader[3] == 0x2B))
3878 47979 : ? 16
3879 : : 8;
3880 23994 : if (poOpenInfo->nHeaderBytes >
3881 23994 : nOffsetOfStructuralMetadata +
3882 23985 : static_cast<int>(strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) &&
3883 23985 : memcmp(poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata,
3884 : "GDAL_STRUCTURAL_METADATA_SIZE=",
3885 : strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
3886 : {
3887 269 : const char *pszStructuralMD = reinterpret_cast<const char *>(
3888 269 : poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata);
3889 538 : poDS->m_bLayoutIFDSBeforeData =
3890 269 : strstr(pszStructuralMD, "LAYOUT=IFDS_BEFORE_DATA") != nullptr;
3891 538 : poDS->m_bBlockOrderRowMajor =
3892 269 : strstr(pszStructuralMD, "BLOCK_ORDER=ROW_MAJOR") != nullptr;
3893 269 : poDS->m_bLeaderSizeAsUInt4 =
3894 538 : strstr(pszStructuralMD, "BLOCK_LEADER=SIZE_AS_UINT4") != nullptr &&
3895 269 : (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
3896 23 : strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
3897 0 : strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
3898 269 : poDS->m_bTrailerRepeatedLast4BytesRepeated =
3899 269 : strstr(pszStructuralMD, "BLOCK_TRAILER=LAST_4_BYTES_REPEATED") !=
3900 538 : nullptr &&
3901 269 : (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
3902 23 : strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
3903 0 : strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
3904 269 : poDS->m_bMaskInterleavedWithImagery =
3905 269 : strstr(pszStructuralMD, "MASK_INTERLEAVED_WITH_IMAGERY=YES") !=
3906 310 : nullptr &&
3907 41 : strstr(pszStructuralMD, "INTERLEAVE=") == nullptr;
3908 538 : poDS->m_bKnownIncompatibleEdition =
3909 269 : strstr(pszStructuralMD, "KNOWN_INCOMPATIBLE_EDITION=YES") !=
3910 : nullptr;
3911 269 : if (poDS->m_bKnownIncompatibleEdition)
3912 : {
3913 7 : poDS->ReportError(
3914 : CE_Warning, CPLE_AppDefined,
3915 : "This file used to have optimizations in its layout, "
3916 : "but those have been, at least partly, invalidated by "
3917 : "later changes");
3918 : }
3919 524 : else if (poDS->m_bLayoutIFDSBeforeData && poDS->m_bBlockOrderRowMajor &&
3920 786 : poDS->m_bLeaderSizeAsUInt4 &&
3921 262 : poDS->m_bTrailerRepeatedLast4BytesRepeated)
3922 : {
3923 275 : if (poOpenInfo->eAccess == GA_Update &&
3924 13 : !CPLTestBool(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
3925 : "IGNORE_COG_LAYOUT_BREAK",
3926 : "FALSE")))
3927 : {
3928 5 : CPLError(CE_Failure, CPLE_AppDefined,
3929 : "File %s has C(loud) O(ptimized) G(eoTIFF) layout. "
3930 : "Updating it will generally result in losing part of "
3931 : "the optimizations (but will still produce a valid "
3932 : "GeoTIFF file). If this is acceptable, open the file "
3933 : "with the IGNORE_COG_LAYOUT_BREAK open option set "
3934 : "to YES.",
3935 : pszFilename);
3936 5 : XTIFFClose(l_hTIFF);
3937 5 : return nullptr;
3938 : }
3939 257 : poDS->m_oGTiffMDMD.SetMetadataItem("LAYOUT", "COG",
3940 : "IMAGE_STRUCTURE");
3941 : }
3942 : }
3943 :
3944 : // In the case of GDAL_DISABLE_READDIR_ON_OPEN = NO / EMPTY_DIR
3945 24158 : if (poOpenInfo->AreSiblingFilesLoaded() &&
3946 169 : CSLCount(poOpenInfo->GetSiblingFiles()) <= 1)
3947 : {
3948 148 : poDS->oOvManager.TransferSiblingFiles(
3949 74 : CSLDuplicate(poOpenInfo->GetSiblingFiles()));
3950 74 : poDS->m_bHasGotSiblingFiles = true;
3951 : }
3952 :
3953 : // Should be capped by 257, to avoid 65535 / m_nColorTableMultiplier to overflow 255
3954 23989 : poDS->m_nColorTableMultiplier = std::max(
3955 71967 : 0, std::min(257,
3956 23989 : atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
3957 23989 : "COLOR_TABLE_MULTIPLIER", "0"))));
3958 :
3959 23989 : if (poDS->OpenOffset(l_hTIFF, TIFFCurrentDirOffset(l_hTIFF),
3960 : poOpenInfo->eAccess, bAllowRGBAInterface,
3961 23989 : true) != CE_None)
3962 : {
3963 9 : return nullptr;
3964 : }
3965 :
3966 : // Do we want blocks that are set to zero and that haven't yet being
3967 : // allocated as tile/strip to remain implicit?
3968 23980 : if (CPLFetchBool(poOpenInfo->papszOpenOptions, "SPARSE_OK", false))
3969 46 : poDS->m_bWriteEmptyTiles = false;
3970 :
3971 23980 : poDS->InitCreationOrOpenOptions(poOpenInfo->eAccess == GA_Update,
3972 23980 : poOpenInfo->papszOpenOptions);
3973 :
3974 23980 : poDS->m_bLoadPam = true;
3975 23980 : poDS->m_bColorProfileMetadataChanged = false;
3976 23980 : poDS->m_bMetadataChanged = false;
3977 23980 : poDS->m_bGeoTIFFInfoChanged = false;
3978 23980 : poDS->m_bNoDataChanged = false;
3979 23980 : poDS->m_bForceUnsetGTOrGCPs = false;
3980 23980 : poDS->m_bForceUnsetProjection = false;
3981 :
3982 : // Used by GTIFFBuildOverviewsEx() for the COG driver
3983 47960 : const char *pszMaskOverviewDS = CSLFetchNameValue(
3984 23980 : poOpenInfo->papszOpenOptions, "MASK_OVERVIEW_DATASET");
3985 23980 : if (pszMaskOverviewDS)
3986 : {
3987 5 : poDS->m_poMaskExtOvrDS.reset(GDALDataset::Open(
3988 : pszMaskOverviewDS, GDAL_OF_RASTER | GDAL_OF_INTERNAL));
3989 5 : if (!poDS->m_poMaskExtOvrDS || !poDS->AssociateExternalMask())
3990 : {
3991 0 : CPLDebug("GTiff",
3992 : "Association with external mask overview file failed");
3993 : }
3994 : }
3995 :
3996 : /* -------------------------------------------------------------------- */
3997 : /* Initialize info for external overviews. */
3998 : /* -------------------------------------------------------------------- */
3999 23980 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo, pszFilename);
4000 :
4001 : // For backward compatibility, in case GTIFF_POINT_GEO_IGNORE is defined
4002 : // load georeferencing right now so as to not require it to be defined
4003 : // at the GetGeoTransform() time.
4004 23980 : if (CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE", nullptr) != nullptr)
4005 : {
4006 14 : poDS->LoadGeoreferencingAndPamIfNeeded();
4007 : }
4008 :
4009 23980 : return poDS.release();
4010 : }
4011 :
4012 : /************************************************************************/
4013 : /* GTiffDatasetSetAreaOrPointMD() */
4014 : /************************************************************************/
4015 :
4016 14130 : static void GTiffDatasetSetAreaOrPointMD(GTIF *hGTIF,
4017 : GDALMultiDomainMetadata &m_oGTiffMDMD)
4018 : {
4019 : // Is this a pixel-is-point dataset?
4020 14130 : unsigned short nRasterType = 0;
4021 :
4022 14130 : if (GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType, 0, 1) == 1)
4023 : {
4024 8768 : if (nRasterType == static_cast<short>(RasterPixelIsPoint))
4025 257 : m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT,
4026 : GDALMD_AOP_POINT);
4027 : else
4028 8511 : m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
4029 : }
4030 14130 : }
4031 :
4032 : /************************************************************************/
4033 : /* LoadMDAreaOrPoint() */
4034 : /************************************************************************/
4035 :
4036 : // This is a light version of LookForProjection(), which saves the
4037 : // potential costly cost of GTIFGetOGISDefn(), since we just need to
4038 : // access to a raw GeoTIFF key, and not build the full projection object.
4039 :
4040 17050 : void GTiffDataset::LoadMDAreaOrPoint()
4041 : {
4042 18120 : if (m_bLookedForProjection || m_bLookedForMDAreaOrPoint ||
4043 1070 : m_oGTiffMDMD.GetMetadataItem(GDALMD_AREA_OR_POINT) != nullptr)
4044 15980 : return;
4045 :
4046 1070 : m_bLookedForMDAreaOrPoint = true;
4047 :
4048 1070 : GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
4049 :
4050 1070 : if (!hGTIF)
4051 : {
4052 0 : ReportError(CE_Warning, CPLE_AppDefined,
4053 : "GeoTIFF tags apparently corrupt, they are being ignored.");
4054 : }
4055 : else
4056 : {
4057 1070 : GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
4058 :
4059 1070 : GTIFFree(hGTIF);
4060 : }
4061 : }
4062 :
4063 : /************************************************************************/
4064 : /* LookForProjection() */
4065 : /************************************************************************/
4066 :
4067 332506 : void GTiffDataset::LookForProjection()
4068 :
4069 : {
4070 332506 : if (m_bLookedForProjection)
4071 319439 : return;
4072 :
4073 13067 : m_bLookedForProjection = true;
4074 :
4075 13067 : IdentifyAuthorizedGeoreferencingSources();
4076 :
4077 13067 : m_oSRS.Clear();
4078 :
4079 26134 : std::set<signed char> aoSetPriorities;
4080 13067 : if (m_nINTERNALGeorefSrcIndex >= 0)
4081 13060 : aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
4082 13067 : if (m_nXMLGeorefSrcIndex >= 0)
4083 13030 : aoSetPriorities.insert(m_nXMLGeorefSrcIndex);
4084 39157 : for (const auto nIndex : aoSetPriorities)
4085 : {
4086 26090 : if (m_nINTERNALGeorefSrcIndex == nIndex)
4087 : {
4088 13060 : LookForProjectionFromGeoTIFF();
4089 : }
4090 13030 : else if (m_nXMLGeorefSrcIndex == nIndex)
4091 : {
4092 13030 : LookForProjectionFromXML();
4093 : }
4094 : }
4095 : }
4096 :
4097 : /************************************************************************/
4098 : /* LookForProjectionFromGeoTIFF() */
4099 : /************************************************************************/
4100 :
4101 13060 : void GTiffDataset::LookForProjectionFromGeoTIFF()
4102 : {
4103 : /* -------------------------------------------------------------------- */
4104 : /* Capture the GeoTIFF projection, if available. */
4105 : /* -------------------------------------------------------------------- */
4106 :
4107 13060 : GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
4108 :
4109 13060 : if (!hGTIF)
4110 : {
4111 0 : ReportError(CE_Warning, CPLE_AppDefined,
4112 : "GeoTIFF tags apparently corrupt, they are being ignored.");
4113 : }
4114 : else
4115 : {
4116 13060 : GTIFDefn *psGTIFDefn = GTIFAllocDefn();
4117 :
4118 13060 : bool bHasErrorBefore = CPLGetLastErrorType() != 0;
4119 : // Collect (PROJ) error messages and remit them later as warnings
4120 : int ret;
4121 26120 : CPLErrorAccumulator oErrorAccumulator;
4122 : {
4123 13060 : auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
4124 13060 : ret = GTIFGetDefn(hGTIF, psGTIFDefn);
4125 : }
4126 :
4127 13060 : bool bWarnAboutEllipsoid = true;
4128 :
4129 13060 : if (ret)
4130 : {
4131 16582 : auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
4132 :
4133 8291 : if (psGTIFDefn->Ellipsoid == 4326 &&
4134 1 : psGTIFDefn->SemiMajor == 6378137 &&
4135 1 : psGTIFDefn->SemiMinor == 6356752.314245)
4136 : {
4137 : // Buggy Sentinel1 geotiff files use a wrong 4326 code for the
4138 : // ellipsoid instead of 7030.
4139 1 : psGTIFDefn->Ellipsoid = 7030;
4140 1 : bWarnAboutEllipsoid = false;
4141 : }
4142 :
4143 8291 : OGRSpatialReferenceH hSRS = GTIFGetOGISDefnAsOSR(hGTIF, psGTIFDefn);
4144 :
4145 8291 : if (hSRS)
4146 : {
4147 8291 : CPLFree(m_pszXMLFilename);
4148 8291 : m_pszXMLFilename = nullptr;
4149 :
4150 8291 : m_oSRS = *(OGRSpatialReference::FromHandle(hSRS));
4151 8291 : OSRDestroySpatialReference(hSRS);
4152 : }
4153 : }
4154 :
4155 26120 : std::set<std::string> oSetErrorMsg;
4156 13072 : for (const auto &oError : oErrorAccumulator.GetErrors())
4157 : {
4158 13 : if (!bWarnAboutEllipsoid &&
4159 1 : oError.msg.find("ellipsoid not found") != std::string::npos)
4160 : {
4161 1 : continue;
4162 : }
4163 :
4164 : // Some error messages might be duplicated in GTIFGetDefn()
4165 : // and GTIFGetOGISDefnAsOSR(). Emit them just once.
4166 11 : if (oSetErrorMsg.find(oError.msg) == oSetErrorMsg.end())
4167 : {
4168 8 : oSetErrorMsg.insert(oError.msg);
4169 16 : CPLError(oError.type == CE_Failure ? CE_Warning : oError.type,
4170 8 : oError.no, "%s", oError.msg.c_str());
4171 : }
4172 : }
4173 :
4174 13060 : if (!bHasErrorBefore && oSetErrorMsg.empty())
4175 : {
4176 12983 : CPLErrorReset();
4177 : }
4178 :
4179 13060 : if (ret && m_oSRS.IsCompound())
4180 : {
4181 35 : const char *pszVertUnit = nullptr;
4182 35 : m_oSRS.GetTargetLinearUnits("COMPD_CS|VERT_CS", &pszVertUnit);
4183 35 : if (pszVertUnit && !EQUAL(pszVertUnit, "unknown"))
4184 : {
4185 35 : CPLFree(m_pszVertUnit);
4186 35 : m_pszVertUnit = CPLStrdup(pszVertUnit);
4187 : }
4188 :
4189 : int versions[3];
4190 35 : GTIFDirectoryInfo(hGTIF, versions, nullptr);
4191 :
4192 : // If GeoTIFF 1.0, strip vertical by default
4193 35 : const char *pszDefaultReportCompdCS =
4194 35 : (versions[0] == 1 && versions[1] == 1 && versions[2] == 0)
4195 70 : ? "NO"
4196 : : "YES";
4197 :
4198 : // Should we simplify away vertical CS stuff?
4199 35 : if (!CPLTestBool(CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
4200 : pszDefaultReportCompdCS)))
4201 : {
4202 10 : CPLDebug("GTiff", "Got COMPD_CS, but stripping it.");
4203 :
4204 10 : m_oSRS.StripVertical();
4205 : }
4206 : }
4207 :
4208 13060 : GTIFFreeDefn(psGTIFDefn);
4209 :
4210 13060 : GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
4211 :
4212 13060 : GTIFFree(hGTIF);
4213 : }
4214 13060 : }
4215 :
4216 : /************************************************************************/
4217 : /* GetSidecarFilenameWithReplacedExtension() ¨ */
4218 : /************************************************************************/
4219 :
4220 : std::string
4221 21598 : GTiffDataset::GetSidecarFilenameWithReplacedExtension(const char *pszExt)
4222 : {
4223 21598 : if (!GDALCanFileAcceptSidecarFile(m_osFilename.c_str()))
4224 0 : return std::string();
4225 :
4226 21598 : CSLConstList papszSiblingFiles = GetSiblingFiles();
4227 : const std::string osSidecarFilenameLowerCaseExt = CPLResetExtensionSafe(
4228 43196 : m_osFilename.c_str(), CPLString(pszExt).tolower());
4229 :
4230 21598 : if (papszSiblingFiles && GDALCanReliablyUseSiblingFileList(
4231 : osSidecarFilenameLowerCaseExt.c_str()))
4232 : {
4233 21544 : const int iSibling = CSLFindString(
4234 : papszSiblingFiles,
4235 : CPLGetFilename(osSidecarFilenameLowerCaseExt.c_str()));
4236 21544 : if (iSibling >= 0)
4237 : {
4238 2018 : std::string osRet = m_osFilename.c_str();
4239 1009 : osRet.resize(m_osFilename.size() -
4240 1009 : strlen(CPLGetFilename(m_osFilename.c_str())));
4241 1009 : osRet += papszSiblingFiles[iSibling];
4242 1009 : return osRet;
4243 : }
4244 : else
4245 : {
4246 20535 : return std::string();
4247 : }
4248 : }
4249 :
4250 : VSIStatBufL sStatBuf;
4251 54 : bool bGotSidecar = VSIStatExL(osSidecarFilenameLowerCaseExt.c_str(),
4252 54 : &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
4253 :
4254 54 : if (bGotSidecar)
4255 : {
4256 1 : return osSidecarFilenameLowerCaseExt;
4257 : }
4258 53 : else if (VSIIsCaseSensitiveFS(osSidecarFilenameLowerCaseExt.c_str()))
4259 : {
4260 : const std::string osSidecarFilenameUppercaseExt = CPLResetExtensionSafe(
4261 53 : m_osFilename.c_str(), CPLString(pszExt).toupper());
4262 53 : bGotSidecar = VSIStatExL(osSidecarFilenameUppercaseExt.c_str(),
4263 : &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
4264 53 : if (bGotSidecar)
4265 : {
4266 0 : return osSidecarFilenameUppercaseExt;
4267 : }
4268 : }
4269 :
4270 53 : return std::string();
4271 : }
4272 :
4273 : /************************************************************************/
4274 : /* LookForProjectionFromXML() */
4275 : /************************************************************************/
4276 :
4277 13030 : void GTiffDataset::LookForProjectionFromXML()
4278 : {
4279 13030 : if (m_poBaseDS != nullptr)
4280 13028 : return;
4281 :
4282 : const std::string osXMLFilename =
4283 12998 : GetSidecarFilenameWithReplacedExtension("xml");
4284 12998 : if (osXMLFilename.empty())
4285 12994 : return;
4286 :
4287 4 : GByte *pabyRet = nullptr;
4288 4 : vsi_l_offset nSize = 0;
4289 4 : constexpr int nMaxSize = 10 * 1024 * 1024;
4290 4 : if (!VSIIngestFile(nullptr, osXMLFilename.c_str(), &pabyRet, &nSize,
4291 : nMaxSize))
4292 0 : return;
4293 : CPLXMLTreeCloser oXML(
4294 4 : CPLParseXMLString(reinterpret_cast<const char *>(pabyRet)));
4295 4 : VSIFree(pabyRet);
4296 4 : if (!oXML.get())
4297 0 : return;
4298 4 : const char *pszCode = CPLGetXMLValue(
4299 4 : oXML.get(), "=metadata.refSysInfo.RefSystem.refSysID.identCode.code",
4300 : "0");
4301 4 : const int nCode = atoi(pszCode);
4302 4 : if (nCode <= 0)
4303 2 : return;
4304 2 : if (nCode <= 32767)
4305 2 : m_oSRS.importFromEPSG(nCode);
4306 : else
4307 0 : m_oSRS.SetFromUserInput(CPLSPrintf("ESRI:%d", nCode));
4308 :
4309 2 : CPLFree(m_pszXMLFilename);
4310 2 : m_pszXMLFilename = CPLStrdup(osXMLFilename.c_str());
4311 : }
4312 :
4313 : /************************************************************************/
4314 : /* ApplyPamInfo() */
4315 : /* */
4316 : /* PAM Information, if available, overrides the GeoTIFF */
4317 : /* geotransform and projection definition. Check for them */
4318 : /* now. */
4319 : /************************************************************************/
4320 :
4321 14953 : void GTiffDataset::ApplyPamInfo()
4322 :
4323 : {
4324 14953 : bool bGotGTFromPAM = false;
4325 :
4326 14953 : if (m_nPAMGeorefSrcIndex >= 0 &&
4327 14953 : ((m_bGeoTransformValid &&
4328 9524 : m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
4329 5439 : m_nGeoTransformGeorefSrcIndex < 0 || !m_bGeoTransformValid))
4330 : {
4331 14943 : GDALGeoTransform pamGT;
4332 14943 : if (GDALPamDataset::GetGeoTransform(pamGT) == CE_None)
4333 : {
4334 43 : if (m_nGeoTransformGeorefSrcIndex == m_nWORLDFILEGeorefSrcIndex)
4335 : {
4336 12 : CPLFree(m_pszGeorefFilename);
4337 12 : m_pszGeorefFilename = nullptr;
4338 : }
4339 43 : m_gt = pamGT;
4340 43 : m_bGeoTransformValid = true;
4341 43 : bGotGTFromPAM = true;
4342 : }
4343 : }
4344 :
4345 14953 : if (m_nPAMGeorefSrcIndex >= 0)
4346 : {
4347 14953 : if ((m_nTABFILEGeorefSrcIndex < 0 ||
4348 14919 : m_nPAMGeorefSrcIndex < m_nTABFILEGeorefSrcIndex) &&
4349 14951 : (m_nINTERNALGeorefSrcIndex < 0 ||
4350 14937 : m_nPAMGeorefSrcIndex < m_nINTERNALGeorefSrcIndex))
4351 : {
4352 14939 : const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
4353 14939 : if (poPamSRS)
4354 : {
4355 45 : m_oSRS = *poPamSRS;
4356 45 : m_bLookedForProjection = true;
4357 : // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4358 14939 : }
4359 : }
4360 : else
4361 : {
4362 14 : if (m_nINTERNALGeorefSrcIndex >= 0)
4363 12 : LookForProjection();
4364 14 : if (m_oSRS.IsEmpty())
4365 : {
4366 8 : const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
4367 8 : if (poPamSRS)
4368 : {
4369 8 : m_oSRS = *poPamSRS;
4370 8 : m_bLookedForProjection = true;
4371 : // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4372 : }
4373 : }
4374 : }
4375 : }
4376 :
4377 : int nPamGCPCount;
4378 14953 : if (m_nPAMGeorefSrcIndex >= 0 && !oMDMD.GetMetadata("xml:ESRI") &&
4379 29925 : (nPamGCPCount = GDALPamDataset::GetGCPCount()) > 0 &&
4380 19 : ((!m_aoGCPs.empty() &&
4381 11 : m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
4382 10 : m_nGeoTransformGeorefSrcIndex < 0 || m_aoGCPs.empty()))
4383 : {
4384 17 : m_aoGCPs = gdal::GCP::fromC(GDALPamDataset::GetGCPs(), nPamGCPCount);
4385 :
4386 : // Invalidate Geotransorm got from less priority sources
4387 19 : if (!m_aoGCPs.empty() && m_bGeoTransformValid && !bGotGTFromPAM &&
4388 2 : m_nPAMGeorefSrcIndex == 0)
4389 : {
4390 2 : m_bGeoTransformValid = false;
4391 : }
4392 :
4393 : // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4394 :
4395 17 : const auto *poPamGCPSRS = GDALPamDataset::GetGCPSpatialRef();
4396 17 : if (poPamGCPSRS)
4397 15 : m_oSRS = *poPamGCPSRS;
4398 : else
4399 2 : m_oSRS.Clear();
4400 :
4401 17 : m_bLookedForProjection = true;
4402 : }
4403 :
4404 14953 : if (m_nPAMGeorefSrcIndex >= 0)
4405 : {
4406 14953 : CPLXMLNode *psValueAsXML = nullptr;
4407 14953 : CPLXMLNode *psGeodataXform = nullptr;
4408 14953 : char **papszXML = oMDMD.GetMetadata("xml:ESRI");
4409 14953 : if (CSLCount(papszXML) == 1)
4410 : {
4411 9 : psValueAsXML = CPLParseXMLString(papszXML[0]);
4412 9 : if (psValueAsXML)
4413 9 : psGeodataXform = CPLGetXMLNode(psValueAsXML, "=GeodataXform");
4414 : }
4415 :
4416 : const char *pszTIFFTagResUnit =
4417 14953 : GetMetadataItem("TIFFTAG_RESOLUTIONUNIT");
4418 14953 : const char *pszTIFFTagXRes = GetMetadataItem("TIFFTAG_XRESOLUTION");
4419 14953 : const char *pszTIFFTagYRes = GetMetadataItem("TIFFTAG_YRESOLUTION");
4420 14953 : if (psGeodataXform && pszTIFFTagXRes && pszTIFFTagYRes &&
4421 1 : pszTIFFTagResUnit && atoi(pszTIFFTagResUnit) == 2)
4422 : {
4423 : CPLXMLNode *psSourceGCPs =
4424 1 : CPLGetXMLNode(psGeodataXform, "SourceGCPs");
4425 : CPLXMLNode *psTargetGCPs =
4426 1 : CPLGetXMLNode(psGeodataXform, "TargetGCPs");
4427 1 : if (psSourceGCPs && psTargetGCPs)
4428 : {
4429 2 : std::vector<double> adfSourceGCPs, adfTargetGCPs;
4430 1 : for (CPLXMLNode *psIter = psSourceGCPs->psChild;
4431 34 : psIter != nullptr; psIter = psIter->psNext)
4432 : {
4433 33 : if (psIter->eType == CXT_Element &&
4434 32 : EQUAL(psIter->pszValue, "Double"))
4435 : {
4436 32 : adfSourceGCPs.push_back(
4437 32 : CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
4438 : }
4439 : }
4440 1 : for (CPLXMLNode *psIter = psTargetGCPs->psChild;
4441 34 : psIter != nullptr; psIter = psIter->psNext)
4442 : {
4443 33 : if (psIter->eType == CXT_Element &&
4444 32 : EQUAL(psIter->pszValue, "Double"))
4445 : {
4446 32 : adfTargetGCPs.push_back(
4447 32 : CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
4448 : }
4449 : }
4450 2 : if (adfSourceGCPs.size() == adfTargetGCPs.size() &&
4451 1 : (adfSourceGCPs.size() % 2) == 0)
4452 : {
4453 1 : const char *pszESRI_WKT = CPLGetXMLValue(
4454 : psGeodataXform, "SpatialReference.WKT", nullptr);
4455 1 : if (pszESRI_WKT)
4456 : {
4457 1 : m_bLookedForProjection = true;
4458 1 : m_oSRS.SetAxisMappingStrategy(
4459 : OAMS_TRADITIONAL_GIS_ORDER);
4460 1 : if (m_oSRS.importFromWkt(pszESRI_WKT) != OGRERR_NONE)
4461 : {
4462 0 : m_oSRS.Clear();
4463 : }
4464 : }
4465 :
4466 1 : m_aoGCPs.clear();
4467 1 : const size_t nNewGCPCount = adfSourceGCPs.size() / 2;
4468 17 : for (size_t i = 0; i < nNewGCPCount; ++i)
4469 : {
4470 : m_aoGCPs.emplace_back(
4471 : "", "",
4472 : // The origin used is the bottom left corner,
4473 : // and raw values to be multiplied by the
4474 : // TIFFTAG_XRESOLUTION/TIFFTAG_YRESOLUTION
4475 : /* pixel = */
4476 16 : adfSourceGCPs[2 * i] * CPLAtof(pszTIFFTagXRes),
4477 : /* line = */
4478 32 : nRasterYSize - adfSourceGCPs[2 * i + 1] *
4479 16 : CPLAtof(pszTIFFTagYRes),
4480 16 : /* X = */ adfTargetGCPs[2 * i],
4481 32 : /* Y = */ adfTargetGCPs[2 * i + 1]);
4482 : }
4483 :
4484 : // Invalidate Geotransform got from less priority sources
4485 2 : if (!m_aoGCPs.empty() && m_bGeoTransformValid &&
4486 2 : !bGotGTFromPAM && m_nPAMGeorefSrcIndex == 0)
4487 : {
4488 0 : m_bGeoTransformValid = false;
4489 : }
4490 : }
4491 : }
4492 : }
4493 :
4494 14953 : if (psValueAsXML)
4495 9 : CPLDestroyXMLNode(psValueAsXML);
4496 : }
4497 :
4498 : /* -------------------------------------------------------------------- */
4499 : /* Copy any PAM metadata into our GeoTIFF context, and with */
4500 : /* the PAM info overriding the GeoTIFF context. */
4501 : /* -------------------------------------------------------------------- */
4502 14953 : CSLConstList papszPamDomains = oMDMD.GetDomainList();
4503 :
4504 14981 : for (int iDomain = 0;
4505 14981 : papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
4506 : {
4507 28 : const char *pszDomain = papszPamDomains[iDomain];
4508 : // We skip IMAGE_STRUCTURE as PAM content is not supposed to modify
4509 : // it and it could cause consistency issues if doing GetMetadata("IMAGE_STRUCTURE")
4510 : // which doesn't load PAM, then GetMetadata(other_domain) and
4511 : // GetMetadata("IMAGE_STRUCTURE")
4512 28 : if (!EQUAL(pszDomain, "IMAGE_STRUCTURE"))
4513 : {
4514 : char **papszGT_MD =
4515 28 : CSLDuplicate(m_oGTiffMDMD.GetMetadata(pszDomain));
4516 28 : char **papszPAM_MD = oMDMD.GetMetadata(pszDomain);
4517 :
4518 28 : papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
4519 :
4520 28 : m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
4521 28 : CSLDestroy(papszGT_MD);
4522 : }
4523 : }
4524 :
4525 399221 : for (int i = 1; i <= GetRasterCount(); ++i)
4526 : {
4527 : GTiffRasterBand *poBand =
4528 384268 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
4529 384268 : papszPamDomains = poBand->oMDMD.GetDomainList();
4530 :
4531 384340 : for (int iDomain = 0;
4532 384340 : papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
4533 : {
4534 72 : const char *pszDomain = papszPamDomains[iDomain];
4535 : char **papszGT_MD =
4536 72 : CSLDuplicate(poBand->m_oGTiffMDMD.GetMetadata(pszDomain));
4537 72 : char **papszPAM_MD = poBand->oMDMD.GetMetadata(pszDomain);
4538 :
4539 72 : papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
4540 :
4541 72 : poBand->m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
4542 72 : CSLDestroy(papszGT_MD);
4543 : }
4544 : }
4545 :
4546 399221 : for (int i = 1; i <= nBands; ++i)
4547 : {
4548 : GTiffRasterBand *poBand =
4549 384268 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
4550 :
4551 : /* Load scale, offset and unittype from PAM if available */
4552 384268 : int nHaveOffsetScale = false;
4553 384268 : double dfScale = poBand->GDALPamRasterBand::GetScale(&nHaveOffsetScale);
4554 384268 : if (nHaveOffsetScale)
4555 : {
4556 2 : poBand->m_bHaveOffsetScale = true;
4557 2 : poBand->m_dfScale = dfScale;
4558 2 : poBand->m_dfOffset = poBand->GDALPamRasterBand::GetOffset();
4559 : }
4560 :
4561 384268 : const char *pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
4562 384268 : if (pszUnitType && pszUnitType[0])
4563 3 : poBand->m_osUnitType = pszUnitType;
4564 :
4565 : const char *pszDescription =
4566 384268 : poBand->GDALPamRasterBand::GetDescription();
4567 384268 : if (pszDescription && pszDescription[0])
4568 4 : poBand->m_osDescription = pszDescription;
4569 :
4570 : GDALColorInterp ePAMColorInterp =
4571 384268 : poBand->GDALPamRasterBand::GetColorInterpretation();
4572 384268 : if (ePAMColorInterp != GCI_Undefined)
4573 51 : poBand->m_eBandInterp = ePAMColorInterp;
4574 :
4575 384268 : if (i == 1)
4576 : {
4577 14953 : const auto poCT = poBand->GDALPamRasterBand::GetColorTable();
4578 14953 : if (poCT)
4579 : {
4580 4 : m_poColorTable.reset(poCT->Clone());
4581 : }
4582 : }
4583 : }
4584 14953 : }
4585 :
4586 : /************************************************************************/
4587 : /* OpenDir() */
4588 : /* */
4589 : /* Open a specific directory as encoded into a filename. */
4590 : /************************************************************************/
4591 :
4592 30 : GDALDataset *GTiffDataset::OpenDir(GDALOpenInfo *poOpenInfo)
4593 :
4594 : {
4595 30 : bool bAllowRGBAInterface = true;
4596 30 : const char *pszFilename = poOpenInfo->pszFilename;
4597 30 : if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
4598 : {
4599 1 : bAllowRGBAInterface = false;
4600 1 : pszFilename += strlen("GTIFF_RAW:");
4601 : }
4602 :
4603 30 : if (!STARTS_WITH_CI(pszFilename, "GTIFF_DIR:") ||
4604 30 : pszFilename[strlen("GTIFF_DIR:")] == '\0')
4605 : {
4606 5 : return nullptr;
4607 : }
4608 :
4609 : /* -------------------------------------------------------------------- */
4610 : /* Split out filename, and dir#/offset. */
4611 : /* -------------------------------------------------------------------- */
4612 25 : pszFilename += strlen("GTIFF_DIR:");
4613 25 : bool bAbsolute = false;
4614 :
4615 25 : if (STARTS_WITH_CI(pszFilename, "off:"))
4616 : {
4617 2 : bAbsolute = true;
4618 2 : pszFilename += 4;
4619 : }
4620 :
4621 25 : toff_t nOffset = atol(pszFilename);
4622 25 : pszFilename += 1;
4623 :
4624 54 : while (*pszFilename != '\0' && pszFilename[-1] != ':')
4625 29 : ++pszFilename;
4626 :
4627 25 : if (*pszFilename == '\0' || nOffset == 0)
4628 : {
4629 0 : ReportError(
4630 : pszFilename, CE_Failure, CPLE_OpenFailed,
4631 : "Unable to extract offset or filename, should take the form:\n"
4632 : "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename");
4633 0 : return nullptr;
4634 : }
4635 :
4636 25 : if (poOpenInfo->eAccess == GA_Update)
4637 : {
4638 1 : ReportError(pszFilename, CE_Warning, CPLE_AppDefined,
4639 : "Opening a specific TIFF directory is not supported in "
4640 : "update mode. Switching to read-only");
4641 : }
4642 :
4643 : /* -------------------------------------------------------------------- */
4644 : /* Try opening the dataset. */
4645 : /* -------------------------------------------------------------------- */
4646 25 : GTiffOneTimeInit();
4647 :
4648 25 : const char *pszFlag = poOpenInfo->eAccess == GA_Update ? "r+DC" : "rDOC";
4649 25 : VSILFILE *l_fpL = VSIFOpenL(pszFilename, pszFlag);
4650 25 : if (l_fpL == nullptr)
4651 0 : return nullptr;
4652 25 : TIFF *l_hTIFF = VSI_TIFFOpen(pszFilename, pszFlag, l_fpL);
4653 25 : if (l_hTIFF == nullptr)
4654 : {
4655 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
4656 0 : return nullptr;
4657 : }
4658 :
4659 : /* -------------------------------------------------------------------- */
4660 : /* If a directory was requested by index, advance to it now. */
4661 : /* -------------------------------------------------------------------- */
4662 25 : if (!bAbsolute)
4663 : {
4664 23 : const toff_t nOffsetRequested = nOffset;
4665 38 : while (nOffset > 1)
4666 : {
4667 15 : if (TIFFReadDirectory(l_hTIFF) == 0)
4668 : {
4669 0 : XTIFFClose(l_hTIFF);
4670 0 : ReportError(pszFilename, CE_Failure, CPLE_OpenFailed,
4671 : "Requested directory %lu not found.",
4672 : static_cast<long unsigned int>(nOffsetRequested));
4673 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
4674 0 : return nullptr;
4675 : }
4676 15 : nOffset--;
4677 : }
4678 :
4679 23 : nOffset = TIFFCurrentDirOffset(l_hTIFF);
4680 : }
4681 :
4682 : /* -------------------------------------------------------------------- */
4683 : /* Create a corresponding GDALDataset. */
4684 : /* -------------------------------------------------------------------- */
4685 50 : auto poDS = std::make_unique<GTiffDataset>();
4686 25 : poDS->SetDescription(poOpenInfo->pszFilename);
4687 25 : poDS->m_osFilename = pszFilename;
4688 25 : poDS->m_fpL = l_fpL;
4689 25 : poDS->m_hTIFF = l_hTIFF;
4690 25 : poDS->m_bSingleIFDOpened = true;
4691 :
4692 25 : if (!EQUAL(pszFilename, poOpenInfo->pszFilename) &&
4693 25 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "GTIFF_RAW:"))
4694 : {
4695 24 : poDS->SetPhysicalFilename(pszFilename);
4696 24 : poDS->SetSubdatasetName(poOpenInfo->pszFilename);
4697 : }
4698 :
4699 25 : if (poOpenInfo->AreSiblingFilesLoaded())
4700 25 : poDS->oOvManager.TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
4701 :
4702 25 : if (poDS->OpenOffset(l_hTIFF, nOffset, poOpenInfo->eAccess,
4703 25 : bAllowRGBAInterface, true) != CE_None)
4704 : {
4705 1 : return nullptr;
4706 : }
4707 :
4708 24 : return poDS.release();
4709 : }
4710 :
4711 : /************************************************************************/
4712 : /* ConvertTransferFunctionToString() */
4713 : /* */
4714 : /* Convert a transfer function table into a string. */
4715 : /* Used by LoadICCProfile(). */
4716 : /************************************************************************/
4717 21 : static CPLString ConvertTransferFunctionToString(const uint16_t *pTable,
4718 : uint32_t nTableEntries)
4719 : {
4720 21 : CPLString sValue;
4721 :
4722 5397 : for (uint32_t i = 0; i < nTableEntries; ++i)
4723 : {
4724 5376 : if (i > 0)
4725 5355 : sValue += ", ";
4726 5376 : sValue += CPLSPrintf("%d", static_cast<uint32_t>(pTable[i]));
4727 : }
4728 :
4729 21 : return sValue;
4730 : }
4731 :
4732 : /************************************************************************/
4733 : /* LoadICCProfile() */
4734 : /* */
4735 : /* Load ICC Profile or colorimetric data into metadata */
4736 : /************************************************************************/
4737 :
4738 5682 : void GTiffDataset::LoadICCProfile()
4739 : {
4740 5682 : if (m_bICCMetadataLoaded)
4741 5134 : return;
4742 561 : m_bICCMetadataLoaded = true;
4743 :
4744 561 : uint32_t nEmbedLen = 0;
4745 561 : uint8_t *pEmbedBuffer = nullptr;
4746 :
4747 561 : if (TIFFGetField(m_hTIFF, TIFFTAG_ICCPROFILE, &nEmbedLen, &pEmbedBuffer))
4748 : {
4749 12 : char *pszBase64Profile = CPLBase64Encode(
4750 : nEmbedLen, reinterpret_cast<const GByte *>(pEmbedBuffer));
4751 :
4752 12 : m_oGTiffMDMD.SetMetadataItem("SOURCE_ICC_PROFILE", pszBase64Profile,
4753 : "COLOR_PROFILE");
4754 :
4755 12 : CPLFree(pszBase64Profile);
4756 :
4757 12 : return;
4758 : }
4759 :
4760 : // Check for colorimetric tiff.
4761 549 : float *pCHR = nullptr;
4762 549 : float *pWP = nullptr;
4763 549 : uint16_t *pTFR = nullptr;
4764 549 : uint16_t *pTFG = nullptr;
4765 549 : uint16_t *pTFB = nullptr;
4766 549 : uint16_t *pTransferRange = nullptr;
4767 :
4768 549 : if (TIFFGetField(m_hTIFF, TIFFTAG_PRIMARYCHROMATICITIES, &pCHR))
4769 : {
4770 8 : if (TIFFGetField(m_hTIFF, TIFFTAG_WHITEPOINT, &pWP))
4771 : {
4772 24 : if (m_nBitsPerSample > 24 ||
4773 8 : !TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERFUNCTION, &pTFR,
4774 8 : &pTFG, &pTFB) ||
4775 16 : pTFR == nullptr || pTFG == nullptr || pTFB == nullptr)
4776 : {
4777 1 : return;
4778 : }
4779 :
4780 7 : const int TIFFTAG_TRANSFERRANGE = 0x0156;
4781 7 : TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERRANGE,
4782 : &pTransferRange);
4783 :
4784 : // Set all the colorimetric metadata.
4785 7 : m_oGTiffMDMD.SetMetadataItem(
4786 : "SOURCE_PRIMARIES_RED",
4787 14 : CPLString().Printf("%.9f, %.9f, 1.0",
4788 7 : static_cast<double>(pCHR[0]),
4789 7 : static_cast<double>(pCHR[1])),
4790 : "COLOR_PROFILE");
4791 7 : m_oGTiffMDMD.SetMetadataItem(
4792 : "SOURCE_PRIMARIES_GREEN",
4793 14 : CPLString().Printf("%.9f, %.9f, 1.0",
4794 7 : static_cast<double>(pCHR[2]),
4795 7 : static_cast<double>(pCHR[3])),
4796 : "COLOR_PROFILE");
4797 7 : m_oGTiffMDMD.SetMetadataItem(
4798 : "SOURCE_PRIMARIES_BLUE",
4799 14 : CPLString().Printf("%.9f, %.9f, 1.0",
4800 7 : static_cast<double>(pCHR[4]),
4801 7 : static_cast<double>(pCHR[5])),
4802 : "COLOR_PROFILE");
4803 :
4804 7 : m_oGTiffMDMD.SetMetadataItem(
4805 : "SOURCE_WHITEPOINT",
4806 14 : CPLString().Printf("%.9f, %.9f, 1.0",
4807 7 : static_cast<double>(pWP[0]),
4808 7 : static_cast<double>(pWP[1])),
4809 : "COLOR_PROFILE");
4810 :
4811 : // Set transfer function metadata.
4812 :
4813 : // Get length of table.
4814 7 : const uint32_t nTransferFunctionLength = 1 << m_nBitsPerSample;
4815 :
4816 7 : m_oGTiffMDMD.SetMetadataItem(
4817 : "TIFFTAG_TRANSFERFUNCTION_RED",
4818 14 : ConvertTransferFunctionToString(pTFR, nTransferFunctionLength),
4819 : "COLOR_PROFILE");
4820 :
4821 7 : m_oGTiffMDMD.SetMetadataItem(
4822 : "TIFFTAG_TRANSFERFUNCTION_GREEN",
4823 14 : ConvertTransferFunctionToString(pTFG, nTransferFunctionLength),
4824 : "COLOR_PROFILE");
4825 :
4826 7 : m_oGTiffMDMD.SetMetadataItem(
4827 : "TIFFTAG_TRANSFERFUNCTION_BLUE",
4828 14 : ConvertTransferFunctionToString(pTFB, nTransferFunctionLength),
4829 : "COLOR_PROFILE");
4830 :
4831 : // Set transfer range.
4832 7 : if (pTransferRange)
4833 : {
4834 0 : m_oGTiffMDMD.SetMetadataItem(
4835 : "TIFFTAG_TRANSFERRANGE_BLACK",
4836 0 : CPLString().Printf("%d, %d, %d",
4837 0 : static_cast<int>(pTransferRange[0]),
4838 0 : static_cast<int>(pTransferRange[2]),
4839 0 : static_cast<int>(pTransferRange[4])),
4840 : "COLOR_PROFILE");
4841 0 : m_oGTiffMDMD.SetMetadataItem(
4842 : "TIFFTAG_TRANSFERRANGE_WHITE",
4843 0 : CPLString().Printf("%d, %d, %d",
4844 0 : static_cast<int>(pTransferRange[1]),
4845 0 : static_cast<int>(pTransferRange[3]),
4846 0 : static_cast<int>(pTransferRange[5])),
4847 : "COLOR_PROFILE");
4848 : }
4849 : }
4850 : }
4851 : }
4852 :
4853 : /************************************************************************/
4854 : /* OpenOffset() */
4855 : /* */
4856 : /* Initialize the GTiffDataset based on a passed in file */
4857 : /* handle, and directory offset to utilize. This is called for */
4858 : /* full res, and overview pages. */
4859 : /************************************************************************/
4860 :
4861 27896 : CPLErr GTiffDataset::OpenOffset(TIFF *hTIFFIn, toff_t nDirOffsetIn,
4862 : GDALAccess eAccessIn, bool bAllowRGBAInterface,
4863 : bool bReadGeoTransform)
4864 :
4865 : {
4866 27896 : if (!hTIFFIn)
4867 0 : return CE_Failure;
4868 :
4869 27896 : eAccess = eAccessIn;
4870 :
4871 27896 : m_hTIFF = hTIFFIn;
4872 :
4873 27896 : m_nDirOffset = nDirOffsetIn;
4874 :
4875 27896 : if (!SetDirectory())
4876 0 : return CE_Failure;
4877 :
4878 : /* -------------------------------------------------------------------- */
4879 : /* Capture some information from the file that is of interest. */
4880 : /* -------------------------------------------------------------------- */
4881 27896 : uint32_t nXSize = 0;
4882 27896 : uint32_t nYSize = 0;
4883 27896 : TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
4884 27896 : TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
4885 :
4886 : // Unlikely to occur, but could happen on a disk full situation.
4887 27896 : if (nXSize == 0 || nYSize == 0)
4888 0 : return CE_Failure;
4889 :
4890 27896 : if (nXSize > INT_MAX || nYSize > INT_MAX)
4891 : {
4892 : // GDAL only supports signed 32bit dimensions.
4893 1 : ReportError(CE_Failure, CPLE_NotSupported,
4894 : "Too large image size: %u x %u", nXSize, nYSize);
4895 1 : return CE_Failure;
4896 : }
4897 27895 : nRasterXSize = nXSize;
4898 27895 : nRasterYSize = nYSize;
4899 :
4900 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &m_nSamplesPerPixel))
4901 7 : nBands = 1;
4902 : else
4903 27888 : nBands = m_nSamplesPerPixel;
4904 :
4905 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_BITSPERSAMPLE, &(m_nBitsPerSample)))
4906 7 : m_nBitsPerSample = 1;
4907 :
4908 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_PLANARCONFIG, &(m_nPlanarConfig)))
4909 0 : m_nPlanarConfig = PLANARCONFIG_CONTIG;
4910 :
4911 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_PHOTOMETRIC, &(m_nPhotometric)))
4912 10 : m_nPhotometric = PHOTOMETRIC_MINISBLACK;
4913 :
4914 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLEFORMAT, &(m_nSampleFormat)))
4915 148 : m_nSampleFormat = SAMPLEFORMAT_UINT;
4916 :
4917 27895 : if (!TIFFGetField(m_hTIFF, TIFFTAG_COMPRESSION, &(m_nCompression)))
4918 0 : m_nCompression = COMPRESSION_NONE;
4919 :
4920 31716 : if (m_nCompression != COMPRESSION_NONE &&
4921 3821 : !TIFFIsCODECConfigured(m_nCompression))
4922 : {
4923 : const char *pszCompressionMethodName =
4924 3 : GTIFFGetCompressionMethodName(m_nCompression);
4925 3 : if (pszCompressionMethodName)
4926 : {
4927 1 : ReportError(CE_Failure, CPLE_AppDefined,
4928 : "Cannot open TIFF file due to missing codec %s.",
4929 : pszCompressionMethodName);
4930 : }
4931 : else
4932 : {
4933 2 : ReportError(
4934 : CE_Failure, CPLE_AppDefined,
4935 : "Cannot open TIFF file due to missing codec of code %d.",
4936 2 : m_nCompression);
4937 : }
4938 3 : return CE_Failure;
4939 : }
4940 :
4941 : /* -------------------------------------------------------------------- */
4942 : /* YCbCr JPEG compressed images should be translated on the fly */
4943 : /* to RGB by libtiff/libjpeg unless specifically requested */
4944 : /* otherwise. */
4945 : /* -------------------------------------------------------------------- */
4946 56248 : if (m_nCompression == COMPRESSION_JPEG &&
4947 28144 : m_nPhotometric == PHOTOMETRIC_YCBCR &&
4948 252 : CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
4949 : {
4950 252 : m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE", "YCbCr",
4951 : "IMAGE_STRUCTURE");
4952 252 : int nColorMode = 0;
4953 504 : if (!TIFFGetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode) ||
4954 252 : nColorMode != JPEGCOLORMODE_RGB)
4955 : {
4956 252 : TIFFSetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4957 : }
4958 : }
4959 :
4960 : /* -------------------------------------------------------------------- */
4961 : /* Get strip/tile layout. */
4962 : /* -------------------------------------------------------------------- */
4963 27892 : if (TIFFIsTiled(m_hTIFF))
4964 : {
4965 3870 : uint32_t l_nBlockXSize = 0;
4966 3870 : uint32_t l_nBlockYSize = 0;
4967 3870 : TIFFGetField(m_hTIFF, TIFFTAG_TILEWIDTH, &(l_nBlockXSize));
4968 3870 : TIFFGetField(m_hTIFF, TIFFTAG_TILELENGTH, &(l_nBlockYSize));
4969 3870 : if (l_nBlockXSize > INT_MAX || l_nBlockYSize > INT_MAX)
4970 : {
4971 2 : ReportError(CE_Failure, CPLE_NotSupported,
4972 : "Too large block size: %u x %u", l_nBlockXSize,
4973 : l_nBlockYSize);
4974 2 : return CE_Failure;
4975 : }
4976 3868 : m_nBlockXSize = static_cast<int>(l_nBlockXSize);
4977 3868 : m_nBlockYSize = static_cast<int>(l_nBlockYSize);
4978 : }
4979 : else
4980 : {
4981 24022 : if (!TIFFGetField(m_hTIFF, TIFFTAG_ROWSPERSTRIP, &(m_nRowsPerStrip)))
4982 : {
4983 6 : ReportError(CE_Warning, CPLE_AppDefined,
4984 : "RowsPerStrip not defined ... assuming all one strip.");
4985 6 : m_nRowsPerStrip = nYSize; // Dummy value.
4986 : }
4987 :
4988 : // If the rows per strip is larger than the file we will get
4989 : // confused. libtiff internally will treat the rowsperstrip as
4990 : // the image height and it is best if we do too. (#4468)
4991 24022 : if (m_nRowsPerStrip > static_cast<uint32_t>(nRasterYSize))
4992 24 : m_nRowsPerStrip = nRasterYSize;
4993 :
4994 24022 : m_nBlockXSize = nRasterXSize;
4995 24022 : m_nBlockYSize = m_nRowsPerStrip;
4996 : }
4997 :
4998 27890 : if (!ComputeBlocksPerColRowAndBand(nBands))
4999 2 : return CE_Failure;
5000 :
5001 : /* -------------------------------------------------------------------- */
5002 : /* Should we handle this using the GTiffBitmapBand? */
5003 : /* -------------------------------------------------------------------- */
5004 27888 : bool bTreatAsBitmap = false;
5005 :
5006 27888 : if (m_nBitsPerSample == 1 && nBands == 1)
5007 : {
5008 409 : bTreatAsBitmap = true;
5009 :
5010 : // Lets treat large "one row" bitmaps using the scanline api.
5011 572 : if (!TIFFIsTiled(m_hTIFF) && m_nBlockYSize == nRasterYSize &&
5012 135 : nRasterYSize > 2000
5013 : // libtiff does not support reading JBIG files with
5014 : // TIFFReadScanline().
5015 572 : && m_nCompression != COMPRESSION_JBIG)
5016 : {
5017 11 : m_bTreatAsSplitBitmap = true;
5018 : }
5019 : }
5020 :
5021 : /* -------------------------------------------------------------------- */
5022 : /* Should we treat this via the RGBA interface? */
5023 : /* -------------------------------------------------------------------- */
5024 27888 : bool bTreatAsRGBA = false;
5025 27888 : if (
5026 : #ifdef DEBUG
5027 53648 : CPLTestBool(CPLGetConfigOption("GTIFF_FORCE_RGBA", "NO")) ||
5028 : #endif
5029 25760 : (bAllowRGBAInterface && !bTreatAsBitmap && !(m_nBitsPerSample > 8) &&
5030 19772 : (m_nPhotometric == PHOTOMETRIC_CIELAB ||
5031 19771 : m_nPhotometric == PHOTOMETRIC_LOGL ||
5032 19771 : m_nPhotometric == PHOTOMETRIC_LOGLUV ||
5033 19771 : m_nPhotometric == PHOTOMETRIC_SEPARATED ||
5034 19761 : (m_nPhotometric == PHOTOMETRIC_YCBCR &&
5035 230 : m_nCompression != COMPRESSION_JPEG))))
5036 : {
5037 35 : char szMessage[1024] = {};
5038 :
5039 35 : if (TIFFRGBAImageOK(m_hTIFF, szMessage) == 1)
5040 : {
5041 35 : const char *pszSourceColorSpace = nullptr;
5042 35 : nBands = 4;
5043 35 : switch (m_nPhotometric)
5044 : {
5045 1 : case PHOTOMETRIC_CIELAB:
5046 1 : pszSourceColorSpace = "CIELAB";
5047 1 : break;
5048 1 : case PHOTOMETRIC_LOGL:
5049 1 : pszSourceColorSpace = "LOGL";
5050 1 : break;
5051 0 : case PHOTOMETRIC_LOGLUV:
5052 0 : pszSourceColorSpace = "LOGLUV";
5053 0 : break;
5054 10 : case PHOTOMETRIC_SEPARATED:
5055 10 : pszSourceColorSpace = "CMYK";
5056 10 : break;
5057 13 : case PHOTOMETRIC_YCBCR:
5058 13 : pszSourceColorSpace = "YCbCr";
5059 13 : nBands = 3; // probably true for other photometric values
5060 13 : break;
5061 : }
5062 35 : if (pszSourceColorSpace)
5063 25 : m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE",
5064 : pszSourceColorSpace,
5065 : "IMAGE_STRUCTURE");
5066 35 : bTreatAsRGBA = true;
5067 : }
5068 : else
5069 : {
5070 0 : CPLDebug("GTiff", "TIFFRGBAImageOK says:\n%s", szMessage);
5071 : }
5072 : }
5073 :
5074 : // libtiff has various issues with OJPEG compression and chunky-strip
5075 : // support with the "classic" scanline/strip/tile interfaces, and that
5076 : // wouldn't work either, so better bail out.
5077 27888 : if (m_nCompression == COMPRESSION_OJPEG && !bTreatAsRGBA)
5078 : {
5079 0 : ReportError(
5080 : CE_Failure, CPLE_NotSupported,
5081 : "Old-JPEG compression only supported through RGBA interface, "
5082 : "which cannot be used probably because the file is corrupted");
5083 0 : return CE_Failure;
5084 : }
5085 :
5086 : // If photometric is YCbCr, scanline/strip/tile interfaces assumes that
5087 : // we are ready with downsampled data. And we are not.
5088 27888 : if (m_nCompression != COMPRESSION_JPEG &&
5089 27424 : m_nCompression != COMPRESSION_OJPEG &&
5090 27422 : m_nPhotometric == PHOTOMETRIC_YCBCR &&
5091 12 : m_nPlanarConfig == PLANARCONFIG_CONTIG && !bTreatAsRGBA)
5092 : {
5093 : uint16_t nF1, nF2;
5094 1 : TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nF1, &nF2);
5095 1 : if (nF1 != 1 || nF2 != 1)
5096 : {
5097 1 : ReportError(CE_Failure, CPLE_AppDefined,
5098 : "Cannot open TIFF file with YCbCr, subsampling and "
5099 : "BitsPerSample > 8 that is not JPEG compressed");
5100 1 : return CE_Failure;
5101 : }
5102 : }
5103 :
5104 : /* -------------------------------------------------------------------- */
5105 : /* Should we treat this via the split interface? */
5106 : /* -------------------------------------------------------------------- */
5107 51908 : if (!TIFFIsTiled(m_hTIFF) && m_nBitsPerSample == 8 &&
5108 51932 : m_nBlockYSize == nRasterYSize && nRasterYSize > 2000 && !bTreatAsRGBA &&
5109 24 : CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
5110 : {
5111 24 : m_bTreatAsSplit = true;
5112 : }
5113 :
5114 : /* -------------------------------------------------------------------- */
5115 : /* Should we treat this via the odd bits interface? */
5116 : /* -------------------------------------------------------------------- */
5117 27887 : bool bTreatAsOdd = false;
5118 27887 : if (m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
5119 : {
5120 1848 : if (m_nBitsPerSample == 24)
5121 2 : bTreatAsOdd = true;
5122 1846 : else if (m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
5123 737 : m_nBitsPerSample != 64)
5124 : {
5125 0 : ReportError(CE_Failure, CPLE_AppDefined,
5126 : "Cannot open TIFF file with SampleFormat=IEEEFP "
5127 : "and BitsPerSample=%d",
5128 0 : m_nBitsPerSample);
5129 0 : return CE_Failure;
5130 : }
5131 : }
5132 26039 : else if (!bTreatAsRGBA && !bTreatAsBitmap && m_nBitsPerSample != 8 &&
5133 4180 : m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
5134 1368 : m_nBitsPerSample != 64 && m_nBitsPerSample != 128)
5135 : {
5136 203 : bTreatAsOdd = true;
5137 : }
5138 :
5139 : /* -------------------------------------------------------------------- */
5140 : /* We can't support 'chunks' bigger than 2GB on 32 bit builds */
5141 : /* -------------------------------------------------------------------- */
5142 : #if SIZEOF_VOIDP == 4
5143 : uint64_t nChunkSize = 0;
5144 : if (m_bTreatAsSplit || m_bTreatAsSplitBitmap)
5145 : {
5146 : nChunkSize = TIFFScanlineSize64(m_hTIFF);
5147 : }
5148 : else
5149 : {
5150 : if (TIFFIsTiled(m_hTIFF))
5151 : nChunkSize = TIFFTileSize64(m_hTIFF);
5152 : else
5153 : nChunkSize = TIFFStripSize64(m_hTIFF);
5154 : }
5155 : if (bTreatAsRGBA)
5156 : {
5157 : nChunkSize =
5158 : std::max(nChunkSize,
5159 : 4 * static_cast<uint64_t>(m_nBlockXSize) * m_nBlockYSize);
5160 : }
5161 : if (nChunkSize > static_cast<uint64_t>(INT_MAX))
5162 : {
5163 : ReportError(CE_Failure, CPLE_NotSupported,
5164 : "Scanline/tile/strip size bigger than 2GB unsupported "
5165 : "on 32-bit builds.");
5166 : return CE_Failure;
5167 : }
5168 : #endif
5169 :
5170 27887 : const bool bMinIsWhite = m_nPhotometric == PHOTOMETRIC_MINISWHITE;
5171 :
5172 : /* -------------------------------------------------------------------- */
5173 : /* Check for NODATA */
5174 : /* -------------------------------------------------------------------- */
5175 27887 : char *pszText = nullptr;
5176 29322 : if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_NODATA, &pszText) &&
5177 1435 : !EQUAL(pszText, ""))
5178 : {
5179 1434 : if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
5180 120 : m_nSampleFormat == SAMPLEFORMAT_INT)
5181 : {
5182 5 : m_bNoDataSetAsInt64 = true;
5183 5 : m_nNoDataValueInt64 =
5184 5 : static_cast<int64_t>(std::strtoll(pszText, nullptr, 10));
5185 : }
5186 1429 : else if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
5187 115 : m_nSampleFormat == SAMPLEFORMAT_UINT)
5188 : {
5189 5 : m_bNoDataSetAsUInt64 = true;
5190 5 : m_nNoDataValueUInt64 =
5191 5 : static_cast<uint64_t>(std::strtoull(pszText, nullptr, 10));
5192 : }
5193 : else
5194 : {
5195 1424 : m_bNoDataSet = true;
5196 1424 : m_dfNoDataValue = CPLAtofM(pszText);
5197 1424 : if (m_nBitsPerSample == 32 &&
5198 206 : m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
5199 : {
5200 148 : m_dfNoDataValue =
5201 148 : GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
5202 148 : m_dfNoDataValue =
5203 148 : static_cast<double>(static_cast<float>(m_dfNoDataValue));
5204 : }
5205 : }
5206 : }
5207 :
5208 : /* -------------------------------------------------------------------- */
5209 : /* Capture the color table if there is one. */
5210 : /* -------------------------------------------------------------------- */
5211 27887 : unsigned short *panRed = nullptr;
5212 27887 : unsigned short *panGreen = nullptr;
5213 27887 : unsigned short *panBlue = nullptr;
5214 :
5215 51566 : if (bTreatAsRGBA || m_nBitsPerSample > 16 ||
5216 23679 : TIFFGetField(m_hTIFF, TIFFTAG_COLORMAP, &panRed, &panGreen, &panBlue) ==
5217 : 0)
5218 : {
5219 : // Build inverted palette if we have inverted photometric.
5220 : // Pixel values remains unchanged. Avoid doing this for *deep*
5221 : // data types (per #1882)
5222 27729 : if (m_nBitsPerSample <= 16 && m_nPhotometric == PHOTOMETRIC_MINISWHITE)
5223 : {
5224 13 : m_poColorTable = std::make_unique<GDALColorTable>();
5225 13 : const int nColorCount = 1 << m_nBitsPerSample;
5226 :
5227 39 : for (int iColor = 0; iColor < nColorCount; ++iColor)
5228 : {
5229 26 : const short nValue = static_cast<short>(
5230 26 : ((255 * (nColorCount - 1 - iColor)) / (nColorCount - 1)));
5231 26 : const GDALColorEntry oEntry = {nValue, nValue, nValue,
5232 26 : static_cast<short>(255)};
5233 26 : m_poColorTable->SetColorEntry(iColor, &oEntry);
5234 : }
5235 :
5236 13 : m_nPhotometric = PHOTOMETRIC_PALETTE;
5237 : }
5238 : else
5239 : {
5240 27716 : m_poColorTable.reset();
5241 : }
5242 : }
5243 : else
5244 : {
5245 158 : const int nColorCount = 1 << m_nBitsPerSample;
5246 158 : m_poColorTable = gdal::tiff_common::TIFFColorMapTagToColorTable(
5247 158 : panRed, panGreen, panBlue, nColorCount, m_nColorTableMultiplier,
5248 158 : DEFAULT_COLOR_TABLE_MULTIPLIER_257, m_bNoDataSet, m_dfNoDataValue);
5249 : }
5250 :
5251 : /* -------------------------------------------------------------------- */
5252 : /* Create band information objects. */
5253 : /* -------------------------------------------------------------------- */
5254 758523 : for (int iBand = 0; iBand < nBands; ++iBand)
5255 : {
5256 730636 : if (bTreatAsRGBA)
5257 127 : SetBand(iBand + 1,
5258 254 : std::make_unique<GTiffRGBABand>(this, iBand + 1));
5259 730509 : else if (m_bTreatAsSplitBitmap)
5260 11 : SetBand(iBand + 1,
5261 22 : std::make_unique<GTiffSplitBitmapBand>(this, iBand + 1));
5262 730498 : else if (m_bTreatAsSplit)
5263 131118 : SetBand(iBand + 1,
5264 262236 : std::make_unique<GTiffSplitBand>(this, iBand + 1));
5265 599380 : else if (bTreatAsBitmap)
5266 398 : SetBand(iBand + 1,
5267 796 : std::make_unique<GTiffBitmapBand>(this, iBand + 1));
5268 598982 : else if (bTreatAsOdd)
5269 346 : SetBand(iBand + 1,
5270 692 : std::make_unique<GTiffOddBitsBand>(this, iBand + 1));
5271 : else
5272 598636 : SetBand(iBand + 1,
5273 1197270 : std::make_unique<GTiffRasterBand>(this, iBand + 1));
5274 : }
5275 :
5276 27887 : if (GetRasterBand(1)->GetRasterDataType() == GDT_Unknown)
5277 : {
5278 1 : ReportError(CE_Failure, CPLE_NotSupported,
5279 : "Unsupported TIFF configuration: BitsPerSample(=%d) and "
5280 : "SampleType(=%d)",
5281 1 : m_nBitsPerSample, m_nSampleFormat);
5282 1 : return CE_Failure;
5283 : }
5284 :
5285 27886 : m_bReadGeoTransform = bReadGeoTransform;
5286 :
5287 : /* -------------------------------------------------------------------- */
5288 : /* Capture some other potentially interesting information. */
5289 : /* -------------------------------------------------------------------- */
5290 27886 : char szWorkMDI[200] = {};
5291 27886 : uint16_t nShort = 0;
5292 :
5293 27886 : const auto *pasTIFFTags = GetTIFFTags();
5294 418290 : for (size_t iTag = 0; pasTIFFTags[iTag].pszTagName; ++iTag)
5295 : {
5296 390404 : if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING)
5297 : {
5298 223088 : if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &pszText))
5299 128 : m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
5300 : pszText);
5301 : }
5302 167316 : else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT)
5303 : {
5304 55772 : float fVal = 0.0;
5305 55772 : if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &fVal))
5306 : {
5307 172 : CPLsnprintf(szWorkMDI, sizeof(szWorkMDI), "%.8g",
5308 : static_cast<double>(fVal));
5309 172 : m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
5310 : szWorkMDI);
5311 : }
5312 : }
5313 111544 : else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT &&
5314 83658 : pasTIFFTags[iTag].nTagVal != TIFFTAG_RESOLUTIONUNIT)
5315 : {
5316 55772 : if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nShort))
5317 : {
5318 8 : snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
5319 8 : m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
5320 : szWorkMDI);
5321 : }
5322 : }
5323 55772 : else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_BYTE_STRING)
5324 : {
5325 27886 : uint32_t nCount = 0;
5326 27886 : if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nCount,
5327 27886 : &pszText))
5328 : {
5329 2 : std::string osStr;
5330 1 : osStr.assign(pszText, nCount);
5331 1 : m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
5332 : osStr.c_str());
5333 : }
5334 : }
5335 : }
5336 :
5337 27886 : if (TIFFGetField(m_hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort))
5338 : {
5339 88 : if (nShort == RESUNIT_NONE)
5340 34 : snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (unitless)", nShort);
5341 54 : else if (nShort == RESUNIT_INCH)
5342 53 : snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/inch)", nShort);
5343 1 : else if (nShort == RESUNIT_CENTIMETER)
5344 1 : snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/cm)", nShort);
5345 : else
5346 0 : snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
5347 88 : m_oGTiffMDMD.SetMetadataItem("TIFFTAG_RESOLUTIONUNIT", szWorkMDI);
5348 : }
5349 :
5350 27886 : int nTagSize = 0;
5351 27886 : void *pData = nullptr;
5352 27886 : if (TIFFGetField(m_hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData))
5353 : {
5354 35 : char *pszXMP = static_cast<char *>(VSI_MALLOC_VERBOSE(nTagSize + 1));
5355 35 : if (pszXMP)
5356 : {
5357 35 : memcpy(pszXMP, pData, nTagSize);
5358 35 : pszXMP[nTagSize] = '\0';
5359 :
5360 35 : char *apszMDList[2] = {pszXMP, nullptr};
5361 35 : m_oGTiffMDMD.SetMetadata(apszMDList, "xml:XMP");
5362 :
5363 35 : CPLFree(pszXMP);
5364 : }
5365 : }
5366 :
5367 27886 : if (m_nCompression != COMPRESSION_NONE)
5368 : {
5369 : const char *pszCompressionMethodName =
5370 3818 : GTIFFGetCompressionMethodName(m_nCompression);
5371 3818 : if (pszCompressionMethodName)
5372 : {
5373 3818 : m_oGTiffMDMD.SetMetadataItem(
5374 : "COMPRESSION", pszCompressionMethodName, "IMAGE_STRUCTURE");
5375 : }
5376 : else
5377 : {
5378 0 : CPLString oComp;
5379 0 : oComp.Printf("%d", m_nCompression);
5380 0 : m_oGTiffMDMD.SetMetadataItem("COMPRESSION", oComp.c_str());
5381 : }
5382 : }
5383 :
5384 27886 : if (m_nCompression == COMPRESSION_JPEG &&
5385 464 : m_nPhotometric == PHOTOMETRIC_YCBCR)
5386 : {
5387 252 : m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "YCbCr JPEG",
5388 : "IMAGE_STRUCTURE");
5389 : }
5390 27634 : else if (m_nCompression == COMPRESSION_LERC)
5391 : {
5392 317 : uint32_t nLercParamCount = 0;
5393 317 : uint32_t *panLercParams = nullptr;
5394 317 : if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_PARAMETERS, &nLercParamCount,
5395 634 : &panLercParams) &&
5396 317 : nLercParamCount == 2)
5397 : {
5398 317 : memcpy(m_anLercAddCompressionAndVersion, panLercParams,
5399 : sizeof(m_anLercAddCompressionAndVersion));
5400 : }
5401 :
5402 317 : uint32_t nAddVersion = LERC_ADD_COMPRESSION_NONE;
5403 634 : if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_ADD_COMPRESSION, &nAddVersion) &&
5404 317 : nAddVersion != LERC_ADD_COMPRESSION_NONE)
5405 : {
5406 173 : if (nAddVersion == LERC_ADD_COMPRESSION_DEFLATE)
5407 : {
5408 90 : m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_DEFLATE",
5409 : "IMAGE_STRUCTURE");
5410 : }
5411 83 : else if (nAddVersion == LERC_ADD_COMPRESSION_ZSTD)
5412 : {
5413 83 : m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_ZSTD",
5414 : "IMAGE_STRUCTURE");
5415 : }
5416 : }
5417 317 : uint32_t nLercVersion = LERC_VERSION_2_4;
5418 317 : if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_VERSION, &nLercVersion))
5419 : {
5420 317 : if (nLercVersion == LERC_VERSION_2_4)
5421 : {
5422 317 : m_oGTiffMDMD.SetMetadataItem("LERC_VERSION", "2.4",
5423 : "IMAGE_STRUCTURE");
5424 : }
5425 : else
5426 : {
5427 0 : ReportError(CE_Warning, CPLE_AppDefined,
5428 : "Unknown Lerc version: %d", nLercVersion);
5429 : }
5430 : }
5431 : }
5432 :
5433 27886 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1)
5434 3055 : m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
5435 : else
5436 24831 : m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
5437 :
5438 27886 : if ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt8 &&
5439 21768 : m_nBitsPerSample != 8) ||
5440 27392 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 &&
5441 56407 : m_nBitsPerSample != 16) ||
5442 27305 : ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 ||
5443 26919 : GetRasterBand(1)->GetRasterDataType() == GDT_Float32) &&
5444 1367 : m_nBitsPerSample != 32))
5445 : {
5446 1372 : for (int i = 0; i < nBands; ++i)
5447 758 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i + 1))
5448 758 : ->m_oGTiffMDMD.SetMetadataItem(
5449 : "NBITS",
5450 1516 : CPLString().Printf("%d",
5451 758 : static_cast<int>(m_nBitsPerSample)),
5452 : "IMAGE_STRUCTURE");
5453 : }
5454 :
5455 27886 : if (bMinIsWhite)
5456 15 : m_oGTiffMDMD.SetMetadataItem("MINISWHITE", "YES", "IMAGE_STRUCTURE");
5457 :
5458 27886 : if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
5459 : {
5460 6718 : auto psRoot = CPLXMLTreeCloser(CPLParseXMLString(pszText));
5461 : const CPLXMLNode *psItem =
5462 3359 : psRoot.get() ? CPLGetXMLNode(psRoot.get(), "=GDALMetadata")
5463 3359 : : nullptr;
5464 3359 : if (psItem)
5465 3359 : psItem = psItem->psChild;
5466 3359 : bool bMaxZErrorFound = false;
5467 3359 : bool bMaxZErrorOverviewFound = false;
5468 18413 : for (; psItem != nullptr; psItem = psItem->psNext)
5469 : {
5470 :
5471 15054 : if (psItem->eType != CXT_Element ||
5472 15054 : !EQUAL(psItem->pszValue, "Item"))
5473 0 : continue;
5474 :
5475 15054 : const char *pszKey = CPLGetXMLValue(psItem, "name", nullptr);
5476 15054 : const char *pszValue = CPLGetXMLValue(psItem, nullptr, nullptr);
5477 15054 : int nBand = atoi(CPLGetXMLValue(psItem, "sample", "-1"));
5478 15054 : if (nBand < -1 || nBand > nBands - 1)
5479 0 : continue;
5480 15054 : nBand++;
5481 15054 : const char *pszRole = CPLGetXMLValue(psItem, "role", "");
5482 15054 : const char *pszDomain = CPLGetXMLValue(psItem, "domain", "");
5483 :
5484 15054 : if (nBand > 0 && pszKey &&
5485 3884 : strcmp(pszKey, DEFAULT_RASTER_ATTRIBUTE_TABLE) == 0 &&
5486 24 : strcmp(pszRole, RAT_ROLE) == 0)
5487 : {
5488 24 : const CPLXMLNode *psValueNode = psItem->psChild;
5489 96 : while (psValueNode && psValueNode->eType != CXT_Element)
5490 72 : psValueNode = psValueNode->psNext;
5491 24 : if (psValueNode && psValueNode->eType == CXT_Element)
5492 : {
5493 : auto poRAT =
5494 48 : std::make_unique<GDALDefaultRasterAttributeTable>();
5495 24 : if (poRAT->XMLInit(psValueNode, nullptr) == CE_None)
5496 : {
5497 : GTiffRasterBand *poBand =
5498 24 : cpl::down_cast<GTiffRasterBand *>(
5499 : GetRasterBand(nBand));
5500 24 : if (poBand != nullptr)
5501 : {
5502 24 : poBand->m_poRAT = std::move(poRAT);
5503 24 : poBand->m_bRATSet = true;
5504 : }
5505 : }
5506 : }
5507 : }
5508 :
5509 15054 : if (pszKey == nullptr || pszValue == nullptr)
5510 311 : continue;
5511 14743 : if (EQUAL(pszDomain, "IMAGE_STRUCTURE"))
5512 : {
5513 848 : if (EQUAL(pszKey, "OVERVIEW_RESAMPLING"))
5514 : {
5515 104 : m_oGTiffMDMD.SetMetadataItem(pszKey, pszValue,
5516 : "IMAGE_STRUCTURE");
5517 : }
5518 744 : else if (EQUAL(pszKey, "INTERLEAVE"))
5519 : {
5520 39 : if (EQUAL(pszValue, "TILE"))
5521 : {
5522 17 : m_bTileInterleave = true;
5523 17 : m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "TILE",
5524 : "IMAGE_STRUCTURE");
5525 : }
5526 : else
5527 : {
5528 22 : CPLDebug("GTiff",
5529 : "Unhandled INTERLEAVE=%s found in "
5530 : "GDAL_METADATA tag",
5531 : pszValue);
5532 : }
5533 : }
5534 705 : else if (m_nCompression == COMPRESSION_WEBP &&
5535 73 : EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
5536 : {
5537 13 : if (EQUAL(pszValue, "LOSSLESS"))
5538 13 : m_bWebPLossless = true;
5539 0 : else if (EQUAL(pszValue, "LOSSY"))
5540 0 : m_bWebPLossless = false;
5541 : }
5542 692 : else if (m_nCompression == COMPRESSION_WEBP &&
5543 60 : EQUAL(pszKey, "WEBP_LEVEL"))
5544 : {
5545 60 : const int nLevel = atoi(pszValue);
5546 60 : if (nLevel >= 1 && nLevel <= 100)
5547 : {
5548 60 : m_oGTiffMDMD.SetMetadataItem(
5549 : "COMPRESSION_REVERSIBILITY", "LOSSY",
5550 : "IMAGE_STRUCTURE");
5551 60 : m_bWebPLossless = false;
5552 60 : m_nWebPLevel = static_cast<signed char>(nLevel);
5553 60 : }
5554 : }
5555 632 : else if (m_nCompression == COMPRESSION_LERC &&
5556 196 : EQUAL(pszKey, "MAX_Z_ERROR"))
5557 : {
5558 28 : bMaxZErrorFound = true;
5559 28 : m_dfMaxZError = CPLAtof(pszValue);
5560 : }
5561 604 : else if (m_nCompression == COMPRESSION_LERC &&
5562 168 : EQUAL(pszKey, "MAX_Z_ERROR_OVERVIEW"))
5563 : {
5564 4 : bMaxZErrorOverviewFound = true;
5565 4 : m_dfMaxZErrorOverview = CPLAtof(pszValue);
5566 : }
5567 : #if HAVE_JXL
5568 600 : else if ((m_nCompression == COMPRESSION_JXL ||
5569 598 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
5570 420 : EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
5571 : {
5572 169 : if (EQUAL(pszValue, "LOSSLESS"))
5573 169 : m_bJXLLossless = true;
5574 0 : else if (EQUAL(pszValue, "LOSSY"))
5575 0 : m_bJXLLossless = false;
5576 : }
5577 431 : else if ((m_nCompression == COMPRESSION_JXL ||
5578 430 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
5579 251 : EQUAL(pszKey, "JXL_DISTANCE"))
5580 : {
5581 39 : const double dfVal = CPLAtof(pszValue);
5582 39 : if (dfVal > 0 && dfVal <= 15)
5583 : {
5584 39 : m_oGTiffMDMD.SetMetadataItem(
5585 : "COMPRESSION_REVERSIBILITY", "LOSSY",
5586 : "IMAGE_STRUCTURE");
5587 39 : m_bJXLLossless = false;
5588 39 : m_fJXLDistance = static_cast<float>(dfVal);
5589 39 : }
5590 : }
5591 392 : else if ((m_nCompression == COMPRESSION_JXL ||
5592 391 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
5593 212 : EQUAL(pszKey, "JXL_ALPHA_DISTANCE"))
5594 : {
5595 4 : const double dfVal = CPLAtof(pszValue);
5596 4 : if (dfVal > 0 && dfVal <= 15)
5597 : {
5598 0 : m_oGTiffMDMD.SetMetadataItem(
5599 : "COMPRESSION_REVERSIBILITY", "LOSSY",
5600 : "IMAGE_STRUCTURE");
5601 0 : m_fJXLAlphaDistance = static_cast<float>(dfVal);
5602 4 : }
5603 : }
5604 388 : else if ((m_nCompression == COMPRESSION_JXL ||
5605 387 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
5606 208 : EQUAL(pszKey, "JXL_EFFORT"))
5607 : {
5608 208 : const int nEffort = atoi(pszValue);
5609 208 : if (nEffort >= 1 && nEffort <= 9)
5610 : {
5611 208 : m_nJXLEffort = nEffort;
5612 208 : }
5613 : }
5614 : #endif
5615 : else
5616 : {
5617 180 : continue;
5618 : }
5619 : }
5620 :
5621 14563 : bool bIsXMLOrJSON = false;
5622 :
5623 14563 : if (STARTS_WITH_CI(pszDomain, "xml:") ||
5624 14561 : STARTS_WITH_CI(pszDomain, "json:"))
5625 22 : bIsXMLOrJSON = true;
5626 :
5627 : // Note: this un-escaping should not normally be done, as the
5628 : // deserialization of the tree from XML also does it, so we end up
5629 : // width double XML escaping, but keep it for backward
5630 : // compatibility.
5631 : char *pszUnescapedValue =
5632 14563 : CPLUnescapeString(pszValue, nullptr, CPLES_XML);
5633 14563 : if (nBand == 0)
5634 : {
5635 10708 : if (bIsXMLOrJSON)
5636 : {
5637 22 : char *apszMD[2] = {pszUnescapedValue, nullptr};
5638 22 : m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
5639 : }
5640 : else
5641 : {
5642 10686 : m_oGTiffMDMD.SetMetadataItem(pszKey, pszUnescapedValue,
5643 : pszDomain);
5644 : }
5645 : }
5646 : else
5647 : {
5648 : GTiffRasterBand *poBand =
5649 3855 : cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
5650 3855 : if (poBand != nullptr)
5651 : {
5652 3855 : if (EQUAL(pszRole, "scale"))
5653 : {
5654 40 : poBand->m_bHaveOffsetScale = true;
5655 40 : poBand->m_dfScale = CPLAtofM(pszUnescapedValue);
5656 : }
5657 3815 : else if (EQUAL(pszRole, "offset"))
5658 : {
5659 40 : poBand->m_bHaveOffsetScale = true;
5660 40 : poBand->m_dfOffset = CPLAtofM(pszUnescapedValue);
5661 : }
5662 3775 : else if (EQUAL(pszRole, "unittype"))
5663 : {
5664 308 : poBand->m_osUnitType = pszUnescapedValue;
5665 : }
5666 3467 : else if (EQUAL(pszRole, "description"))
5667 : {
5668 73 : poBand->m_osDescription = pszUnescapedValue;
5669 : }
5670 3394 : else if (EQUAL(pszRole, "colorinterp"))
5671 : {
5672 644 : if (EQUAL(pszUnescapedValue, "undefined"))
5673 192 : poBand->m_eBandInterp = GCI_Undefined;
5674 : else
5675 : {
5676 452 : poBand->m_eBandInterp =
5677 452 : GDALGetColorInterpretationByName(
5678 : pszUnescapedValue);
5679 452 : if (poBand->m_eBandInterp == GCI_Undefined)
5680 : {
5681 1 : poBand->m_oGTiffMDMD.SetMetadataItem(
5682 : "COLOR_INTERPRETATION", pszUnescapedValue);
5683 : }
5684 : }
5685 : }
5686 : else
5687 : {
5688 2750 : if (bIsXMLOrJSON)
5689 : {
5690 0 : char *apszMD[2] = {pszUnescapedValue, nullptr};
5691 0 : poBand->m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
5692 : }
5693 : else
5694 : {
5695 2750 : poBand->m_oGTiffMDMD.SetMetadataItem(
5696 : pszKey, pszUnescapedValue, pszDomain);
5697 : }
5698 : }
5699 : }
5700 : }
5701 14563 : CPLFree(pszUnescapedValue);
5702 : }
5703 :
5704 3359 : if (bMaxZErrorFound && !bMaxZErrorOverviewFound)
5705 : {
5706 27 : m_dfMaxZErrorOverview = m_dfMaxZError;
5707 : }
5708 : }
5709 :
5710 27886 : if (m_bStreamingIn)
5711 : {
5712 7 : toff_t *panOffsets = nullptr;
5713 7 : TIFFGetField(m_hTIFF,
5714 7 : TIFFIsTiled(m_hTIFF) ? TIFFTAG_TILEOFFSETS
5715 : : TIFFTAG_STRIPOFFSETS,
5716 : &panOffsets);
5717 7 : if (panOffsets)
5718 : {
5719 7 : int nBlockCount = TIFFIsTiled(m_hTIFF)
5720 7 : ? TIFFNumberOfTiles(m_hTIFF)
5721 6 : : TIFFNumberOfStrips(m_hTIFF);
5722 1437 : for (int i = 1; i < nBlockCount; ++i)
5723 : {
5724 1431 : if (panOffsets[i] < panOffsets[i - 1])
5725 : {
5726 1 : m_oGTiffMDMD.SetMetadataItem("UNORDERED_BLOCKS", "YES",
5727 : "TIFF");
5728 1 : CPLDebug("GTIFF",
5729 : "Offset of block %d is lower than previous block. "
5730 : "Reader must be careful",
5731 : i);
5732 1 : break;
5733 : }
5734 : }
5735 : }
5736 : }
5737 :
5738 27886 : if (m_nCompression == COMPRESSION_JPEG)
5739 : {
5740 464 : bool bHasQuantizationTable = false;
5741 464 : bool bHasHuffmanTable = false;
5742 : int nQuality =
5743 464 : GuessJPEGQuality(bHasQuantizationTable, bHasHuffmanTable);
5744 464 : if (nQuality > 0)
5745 : {
5746 440 : m_oGTiffMDMD.SetMetadataItem(
5747 : "JPEG_QUALITY", CPLSPrintf("%d", nQuality), "IMAGE_STRUCTURE");
5748 440 : int nJpegTablesMode = JPEGTABLESMODE_QUANT;
5749 440 : if (bHasHuffmanTable)
5750 : {
5751 91 : nJpegTablesMode |= JPEGTABLESMODE_HUFF;
5752 : }
5753 440 : m_oGTiffMDMD.SetMetadataItem("JPEGTABLESMODE",
5754 : CPLSPrintf("%d", nJpegTablesMode),
5755 : "IMAGE_STRUCTURE");
5756 : }
5757 464 : if (eAccess == GA_Update)
5758 : {
5759 161 : SetJPEGQualityAndTablesModeFromFile(nQuality, bHasQuantizationTable,
5760 : bHasHuffmanTable);
5761 : }
5762 : }
5763 31066 : else if (eAccess == GA_Update &&
5764 3644 : m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
5765 : "IMAGE_STRUCTURE") == nullptr)
5766 : {
5767 3537 : if (m_nCompression == COMPRESSION_WEBP)
5768 : {
5769 : const char *pszReversibility =
5770 37 : GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
5771 37 : if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
5772 : {
5773 2 : m_bWebPLossless = true;
5774 : }
5775 35 : else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
5776 : {
5777 8 : m_bWebPLossless = false;
5778 : }
5779 : }
5780 : #ifdef HAVE_JXL
5781 3500 : else if (m_nCompression == COMPRESSION_JXL ||
5782 3500 : m_nCompression == COMPRESSION_JXL_DNG_1_7)
5783 : {
5784 : const char *pszReversibility =
5785 16 : GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
5786 16 : if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
5787 : {
5788 2 : m_bJXLLossless = true;
5789 : }
5790 14 : else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
5791 : {
5792 6 : m_bJXLLossless = false;
5793 : }
5794 : }
5795 : #endif
5796 : }
5797 :
5798 27886 : if (GTIFFSupportsPredictor(m_nCompression))
5799 : {
5800 2181 : uint16_t nPredictor = 0;
5801 4330 : if (TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &nPredictor) &&
5802 2149 : nPredictor > 1)
5803 : {
5804 95 : m_oGTiffMDMD.SetMetadataItem(
5805 : "PREDICTOR", CPLSPrintf("%d", nPredictor), "IMAGE_STRUCTURE");
5806 : }
5807 : }
5808 :
5809 27886 : CPLAssert(m_bReadGeoTransform == bReadGeoTransform);
5810 27886 : CPLAssert(!m_bMetadataChanged);
5811 27886 : m_bMetadataChanged = false;
5812 :
5813 27886 : return CE_None;
5814 : }
5815 :
5816 : /************************************************************************/
5817 : /* GetSiblingFiles() */
5818 : /************************************************************************/
5819 :
5820 354247 : CSLConstList GTiffDataset::GetSiblingFiles()
5821 : {
5822 354247 : if (m_poBaseDS != nullptr)
5823 0 : return nullptr;
5824 :
5825 354247 : if (m_bHasGotSiblingFiles)
5826 : {
5827 331528 : return oOvManager.GetSiblingFiles();
5828 : }
5829 :
5830 22719 : m_bHasGotSiblingFiles = true;
5831 : const int nMaxFiles =
5832 22719 : atoi(CPLGetConfigOption("GDAL_READDIR_LIMIT_ON_OPEN", "1000"));
5833 45438 : const std::string osDirname = CPLGetDirnameSafe(m_osFilename.c_str());
5834 45438 : CPLStringList aosSiblingFiles(VSIReadDirEx(osDirname.c_str(), nMaxFiles));
5835 22719 : if (nMaxFiles > 0 && aosSiblingFiles.size() > nMaxFiles)
5836 : {
5837 1 : CPLDebug("GTiff", "GDAL_READDIR_LIMIT_ON_OPEN reached on %s",
5838 : osDirname.c_str());
5839 1 : aosSiblingFiles.clear();
5840 : }
5841 22719 : oOvManager.TransferSiblingFiles(aosSiblingFiles.StealList());
5842 :
5843 22719 : return oOvManager.GetSiblingFiles();
5844 : }
5845 :
5846 : /************************************************************************/
5847 : /* IdentifyAuthorizedGeoreferencingSources() */
5848 : /************************************************************************/
5849 :
5850 30158 : void GTiffDataset::IdentifyAuthorizedGeoreferencingSources()
5851 : {
5852 30158 : if (m_bHasIdentifiedAuthorizedGeoreferencingSources)
5853 13035 : return;
5854 17123 : m_bHasIdentifiedAuthorizedGeoreferencingSources = true;
5855 : CPLString osGeorefSources = CSLFetchNameValueDef(
5856 17123 : papszOpenOptions, "GEOREF_SOURCES",
5857 : CPLGetConfigOption("GDAL_GEOREF_SOURCES",
5858 34246 : "PAM,INTERNAL,TABFILE,WORLDFILE,XML"));
5859 17123 : char **papszTokens = CSLTokenizeString2(osGeorefSources, ",", 0);
5860 17123 : m_nPAMGeorefSrcIndex =
5861 17123 : static_cast<signed char>(CSLFindString(papszTokens, "PAM"));
5862 17123 : m_nINTERNALGeorefSrcIndex =
5863 17123 : static_cast<signed char>(CSLFindString(papszTokens, "INTERNAL"));
5864 17123 : m_nTABFILEGeorefSrcIndex =
5865 17123 : static_cast<signed char>(CSLFindString(papszTokens, "TABFILE"));
5866 17123 : m_nWORLDFILEGeorefSrcIndex =
5867 17123 : static_cast<signed char>(CSLFindString(papszTokens, "WORLDFILE"));
5868 17123 : m_nXMLGeorefSrcIndex =
5869 17123 : static_cast<signed char>(CSLFindString(papszTokens, "XML"));
5870 17123 : CSLDestroy(papszTokens);
5871 : }
5872 :
5873 : /************************************************************************/
5874 : /* LoadGeoreferencingAndPamIfNeeded() */
5875 : /************************************************************************/
5876 :
5877 3513210 : void GTiffDataset::LoadGeoreferencingAndPamIfNeeded()
5878 :
5879 : {
5880 3513210 : if (!m_bReadGeoTransform && !m_bLoadPam)
5881 3496120 : return;
5882 17091 : if (m_poBaseDS != nullptr)
5883 0 : return;
5884 :
5885 17091 : IdentifyAuthorizedGeoreferencingSources();
5886 :
5887 : /* -------------------------------------------------------------------- */
5888 : /* Get the transform or gcps from the GeoTIFF file. */
5889 : /* -------------------------------------------------------------------- */
5890 17091 : if (m_bReadGeoTransform)
5891 : {
5892 17091 : m_bReadGeoTransform = false;
5893 :
5894 17091 : char *pszTabWKT = nullptr;
5895 17091 : double *padfTiePoints = nullptr;
5896 17091 : double *padfScale = nullptr;
5897 17091 : double *padfMatrix = nullptr;
5898 17091 : uint16_t nCount = 0;
5899 17091 : bool bPixelIsPoint = false;
5900 17091 : unsigned short nRasterType = 0;
5901 17091 : bool bPointGeoIgnore = false;
5902 :
5903 34182 : std::set<signed char> aoSetPriorities;
5904 17091 : if (m_nINTERNALGeorefSrcIndex >= 0)
5905 17065 : aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
5906 17091 : if (m_nTABFILEGeorefSrcIndex >= 0)
5907 17039 : aoSetPriorities.insert(m_nTABFILEGeorefSrcIndex);
5908 17091 : if (m_nWORLDFILEGeorefSrcIndex >= 0)
5909 17055 : aoSetPriorities.insert(m_nWORLDFILEGeorefSrcIndex);
5910 34716 : for (const auto nIndex : aoSetPriorities)
5911 : {
5912 28833 : if (m_nINTERNALGeorefSrcIndex == nIndex)
5913 : {
5914 : GTIF *psGTIF =
5915 17057 : GTiffDataset::GTIFNew(m_hTIFF); // How expensive this is?
5916 :
5917 17057 : if (psGTIF)
5918 : {
5919 17057 : if (GDALGTIFKeyGetSHORT(psGTIF, GTRasterTypeGeoKey,
5920 27292 : &nRasterType, 0, 1) == 1 &&
5921 10235 : nRasterType == static_cast<short>(RasterPixelIsPoint))
5922 : {
5923 278 : bPixelIsPoint = true;
5924 278 : bPointGeoIgnore = CPLTestBool(CPLGetConfigOption(
5925 : "GTIFF_POINT_GEO_IGNORE", "FALSE"));
5926 : }
5927 :
5928 17057 : GTIFFree(psGTIF);
5929 : }
5930 :
5931 17057 : m_gt = GDALGeoTransform();
5932 :
5933 17057 : uint16_t nCountScale = 0;
5934 17057 : if (TIFFGetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE, &nCountScale,
5935 11002 : &padfScale) &&
5936 28059 : nCountScale >= 2 && padfScale[0] != 0.0 &&
5937 11002 : padfScale[1] != 0.0)
5938 : {
5939 11002 : m_gt.xscale = padfScale[0];
5940 11002 : if (padfScale[1] < 0)
5941 : {
5942 3 : const char *pszOptionVal = CPLGetConfigOption(
5943 : "GTIFF_HONOUR_NEGATIVE_SCALEY", nullptr);
5944 3 : if (pszOptionVal == nullptr)
5945 : {
5946 1 : ReportError(
5947 : CE_Warning, CPLE_AppDefined,
5948 : "File with negative value for ScaleY in "
5949 : "GeoPixelScale tag. This is rather "
5950 : "unusual. GDAL, contrary to the GeoTIFF "
5951 : "specification, assumes that the file "
5952 : "was intended to be north-up, and will "
5953 : "treat this file as if ScaleY was "
5954 : "positive. You may override this behavior "
5955 : "by setting the GTIFF_HONOUR_NEGATIVE_SCALEY "
5956 : "configuration option to YES");
5957 1 : m_gt.yscale = padfScale[1];
5958 : }
5959 2 : else if (CPLTestBool(pszOptionVal))
5960 : {
5961 1 : m_gt.yscale = -padfScale[1];
5962 : }
5963 : else
5964 : {
5965 1 : m_gt.yscale = padfScale[1];
5966 : }
5967 : }
5968 : else
5969 : {
5970 10999 : m_gt.yscale = -padfScale[1];
5971 : }
5972 :
5973 11002 : if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
5974 22004 : &padfTiePoints) &&
5975 11002 : nCount >= 6)
5976 : {
5977 11002 : m_gt.xorig =
5978 11002 : padfTiePoints[3] - padfTiePoints[0] * m_gt.xscale;
5979 11002 : m_gt.yorig =
5980 11002 : padfTiePoints[4] - padfTiePoints[1] * m_gt.yscale;
5981 :
5982 11002 : if (bPixelIsPoint && !bPointGeoIgnore)
5983 : {
5984 241 : m_gt.xorig -= (m_gt.xscale * 0.5 + m_gt.xrot * 0.5);
5985 241 : m_gt.yorig -= (m_gt.yrot * 0.5 + m_gt.yscale * 0.5);
5986 : }
5987 :
5988 11002 : m_bGeoTransformValid = true;
5989 11002 : m_nGeoTransformGeorefSrcIndex = nIndex;
5990 :
5991 18305 : if (nCountScale >= 3 && GetRasterCount() == 1 &&
5992 7303 : (padfScale[2] != 0.0 || padfTiePoints[2] != 0.0 ||
5993 7277 : padfTiePoints[5] != 0.0))
5994 : {
5995 28 : LookForProjection();
5996 28 : if (!m_oSRS.IsEmpty() && m_oSRS.IsVertical())
5997 : {
5998 : /* modelTiePointTag = (pixel, line, z0, X, Y,
5999 : * Z0) */
6000 : /* thus Z(some_point) = (z(some_point) - z0) *
6001 : * scaleZ + Z0 */
6002 : /* equivalently written as */
6003 : /* Z(some_point) = z(some_point) * scaleZ +
6004 : * offsetZ with */
6005 : /* offsetZ = - z0 * scaleZ + Z0 */
6006 18 : double dfScale = padfScale[2];
6007 18 : double dfOffset = -padfTiePoints[2] * dfScale +
6008 18 : padfTiePoints[5];
6009 : GTiffRasterBand *poBand =
6010 18 : cpl::down_cast<GTiffRasterBand *>(
6011 : GetRasterBand(1));
6012 18 : poBand->m_bHaveOffsetScale = true;
6013 18 : poBand->m_dfScale = dfScale;
6014 18 : poBand->m_dfOffset = dfOffset;
6015 : }
6016 : }
6017 : }
6018 : }
6019 :
6020 6055 : else if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX, &nCount,
6021 6210 : &padfMatrix) &&
6022 155 : nCount == 16)
6023 : {
6024 155 : m_gt.xorig = padfMatrix[3];
6025 155 : m_gt.xscale = padfMatrix[0];
6026 155 : m_gt.xrot = padfMatrix[1];
6027 155 : m_gt.yorig = padfMatrix[7];
6028 155 : m_gt.yrot = padfMatrix[4];
6029 155 : m_gt.yscale = padfMatrix[5];
6030 :
6031 155 : if (bPixelIsPoint && !bPointGeoIgnore)
6032 : {
6033 6 : m_gt.xorig -= m_gt.xscale * 0.5 + m_gt.xrot * 0.5;
6034 6 : m_gt.yorig -= m_gt.yrot * 0.5 + m_gt.yscale * 0.5;
6035 : }
6036 :
6037 155 : m_bGeoTransformValid = true;
6038 155 : m_nGeoTransformGeorefSrcIndex = nIndex;
6039 : }
6040 17057 : if (m_bGeoTransformValid)
6041 11157 : break;
6042 : }
6043 :
6044 : /* --------------------------------------------------------------------
6045 : */
6046 : /* Otherwise try looking for a .tab, .tfw, .tifw or .wld file.
6047 : */
6048 : /* --------------------------------------------------------------------
6049 : */
6050 17676 : if (m_nTABFILEGeorefSrcIndex == nIndex)
6051 : {
6052 5884 : char *pszGeorefFilename = nullptr;
6053 :
6054 5884 : CSLConstList papszSiblingFiles = GetSiblingFiles();
6055 :
6056 : // Begin with .tab since it can also have projection info.
6057 5884 : int nGCPCount = 0;
6058 5884 : GDAL_GCP *pasGCPList = nullptr;
6059 5884 : const int bTabFileOK = GDALReadTabFile2(
6060 : m_osFilename.c_str(), m_gt.data(), &pszTabWKT, &nGCPCount,
6061 : &pasGCPList, papszSiblingFiles, &pszGeorefFilename);
6062 :
6063 5884 : if (bTabFileOK)
6064 : {
6065 14 : m_nGeoTransformGeorefSrcIndex = nIndex;
6066 : // if( pszTabWKT )
6067 : // {
6068 : // m_nProjectionGeorefSrcIndex = nIndex;
6069 : // }
6070 14 : m_aoGCPs = gdal::GCP::fromC(pasGCPList, nGCPCount);
6071 14 : if (m_aoGCPs.empty())
6072 : {
6073 14 : m_bGeoTransformValid = true;
6074 : }
6075 : }
6076 :
6077 5884 : if (nGCPCount)
6078 : {
6079 0 : GDALDeinitGCPs(nGCPCount, pasGCPList);
6080 0 : CPLFree(pasGCPList);
6081 : }
6082 :
6083 5884 : if (pszGeorefFilename)
6084 : {
6085 14 : CPLFree(m_pszGeorefFilename);
6086 14 : m_pszGeorefFilename = pszGeorefFilename;
6087 14 : pszGeorefFilename = nullptr;
6088 : }
6089 5884 : if (m_bGeoTransformValid)
6090 14 : break;
6091 : }
6092 :
6093 17662 : if (m_nWORLDFILEGeorefSrcIndex == nIndex)
6094 : {
6095 5892 : char *pszGeorefFilename = nullptr;
6096 :
6097 5892 : CSLConstList papszSiblingFiles = GetSiblingFiles();
6098 :
6099 5892 : m_bGeoTransformValid = CPL_TO_BOOL(
6100 5892 : GDALReadWorldFile2(m_osFilename.c_str(), nullptr, m_gt,
6101 : papszSiblingFiles, &pszGeorefFilename));
6102 :
6103 5892 : if (!m_bGeoTransformValid)
6104 : {
6105 5860 : m_bGeoTransformValid = CPL_TO_BOOL(GDALReadWorldFile2(
6106 5860 : m_osFilename.c_str(), "wld", m_gt, papszSiblingFiles,
6107 : &pszGeorefFilename));
6108 : }
6109 5892 : if (m_bGeoTransformValid)
6110 37 : m_nGeoTransformGeorefSrcIndex = nIndex;
6111 :
6112 5892 : if (pszGeorefFilename)
6113 : {
6114 37 : CPLFree(m_pszGeorefFilename);
6115 37 : m_pszGeorefFilename = pszGeorefFilename;
6116 37 : pszGeorefFilename = nullptr;
6117 : }
6118 5892 : if (m_bGeoTransformValid)
6119 37 : break;
6120 : }
6121 : }
6122 :
6123 : /* --------------------------------------------------------------------
6124 : */
6125 : /* Check for GCPs. */
6126 : /* --------------------------------------------------------------------
6127 : */
6128 51247 : if (m_nINTERNALGeorefSrcIndex >= 0 &&
6129 17065 : TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
6130 34156 : &padfTiePoints) &&
6131 11139 : !m_bGeoTransformValid)
6132 : {
6133 137 : m_aoGCPs.clear();
6134 137 : const int nNewGCPCount = nCount / 6;
6135 645 : for (int iGCP = 0; iGCP < nNewGCPCount; ++iGCP)
6136 : {
6137 0 : m_aoGCPs.emplace_back(CPLSPrintf("%d", iGCP + 1), "",
6138 508 : /* pixel = */ padfTiePoints[iGCP * 6 + 0],
6139 508 : /* line = */ padfTiePoints[iGCP * 6 + 1],
6140 508 : /* X = */ padfTiePoints[iGCP * 6 + 3],
6141 508 : /* Y = */ padfTiePoints[iGCP * 6 + 4],
6142 508 : /* Z = */ padfTiePoints[iGCP * 6 + 5]);
6143 :
6144 508 : if (bPixelIsPoint && !bPointGeoIgnore)
6145 : {
6146 48 : m_aoGCPs.back().Pixel() += 0.5;
6147 48 : m_aoGCPs.back().Line() += 0.5;
6148 : }
6149 : }
6150 137 : m_nGeoTransformGeorefSrcIndex = m_nINTERNALGeorefSrcIndex;
6151 : }
6152 :
6153 : /* --------------------------------------------------------------------
6154 : */
6155 : /* Did we find a tab file? If so we will use its coordinate */
6156 : /* system and give it precedence. */
6157 : /* --------------------------------------------------------------------
6158 : */
6159 17091 : if (pszTabWKT != nullptr && m_oSRS.IsEmpty())
6160 : {
6161 14 : m_oSRS.importFromWkt(pszTabWKT);
6162 14 : m_bLookedForProjection = true;
6163 : }
6164 :
6165 17091 : CPLFree(pszTabWKT);
6166 : }
6167 :
6168 17091 : if (m_bLoadPam && m_nPAMGeorefSrcIndex >= 0)
6169 : {
6170 : /* --------------------------------------------------------------------
6171 : */
6172 : /* Initialize any PAM information. */
6173 : /* --------------------------------------------------------------------
6174 : */
6175 14953 : CPLAssert(!m_bColorProfileMetadataChanged);
6176 14953 : CPLAssert(!m_bMetadataChanged);
6177 14953 : CPLAssert(!m_bGeoTIFFInfoChanged);
6178 14953 : CPLAssert(!m_bNoDataChanged);
6179 :
6180 : // We must absolutely unset m_bLoadPam now, otherwise calling
6181 : // GetFileList() on a .tif with a .aux will result in an (almost)
6182 : // endless sequence of calls.
6183 14953 : m_bLoadPam = false;
6184 :
6185 14953 : TryLoadXML(GetSiblingFiles());
6186 14953 : ApplyPamInfo();
6187 :
6188 14953 : m_bColorProfileMetadataChanged = false;
6189 14953 : m_bMetadataChanged = false;
6190 14953 : m_bGeoTIFFInfoChanged = false;
6191 14953 : m_bNoDataChanged = false;
6192 : }
6193 17091 : m_bLoadPam = false;
6194 : }
6195 :
6196 : /************************************************************************/
6197 : /* GetSpatialRef() */
6198 : /************************************************************************/
6199 :
6200 21202 : const OGRSpatialReference *GTiffDataset::GetSpatialRef() const
6201 :
6202 : {
6203 21202 : const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
6204 21202 : if (m_aoGCPs.empty())
6205 : {
6206 20673 : const_cast<GTiffDataset *>(this)->LookForProjection();
6207 : }
6208 :
6209 21202 : return m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
6210 : }
6211 :
6212 : /************************************************************************/
6213 : /* GetGeoTransform() */
6214 : /************************************************************************/
6215 :
6216 320312 : CPLErr GTiffDataset::GetGeoTransform(GDALGeoTransform >) const
6217 :
6218 : {
6219 320312 : const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
6220 :
6221 320312 : gt = m_gt;
6222 :
6223 320312 : if (!m_bGeoTransformValid)
6224 304019 : return CE_Failure;
6225 :
6226 : // Same logic as in the .gtx driver, for the benefit of
6227 : // GDALOpenVerticalShiftGrid() when used with PROJ-data's US geoids.
6228 16293 : if (CPLFetchBool(papszOpenOptions, "SHIFT_ORIGIN_IN_MINUS_180_PLUS_180",
6229 : false))
6230 : {
6231 0 : if (gt.xorig < -180.0 - gt.xscale)
6232 0 : gt.xorig += 360.0;
6233 0 : else if (gt.xorig > 180.0)
6234 0 : gt.xorig -= 360.0;
6235 : }
6236 :
6237 16293 : return CE_None;
6238 : }
6239 :
6240 : /************************************************************************/
6241 : /* GetGCPCount() */
6242 : /************************************************************************/
6243 :
6244 7713 : int GTiffDataset::GetGCPCount()
6245 :
6246 : {
6247 7713 : LoadGeoreferencingAndPamIfNeeded();
6248 :
6249 7713 : return static_cast<int>(m_aoGCPs.size());
6250 : }
6251 :
6252 : /************************************************************************/
6253 : /* GetGCPSpatialRef() */
6254 : /************************************************************************/
6255 :
6256 636 : const OGRSpatialReference *GTiffDataset::GetGCPSpatialRef() const
6257 :
6258 : {
6259 636 : const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
6260 :
6261 636 : if (!m_aoGCPs.empty())
6262 : {
6263 157 : const_cast<GTiffDataset *>(this)->LookForProjection();
6264 : }
6265 636 : return !m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
6266 : }
6267 :
6268 : /************************************************************************/
6269 : /* GetGCPs() */
6270 : /************************************************************************/
6271 :
6272 493 : const GDAL_GCP *GTiffDataset::GetGCPs()
6273 :
6274 : {
6275 493 : LoadGeoreferencingAndPamIfNeeded();
6276 :
6277 493 : return gdal::GCP::c_ptr(m_aoGCPs);
6278 : }
6279 :
6280 : /************************************************************************/
6281 : /* GetMetadataDomainList() */
6282 : /************************************************************************/
6283 :
6284 33 : char **GTiffDataset::GetMetadataDomainList()
6285 : {
6286 33 : LoadGeoreferencingAndPamIfNeeded();
6287 :
6288 33 : char **papszDomainList = CSLDuplicate(m_oGTiffMDMD.GetDomainList());
6289 33 : char **papszBaseList = GDALDataset::GetMetadataDomainList();
6290 :
6291 33 : const int nbBaseDomains = CSLCount(papszBaseList);
6292 :
6293 66 : for (int domainId = 0; domainId < nbBaseDomains; ++domainId)
6294 : {
6295 33 : if (CSLFindString(papszDomainList, papszBaseList[domainId]) < 0)
6296 : {
6297 : papszDomainList =
6298 33 : CSLAddString(papszDomainList, papszBaseList[domainId]);
6299 : }
6300 : }
6301 :
6302 33 : CSLDestroy(papszBaseList);
6303 :
6304 33 : return BuildMetadataDomainList(papszDomainList, TRUE, "",
6305 : "ProxyOverviewRequest", MD_DOMAIN_RPC,
6306 : MD_DOMAIN_IMD, "SUBDATASETS", "EXIF",
6307 33 : "xml:XMP", "COLOR_PROFILE", nullptr);
6308 : }
6309 :
6310 : /************************************************************************/
6311 : /* GetMetadata() */
6312 : /************************************************************************/
6313 :
6314 36622 : CSLConstList GTiffDataset::GetMetadata(const char *pszDomain)
6315 :
6316 : {
6317 36622 : if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
6318 : {
6319 138 : GTiffDataset::GetMetadataItem("COMPRESSION_REVERSIBILITY", pszDomain);
6320 138 : GTiffDataset::GetMetadataItem("LAYOUT", pszDomain);
6321 : }
6322 : else
6323 : {
6324 36484 : LoadGeoreferencingAndPamIfNeeded();
6325 : }
6326 :
6327 36622 : if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
6328 33 : return GDALPamDataset::GetMetadata(pszDomain);
6329 :
6330 36589 : if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
6331 : {
6332 6 : return GDALDataset::GetMetadata(pszDomain);
6333 : }
6334 :
6335 36583 : else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
6336 23180 : EQUAL(pszDomain, MD_DOMAIN_IMD) ||
6337 16544 : EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
6338 19365 : LoadMetadata();
6339 :
6340 17218 : else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
6341 1320 : ScanDirectories();
6342 :
6343 15898 : else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
6344 58 : LoadEXIFMetadata();
6345 :
6346 15840 : else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
6347 48 : LoadICCProfile();
6348 :
6349 15792 : else if (pszDomain == nullptr || EQUAL(pszDomain, ""))
6350 8133 : LoadMDAreaOrPoint(); // To set GDALMD_AREA_OR_POINT.
6351 :
6352 36583 : return m_oGTiffMDMD.GetMetadata(pszDomain);
6353 : }
6354 :
6355 : /************************************************************************/
6356 : /* GetMetadataItem() */
6357 : /************************************************************************/
6358 :
6359 150803 : const char *GTiffDataset::GetMetadataItem(const char *pszName,
6360 : const char *pszDomain)
6361 :
6362 : {
6363 150803 : if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
6364 : {
6365 218130 : if ((m_nCompression == COMPRESSION_WEBP ||
6366 71322 : m_nCompression == COMPRESSION_JXL ||
6367 71321 : m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
6368 144803 : EQUAL(pszName, "COMPRESSION_REVERSIBILITY") &&
6369 77 : m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
6370 : "IMAGE_STRUCTURE") == nullptr)
6371 : {
6372 60 : const char *pszDriverName =
6373 60 : m_nCompression == COMPRESSION_WEBP ? "WEBP" : "JPEGXL";
6374 60 : auto poTileDriver = GDALGetDriverByName(pszDriverName);
6375 60 : if (poTileDriver)
6376 : {
6377 60 : vsi_l_offset nOffset = 0;
6378 60 : vsi_l_offset nSize = 0;
6379 60 : CPL_IGNORE_RET_VAL(
6380 60 : IsBlockAvailable(0, &nOffset, &nSize, nullptr));
6381 60 : if (nSize > 0)
6382 : {
6383 : const std::string osSubfile(
6384 : CPLSPrintf("/vsisubfile/" CPL_FRMT_GUIB "_%d,%s",
6385 : static_cast<GUIntBig>(nOffset),
6386 25 : static_cast<int>(std::min(
6387 50 : static_cast<vsi_l_offset>(1024), nSize)),
6388 75 : m_osFilename.c_str()));
6389 25 : const char *const apszDrivers[] = {pszDriverName, nullptr};
6390 : auto poWebPDataset =
6391 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
6392 50 : osSubfile.c_str(), GDAL_OF_RASTER, apszDrivers));
6393 25 : if (poWebPDataset)
6394 : {
6395 : const char *pszReversibility =
6396 25 : poWebPDataset->GetMetadataItem(
6397 25 : "COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
6398 25 : if (pszReversibility)
6399 25 : m_oGTiffMDMD.SetMetadataItem(
6400 : "COMPRESSION_REVERSIBILITY", pszReversibility,
6401 : "IMAGE_STRUCTURE");
6402 : }
6403 : }
6404 : }
6405 : }
6406 :
6407 73404 : if (!m_bLayoutChecked && m_poBaseDS == nullptr)
6408 : {
6409 5215 : m_bLayoutChecked = true;
6410 : const char *pszLayout =
6411 5215 : m_oGTiffMDMD.GetMetadataItem("LAYOUT", "IMAGE_STRUCTURE");
6412 5215 : if (eAccess == GA_ReadOnly && !pszLayout && CheckCOGLayout())
6413 : {
6414 166 : m_oGTiffMDMD.SetMetadataItem("LAYOUT", "COG",
6415 : "IMAGE_STRUCTURE");
6416 : }
6417 73404 : }
6418 : }
6419 : else
6420 : {
6421 77399 : LoadGeoreferencingAndPamIfNeeded();
6422 : }
6423 :
6424 150803 : if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
6425 : {
6426 4 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
6427 : }
6428 150799 : else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
6429 150744 : EQUAL(pszDomain, MD_DOMAIN_IMD) ||
6430 150742 : EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
6431 : {
6432 57 : LoadMetadata();
6433 : }
6434 150742 : else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
6435 : {
6436 1 : ScanDirectories();
6437 : }
6438 150741 : else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
6439 : {
6440 1 : LoadEXIFMetadata();
6441 : }
6442 150740 : else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
6443 : {
6444 5634 : LoadICCProfile();
6445 : }
6446 145106 : else if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
6447 64985 : pszName != nullptr && EQUAL(pszName, GDALMD_AREA_OR_POINT))
6448 : {
6449 8917 : LoadMDAreaOrPoint(); // To set GDALMD_AREA_OR_POINT.
6450 : }
6451 136189 : else if (pszDomain != nullptr && EQUAL(pszDomain, "_DEBUG_") &&
6452 79 : pszName != nullptr)
6453 : {
6454 : #ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
6455 : if (EQUAL(pszName, "UNREACHED_VIRTUALMEMIO_CODE_PATH"))
6456 : {
6457 : CPLString osMissing;
6458 : for (int i = 0;
6459 : i < static_cast<int>(CPL_ARRAYSIZE(anReachedVirtualMemIO));
6460 : ++i)
6461 : {
6462 : if (!anReachedVirtualMemIO[i])
6463 : {
6464 : if (!osMissing.empty())
6465 : osMissing += ",";
6466 : osMissing += CPLSPrintf("%d", i);
6467 : }
6468 : }
6469 : return (osMissing.size()) ? CPLSPrintf("%s", osMissing.c_str())
6470 : : nullptr;
6471 : }
6472 : else
6473 : #endif
6474 79 : if (EQUAL(pszName, "TIFFTAG_EXTRASAMPLES"))
6475 : {
6476 18 : CPLString osRet;
6477 18 : uint16_t *v = nullptr;
6478 18 : uint16_t count = 0;
6479 :
6480 18 : if (TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
6481 : {
6482 53 : for (int i = 0; i < static_cast<int>(count); ++i)
6483 : {
6484 37 : if (i > 0)
6485 21 : osRet += ",";
6486 37 : osRet += CPLSPrintf("%d", v[i]);
6487 : }
6488 : }
6489 18 : return (osRet.size()) ? CPLSPrintf("%s", osRet.c_str()) : nullptr;
6490 : }
6491 61 : else if (EQUAL(pszName, "TIFFTAG_PHOTOMETRIC"))
6492 : {
6493 6 : return CPLSPrintf("%d", m_nPhotometric);
6494 : }
6495 :
6496 55 : else if (EQUAL(pszName, "TIFFTAG_GDAL_METADATA"))
6497 : {
6498 7 : char *pszText = nullptr;
6499 7 : if (!TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
6500 6 : return nullptr;
6501 :
6502 1 : return pszText;
6503 : }
6504 48 : else if (EQUAL(pszName, "HAS_USED_READ_ENCODED_API"))
6505 : {
6506 6 : return m_bHasUsedReadEncodedAPI ? "1" : "0";
6507 : }
6508 42 : else if (EQUAL(pszName, "WEBP_LOSSLESS"))
6509 : {
6510 6 : return m_bWebPLossless ? "1" : "0";
6511 : }
6512 36 : else if (EQUAL(pszName, "WEBP_LEVEL"))
6513 : {
6514 2 : return CPLSPrintf("%d", m_nWebPLevel);
6515 : }
6516 34 : else if (EQUAL(pszName, "MAX_Z_ERROR"))
6517 : {
6518 10 : return CPLSPrintf("%f", m_dfMaxZError);
6519 : }
6520 24 : else if (EQUAL(pszName, "MAX_Z_ERROR_OVERVIEW"))
6521 : {
6522 6 : return CPLSPrintf("%f", m_dfMaxZErrorOverview);
6523 : }
6524 : #if HAVE_JXL
6525 18 : else if (EQUAL(pszName, "JXL_LOSSLESS"))
6526 : {
6527 9 : return m_bJXLLossless ? "1" : "0";
6528 : }
6529 9 : else if (EQUAL(pszName, "JXL_DISTANCE"))
6530 : {
6531 4 : return CPLSPrintf("%f", static_cast<double>(m_fJXLDistance));
6532 : }
6533 5 : else if (EQUAL(pszName, "JXL_ALPHA_DISTANCE"))
6534 : {
6535 0 : return CPLSPrintf("%f", static_cast<double>(m_fJXLAlphaDistance));
6536 : }
6537 5 : else if (EQUAL(pszName, "JXL_EFFORT"))
6538 : {
6539 4 : return CPLSPrintf("%u", m_nJXLEffort);
6540 : }
6541 : #endif
6542 1 : return nullptr;
6543 : }
6544 :
6545 136110 : else if (pszDomain != nullptr && EQUAL(pszDomain, "TIFF") &&
6546 7 : pszName != nullptr)
6547 : {
6548 7 : if (EQUAL(pszName, "GDAL_STRUCTURAL_METADATA"))
6549 : {
6550 2 : const auto nOffset = VSIFTellL(m_fpL);
6551 2 : VSIFSeekL(m_fpL, 0, SEEK_SET);
6552 : GByte abyData[1024];
6553 2 : size_t nRead = VSIFReadL(abyData, 1, sizeof(abyData) - 1, m_fpL);
6554 2 : abyData[nRead] = 0;
6555 2 : VSIFSeekL(m_fpL, nOffset, SEEK_SET);
6556 2 : if (nRead > 4)
6557 : {
6558 2 : const int nOffsetOfStructuralMetadata =
6559 2 : (abyData[2] == 0x2B || abyData[3] == 0x2B) ? 16 : 8;
6560 2 : const int nSizePatternLen =
6561 : static_cast<int>(strlen("XXXXXX bytes\n"));
6562 2 : if (nRead > nOffsetOfStructuralMetadata +
6563 2 : strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
6564 2 : nSizePatternLen &&
6565 2 : memcmp(abyData + nOffsetOfStructuralMetadata,
6566 : "GDAL_STRUCTURAL_METADATA_SIZE=",
6567 : strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
6568 : {
6569 1 : char *pszStructuralMD = reinterpret_cast<char *>(
6570 1 : abyData + nOffsetOfStructuralMetadata);
6571 : const int nLenMD =
6572 1 : atoi(pszStructuralMD +
6573 : strlen("GDAL_STRUCTURAL_METADATA_SIZE="));
6574 1 : if (nOffsetOfStructuralMetadata +
6575 : strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
6576 1 : nSizePatternLen + nLenMD <=
6577 : nRead)
6578 : {
6579 : pszStructuralMD[strlen(
6580 : "GDAL_STRUCTURAL_METADATA_SIZE=") +
6581 1 : nSizePatternLen + nLenMD] = 0;
6582 1 : return CPLSPrintf("%s", pszStructuralMD);
6583 : }
6584 : }
6585 : }
6586 1 : return nullptr;
6587 5 : }
6588 : }
6589 :
6590 136103 : else if (pszName && pszDomain && EQUAL(pszDomain, "json:ISIS3"))
6591 : {
6592 4 : auto oIter = m_oMapISIS3MetadataItems.find(pszName);
6593 4 : if (oIter != m_oMapISIS3MetadataItems.end())
6594 : {
6595 1 : return oIter->second.c_str();
6596 : }
6597 : else
6598 : {
6599 3 : if (!m_oISIS3Metadata.IsValid())
6600 : {
6601 2 : CSLConstList papszMD = m_oGTiffMDMD.GetMetadata(pszDomain);
6602 2 : if (papszMD && papszMD[0])
6603 : {
6604 4 : CPLJSONDocument oDoc;
6605 2 : if (oDoc.LoadMemory(papszMD[0]))
6606 : {
6607 2 : m_oISIS3Metadata = oDoc.GetRoot();
6608 : }
6609 : }
6610 : }
6611 9 : CPLJSONObject obj = m_oISIS3Metadata[pszName];
6612 3 : if (obj.IsValid())
6613 : {
6614 : return m_oMapISIS3MetadataItems
6615 2 : .insert(std::pair<std::string, std::string>(pszName,
6616 3 : obj.ToString()))
6617 1 : .first->second.c_str();
6618 : }
6619 2 : return nullptr;
6620 : }
6621 : }
6622 :
6623 150714 : return m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
6624 : }
6625 :
6626 : /************************************************************************/
6627 : /* LoadEXIFMetadata() */
6628 : /************************************************************************/
6629 :
6630 59 : void GTiffDataset::LoadEXIFMetadata()
6631 : {
6632 59 : if (m_bEXIFMetadataLoaded)
6633 7 : return;
6634 52 : m_bEXIFMetadataLoaded = true;
6635 :
6636 52 : VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
6637 :
6638 52 : GByte abyHeader[2] = {0};
6639 52 : if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || VSIFReadL(abyHeader, 1, 2, fp) != 2)
6640 0 : return;
6641 :
6642 52 : const bool bLittleEndian = abyHeader[0] == 'I' && abyHeader[1] == 'I';
6643 52 : const bool bLeastSignificantBit = CPL_IS_LSB != 0;
6644 52 : const bool bSwabflag = bLittleEndian != bLeastSignificantBit; // != is XOR.
6645 :
6646 52 : char **papszMetadata = nullptr;
6647 52 : toff_t nOffset = 0;
6648 :
6649 52 : if (TIFFGetField(m_hTIFF, TIFFTAG_EXIFIFD, &nOffset))
6650 : {
6651 3 : uint32_t nExifOffset = static_cast<uint32_t>(nOffset);
6652 3 : uint32_t nInterOffset = 0;
6653 3 : uint32_t nGPSOffset = 0;
6654 3 : EXIFExtractMetadata(papszMetadata, fp, static_cast<uint32_t>(nOffset),
6655 : bSwabflag, 0, nExifOffset, nInterOffset,
6656 : nGPSOffset);
6657 : }
6658 :
6659 52 : if (TIFFGetField(m_hTIFF, TIFFTAG_GPSIFD, &nOffset))
6660 : {
6661 3 : uint32_t nExifOffset = 0;
6662 3 : uint32_t nInterOffset = 0;
6663 3 : uint32_t nGPSOffset = static_cast<uint32_t>(nOffset);
6664 3 : EXIFExtractMetadata(papszMetadata, fp, static_cast<uint32_t>(nOffset),
6665 : bSwabflag, 0, nExifOffset, nInterOffset,
6666 : nGPSOffset);
6667 : }
6668 :
6669 52 : if (papszMetadata)
6670 : {
6671 3 : m_oGTiffMDMD.SetMetadata(papszMetadata, "EXIF");
6672 3 : CSLDestroy(papszMetadata);
6673 : }
6674 : }
6675 :
6676 : /************************************************************************/
6677 : /* LoadMetadata() */
6678 : /************************************************************************/
6679 21963 : void GTiffDataset::LoadMetadata()
6680 : {
6681 21963 : if (m_bIMDRPCMetadataLoaded)
6682 17187 : return;
6683 4852 : m_bIMDRPCMetadataLoaded = true;
6684 :
6685 4852 : if (EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "ovr"))
6686 : {
6687 : // Do not attempt to retrieve metadata files on .tif.ovr files.
6688 : // For example the Pleiades metadata reader might wrongly associate a
6689 : // DIM_xxx.XML file that was meant to be associated with the main
6690 : // TIFF file. The consequence of that wrong association is that if
6691 : // one cleans overviews, then the Delete() method would then delete
6692 : // that DIM_xxx.XML file since it would be reported in the GetFileList()
6693 : // of the overview dataset.
6694 76 : return;
6695 : }
6696 :
6697 9552 : GDALMDReaderManager mdreadermanager;
6698 : GDALMDReaderBase *mdreader =
6699 4776 : m_poBaseDS == nullptr
6700 4776 : ? mdreadermanager.GetReader(m_osFilename.c_str(),
6701 : oOvManager.GetSiblingFiles(), MDR_ANY)
6702 4776 : : nullptr;
6703 :
6704 4776 : if (nullptr != mdreader)
6705 : {
6706 65 : mdreader->FillMetadata(&m_oGTiffMDMD);
6707 :
6708 65 : if (mdreader->GetMetadataDomain(MD_DOMAIN_RPC) == nullptr)
6709 : {
6710 36 : char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
6711 36 : if (papszRPCMD)
6712 : {
6713 12 : m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
6714 12 : CSLDestroy(papszRPCMD);
6715 : }
6716 : }
6717 :
6718 65 : m_papszMetadataFiles = mdreader->GetMetadataFiles();
6719 : }
6720 : else
6721 : {
6722 4711 : char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
6723 4711 : if (papszRPCMD)
6724 : {
6725 20 : m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
6726 20 : CSLDestroy(papszRPCMD);
6727 : }
6728 : }
6729 : }
6730 :
6731 : /************************************************************************/
6732 : /* LoadENVIHdrIfNeeded() */
6733 : /************************************************************************/
6734 :
6735 26371 : void GTiffDataset::LoadENVIHdrIfNeeded()
6736 : {
6737 26371 : if (m_bENVIHdrTried || m_poBaseDS)
6738 26365 : return;
6739 8599 : m_bENVIHdrTried = true;
6740 :
6741 : const std::string osHdrFilename =
6742 8599 : GetSidecarFilenameWithReplacedExtension("hdr");
6743 8599 : if (osHdrFilename.empty())
6744 7594 : return;
6745 :
6746 1005 : auto fp = VSIFilesystemHandler::OpenStatic(osHdrFilename.c_str(), "rb");
6747 1005 : if (!fp)
6748 0 : return;
6749 :
6750 1005 : constexpr int MAX_LINE_SIZE = 10000;
6751 :
6752 : // Check line is "ENVI"
6753 1005 : const char *pszFirstLine = CPLReadLine2L(fp.get(), MAX_LINE_SIZE, nullptr);
6754 1005 : if (!pszFirstLine || !EQUAL(pszFirstLine, "ENVI"))
6755 0 : return;
6756 :
6757 1005 : VSIRewindL(fp.get());
6758 :
6759 1005 : const CPLStringList aosHeaders(GDALReadENVIHeader(fp.get()));
6760 :
6761 : // Basic check to verify the .hdr file is indeed related to the GeoTIFF one
6762 1005 : if (atoi(aosHeaders.FetchNameValueDef("samples", "0")) != nRasterXSize ||
6763 2009 : atoi(aosHeaders.FetchNameValueDef("lines", "0")) != nRasterYSize ||
6764 1004 : !EQUAL(aosHeaders.FetchNameValueDef("file_type", ""), "TIFF"))
6765 : {
6766 999 : return;
6767 : }
6768 :
6769 6 : m_bENVIHdrFound = true;
6770 :
6771 6 : const char *const apszOptions[] = {
6772 : "APPLY_DEFAULT_BANDS=NO", "APPLY_CLASS_LOOKUP=NO",
6773 : "APPLY_DATA_IGNORE_VALUE=NO", "SET_BAND_NAME=NO",
6774 : "SET_DATASET_LEVEL_METADATA=NO", nullptr,
6775 : };
6776 6 : GDALApplyENVIHeaders(this, aosHeaders, apszOptions);
6777 : }
6778 :
6779 : /************************************************************************/
6780 : /* HasOptimizedReadMultiRange() */
6781 : /************************************************************************/
6782 :
6783 2898950 : bool GTiffDataset::HasOptimizedReadMultiRange()
6784 : {
6785 2898950 : if (m_nHasOptimizedReadMultiRange >= 0)
6786 2883320 : return m_nHasOptimizedReadMultiRange != 0;
6787 15634 : m_nHasOptimizedReadMultiRange = static_cast<signed char>(
6788 15634 : VSIHasOptimizedReadMultiRange(m_osFilename.c_str())
6789 : // Config option for debug and testing purposes only
6790 15634 : || CPLTestBool(CPLGetConfigOption(
6791 : "GTIFF_HAS_OPTIMIZED_READ_MULTI_RANGE", "NO")));
6792 15634 : return m_nHasOptimizedReadMultiRange != 0;
6793 : }
6794 :
6795 : /************************************************************************/
6796 : /* CacheMultiRange() */
6797 : /************************************************************************/
6798 :
6799 256 : static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
6800 : {
6801 : GByte abyTrailer[4];
6802 256 : memcpy(abyTrailer, strileData + nStrileSize, 4);
6803 256 : GByte abyLastBytes[4] = {};
6804 256 : if (nStrileSize >= 4)
6805 256 : memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
6806 : else
6807 : {
6808 : // The last bytes will be zero due to the above {} initialization,
6809 : // and that's what should be in abyTrailer too when the trailer is
6810 : // correct.
6811 0 : memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
6812 : }
6813 256 : return memcmp(abyTrailer, abyLastBytes, 4) == 0;
6814 : }
6815 :
6816 268 : void *GTiffDataset::CacheMultiRange(int nXOff, int nYOff, int nXSize,
6817 : int nYSize, int nBufXSize, int nBufYSize,
6818 : const int *panBandMap, int nBandCount,
6819 : GDALRasterIOExtraArg *psExtraArg)
6820 : {
6821 268 : void *pBufferedData = nullptr;
6822 : // Same logic as in GDALRasterBand::IRasterIO()
6823 268 : double dfXOff = nXOff;
6824 268 : double dfYOff = nYOff;
6825 268 : double dfXSize = nXSize;
6826 268 : double dfYSize = nYSize;
6827 268 : if (psExtraArg->bFloatingPointWindowValidity)
6828 : {
6829 48 : dfXOff = psExtraArg->dfXOff;
6830 48 : dfYOff = psExtraArg->dfYOff;
6831 48 : dfXSize = psExtraArg->dfXSize;
6832 48 : dfYSize = psExtraArg->dfYSize;
6833 : }
6834 268 : const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
6835 268 : const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
6836 268 : const double EPS = 1e-10;
6837 : const int nBlockX1 =
6838 268 : static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
6839 268 : m_nBlockXSize;
6840 : const int nBlockY1 =
6841 268 : static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
6842 268 : m_nBlockYSize;
6843 : const int nBlockX2 =
6844 268 : static_cast<int>(
6845 536 : std::min(static_cast<double>(nRasterXSize - 1),
6846 268 : (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
6847 268 : m_nBlockXSize;
6848 : const int nBlockY2 =
6849 268 : static_cast<int>(
6850 536 : std::min(static_cast<double>(nRasterYSize - 1),
6851 268 : (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
6852 268 : m_nBlockYSize;
6853 :
6854 : struct StrileData
6855 : {
6856 : vsi_l_offset nOffset;
6857 : vsi_l_offset nByteCount;
6858 : bool bTryMask;
6859 : };
6860 :
6861 536 : std::map<int, StrileData> oMapStrileToOffsetByteCount;
6862 :
6863 : // Dedicated method to retrieved the offset and size in an efficient way
6864 : // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
6865 : // met.
6866 : // Except for the last block, we just read the offset from the TIFF offset
6867 : // array, and retrieve the size in the leader 4 bytes that come before the
6868 : // payload.
6869 : auto OptimizedRetrievalOfOffsetSize =
6870 218 : [&](int nBand, int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
6871 : size_t nTotalSize, size_t nMaxRawBlockCacheSize)
6872 : {
6873 1224 : bool bTryMask = m_bMaskInterleavedWithImagery;
6874 218 : nOffset = TIFFGetStrileOffset(m_hTIFF, nBlockId);
6875 218 : if (nOffset >= 4)
6876 : {
6877 155 : if ((m_nPlanarConfig == PLANARCONFIG_CONTIG &&
6878 131 : nBlockId == m_nBlocksPerBand - 1) ||
6879 129 : (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
6880 24 : nBlockId == m_nBlocksPerBand * nBands - 1))
6881 : {
6882 : // Special case for the last block. As there is no next block
6883 : // from which to retrieve an offset, use the good old method
6884 : // that consists in reading the ByteCount array.
6885 26 : if (m_nPlanarConfig == PLANARCONFIG_CONTIG && bTryMask &&
6886 54 : GetRasterBand(1)->GetMaskBand() && m_poMaskDS)
6887 : {
6888 : auto nMaskOffset =
6889 23 : TIFFGetStrileOffset(m_poMaskDS->m_hTIFF, nBlockId);
6890 23 : if (nMaskOffset)
6891 : {
6892 23 : nSize = nMaskOffset +
6893 23 : TIFFGetStrileByteCount(m_poMaskDS->m_hTIFF,
6894 23 : nBlockId) -
6895 23 : nOffset;
6896 : }
6897 : else
6898 : {
6899 0 : bTryMask = false;
6900 : }
6901 : }
6902 28 : if (nSize == 0)
6903 : {
6904 5 : nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
6905 : }
6906 28 : if (nSize && m_bTrailerRepeatedLast4BytesRepeated)
6907 : {
6908 28 : nSize += 4;
6909 28 : }
6910 : }
6911 : else
6912 : {
6913 127 : const auto nNextBlockId =
6914 11 : (m_bTileInterleave && nBand < nBands)
6915 254 : ? nBlockId + m_nBlocksPerBand
6916 3 : : (m_bTileInterleave && nBand == nBands)
6917 122 : ? nBlockId - (nBand - 1) * m_nBlocksPerBand + 1
6918 116 : : nBlockId + 1;
6919 127 : auto nOffsetNext = TIFFGetStrileOffset(m_hTIFF, nNextBlockId);
6920 127 : if (nOffsetNext > nOffset)
6921 : {
6922 119 : nSize = nOffsetNext - nOffset;
6923 : }
6924 : else
6925 : {
6926 : // Shouldn't happen for a compliant file
6927 8 : if (nOffsetNext != 0)
6928 : {
6929 0 : CPLDebug("GTiff", "Tile %d is not located after %d",
6930 : nNextBlockId, nBlockId);
6931 : }
6932 8 : bTryMask = false;
6933 8 : nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
6934 8 : if (m_bTrailerRepeatedLast4BytesRepeated)
6935 8 : nSize += 4;
6936 : }
6937 : }
6938 155 : if (nSize)
6939 : {
6940 155 : nOffset -= 4;
6941 155 : nSize += 4;
6942 155 : if (nTotalSize + nSize < nMaxRawBlockCacheSize)
6943 : {
6944 : StrileData data;
6945 155 : data.nOffset = nOffset;
6946 155 : data.nByteCount = nSize;
6947 155 : data.bTryMask = bTryMask;
6948 155 : oMapStrileToOffsetByteCount[nBlockId] = data;
6949 : }
6950 : }
6951 : }
6952 : else
6953 : {
6954 : // Sparse tile
6955 : StrileData data;
6956 63 : data.nOffset = 0;
6957 63 : data.nByteCount = 0;
6958 63 : data.bTryMask = false;
6959 63 : oMapStrileToOffsetByteCount[nBlockId] = data;
6960 : }
6961 218 : };
6962 :
6963 : // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
6964 : // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
6965 : // mask) from the temporary oMapStrileToOffsetByteCount.
6966 : auto FillCacheStrileToOffsetByteCount =
6967 37 : [&](const std::vector<vsi_l_offset> &anOffsets,
6968 : const std::vector<size_t> &anSizes,
6969 : const std::vector<void *> &apData)
6970 : {
6971 37 : CPLAssert(m_bLeaderSizeAsUInt4);
6972 37 : size_t i = 0;
6973 37 : vsi_l_offset nLastOffset = 0;
6974 215 : for (const auto &entry : oMapStrileToOffsetByteCount)
6975 : {
6976 178 : const auto nBlockId = entry.first;
6977 178 : const auto nOffset = entry.second.nOffset;
6978 178 : const auto nSize = entry.second.nByteCount;
6979 178 : if (nOffset == 0)
6980 : {
6981 : // Sparse tile
6982 : m_oCacheStrileToOffsetByteCount.insert(nBlockId,
6983 23 : std::pair(0, 0));
6984 77 : continue;
6985 : }
6986 :
6987 155 : if (nOffset < nLastOffset)
6988 : {
6989 : // shouldn't happen normally if tiles are sorted
6990 2 : i = 0;
6991 : }
6992 155 : nLastOffset = nOffset;
6993 318 : while (i < anOffsets.size() &&
6994 159 : !(nOffset >= anOffsets[i] &&
6995 159 : nOffset + nSize <= anOffsets[i] + anSizes[i]))
6996 : {
6997 4 : i++;
6998 : }
6999 155 : CPLAssert(i < anOffsets.size());
7000 155 : CPLAssert(nOffset >= anOffsets[i]);
7001 155 : CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
7002 : GUInt32 nSizeFromLeader;
7003 155 : memcpy(&nSizeFromLeader,
7004 : // cppcheck-suppress containerOutOfBounds
7005 155 : static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
7006 : sizeof(nSizeFromLeader));
7007 155 : CPL_LSBPTR32(&nSizeFromLeader);
7008 155 : bool bOK = true;
7009 155 : constexpr int nLeaderSize = 4;
7010 155 : const int nTrailerSize =
7011 155 : (m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
7012 155 : if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
7013 : {
7014 0 : CPLDebug("GTiff",
7015 : "Inconsistent block size from in leader of block %d",
7016 : nBlockId);
7017 0 : bOK = false;
7018 : }
7019 155 : else if (m_bTrailerRepeatedLast4BytesRepeated)
7020 : {
7021 : // Check trailer consistency
7022 155 : const GByte *strileData = static_cast<GByte *>(apData[i]) +
7023 155 : nOffset - anOffsets[i] + nLeaderSize;
7024 155 : if (!CheckTrailer(strileData, nSizeFromLeader))
7025 : {
7026 0 : CPLDebug("GTiff", "Inconsistent trailer of block %d",
7027 : nBlockId);
7028 0 : bOK = false;
7029 : }
7030 : }
7031 155 : if (!bOK)
7032 : {
7033 0 : return false;
7034 : }
7035 :
7036 : {
7037 155 : const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
7038 155 : const vsi_l_offset nRealSize = nSizeFromLeader;
7039 : #ifdef DEBUG_VERBOSE
7040 : CPLDebug("GTiff",
7041 : "Block %d found at offset " CPL_FRMT_GUIB
7042 : " with size " CPL_FRMT_GUIB,
7043 : nBlockId, nRealOffset, nRealSize);
7044 : #endif
7045 : m_oCacheStrileToOffsetByteCount.insert(
7046 155 : nBlockId, std::pair(nRealOffset, nRealSize));
7047 : }
7048 :
7049 : // Processing of mask
7050 256 : if (!(entry.second.bTryMask && m_bMaskInterleavedWithImagery &&
7051 101 : GetRasterBand(1)->GetMaskBand() && m_poMaskDS))
7052 : {
7053 54 : continue;
7054 : }
7055 :
7056 101 : bOK = false;
7057 101 : const vsi_l_offset nMaskOffsetWithLeader =
7058 101 : nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
7059 202 : if (nMaskOffsetWithLeader + nLeaderSize <=
7060 101 : anOffsets[i] + anSizes[i])
7061 : {
7062 : GUInt32 nMaskSizeFromLeader;
7063 101 : memcpy(&nMaskSizeFromLeader,
7064 101 : static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
7065 101 : anOffsets[i],
7066 : sizeof(nMaskSizeFromLeader));
7067 101 : CPL_LSBPTR32(&nMaskSizeFromLeader);
7068 202 : if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
7069 202 : nTrailerSize <=
7070 101 : anOffsets[i] + anSizes[i])
7071 : {
7072 101 : bOK = true;
7073 101 : if (m_bTrailerRepeatedLast4BytesRepeated)
7074 : {
7075 : // Check trailer consistency
7076 : const GByte *strileMaskData =
7077 101 : static_cast<GByte *>(apData[i]) + nOffset -
7078 202 : anOffsets[i] + nLeaderSize + nSizeFromLeader +
7079 101 : nTrailerSize + nLeaderSize;
7080 101 : if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
7081 : {
7082 0 : CPLDebug("GTiff",
7083 : "Inconsistent trailer of mask of block %d",
7084 : nBlockId);
7085 0 : bOK = false;
7086 : }
7087 : }
7088 : }
7089 101 : if (bOK)
7090 : {
7091 101 : const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
7092 101 : nSizeFromLeader +
7093 101 : nTrailerSize + nLeaderSize;
7094 101 : const vsi_l_offset nRealSize = nMaskSizeFromLeader;
7095 : #ifdef DEBUG_VERBOSE
7096 : CPLDebug("GTiff",
7097 : "Mask of block %d found at offset " CPL_FRMT_GUIB
7098 : " with size " CPL_FRMT_GUIB,
7099 : nBlockId, nRealOffset, nRealSize);
7100 : #endif
7101 :
7102 101 : m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
7103 101 : nBlockId, std::pair(nRealOffset, nRealSize));
7104 : }
7105 : }
7106 101 : if (!bOK)
7107 : {
7108 0 : CPLDebug("GTiff",
7109 : "Mask for block %d is not properly interleaved with "
7110 : "imagery block",
7111 : nBlockId);
7112 : }
7113 : }
7114 37 : return true;
7115 268 : };
7116 :
7117 268 : thandle_t th = TIFFClientdata(m_hTIFF);
7118 268 : if (!VSI_TIFFHasCachedRanges(th))
7119 : {
7120 234 : std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
7121 234 : size_t nTotalSize = 0;
7122 234 : const unsigned int nMaxRawBlockCacheSize = atoi(
7123 234 : CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
7124 234 : bool bGoOn = true;
7125 472 : for (int iBand = 0; iBand < nBandCount; ++iBand)
7126 : {
7127 238 : const int nBand = panBandMap[iBand];
7128 : GTiffRasterBand *poBand =
7129 238 : cpl::down_cast<GTiffRasterBand *>(papoBands[nBand - 1]);
7130 557 : for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
7131 : {
7132 1042 : for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
7133 : {
7134 : GDALRasterBlock *poBlock =
7135 723 : poBand->TryGetLockedBlockRef(iX, iY);
7136 723 : if (poBlock != nullptr)
7137 : {
7138 299 : poBlock->DropLock();
7139 299 : continue;
7140 : }
7141 424 : int nBlockId = iX + iY * m_nBlocksPerRow;
7142 424 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
7143 24 : nBlockId += (nBand - 1) * m_nBlocksPerBand;
7144 424 : vsi_l_offset nOffset = 0;
7145 424 : vsi_l_offset nSize = 0;
7146 :
7147 424 : if (!m_bStreamingIn && m_bBlockOrderRowMajor &&
7148 218 : m_bLeaderSizeAsUInt4)
7149 : {
7150 218 : OptimizedRetrievalOfOffsetSize(nBand, nBlockId, nOffset,
7151 : nSize, nTotalSize,
7152 : nMaxRawBlockCacheSize);
7153 : }
7154 : else
7155 : {
7156 206 : CPL_IGNORE_RET_VAL(IsBlockAvailable(nBlockId, &nOffset,
7157 : &nSize, nullptr));
7158 : }
7159 424 : if (nSize)
7160 : {
7161 166 : if (nTotalSize + nSize < nMaxRawBlockCacheSize)
7162 : {
7163 : #ifdef DEBUG_VERBOSE
7164 : CPLDebug(
7165 : "GTiff",
7166 : "Precaching for block (%d, %d), " CPL_FRMT_GUIB
7167 : "-" CPL_FRMT_GUIB,
7168 : iX, iY, nOffset,
7169 : nOffset + static_cast<size_t>(nSize) - 1);
7170 : #endif
7171 166 : aOffsetSize.push_back(
7172 166 : std::pair(nOffset, static_cast<size_t>(nSize)));
7173 166 : nTotalSize += static_cast<size_t>(nSize);
7174 : }
7175 : else
7176 : {
7177 0 : bGoOn = false;
7178 : }
7179 : }
7180 : }
7181 : }
7182 : }
7183 :
7184 234 : std::sort(aOffsetSize.begin(), aOffsetSize.end());
7185 :
7186 234 : if (nTotalSize > 0)
7187 : {
7188 42 : pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
7189 42 : if (pBufferedData)
7190 : {
7191 42 : std::vector<vsi_l_offset> anOffsets;
7192 42 : std::vector<size_t> anSizes;
7193 42 : std::vector<void *> apData;
7194 42 : anOffsets.push_back(aOffsetSize[0].first);
7195 42 : apData.push_back(static_cast<GByte *>(pBufferedData));
7196 42 : size_t nChunkSize = aOffsetSize[0].second;
7197 42 : size_t nAccOffset = 0;
7198 : // Try to merge contiguous or slightly overlapping ranges
7199 166 : for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
7200 : {
7201 248 : if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
7202 124 : aOffsetSize[i].first + aOffsetSize[i].second >=
7203 124 : aOffsetSize[i + 1].first)
7204 : {
7205 120 : const auto overlap = aOffsetSize[i].first +
7206 120 : aOffsetSize[i].second -
7207 120 : aOffsetSize[i + 1].first;
7208 : // That should always be the case for well behaved
7209 : // TIFF files.
7210 120 : if (aOffsetSize[i + 1].second > overlap)
7211 : {
7212 120 : nChunkSize += static_cast<size_t>(
7213 120 : aOffsetSize[i + 1].second - overlap);
7214 : }
7215 : }
7216 : else
7217 : {
7218 : // terminate current block
7219 4 : anSizes.push_back(nChunkSize);
7220 : #ifdef DEBUG_VERBOSE
7221 : CPLDebug("GTiff",
7222 : "Requesting range [" CPL_FRMT_GUIB
7223 : "-" CPL_FRMT_GUIB "]",
7224 : anOffsets.back(),
7225 : anOffsets.back() + anSizes.back() - 1);
7226 : #endif
7227 4 : nAccOffset += nChunkSize;
7228 : // start a new range
7229 4 : anOffsets.push_back(aOffsetSize[i + 1].first);
7230 4 : apData.push_back(static_cast<GByte *>(pBufferedData) +
7231 : nAccOffset);
7232 4 : nChunkSize = aOffsetSize[i + 1].second;
7233 : }
7234 : }
7235 : // terminate last block
7236 42 : anSizes.push_back(nChunkSize);
7237 : #ifdef DEBUG_VERBOSE
7238 : CPLDebug(
7239 : "GTiff",
7240 : "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
7241 : anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
7242 : #endif
7243 :
7244 42 : VSILFILE *fp = VSI_TIFFGetVSILFile(th);
7245 :
7246 : // An error in VSIFReadMultiRangeL() will not be critical,
7247 : // as this method is an optimization, and if it fails,
7248 : // tile-by-tile data acquisition will be done, so we can
7249 : // temporary turn failures into warnings.
7250 : bool ok;
7251 : {
7252 : CPLTurnFailureIntoWarningBackuper
7253 42 : oFailureToWarningBackuper{};
7254 42 : ok = VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
7255 42 : &apData[0], &anOffsets[0],
7256 42 : &anSizes[0], fp) == 0;
7257 : }
7258 :
7259 42 : if (ok)
7260 : {
7261 79 : if (!oMapStrileToOffsetByteCount.empty() &&
7262 37 : !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
7263 : apData))
7264 : {
7265 : // Retry without optimization
7266 0 : CPLFree(pBufferedData);
7267 0 : m_bLeaderSizeAsUInt4 = false;
7268 0 : void *pRet = CacheMultiRange(
7269 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
7270 : panBandMap, nBandCount, psExtraArg);
7271 0 : m_bLeaderSizeAsUInt4 = true;
7272 0 : return pRet;
7273 : }
7274 :
7275 42 : VSI_TIFFSetCachedRanges(
7276 42 : th, static_cast<int>(anSizes.size()), &apData[0],
7277 42 : &anOffsets[0], &anSizes[0]);
7278 : }
7279 : else
7280 : {
7281 0 : CPLFree(pBufferedData);
7282 0 : pBufferedData = nullptr;
7283 : }
7284 : }
7285 : }
7286 : }
7287 268 : return pBufferedData;
7288 : }
7289 :
7290 : /************************************************************************/
7291 : /* CheckCOGLayout() */
7292 : /************************************************************************/
7293 :
7294 2903 : bool GTiffDataset::CheckCOGLayout()
7295 : {
7296 2903 : bool bRet = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
7297 2903 : const bool bNeedsOverviews = (nRasterXSize > 512 || nRasterYSize > 512);
7298 2903 : if (bNeedsOverviews)
7299 355 : ScanDirectories();
7300 2903 : bRet = bRet && !(m_apoOverviewDS.empty() && bNeedsOverviews);
7301 : #ifdef TIFFLIB_MAJOR_VERSION
7302 : // TIFFIsBigTIFF() added in libtiff 4.4
7303 2903 : const uint64_t nExpectedDirOffset = TIFFIsBigTIFF(m_hTIFF) ? 16 : 8;
7304 : #else
7305 : GByte abyData[4] = {0, 0, 0, 0};
7306 : {
7307 : const auto nCurFPOffset = VSIFTellL(m_fpL);
7308 : VSIFSeekL(m_fpL, 0, SEEK_SET);
7309 : CPL_IGNORE_RET_VAL(VSIFReadL(abyData, 1, sizeof(abyData), m_fpL));
7310 : VSIFSeekL(m_fpL, nCurFPOffset, SEEK_SET);
7311 : }
7312 : const uint64_t nExpectedDirOffset =
7313 : (abyData[2] == 0x2B || abyData[3] == 0x2B) ? 16 : 8;
7314 : #endif
7315 2903 : bRet = bRet && (m_nDirOffset == nExpectedDirOffset);
7316 2903 : uint64_t nLastIFDOffset = nExpectedDirOffset;
7317 2903 : int nLastXSize = nRasterXSize;
7318 2903 : int nLastYSize = nRasterYSize;
7319 2962 : for (const auto &poOvrDS : m_apoOverviewDS)
7320 : {
7321 59 : bRet = bRet && poOvrDS->m_nDirOffset > nLastIFDOffset;
7322 59 : bRet = bRet && poOvrDS->nRasterXSize <= nLastXSize;
7323 59 : bRet = bRet && poOvrDS->nRasterYSize <= nLastYSize;
7324 59 : bRet = bRet && CPL_TO_BOOL(TIFFIsTiled(poOvrDS->m_hTIFF));
7325 59 : nLastXSize = poOvrDS->nRasterXSize;
7326 59 : nLastYSize = poOvrDS->nRasterYSize;
7327 59 : nLastIFDOffset = poOvrDS->m_nDirOffset;
7328 : }
7329 2903 : uint64_t nDataOffset = nLastIFDOffset;
7330 2927 : for (auto iter = m_apoOverviewDS.rbegin();
7331 2951 : bRet && iter != m_apoOverviewDS.rend(); ++iter)
7332 : {
7333 24 : bRet = CPL_TO_BOOL(TIFFIsTiled((*iter)->m_hTIFF));
7334 24 : vsi_l_offset nOffset = 0;
7335 24 : vsi_l_offset nSize = 0;
7336 24 : if ((*iter)->IsBlockAvailable(0, &nOffset, &nSize, nullptr))
7337 : {
7338 21 : bRet = bRet && nOffset > nDataOffset;
7339 21 : nDataOffset = nOffset;
7340 : }
7341 : }
7342 2903 : if (!m_apoOverviewDS.empty())
7343 : {
7344 38 : vsi_l_offset nOffset = 0;
7345 38 : vsi_l_offset nSize = 0;
7346 38 : if (IsBlockAvailable(0, &nOffset, &nSize, nullptr))
7347 : {
7348 31 : bRet = bRet && nOffset > nDataOffset;
7349 : }
7350 : }
7351 2903 : return bRet;
7352 : }
|