Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_vsi_virtual.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  VSI Virtual File System
4
 * Purpose:  Declarations for classes related to the virtual filesystem.
5
 *           These would only be normally required by applications implementing
6
 *           their own virtual file system classes which should be rare.
7
 *           The class interface may be fragile through versions.
8
 * Author:   Frank Warmerdam, warmerdam@pobox.com
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
12
 * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
13
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16
17
#ifndef CPL_VSI_VIRTUAL_H_INCLUDED
18
#define CPL_VSI_VIRTUAL_H_INCLUDED
19
20
#include "cpl_progress.h"
21
#include "cpl_vsi.h"
22
#include "cpl_vsi_error.h"
23
#include "cpl_string.h"
24
25
#include <cstdint>
26
#include <map>
27
#include <memory>
28
#include <mutex>
29
#include <vector>
30
#include <string>
31
32
// To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows
33
#ifdef GetDiskFreeSpace
34
#undef GetDiskFreeSpace
35
#endif
36
37
// To avoid aliasing to CopyFile to CopyFileA on Windows
38
#ifdef CopyFile
39
#undef CopyFile
40
#endif
41
42
/************************************************************************/
43
/*                           VSIVirtualHandle                           */
44
/************************************************************************/
45
46
/** Virtual file handle */
47
struct CPL_DLL VSIVirtualHandle
48
{
49
  public:
50
    virtual int Seek(vsi_l_offset nOffset, int nWhence) = 0;
51
52
#ifdef GDAL_COMPILATION
53
    /*! @cond Doxygen_Suppress */
54
    inline int Seek(int &&nOffset, int nWhence)
55
1.22k
    {
56
1.22k
        return Seek(static_cast<vsi_l_offset>(nOffset), nWhence);
57
1.22k
    }
58
59
    inline int Seek(unsigned &&nOffset, int nWhence)
60
0
    {
61
0
        return Seek(static_cast<vsi_l_offset>(nOffset), nWhence);
62
0
    }
63
64
    template <typename T>
65
    inline std::enable_if_t<std::is_same_v<T, uint64_t> &&
66
                                !std::is_same_v<uint64_t, vsi_l_offset>,
67
                            int>
68
    Seek(T nOffset, int nWhence)
69
    {
70
        return Seek(static_cast<vsi_l_offset>(nOffset), nWhence);
71
    }
72
73
    template <typename T>
74
    inline std::enable_if_t<std::is_same_v<T, size_t> &&
75
                                !std::is_same_v<T, uint64_t> &&
76
                                !std::is_same_v<size_t, unsigned> &&
77
                                !std::is_same_v<size_t, vsi_l_offset>,
78
                            int>
79
    Seek(T nOffset, int nWhence) = delete;
80
81
    int Seek(int &nOffset, int nWhence) = delete;
82
    int Seek(const int &nOffset, int nWhence) = delete;
83
    int Seek(unsigned &nOffset, int nWhence) = delete;
84
    int Seek(const unsigned &nOffset, int nWhence) = delete;
85
/*! @endcond */
86
#endif
87
88
    virtual vsi_l_offset Tell() = 0;
89
    size_t Read(void *pBuffer, size_t nSize, size_t nCount);
90
91
    virtual size_t Read(void *pBuffer, size_t nBytes) = 0;
92
93
    /** Read a primitive type from LSB-ordered byte sequence.
94
     *
95
     * Failure to read the value can be detected by testing *pbError,
96
     * or Eof() || Error()
97
     *
98
     * @param[out] pbError Pointer to a boolean that will be set to true if
99
     * the value cannot be read, or nullptr.
100
     * Note that this boolean must be initialized to false by the caller,
101
     * and that this method will not set it to false.
102
     */
103
    template <class T> inline T ReadLSB(bool *pbError = nullptr)
104
0
    {
105
0
        T val;
106
0
        if (Read(&val, sizeof(val)) != sizeof(val))
107
0
        {
108
0
            if (pbError)
109
0
                *pbError = true;
110
0
            return 0;
111
0
        }
112
0
        return CPL_AS_LSB(val);
113
0
    }
Unexecuted instantiation: unsigned int VSIVirtualHandle::ReadLSB<unsigned int>(bool*)
Unexecuted instantiation: unsigned long VSIVirtualHandle::ReadLSB<unsigned long>(bool*)
114
115
    /** Read a primitive type from LSB-ordered byte sequence */
116
    template <class T> inline bool ReadLSB(T &val)
117
0
    {
118
0
        if (Read(&val, sizeof(val)) != sizeof(val))
119
0
        {
120
0
            return false;
121
0
        }
122
0
        val = CPL_AS_LSB(val);
123
0
        return true;
124
0
    }
125
126
    bool ReadLSB(bool &) = delete;
127
128
    virtual int ReadMultiRange(int nRanges, void **ppData,
129
                               const vsi_l_offset *panOffsets,
130
                               const size_t *panSizes);
131
132
    /** This method is called when code plans to access soon one or several
133
     * ranges in a file. Some file systems may be able to use this hint to
134
     * for example asynchronously start such requests.
135
     *
136
     * Offsets may be given in a non-increasing order, and may potentially
137
     * overlap.
138
     *
139
     * @param nRanges Size of the panOffsets and panSizes arrays.
140
     * @param panOffsets Array containing the start offset of each range.
141
     * @param panSizes Array containing the size (in bytes) of each range.
142
     * @since GDAL 3.7
143
     */
144
    virtual void AdviseRead(CPL_UNUSED int nRanges,
145
                            CPL_UNUSED const vsi_l_offset *panOffsets,
146
                            CPL_UNUSED const size_t *panSizes)
147
0
    {
148
0
    }
149
150
    /** Return the total maximum number of bytes that AdviseRead() can handle
151
     * at once.
152
     *
153
     * Some AdviseRead() implementations may give up if the sum of the values
154
     * in the panSizes[] array provided to AdviseRead() exceeds a limit.
155
     *
156
     * Callers might use that threshold to optimize the efficiency of
157
     * AdviseRead().
158
     *
159
     * A returned value of 0 indicates a unknown limit.
160
     * @since GDAL 3.9
161
     */
162
    virtual size_t GetAdviseReadTotalBytesLimit() const
163
0
    {
164
0
        return 0;
165
0
    }
166
167
    virtual size_t Write(const void *pBuffer, size_t nBytes) = 0;
168
    size_t Write(const void *pBuffer, size_t nSize, size_t nCount);
169
170
    /** Write a primitive type as LSB-ordered byte sequence */
171
    template <class T> inline bool WriteLSB(T val)
172
    {
173
        val = CPL_AS_LSB(val);
174
        return Write(&val, sizeof(val)) == sizeof(val);
175
    }
176
177
    int Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
178
        CPL_PRINT_FUNC_FORMAT(2, 3);
179
180
    virtual void ClearErr() = 0;
181
182
    virtual int Eof() = 0;
183
184
    virtual int Error() = 0;
185
186
    virtual int Flush()
187
0
    {
188
0
        return 0;
189
0
    }
190
191
    virtual int Close() = 0;
192
    // Base implementation that only supports file extension.
193
    virtual int Truncate(vsi_l_offset nNewSize);
194
195
    virtual void *GetNativeFileDescriptor()
196
0
    {
197
0
        return nullptr;
198
0
    }
199
200
    virtual VSIRangeStatus GetRangeStatus(CPL_UNUSED vsi_l_offset nOffset,
201
                                          CPL_UNUSED vsi_l_offset nLength)
202
0
    {
203
0
        return VSI_RANGE_STATUS_UNKNOWN;
204
0
    }
205
206
    virtual bool HasPRead() const;
207
    virtual size_t PRead(void *pBuffer, size_t nSize,
208
                         vsi_l_offset nOffset) const;
209
210
    /** Ask current operations to be interrupted.
211
     * Implementations must be thread-safe, as this will typically be called
212
     * from another thread than the active one for this file.
213
     */
214
    virtual void Interrupt()
215
0
    {
216
0
    }
217
218
    /** For a file created with CreateOnlyVisibleAtCloseTime(), ask for the
219
     * file to not be created at all (if possible)
220
     */
221
    virtual void CancelCreation()
222
0
    {
223
0
    }
224
225
    // NOTE: when adding new methods, besides the "actual" implementations,
226
    // also consider the VSICachedFile and VSIVirtualHandleOnlyVisibleAtCloseTime one.
227
228
    virtual ~VSIVirtualHandle()
229
10.7k
    {
230
10.7k
    }
231
};
232
233
/************************************************************************/
234
/*                        VSIVirtualHandleCloser                        */
235
/************************************************************************/
236
237
/** Helper close to use with a std:unique_ptr<VSIVirtualHandle>,
238
 *  such as VSIVirtualHandleUniquePtr. */
