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