Coverage Report

Created: 2025-08-28 06:57

/src/gdal/ogr/ogrsf_frmts/shape/shp_vsi.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  IO Redirection via VSI services for shp/dbf io.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007,  Frank Warmerdam
9
 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "shp_vsi.h"
15
#include "cpl_error.h"
16
#include "cpl_conv.h"
17
#include "cpl_vsi_error.h"
18
#include <limits.h>
19
20
#include "shapefil_private.h"
21
22
typedef struct
23
{
24
    VSILFILE *fp;
25
    char *pszFilename;
26
    int bEnforce2GBLimit;
27
    int bHasWarned2GB;
28
    SAOffset nCurOffset;
29
} OGRSHPDBFFile;
30
31
/************************************************************************/
32
/*                         VSI_SHP_OpenInternal()                       */
33
/************************************************************************/
34
35
static SAFile VSI_SHP_OpenInternal(const char *pszFilename,
36
                                   const char *pszAccess, int bEnforce2GBLimit)
37
38
0
{
39
0
    OGRSHPDBFFile *pFile;
40
0
    VSILFILE *fp = VSIFOpenExL(pszFilename, pszAccess, TRUE);
41
0
    if (fp == SHPLIB_NULLPTR)
42
0
        return SHPLIB_NULLPTR;
43
0
    pFile = static_cast<OGRSHPDBFFile *>(CPLCalloc(1, sizeof(OGRSHPDBFFile)));
44
0
    pFile->fp = fp;
45
0
    pFile->pszFilename = CPLStrdup(pszFilename);
46
0
    pFile->bEnforce2GBLimit = bEnforce2GBLimit;
47
0
    pFile->nCurOffset = 0;
48
0
    return reinterpret_cast<SAFile>(pFile);
49
0
}
50
51
/************************************************************************/
52
/*                            VSI_SHP_Open()                            */
53
/************************************************************************/
54
55
static SAFile VSI_SHP_Open(const char *pszFilename, const char *pszAccess,
56
                           void *userData)
57
58
0
{
59
0
    (void)userData;
60
0
    return VSI_SHP_OpenInternal(pszFilename, pszAccess, FALSE);
61
0
}
62
63
/************************************************************************/
64
/*                            VSI_SHP_Read()                            */
65
/************************************************************************/
66
67
static SAOffset VSI_SHP_Read(void *p, SAOffset size, SAOffset nmemb,
68
                             SAFile file)
69
70
0
{
71
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
72
0
    SAOffset ret = static_cast<SAOffset>(VSIFReadL(
73
0
        p, static_cast<size_t>(size), static_cast<size_t>(nmemb), pFile->fp));
74
0
    pFile->nCurOffset += ret * size;
75
0
    return ret;
76
0
}
77
78
/************************************************************************/
79
/*                      VSI_SHP_WriteMoreDataOK()                       */
80
/************************************************************************/
81
82
int VSI_SHP_WriteMoreDataOK(SAFile file, SAOffset nExtraBytes)
83
0
{
84
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
85
0
    if (pFile->nCurOffset + nExtraBytes > INT_MAX)
86
0
    {
87
0
        if (pFile->bEnforce2GBLimit)
88
0
        {
89
0
            CPLError(CE_Failure, CPLE_AppDefined,
90
0
                     "2GB file size limit reached for %s", pFile->pszFilename);
91
0
            return FALSE;
92
0
        }
93
0
        else if (!pFile->bHasWarned2GB)
94
0
        {
95
0
            pFile->bHasWarned2GB = TRUE;
96
0
            CPLError(CE_Warning, CPLE_AppDefined,
97
0
                     "2GB file size limit reached for %s. "
98
0
                     "Going on, but might cause compatibility issues with "
99
0
                     "third party software",
100
0
                     pFile->pszFilename);
101
0
        }
102
0
    }
103
104
0
    return TRUE;
105
0
}
106
107
/************************************************************************/
108
/*                           VSI_SHP_Write()                            */
109
/************************************************************************/
110
111
static SAOffset VSI_SHP_Write(const void *p, SAOffset size, SAOffset nmemb,
112
                              SAFile file)
