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