Line data Source code
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 26103 : static SAFile VSI_SHP_OpenInternal(const char *pszFilename,
36 : const char *pszAccess, int bEnforce2GBLimit)
37 :
38 : {
39 : OGRSHPDBFFile *pFile;
40 26103 : VSILFILE *fp = VSIFOpenExL(pszFilename, pszAccess, TRUE);
41 26103 : if (fp == SHPLIB_NULLPTR)
42 11170 : return SHPLIB_NULLPTR;
43 14933 : pFile = (OGRSHPDBFFile *)CPLCalloc(1, sizeof(OGRSHPDBFFile));
44 14933 : pFile->fp = fp;
45 14933 : pFile->pszFilename = CPLStrdup(pszFilename);
46 14933 : pFile->bEnforce2GBLimit = bEnforce2GBLimit;
47 14933 : pFile->nCurOffset = 0;
48 14933 : return (SAFile)pFile;
49 : }
50 :
51 : /************************************************************************/
52 : /* VSI_SHP_Open() */
53 : /************************************************************************/
54 :
55 26103 : static SAFile VSI_SHP_Open(const char *pszFilename, const char *pszAccess,
56 : void *userData)
57 :
58 : {
59 : (void)userData;
60 26103 : return VSI_SHP_OpenInternal(pszFilename, pszAccess, FALSE);
61 : }
62 :
63 : /************************************************************************/
64 : /* VSI_SHP_Read() */
65 : /************************************************************************/
66 :
67 2685090 : static SAOffset VSI_SHP_Read(void *p, SAOffset size, SAOffset nmemb,
68 : SAFile file)
69 :
70 : {
71 2685090 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
72 : SAOffset ret =
73 2685090 : (SAOffset)VSIFReadL(p, (size_t)size, (size_t)nmemb, pFile->fp);
74 2685090 : pFile->nCurOffset += ret * size;
75 2685090 : return ret;
76 : }
77 :
78 : /************************************************************************/
79 : /* VSI_SHP_WriteMoreDataOK() */
80 : /************************************************************************/
81 :
82 359257 : int VSI_SHP_WriteMoreDataOK(SAFile file, SAOffset nExtraBytes)
83 : {
84 359257 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
85 359257 : if (pFile->nCurOffset + nExtraBytes > INT_MAX)
86 : {
87 0 : if (pFile->bEnforce2GBLimit)
88 : {
89 0 : CPLError(CE_Failure, CPLE_AppDefined,
90 : "2GB file size limit reached for %s", pFile->pszFilename);
91 0 : return FALSE;
92 : }
93 0 : else if (!pFile->bHasWarned2GB)
94 : {
95 0 : pFile->bHasWarned2GB = TRUE;
96 0 : CPLError(CE_Warning, CPLE_AppDefined,
97 : "2GB file size limit reached for %s. "
98 : "Going on, but might cause compatibility issues with "
99 : "third party software",
100 : pFile->pszFilename);
101 : }
102 : }
103 :
104 359257 : return TRUE;
105 : }
106 :
107 : /************************************************************************/
108 : /* VSI_SHP_Write() */
109 : /************************************************************************/
110 :
111 295610 : static SAOffset VSI_SHP_Write(const void *p, SAOffset size, SAOffset nmemb,
112 : SAFile file)
113 :
114 : {
115 295610 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
116 : SAOffset ret;
117 295610 : if (!VSI_SHP_WriteMoreDataOK(file, size * nmemb))
118 0 : return 0;
119 295610 : ret = (SAOffset)VSIFWriteL(p, (size_t)size, (size_t)nmemb, pFile->fp);
120 295610 : pFile->nCurOffset += ret * size;
121 295610 : return ret;
122 : }
123 :
124 : /************************************************************************/
125 : /* VSI_SHP_Seek() */
126 : /************************************************************************/
127 :
128 801768 : static SAOffset VSI_SHP_Seek(SAFile file, SAOffset offset, int whence)
129 :
130 : {
131 801768 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
132 801768 : SAOffset ret = (SAOffset)VSIFSeekL(pFile->fp, (vsi_l_offset)offset, whence);
133 801768 : if (whence == 0 && ret == 0)
134 439917 : pFile->nCurOffset = offset;
135 : else
136 361851 : pFile->nCurOffset = (SAOffset)VSIFTellL(pFile->fp);
137 801768 : return ret;
138 : }
139 :
140 : /************************************************************************/
141 : /* VSI_SHP_Tell() */
142 : /************************************************************************/
143 :
144 133563 : static SAOffset VSI_SHP_Tell(SAFile file)
145 :
146 : {
147 133563 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
148 133563 : return (SAOffset)pFile->nCurOffset;
149 : }
150 :
151 : /************************************************************************/
152 : /* VSI_SHP_Flush() */
153 : /************************************************************************/
154 :
155 6213 : static int VSI_SHP_Flush(SAFile file)
156 :
157 : {
158 6213 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
159 6213 : return VSIFFlushL(pFile->fp);
160 : }
161 :
162 : /************************************************************************/
163 : /* VSI_SHP_Close() */
164 : /************************************************************************/
165 :
166 14917 : static int VSI_SHP_Close(SAFile file)
167 :
168 : {
169 14917 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
170 14917 : int ret = VSIFCloseL(pFile->fp);
171 14917 : CPLFree(pFile->pszFilename);
172 14917 : CPLFree(pFile);
173 14917 : return ret;
174 : }
175 :
176 : /************************************************************************/
177 : /* SADError() */
178 : /************************************************************************/
179 :
180 348 : static void VSI_SHP_Error(const char *message)
181 :
182 : {
183 348 : CPLError(CE_Failure, CPLE_AppDefined, "%s", message);
184 348 : }
185 :
186 : /************************************************************************/
187 : /* VSI_SHP_Remove() */
188 : /************************************************************************/
189 :
190 1591 : static int VSI_SHP_Remove(const char *pszFilename, void *userData)
191 :
192 : {
193 : (void)userData;
194 1591 : return VSIUnlink(pszFilename);
195 : }
196 :
197 : /************************************************************************/
198 : /* SASetupDefaultHooks() */
199 : /************************************************************************/
200 :
201 3365 : void SASetupDefaultHooks(SAHooks *psHooks)
202 :
203 : {
204 3365 : psHooks->FOpen = VSI_SHP_Open;
205 3365 : psHooks->FRead = VSI_SHP_Read;
206 3365 : psHooks->FWrite = VSI_SHP_Write;
207 3365 : psHooks->FSeek = VSI_SHP_Seek;
208 3365 : psHooks->FTell = VSI_SHP_Tell;
209 3365 : psHooks->FFlush = VSI_SHP_Flush;
210 3365 : psHooks->FClose = VSI_SHP_Close;
211 3365 : psHooks->Remove = VSI_SHP_Remove;
212 :
213 3365 : psHooks->Error = VSI_SHP_Error;
214 3365 : psHooks->Atof = CPLAtof;
215 3365 : psHooks->pvUserData = SHPLIB_NULLPTR;
216 3365 : }
217 :
218 : #ifndef SHP_VSI_ONLY_SETUP_HOOKS
219 :
220 : /************************************************************************/
221 : /* VSI_SHP_GetVSIL() */
222 : /************************************************************************/
223 :
224 191464 : VSILFILE *VSI_SHP_GetVSIL(SAFile file)
225 : {
226 191464 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
227 191464 : return pFile->fp;
228 : }
229 :
230 : /************************************************************************/
231 : /* VSI_SHP_GetFilename() */
232 : /************************************************************************/
233 :
234 156 : const char *VSI_SHP_GetFilename(SAFile file)
235 : {
236 156 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
237 156 : return pFile->pszFilename;
238 : }
239 :
240 : /************************************************************************/
241 : /* VSI_SHP_Open2GBLimit() */
242 : /************************************************************************/
243 :
244 0 : static SAFile VSI_SHP_Open2GBLimit(const char *pszFilename,
245 : const char *pszAccess, void *userData)
246 :
247 : {
248 : (void)userData;
249 0 : return VSI_SHP_OpenInternal(pszFilename, pszAccess, TRUE);
250 : }
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 10281 : const SAHooks *VSI_SHP_GetHook(int b2GBLimit)
267 : {
268 10281 : return (b2GBLimit) ? &sOGRHook2GBLimit : &sOGRHook;
269 : }
270 :
271 : #endif
|