239
struct VSIVirtualHandleCloser
240
241
{
242
    /** Operator () that closes and deletes the file handle. */
243
    void operator()(VSIVirtualHandle *poHandle)
244
2.52k
    {
245
2.52k
        if (poHandle)
246
2.52k
        {
247
2.52k
            poHandle->Close();
248
2.52k
            delete poHandle;
249
2.52k
        }
250
2.52k
    }
251
};
252
253
/** Unique pointer of VSIVirtualHandle that calls the Close() method */
254
typedef std::unique_ptr<VSIVirtualHandle, VSIVirtualHandleCloser>
255
    VSIVirtualHandleUniquePtr;
256
257
/************************************************************************/
258
/*                          VSIProxyFileHandle                          */
259
/************************************************************************/
260
261
#ifndef DOXYGEN_SKIP
262
class VSIProxyFileHandle /* non final */ : public VSIVirtualHandle
263
{
264
  protected:
265
    VSIVirtualHandleUniquePtr m_nativeHandle{};
266
267
  public:
268
    explicit VSIProxyFileHandle(VSIVirtualHandleUniquePtr &&nativeHandle)
269
0
        : m_nativeHandle(std::move(nativeHandle))
270
0
    {
271
0
    }
272
273
    int Seek(vsi_l_offset nOffset, int nWhence) override
274
0
    {
275
0
        return m_nativeHandle->Seek(nOffset, nWhence);
276
0
    }
277
278
    vsi_l_offset Tell() override
279
0
    {
280
0
        return m_nativeHandle->Tell();
281
0
    }
282
283
    size_t Read(void *pBuffer, size_t nBytes) override
284
0
    {
285
0
        return m_nativeHandle->Read(pBuffer, nBytes);
286
0
    }
287
288
    int ReadMultiRange(int nRanges, void **ppData,
289
                       const vsi_l_offset *panOffsets,
290
                       const size_t *panSizes) override
291
0
    {
292
0
        return m_nativeHandle->ReadMultiRange(nRanges, ppData, panOffsets,
293
0
                                              panSizes);
294
0
    }
295
296
    void AdviseRead(int nRanges, const vsi_l_offset *panOffsets,
297
                    const size_t *panSizes) override
298
0
    {
299
0
        return m_nativeHandle->AdviseRead(nRanges, panOffsets, panSizes);
300
0
    }
301
302
    size_t GetAdviseReadTotalBytesLimit() const override
303
0
    {
304
0
        return m_nativeHandle->GetAdviseReadTotalBytesLimit();
305
0
    }
306
307
    size_t Write(const void *pBuffer, size_t nBytes) override
308
0
    {
309
0
        return m_nativeHandle->Write(pBuffer, nBytes);
310
0
    }
311
312
    void ClearErr() override
313
0
    {
314
0
        return m_nativeHandle->ClearErr();
315
0
    }
316
317
    int Eof() override
318
0
    {
319
0
        return m_nativeHandle->Eof();
320
0
    }
321
322
    int Error() override
323
0
    {
324
0
        return m_nativeHandle->Error();
325
0
    }
326
327
    int Flush() override
328
0
    {
329
0
        return m_nativeHandle->Flush();
330
0
    }
331
332
    int Close() override
333
0
    {
334
0
        return m_nativeHandle->Close();
335
0
    }
336
337
    int Truncate(vsi_l_offset nNewSize) override
338
0
    {
339
0
        return m_nativeHandle->Truncate(nNewSize);
340
0
    }
341
342
    void *GetNativeFileDescriptor() override
343
0
    {
344
0
        return m_nativeHandle->GetNativeFileDescriptor();
345
0
    }
346
347
    VSIRangeStatus GetRangeStatus(vsi_l_offset nOffset,
348
                                  vsi_l_offset nLength) override
349
0
    {
350
0
        return m_nativeHandle->GetRangeStatus(nOffset, nLength);
351
0
    }
352
353
    bool HasPRead() const override
354
0
    {
355
0
        return m_nativeHandle->HasPRead();
356
0
    }
357
358
    size_t PRead(void *pBuffer, size_t nSize,
359
                 vsi_l_offset nOffset) const override
360
0
    {
361
0
        return m_nativeHandle->PRead(pBuffer, nSize, nOffset);
362
0
    }
363
364
    void Interrupt() override
365
0
    {
366
0
        m_nativeHandle->Interrupt();
367
0
    }
368
369
    void CancelCreation() override;
370
};
371
#endif
372
373
/************************************************************************/
374
/*                         VSIFilesystemHandler                         */
375
/************************************************************************/
376
377
#ifndef DOXYGEN_SKIP
378
class CPL_DLL VSIFilesystemHandler
379
{
380
381
  public:
382
0
    virtual ~VSIFilesystemHandler() = default;
383
384
    static VSIVirtualHandleUniquePtr
385
    OpenStatic(const char *pszFilename, const char *pszAccess,
386
               bool bSetError = false, CSLConstList papszOptions = nullptr);
387
388
    virtual VSIVirtualHandleUniquePtr
389
    Open(const char *pszFilename, const char *pszAccess, bool bSetError = false,
390
         CSLConstList papszOptions = nullptr) = 0;
391
392
    virtual VSIVirtualHandleUniquePtr
393
    CreateOnlyVisibleAtCloseTime(const char *pszFilename,
394
                                 bool bEmulationAllowed,
395
                                 CSLConstList papszOptions);
396
397
    virtual int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
398
                     int nFlags) = 0;
