1 /******************************************************************************
2 * $Id: ogrbnadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
3 *
4 * Project: BNA Translator
5 * Purpose: Implements OGRBNADataSource class
6 * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 *
8 ******************************************************************************
9 * Copyright (c) 2007-2011, Even Rouault <even dot rouault at mines-paris dot org>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "ogr_bna.h"
31 #include "cpl_conv.h"
32 #include "cpl_string.h"
33 #include "cpl_csv.h"
34 #include "ogrbnaparser.h"
35
36 /************************************************************************/
37 /* OGRBNADataSource() */
38 /************************************************************************/
39
OGRBNADataSource()40 OGRBNADataSource::OGRBNADataSource()
41
42 {
43 papoLayers = NULL;
44 nLayers = 0;
45
46 fpOutput = NULL;
47
48 pszName = NULL;
49
50 pszCoordinateSeparator = NULL;
51
52 bUpdate = FALSE;
53 }
54
55 /************************************************************************/
56 /* ~OGRBNADataSource() */
57 /************************************************************************/
58
~OGRBNADataSource()59 OGRBNADataSource::~OGRBNADataSource()
60
61 {
62 if ( fpOutput != NULL )
63 {
64 VSIFCloseL( fpOutput);
65 }
66
67 for( int i = 0; i < nLayers; i++ )
68 delete papoLayers[i];
69 CPLFree( papoLayers );
70
71 CPLFree( pszCoordinateSeparator );
72
73 CPLFree( pszName );
74 }
75
76 /************************************************************************/
77 /* TestCapability() */
78 /************************************************************************/
79
TestCapability(const char * pszCap)80 int OGRBNADataSource::TestCapability( const char * pszCap )
81
82 {
83 if( EQUAL(pszCap,ODsCCreateLayer) )
84 return TRUE;
85 else if( EQUAL(pszCap,ODsCDeleteLayer) )
86 return FALSE;
87 else
88 return FALSE;
89 }
90
91 /************************************************************************/
92 /* GetLayer() */
93 /************************************************************************/
94
GetLayer(int iLayer)95 OGRLayer *OGRBNADataSource::GetLayer( int iLayer )
96
97 {
98 if( iLayer < 0 || iLayer >= nLayers )
99 return NULL;
100 else
101 return papoLayers[iLayer];
102 }
103
104 /************************************************************************/
105 /* ICreateLayer() */
106 /************************************************************************/
107
ICreateLayer(const char * pszLayerName,CPL_UNUSED OGRSpatialReference * poSRS,OGRwkbGeometryType eType,CPL_UNUSED char ** papszOptions)108 OGRLayer * OGRBNADataSource::ICreateLayer( const char * pszLayerName,
109 CPL_UNUSED OGRSpatialReference *poSRS,
110 OGRwkbGeometryType eType,
111 CPL_UNUSED char ** papszOptions )
112 {
113 BNAFeatureType bnaFeatureType;
114
115 switch(eType)
116 {
117 case wkbPolygon:
118 case wkbPolygon25D:
119 case wkbMultiPolygon:
120 case wkbMultiPolygon25D:
121 bnaFeatureType = BNA_POLYGON;
122 break;
123
124 case wkbPoint:
125 case wkbPoint25D:
126 bnaFeatureType = BNA_POINT;
127 break;
128
129 case wkbLineString:
130 case wkbLineString25D:
131 bnaFeatureType = BNA_POLYLINE;
132 break;
133
134 default:
135 CPLError( CE_Failure, CPLE_NotSupported,
136 "Geometry type of `%s' not supported in BNAs.\n",
137 OGRGeometryTypeToName(eType) );
138 return NULL;
139 }
140
141 nLayers++;
142 papoLayers = (OGRBNALayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRBNALayer*));
143 papoLayers[nLayers-1] = new OGRBNALayer( pszName, pszLayerName, bnaFeatureType, eType, TRUE, this );
144
145 return papoLayers[nLayers-1];
146 }
147
148 /************************************************************************/
149 /* Open() */
150 /************************************************************************/
151
Open(const char * pszFilename,int bUpdateIn)152 int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn)
153
154 {
155 int ok = FALSE;
156
157 pszName = CPLStrdup( pszFilename );
158 bUpdate = bUpdateIn;
159
160 VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
161 if (fp)
162 {
163 BNARecord* record;
164 int curLine = 0;
165 const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"};
166 OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon };
167 int i;
168 #if defined(BNA_FAST_DS_OPEN)
169 record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
170 BNA_FreeRecord(record);
171
172 if (ok)
173 {
174 nLayers = 4;
175
176 papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
177 for(i=0;i<4;i++)
178 papoLayers[i] = new OGRBNALayer( pszFilename,
179 layerRadixName[i],
180 (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this );
181 }
182 #else
183 int nFeatures[4] = { 0, 0, 0, 0 };
184 OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL };
185 int nIDs[4] = {0, 0, 0, 0};
186 int partialIndexTable = TRUE;
187
188 while(1)
189 {
190 int offset = (int) VSIFTellL(fp);
191 int line = curLine;
192 record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
193 if (ok == FALSE)
194 {
195 BNA_FreeRecord(record);
196 if (line != 0)
197 ok = TRUE;
198 break;
199 }
200 if (record == NULL)
201 {
202 /* end of file */
203 ok = TRUE;
204
205 /* and we have finally build the whole index table */
206 partialIndexTable = FALSE;
207 break;
208 }
209
210 if (record->nIDs > nIDs[record->featureType])
211 nIDs[record->featureType] = record->nIDs;
212
213 nFeatures[record->featureType]++;
214 offsetAndLineFeaturesTable[record->featureType] =
215 (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType],
216 nFeatures[record->featureType] * sizeof(OffsetAndLine));
217 offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset;
218 offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line;
219
220 BNA_FreeRecord(record);
221 }
222
223 nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0);
224 papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
225 int iLayer = 0;
226 for(i=0;i<4;i++)
227 {
228 if (nFeatures[i])
229 {
230 papoLayers[iLayer] = new OGRBNALayer( pszFilename,
231 layerRadixName[i],
232 (BNAFeatureType)i,
233 wkbGeomTypes[i],
234 FALSE,
235 this,
236 nIDs[i]);
237 papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i],
238 offsetAndLineFeaturesTable[i],
239 partialIndexTable);
240 iLayer++;
241 }
242 }
243 #endif
244 VSIFCloseL(fp);
245 }
246
247 return ok;
248 }
249
250
251 /************************************************************************/
252 /* Create() */
253 /************************************************************************/
254
Create(const char * pszFilename,char ** papszOptions)255 int OGRBNADataSource::Create( const char *pszFilename,
256 char **papszOptions )
257 {
258 if( fpOutput != NULL)
259 {
260 CPLAssert( FALSE );
261 return FALSE;
262 }
263
264 if( strcmp(pszFilename,"/dev/stdout") == 0 )
265 pszFilename = "/vsistdout/";
266
267 /* -------------------------------------------------------------------- */
268 /* Do not override exiting file. */
269 /* -------------------------------------------------------------------- */
270 VSIStatBufL sStatBuf;
271
272 if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
273 return FALSE;
274
275 /* -------------------------------------------------------------------- */
276 /* Create the output file. */
277 /* -------------------------------------------------------------------- */
278 pszName = CPLStrdup( pszFilename );
279
280 fpOutput = VSIFOpenL( pszFilename, "wb" );
281 if( fpOutput == NULL )
282 {
283 CPLError( CE_Failure, CPLE_OpenFailed,
284 "Failed to create BNA file %s.",
285 pszFilename );
286 return FALSE;
287 }
288
289 /* EOL token */
290 const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
291
292 if( pszCRLFFormat == NULL )
293 {
294 #ifdef WIN32
295 bUseCRLF = TRUE;
296 #else
297 bUseCRLF = FALSE;
298 #endif
299 }
300 else if( EQUAL(pszCRLFFormat,"CRLF") )
301 bUseCRLF = TRUE;
302 else if( EQUAL(pszCRLFFormat,"LF") )
303 bUseCRLF = FALSE;
304 else
305 {
306 CPLError( CE_Warning, CPLE_AppDefined,
307 "LINEFORMAT=%s not understood, use one of CRLF or LF.",
308 pszCRLFFormat );
309 #ifdef WIN32
310 bUseCRLF = TRUE;
311 #else
312 bUseCRLF = FALSE;
313 #endif
314 }
315
316 /* Multi line or single line format ? */
317 bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE);
318
319 /* Number of identifiers per record */
320 const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS");
321 if (pszNbOutID == NULL)
322 {
323 nbOutID = NB_MIN_BNA_IDS;
324 }
325 else if (EQUAL(pszNbOutID, "NB_SOURCE_FIELDS"))
326 {
327 nbOutID = -1;
328 }
329 else
330 {
331 nbOutID = atoi(pszNbOutID);
332 if (nbOutID <= 0)
333 {
334 CPLError( CE_Warning, CPLE_AppDefined,
335 "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
336 pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
337 nbOutID = NB_MIN_BNA_IDS;
338 }
339 if (nbOutID > NB_MAX_BNA_IDS)
340 {
341 CPLError( CE_Warning, CPLE_AppDefined,
342 "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
343 pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
344 nbOutID = NB_MAX_BNA_IDS;
345 }
346 }
347
348 /* Ellipses export as ellipses or polygons ? */
349 bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE);
350
351 /* Number of coordinate pairs per line */
352 const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE");
353 if (pszNbPairPerLine)
354 {
355 nbPairPerLine = atoi(pszNbPairPerLine);
356 if (nbPairPerLine <= 0)
357 nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
358 if (bMultiLine == FALSE)
359 {
360 CPLError( CE_Warning, CPLE_AppDefined, "NB_PAIR_PER_LINE option is ignored when MULTILINE=NO");
361 }
362 }
363 else
364 {
365 nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
366 }
367
368 /* Coordinate precision */
369 const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION");
370 if (pszCoordinatePrecision)
371 {
372 coordinatePrecision = atoi(pszCoordinatePrecision);
373 if (coordinatePrecision <= 0)
374 coordinatePrecision = 0;
375 else if (coordinatePrecision >= 20)
376 coordinatePrecision = 20;
377 }
378 else
379 {
380 coordinatePrecision = 10;
381 }
382
383 pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR");
384 if (pszCoordinateSeparator == NULL)
385 pszCoordinateSeparator = CPLStrdup(",");
386 else
387 pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator);
388
389 return TRUE;
390 }
391