Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GeoTIFF Driver
4 : * Purpose: Implement system hook functions for libtiff on top of CPL/VSI,
5 : * including > 2GB support. Based on tif_unix.c from libtiff
6 : * distribution.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam, warmerdam@pobox.com
11 : * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : // TIFF Library UNIX-specific Routines.
17 :
18 : #include "cpl_port.h"
19 : #include "tifvsi.h"
20 :
21 : #include <assert.h>
22 : #include <string.h>
23 : #include <cerrno>
24 : #if HAVE_FCNTL_H
25 : #include <fcntl.h>
26 : #endif
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_vsi.h"
30 : #include "cpl_string.h"
31 :
32 : // We avoid including xtiffio.h since it drags in the libgeotiff version
33 : // of the VSI functions.
34 :
35 : #ifdef RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS
36 : #include "gdal_libgeotiff_symbol_rename.h"
37 : #endif
38 :
39 : #include "xtiffio.h"
40 :
41 : #include <limits>
42 :
43 : #if (TIFFLIB_VERSION > 20220520) || defined(INTERNAL_LIBTIFF) // > 4.4.0
44 : #define SUPPORTS_LIBTIFF_OPEN_OPTIONS
45 :
46 : extern int GTiffWarningHandlerExt(TIFF *tif, void *user_data,
47 : const char *module, const char *fmt,
48 : va_list ap);
49 : extern int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
50 : const char *fmt, va_list ap);
51 :
52 : #endif
53 :
54 : constexpr int BUFFER_SIZE = 65536;
55 :
56 : struct GDALTiffHandle;
57 :
58 : struct GDALTiffHandleShared
59 : {
60 : VSILFILE *fpL;
61 : bool bReadOnly;
62 : bool bLazyStrileLoading;
63 : char *pszName;
64 : GDALTiffHandle *psActiveHandle; // only used on the parent
65 : int nUserCounter;
66 : bool bAtEndOfFile;
67 : vsi_l_offset nFileLength;
68 : };
69 :
70 : struct GDALTiffHandle
71 : {
72 : bool bFree;
73 :
74 : GDALTiffHandle *psParent; // nullptr for the parent itself
75 : GDALTiffHandleShared *psShared;
76 :
77 : GByte *abyWriteBuffer;
78 : int nWriteBufferSize;
79 :
80 : // For pseudo-mmap'ed /vsimem/ file
81 : vsi_l_offset nDataLength;
82 : void *pBase;
83 :
84 : // If we pre-cached data (typically from /vsicurl/ )
85 : int nCachedRanges;
86 : void **ppCachedData;
87 : vsi_l_offset *panCachedOffsets;
88 : size_t *panCachedSizes;
89 : };
90 :
91 : static bool GTHFlushBuffer(thandle_t th);
92 :
93 3269940 : static void SetActiveGTH(GDALTiffHandle *psGTH)
94 : {
95 3269940 : auto psShared = psGTH->psShared;
96 3269940 : if (psShared->psActiveHandle != psGTH)
97 : {
98 16298 : if (psShared->psActiveHandle != nullptr)
99 : {
100 14736 : GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
101 : }
102 16298 : psShared->psActiveHandle = psGTH;
103 : }
104 3269940 : }
105 :
106 229 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
107 : {
108 229 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
109 283 : for (int i = 0; i < psGTH->nCachedRanges; i++)
110 : {
111 283 : if (nOffset >= psGTH->panCachedOffsets[i] &&
112 283 : nOffset + nSize <=
113 283 : psGTH->panCachedOffsets[i] + psGTH->panCachedSizes[i])
114 : {
115 229 : return static_cast<GByte *>(psGTH->ppCachedData[i]) +
116 229 : (nOffset - psGTH->panCachedOffsets[i]);
117 : }
118 54 : if (nOffset < psGTH->panCachedOffsets[i])
119 0 : break;
120 : }
121 0 : return nullptr;
122 : }
123 :
124 2608420 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
125 : {
126 2608420 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
127 : // SetActiveGTH(psGTH);
128 :
129 2608420 : if (psGTH->nCachedRanges)
130 : {
131 11 : const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
132 : void *data =
133 11 : VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
134 11 : if (data)
135 : {
136 11 : memcpy(buf, data, size);
137 11 : VSIFSeekL(psGTH->psShared->fpL, nCurOffset + size, SEEK_SET);
138 11 : return size;
139 : }
140 : }
141 :
142 : #ifdef DEBUG_VERBOSE_EXTRA
143 : CPLDebug("GTiff", "Reading %d bytes at offset " CPL_FRMT_GUIB,
144 : static_cast<int>(size), VSIFTellL(psGTH->psShared->fpL));
145 : #endif
146 2608400 : return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
147 : }
148 :
149 2612810 : static bool GTHFlushBuffer(thandle_t th)
150 : {
151 2612810 : GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
152 2612810 : bool bRet = true;
153 2612810 : if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
154 : {
155 : const tsize_t nRet =
156 22150 : VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
157 11075 : psGTH->psShared->fpL);
158 11075 : bRet = nRet == psGTH->nWriteBufferSize;
159 11075 : if (!bRet)
160 : {
161 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
162 : }
163 11075 : psGTH->nWriteBufferSize = 0;
164 : }
165 2612810 : return bRet;
166 : }
167 :
168 388569 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
169 : {
170 388569 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
171 388569 : SetActiveGTH(psGTH);
172 :
173 : // If we have a write buffer and are at end of file, then accumulate
174 : // the bytes until the buffer is full.
175 388559 : if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
176 : {
177 91691 : const GByte *pabyData = reinterpret_cast<GByte *>(buf);
178 91691 : tsize_t nRemainingBytes = size;
179 : while (true)
180 : {
181 96450 : if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
182 : {
183 91691 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
184 : pabyData, nRemainingBytes);
185 91691 : psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
186 91691 : if (psGTH->psShared->bAtEndOfFile)
187 : {
188 91691 : psGTH->psShared->nFileLength += size;
189 : }
190 91691 : return size;
191 : }
192 :
193 4759 : int nAppendable = BUFFER_SIZE - psGTH->nWriteBufferSize;
194 4759 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize, pabyData,
195 : nAppendable);
196 9518 : const tsize_t nRet = VSIFWriteL(psGTH->abyWriteBuffer, 1,
197 4759 : BUFFER_SIZE, psGTH->psShared->fpL);
198 4759 : psGTH->nWriteBufferSize = 0;
199 4759 : if (nRet != BUFFER_SIZE)
200 : {
201 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
202 0 : return 0;
203 : }
204 :
205 4759 : pabyData += nAppendable;
206 4759 : nRemainingBytes -= nAppendable;
207 4759 : }
208 : }
209 :
210 296868 : const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
211 296876 : if (nRet < size)
212 : {
213 73 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
214 : }
215 :
216 296874 : if (psGTH->psShared->bAtEndOfFile)
217 : {
218 128981 : psGTH->psShared->nFileLength += nRet;
219 : }
220 296874 : return nRet;
221 : }
222 :
223 2776710 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
224 : {
225 2776710 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
226 2776710 : SetActiveGTH(psGTH);
227 :
228 : // Optimization: if we are already at end, then no need to
229 : // issue a VSIFSeekL().
230 2776680 : if (whence == SEEK_END)
231 : {
232 246528 : if (psGTH->psShared->bAtEndOfFile)
233 : {
234 192774 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
235 : }
236 :
237 53754 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) != 0)
238 : {
239 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
240 0 : return static_cast<toff_t>(-1);
241 : }
242 53755 : psGTH->psShared->bAtEndOfFile = true;
243 53755 : psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
244 53752 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
245 : }
246 :
247 2530150 : GTHFlushBuffer(th);
248 2530160 : psGTH->psShared->bAtEndOfFile = false;
249 2530160 : psGTH->psShared->nFileLength = 0;
250 :
251 2530160 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
252 : {
253 2530260 : return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
254 : }
255 : else
256 : {
257 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
258 0 : return static_cast<toff_t>(-1);
259 : }
260 : }
261 :
262 61980 : static void FreeGTH(GDALTiffHandle *psGTH)
263 : {
264 61980 : psGTH->psShared->nUserCounter--;
265 61980 : if (psGTH->psParent == nullptr)
266 : {
267 60419 : assert(psGTH->psShared->nUserCounter == 0);
268 60419 : CPLFree(psGTH->psShared->pszName);
269 60422 : CPLFree(psGTH->psShared);
270 : }
271 : else
272 : {
273 1561 : if (psGTH->psShared->psActiveHandle == psGTH)
274 1562 : psGTH->psShared->psActiveHandle = nullptr;
275 : }
276 61983 : CPLFree(psGTH->abyWriteBuffer);
277 61979 : CPLFree(psGTH->ppCachedData);
278 61979 : CPLFree(psGTH->panCachedOffsets);
279 61979 : CPLFree(psGTH->panCachedSizes);
280 61982 : CPLFree(psGTH);
281 61983 : }
282 :
283 61979 : static int _tiffCloseProc(thandle_t th)
284 : {
285 61979 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
286 61979 : SetActiveGTH(psGTH);
287 61976 : GTHFlushBuffer(th);
288 61975 : if (psGTH->bFree)
289 61968 : FreeGTH(psGTH);
290 61979 : return 0;
291 : }
292 :
293 29668 : static toff_t _tiffSizeProc(thandle_t th)
294 : {
295 29668 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
296 29668 : SetActiveGTH(psGTH);
297 :
298 29642 : if (psGTH->psShared->bAtEndOfFile)
299 : {
300 7744 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
301 : }
302 :
303 21898 : const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
304 21886 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
305 :
306 : const toff_t file_size =
307 21836 : static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
308 21884 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
309 :
310 21869 : return file_size;
311 : }
312 :
313 22693 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
314 : {
315 22693 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
316 : // SetActiveGTH(psGTH);
317 :
318 22693 : if (psGTH->pBase)
319 : {
320 8 : *pbase = psGTH->pBase;
321 8 : *psize = static_cast<toff_t>(psGTH->nDataLength);
322 8 : return 1;
323 : }
324 22685 : return 0;
325 : }
326 :
327 8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
328 : toff_t /* size */)
329 : {
330 8 : }
331 :
332 5681 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
333 : {
334 5681 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
335 5681 : SetActiveGTH(psGTH);
336 5681 : VSI_TIFFFlushBufferedWrite(th);
337 5681 : return psGTH->psShared->fpL;
338 : }
339 :
340 5906 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
341 : {
342 5906 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
343 5906 : SetActiveGTH(psGTH);
344 5906 : psGTH->psShared->bAtEndOfFile = false;
345 5906 : return GTHFlushBuffer(th);
346 : }
347 :
348 371 : int VSI_TIFFHasCachedRanges(thandle_t th)
349 : {
350 371 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
351 371 : return psGTH->nCachedRanges != 0;
352 : }
353 :
354 24695 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
355 : {
356 24695 : thandle_t th = TIFFClientdata(tif);
357 24695 : return _tiffSeekProc(th, off, whence);
358 : }
359 :
360 49042 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
361 : {
362 49042 : thandle_t th = TIFFClientdata(tif);
363 49042 : return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
364 49042 : buffersize)) == buffersize;
365 : }
366 :
367 82 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
368 : const vsi_l_offset *panOffsets,
369 : const size_t *panSizes)
370 : {
371 82 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
372 82 : psGTH->nCachedRanges = nRanges;
373 82 : if (nRanges)
374 : {
375 41 : psGTH->ppCachedData = static_cast<void **>(
376 41 : CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
377 41 : memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
378 :
379 82 : psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
380 41 : psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
381 41 : memcpy(psGTH->panCachedOffsets, panOffsets,
382 41 : nRanges * sizeof(vsi_l_offset));
383 :
384 41 : psGTH->panCachedSizes = static_cast<size_t *>(
385 41 : CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
386 41 : memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
387 : }
388 82 : }
389 :
390 61983 : static bool IsReadOnly(const char *mode)
391 : {
392 61983 : bool bReadOnly = true;
393 252048 : for (int i = 0; mode[i] != '\0'; i++)
394 : {
395 190065 : if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
396 : {
397 74864 : bReadOnly = false;
398 : }
399 : }
400 61983 : return bReadOnly;
401 : }
402 :
403 61981 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
404 : {
405 : // No need to buffer on /vsimem/
406 61981 : const bool bReadOnly = IsReadOnly(pszMode);
407 61960 : bool bAllocBuffer = !bReadOnly;
408 61960 : if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
409 : {
410 51433 : if (bReadOnly &&
411 7862 : CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
412 : {
413 8 : psGTH->nDataLength = 0;
414 8 : psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
415 : &psGTH->nDataLength, FALSE);
416 : }
417 43571 : bAllocBuffer = false;
418 : }
419 :
420 61946 : psGTH->abyWriteBuffer =
421 61946 : bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
422 61946 : psGTH->nWriteBufferSize = 0;
423 61946 : }
424 :
425 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
426 61966 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
427 : {
428 61966 : TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
429 61940 : TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
430 : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
431 : // Read-once and stored in static storage otherwise affects
432 : // autotest/benchmark/test_gtiff.py::test_gtiff_byte
433 607 : static const GIntBig nMemLimit = []() -> GIntBig
434 : {
435 607 : if (const char *pszLimit =
436 607 : CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
437 0 : return CPLAtoGIntBig(pszLimit);
438 : else
439 : {
440 607 : const auto nUsableRAM = CPLGetUsablePhysicalRAM();
441 607 : if (nUsableRAM > 0)
442 : {
443 : // coverity[return_overflow]
444 607 : return nUsableRAM / 10 * 9;
445 : }
446 : else
447 0 : return 0;
448 : }
449 61929 : }();
450 61959 : if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
451 : {
452 : //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
453 : // static_cast<uint64_t>(nMemLimit));
454 61957 : TIFFOpenOptionsSetMaxCumulatedMemAlloc(
455 : opts, static_cast<tmsize_t>(nMemLimit));
456 : }
457 : #endif
458 61936 : }
459 : #endif
460 :
461 61957 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
462 : {
463 61957 : InitializeWriteBuffer(psGTH, pszMode);
464 :
465 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
466 61933 : XTIFFInitialize();
467 61953 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
468 61923 : if (opts == nullptr)
469 : {
470 0 : FreeGTH(psGTH);
471 0 : return nullptr;
472 : }
473 61923 : VSI_TIFFSetOpenOptions(opts);
474 123879 : TIFF *tif = TIFFClientOpenExt(
475 61938 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
476 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
477 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
478 61941 : TIFFOpenOptionsFree(opts);
479 : #else
480 : TIFF *tif = XTIFFClientOpen(
481 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
482 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
483 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
484 : #endif
485 61936 : if (tif == nullptr)
486 14 : FreeGTH(psGTH);
487 :
488 61897 : return tif;
489 : }
490 :
491 : // Open a TIFF file for read/writing.
492 60424 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
493 : {
494 :
495 60424 : if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
496 0 : return nullptr;
497 :
498 : GDALTiffHandle *psGTH =
499 60420 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
500 60419 : psGTH->bFree = true;
501 60419 : psGTH->psParent = nullptr;
502 60415 : psGTH->psShared = static_cast<GDALTiffHandleShared *>(
503 60419 : CPLCalloc(1, sizeof(GDALTiffHandleShared)));
504 60415 : psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
505 60415 : psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
506 60415 : psGTH->psShared->pszName = CPLStrdup(name);
507 60415 : psGTH->psShared->fpL = fpL;
508 60415 : psGTH->psShared->psActiveHandle = psGTH;
509 60415 : psGTH->psShared->nFileLength = 0;
510 60415 : psGTH->psShared->bAtEndOfFile = false;
511 60415 : psGTH->psShared->nUserCounter = 1;
512 :
513 60415 : return VSI_TIFFOpen_common(psGTH, mode);
514 : }
515 :
516 1562 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
517 : {
518 : GDALTiffHandle *psGTHParent =
519 1562 : reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
520 :
521 : GDALTiffHandle *psGTH =
522 1562 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
523 1562 : psGTH->bFree = true;
524 1562 : psGTH->psParent = psGTHParent;
525 1562 : psGTH->psShared = psGTHParent->psShared;
526 1562 : psGTH->psShared->nUserCounter++;
527 :
528 1562 : SetActiveGTH(psGTH);
529 1562 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
530 1562 : psGTH->psShared->bAtEndOfFile = false;
531 :
532 1562 : const char *mode =
533 750 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
534 3124 : ? "rDO"
535 1624 : : psGTH->psShared->bReadOnly ? "r"
536 812 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
537 : : "r+";
538 1562 : return VSI_TIFFOpen_common(psGTH, mode);
539 : }
540 :
541 : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
542 9 : TIFF *VSI_TIFFReOpen(TIFF *tif)
543 : {
544 9 : thandle_t th = TIFFClientdata(tif);
545 9 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
546 :
547 : // Disable freeing of psGTH in _tiffCloseProc(), which could be called
548 : // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
549 9 : psGTH->bFree = false;
550 :
551 9 : const char *mode =
552 0 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
553 18 : ? "rDO"
554 18 : : psGTH->psShared->bReadOnly ? "r"
555 9 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
556 : : "r+";
557 :
558 9 : SetActiveGTH(psGTH);
559 9 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
560 9 : psGTH->psShared->bAtEndOfFile = false;
561 :
562 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
563 9 : TIFF *newHandle = nullptr;
564 9 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
565 9 : if (opts != nullptr)
566 : {
567 9 : VSI_TIFFSetOpenOptions(opts);
568 18 : newHandle = TIFFClientOpenExt(
569 9 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
570 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
571 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
572 9 : TIFFOpenOptionsFree(opts);
573 : }
574 : #else
575 : TIFF *newHandle = XTIFFClientOpen(
576 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
577 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
578 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
579 : #endif
580 9 : if (newHandle != nullptr)
581 9 : XTIFFClose(tif);
582 :
583 9 : psGTH->bFree = true;
584 :
585 9 : return newHandle;
586 : }
|