399
400
    virtual int Unlink(const char *pszFilename)
401
0
    {
402
0
        (void)pszFilename;
403
0
        errno = ENOENT;
404
0
        return -1;
405
0
    }
406
407
    virtual int *UnlinkBatch(CSLConstList papszFiles);
408
409
    virtual int Mkdir(const char *pszDirname, long nMode)
410
0
    {
411
0
        (void)pszDirname;
412
0
        (void)nMode;
413
0
        errno = ENOENT;
414
0
        return -1;
415
0
    }
416
417
    virtual int Rmdir(const char *pszDirname)
418
0
    {
419
0
        (void)pszDirname;
420
0
        errno = ENOENT;
421
0
        return -1;
422
0
    }
423
424
    virtual int RmdirRecursive(const char *pszDirname);
425
426
    char **ReadDir(const char *pszDirname)
427
0
    {
428
0
        return ReadDirEx(pszDirname, 0);
429
0
    }
430
431
    virtual char **ReadDirEx(const char * /*pszDirname*/, int /* nMaxFiles */)
432
0
    {
433
0
        return nullptr;
434
0
    }
435
436
    virtual char **SiblingFiles(const char * /*pszFilename*/)
437
0
    {
438
0
        return nullptr;
439
0
    }
440
441
    virtual int Rename(const char *oldpath, const char *newpath,
442
                       GDALProgressFunc pProgressFunc, void *pProgressData)
