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 3360550 : static void SetActiveGTH(GDALTiffHandle *psGTH)
94 : {
95 3360550 : auto psShared = psGTH->psShared;
96 3360550 : if (psShared->psActiveHandle != psGTH)
97 : {
98 16602 : if (psShared->psActiveHandle != nullptr)
99 : {
100 14962 : GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
101 : }
102 16602 : psShared->psActiveHandle = psGTH;
103 : }
104 3360550 : }
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 2619010 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
125 : {
126 2619010 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
127 : // SetActiveGTH(psGTH);
128 :
129 2619010 : 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 2619000 : return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
147 : }
148 :
149 2660080 : static bool GTHFlushBuffer(thandle_t th)
150 : {
151 2660080 : GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
152 2660080 : bool bRet = true;
153 2660080 : if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
154 : {
155 : const tsize_t nRet =
156 22164 : VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
157 11082 : psGTH->psShared->fpL);
158 11082 : bRet = nRet == psGTH->nWriteBufferSize;
159 11082 : if (!bRet)
160 : {
161 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
162 : }
163 11082 : psGTH->nWriteBufferSize = 0;
164 : }
165 2660080 : return bRet;
166 : }
167 :
168 429877 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
169 : {
170 429877 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
171 429877 : 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 429869 : if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
176 : {
177 91776 : const GByte *pabyData = reinterpret_cast<GByte *>(buf);
178 91776 : tsize_t nRemainingBytes = size;
179 : while (true)
180 : {
181 96535 : if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
182 : {
183 91776 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
184 : pabyData, nRemainingBytes);
185 91776 : psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
186 91776 : if (psGTH->psShared->bAtEndOfFile)
187 : {
188 91776 : psGTH->psShared->nFileLength += size;
189 : }
190 91776 : 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 338093 : const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
211 338102 : if (nRet < size)
212 : {
213 76 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
214 : }
215 :
216 338100 : if (psGTH->psShared->bAtEndOfFile)
217 : {
218 129952 : psGTH->psShared->nFileLength += nRet;
219 : }
220 338100 : return nRet;
221 : }
222 :
223 2824830 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
224 : {
225 2824830 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
226 2824830 : SetActiveGTH(psGTH);
227 :
228 : // Optimization: if we are already at end, then no need to
229 : // issue a VSIFSeekL().
230 2824700 : if (whence == SEEK_END)
231 : {
232 247981 : if (psGTH->psShared->bAtEndOfFile)
233 : {
234 193810 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
235 : }
236 :
237 54171 : 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 54170 : psGTH->psShared->bAtEndOfFile = true;
243 54170 : psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
244 54170 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
245 : }
246 :
247 2576710 : GTHFlushBuffer(th);
248 2576670 : psGTH->psShared->bAtEndOfFile = false;
249 2576670 : psGTH->psShared->nFileLength = 0;
250 :
251 2576670 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
252 : {
253 2576830 : 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 62539 : static void FreeGTH(GDALTiffHandle *psGTH)
263 : {
264 62539 : psGTH->psShared->nUserCounter--;
265 62539 : if (psGTH->psParent == nullptr)
266 : {
267 60898 : assert(psGTH->psShared->nUserCounter == 0);
268 60898 : CPLFree(psGTH->psShared->pszName);
269 60899 : CPLFree(psGTH->psShared);
270 : }
271 : else
272 : {
273 1641 : if (psGTH->psShared->psActiveHandle == psGTH)
274 1640 : psGTH->psShared->psActiveHandle = nullptr;
275 : }
276 62542 : CPLFree(psGTH->abyWriteBuffer);
277 62540 : CPLFree(psGTH->ppCachedData);
278 62541 : CPLFree(psGTH->panCachedOffsets);
279 62541 : CPLFree(psGTH->panCachedSizes);
280 62539 : CPLFree(psGTH);
281 62542 : }
282 :
283 62536 : static int _tiffCloseProc(thandle_t th)
284 : {
285 62536 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
286 62536 : SetActiveGTH(psGTH);
287 62531 : GTHFlushBuffer(th);
288 62529 : if (psGTH->bFree)
289 62524 : FreeGTH(psGTH);
290 62535 : return 0;
291 : }
292 :
293 30283 : static toff_t _tiffSizeProc(thandle_t th)
294 : {
295 30283 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
296 30283 : SetActiveGTH(psGTH);
297 :
298 30291 : if (psGTH->psShared->bAtEndOfFile)
299 : {
300 7967 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
301 : }
302 :
303 22324 : const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
304 22316 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
305 :
306 : const toff_t file_size =
307 22282 : static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
308 22322 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
309 :
310 22314 : return file_size;
311 : }
312 :
313 23053 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
314 : {
315 23053 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
316 : // SetActiveGTH(psGTH);
317 :
318 23053 : if (psGTH->pBase)
319 : {
320 8 : *pbase = psGTH->pBase;
321 8 : *psize = static_cast<toff_t>(psGTH->nDataLength);
322 8 : return 1;
323 : }
324 23045 : return 0;
325 : }
326 :
327 8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
328 : toff_t /* size */)
329 : {
330 8 : }
331 :
332 5718 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
333 : {
334 5718 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
335 5718 : SetActiveGTH(psGTH);
336 5718 : VSI_TIFFFlushBufferedWrite(th);
337 5718 : return psGTH->psShared->fpL;
338 : }
339 :
340 5943 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
341 : {
342 5943 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
343 5943 : SetActiveGTH(psGTH);
344 5943 : psGTH->psShared->bAtEndOfFile = false;
345 5943 : 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 24696 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
355 : {
356 24696 : thandle_t th = TIFFClientdata(tif);
357 24696 : return _tiffSeekProc(th, off, whence);
358 : }
359 :
360 49045 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
361 : {
362 49045 : thandle_t th = TIFFClientdata(tif);
363 49045 : return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
364 49045 : 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 62535 : static bool IsReadOnly(const char *mode)
391 : {
392 62535 : bool bReadOnly = true;
393 254411 : for (int i = 0; mode[i] != '\0'; i++)
394 : {
395 191876 : if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
396 : {
397 75170 : bReadOnly = false;
398 : }
399 : }
400 62535 : return bReadOnly;
401 : }
402 :
403 62532 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
404 : {
405 : // No need to buffer on /vsimem/
406 62532 : const bool bReadOnly = IsReadOnly(pszMode);
407 62517 : bool bAllocBuffer = !bReadOnly;
408 62517 : if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
409 : {
410 51974 : if (bReadOnly &&
411 8049 : 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 43925 : bAllocBuffer = false;
418 : }
419 :
420 62493 : psGTH->abyWriteBuffer =
421 62493 : bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
422 62493 : psGTH->nWriteBufferSize = 0;
423 62493 : }
424 :
425 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
426 62532 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
427 : {
428 62532 : TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
429 62498 : 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 620 : static const GIntBig nMemLimit = []() -> GIntBig
434 : {
435 620 : if (const char *pszLimit =
436 620 : CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
437 0 : return CPLAtoGIntBig(pszLimit);
438 : else
439 : {
440 620 : const auto nUsableRAM = CPLGetUsablePhysicalRAM();
441 620 : if (nUsableRAM > 0)
442 : {
443 : // coverity[return_overflow]
444 620 : return nUsableRAM / 10 * 9;
445 : }
446 : else
447 0 : return 0;
448 : }
449 62481 : }();
450 62489 : if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
451 : {
452 : //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
453 : // static_cast<uint64_t>(nMemLimit));
454 62463 : TIFFOpenOptionsSetMaxCumulatedMemAlloc(
455 : opts, static_cast<tmsize_t>(nMemLimit));
456 : }
457 : #endif
458 62461 : }
459 : #endif
460 :
461 62501 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
462 : {
463 62501 : InitializeWriteBuffer(psGTH, pszMode);
464 :
465 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
466 62480 : XTIFFInitialize();
467 62487 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
468 62528 : if (opts == nullptr)
469 : {
470 0 : FreeGTH(psGTH);
471 0 : return nullptr;
472 : }
473 62528 : VSI_TIFFSetOpenOptions(opts);
474 124968 : TIFF *tif = TIFFClientOpenExt(
475 62449 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
476 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
477 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
478 62519 : 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 62471 : if (tif == nullptr)
486 15 : FreeGTH(psGTH);
487 :
488 62425 : return tif;
489 : }
490 :
491 : // Open a TIFF file for read/writing.
492 60904 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
493 : {
494 :
495 60904 : if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
496 0 : return nullptr;
497 :
498 : GDALTiffHandle *psGTH =
499 60897 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
500 60900 : psGTH->bFree = true;
501 60900 : psGTH->psParent = nullptr;
502 60902 : psGTH->psShared = static_cast<GDALTiffHandleShared *>(
503 60900 : CPLCalloc(1, sizeof(GDALTiffHandleShared)));
504 60902 : psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
505 60902 : psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
506 60902 : psGTH->psShared->pszName = CPLStrdup(name);
507 60901 : psGTH->psShared->fpL = fpL;
508 60901 : psGTH->psShared->psActiveHandle = psGTH;
509 60901 : psGTH->psShared->nFileLength = 0;
510 60901 : psGTH->psShared->bAtEndOfFile = false;
511 60901 : psGTH->psShared->nUserCounter = 1;
512 :
513 60901 : return VSI_TIFFOpen_common(psGTH, mode);
514 : }
515 :
516 1640 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
517 : {
518 : GDALTiffHandle *psGTHParent =
519 1640 : reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
520 :
521 : GDALTiffHandle *psGTH =
522 1640 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
523 1640 : psGTH->bFree = true;
524 1640 : psGTH->psParent = psGTHParent;
525 1640 : psGTH->psShared = psGTHParent->psShared;
526 1640 : psGTH->psShared->nUserCounter++;
527 :
528 1640 : SetActiveGTH(psGTH);
529 1640 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
530 1640 : psGTH->psShared->bAtEndOfFile = false;
531 :
532 1640 : const char *mode =
533 812 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
534 3280 : ? "rDO"
535 1656 : : psGTH->psShared->bReadOnly ? "r"
536 828 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
537 : : "r+";
538 1640 : 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 : }
|