Coverage Report

Created: 2025-06-13 06:29

/src/gdal/ogr/ogrsf_frmts/shape/shp_vsi.c
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 = (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 (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 = (OGRSHPDBFFile *)file;
72
0
    SAOffset ret =
73
0
        (SAOffset)VSIFReadL(p, (size_t)size, (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 = (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 = (OGRSHPDBFFile *)file;
116
0
    SAOffset ret;
117
0
    if (!VSI_SHP_WriteMoreDataOK(file, size * nmemb))
118
0
        return 0;
119
0
    ret = (SAOffset)VSIFWriteL(p, (size_t)size, (size_t)nmemb, pFile->fp);
120
0
    pFile->nCurOffset += ret * size;
121
0
    return ret;
122
0
}
123
124
/************************************************************************/
125
/*                            VSI_SHP_Seek()                            */
126
/************************************************************************/
127
128
static SAOffset VSI_SHP_Seek(SAFile file, SAOffset offset, int whence)
129
130
0
{
131
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
132
0
    SAOffset ret = (SAOffset)VSIFSeekL(pFile->fp, (vsi_l_offset)offset, whence);
133
0
    if (whence == 0 && ret == 0)
134
0
        pFile->nCurOffset = offset;
135
0
    else
136
0
        pFile->nCurOffset = (SAOffset)VSIFTellL(pFile->fp);
137
0
    return ret;
138
0
}
139
140
/************************************************************************/
141
/*                            VSI_SHP_Tell()                            */
142
/************************************************************************/
143
144
static SAOffset VSI_SHP_Tell(SAFile file)
145
146
0
{
147
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
148
0
    return (SAOffset)pFile->nCurOffset;
149
0
}
150
151
/************************************************************************/
152
/*                           VSI_SHP_Flush()                            */
153
/************************************************************************/
154
155
static int VSI_SHP_Flush(SAFile file)
156
157
0
{
158
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
159
0
    return VSIFFlushL(pFile->fp);
160
0
}
161
162
/************************************************************************/
163
/*                           VSI_SHP_Close()                            */
164
/************************************************************************/
165
166
static int VSI_SHP_Close(SAFile file)
167
168
0
{
169
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
170
0
    int ret = VSIFCloseL(pFile->fp);
171
0
    CPLFree(pFile->pszFilename);
172
0
    CPLFree(pFile);
173
0
    return ret;
174
0
}
175
176
/************************************************************************/
177
/*                              SADError()                              */
178
/************************************************************************/
179
180
static void VSI_SHP_Error(const char *message)
181
182
0
{
183
0
    CPLError(CE_Failure, CPLE_AppDefined, "%s", message);
184
0
}
185
186
/************************************************************************/
187
/*                           VSI_SHP_Remove()                           */
188
/************************************************************************/
189
190
static int VSI_SHP_Remove(const char *pszFilename, void *userData)
191
192
0
{
193
0
    (void)userData;
194
0
    return VSIUnlink(pszFilename);
195
0
}
196
197
/************************************************************************/
198
/*                        SASetupDefaultHooks()                         */
199
/************************************************************************/
200
201
void SASetupDefaultHooks(SAHooks *psHooks)
202
203
0
{
204
0
    psHooks->FOpen = VSI_SHP_Open;
205
0
    psHooks->FRead = VSI_SHP_Read;
206
0
    psHooks->FWrite = VSI_SHP_Write;
207
0
    psHooks->FSeek = VSI_SHP_Seek;
208
0
    psHooks->FTell = VSI_SHP_Tell;
209
0
    psHooks->FFlush = VSI_SHP_Flush;
210
0
    psHooks->FClose = VSI_SHP_Close;
211
0
    psHooks->Remove = VSI_SHP_Remove;
212
213
0
    psHooks->Error = VSI_SHP_Error;
214
0
    psHooks->Atof = CPLAtof;
215
0
    psHooks->pvUserData = SHPLIB_NULLPTR;
216
0
}
217
218
#ifndef SHP_VSI_ONLY_SETUP_HOOKS
219
220
/************************************************************************/
221
/*                         VSI_SHP_GetVSIL()                            */
222
/************************************************************************/
223
224
VSILFILE *VSI_SHP_GetVSIL(SAFile file)
225
0
{
226
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
227
0
    return pFile->fp;
228
0
}
229
230
/************************************************************************/
231
/*                        VSI_SHP_GetFilename()                         */
232
/************************************************************************/
233
234
const char *VSI_SHP_GetFilename(SAFile file)
235
0
{
236
0
    OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
237
0
    return pFile->pszFilename;
238
0
}
239
240
/************************************************************************/
241
/*                        VSI_SHP_Open2GBLimit()                        */
242
/************************************************************************/
243
244
static SAFile VSI_SHP_Open2GBLimit(const char *pszFilename,
245
                                   const char *pszAccess, void *userData)
246
247
0
{
248
0
    (void)userData;
249
0
    return VSI_SHP_OpenInternal(pszFilename, pszAccess, TRUE);
250
0
}
251
252
/************************************************************************/
253
/*                         VSI_SHP_GetHook()                            */
254
/************************************************************************/
255
256
static const SAHooks sOGRHook = {
257
    VSI_SHP_Open,  VSI_SHP_Read,  VSI_SHP_Write, VSI_SHP_Seek,
258
    VSI_SHP_Tell,  VSI_SHP_Flush, VSI_SHP_Close, VSI_SHP_Remove,
259
    VSI_SHP_Error, CPLAtof,       NULL};
260
261
static const SAHooks sOGRHook2GBLimit = {
262
    VSI_SHP_Open2GBLimit, VSI_SHP_Read,  VSI_SHP_Write, VSI_SHP_Seek,
263
    VSI_SHP_Tell,         VSI_SHP_Flush, VSI_SHP_Close, VSI_SHP_Remove,
264
    VSI_SHP_Error,        CPLAtof,       NULL};
265
266
const SAHooks *VSI_SHP_GetHook(int b2GBLimit)
267
0
{
268
0
    return (b2GBLimit) ? &sOGRHook2GBLimit : &sOGRHook;
269
0
}
270
271
#endif