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