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