443
0
    {
444
0
        (void)oldpath;
445
0
        (void)newpath;
446
0
        (void)pProgressFunc;
447
0
        (void)pProgressData;
448
0
        errno = ENOENT;
449
0
        return -1;
450
0
    }
451
452
    virtual int IsCaseSensitive(const char *pszFilename)
453
0
    {
454
0
        (void)pszFilename;
455
0
        return TRUE;
456
0
    }
457
458
    virtual GIntBig GetDiskFreeSpace(const char * /* pszDirname */)
459
0
    {
460
0
        return -1;
461
0
    }
462
463
    virtual int SupportsSparseFiles(const char * /* pszPath */)
464
0
    {
465
0
        return FALSE;
466
0
    }
467
468
    virtual int HasOptimizedReadMultiRange(const char * /* pszPath */)
469
0
    {
470
0
        return FALSE;
471
0
    }
472
473
    virtual const char *GetActualURL(const char * /*pszFilename*/)
474
0
    {
475
0
        return nullptr;
476
0
    }
477
478
    virtual const char *GetOptions()
479
0
    {
480
0
        return nullptr;
481
0
    }
482
483
    virtual char *GetSignedURL(const char * /*pszFilename*/,
484
                               CSLConstList /* papszOptions */)
485
0
    {
486
0
        return nullptr;
487
0
    }
488
489
    virtual bool Sync(const char *pszSource, const char *pszTarget,
490
                      const char *const *papszOptions,
491
                      GDALProgressFunc pProgressFunc, void *pProgressData,
492
                      char ***ppapszOutputs);
493
494
    virtual int CopyFile(const char *pszSource, const char *pszTarget,
495
                         VSILFILE *fpSource, vsi_l_offset nSourceSize,
496
                         const char *const *papszOptions,
497
                         GDALProgressFunc pProgressFunc, void *pProgressData);