113
114
0
{
115
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
116
0
    SAOffset ret;
117
0
    if (!VSI_SHP_WriteMoreDataOK(file, size * nmemb))
118
0
        return 0;
119
0
    ret = static_cast<SAOffset>(VSIFWriteL(
120
0
        p, static_cast<size_t>(size), static_cast<size_t>(nmemb), pFile->fp));
121
0
    pFile->nCurOffset += ret * size;
122
0
    return ret;
123
0
}
124
125
/************************************************************************/
126
/*                            VSI_SHP_Seek()                            */
127
/************************************************************************/
128
129
static SAOffset VSI_SHP_Seek(SAFile file, SAOffset offset, int whence)
130
131
0
{
132
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
133
0
    int ret = VSIFSeekL(pFile->fp, static_cast<vsi_l_offset>(offset), whence);
134
0
    if (whence == 0 && ret == 0)
135
0
        pFile->nCurOffset = offset;
136
0
    else
137
0
        pFile->nCurOffset = static_cast<SAOffset>(VSIFTellL(pFile->fp));
138
0
    return ret;
139
0
}
140
141
/************************************************************************/
142
/*                            VSI_SHP_Tell()                            */
143
/************************************************************************/
144
145
static SAOffset VSI_SHP_Tell(SAFile file)
146
147
0
{
148
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
149
0
    return static_cast<SAOffset>(pFile->nCurOffset);
150
0
}
151
152
/************************************************************************/
153
/*                           VSI_SHP_Flush()                            */
154
/************************************************************************/
155
156
static int VSI_SHP_Flush(SAFile file)
157
158
0
{
159
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
160
0
    return VSIFFlushL(pFile->fp);
161
0
}
162
163
/************************************************************************/
164
/*                           VSI_SHP_Close()                            */
165
/************************************************************************/
166
167
static int VSI_SHP_Close(SAFile file)
168
169
0
{
170
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
171
0
    int ret = VSIFCloseL(pFile->fp);
172
0
    CPLFree(pFile->pszFilename);
173
0
    CPLFree(pFile);
174
0
    return ret;
175
0
}
176
177
/************************************************************************/
178
/*                              SADError()                              */
179
/************************************************************************/
180
181
static void VSI_SHP_Error(const char *message)
182
183
0
{
184
0
    CPLError(CE_Failure, CPLE_AppDefined, "%s", message);
185
0
}
186
187
/************************************************************************/
188
/*                           VSI_SHP_Remove()                           */
189
/************************************************************************/
190
191
static int VSI_SHP_Remove(const char *pszFilename, void *userData)
192
193
0
{
194
0
    (void)userData;
195
0
    return VSIUnlink(pszFilename);
196
0
}
197
198
/************************************************************************/
199
/*                        SASetupDefaultHooks()                         */
200
/************************************************************************/
201
202
void SASetupDefaultHooks(SAHooks *psHooks)
203
204
0
{
205
0
    psHooks->FOpen = VSI_SHP_Open;
206
0
    psHooks->FRead = VSI_SHP_Read;
207
0
    psHooks->FWrite = VSI_SHP_Write;
208
0
    psHooks->FSeek = VSI_SHP_Seek;
209
0
    psHooks->FTell = VSI_SHP_Tell;
210
0
    psHooks->FFlush = VSI_SHP_Flush;
211
0
    psHooks->FClose = VSI_SHP_Close;
212
0
    psHooks->Remove = VSI_SHP_Remove;
213
214
0
    psHooks->Error = VSI_SHP_Error;
215
0
    psHooks->Atof = CPLAtof;
216
0
    psHooks->pvUserData = SHPLIB_NULLPTR;
217
0
}
218
219
#ifndef SHP_VSI_ONLY_SETUP_HOOKS
220
221
/************************************************************************/
222
/*                         VSI_SHP_GetVSIL()                            */
223
/************************************************************************/
224
225
VSILFILE *VSI_SHP_GetVSIL(SAFile file)
226
0
{
227
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
228
0
    return pFile->fp;
229
0
}
230
231
/************************************************************************/
232
/*                        VSI_SHP_GetFilename()                         */
233
/************************************************************************/
234
235
const char *VSI_SHP_GetFilename(SAFile file)
236
0
{
237
0
    OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
238
0
    return pFile->pszFilename;
239
0
}
240
241
/************************************************************************/
242
/*                        VSI_SHP_Open2GBLimit()                        */
243
/************************************************************************/
244
245
static SAFile VSI_SHP_Open2GBLimit(const char *pszFilename,
246
                                   const char *pszAccess, void *userData)
247
248
0
{
249
0
    (void)userData;
250
0
    return VSI_SHP_OpenInternal(pszFilename, pszAccess, TRUE);
251
0
}
252
253
/************************************************************************/
254
/*                         VSI_SHP_GetHook()                            */
255
/************************************************************************/
256
257
static const SAHooks sOGRHook = {VSI_SHP_Open,  VSI_SHP_Read,   VSI_SHP_Write,
258
                                 VSI_SHP_Seek,  VSI_SHP_Tell,   VSI_SHP_Flush,
259
                                 VSI_SHP_Close, VSI_SHP_Remove, VSI_SHP_Error,
260
                                 CPLAtof,       nullptr};
261
262
static const SAHooks sOGRHook2GBLimit = {
263
    VSI_SHP_Open2GBLimit, VSI_SHP_Read,  VSI_SHP_Write, VSI_SHP_Seek,
264
    VSI_SHP_Tell,         VSI_SHP_Flush, VSI_SHP_Close, VSI_SHP_Remove,
265
    VSI_SHP_Error,        CPLAtof,       nullptr};
266
267
const SAHooks *VSI_SHP_GetHook(int b2GBLimit)
268
0
{
269
0
    return (b2GBLimit) ? &sOGRHook2GBLimit : &sOGRHook;
270
0
}
271
272
#endif