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 3478600 : static void SetActiveGTH(GDALTiffHandle *psGTH)
91 : {
92 3478600 : auto psShared = psGTH->psShared;
93 3478600 : if (psShared->psActiveHandle != psGTH)
94 : {
95 17543 : if (psShared->psActiveHandle != nullptr)
96 : {
97 15742 : GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
98 : }
99 17544 : psShared->psActiveHandle = psGTH;
100 : }
101 3478600 : }
102 :
103 251 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
104 : {
105 251 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
106 305 : for (int i = 0; i < psGTH->nCachedRanges; i++)
107 : {
108 305 : 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 54 : if (nOffset < psGTH->panCachedOffsets[i])
116 0 : break;
117 : }
118 0 : return nullptr;
119 : }
120 :
121 2724590 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
122 : {
123 2724590 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
124 : // SetActiveGTH(psGTH);
125 :
126 2724590 : if (psGTH->nCachedRanges)
127 : {
128 11 : const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
129 : void *data =
130 11 : VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
131 11 : 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 2724580 : return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
144 : }
145 :
146 2732600 : static bool GTHFlushBuffer(thandle_t th)
147 : {
148 2732600 : GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
149 2732600 : bool bRet = true;
150 2732600 : if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
151 : {
152 : const tsize_t nRet =
153 22468 : VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
154 11234 : psGTH->psShared->fpL);
155 11234 : bRet = nRet == psGTH->nWriteBufferSize;
156 11234 : if (!bRet)
157 : {
158 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
159 : }
160 11234 : psGTH->nWriteBufferSize = 0;
161 : }
162 2732600 : return bRet;
163 : }
164 :
165 455859 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
166 : {
167 455859 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
168 455859 : 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 455828 : if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
173 : {
174 92970 : const GByte *pabyData = reinterpret_cast<GByte *>(buf);
175 92970 : tsize_t nRemainingBytes = size;
176 : while (true)
177 : {
178 97763 : if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
179 : {
180 92970 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
181 : pabyData, nRemainingBytes);
182 92970 : psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
183 92970 : if (psGTH->psShared->bAtEndOfFile)
184 : {
185 92970 : psGTH->psShared->nFileLength += size;
186 : }
187 92970 : 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 362858 : const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
208 362881 : if (nRet < size)
209 : {
210 76 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
211 : }
212 :
213 362875 : if (psGTH->psShared->bAtEndOfFile)
214 : {
215 136292 : psGTH->psShared->nFileLength += nRet;
216 : }
217 362875 : return nRet;
218 : }
219 :
220 2902200 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
221 : {
222 2902200 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
223 2902200 : SetActiveGTH(psGTH);
224 :
225 : // Optimization: if we are already at end, then no need to
226 : // issue a VSIFSeekL().
227 2902070 : if (whence == SEEK_END)
228 : {
229 261203 : if (psGTH->psShared->bAtEndOfFile)
230 : {
231 200508 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
232 : }
233 :
234 60695 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) != 0)
235 : {
236 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
237 0 : return static_cast<toff_t>(-1);
238 : }
239 60692 : psGTH->psShared->bAtEndOfFile = true;
240 60692 : psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
241 60692 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
242 : }
243 :
244 2640870 : GTHFlushBuffer(th);
245 2640890 : psGTH->psShared->bAtEndOfFile = false;
246 2640890 : psGTH->psShared->nFileLength = 0;
247 :
248 2640890 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
249 : {
250 2641100 : return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
251 : }
252 : else
253 : {
254 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
255 0 : return static_cast<toff_t>(-1);
256 : }
257 : }
258 :
259 69569 : static void FreeGTH(GDALTiffHandle *psGTH)
260 : {
261 69569 : psGTH->psShared->nUserCounter--;
262 69569 : if (psGTH->psParent == nullptr)
263 : {
264 67768 : assert(psGTH->psShared->nUserCounter == 0);
265 67768 : CPLFree(psGTH->psShared->pszName);
266 67772 : CPLFree(psGTH->psShared);
267 : }
268 : else
269 : {
270 1801 : if (psGTH->psShared->psActiveHandle == psGTH)
271 1801 : psGTH->psShared->psActiveHandle = nullptr;
272 : }
273 69571 : CPLFree(psGTH->abyWriteBuffer);
274 69571 : CPLFree(psGTH->ppCachedData);
275 69572 : CPLFree(psGTH->panCachedOffsets);
276 69571 : CPLFree(psGTH->panCachedSizes);
277 69569 : CPLFree(psGTH);
278 69571 : }
279 :
280 69567 : static int _tiffCloseProc(thandle_t th)
281 : {
282 69567 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
283 69567 : SetActiveGTH(psGTH);
284 69565 : GTHFlushBuffer(th);
285 69566 : if (psGTH->bFree)
286 69555 : FreeGTH(psGTH);
287 69563 : return 0;
288 : }
289 :
290 36650 : static toff_t _tiffSizeProc(thandle_t th)
291 : {
292 36650 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
293 36650 : SetActiveGTH(psGTH);
294 :
295 36604 : if (psGTH->psShared->bAtEndOfFile)
296 : {
297 10600 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
298 : }
299 :
300 26004 : const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
301 25929 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
302 :
303 : const toff_t file_size =
304 25977 : static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
305 25960 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
306 :
307 25895 : return file_size;
308 : }
309 :
310 26659 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
311 : {
312 26659 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
313 : // SetActiveGTH(psGTH);
314 :
315 26659 : if (psGTH->pBase)
316 : {
317 8 : *pbase = psGTH->pBase;
318 8 : *psize = static_cast<toff_t>(psGTH->nDataLength);
319 8 : return 1;
320 : }
321 26651 : return 0;
322 : }
323 :
324 8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
325 : toff_t /* size */)
326 : {
327 8 : }
328 :
329 6197 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
330 : {
331 6197 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
332 6197 : SetActiveGTH(psGTH);
333 6197 : VSI_TIFFFlushBufferedWrite(th);
334 6197 : return psGTH->psShared->fpL;
335 : }
336 :
337 6423 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
338 : {
339 6423 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
340 6423 : SetActiveGTH(psGTH);
341 6423 : psGTH->psShared->bAtEndOfFile = false;
342 6423 : return GTHFlushBuffer(th);
343 : }
344 :
345 376 : int VSI_TIFFHasCachedRanges(thandle_t th)
346 : {
347 376 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
348 376 : return psGTH->nCachedRanges != 0;
349 : }
350 :
351 25213 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
352 : {
353 25213 : thandle_t th = TIFFClientdata(tif);
354 25213 : return _tiffSeekProc(th, off, whence);
355 : }
356 :
357 50089 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
358 : {
359 50089 : thandle_t th = TIFFClientdata(tif);
360 50089 : return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
361 50089 : buffersize)) == buffersize;
362 : }
363 :
364 84 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
365 : const vsi_l_offset *panOffsets,
366 : const size_t *panSizes)
367 : {
368 84 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
369 84 : psGTH->nCachedRanges = nRanges;
370 84 : if (nRanges)
371 : {
372 42 : psGTH->ppCachedData = static_cast<void **>(
373 42 : CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
374 42 : memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
375 :
376 84 : psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
377 42 : psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
378 42 : memcpy(psGTH->panCachedOffsets, panOffsets,
379 42 : nRanges * sizeof(vsi_l_offset));
380 :
381 42 : psGTH->panCachedSizes = static_cast<size_t *>(
382 42 : CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
383 42 : memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
384 : }
385 84 : }
386 :
387 69553 : static bool IsReadOnly(const char *mode)
388 : {
389 69553 : bool bReadOnly = true;
390 283139 : for (int i = 0; mode[i] != '\0'; i++)
391 : {
392 213586 : if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
393 : {
394 81658 : bReadOnly = false;
395 : }
396 : }
397 69553 : return bReadOnly;
398 : }
399 :
400 69564 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
401 : {
402 : // No need to buffer on /vsimem/
403 69564 : const bool bReadOnly = IsReadOnly(pszMode);
404 69499 : bool bAllocBuffer = !bReadOnly;
405 69499 : if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
406 : {
407 60503 : if (bReadOnly &&
408 10724 : CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
409 : {
410 8 : psGTH->nDataLength = 0;
411 8 : psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
412 : &psGTH->nDataLength, FALSE);
413 : }
414 49779 : bAllocBuffer = false;
415 : }
416 :
417 69504 : psGTH->abyWriteBuffer =
418 69504 : bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
419 69504 : psGTH->nWriteBufferSize = 0;
420 69504 : }
421 :
422 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
423 69520 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
424 : {
425 69520 : TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
426 69500 : TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
427 : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
428 : // Read-once and stored in static storage otherwise affects
429 : // autotest/benchmark/test_gtiff.py::test_gtiff_byte
430 670 : static const GIntBig nMemLimit = []() -> GIntBig
431 : {
432 670 : if (const char *pszLimit =
433 670 : CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
434 0 : return CPLAtoGIntBig(pszLimit);
435 : else
436 : {
437 670 : const auto nUsableRAM = CPLGetUsablePhysicalRAM();
438 670 : if (nUsableRAM > 0)
439 : {
440 : // coverity[return_overflow]
441 670 : return nUsableRAM / 10 * 9;
442 : }
443 : else
444 0 : return 0;
445 : }
446 69470 : }();
447 69540 : if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
448 : {
449 : //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
450 : // static_cast<uint64_t>(nMemLimit));
451 69519 : TIFFOpenOptionsSetMaxCumulatedMemAlloc(
452 : opts, static_cast<tmsize_t>(nMemLimit));
453 : }
454 : #endif
455 69318 : }
456 : #endif
457 :
458 69528 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
459 : {
460 69528 : InitializeWriteBuffer(psGTH, pszMode);
461 :
462 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
463 69488 : XTIFFInitialize();
464 69497 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
465 69450 : if (opts == nullptr)
466 : {
467 0 : FreeGTH(psGTH);
468 0 : return nullptr;
469 : }
470 69450 : VSI_TIFFSetOpenOptions(opts);
471 138872 : TIFF *tif = TIFFClientOpenExt(
472 69409 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
473 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
474 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
475 69463 : TIFFOpenOptionsFree(opts);
476 : #else
477 : TIFF *tif = XTIFFClientOpen(
478 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
479 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
480 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
481 : #endif
482 69421 : if (tif == nullptr)
483 15 : FreeGTH(psGTH);
484 :
485 69367 : return tif;
486 : }
487 :
488 : // Open a TIFF file for read/writing.
489 67772 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
490 : {
491 :
492 67772 : if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
493 0 : return nullptr;
494 :
495 : GDALTiffHandle *psGTH =
496 67768 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
497 67763 : psGTH->bFree = true;
498 67763 : psGTH->psParent = nullptr;
499 67767 : psGTH->psShared = static_cast<GDALTiffHandleShared *>(
500 67763 : CPLCalloc(1, sizeof(GDALTiffHandleShared)));
501 67767 : psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
502 67767 : psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
503 67767 : psGTH->psShared->pszName = CPLStrdup(name);
504 67741 : psGTH->psShared->fpL = fpL;
505 67741 : psGTH->psShared->psActiveHandle = psGTH;
506 67741 : psGTH->psShared->nFileLength = 0;
507 67741 : psGTH->psShared->bAtEndOfFile = false;
508 67741 : psGTH->psShared->nUserCounter = 1;
509 :
510 67741 : return VSI_TIFFOpen_common(psGTH, mode);
511 : }
512 :
513 1801 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
514 : {
515 : GDALTiffHandle *psGTHParent =
516 1801 : reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
517 :
518 : GDALTiffHandle *psGTH =
519 1801 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
520 1800 : psGTH->bFree = true;
521 1800 : psGTH->psParent = psGTHParent;
522 1800 : psGTH->psShared = psGTHParent->psShared;
523 1800 : psGTH->psShared->nUserCounter++;
524 :
525 1800 : SetActiveGTH(psGTH);
526 1801 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
527 1801 : psGTH->psShared->bAtEndOfFile = false;
528 :
529 1801 : const char *mode =
530 895 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
531 3602 : ? "rDO"
532 1812 : : psGTH->psShared->bReadOnly ? "r"
533 906 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
534 : : "r+";
535 1801 : return VSI_TIFFOpen_common(psGTH, mode);
536 : }
537 :
538 : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
539 9 : TIFF *VSI_TIFFReOpen(TIFF *tif)
540 : {
541 9 : thandle_t th = TIFFClientdata(tif);
542 9 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
543 :
544 : // Disable freeing of psGTH in _tiffCloseProc(), which could be called
545 : // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
546 9 : psGTH->bFree = false;
547 :
548 9 : const char *mode =
549 0 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
550 18 : ? "rDO"
551 18 : : psGTH->psShared->bReadOnly ? "r"
552 9 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
553 : : "r+";
554 :
555 9 : SetActiveGTH(psGTH);
556 9 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
557 9 : psGTH->psShared->bAtEndOfFile = false;
558 :
559 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
560 9 : TIFF *newHandle = nullptr;
561 9 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
562 9 : if (opts != nullptr)
563 : {
564 9 : VSI_TIFFSetOpenOptions(opts);
565 18 : newHandle = TIFFClientOpenExt(
566 9 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
567 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
568 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
569 9 : TIFFOpenOptionsFree(opts);
570 : }
571 : #else
572 : TIFF *newHandle = XTIFFClientOpen(
573 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
574 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
575 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
576 : #endif
577 9 : if (newHandle != nullptr)
578 9 : XTIFFClose(tif);
579 :
580 9 : psGTH->bFree = true;
581 :
582 9 : return newHandle;
583 : }
|