1 : /******************************************************************************
2 : * $Id: ogrbnadatasource.cpp
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, Even Rouault
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 :
40 174 : OGRBNADataSource::OGRBNADataSource()
41 :
42 : {
43 174 : papoLayers = NULL;
44 174 : nLayers = 0;
45 :
46 174 : fpOutput = NULL;
47 :
48 174 : pszName = NULL;
49 :
50 174 : pszCoordinateSeparator = NULL;
51 :
52 174 : bUpdate = FALSE;
53 174 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRBNADataSource() */
57 : /************************************************************************/
58 :
59 348 : OGRBNADataSource::~OGRBNADataSource()
60 :
61 : {
62 174 : if ( fpOutput != NULL )
63 : {
64 3 : VSIFClose( fpOutput);
65 : }
66 :
67 215 : for( int i = 0; i < nLayers; i++ )
68 41 : delete papoLayers[i];
69 174 : CPLFree( papoLayers );
70 :
71 174 : CPLFree( pszCoordinateSeparator );
72 :
73 174 : CPLFree( pszName );
74 348 : }
75 :
76 : /************************************************************************/
77 : /* TestCapability() */
78 : /************************************************************************/
79 :
80 0 : int OGRBNADataSource::TestCapability( const char * pszCap )
81 :
82 : {
83 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
84 0 : return TRUE;
85 0 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
86 0 : return FALSE;
87 : else
88 0 : return FALSE;
89 : }
90 :
91 : /************************************************************************/
92 : /* GetLayer() */
93 : /************************************************************************/
94 :
95 101 : OGRLayer *OGRBNADataSource::GetLayer( int iLayer )
96 :
97 : {
98 101 : if( iLayer < 0 || iLayer >= nLayers )
99 0 : return NULL;
100 : else
101 101 : return papoLayers[iLayer];
102 : }
103 :
104 : /************************************************************************/
105 : /* CreateLayer() */
106 : /************************************************************************/
107 :
108 12 : OGRLayer * OGRBNADataSource::CreateLayer( const char * pszLayerName,
109 : OGRSpatialReference *poSRS,
110 : OGRwkbGeometryType eType,
111 : char ** papszOptions )
112 :
113 : {
114 : BNAFeatureType bnaFeatureType;
115 :
116 12 : switch(eType)
117 : {
118 : case wkbPolygon:
119 : case wkbPolygon25D:
120 : case wkbMultiPolygon:
121 : case wkbMultiPolygon25D:
122 6 : bnaFeatureType = BNA_POLYGON;
123 6 : break;
124 :
125 : case wkbPoint:
126 : case wkbPoint25D:
127 3 : bnaFeatureType = BNA_POINT;
128 3 : break;
129 :
130 : case wkbLineString:
131 : case wkbLineString25D:
132 3 : bnaFeatureType = BNA_POLYLINE;
133 3 : break;
134 :
135 : default:
136 : CPLError( CE_Failure, CPLE_NotSupported,
137 : "Geometry type of `%s' not supported in BNAs.\n",
138 0 : OGRGeometryTypeToName(eType) );
139 0 : return NULL;
140 : }
141 :
142 12 : nLayers++;
143 12 : papoLayers = (OGRBNALayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRBNALayer*));
144 12 : papoLayers[nLayers-1] = new OGRBNALayer( pszName, pszLayerName, bnaFeatureType, eType, TRUE, this );
145 :
146 12 : return papoLayers[nLayers-1];
147 : }
148 :
149 : /************************************************************************/
150 : /* Open() */
151 : /************************************************************************/
152 :
153 171 : int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn)
154 :
155 : {
156 171 : int ok = FALSE;
157 :
158 171 : pszName = CPLStrdup( pszFilename );
159 171 : bUpdate = bUpdateIn;
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Determine what sort of object this is. */
163 : /* -------------------------------------------------------------------- */
164 : VSIStatBufL sStatBuf;
165 :
166 171 : if( VSIStatL( pszFilename, &sStatBuf ) != 0 )
167 60 : return FALSE;
168 :
169 : // --------------------------------------------------------------------
170 : // Does this appear to be an .bna file?
171 : // --------------------------------------------------------------------
172 111 : if( !EQUAL( CPLGetExtension(pszFilename), "bna" ) )
173 103 : return FALSE;
174 :
175 8 : FILE* fp = VSIFOpen(pszFilename, "rb");
176 8 : if (fp)
177 : {
178 : BNARecord* record;
179 8 : int curLine = 0;
180 8 : const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"};
181 8 : OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon };
182 : int i;
183 : #if defined(BNA_FAST_DS_OPEN)
184 : record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
185 : BNA_FreeRecord(record);
186 :
187 : if (ok)
188 : {
189 : nLayers = 4;
190 :
191 : papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
192 : for(i=0;i<4;i++)
193 : papoLayers[i] = new OGRBNALayer( pszFilename,
194 : layerRadixName[i],
195 : (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this );
196 : }
197 : #else
198 8 : int nFeatures[4] = { 0, 0, 0, 0 };
199 8 : OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL };
200 8 : int nIDs[4] = {0, 0, 0, 0};
201 8 : int partialIndexTable = TRUE;
202 :
203 58 : while(1)
204 : {
205 66 : int offset = VSIFTell(fp);
206 66 : int line = curLine;
207 66 : record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
208 66 : if (ok == FALSE)
209 : {
210 0 : BNA_FreeRecord(record);
211 0 : if (line != 0)
212 0 : ok = TRUE;
213 0 : break;
214 : }
215 66 : if (record == NULL)
216 : {
217 : /* end of file */
218 8 : ok = TRUE;
219 :
220 : /* and we have finally build the whole index table */
221 8 : partialIndexTable = FALSE;
222 8 : break;
223 : }
224 :
225 58 : if (record->nIDs > nIDs[record->featureType])
226 29 : nIDs[record->featureType] = record->nIDs;
227 :
228 58 : nFeatures[record->featureType]++;
229 58 : offsetAndLineFeaturesTable[record->featureType] =
230 58 : (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType],
231 116 : nFeatures[record->featureType] * sizeof(OffsetAndLine));
232 58 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset;
233 58 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line;
234 :
235 58 : BNA_FreeRecord(record);
236 : }
237 :
238 8 : nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0);
239 8 : papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
240 8 : int iLayer = 0;
241 40 : for(i=0;i<4;i++)
242 : {
243 32 : if (nFeatures[i])
244 : {
245 29 : papoLayers[iLayer] = new OGRBNALayer( pszFilename,
246 : layerRadixName[i],
247 : (BNAFeatureType)i,
248 : wkbGeomTypes[i],
249 : FALSE,
250 : this,
251 58 : nIDs[i]);
252 29 : papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i],
253 : offsetAndLineFeaturesTable[i],
254 58 : partialIndexTable);
255 29 : iLayer++;
256 : }
257 : }
258 : #endif
259 8 : VSIFClose(fp);
260 : }
261 :
262 8 : return ok;
263 : }
264 :
265 :
266 : /************************************************************************/
267 : /* Create() */
268 : /************************************************************************/
269 :
270 3 : int OGRBNADataSource::Create( const char *pszFilename,
271 : char **papszOptions )
272 : {
273 3 : if( fpOutput != NULL)
274 : {
275 : CPLAssert( FALSE );
276 0 : return FALSE;
277 : }
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Do not override exiting file. */
281 : /* -------------------------------------------------------------------- */
282 : VSIStatBufL sStatBuf;
283 :
284 3 : if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
285 0 : return FALSE;
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Create the output file. */
289 : /* -------------------------------------------------------------------- */
290 3 : pszName = CPLStrdup( pszFilename );
291 :
292 3 : if( EQUAL(pszFilename,"stdout") )
293 0 : fpOutput = stdout;
294 : else
295 3 : fpOutput = VSIFOpen( pszFilename, "wb" );
296 3 : if( fpOutput == NULL )
297 : {
298 : CPLError( CE_Failure, CPLE_OpenFailed,
299 : "Failed to create BNA file %s.",
300 0 : pszFilename );
301 0 : return FALSE;
302 : }
303 :
304 : /* EOL token */
305 3 : const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
306 :
307 3 : if( pszCRLFFormat == NULL )
308 : {
309 : #ifdef WIN32
310 : bUseCRLF = TRUE;
311 : #else
312 1 : bUseCRLF = FALSE;
313 : #endif
314 : }
315 2 : else if( EQUAL(pszCRLFFormat,"CRLF") )
316 1 : bUseCRLF = TRUE;
317 1 : else if( EQUAL(pszCRLFFormat,"LF") )
318 1 : bUseCRLF = FALSE;
319 : else
320 : {
321 : CPLError( CE_Warning, CPLE_AppDefined,
322 : "LINEFORMAT=%s not understood, use one of CRLF or LF.",
323 0 : pszCRLFFormat );
324 : #ifdef WIN32
325 : bUseCRLF = TRUE;
326 : #else
327 0 : bUseCRLF = FALSE;
328 : #endif
329 : }
330 :
331 : /* Multi line or single line format ? */
332 3 : bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE);
333 :
334 : /* Number of identifiers per record */
335 3 : const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS");
336 3 : if (pszNbOutID == NULL)
337 : {
338 3 : nbOutID = NB_MIN_BNA_IDS;
339 : }
340 0 : else if (EQUAL(pszNbOutID, "NB_SOURCE_FIELDS"))
341 : {
342 0 : nbOutID = -1;
343 : }
344 : else
345 : {
346 0 : nbOutID = atoi(pszNbOutID);
347 0 : if (nbOutID <= 0)
348 : {
349 : CPLError( CE_Warning, CPLE_AppDefined,
350 : "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
351 0 : pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
352 0 : nbOutID = NB_MIN_BNA_IDS;
353 : }
354 0 : if (nbOutID > NB_MAX_BNA_IDS)
355 : {
356 : CPLError( CE_Warning, CPLE_AppDefined,
357 : "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
358 0 : pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
359 0 : nbOutID = NB_MAX_BNA_IDS;
360 : }
361 : }
362 :
363 : /* Ellipses export as ellipses or polygons ? */
364 3 : bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE);
365 :
366 : /* Number of coordinate pairs per line */
367 3 : const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE");
368 3 : if (pszNbPairPerLine)
369 : {
370 0 : nbPairPerLine = atoi(pszNbPairPerLine);
371 0 : if (nbPairPerLine <= 0)
372 0 : nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
373 0 : if (bMultiLine == FALSE)
374 : {
375 0 : CPLError( CE_Warning, CPLE_AppDefined, "NB_PAIR_PER_LINE option is ignored when MULTILINE=NO");
376 : }
377 : }
378 : else
379 : {
380 3 : nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
381 : }
382 :
383 : /* Coordinate precision */
384 3 : const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION");
385 3 : if (pszCoordinatePrecision)
386 : {
387 2 : coordinatePrecision = atoi(pszCoordinatePrecision);
388 2 : if (coordinatePrecision <= 0)
389 0 : coordinatePrecision = 0;
390 2 : else if (coordinatePrecision >= 20)
391 0 : coordinatePrecision = 20;
392 : }
393 : else
394 : {
395 1 : coordinatePrecision = 10;
396 : }
397 :
398 3 : pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR");
399 3 : if (pszCoordinateSeparator == NULL)
400 3 : pszCoordinateSeparator = CPLStrdup(",");
401 : else
402 0 : pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator);
403 :
404 3 : return TRUE;
405 : }
|