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 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : // TIFF Library UNIX-specific Routines.
33 :
34 : #include "cpl_port.h"
35 : #include "tifvsi.h"
36 :
37 : #include <assert.h>
38 : #include <string.h>
39 : #include <cerrno>
40 : #if HAVE_FCNTL_H
41 : #include <fcntl.h>
42 : #endif
43 :
44 : #include "cpl_conv.h"
45 : #include "cpl_vsi.h"
46 : #include "cpl_string.h"
47 :
48 : // We avoid including xtiffio.h since it drags in the libgeotiff version
49 : // of the VSI functions.
50 :
51 : #ifdef RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS
52 : #include "gdal_libgeotiff_symbol_rename.h"
53 : #endif
54 :
55 : #include "xtiffio.h"
56 :
57 : #include <limits>
58 :
59 : #if (TIFFLIB_VERSION > 20220520) || defined(INTERNAL_LIBTIFF) // > 4.4.0
60 : #define SUPPORTS_LIBTIFF_OPEN_OPTIONS
61 :
62 : extern int GTiffWarningHandlerExt(TIFF *tif, void *user_data,
63 : const char *module, const char *fmt,
64 : va_list ap);
65 : extern int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
66 : const char *fmt, va_list ap);
67 :
68 : #endif
69 :
70 : constexpr int BUFFER_SIZE = 65536;
71 :
72 : struct GDALTiffHandle;
73 :
74 : struct GDALTiffHandleShared
75 : {
76 : VSILFILE *fpL;
77 : bool bReadOnly;
78 : bool bLazyStrileLoading;
79 : char *pszName;
80 : GDALTiffHandle *psActiveHandle; // only used on the parent
81 : int nUserCounter;
82 : bool bAtEndOfFile;
83 : vsi_l_offset nFileLength;
84 : };
85 :
86 : struct GDALTiffHandle
87 : {
88 : bool bFree;
89 :
90 : GDALTiffHandle *psParent; // nullptr for the parent itself
91 : GDALTiffHandleShared *psShared;
92 :
93 : GByte *abyWriteBuffer;
94 : int nWriteBufferSize;
95 :
96 : // For pseudo-mmap'ed /vsimem/ file
97 : vsi_l_offset nDataLength;
98 : void *pBase;
99 :
100 : // If we pre-cached data (typically from /vsicurl/ )
101 : int nCachedRanges;
102 : void **ppCachedData;
103 : vsi_l_offset *panCachedOffsets;
104 : size_t *panCachedSizes;
105 : };
106 :
107 : static bool GTHFlushBuffer(thandle_t th);
108 :
109 3217500 : static void SetActiveGTH(GDALTiffHandle *psGTH)
110 : {
111 3217500 : auto psShared = psGTH->psShared;
112 3217500 : if (psShared->psActiveHandle != psGTH)
113 : {
114 15991 : if (psShared->psActiveHandle != nullptr)
115 : {
116 14504 : GTHFlushBuffer(static_cast<thandle_t>(psShared->psActiveHandle));
117 : }
118 15991 : psShared->psActiveHandle = psGTH;
119 : }
120 3217500 : }
121 :
122 228 : void *VSI_TIFFGetCachedRange(thandle_t th, vsi_l_offset nOffset, size_t nSize)
123 : {
124 228 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
125 282 : for (int i = 0; i < psGTH->nCachedRanges; i++)
126 : {
127 282 : if (nOffset >= psGTH->panCachedOffsets[i] &&
128 282 : nOffset + nSize <=
129 282 : psGTH->panCachedOffsets[i] + psGTH->panCachedSizes[i])
130 : {
131 228 : return static_cast<GByte *>(psGTH->ppCachedData[i]) +
132 228 : (nOffset - psGTH->panCachedOffsets[i]);
133 : }
134 54 : if (nOffset < psGTH->panCachedOffsets[i])
135 0 : break;
136 : }
137 0 : return nullptr;
138 : }
139 :
140 2511610 : static tsize_t _tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
141 : {
142 2511610 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
143 : // SetActiveGTH(psGTH);
144 :
145 2511610 : if (psGTH->nCachedRanges)
146 : {
147 10 : const vsi_l_offset nCurOffset = VSIFTellL(psGTH->psShared->fpL);
148 : void *data =
149 10 : VSI_TIFFGetCachedRange(th, nCurOffset, static_cast<size_t>(size));
150 10 : if (data)
151 : {
152 10 : memcpy(buf, data, size);
153 10 : VSIFSeekL(psGTH->psShared->fpL, nCurOffset + size, SEEK_SET);
154 10 : return size;
155 : }
156 : }
157 :
158 : #ifdef DEBUG_VERBOSE_EXTRA
159 : CPLDebug("GTiff", "Reading %d bytes at offset " CPL_FRMT_GUIB,
160 : static_cast<int>(size), VSIFTellL(psGTH->psShared->fpL));
161 : #endif
162 2511600 : return VSIFReadL(buf, 1, size, psGTH->psShared->fpL);
163 : }
164 :
165 2568000 : static bool GTHFlushBuffer(thandle_t th)
166 : {
167 2568000 : GDALTiffHandle *psGTH = static_cast<GDALTiffHandle *>(th);
168 2568000 : bool bRet = true;
169 2568000 : if (psGTH->abyWriteBuffer && psGTH->nWriteBufferSize)
170 : {
171 : const tsize_t nRet =
172 22048 : VSIFWriteL(psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize,
173 11024 : psGTH->psShared->fpL);
174 11024 : bRet = nRet == psGTH->nWriteBufferSize;
175 11024 : if (!bRet)
176 : {
177 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
178 : }
179 11024 : psGTH->nWriteBufferSize = 0;
180 : }
181 2568000 : return bRet;
182 : }
183 :
184 401280 : static tsize_t _tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
185 : {
186 401280 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
187 401280 : SetActiveGTH(psGTH);
188 :
189 : // If we have a write buffer and are at end of file, then accumulate
190 : // the bytes until the buffer is full.
191 401017 : if (psGTH->psShared->bAtEndOfFile && psGTH->abyWriteBuffer)
192 : {
193 91637 : const GByte *pabyData = reinterpret_cast<GByte *>(buf);
194 91637 : tsize_t nRemainingBytes = size;
195 : while (true)
196 : {
197 96936 : if (psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE)
198 : {
199 91637 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
200 : pabyData, nRemainingBytes);
201 91637 : psGTH->nWriteBufferSize += static_cast<int>(nRemainingBytes);
202 91637 : if (psGTH->psShared->bAtEndOfFile)
203 : {
204 91637 : psGTH->psShared->nFileLength += size;
205 : }
206 91637 : return size;
207 : }
208 :
209 5299 : int nAppendable = BUFFER_SIZE - psGTH->nWriteBufferSize;
210 5299 : memcpy(psGTH->abyWriteBuffer + psGTH->nWriteBufferSize, pabyData,
211 : nAppendable);
212 10598 : const tsize_t nRet = VSIFWriteL(psGTH->abyWriteBuffer, 1,
213 5299 : BUFFER_SIZE, psGTH->psShared->fpL);
214 5299 : psGTH->nWriteBufferSize = 0;
215 5299 : if (nRet != BUFFER_SIZE)
216 : {
217 0 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
218 0 : return 0;
219 : }
220 :
221 5299 : pabyData += nAppendable;
222 5299 : nRemainingBytes -= nAppendable;
223 5299 : }
224 : }
225 :
226 309380 : const tsize_t nRet = VSIFWriteL(buf, 1, size, psGTH->psShared->fpL);
227 309882 : if (nRet < size)
228 : {
229 73 : TIFFErrorExt(th, "_tiffWriteProc", "%s", VSIStrerror(errno));
230 : }
231 :
232 309798 : if (psGTH->psShared->bAtEndOfFile)
233 : {
234 114979 : psGTH->psShared->nFileLength += nRet;
235 : }
236 309798 : return nRet;
237 : }
238 :
239 2721450 : static toff_t _tiffSeekProc(thandle_t th, toff_t off, int whence)
240 : {
241 2721450 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
242 2721450 : SetActiveGTH(psGTH);
243 :
244 : // Optimization: if we are already at end, then no need to
245 : // issue a VSIFSeekL().
246 2721000 : if (whence == SEEK_END)
247 : {
248 229869 : if (psGTH->psShared->bAtEndOfFile)
249 : {
250 179561 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
251 : }
252 :
253 50308 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) != 0)
254 : {
255 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
256 0 : return static_cast<toff_t>(-1);
257 : }
258 50309 : psGTH->psShared->bAtEndOfFile = true;
259 50309 : psGTH->psShared->nFileLength = VSIFTellL(psGTH->psShared->fpL);
260 50308 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
261 : }
262 :
263 2491130 : GTHFlushBuffer(th);
264 2491380 : psGTH->psShared->bAtEndOfFile = false;
265 2491380 : psGTH->psShared->nFileLength = 0;
266 :
267 2491380 : if (VSIFSeekL(psGTH->psShared->fpL, off, whence) == 0)
268 : {
269 2491080 : return static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
270 : }
271 : else
272 : {
273 0 : TIFFErrorExt(th, "_tiffSeekProc", "%s", VSIStrerror(errno));
274 0 : return static_cast<toff_t>(-1);
275 : }
276 : }
277 :
278 56523 : static void FreeGTH(GDALTiffHandle *psGTH)
279 : {
280 56523 : psGTH->psShared->nUserCounter--;
281 56523 : if (psGTH->psParent == nullptr)
282 : {
283 55039 : assert(psGTH->psShared->nUserCounter == 0);
284 55039 : CPLFree(psGTH->psShared->pszName);
285 55038 : CPLFree(psGTH->psShared);
286 : }
287 : else
288 : {
289 1484 : if (psGTH->psShared->psActiveHandle == psGTH)
290 1487 : psGTH->psShared->psActiveHandle = nullptr;
291 : }
292 56522 : CPLFree(psGTH->abyWriteBuffer);
293 56523 : CPLFree(psGTH->ppCachedData);
294 56524 : CPLFree(psGTH->panCachedOffsets);
295 56513 : CPLFree(psGTH->panCachedSizes);
296 56522 : CPLFree(psGTH);
297 56525 : }
298 :
299 56521 : static int _tiffCloseProc(thandle_t th)
300 : {
301 56521 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
302 56521 : SetActiveGTH(psGTH);
303 56520 : GTHFlushBuffer(th);
304 56518 : if (psGTH->bFree)
305 56509 : FreeGTH(psGTH);
306 56519 : return 0;
307 : }
308 :
309 26013 : static toff_t _tiffSizeProc(thandle_t th)
310 : {
311 26013 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
312 26013 : SetActiveGTH(psGTH);
313 :
314 26001 : if (psGTH->psShared->bAtEndOfFile)
315 : {
316 6823 : return static_cast<toff_t>(psGTH->psShared->nFileLength);
317 : }
318 :
319 19178 : const vsi_l_offset old_off = VSIFTellL(psGTH->psShared->fpL);
320 19177 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_END));
321 :
322 : const toff_t file_size =
323 19177 : static_cast<toff_t>(VSIFTellL(psGTH->psShared->fpL));
324 19181 : CPL_IGNORE_RET_VAL(VSIFSeekL(psGTH->psShared->fpL, old_off, SEEK_SET));
325 :
326 19178 : return file_size;
327 : }
328 :
329 19002 : static int _tiffMapProc(thandle_t th, tdata_t *pbase, toff_t *psize)
330 : {
331 19002 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
332 : // SetActiveGTH(psGTH);
333 :
334 19002 : if (psGTH->pBase)
335 : {
336 8 : *pbase = psGTH->pBase;
337 8 : *psize = static_cast<toff_t>(psGTH->nDataLength);
338 8 : return 1;
339 : }
340 18994 : return 0;
341 : }
342 :
343 8 : static void _tiffUnmapProc(thandle_t /* th */, tdata_t /* base */,
344 : toff_t /* size */)
345 : {
346 8 : }
347 :
348 5399 : VSILFILE *VSI_TIFFGetVSILFile(thandle_t th)
349 : {
350 5399 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
351 5399 : SetActiveGTH(psGTH);
352 5399 : VSI_TIFFFlushBufferedWrite(th);
353 5399 : return psGTH->psShared->fpL;
354 : }
355 :
356 5624 : int VSI_TIFFFlushBufferedWrite(thandle_t th)
357 : {
358 5624 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
359 5624 : SetActiveGTH(psGTH);
360 5624 : psGTH->psShared->bAtEndOfFile = false;
361 5624 : return GTHFlushBuffer(th);
362 : }
363 :
364 242 : int VSI_TIFFHasCachedRanges(thandle_t th)
365 : {
366 242 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
367 242 : return psGTH->nCachedRanges != 0;
368 : }
369 :
370 24675 : toff_t VSI_TIFFSeek(TIFF *tif, toff_t off, int whence)
371 : {
372 24675 : thandle_t th = TIFFClientdata(tif);
373 24675 : return _tiffSeekProc(th, off, whence);
374 : }
375 :
376 48999 : int VSI_TIFFWrite(TIFF *tif, const void *buffer, size_t buffersize)
377 : {
378 48999 : thandle_t th = TIFFClientdata(tif);
379 48999 : return static_cast<size_t>(_tiffWriteProc(th, const_cast<tdata_t>(buffer),
380 48999 : buffersize)) == buffersize;
381 : }
382 :
383 80 : void VSI_TIFFSetCachedRanges(thandle_t th, int nRanges, void **ppData,
384 : const vsi_l_offset *panOffsets,
385 : const size_t *panSizes)
386 : {
387 80 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
388 80 : psGTH->nCachedRanges = nRanges;
389 80 : if (nRanges)
390 : {
391 40 : psGTH->ppCachedData = static_cast<void **>(
392 40 : CPLRealloc(psGTH->ppCachedData, nRanges * sizeof(void *)));
393 40 : memcpy(psGTH->ppCachedData, ppData, nRanges * sizeof(void *));
394 :
395 80 : psGTH->panCachedOffsets = static_cast<vsi_l_offset *>(CPLRealloc(
396 40 : psGTH->panCachedOffsets, nRanges * sizeof(vsi_l_offset)));
397 40 : memcpy(psGTH->panCachedOffsets, panOffsets,
398 40 : nRanges * sizeof(vsi_l_offset));
399 :
400 40 : psGTH->panCachedSizes = static_cast<size_t *>(
401 40 : CPLRealloc(psGTH->panCachedSizes, nRanges * sizeof(size_t)));
402 40 : memcpy(psGTH->panCachedSizes, panSizes, nRanges * sizeof(size_t));
403 : }
404 80 : }
405 :
406 56530 : static bool IsReadOnly(const char *mode)
407 : {
408 56530 : bool bReadOnly = true;
409 228337 : for (int i = 0; mode[i] != '\0'; i++)
410 : {
411 171807 : if (mode[i] == 'w' || mode[i] == '+' || mode[i] == 'a')
412 : {
413 72265 : bReadOnly = false;
414 : }
415 : }
416 56530 : return bReadOnly;
417 : }
418 :
419 56528 : static void InitializeWriteBuffer(GDALTiffHandle *psGTH, const char *pszMode)
420 : {
421 : // No need to buffer on /vsimem/
422 56528 : const bool bReadOnly = IsReadOnly(pszMode);
423 56524 : bool bAllocBuffer = !bReadOnly;
424 56524 : if (STARTS_WITH(psGTH->psShared->pszName, "/vsimem/"))
425 : {
426 47141 : if (bReadOnly &&
427 6545 : CPLTestBool(CPLGetConfigOption("GTIFF_USE_MMAP", "NO")))
428 : {
429 8 : psGTH->nDataLength = 0;
430 8 : psGTH->pBase = VSIGetMemFileBuffer(psGTH->psShared->pszName,
431 : &psGTH->nDataLength, FALSE);
432 : }
433 40596 : bAllocBuffer = false;
434 : }
435 :
436 56521 : psGTH->abyWriteBuffer =
437 56521 : bAllocBuffer ? static_cast<GByte *>(VSIMalloc(BUFFER_SIZE)) : nullptr;
438 56521 : psGTH->nWriteBufferSize = 0;
439 56521 : }
440 :
441 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
442 56532 : static void VSI_TIFFSetOpenOptions(TIFFOpenOptions *opts)
443 : {
444 56532 : TIFFOpenOptionsSetErrorHandlerExtR(opts, GTiffErrorHandlerExt, nullptr);
445 56524 : TIFFOpenOptionsSetWarningHandlerExtR(opts, GTiffWarningHandlerExt, nullptr);
446 : #if defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20230908
447 : // Read-once and stored in static storage otherwise affects
448 : // autotest/benchmark/test_gtiff.py::test_gtiff_byte
449 555 : static const GIntBig nMemLimit = []()
450 : {
451 555 : if (const char *pszLimit =
452 555 : CPLGetConfigOption("GTIFF_MAX_CUMULATED_MEM_USAGE", nullptr))
453 0 : return CPLAtoGIntBig(pszLimit);
454 : else
455 555 : return CPLGetUsablePhysicalRAM() * 9 / 10;
456 56522 : }();
457 56525 : if (nMemLimit > 0 && nMemLimit < std::numeric_limits<tmsize_t>::max())
458 : {
459 : //CPLDebug("GTiff", "TIFFOpenOptionsSetMaxCumulatedMemAlloc(%" PRIu64 ")",
460 : // static_cast<uint64_t>(nMemLimit));
461 56520 : TIFFOpenOptionsSetMaxCumulatedMemAlloc(
462 : opts, static_cast<tmsize_t>(nMemLimit));
463 : }
464 : #endif
465 56521 : }
466 : #endif
467 :
468 56525 : static TIFF *VSI_TIFFOpen_common(GDALTiffHandle *psGTH, const char *pszMode)
469 : {
470 56525 : InitializeWriteBuffer(psGTH, pszMode);
471 :
472 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
473 56520 : XTIFFInitialize();
474 56523 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
475 56524 : if (opts == nullptr)
476 : {
477 0 : FreeGTH(psGTH);
478 0 : return nullptr;
479 : }
480 56524 : VSI_TIFFSetOpenOptions(opts);
481 113029 : TIFF *tif = TIFFClientOpenExt(
482 56513 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
483 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
484 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
485 56516 : TIFFOpenOptionsFree(opts);
486 : #else
487 : TIFF *tif = XTIFFClientOpen(
488 : psGTH->psShared->pszName, pszMode, reinterpret_cast<thandle_t>(psGTH),
489 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
490 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
491 : #endif
492 56500 : if (tif == nullptr)
493 14 : FreeGTH(psGTH);
494 :
495 56495 : return tif;
496 : }
497 :
498 : // Open a TIFF file for read/writing.
499 55043 : TIFF *VSI_TIFFOpen(const char *name, const char *mode, VSILFILE *fpL)
500 : {
501 :
502 55043 : if (VSIFSeekL(fpL, 0, SEEK_SET) < 0)
503 0 : return nullptr;
504 :
505 : GDALTiffHandle *psGTH =
506 55041 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
507 55042 : psGTH->bFree = true;
508 55042 : psGTH->psParent = nullptr;
509 55041 : psGTH->psShared = static_cast<GDALTiffHandleShared *>(
510 55042 : CPLCalloc(1, sizeof(GDALTiffHandleShared)));
511 55041 : psGTH->psShared->bReadOnly = (strchr(mode, '+') == nullptr);
512 55041 : psGTH->psShared->bLazyStrileLoading = (strchr(mode, 'D') != nullptr);
513 55041 : psGTH->psShared->pszName = CPLStrdup(name);
514 55040 : psGTH->psShared->fpL = fpL;
515 55040 : psGTH->psShared->psActiveHandle = psGTH;
516 55040 : psGTH->psShared->nFileLength = 0;
517 55040 : psGTH->psShared->bAtEndOfFile = false;
518 55040 : psGTH->psShared->nUserCounter = 1;
519 :
520 55040 : return VSI_TIFFOpen_common(psGTH, mode);
521 : }
522 :
523 1487 : TIFF *VSI_TIFFOpenChild(TIFF *parent)
524 : {
525 : GDALTiffHandle *psGTHParent =
526 1487 : reinterpret_cast<GDALTiffHandle *>(TIFFClientdata(parent));
527 :
528 : GDALTiffHandle *psGTH =
529 1487 : static_cast<GDALTiffHandle *>(CPLCalloc(1, sizeof(GDALTiffHandle)));
530 1487 : psGTH->bFree = true;
531 1487 : psGTH->psParent = psGTHParent;
532 1487 : psGTH->psShared = psGTHParent->psShared;
533 1487 : psGTH->psShared->nUserCounter++;
534 :
535 1487 : SetActiveGTH(psGTH);
536 1487 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
537 1487 : psGTH->psShared->bAtEndOfFile = false;
538 :
539 1487 : const char *mode =
540 691 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
541 2974 : ? "rDO"
542 1592 : : psGTH->psShared->bReadOnly ? "r"
543 796 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
544 : : "r+";
545 1487 : return VSI_TIFFOpen_common(psGTH, mode);
546 : }
547 :
548 : // Re-open a TIFF handle (seeking to the appropriate directory is then needed)
549 9 : TIFF *VSI_TIFFReOpen(TIFF *tif)
550 : {
551 9 : thandle_t th = TIFFClientdata(tif);
552 9 : GDALTiffHandle *psGTH = reinterpret_cast<GDALTiffHandle *>(th);
553 :
554 : // Disable freeing of psGTH in _tiffCloseProc(), which could be called
555 : // if XTIFFClientOpen() fails, or obviously by XTIFFClose()
556 9 : psGTH->bFree = false;
557 :
558 9 : const char *mode =
559 0 : psGTH->psShared->bReadOnly && psGTH->psShared->bLazyStrileLoading
560 18 : ? "rDO"
561 18 : : psGTH->psShared->bReadOnly ? "r"
562 9 : : psGTH->psShared->bLazyStrileLoading ? "r+D"
563 : : "r+";
564 :
565 9 : SetActiveGTH(psGTH);
566 9 : VSIFSeekL(psGTH->psShared->fpL, 0, SEEK_SET);
567 9 : psGTH->psShared->bAtEndOfFile = false;
568 :
569 : #ifdef SUPPORTS_LIBTIFF_OPEN_OPTIONS
570 9 : TIFF *newHandle = nullptr;
571 9 : TIFFOpenOptions *opts = TIFFOpenOptionsAlloc();
572 9 : if (opts != nullptr)
573 : {
574 9 : VSI_TIFFSetOpenOptions(opts);
575 18 : newHandle = TIFFClientOpenExt(
576 9 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
577 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
578 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc, opts);
579 9 : TIFFOpenOptionsFree(opts);
580 : }
581 : #else
582 : TIFF *newHandle = XTIFFClientOpen(
583 : psGTH->psShared->pszName, mode, reinterpret_cast<thandle_t>(psGTH),
584 : _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
585 : _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
586 : #endif
587 9 : if (newHandle != nullptr)
588 9 : XTIFFClose(tif);
589 :
590 9 : psGTH->bFree = true;
591 :
592 9 : return newHandle;
593 : }
|