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 28390 : static SAFile VSI_SHP_OpenInternal(const char *pszFilename,
36 : const char *pszAccess, int bEnforce2GBLimit)
37 :
38 : {
39 : OGRSHPDBFFile *pFile;
40 28390 : VSILFILE *fp = VSIFOpenExL(pszFilename, pszAccess, TRUE);
41 28390 : if (fp == SHPLIB_NULLPTR)
42 12138 : return SHPLIB_NULLPTR;
43 16252 : pFile = static_cast<OGRSHPDBFFile *>(CPLCalloc(1, sizeof(OGRSHPDBFFile)));
44 16252 : pFile->fp = fp;
45 16252 : pFile->pszFilename = CPLStrdup(pszFilename);
46 16252 : pFile->bEnforce2GBLimit = bEnforce2GBLimit;
47 16252 : pFile->nCurOffset = 0;
48 16252 : return reinterpret_cast<SAFile>(pFile);
49 : }
50 :
51 : /************************************************************************/
52 : /* VSI_SHP_Open() */
53 : /************************************************************************/
54 :
55 28390 : static SAFile VSI_SHP_Open(const char *pszFilename, const char *pszAccess,
56 : void *userData)
57 :
58 : {
59 : (void)userData;
60 28390 : return VSI_SHP_OpenInternal(pszFilename, pszAccess, FALSE);
61 : }
62 :
63 : /************************************************************************/
64 : /* VSI_SHP_Read() */
65 : /************************************************************************/
66 :
67 2696940 : static SAOffset VSI_SHP_Read(void *p, SAOffset size, SAOffset nmemb,
68 : SAFile file)
69 :
70 : {
71 2696940 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
72 2696940 : SAOffset ret = static_cast<SAOffset>(VSIFReadL(
73 : p, static_cast<size_t>(size), static_cast<size_t>(nmemb), pFile->fp));
74 2696940 : pFile->nCurOffset += ret * size;
75 2696940 : return ret;
76 : }
77 :
78 : /************************************************************************/
79 : /* VSI_SHP_WriteMoreDataOK() */
80 : /************************************************************************/
81 :
82 364616 : int VSI_SHP_WriteMoreDataOK(SAFile file, SAOffset nExtraBytes)
83 : {
84 364616 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
85 364616 : 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 364616 : return TRUE;
105 : }
106 :
107 : /************************************************************************/
108 : /* VSI_SHP_Write() */
109 : /************************************************************************/
110 :
111 299870 : static SAOffset VSI_SHP_Write(const void *p, SAOffset size, SAOffset nmemb,
112 : SAFile file)
113 :
114 : {
115 299870 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
116 : SAOffset ret;
117 299870 : if (!VSI_SHP_WriteMoreDataOK(file, size * nmemb))
118 0 : return 0;
119 299870 : ret = static_cast<SAOffset>(VSIFWriteL(
120 : p, static_cast<size_t>(size), static_cast<size_t>(nmemb), pFile->fp));
121 299870 : pFile->nCurOffset += ret * size;
122 299870 : return ret;
123 : }
124 :
125 : /************************************************************************/
126 : /* VSI_SHP_Seek() */
127 : /************************************************************************/
128 :
129 815162 : static SAOffset VSI_SHP_Seek(SAFile file, SAOffset offset, int whence)
130 :
131 : {
132 815162 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
133 815162 : int ret = VSIFSeekL(pFile->fp, static_cast<vsi_l_offset>(offset), whence);
134 815162 : if (whence == 0 && ret == 0)
135 453676 : pFile->nCurOffset = offset;
136 : else
137 361486 : pFile->nCurOffset = static_cast<SAOffset>(VSIFTellL(pFile->fp));
138 815162 : return ret;
139 : }
140 :
141 : /************************************************************************/
142 : /* VSI_SHP_Tell() */
143 : /************************************************************************/
144 :
145 135695 : static SAOffset VSI_SHP_Tell(SAFile file)
146 :
147 : {
148 135695 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
149 135695 : return static_cast<SAOffset>(pFile->nCurOffset);
150 : }
151 :
152 : /************************************************************************/
153 : /* VSI_SHP_Flush() */
154 : /************************************************************************/
155 :
156 6600 : static int VSI_SHP_Flush(SAFile file)
157 :
158 : {
159 6600 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
160 6600 : return VSIFFlushL(pFile->fp);
161 : }
162 :
163 : /************************************************************************/
164 : /* VSI_SHP_Close() */
165 : /************************************************************************/
166 :
167 16236 : static int VSI_SHP_Close(SAFile file)
168 :
169 : {
170 16236 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
171 16236 : int ret = VSIFCloseL(pFile->fp);
172 16236 : CPLFree(pFile->pszFilename);
173 16236 : CPLFree(pFile);
174 16236 : return ret;
175 : }
176 :
177 : /************************************************************************/
178 : /* SADError() */
179 : /************************************************************************/
180 :
181 356 : static void VSI_SHP_Error(const char *message)
182 :
183 : {
184 356 : CPLError(CE_Failure, CPLE_AppDefined, "%s", message);
185 356 : }
186 :
187 : /************************************************************************/
188 : /* VSI_SHP_Remove() */
189 : /************************************************************************/
190 :
191 1679 : static int VSI_SHP_Remove(const char *pszFilename, void *userData)
192 :
193 : {
194 : (void)userData;
195 1679 : return VSIUnlink(pszFilename);
196 : }
197 :
198 : /************************************************************************/
199 : /* SASetupDefaultHooks() */
200 : /************************************************************************/
201 :
202 3575 : void SASetupDefaultHooks(SAHooks *psHooks)
203 :
204 : {
205 3575 : psHooks->FOpen = VSI_SHP_Open;
206 3575 : psHooks->FRead = VSI_SHP_Read;
207 3575 : psHooks->FWrite = VSI_SHP_Write;
208 3575 : psHooks->FSeek = VSI_SHP_Seek;
209 3575 : psHooks->FTell = VSI_SHP_Tell;
210 3575 : psHooks->FFlush = VSI_SHP_Flush;
211 3575 : psHooks->FClose = VSI_SHP_Close;
212 3575 : psHooks->Remove = VSI_SHP_Remove;
213 :
214 3575 : psHooks->Error = VSI_SHP_Error;
215 3575 : psHooks->Atof = CPLAtof;
216 3575 : psHooks->pvUserData = SHPLIB_NULLPTR;
217 3575 : }
218 :
219 : #ifndef SHP_VSI_ONLY_SETUP_HOOKS
220 :
221 : /************************************************************************/
222 : /* VSI_SHP_GetVSIL() */
223 : /************************************************************************/
224 :
225 201810 : VSILFILE *VSI_SHP_GetVSIL(SAFile file)
226 : {
227 201810 : OGRSHPDBFFile *pFile = reinterpret_cast<OGRSHPDBFFile *>(file);
228 201810 : 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 = reinterpret_cast<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 = {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 11178 : const SAHooks *VSI_SHP_GetHook(int b2GBLimit)
268 : {
269 11178 : return (b2GBLimit) ? &sOGRHook2GBLimit : &sOGRHook;
270 : }
271 :
272 : #endif
|