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