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