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