Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoTIFF Driver
4 : * Purpose: GDAL GeoTIFF support.
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 :
18 : #include <cassert>
19 :
20 : #include <algorithm>
21 : #include <limits>
22 : #include <memory>
23 : #include <set>
24 : #include <string>
25 : #include <tuple>
26 : #include <utility>
27 :
28 : #include "cpl_error.h"
29 : #include "cpl_vsi.h"
30 : #include "cpl_vsi_virtual.h"
31 : #include "cpl_worker_thread_pool.h"
32 : #include "ogr_proj_p.h" // OSRGetProjTLSContext()
33 : #include "tif_jxl.h"
34 : #include "tifvsi.h"
35 : #include "xtiffio.h"
36 :
37 : static const GTIFFTag asTIFFTags[] = {
38 : {"TIFFTAG_DOCUMENTNAME", TIFFTAG_DOCUMENTNAME, GTIFFTAGTYPE_STRING},
39 : {"TIFFTAG_IMAGEDESCRIPTION", TIFFTAG_IMAGEDESCRIPTION, GTIFFTAGTYPE_STRING},
40 : {"TIFFTAG_SOFTWARE", TIFFTAG_SOFTWARE, GTIFFTAGTYPE_STRING},
41 : {"TIFFTAG_DATETIME", TIFFTAG_DATETIME, GTIFFTAGTYPE_STRING},
42 : {"TIFFTAG_ARTIST", TIFFTAG_ARTIST, GTIFFTAGTYPE_STRING},
43 : {"TIFFTAG_HOSTCOMPUTER", TIFFTAG_HOSTCOMPUTER, GTIFFTAGTYPE_STRING},
44 : {"TIFFTAG_COPYRIGHT", TIFFTAG_COPYRIGHT, GTIFFTAGTYPE_STRING},
45 : {"TIFFTAG_XRESOLUTION", TIFFTAG_XRESOLUTION, GTIFFTAGTYPE_FLOAT},
46 : {"TIFFTAG_YRESOLUTION", TIFFTAG_YRESOLUTION, GTIFFTAGTYPE_FLOAT},
47 : // Dealt as special case.
48 : {"TIFFTAG_RESOLUTIONUNIT", TIFFTAG_RESOLUTIONUNIT, GTIFFTAGTYPE_SHORT},
49 : {"TIFFTAG_MINSAMPLEVALUE", TIFFTAG_MINSAMPLEVALUE, GTIFFTAGTYPE_SHORT},
50 : {"TIFFTAG_MAXSAMPLEVALUE", TIFFTAG_MAXSAMPLEVALUE, GTIFFTAGTYPE_SHORT},
51 :
52 : // GeoTIFF DGIWG tags
53 : {"GEO_METADATA", TIFFTAG_GEO_METADATA, GTIFFTAGTYPE_BYTE_STRING},
54 : {"TIFF_RSID", TIFFTAG_TIFF_RSID, GTIFFTAGTYPE_STRING},
55 : {nullptr, 0, GTIFFTAGTYPE_STRING},
56 : };
57 :
58 : /************************************************************************/
59 : /* GetTIFFTags() */
60 : /************************************************************************/
61 :
62 25815 : const GTIFFTag *GTiffDataset::GetTIFFTags()
63 : {
64 25815 : return asTIFFTags;
65 : }
66 :
67 : /************************************************************************/
68 : /* GTiffDataset() */
69 : /************************************************************************/
70 :
71 27024 : GTiffDataset::GTiffDataset()
72 : : m_bStreamingIn(false), m_bStreamingOut(false), m_bScanDeferred(true),
73 : m_bSingleIFDOpened(false), m_bLoadedBlockDirty(false),
74 : m_bWriteError(false), m_bLookedForProjection(false),
75 : m_bLookedForMDAreaOrPoint(false), m_bGeoTransformValid(false),
76 : m_bCrystalized(true), m_bGeoTIFFInfoChanged(false),
77 : m_bForceUnsetGTOrGCPs(false), m_bForceUnsetProjection(false),
78 : m_bNoDataChanged(false), m_bNoDataSet(false), m_bNoDataSetAsInt64(false),
79 : m_bNoDataSetAsUInt64(false), m_bMetadataChanged(false),
80 : m_bColorProfileMetadataChanged(false), m_bForceUnsetRPC(false),
81 : m_bNeedsRewrite(false), m_bLoadingOtherBands(false), m_bIsOverview(false),
82 : m_bWriteEmptyTiles(true), m_bFillEmptyTilesAtClosing(false),
83 : m_bTreatAsSplit(false), m_bTreatAsSplitBitmap(false), m_bClipWarn(false),
84 : m_bIMDRPCMetadataLoaded(false), m_bEXIFMetadataLoaded(false),
85 : m_bICCMetadataLoaded(false),
86 : m_bHasWarnedDisableAggressiveBandCaching(false),
87 : m_bDontReloadFirstBlock(false), m_bWebPLossless(false),
88 : m_bPromoteTo8Bits(false),
89 : m_bDebugDontWriteBlocks(
90 27041 : CPLTestBool(CPLGetConfigOption("GTIFF_DONT_WRITE_BLOCKS", "NO"))),
91 : m_bIsFinalized(false),
92 : m_bIgnoreReadErrors(
93 27041 : CPLTestBool(CPLGetConfigOption("GTIFF_IGNORE_READ_ERRORS", "NO"))),
94 27038 : m_bDirectIO(CPLTestBool(CPLGetConfigOption("GTIFF_DIRECT_IO", "NO"))),
95 : m_bReadGeoTransform(false), m_bLoadPam(false),
96 : m_bHasGotSiblingFiles(false),
97 : m_bHasIdentifiedAuthorizedGeoreferencingSources(false),
98 : m_bLayoutIFDSBeforeData(false), m_bBlockOrderRowMajor(false),
99 : m_bLeaderSizeAsUInt4(false), m_bTrailerRepeatedLast4BytesRepeated(false),
100 : m_bMaskInterleavedWithImagery(false), m_bKnownIncompatibleEdition(false),
101 : m_bWriteKnownIncompatibleEdition(false), m_bHasUsedReadEncodedAPI(false),
102 81102 : m_bWriteCOGLayout(false), m_bTileInterleave(false)
103 : {
104 : // CPLDebug("GDAL", "sizeof(GTiffDataset) = %d bytes", static_cast<int>(
105 : // sizeof(GTiffDataset)));
106 :
107 : const char *pszVirtualMemIO =
108 27041 : CPLGetConfigOption("GTIFF_VIRTUAL_MEM_IO", "NO");
109 27038 : if (EQUAL(pszVirtualMemIO, "IF_ENOUGH_RAM"))
110 0 : m_eVirtualMemIOUsage = VirtualMemIOEnum::IF_ENOUGH_RAM;
111 27038 : else if (CPLTestBool(pszVirtualMemIO))
112 41 : m_eVirtualMemIOUsage = VirtualMemIOEnum::YES;
113 :
114 27020 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
115 26772 : }
116 :
117 : /************************************************************************/
118 : /* ~GTiffDataset() */
119 : /************************************************************************/
120 :
121 54072 : GTiffDataset::~GTiffDataset()
122 :
123 : {
124 27038 : GTiffDataset::Close();
125 54073 : }
126 :
127 : /************************************************************************/
128 : /* Close() */
129 : /************************************************************************/
130 :
131 47983 : CPLErr GTiffDataset::Close()
132 : {
133 47983 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
134 : {
135 27039 : auto [eErr, bDroppedRef] = Finalize();
136 :
137 27034 : if (m_pszTmpFilename)
138 : {
139 4 : VSIUnlink(m_pszTmpFilename);
140 4 : CPLFree(m_pszTmpFilename);
141 : }
142 :
143 27034 : if (GDALPamDataset::Close() != CE_None)
144 0 : eErr = CE_Failure;
145 27031 : return eErr;
146 : }
147 20944 : return CE_None;
148 : }
149 :
150 : /************************************************************************/
151 : /* Finalize() */
152 : /************************************************************************/
153 :
154 : // Return a tuple (CPLErr, bool) to indicate respectively if an I/O error has
155 : // occurred and if a reference to an auxiliary dataset has been dropped.
156 27100 : std::tuple<CPLErr, bool> GTiffDataset::Finalize()
157 : {
158 27100 : bool bDroppedRef = false;
159 27100 : if (m_bIsFinalized)
160 122 : return std::tuple(CE_None, bDroppedRef);
161 :
162 27039 : CPLErr eErr = CE_None;
163 27039 : Crystalize();
164 :
165 27039 : if (m_bColorProfileMetadataChanged)
166 : {
167 2 : SaveICCProfile(this, nullptr, nullptr, 0);
168 2 : m_bColorProfileMetadataChanged = false;
169 : }
170 :
171 : /* -------------------------------------------------------------------- */
172 : /* Handle forcing xml:ESRI data to be written to PAM. */
173 : /* -------------------------------------------------------------------- */
174 27039 : if (CPLTestBool(CPLGetConfigOption("ESRI_XML_PAM", "NO")))
175 : {
176 7 : char **papszESRIMD = GTiffDataset::GetMetadata("xml:ESRI");
177 7 : if (papszESRIMD)
178 : {
179 5 : GDALPamDataset::SetMetadata(papszESRIMD, "xml:ESRI");
180 : }
181 : }
182 :
183 27039 : if (m_psVirtualMemIOMapping)
184 11 : CPLVirtualMemFree(m_psVirtualMemIOMapping);
185 27039 : m_psVirtualMemIOMapping = nullptr;
186 :
187 : /* -------------------------------------------------------------------- */
188 : /* Fill in missing blocks with empty data. */
189 : /* -------------------------------------------------------------------- */
190 27039 : if (m_bFillEmptyTilesAtClosing)
191 : {
192 : /* --------------------------------------------------------------------
193 : */
194 : /* Ensure any blocks write cached by GDAL gets pushed through libtiff.
195 : */
196 : /* --------------------------------------------------------------------
197 : */
198 5393 : if (FlushCacheInternal(true, /* at closing */
199 5393 : false /* do not call FlushDirectory */) !=
200 : CE_None)
201 : {
202 0 : eErr = CE_Failure;
203 : }
204 :
205 5393 : if (FillEmptyTiles() != CE_None)
206 : {
207 9 : eErr = CE_Failure;
208 : }
209 5393 : m_bFillEmptyTilesAtClosing = false;
210 : }
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Force a complete flush, including either rewriting(moving) */
214 : /* of writing in place the current directory. */
215 : /* -------------------------------------------------------------------- */
216 27039 : if (FlushCacheInternal(true /* at closing */, true) != CE_None)
217 : {
218 7 : eErr = CE_Failure;
219 : }
220 :
221 : // Destroy compression queue
222 27038 : if (m_poCompressQueue)
223 : {
224 58 : m_poCompressQueue->WaitCompletion();
225 :
226 280 : for (int i = 0; i < static_cast<int>(m_asCompressionJobs.size()); ++i)
227 : {
228 222 : CPLFree(m_asCompressionJobs[i].pabyBuffer);
229 222 : if (m_asCompressionJobs[i].pszTmpFilename)
230 : {
231 222 : VSIUnlink(m_asCompressionJobs[i].pszTmpFilename);
232 222 : CPLFree(m_asCompressionJobs[i].pszTmpFilename);
233 : }
234 : }
235 58 : m_poCompressQueue.reset();
236 : }
237 :
238 : /* -------------------------------------------------------------------- */
239 : /* If there is still changed metadata, then presumably we want */
240 : /* to push it into PAM. */
241 : /* -------------------------------------------------------------------- */
242 27039 : if (m_bMetadataChanged)
243 : {
244 6 : PushMetadataToPam();
245 6 : m_bMetadataChanged = false;
246 6 : GDALPamDataset::FlushCache(false);
247 : }
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Cleanup overviews. */
251 : /* -------------------------------------------------------------------- */
252 27039 : if (!m_poBaseDS)
253 : {
254 : // Nullify m_nOverviewCount before deleting overviews, otherwise
255 : // GTiffDataset::FlushDirectory() might try to access an overview
256 : // that is being deleted (#5580)
257 25299 : const int nOldOverviewCount = m_nOverviewCount;
258 25299 : m_nOverviewCount = 0;
259 26684 : for (int i = 0; i < nOldOverviewCount; ++i)
260 : {
261 1384 : delete m_papoOverviewDS[i];
262 1385 : bDroppedRef = true;
263 : }
264 :
265 25359 : for (int i = 0; i < m_nJPEGOverviewCountOri; ++i)
266 : {
267 60 : delete m_papoJPEGOverviewDS[i];
268 59 : bDroppedRef = true;
269 : }
270 25299 : m_nJPEGOverviewCount = 0;
271 25299 : m_nJPEGOverviewCountOri = 0;
272 25299 : CPLFree(m_papoJPEGOverviewDS);
273 25299 : m_papoJPEGOverviewDS = nullptr;
274 : }
275 :
276 : // If we are a mask dataset, we can have overviews, but we don't
277 : // own them. We can only free the array, not the overviews themselves.
278 27039 : CPLFree(m_papoOverviewDS);
279 27038 : m_papoOverviewDS = nullptr;
280 :
281 : // m_poMaskDS is owned by the main image and the overviews
282 : // so because of the latter case, we can delete it even if
283 : // we are not the base image.
284 27038 : if (m_poMaskDS)
285 : {
286 : // Nullify m_nOverviewCount before deleting overviews, otherwise
287 : // GTiffDataset::FlushDirectory() might try to access it while being
288 : // deleted. (#5580)
289 352 : auto poMaskDS = m_poMaskDS;
290 352 : m_poMaskDS = nullptr;
291 352 : delete poMaskDS;
292 352 : bDroppedRef = true;
293 : }
294 :
295 27038 : m_poColorTable.reset();
296 :
297 27038 : if (m_hTIFF)
298 : {
299 27037 : XTIFFClose(m_hTIFF);
300 27038 : m_hTIFF = nullptr;
301 : }
302 :
303 27039 : if (!m_poBaseDS)
304 : {
305 25300 : if (m_fpL != nullptr)
306 : {
307 25300 : if (m_bWriteKnownIncompatibleEdition)
308 : {
309 : GByte abyHeader[4096];
310 9 : VSIFSeekL(m_fpL, 0, SEEK_SET);
311 9 : VSIFReadL(abyHeader, 1, sizeof(abyHeader), m_fpL);
312 9 : const char *szKeyToLook =
313 : "KNOWN_INCOMPATIBLE_EDITION=NO\n "; // trailing space
314 : // intended
315 1449 : for (size_t i = 0; i < sizeof(abyHeader) - strlen(szKeyToLook);
316 : i++)
317 : {
318 1449 : if (memcmp(abyHeader + i, szKeyToLook,
319 : strlen(szKeyToLook)) == 0)
320 : {
321 9 : const char *szNewKey =
322 : "KNOWN_INCOMPATIBLE_EDITION=YES\n";
323 9 : CPLAssert(strlen(szKeyToLook) == strlen(szNewKey));
324 9 : memcpy(abyHeader + i, szNewKey, strlen(szNewKey));
325 9 : VSIFSeekL(m_fpL, 0, SEEK_SET);
326 9 : VSIFWriteL(abyHeader, 1, sizeof(abyHeader), m_fpL);
327 9 : break;
328 : }
329 : }
330 : }
331 25300 : if (VSIFCloseL(m_fpL) != 0)
332 : {
333 0 : eErr = CE_Failure;
334 0 : ReportError(CE_Failure, CPLE_FileIO, "I/O error");
335 : }
336 25299 : m_fpL = nullptr;
337 : }
338 : }
339 :
340 27038 : if (m_fpToWrite != nullptr)
341 : {
342 7 : if (VSIFCloseL(m_fpToWrite) != 0)
343 : {
344 0 : eErr = CE_Failure;
345 0 : ReportError(CE_Failure, CPLE_FileIO, "I/O error");
346 : }
347 7 : m_fpToWrite = nullptr;
348 : }
349 :
350 27038 : m_aoGCPs.clear();
351 :
352 27037 : CSLDestroy(m_papszCreationOptions);
353 27038 : m_papszCreationOptions = nullptr;
354 :
355 27038 : CPLFree(m_pabyTempWriteBuffer);
356 27038 : m_pabyTempWriteBuffer = nullptr;
357 :
358 27038 : m_bIMDRPCMetadataLoaded = false;
359 27038 : CSLDestroy(m_papszMetadataFiles);
360 27037 : m_papszMetadataFiles = nullptr;
361 :
362 27037 : VSIFree(m_pTempBufferForCommonDirectIO);
363 27036 : m_pTempBufferForCommonDirectIO = nullptr;
364 :
365 27036 : CPLFree(m_panMaskOffsetLsb);
366 27039 : m_panMaskOffsetLsb = nullptr;
367 :
368 27039 : CPLFree(m_pszVertUnit);
369 27035 : m_pszVertUnit = nullptr;
370 :
371 27035 : CPLFree(m_pszFilename);
372 27036 : m_pszFilename = nullptr;
373 :
374 27036 : CPLFree(m_pszGeorefFilename);
375 27036 : m_pszGeorefFilename = nullptr;
376 :
377 27036 : CPLFree(m_pszXMLFilename);
378 27036 : m_pszXMLFilename = nullptr;
379 :
380 27036 : m_bIsFinalized = true;
381 :
382 27036 : return std::tuple(eErr, bDroppedRef);
383 : }
384 :
385 : /************************************************************************/
386 : /* CloseDependentDatasets() */
387 : /************************************************************************/
388 :
389 61 : int GTiffDataset::CloseDependentDatasets()
390 : {
391 61 : if (m_poBaseDS)
392 0 : return FALSE;
393 :
394 61 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
395 :
396 : // We ignore eErr as it is not relevant for CloseDependentDatasets(),
397 : // which is called in a "garbage collection" context.
398 61 : auto [eErr, bHasDroppedRefInFinalize] = Finalize();
399 61 : if (bHasDroppedRefInFinalize)
400 1 : bHasDroppedRef = true;
401 :
402 61 : return bHasDroppedRef;
403 : }
404 :
405 : /************************************************************************/
406 : /* IsWholeBlock() */
407 : /************************************************************************/
408 :
409 27 : bool GTiffDataset::IsWholeBlock(int nXOff, int nYOff, int nXSize,
410 : int nYSize) const
411 : {
412 27 : if ((nXOff % m_nBlockXSize) != 0 || (nYOff % m_nBlockYSize) != 0)
413 : {
414 0 : return false;
415 : }
416 27 : if (TIFFIsTiled(m_hTIFF))
417 : {
418 3 : return nXSize == m_nBlockXSize && nYSize == m_nBlockYSize;
419 : }
420 : else
421 : {
422 46 : return nXSize == m_nBlockXSize &&
423 46 : (nYSize == m_nBlockYSize || nYOff + nYSize == nRasterYSize);
424 : }
425 : }
426 :
427 : /************************************************************************/
428 : /* IRasterIO() */
429 : /************************************************************************/
430 :
431 436670 : CPLErr GTiffDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
432 : int nXSize, int nYSize, void *pData,
433 : int nBufXSize, int nBufYSize,
434 : GDALDataType eBufType, int nBandCount,
435 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
436 : GSpacing nLineSpace, GSpacing nBandSpace,
437 : GDALRasterIOExtraArg *psExtraArg)
438 :
439 : {
440 : // Try to pass the request to the most appropriate overview dataset.
441 436670 : if (nBufXSize < nXSize && nBufYSize < nYSize)
442 : {
443 157851 : int bTried = FALSE;
444 157851 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
445 157699 : ++m_nJPEGOverviewVisibilityCounter;
446 157851 : const CPLErr eErr = TryOverviewRasterIO(
447 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
448 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
449 : nBandSpace, psExtraArg, &bTried);
450 157851 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
451 157699 : --m_nJPEGOverviewVisibilityCounter;
452 157851 : if (bTried)
453 22 : return eErr;
454 : }
455 :
456 436648 : if (m_eVirtualMemIOUsage != VirtualMemIOEnum::NO)
457 : {
458 : const int nErr =
459 649 : VirtualMemIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
460 : nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap,
461 : nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
462 649 : if (nErr >= 0)
463 608 : return static_cast<CPLErr>(nErr);
464 : }
465 436040 : if (m_bDirectIO)
466 : {
467 : const int nErr =
468 471 : DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
469 : nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
470 : nLineSpace, nBandSpace, psExtraArg);
471 471 : if (nErr >= 0)
472 414 : return static_cast<CPLErr>(nErr);
473 : }
474 :
475 435626 : bool bCanUseMultiThreadedRead = false;
476 435626 : if (m_nDisableMultiThreadedRead == 0 && m_poThreadPool &&
477 871399 : eRWFlag == GF_Read && nBufXSize == nXSize && nBufYSize == nYSize &&
478 147 : IsMultiThreadedReadCompatible())
479 : {
480 147 : const int nBlockX1 = nXOff / m_nBlockXSize;
481 147 : const int nBlockY1 = nYOff / m_nBlockYSize;
482 147 : const int nBlockX2 = (nXOff + nXSize - 1) / m_nBlockXSize;
483 147 : const int nBlockY2 = (nYOff + nYSize - 1) / m_nBlockYSize;
484 147 : const int nXBlocks = nBlockX2 - nBlockX1 + 1;
485 147 : const int nYBlocks = nBlockY2 - nBlockY1 + 1;
486 147 : const size_t nBlocks =
487 147 : static_cast<size_t>(nXBlocks) * nYBlocks *
488 147 : (m_nPlanarConfig == PLANARCONFIG_CONTIG ? 1 : nBandCount);
489 147 : if (nBlocks > 1)
490 : {
491 144 : bCanUseMultiThreadedRead = true;
492 : }
493 : }
494 :
495 435626 : void *pBufferedData = nullptr;
496 435626 : const auto poFirstBand = cpl::down_cast<GTiffRasterBand *>(papoBands[0]);
497 435626 : const auto eDataType = poFirstBand->GetRasterDataType();
498 :
499 37878 : if (eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
500 473521 : HasOptimizedReadMultiRange() &&
501 17 : !(bCanUseMultiThreadedRead &&
502 3 : VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF))->HasPRead()))
503 : {
504 14 : if (nBands == 1 || m_nPlanarConfig == PLANARCONFIG_CONTIG)
505 : {
506 12 : const int nBandOne = 1;
507 : pBufferedData =
508 12 : CacheMultiRange(nXOff, nYOff, nXSize, nYSize, nBufXSize,
509 12 : nBufYSize, &nBandOne, 1, psExtraArg);
510 : }
511 : else
512 : {
513 : pBufferedData =
514 2 : CacheMultiRange(nXOff, nYOff, nXSize, nYSize, nBufXSize,
515 : nBufYSize, panBandMap, nBandCount, psExtraArg);
516 : }
517 : }
518 435612 : else if (bCanUseMultiThreadedRead)
519 : {
520 144 : return MultiThreadedRead(nXOff, nYOff, nXSize, nYSize, pData, eBufType,
521 : nBandCount, panBandMap, nPixelSpace,
522 144 : nLineSpace, nBandSpace);
523 : }
524 :
525 : // Write optimization when writing whole blocks, by-passing the block cache.
526 : // We require the block cache to be non instantiated to simplify things
527 : // (otherwise we might need to evict corresponding existing blocks from the
528 : // block cache).
529 204420 : else if (eRWFlag == GF_Write && nBands > 1 &&
530 30497 : m_nPlanarConfig == PLANARCONFIG_CONTIG &&
531 : // Could be extended to "odd bit" case, but more work
532 27453 : m_nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
533 27442 : nXSize == nBufXSize && nYSize == nBufYSize &&
534 27440 : nBandCount == nBands && !m_bLoadedBlockDirty &&
535 27418 : (nXOff % m_nBlockXSize) == 0 && (nYOff % m_nBlockYSize) == 0 &&
536 1677 : (nXOff + nXSize == nRasterXSize ||
537 639928 : (nXSize % m_nBlockXSize) == 0) &&
538 1674 : (nYOff + nYSize == nRasterYSize || (nYSize % m_nBlockYSize) == 0))
539 : {
540 1552 : bool bOptimOK = true;
541 1552 : bool bOrderedBands = true;
542 6435 : for (int i = 0; i < nBands; ++i)
543 : {
544 4911 : if (panBandMap[i] != i + 1)
545 : {
546 26 : bOrderedBands = false;
547 : }
548 9822 : if (cpl::down_cast<GTiffRasterBand *>(papoBands[panBandMap[i] - 1])
549 4911 : ->HasBlockCache())
550 : {
551 28 : bOptimOK = false;
552 28 : break;
553 : }
554 : }
555 1552 : if (bOptimOK)
556 : {
557 1524 : Crystalize();
558 :
559 1524 : if (m_bDebugDontWriteBlocks)
560 0 : return CE_None;
561 :
562 1524 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
563 1524 : if (bOrderedBands && nXSize == m_nBlockXSize &&
564 1323 : nYSize == m_nBlockYSize && eBufType == eDataType &&
565 1163 : nBandSpace == nDTSize &&
566 15 : nPixelSpace == static_cast<GSpacing>(nDTSize) * nBands &&
567 5 : nLineSpace == nPixelSpace * m_nBlockXSize)
568 : {
569 : // If writing one single block with the right data type and
570 : // layout (interleaved per pixel), we don't need a temporary
571 : // buffer
572 10 : const int nBlockId = poFirstBand->ComputeBlockId(
573 5 : nXOff / m_nBlockXSize, nYOff / m_nBlockYSize);
574 5 : return WriteEncodedTileOrStrip(nBlockId, pData,
575 5 : /* bPreserveDataBuffer= */ true);
576 : }
577 :
578 : // Make sure m_poGDS->m_pabyBlockBuf is allocated.
579 : // We could actually use any temporary buffer
580 1519 : if (LoadBlockBuf(/* nBlockId = */ -1,
581 1519 : /* bReadFromDisk = */ false) != CE_None)
582 : {
583 0 : return CE_Failure;
584 : }
585 :
586 : // Iterate over all blocks defined by
587 : // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
588 : // and write their content as a nBlockXSize x nBlockYSize strile
589 : // in a temporary buffer, before calling WriteEncodedTileOrStrip()
590 : // on it
591 1519 : const int nYBlockStart = nYOff / m_nBlockYSize;
592 1519 : const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / m_nBlockYSize;
593 1519 : const int nXBlockStart = nXOff / m_nBlockXSize;
594 1519 : const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / m_nBlockXSize;
595 17619 : for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
596 : {
597 : const int nValidY = std::min(
598 16104 : m_nBlockYSize, nRasterYSize - nYBlock * m_nBlockYSize);
599 34461 : for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd;
600 : ++nXBlock)
601 : {
602 : const int nValidX = std::min(
603 18361 : m_nBlockXSize, nRasterXSize - nXBlock * m_nBlockXSize);
604 18361 : if (nValidY < m_nBlockYSize || nValidX < m_nBlockXSize)
605 : {
606 : // Make sure padding bytes at the right/bottom of the
607 : // tile are initialized to zero.
608 332 : memset(m_pabyBlockBuf, 0,
609 332 : static_cast<size_t>(m_nBlockXSize) *
610 332 : m_nBlockYSize * nBands * nDTSize);
611 : }
612 18361 : const auto nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
613 18361 : const GByte *pabySrcData =
614 : static_cast<const GByte *>(pData) +
615 18361 : static_cast<size_t>(nYBlock - nYBlockStart) *
616 18361 : m_nBlockYSize * nLineSpace +
617 18361 : static_cast<size_t>(nXBlock - nXBlockStart) *
618 18361 : m_nBlockXSize * nPixelSpace;
619 18361 : if (bOrderedBands && nBandSpace == nBufDTSize &&
620 16 : nPixelSpace == nBands * nBandSpace)
621 : {
622 : // Input buffer is pixel interleaved
623 17 : for (int iY = 0; iY < nValidY; ++iY)
624 : {
625 16 : GDALCopyWords64(
626 16 : pabySrcData +
627 16 : static_cast<size_t>(iY) * nLineSpace,
628 : eBufType, nBufDTSize,
629 16 : m_pabyBlockBuf + static_cast<size_t>(iY) *
630 16 : m_nBlockXSize * nBands *
631 16 : nDTSize,
632 : eDataType, nDTSize,
633 16 : static_cast<GPtrDiff_t>(nValidX) * nBands);
634 1 : }
635 : }
636 : else
637 : {
638 : // "Random" spacing for input buffer
639 75325 : for (int iBand = 0; iBand < nBands; ++iBand)
640 : {
641 1730930 : for (int iY = 0; iY < nValidY; ++iY)
642 : {
643 1673970 : GDALCopyWords64(
644 1673970 : pabySrcData +
645 1673970 : static_cast<size_t>(iY) * nLineSpace,
646 : eBufType, static_cast<int>(nPixelSpace),
647 1673970 : m_pabyBlockBuf +
648 1673970 : (panBandMap[iBand] - 1 +
649 1673970 : static_cast<size_t>(iY) *
650 1673970 : m_nBlockXSize * nBands) *
651 1673970 : nDTSize,
652 1673970 : eDataType, nDTSize * nBands, nValidX);
653 : }
654 56965 : pabySrcData += nBandSpace;
655 : }
656 : }
657 :
658 : const int nBlockId =
659 18361 : poFirstBand->ComputeBlockId(nXBlock, nYBlock);
660 36722 : if (WriteEncodedTileOrStrip(
661 18361 : nBlockId, m_pabyBlockBuf,
662 18361 : /* bPreserveDataBuffer= */ false) != CE_None)
663 : {
664 4 : return CE_Failure;
665 : }
666 : }
667 : }
668 1515 : return CE_None;
669 : }
670 : }
671 :
672 433958 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
673 433798 : ++m_nJPEGOverviewVisibilityCounter;
674 433958 : const CPLErr eErr = GDALPamDataset::IRasterIO(
675 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
676 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
677 : psExtraArg);
678 433958 : if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
679 433798 : m_nJPEGOverviewVisibilityCounter--;
680 :
681 433958 : if (pBufferedData)
682 : {
683 8 : VSIFree(pBufferedData);
684 8 : VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr, nullptr,
685 : nullptr);
686 : }
687 :
688 433958 : return eErr;
689 : }
690 :
691 : /************************************************************************/
692 : /* GetGTIFFKeysFlavor() */
693 : /************************************************************************/
694 :
695 26561 : GTIFFKeysFlavorEnum GetGTIFFKeysFlavor(CSLConstList papszOptions)
696 : {
697 : const char *pszGeoTIFFKeysFlavor =
698 26561 : CSLFetchNameValueDef(papszOptions, "GEOTIFF_KEYS_FLAVOR", "STANDARD");
699 26645 : if (EQUAL(pszGeoTIFFKeysFlavor, "ESRI_PE"))
700 1 : return GEOTIFF_KEYS_ESRI_PE;
701 26644 : return GEOTIFF_KEYS_STANDARD;
702 : }
703 :
704 : /************************************************************************/
705 : /* GetGeoTIFFVersion() */
706 : /************************************************************************/
707 :
708 26586 : GeoTIFFVersionEnum GetGeoTIFFVersion(CSLConstList papszOptions)
709 : {
710 : const char *pszVersion =
711 26586 : CSLFetchNameValueDef(papszOptions, "GEOTIFF_VERSION", "AUTO");
712 26606 : if (EQUAL(pszVersion, "1.0"))
713 3 : return GEOTIFF_VERSION_1_0;
714 26603 : if (EQUAL(pszVersion, "1.1"))
715 5 : return GEOTIFF_VERSION_1_1;
716 26598 : return GEOTIFF_VERSION_AUTO;
717 : }
718 :
719 : /************************************************************************/
720 : /* InitCreationOrOpenOptions() */
721 : /************************************************************************/
722 :
723 25251 : void GTiffDataset::InitCreationOrOpenOptions(bool bUpdateMode,
724 : CSLConstList papszOptions)
725 : {
726 25251 : InitCompressionThreads(bUpdateMode, papszOptions);
727 :
728 25169 : m_eGeoTIFFKeysFlavor = GetGTIFFKeysFlavor(papszOptions);
729 25112 : m_eGeoTIFFVersion = GetGeoTIFFVersion(papszOptions);
730 25109 : }
731 :
732 : /************************************************************************/
733 : /* IsBlockAvailable() */
734 : /* */
735 : /* Return true if the indicated strip/tile is available. We */
736 : /* establish this by testing if the stripbytecount is zero. If */
737 : /* zero then the block has never been committed to disk. */
738 : /************************************************************************/
739 :
740 2293820 : bool GTiffDataset::IsBlockAvailable(int nBlockId, vsi_l_offset *pnOffset,
741 : vsi_l_offset *pnSize, bool *pbErrOccurred)
742 :
743 : {
744 2293820 : if (pbErrOccurred)
745 2244760 : *pbErrOccurred = false;
746 :
747 2293820 : std::pair<vsi_l_offset, vsi_l_offset> oPair;
748 2293820 : if (m_oCacheStrileToOffsetByteCount.tryGet(nBlockId, oPair))
749 : {
750 452 : if (pnOffset)
751 111 : *pnOffset = oPair.first;
752 452 : if (pnSize)
753 0 : *pnSize = oPair.second;
754 452 : return oPair.first != 0;
755 : }
756 :
757 2293180 : WaitCompletionForBlock(nBlockId);
758 :
759 : // Optimization to avoid fetching the whole Strip/TileCounts and
760 : // Strip/TileOffsets arrays.
761 2293130 : if (eAccess == GA_ReadOnly && !m_bStreamingIn)
762 : {
763 2173100 : int nErrOccurred = 0;
764 : auto bytecount =
765 2173100 : TIFFGetStrileByteCountWithErr(m_hTIFF, nBlockId, &nErrOccurred);
766 2173260 : if (nErrOccurred && pbErrOccurred)
767 1 : *pbErrOccurred = true;
768 2173260 : if (pnOffset)
769 : {
770 2130170 : *pnOffset =
771 2130130 : TIFFGetStrileOffsetWithErr(m_hTIFF, nBlockId, &nErrOccurred);
772 2130170 : if (nErrOccurred && pbErrOccurred)
773 3 : *pbErrOccurred = true;
774 : }
775 2173310 : if (pnSize)
776 11956 : *pnSize = bytecount;
777 2173310 : return bytecount != 0;
778 : }
779 :
780 120030 : if (!m_bCrystalized)
781 : {
782 : // If this is a fresh new file not yet crystalized, do not try to
783 : // read the [Strip|Tile][ByteCounts|Offsets] tags as they do not yet
784 : // exist. Trying would set *pbErrOccurred=true, which is not desirable.
785 2 : if (pnOffset)
786 2 : *pnOffset = 0;
787 2 : if (pnSize)
788 2 : *pnSize = 0;
789 2 : return false;
790 : }
791 :
792 120028 : toff_t *panByteCounts = nullptr;
793 120028 : toff_t *panOffsets = nullptr;
794 120028 : const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
795 :
796 153185 : if ((bIsTiled &&
797 33138 : TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts) &&
798 25024 : (pnOffset == nullptr ||
799 240094 : TIFFGetField(m_hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets))) ||
800 86909 : (!bIsTiled &&
801 86909 : TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts) &&
802 38468 : (pnOffset == nullptr ||
803 38468 : TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets))))
804 : {
805 120047 : if (panByteCounts == nullptr ||
806 63492 : (pnOffset != nullptr && panOffsets == nullptr))
807 : {
808 0 : if (pbErrOccurred)
809 0 : *pbErrOccurred = true;
810 0 : return false;
811 : }
812 : const int nBlockCount =
813 120047 : bIsTiled ? TIFFNumberOfTiles(m_hTIFF) : TIFFNumberOfStrips(m_hTIFF);
814 120047 : if (nBlockId >= nBlockCount)
815 : {
816 0 : if (pbErrOccurred)
817 0 : *pbErrOccurred = true;
818 0 : return false;
819 : }
820 :
821 120047 : if (pnOffset)
822 63492 : *pnOffset = panOffsets[nBlockId];
823 120047 : if (pnSize)
824 7071 : *pnSize = panByteCounts[nBlockId];
825 120047 : return panByteCounts[nBlockId] != 0;
826 : }
827 : else
828 : {
829 0 : if (pbErrOccurred)
830 0 : *pbErrOccurred = true;
831 : }
832 :
833 0 : return false;
834 : }
835 :
836 : /************************************************************************/
837 : /* ReloadDirectory() */
838 : /************************************************************************/
839 :
840 6906 : void GTiffDataset::ReloadDirectory(bool bReopenHandle)
841 : {
842 6906 : bool bNeedSetInvalidDir = true;
843 6906 : if (bReopenHandle)
844 : {
845 : // When issuing a TIFFRewriteDirectory() or when a TIFFFlush() has
846 : // caused a move of the directory, we would need to invalidate the
847 : // tif_lastdiroff member, but it is not possible to do so without
848 : // re-opening the TIFF handle.
849 9 : auto hTIFFNew = VSI_TIFFReOpen(m_hTIFF);
850 9 : if (hTIFFNew != nullptr)
851 : {
852 9 : m_hTIFF = hTIFFNew;
853 9 : bNeedSetInvalidDir = false; // we could do it, but not needed
854 : }
855 : else
856 : {
857 0 : CPLError(CE_Failure, CPLE_AppDefined,
858 : "Cannot re-open TIFF handle for file %s. "
859 : "Directory chaining may be corrupted !",
860 : m_pszFilename);
861 : }
862 : }
863 6906 : if (bNeedSetInvalidDir)
864 : {
865 6897 : TIFFSetSubDirectory(m_hTIFF, 0);
866 : }
867 6906 : CPL_IGNORE_RET_VAL(SetDirectory());
868 6906 : }
869 :
870 : /************************************************************************/
871 : /* SetDirectory() */
872 : /************************************************************************/
873 :
874 48011 : bool GTiffDataset::SetDirectory()
875 :
876 : {
877 48011 : Crystalize();
878 :
879 47973 : if (TIFFCurrentDirOffset(m_hTIFF) == m_nDirOffset)
880 : {
881 39216 : return true;
882 : }
883 :
884 8636 : const int nSetDirResult = TIFFSetSubDirectory(m_hTIFF, m_nDirOffset);
885 8646 : if (!nSetDirResult)
886 0 : return false;
887 :
888 8646 : RestoreVolatileParameters(m_hTIFF);
889 :
890 8645 : return true;
891 : }
892 :
893 : /************************************************************************/
894 : /* GTiffSetDeflateSubCodec() */
895 : /************************************************************************/
896 :
897 6400 : void GTiffSetDeflateSubCodec(TIFF *hTIFF)
898 : {
899 : (void)hTIFF;
900 :
901 : #if defined(TIFFTAG_DEFLATE_SUBCODEC) && defined(LIBDEFLATE_SUPPORT)
902 : // Mostly for strict reproducibility purposes
903 6400 : if (EQUAL(CPLGetConfigOption("GDAL_TIFF_DEFLATE_SUBCODEC", ""), "ZLIB"))
904 : {
905 4097 : TIFFSetField(hTIFF, TIFFTAG_DEFLATE_SUBCODEC, DEFLATE_SUBCODEC_ZLIB);
906 : }
907 : #endif
908 6400 : }
909 :
910 : /************************************************************************/
911 : /* RestoreVolatileParameters() */
912 : /************************************************************************/
913 :
914 41382 : void GTiffDataset::RestoreVolatileParameters(TIFF *hTIFF)
915 : {
916 :
917 : /* -------------------------------------------------------------------- */
918 : /* YCbCr JPEG compressed images should be translated on the fly */
919 : /* to RGB by libtiff/libjpeg unless specifically requested */
920 : /* otherwise. */
921 : /* -------------------------------------------------------------------- */
922 83189 : if (m_nCompression == COMPRESSION_JPEG &&
923 41664 : m_nPhotometric == PHOTOMETRIC_YCBCR &&
924 285 : CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
925 : {
926 285 : int nColorMode = JPEGCOLORMODE_RAW; // Initialize to 0;
927 :
928 285 : TIFFGetField(hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode);
929 285 : if (nColorMode != JPEGCOLORMODE_RGB)
930 : {
931 251 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
932 : }
933 : }
934 :
935 41379 : if (m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
936 35573 : m_nCompression == COMPRESSION_LERC)
937 : {
938 6043 : GTiffSetDeflateSubCodec(hTIFF);
939 : }
940 :
941 : /* -------------------------------------------------------------------- */
942 : /* Propagate any quality settings. */
943 : /* -------------------------------------------------------------------- */
944 41380 : if (eAccess == GA_Update)
945 : {
946 : // Now, reset zip and jpeg quality.
947 35177 : if (m_nJpegQuality > 0 && m_nCompression == COMPRESSION_JPEG)
948 : {
949 : #ifdef DEBUG_VERBOSE
950 : CPLDebug("GTiff", "Propagate JPEG_QUALITY(%d) in SetDirectory()",
951 : m_nJpegQuality);
952 : #endif
953 185 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, m_nJpegQuality);
954 : }
955 35177 : if (m_nJpegTablesMode >= 0 && m_nCompression == COMPRESSION_JPEG)
956 326 : TIFFSetField(hTIFF, TIFFTAG_JPEGTABLESMODE, m_nJpegTablesMode);
957 35177 : if (m_nZLevel > 0 && (m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
958 12 : m_nCompression == COMPRESSION_LERC))
959 26 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, m_nZLevel);
960 35177 : if (m_nLZMAPreset > 0 && m_nCompression == COMPRESSION_LZMA)
961 8 : TIFFSetField(hTIFF, TIFFTAG_LZMAPRESET, m_nLZMAPreset);
962 35177 : if (m_nZSTDLevel > 0 && (m_nCompression == COMPRESSION_ZSTD ||
963 12 : m_nCompression == COMPRESSION_LERC))
964 18 : TIFFSetField(hTIFF, TIFFTAG_ZSTD_LEVEL, m_nZSTDLevel);
965 35177 : if (m_nCompression == COMPRESSION_LERC)
966 : {
967 185 : TIFFSetField(hTIFF, TIFFTAG_LERC_MAXZERROR, m_dfMaxZError);
968 : }
969 35177 : if (m_nWebPLevel > 0 && m_nCompression == COMPRESSION_WEBP)
970 124 : TIFFSetField(hTIFF, TIFFTAG_WEBP_LEVEL, m_nWebPLevel);
971 35177 : if (m_bWebPLossless && m_nCompression == COMPRESSION_WEBP)
972 50 : TIFFSetField(hTIFF, TIFFTAG_WEBP_LOSSLESS, 1);
973 : #ifdef HAVE_JXL
974 35177 : if (m_nCompression == COMPRESSION_JXL ||
975 35175 : m_nCompression == COMPRESSION_JXL_DNG_1_7)
976 : {
977 76 : TIFFSetField(hTIFF, TIFFTAG_JXL_LOSSYNESS,
978 76 : m_bJXLLossless ? JXL_LOSSLESS : JXL_LOSSY);
979 76 : TIFFSetField(hTIFF, TIFFTAG_JXL_EFFORT, m_nJXLEffort);
980 76 : TIFFSetField(hTIFF, TIFFTAG_JXL_DISTANCE, m_fJXLDistance);
981 76 : TIFFSetField(hTIFF, TIFFTAG_JXL_ALPHA_DISTANCE,
982 76 : m_fJXLAlphaDistance);
983 : }
984 : #endif
985 : }
986 41380 : }
987 :
988 : /************************************************************************/
989 : /* ComputeBlocksPerColRowAndBand() */
990 : /************************************************************************/
991 :
992 26953 : bool GTiffDataset::ComputeBlocksPerColRowAndBand(int l_nBands)
993 : {
994 26953 : m_nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, m_nBlockYSize);
995 26953 : m_nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, m_nBlockXSize);
996 26953 : if (m_nBlocksPerColumn > INT_MAX / m_nBlocksPerRow)
997 : {
998 1 : ReportError(CE_Failure, CPLE_AppDefined, "Too many blocks: %d x %d",
999 : m_nBlocksPerRow, m_nBlocksPerColumn);
1000 1 : return false;
1001 : }
1002 :
1003 : // Note: we could potentially go up to UINT_MAX blocks, but currently
1004 : // we use a int nBlockId
1005 26952 : m_nBlocksPerBand = m_nBlocksPerColumn * m_nBlocksPerRow;
1006 26952 : if (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
1007 3811 : m_nBlocksPerBand > INT_MAX / l_nBands)
1008 : {
1009 1 : ReportError(CE_Failure, CPLE_AppDefined,
1010 : "Too many blocks: %d x %d x %d bands", m_nBlocksPerRow,
1011 : m_nBlocksPerColumn, l_nBands);
1012 1 : return false;
1013 : }
1014 26951 : return true;
1015 : }
1016 :
1017 : /************************************************************************/
1018 : /* SetStructuralMDFromParent() */
1019 : /************************************************************************/
1020 :
1021 1115 : void GTiffDataset::SetStructuralMDFromParent(GTiffDataset *poParentDS)
1022 : {
1023 1115 : m_bBlockOrderRowMajor = poParentDS->m_bBlockOrderRowMajor;
1024 1115 : m_bLeaderSizeAsUInt4 = poParentDS->m_bLeaderSizeAsUInt4;
1025 1115 : m_bTrailerRepeatedLast4BytesRepeated =
1026 1115 : poParentDS->m_bTrailerRepeatedLast4BytesRepeated;
1027 1115 : m_bMaskInterleavedWithImagery = poParentDS->m_bMaskInterleavedWithImagery;
1028 1115 : m_bWriteEmptyTiles = poParentDS->m_bWriteEmptyTiles;
1029 1115 : m_bTileInterleave = poParentDS->m_bTileInterleave;
1030 1115 : }
1031 :
1032 : /************************************************************************/
1033 : /* ScanDirectories() */
1034 : /* */
1035 : /* Scan through all the directories finding overviews, masks */
1036 : /* and subdatasets. */
1037 : /************************************************************************/
1038 :
1039 807036 : void GTiffDataset::ScanDirectories()
1040 :
1041 : {
1042 : /* -------------------------------------------------------------------- */
1043 : /* We only scan once. We do not scan for non-base datasets. */
1044 : /* -------------------------------------------------------------------- */
1045 807036 : if (!m_bScanDeferred)
1046 800611 : return;
1047 :
1048 6741 : m_bScanDeferred = false;
1049 :
1050 6741 : if (m_poBaseDS)
1051 316 : return;
1052 :
1053 6425 : Crystalize();
1054 :
1055 6257 : CPLDebug("GTiff", "ScanDirectories()");
1056 :
1057 : /* ==================================================================== */
1058 : /* Scan all directories. */
1059 : /* ==================================================================== */
1060 12512 : CPLStringList aosSubdatasets;
1061 6257 : int iDirIndex = 0;
1062 :
1063 6257 : FlushDirectory();
1064 :
1065 1102 : do
1066 : {
1067 7359 : toff_t nTopDir = TIFFCurrentDirOffset(m_hTIFF);
1068 7360 : uint32_t nSubType = 0;
1069 :
1070 7360 : ++iDirIndex;
1071 :
1072 7360 : toff_t *tmpSubIFDOffsets = nullptr;
1073 7360 : toff_t *subIFDOffsets = nullptr;
1074 7360 : uint16_t nSubIFDs = 0;
1075 7360 : if (TIFFGetField(m_hTIFF, TIFFTAG_SUBIFD, &nSubIFDs,
1076 7360 : &tmpSubIFDOffsets) &&
1077 : iDirIndex == 1)
1078 : {
1079 : subIFDOffsets =
1080 13 : static_cast<toff_t *>(CPLMalloc(nSubIFDs * sizeof(toff_t)));
1081 39 : for (uint16_t iSubIFD = 0; iSubIFD < nSubIFDs; iSubIFD++)
1082 : {
1083 26 : subIFDOffsets[iSubIFD] = tmpSubIFDOffsets[iSubIFD];
1084 : }
1085 : }
1086 :
1087 : // early break for backwards compatibility: if the first directory read
1088 : // is also the last, and there are no subIFDs, no use continuing
1089 7360 : if (iDirIndex == 1 && nSubIFDs == 0 && TIFFLastDirectory(m_hTIFF))
1090 : {
1091 5613 : CPLFree(subIFDOffsets);
1092 5613 : break;
1093 : }
1094 :
1095 3520 : for (uint16_t iSubIFD = 0; iSubIFD <= nSubIFDs; iSubIFD++)
1096 : {
1097 1781 : toff_t nThisDir = nTopDir;
1098 1781 : if (iSubIFD > 0 && iDirIndex > 1) // don't read subIFDs if we are
1099 : // not in the original directory
1100 8 : break;
1101 1773 : if (iSubIFD > 0)
1102 : {
1103 : // make static analyzer happy. subIFDOffsets cannot be null if
1104 : // iSubIFD>0
1105 26 : assert(subIFDOffsets != nullptr);
1106 26 : nThisDir = subIFDOffsets[iSubIFD - 1];
1107 : // CPLDebug("GTiff", "Opened subIFD %d/%d at offset %llu.",
1108 : // iSubIFD, nSubIFDs, nThisDir);
1109 26 : if (!TIFFSetSubDirectory(m_hTIFF, nThisDir))
1110 0 : break;
1111 : }
1112 :
1113 1773 : if (!TIFFGetField(m_hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
1114 399 : nSubType = 0;
1115 :
1116 : /* Embedded overview of the main image */
1117 1772 : if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
1118 1267 : (nSubType & FILETYPE_MASK) == 0 &&
1119 1161 : ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0) &&
1120 903 : m_nOverviewCount < 30 /* to avoid DoS */)
1121 : {
1122 903 : GTiffDataset *poODS = new GTiffDataset();
1123 903 : poODS->ShareLockWithParentDataset(this);
1124 902 : poODS->SetStructuralMDFromParent(this);
1125 902 : if (m_bHasGotSiblingFiles)
1126 171 : poODS->oOvManager.TransferSiblingFiles(
1127 : CSLDuplicate(GetSiblingFiles()));
1128 902 : poODS->m_pszFilename = CPLStrdup(m_pszFilename);
1129 902 : poODS->m_nColorTableMultiplier = m_nColorTableMultiplier;
1130 902 : if (poODS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
1131 1806 : eAccess) != CE_None ||
1132 903 : poODS->GetRasterCount() != GetRasterCount())
1133 : {
1134 0 : delete poODS;
1135 : }
1136 : else
1137 : {
1138 903 : CPLDebug("GTiff", "Opened %dx%d overview.",
1139 : poODS->GetRasterXSize(), poODS->GetRasterYSize());
1140 903 : ++m_nOverviewCount;
1141 1806 : m_papoOverviewDS = static_cast<GTiffDataset **>(CPLRealloc(
1142 903 : m_papoOverviewDS, m_nOverviewCount * (sizeof(void *))));
1143 903 : m_papoOverviewDS[m_nOverviewCount - 1] = poODS;
1144 903 : poODS->m_poBaseDS = this;
1145 903 : poODS->m_bIsOverview = true;
1146 :
1147 : // Propagate a few compression related settings that are
1148 : // no preserved at the TIFF tag level, but may be set in
1149 : // the GDAL_METADATA tag in the IMAGE_STRUCTURE domain
1150 : // Note: this might not be totally reflecting the reality
1151 : // if users have created overviews with different settings
1152 : // but this is probably better than the default ones
1153 903 : poODS->m_nWebPLevel = m_nWebPLevel;
1154 : // below is not a copy & paste error: we transfer the
1155 : // m_dfMaxZErrorOverview overview of the parent to
1156 : // m_dfMaxZError of the overview
1157 903 : poODS->m_dfMaxZError = m_dfMaxZErrorOverview;
1158 903 : poODS->m_dfMaxZErrorOverview = m_dfMaxZErrorOverview;
1159 : #if HAVE_JXL
1160 903 : poODS->m_bJXLLossless = m_bJXLLossless;
1161 903 : poODS->m_fJXLDistance = m_fJXLDistance;
1162 903 : poODS->m_fJXLAlphaDistance = m_fJXLAlphaDistance;
1163 903 : poODS->m_nJXLEffort = m_nJXLEffort;
1164 : #endif
1165 : // Those ones are not serialized currently..
1166 : // poODS->m_nZLevel = m_nZLevel;
1167 : // poODS->m_nLZMAPreset = m_nLZMAPreset;
1168 : // poODS->m_nZSTDLevel = m_nZSTDLevel;
1169 903 : }
1170 : }
1171 : // Embedded mask of the main image.
1172 869 : else if ((nSubType & FILETYPE_MASK) != 0 &&
1173 213 : (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
1174 107 : ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0) &&
1175 107 : m_poMaskDS == nullptr)
1176 : {
1177 107 : m_poMaskDS = new GTiffDataset();
1178 107 : m_poMaskDS->ShareLockWithParentDataset(this);
1179 107 : m_poMaskDS->SetStructuralMDFromParent(this);
1180 107 : m_poMaskDS->m_pszFilename = CPLStrdup(m_pszFilename);
1181 :
1182 : // The TIFF6 specification - page 37 - only allows 1
1183 : // SamplesPerPixel and 1 BitsPerSample Here we support either 1
1184 : // or 8 bit per sample and we support either 1 sample per pixel
1185 : // or as many samples as in the main image We don't check the
1186 : // value of the PhotometricInterpretation tag, which should be
1187 : // set to "Transparency mask" (4) according to the specification
1188 : // (page 36). However, the TIFF6 specification allows image
1189 : // masks to have a higher resolution than the main image, what
1190 : // we don't support here.
1191 :
1192 107 : if (m_poMaskDS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
1193 107 : eAccess) != CE_None ||
1194 107 : m_poMaskDS->GetRasterCount() == 0 ||
1195 107 : !(m_poMaskDS->GetRasterCount() == 1 ||
1196 3 : m_poMaskDS->GetRasterCount() == GetRasterCount()) ||
1197 107 : m_poMaskDS->GetRasterXSize() != GetRasterXSize() ||
1198 321 : m_poMaskDS->GetRasterYSize() != GetRasterYSize() ||
1199 107 : m_poMaskDS->GetRasterBand(1)->GetRasterDataType() !=
1200 : GDT_Byte)
1201 : {
1202 0 : delete m_poMaskDS;
1203 0 : m_poMaskDS = nullptr;
1204 : }
1205 : else
1206 : {
1207 107 : CPLDebug("GTiff", "Opened band mask.");
1208 107 : m_poMaskDS->m_poBaseDS = this;
1209 107 : m_poMaskDS->m_poImageryDS = this;
1210 :
1211 214 : m_poMaskDS->m_bPromoteTo8Bits =
1212 107 : CPLTestBool(CPLGetConfigOption(
1213 : "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
1214 : }
1215 : }
1216 :
1217 : // Embedded mask of an overview. The TIFF6 specification allows the
1218 : // combination of the FILETYPE_xxxx masks.
1219 762 : else if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
1220 364 : (nSubType & FILETYPE_MASK) != 0 &&
1221 106 : ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0))
1222 : {
1223 106 : GTiffDataset *poDS = new GTiffDataset();
1224 106 : poDS->ShareLockWithParentDataset(this);
1225 106 : poDS->SetStructuralMDFromParent(this);
1226 106 : poDS->m_pszFilename = CPLStrdup(m_pszFilename);
1227 106 : if (poDS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
1228 106 : eAccess) != CE_None ||
1229 212 : poDS->GetRasterCount() == 0 ||
1230 106 : poDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
1231 : {
1232 0 : delete poDS;
1233 : }
1234 : else
1235 : {
1236 106 : int i = 0; // Used after for.
1237 158 : for (; i < m_nOverviewCount; ++i)
1238 : {
1239 158 : auto poOvrDS = cpl::down_cast<GTiffDataset *>(
1240 158 : GDALDataset::FromHandle(m_papoOverviewDS[i]));
1241 422 : if (poOvrDS->m_poMaskDS == nullptr &&
1242 106 : poDS->GetRasterXSize() ==
1243 106 : m_papoOverviewDS[i]->GetRasterXSize() &&
1244 106 : poDS->GetRasterYSize() ==
1245 370 : m_papoOverviewDS[i]->GetRasterYSize() &&
1246 106 : (poDS->GetRasterCount() == 1 ||
1247 0 : poDS->GetRasterCount() == GetRasterCount()))
1248 : {
1249 106 : CPLDebug(
1250 : "GTiff", "Opened band mask for %dx%d overview.",
1251 : poDS->GetRasterXSize(), poDS->GetRasterYSize());
1252 106 : poDS->m_poImageryDS = poOvrDS;
1253 106 : poOvrDS->m_poMaskDS = poDS;
1254 106 : poDS->m_bPromoteTo8Bits =
1255 106 : CPLTestBool(CPLGetConfigOption(
1256 : "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
1257 106 : poDS->m_poBaseDS = this;
1258 106 : break;
1259 : }
1260 : }
1261 106 : if (i == m_nOverviewCount)
1262 : {
1263 0 : delete poDS;
1264 : }
1265 106 : }
1266 : }
1267 656 : else if (!m_bSingleIFDOpened &&
1268 652 : (nSubType == 0 || nSubType == FILETYPE_PAGE))
1269 : {
1270 393 : uint32_t nXSize = 0;
1271 393 : uint32_t nYSize = 0;
1272 :
1273 393 : TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
1274 394 : TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
1275 :
1276 : // For Geodetic TIFF grids (GTG)
1277 : // (https://proj.org/specifications/geodetictiffgrids.html)
1278 : // extract the grid_name to put it in the description
1279 788 : std::string osFriendlyName;
1280 394 : char *pszText = nullptr;
1281 458 : if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText) &&
1282 64 : strstr(pszText, "grid_name") != nullptr)
1283 : {
1284 4 : CPLXMLNode *psRoot = CPLParseXMLString(pszText);
1285 : const CPLXMLNode *psItem =
1286 4 : psRoot ? CPLGetXMLNode(psRoot, "=GDALMetadata")
1287 4 : : nullptr;
1288 4 : if (psItem)
1289 4 : psItem = psItem->psChild;
1290 4 : for (; psItem != nullptr; psItem = psItem->psNext)
1291 : {
1292 :
1293 4 : if (psItem->eType != CXT_Element ||
1294 4 : !EQUAL(psItem->pszValue, "Item"))
1295 0 : continue;
1296 :
1297 : const char *pszKey =
1298 4 : CPLGetXMLValue(psItem, "name", nullptr);
1299 : const char *pszValue =
1300 4 : CPLGetXMLValue(psItem, nullptr, nullptr);
1301 : int nBand =
1302 4 : atoi(CPLGetXMLValue(psItem, "sample", "-1"));
1303 4 : if (pszKey && pszValue && nBand <= 0 &&
1304 4 : EQUAL(pszKey, "grid_name"))
1305 : {
1306 4 : osFriendlyName = ": ";
1307 4 : osFriendlyName += pszValue;
1308 4 : break;
1309 : }
1310 : }
1311 :
1312 4 : CPLDestroyXMLNode(psRoot);
1313 : }
1314 :
1315 394 : if (nXSize > INT_MAX || nYSize > INT_MAX)
1316 : {
1317 1 : CPLDebug("GTiff",
1318 : "Skipping directory with too large image: %u x %u",
1319 : nXSize, nYSize);
1320 : }
1321 : else
1322 : {
1323 393 : uint16_t nSPP = 0;
1324 393 : if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP))
1325 0 : nSPP = 1;
1326 :
1327 786 : CPLString osName, osDesc;
1328 : osName.Printf("SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
1329 393 : iDirIndex, iDirIndex, m_pszFilename);
1330 : osDesc.Printf(
1331 : "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
1332 : iDirIndex, iDirIndex, static_cast<int>(nXSize),
1333 393 : static_cast<int>(nYSize), nSPP);
1334 393 : osDesc += osFriendlyName;
1335 :
1336 393 : aosSubdatasets.AddString(osName);
1337 393 : aosSubdatasets.AddString(osDesc);
1338 : }
1339 : }
1340 : }
1341 1747 : CPLFree(subIFDOffsets);
1342 :
1343 : // Make sure we are stepping from the expected directory regardless
1344 : // of churn done processing the above.
1345 1747 : if (TIFFCurrentDirOffset(m_hTIFF) != nTopDir)
1346 13 : TIFFSetSubDirectory(m_hTIFF, nTopDir);
1347 2850 : } while (!m_bSingleIFDOpened && !TIFFLastDirectory(m_hTIFF) &&
1348 1103 : TIFFReadDirectory(m_hTIFF) != 0);
1349 :
1350 6258 : ReloadDirectory();
1351 :
1352 : // If we have a mask for the main image, loop over the overviews, and if
1353 : // they have a mask, let's set this mask as an overview of the main mask.
1354 6257 : if (m_poMaskDS != nullptr)
1355 : {
1356 213 : for (int i = 0; i < m_nOverviewCount; ++i)
1357 : {
1358 106 : if (cpl::down_cast<GTiffDataset *>(
1359 106 : GDALDataset::FromHandle(m_papoOverviewDS[i]))
1360 106 : ->m_poMaskDS != nullptr)
1361 : {
1362 106 : ++m_poMaskDS->m_nOverviewCount;
1363 212 : m_poMaskDS->m_papoOverviewDS =
1364 212 : static_cast<GTiffDataset **>(CPLRealloc(
1365 106 : m_poMaskDS->m_papoOverviewDS,
1366 106 : m_poMaskDS->m_nOverviewCount * (sizeof(void *))));
1367 106 : m_poMaskDS->m_papoOverviewDS[m_poMaskDS->m_nOverviewCount - 1] =
1368 106 : cpl::down_cast<GTiffDataset *>(
1369 106 : GDALDataset::FromHandle(m_papoOverviewDS[i]))
1370 106 : ->m_poMaskDS;
1371 : }
1372 : }
1373 : }
1374 :
1375 : // Assign color interpretation from main dataset
1376 6257 : const int l_nBands = GetRasterCount();
1377 7160 : for (int iOvr = 0; iOvr < m_nOverviewCount; ++iOvr)
1378 : {
1379 2518 : for (int i = 1; i <= l_nBands; i++)
1380 : {
1381 0 : auto poBand = dynamic_cast<GTiffRasterBand *>(
1382 1615 : m_papoOverviewDS[iOvr]->GetRasterBand(i));
1383 1615 : if (poBand)
1384 1614 : poBand->m_eBandInterp =
1385 1614 : GetRasterBand(i)->GetColorInterpretation();
1386 : }
1387 : }
1388 :
1389 : /* -------------------------------------------------------------------- */
1390 : /* Only keep track of subdatasets if we have more than one */
1391 : /* subdataset (pair). */
1392 : /* -------------------------------------------------------------------- */
1393 6257 : if (aosSubdatasets.size() > 2)
1394 : {
1395 10 : m_oGTiffMDMD.SetMetadata(aosSubdatasets.List(), "SUBDATASETS");
1396 : }
1397 : }
1398 :
1399 : /************************************************************************/
1400 : /* GetInternalHandle() */
1401 : /************************************************************************/
1402 :
1403 2128 : void *GTiffDataset::GetInternalHandle(const char * /* pszHandleName */)
1404 :
1405 : {
1406 2128 : return m_hTIFF;
1407 : }
1408 :
1409 : /************************************************************************/
1410 : /* GetFileList() */
1411 : /************************************************************************/
1412 :
1413 2462 : char **GTiffDataset::GetFileList()
1414 :
1415 : {
1416 2462 : LoadGeoreferencingAndPamIfNeeded();
1417 :
1418 2462 : char **papszFileList = GDALPamDataset::GetFileList();
1419 :
1420 2462 : LoadMetadata();
1421 2462 : if (nullptr != m_papszMetadataFiles)
1422 : {
1423 77 : for (int i = 0; m_papszMetadataFiles[i] != nullptr; ++i)
1424 : {
1425 44 : if (CSLFindString(papszFileList, m_papszMetadataFiles[i]) < 0)
1426 : {
1427 : papszFileList =
1428 44 : CSLAddString(papszFileList, m_papszMetadataFiles[i]);
1429 : }
1430 : }
1431 : }
1432 :
1433 2468 : if (m_pszGeorefFilename &&
1434 6 : CSLFindString(papszFileList, m_pszGeorefFilename) == -1)
1435 : {
1436 6 : papszFileList = CSLAddString(papszFileList, m_pszGeorefFilename);
1437 : }
1438 :
1439 2462 : if (m_nXMLGeorefSrcIndex >= 0)
1440 2462 : LookForProjection();
1441 :
1442 2463 : if (m_pszXMLFilename &&
1443 1 : CSLFindString(papszFileList, m_pszXMLFilename) == -1)
1444 : {
1445 1 : papszFileList = CSLAddString(papszFileList, m_pszXMLFilename);
1446 : }
1447 :
1448 2462 : return papszFileList;
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* GetRawBinaryLayout() */
1453 : /************************************************************************/
1454 :
1455 9 : bool GTiffDataset::GetRawBinaryLayout(GDALDataset::RawBinaryLayout &sLayout)
1456 : {
1457 9 : if (eAccess == GA_Update)
1458 : {
1459 3 : FlushCache(false);
1460 3 : Crystalize();
1461 : }
1462 :
1463 9 : if (m_nCompression != COMPRESSION_NONE)
1464 1 : return false;
1465 8 : if (!CPLIsPowerOfTwo(m_nBitsPerSample) || m_nBitsPerSample < 8)
1466 0 : return false;
1467 8 : const auto eDT = GetRasterBand(1)->GetRasterDataType();
1468 8 : if (GDALDataTypeIsComplex(eDT))
1469 0 : return false;
1470 :
1471 8 : toff_t *panByteCounts = nullptr;
1472 8 : toff_t *panOffsets = nullptr;
1473 8 : const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
1474 :
1475 16 : if (!((bIsTiled &&
1476 3 : TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts) &&
1477 3 : TIFFGetField(m_hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets)) ||
1478 5 : (!bIsTiled &&
1479 5 : TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts) &&
1480 5 : TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets))))
1481 : {
1482 0 : return false;
1483 : }
1484 :
1485 8 : const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
1486 8 : vsi_l_offset nImgOffset = panOffsets[0];
1487 16 : GIntBig nPixelOffset = (m_nPlanarConfig == PLANARCONFIG_CONTIG)
1488 8 : ? static_cast<GIntBig>(nDTSize) * nBands
1489 : : nDTSize;
1490 8 : GIntBig nLineOffset = nPixelOffset * nRasterXSize;
1491 8 : GIntBig nBandOffset =
1492 8 : (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1) ? nDTSize : 0;
1493 8 : RawBinaryLayout::Interleaving eInterleaving =
1494 12 : (nBands == 1) ? RawBinaryLayout::Interleaving::UNKNOWN
1495 4 : : (m_nPlanarConfig == PLANARCONFIG_CONTIG)
1496 4 : ? RawBinaryLayout::Interleaving::BIP
1497 : : RawBinaryLayout::Interleaving::BSQ;
1498 8 : if (bIsTiled)
1499 : {
1500 : // Only a single block tiled file with same dimension as the raster
1501 : // might be acceptable
1502 3 : if (m_nBlockXSize != nRasterXSize || m_nBlockYSize != nRasterYSize)
1503 1 : return false;
1504 2 : if (nBands > 1 && m_nPlanarConfig != PLANARCONFIG_CONTIG)
1505 : {
1506 1 : nBandOffset = static_cast<GIntBig>(panOffsets[1]) -
1507 1 : static_cast<GIntBig>(panOffsets[0]);
1508 2 : for (int i = 2; i < nBands; i++)
1509 : {
1510 1 : if (static_cast<GIntBig>(panOffsets[i]) -
1511 1 : static_cast<GIntBig>(panOffsets[i - 1]) !=
1512 : nBandOffset)
1513 0 : return false;
1514 : }
1515 : }
1516 : }
1517 : else
1518 : {
1519 5 : const int nStrips = DIV_ROUND_UP(nRasterYSize, m_nRowsPerStrip);
1520 5 : if (nBands == 1 || m_nPlanarConfig == PLANARCONFIG_CONTIG)
1521 : {
1522 4 : vsi_l_offset nLastStripEnd = panOffsets[0] + panByteCounts[0];
1523 16 : for (int iStrip = 1; iStrip < nStrips; iStrip++)
1524 : {
1525 12 : if (nLastStripEnd != panOffsets[iStrip])
1526 0 : return false;
1527 12 : nLastStripEnd = panOffsets[iStrip] + panByteCounts[iStrip];
1528 4 : }
1529 : }
1530 : else
1531 : {
1532 : // Note: we could potentially have BIL order with m_nRowsPerStrip ==
1533 : // 1 and if strips are ordered strip_line_1_band_1, ...,
1534 : // strip_line_1_band_N, strip_line2_band1, ... strip_line2_band_N,
1535 : // etc.... but that'd be faily exotic ! So only detect BSQ layout
1536 : // here
1537 1 : nBandOffset = static_cast<GIntBig>(panOffsets[nStrips]) -
1538 1 : static_cast<GIntBig>(panOffsets[0]);
1539 4 : for (int i = 0; i < nBands; i++)
1540 : {
1541 3 : uint32_t iStripOffset = nStrips * i;
1542 3 : vsi_l_offset nLastStripEnd =
1543 3 : panOffsets[iStripOffset] + panByteCounts[iStripOffset];
1544 3 : for (int iStrip = 1; iStrip < nStrips; iStrip++)
1545 : {
1546 0 : if (nLastStripEnd != panOffsets[iStripOffset + iStrip])
1547 0 : return false;
1548 0 : nLastStripEnd = panOffsets[iStripOffset + iStrip] +
1549 0 : panByteCounts[iStripOffset + iStrip];
1550 : }
1551 3 : if (i >= 2 && static_cast<GIntBig>(panOffsets[iStripOffset]) -
1552 1 : static_cast<GIntBig>(
1553 1 : panOffsets[iStripOffset - nStrips]) !=
1554 : nBandOffset)
1555 : {
1556 0 : return false;
1557 : }
1558 : }
1559 : }
1560 : }
1561 :
1562 7 : sLayout.osRawFilename = m_pszFilename;
1563 7 : sLayout.eInterleaving = eInterleaving;
1564 7 : sLayout.eDataType = eDT;
1565 : #ifdef CPL_LSB
1566 7 : sLayout.bLittleEndianOrder = !TIFFIsByteSwapped(m_hTIFF);
1567 : #else
1568 : sLayout.bLittleEndianOrder = TIFFIsByteSwapped(m_hTIFF);
1569 : #endif
1570 7 : sLayout.nImageOffset = nImgOffset;
1571 7 : sLayout.nPixelOffset = nPixelOffset;
1572 7 : sLayout.nLineOffset = nLineOffset;
1573 7 : sLayout.nBandOffset = nBandOffset;
1574 :
1575 7 : return true;
1576 : }
1577 :
1578 : /************************************************************************/
1579 : /* GTiffDatasetLibGeotiffErrorCallback() */
1580 : /************************************************************************/
1581 :
1582 0 : static void GTiffDatasetLibGeotiffErrorCallback(GTIF *, int level,
1583 : const char *pszMsg, ...)
1584 : {
1585 : va_list ap;
1586 0 : va_start(ap, pszMsg);
1587 0 : CPLErrorV((level == LIBGEOTIFF_WARNING) ? CE_Warning : CE_Failure,
1588 : CPLE_AppDefined, pszMsg, ap);
1589 0 : va_end(ap);
1590 0 : }
1591 :
1592 : /************************************************************************/
1593 : /* GTIFNew() */
1594 : /************************************************************************/
1595 :
1596 26756 : /* static */ GTIF *GTiffDataset::GTIFNew(TIFF *hTIFF)
1597 : {
1598 26756 : GTIF *gtif = GTIFNewEx(hTIFF, GTiffDatasetLibGeotiffErrorCallback, nullptr);
1599 26756 : if (gtif)
1600 : {
1601 26756 : GTIFAttachPROJContext(gtif, OSRGetProjTLSContext());
1602 : }
1603 26756 : return gtif;
1604 : }
|