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 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "shp_vsi.h"
32 : #include "cpl_error.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_vsi_error.h"
35 : #include <limits.h>
36 :
37 : typedef struct
38 : {
39 : VSILFILE *fp;
40 : char *pszFilename;
41 : int bEnforce2GBLimit;
42 : int bHasWarned2GB;
43 : SAOffset nCurOffset;
44 : } OGRSHPDBFFile;
45 :
46 : /************************************************************************/
47 : /* VSI_SHP_GetVSIL() */
48 : /************************************************************************/
49 :
50 80249 : VSILFILE *VSI_SHP_GetVSIL(SAFile file)
51 : {
52 80249 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
53 80249 : return pFile->fp;
54 : }
55 :
56 : /************************************************************************/
57 : /* VSI_SHP_GetFilename() */
58 : /************************************************************************/
59 :
60 156 : const char *VSI_SHP_GetFilename(SAFile file)
61 : {
62 156 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
63 156 : return pFile->pszFilename;
64 : }
65 :
66 : /************************************************************************/
67 : /* VSI_SHP_OpenInternal() */
68 : /************************************************************************/
69 :
70 25544 : static SAFile VSI_SHP_OpenInternal(const char *pszFilename,
71 : const char *pszAccess, int bEnforce2GBLimit)
72 :
73 : {
74 : OGRSHPDBFFile *pFile;
75 25544 : VSILFILE *fp = VSIFOpenExL(pszFilename, pszAccess, TRUE);
76 25544 : if (fp == NULL)
77 10962 : return NULL;
78 14582 : pFile = (OGRSHPDBFFile *)CPLCalloc(1, sizeof(OGRSHPDBFFile));
79 14582 : pFile->fp = fp;
80 14582 : pFile->pszFilename = CPLStrdup(pszFilename);
81 14582 : pFile->bEnforce2GBLimit = bEnforce2GBLimit;
82 14582 : pFile->nCurOffset = 0;
83 14582 : return (SAFile)pFile;
84 : }
85 :
86 : /************************************************************************/
87 : /* VSI_SHP_Open() */
88 : /************************************************************************/
89 :
90 25544 : static SAFile VSI_SHP_Open(const char *pszFilename, const char *pszAccess,
91 : void *userData)
92 :
93 : {
94 : (void)userData;
95 25544 : return VSI_SHP_OpenInternal(pszFilename, pszAccess, FALSE);
96 : }
97 :
98 : /************************************************************************/
99 : /* VSI_SHP_Open2GBLimit() */
100 : /************************************************************************/
101 :
102 0 : static SAFile VSI_SHP_Open2GBLimit(const char *pszFilename,
103 : const char *pszAccess, void *userData)
104 :
105 : {
106 : (void)userData;
107 0 : return VSI_SHP_OpenInternal(pszFilename, pszAccess, TRUE);
108 : }
109 :
110 : /************************************************************************/
111 : /* VSI_SHP_Read() */
112 : /************************************************************************/
113 :
114 2671580 : static SAOffset VSI_SHP_Read(void *p, SAOffset size, SAOffset nmemb,
115 : SAFile file)
116 :
117 : {
118 2671580 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
119 : SAOffset ret =
120 2671580 : (SAOffset)VSIFReadL(p, (size_t)size, (size_t)nmemb, pFile->fp);
121 2671580 : pFile->nCurOffset += ret * size;
122 2671580 : return ret;
123 : }
124 :
125 : /************************************************************************/
126 : /* VSI_SHP_WriteMoreDataOK() */
127 : /************************************************************************/
128 :
129 413471 : int VSI_SHP_WriteMoreDataOK(SAFile file, SAOffset nExtraBytes)
130 : {
131 413471 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
132 413471 : if (pFile->nCurOffset + nExtraBytes > INT_MAX)
133 : {
134 0 : if (pFile->bEnforce2GBLimit)
135 : {
136 0 : CPLError(CE_Failure, CPLE_AppDefined,
137 : "2GB file size limit reached for %s", pFile->pszFilename);
138 0 : return FALSE;
139 : }
140 0 : else if (!pFile->bHasWarned2GB)
141 : {
142 0 : pFile->bHasWarned2GB = TRUE;
143 0 : CPLError(CE_Warning, CPLE_AppDefined,
144 : "2GB file size limit reached for %s. "
145 : "Going on, but might cause compatibility issues with "
146 : "third party software",
147 : pFile->pszFilename);
148 : }
149 : }
150 :
151 413471 : return TRUE;
152 : }
153 :
154 : /************************************************************************/
155 : /* VSI_SHP_Write() */
156 : /************************************************************************/
157 :
158 336224 : static SAOffset VSI_SHP_Write(const void *p, SAOffset size, SAOffset nmemb,
159 : SAFile file)
160 :
161 : {
162 336224 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
163 : SAOffset ret;
164 336224 : if (!VSI_SHP_WriteMoreDataOK(file, size * nmemb))
165 0 : return 0;
166 336224 : ret = (SAOffset)VSIFWriteL(p, (size_t)size, (size_t)nmemb, pFile->fp);
167 336224 : pFile->nCurOffset += ret * size;
168 336224 : return ret;
169 : }
170 :
171 : /************************************************************************/
172 : /* VSI_SHP_Seek() */
173 : /************************************************************************/
174 :
175 812416 : static SAOffset VSI_SHP_Seek(SAFile file, SAOffset offset, int whence)
176 :
177 : {
178 812416 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
179 812416 : SAOffset ret = (SAOffset)VSIFSeekL(pFile->fp, (vsi_l_offset)offset, whence);
180 812416 : if (whence == 0 && ret == 0)
181 452046 : pFile->nCurOffset = offset;
182 : else
183 360370 : pFile->nCurOffset = (SAOffset)VSIFTellL(pFile->fp);
184 812416 : return ret;
185 : }
186 :
187 : /************************************************************************/
188 : /* VSI_SHP_Tell() */
189 : /************************************************************************/
190 :
191 160820 : static SAOffset VSI_SHP_Tell(SAFile file)
192 :
193 : {
194 160820 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
195 160820 : return (SAOffset)pFile->nCurOffset;
196 : }
197 :
198 : /************************************************************************/
199 : /* VSI_SHP_Flush() */
200 : /************************************************************************/
201 :
202 6011 : static int VSI_SHP_Flush(SAFile file)
203 :
204 : {
205 6011 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
206 6011 : return VSIFFlushL(pFile->fp);
207 : }
208 :
209 : /************************************************************************/
210 : /* VSI_SHP_Close() */
211 : /************************************************************************/
212 :
213 14566 : static int VSI_SHP_Close(SAFile file)
214 :
215 : {
216 14566 : OGRSHPDBFFile *pFile = (OGRSHPDBFFile *)file;
217 14566 : int ret = VSIFCloseL(pFile->fp);
218 14566 : CPLFree(pFile->pszFilename);
219 14566 : CPLFree(pFile);
220 14566 : return ret;
221 : }
222 :
223 : /************************************************************************/
224 : /* SADError() */
225 : /************************************************************************/
226 :
227 343 : static void VSI_SHP_Error(const char *message)
228 :
229 : {
230 343 : CPLError(CE_Failure, CPLE_AppDefined, "%s", message);
231 343 : }
232 :
233 : /************************************************************************/
234 : /* VSI_SHP_Remove() */
235 : /************************************************************************/
236 :
237 1577 : static int VSI_SHP_Remove(const char *pszFilename, void *userData)
238 :
239 : {
240 : (void)userData;
241 1577 : return VSIUnlink(pszFilename);
242 : }
243 :
244 : /************************************************************************/
245 : /* SASetupDefaultHooks() */
246 : /************************************************************************/
247 :
248 3337 : void SASetupDefaultHooks(SAHooks *psHooks)
249 :
250 : {
251 3337 : psHooks->FOpen = VSI_SHP_Open;
252 3337 : psHooks->FRead = VSI_SHP_Read;
253 3337 : psHooks->FWrite = VSI_SHP_Write;
254 3337 : psHooks->FSeek = VSI_SHP_Seek;
255 3337 : psHooks->FTell = VSI_SHP_Tell;
256 3337 : psHooks->FFlush = VSI_SHP_Flush;
257 3337 : psHooks->FClose = VSI_SHP_Close;
258 3337 : psHooks->Remove = VSI_SHP_Remove;
259 :
260 3337 : psHooks->Error = VSI_SHP_Error;
261 3337 : psHooks->Atof = CPLAtof;
262 3337 : psHooks->pvUserData = NULL;
263 3337 : }
264 :
265 : /************************************************************************/
266 : /* VSI_SHP_GetHook() */
267 : /************************************************************************/
268 :
269 : static const SAHooks sOGRHook = {
270 : VSI_SHP_Open, VSI_SHP_Read, VSI_SHP_Write, VSI_SHP_Seek,
271 : VSI_SHP_Tell, VSI_SHP_Flush, VSI_SHP_Close, VSI_SHP_Remove,
272 : VSI_SHP_Error, CPLAtof, NULL};
273 :
274 : static const SAHooks sOGRHook2GBLimit = {
275 : VSI_SHP_Open2GBLimit, VSI_SHP_Read, VSI_SHP_Write, VSI_SHP_Seek,
276 : VSI_SHP_Tell, VSI_SHP_Flush, VSI_SHP_Close, VSI_SHP_Remove,
277 : VSI_SHP_Error, CPLAtof, NULL};
278 :
279 10051 : const SAHooks *VSI_SHP_GetHook(int b2GBLimit)
280 : {
281 10051 : return (b2GBLimit) ? &sOGRHook2GBLimit : &sOGRHook;
282 : }
|