498
499
    virtual int
500
    CopyFileRestartable(const char *pszSource, const char *pszTarget,
501
                        const char *pszInputPayload, char **ppszOutputPayload,
502
                        CSLConstList papszOptions,
503
                        GDALProgressFunc pProgressFunc, void *pProgressData);
504
505
    virtual VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
506
                            const char *const *papszOptions);
507
508
    virtual char **GetFileMetadata(const char *pszFilename,
509
                                   const char *pszDomain,
510
                                   CSLConstList papszOptions);
511
512
    virtual bool SetFileMetadata(const char *pszFilename,
513
                                 CSLConstList papszMetadata,
514
                                 const char *pszDomain,
515
                                 CSLConstList papszOptions);
516
517
    virtual bool
518
    MultipartUploadGetCapabilities(int *pbNonSequentialUploadSupported,
519
                                   int *pbParallelUploadSupported,
520
                                   int *pbAbortSupported, size_t *pnMinPartSize,
521
                                   size_t *pnMaxPartSize, int *pnMaxPartCount);
522
523
    virtual char *MultipartUploadStart(const char *pszFilename,
524
                                       CSLConstList papszOptions);
525
526
    virtual char *MultipartUploadAddPart(const char *pszFilename,
527
                                         const char *pszUploadId,
528
                                         int nPartNumber,
529
                                         vsi_l_offset nFileOffset,
530
                                         const void *pData, size_t nDataLength,
531
                                         CSLConstList papszOptions);
532
533
    virtual bool
534
    MultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
535
                       size_t nPartIdsCount, const char *const *apszPartIds,
536
                       vsi_l_offset nTotalSize, CSLConstList papszOptions);
537
538
    virtual bool MultipartUploadAbort(const char *pszFilename,
539
                                      const char *pszUploadId,
540
                                      CSLConstList papszOptions);
541
542
    virtual bool AbortPendingUploads(const char * /*pszFilename*/)
543
0
    {
544
0
        return true;
545
0
    }
546
547
    virtual std::string
548
    GetStreamingFilename(const std::string &osFilename) const
549
0
    {
550
0
        return osFilename;
551
0
    }
552
553
    virtual std::string
554
    GetNonStreamingFilename(const std::string &osFilename) const
555
0
    {
556
0
        return osFilename;
557
0
    }
558
559
    /** Return the canonical filename.
560
     *
561
     * May be implemented by case-insensitive filesystems
562
     * (currently Win32 and MacOSX)
563
     * to return the filename with its actual case (i.e. the one that would
564
     * be used when listing the content of the directory).
565
     */
566
    virtual std::string
567
    GetCanonicalFilename(const std::string &osFilename) const
568
0
    {
569
0
        return osFilename;
570
0
    }
571
572
    virtual bool IsLocal(const char * /* pszPath */) const
573
0
    {
574
0
        return true;
575
0
    }
576
577
    virtual bool IsArchive(const char * /* pszPath */) const
578
0
    {
579
0
        return false;
580
0
    }
581
582
    virtual bool SupportsSequentialWrite(const char * /* pszPath */,
583
                                         bool /* bAllowLocalTempFile */)
584
0
    {
585
0
        return true;
586
0
    }
587
588
    virtual bool SupportsRandomWrite(const char * /* pszPath */,
589
                                     bool /* bAllowLocalTempFile */)
590
0
    {
591
0
        return true;
592
0
    }
593
594
    virtual bool SupportsRead(const char * /* pszPath */)
595
0
    {
596
0
        return true;
597
0
    }
598
599
    virtual VSIFilesystemHandler *Duplicate(const char * /* pszPrefix */)
600
0
    {
601
0
        CPLError(CE_Failure, CPLE_NotSupported,
602
0
                 "Duplicate() not supported on this file "
603
0
                 "system");
604
0
        return nullptr;
605
0
    }
606
607
    /** Return the directory separator.
608
     *
609
     * Default is forward slash. The only exception currently is the Windows
610
     * file system which returns anti-slash, unless the specified path is of the
611
     * form "{drive_letter}:/{rest_of_the_path}".
612
     */
613
    virtual const char *GetDirectorySeparator(CPL_UNUSED const char *pszPath)
614
16.2k
    {
615
16.2k
        return "/";
616
16.2k
    }
617
618
    /** Returns a hint about the path that this file system
619
     * could (potentially) recognize given the input path.
620
     *
621
     * e.g. /vsizip/ will return "/vsizip/my.zip" if provided with "my.zip",
622
     * /vsicurl/ will return "/vsicurl/https://example.com" if provided with
623
     * "https://example.com", /vsis3/ will return "/vsis3/bucket/object" if
624
     * provided with "s3://bucket/object", etc.
625
     *
626
     * Returns an empty string if the input path cannot easily be identified
627
     * as a potential match for the file system.
628
     */
629
    virtual std::string
630
    GetHintForPotentiallyRecognizedPath(const std::string &osPath)
631
0
    {
632
0
        (void)osPath;
633
0
        return std::string();
634
0
    }
635
};
636
#endif /* #ifndef DOXYGEN_SKIP */
637
638
/************************************************************************/
639
/*                            VSIFileManager                            */
640
/************************************************************************/
641
642
#ifndef DOXYGEN_SKIP
643
class CPL_DLL VSIFileManager
644
{
645
  private:
646
    std::shared_ptr<VSIFilesystemHandler> m_poDefaultHandler{};
647
    std::map<std::string, std::shared_ptr<VSIFilesystemHandler>>
648
        m_apoHandlers{};
649
650
    VSIFileManager();
651
652
    static VSIFileManager *Get();
653
654
    CPL_DISALLOW_COPY_ASSIGN(VSIFileManager)
655
656
  public:
657
    ~VSIFileManager();
658
659
    static VSIFilesystemHandler *GetHandler(const char *);
660
    static void InstallHandler(const std::string &osPrefix,
661
                               const std::shared_ptr<VSIFilesystemHandler> &);
662
    static void InstallHandler(const std::string &osPrefix,
663
                               VSIFilesystemHandler *)
664
        CPL_WARN_DEPRECATED("Use version with std::shared_ptr<> instead");
665
    static void RemoveHandler(const std::string &osPrefix);
666
667
    static char **GetPrefixes();
668
};
669
#endif /* #ifndef DOXYGEN_SKIP */
670
671
/************************************************************************/
672
/* ==================================================================== */
673
/*                       VSIArchiveFilesystemHandler                   */
674
/* ==================================================================== */
675
/************************************************************************/
676
677
#ifndef DOXYGEN_SKIP
678
679
class VSIArchiveEntryFileOffset
680
{
681
  public:
682
    virtual ~VSIArchiveEntryFileOffset();
683
};
684
685
class VSIArchiveEntry
686
{
687
  public:
688
    std::string fileName{};
689
    vsi_l_offset uncompressed_size = 0;
690
    std::unique_ptr<VSIArchiveEntryFileOffset> file_pos{};
691
    bool bIsDir = false;
692
    GIntBig nModifiedTime = 0;
693
};
694
695
class VSIArchiveContent
696
{
697
  public:
698
    time_t mTime = 0;
699
    vsi_l_offset nFileSize = 0;
700
    std::vector<VSIArchiveEntry> entries{};
701
702
    // Store list of child indices for each directory
703
    using DirectoryChildren = std::vector<int>;
704
705
    std::map<std::string, DirectoryChildren> dirIndex{};
706
707
0
    VSIArchiveContent() = default;
708
709
    ~VSIArchiveContent();
710
711
  private:
712
    CPL_DISALLOW_COPY_ASSIGN(VSIArchiveContent)
713
};
714
715
class VSIArchiveReader
716
{
717
  public:
718
    virtual ~VSIArchiveReader();
719
720
    virtual int GotoFirstFile() = 0;
721
    virtual int GotoNextFile() = 0;
722
    virtual VSIArchiveEntryFileOffset *GetFileOffset() = 0;
723
    virtual GUIntBig GetFileSize() = 0;
724
    virtual CPLString GetFileName() = 0;
725
    virtual GIntBig GetModifiedTime() = 0;
726
    virtual int GotoFileOffset(VSIArchiveEntryFileOffset *pOffset) = 0;
727
};
728
729
class VSIArchiveFilesystemHandler /* non final */ : public VSIFilesystemHandler
730
{
731
    CPL_DISALLOW_COPY_ASSIGN(VSIArchiveFilesystemHandler)
732
733
    bool FindFileInArchive(const char *archiveFilename,
734
                           const char *fileInArchiveName,
735
                           const VSIArchiveEntry **archiveEntry);
736
737
  protected:
738
    mutable std::recursive_mutex oMutex{};
739
740
    /* We use a cache that contains the list of files contained in a VSIArchive
741
     * file as */
742
    /* unarchive.c is quite inefficient in listing them. This speeds up access
743
     * to VSIArchive files */
744
    /* containing ~1000 files like a CADRG product */
745
    std::map<CPLString, std::unique_ptr<VSIArchiveContent>> oFileList{};
746
747
    virtual const char *GetPrefix() const = 0;
748
    virtual std::vector<CPLString> GetExtensions() const = 0;
749
    virtual std::unique_ptr<VSIArchiveReader>
750
    CreateReader(const char *pszArchiveFileName) = 0;
751
752
  public:
753
    VSIArchiveFilesystemHandler();
754
    ~VSIArchiveFilesystemHandler() override;
755
756
    int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
757
             int nFlags) override;
758
    char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
759
760
    virtual const VSIArchiveContent *
761
    GetContentOfArchive(const char *archiveFilename,
762
                        VSIArchiveReader *poReader = nullptr);
763
    virtual std::unique_ptr<char, VSIFreeReleaser>
764
    SplitFilename(const char *pszFilename, CPLString &osFileInArchive,
765
                  bool bCheckMainFileExists, bool bSetError) const;
766
    virtual std::unique_ptr<VSIArchiveReader>
767
    OpenArchiveFile(const char *archiveFilename, const char *fileInArchiveName);
768
769
    bool IsLocal(const char *pszPath) const override;
770
771
    bool IsArchive(const char *pszPath) const override;
772
773
    bool SupportsSequentialWrite(const char * /* pszPath */,
774
                                 bool /* bAllowLocalTempFile */) override
775
0
    {
776
0
        return false;
777
0
    }
778
779
    bool SupportsRandomWrite(const char * /* pszPath */,
780
                             bool /* bAllowLocalTempFile */) override
781
0
    {
782
0
        return false;
783
0
    }
784
785
    std::string
786
    GetHintForPotentiallyRecognizedPath(const std::string &osPath) override;
787
};
788
789
/************************************************************************/
790
/*                                VSIDIR                                */
791
/************************************************************************/
792
793
struct CPL_DLL VSIDIR
794
{
795
0
    VSIDIR() = default;
796
    virtual ~VSIDIR();
797
798
    virtual const VSIDIREntry *NextDirEntry() = 0;
799
800
  private:
801
    VSIDIR(const VSIDIR &) = delete;
802
    VSIDIR &operator=(const VSIDIR &) = delete;
803
};
804
805
#endif /* #ifndef DOXYGEN_SKIP */
806
807
VSIVirtualHandle CPL_DLL *
808
VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle);
809
VSIVirtualHandle *
810
VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle,
811
                              const GByte *pabyBeginningContent,
812
                              vsi_l_offset nCheatFileSize);
813
constexpr int VSI_CACHED_DEFAULT_CHUNK_SIZE = 32768;
814
VSIVirtualHandle CPL_DLL *
815
VSICreateCachedFile(VSIVirtualHandle *poBaseHandle,
816
                    size_t nChunkSize = VSI_CACHED_DEFAULT_CHUNK_SIZE,
817
                    size_t nCacheSize = 0);
818
819
const int CPL_DEFLATE_TYPE_GZIP = 0;
820
const int CPL_DEFLATE_TYPE_ZLIB = 1;
821
const int CPL_DEFLATE_TYPE_RAW_DEFLATE = 2;
822
VSIVirtualHandle CPL_DLL *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle,
823
                                                int nDeflateType,
824
                                                int bAutoCloseBaseHandle);
825
826
VSIVirtualHandle *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle,
827
                                        int nDeflateType,
828
                                        bool bAutoCloseBaseHandle, int nThreads,
829
                                        size_t nChunkSize,
830
                                        size_t nSOZIPIndexEltSize,
831
                                        std::vector<uint8_t> *panSOZIPIndex);
832
833
VSIVirtualHandle *
834
VSICreateUploadOnCloseFile(VSIVirtualHandleUniquePtr &&poWritableHandle,
835
                           VSIVirtualHandleUniquePtr &&poTmpFile,
836
                           const std::string &osTmpFilename);
837
838
#endif /* ndef CPL_VSI_VIRTUAL_H_INCLUDED */