1 : /******************************************************************************
2 : * $Id: ogrbnadatasource.cpp 23244 2011-10-16 21:52:16Z rouault $
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 730 : OGRBNADataSource::OGRBNADataSource()
41 :
42 : {
43 730 : papoLayers = NULL;
44 730 : nLayers = 0;
45 :
46 730 : fpOutput = NULL;
47 :
48 730 : pszName = NULL;
49 :
50 730 : pszCoordinateSeparator = NULL;
51 :
52 730 : bUpdate = FALSE;
53 730 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRBNADataSource() */
57 : /************************************************************************/
58 :
59 730 : OGRBNADataSource::~OGRBNADataSource()
60 :
61 : {
62 730 : if ( fpOutput != NULL )
63 : {
64 3 : VSIFCloseL( fpOutput);
65 : }
66 :
67 771 : for( int i = 0; i < nLayers; i++ )
68 41 : delete papoLayers[i];
69 730 : CPLFree( papoLayers );
70 :
71 730 : CPLFree( pszCoordinateSeparator );
72 :
73 730 : CPLFree( pszName );
74 730 : }
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 727 : int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn)
154 :
155 : {
156 727 : int ok = FALSE;
157 :
158 727 : pszName = CPLStrdup( pszFilename );
159 727 : bUpdate = bUpdateIn;
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Determine what sort of object this is. */
163 : /* -------------------------------------------------------------------- */
164 : VSIStatBufL sStatBuf;
165 :
166 727 : if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0 )
167 189 : return FALSE;
168 :
169 : // --------------------------------------------------------------------
170 : // Does this appear to be a .bna file?
171 : // --------------------------------------------------------------------
172 538 : if( !(EQUAL( CPLGetExtension(pszFilename), "bna" )
173 : || ((EQUALN( pszFilename, "/vsigzip/", 9) || EQUALN( pszFilename, "/vsizip/", 8)) &&
174 : (strstr( pszFilename, ".bna") || strstr( pszFilename, ".BNA")))) )
175 530 : return FALSE;
176 :
177 8 : VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
178 8 : if (fp)
179 : {
180 : BNARecord* record;
181 8 : int curLine = 0;
182 8 : const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"};
183 8 : OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon };
184 : int i;
185 : #if defined(BNA_FAST_DS_OPEN)
186 : record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
187 : BNA_FreeRecord(record);
188 :
189 : if (ok)
190 : {
191 : nLayers = 4;
192 :
193 : papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
194 : for(i=0;i<4;i++)
195 : papoLayers[i] = new OGRBNALayer( pszFilename,
196 : layerRadixName[i],
197 : (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this );
198 : }
199 : #else
200 8 : int nFeatures[4] = { 0, 0, 0, 0 };
201 8 : OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL };
202 8 : int nIDs[4] = {0, 0, 0, 0};
203 8 : int partialIndexTable = TRUE;
204 :
205 58 : while(1)
206 : {
207 66 : int offset = (int) VSIFTellL(fp);
208 66 : int line = curLine;
209 66 : record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
210 66 : if (ok == FALSE)
211 : {
212 0 : BNA_FreeRecord(record);
213 0 : if (line != 0)
214 0 : ok = TRUE;
215 0 : break;
216 : }
217 66 : if (record == NULL)
218 : {
219 : /* end of file */
220 8 : ok = TRUE;
221 :
222 : /* and we have finally build the whole index table */
223 8 : partialIndexTable = FALSE;
224 8 : break;
225 : }
226 :
227 58 : if (record->nIDs > nIDs[record->featureType])
228 29 : nIDs[record->featureType] = record->nIDs;
229 :
230 58 : nFeatures[record->featureType]++;
231 58 : offsetAndLineFeaturesTable[record->featureType] =
232 58 : (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType],
233 116 : nFeatures[record->featureType] * sizeof(OffsetAndLine));
234 58 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset;
235 58 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line;
236 :
237 58 : BNA_FreeRecord(record);
238 : }
239 :
240 8 : nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0);
241 8 : papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
242 8 : int iLayer = 0;
243 40 : for(i=0;i<4;i++)
244 : {
245 32 : if (nFeatures[i])
246 : {
247 29 : papoLayers[iLayer] = new OGRBNALayer( pszFilename,
248 : layerRadixName[i],
249 : (BNAFeatureType)i,
250 : wkbGeomTypes[i],
251 : FALSE,
252 : this,
253 58 : nIDs[i]);
254 29 : papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i],
255 : offsetAndLineFeaturesTable[i],
256 58 : partialIndexTable);
257 29 : iLayer++;
258 : }
259 : }
260 : #endif
261 8 : VSIFCloseL(fp);
262 : }
263 :
264 8 : return ok;
265 : }
266 :
267 :
268 : /************************************************************************/
269 : /* Create() */
270 : /************************************************************************/
271 :
272 3 : int OGRBNADataSource::Create( const char *pszFilename,
273 : char **papszOptions )
274 : {
275 3 : if( fpOutput != NULL)
276 : {
277 0 : CPLAssert( FALSE );
278 0 : return FALSE;
279 : }
280 :
281 3 : if( strcmp(pszFilename,"/dev/stdout") == 0 )
282 0 : pszFilename = "/vsistdout/";
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Do not override exiting file. */
286 : /* -------------------------------------------------------------------- */
287 : VSIStatBufL sStatBuf;
288 :
289 3 : if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
290 0 : return FALSE;
291 :
292 : /* -------------------------------------------------------------------- */
293 : /* Create the output file. */
294 : /* -------------------------------------------------------------------- */
295 3 : pszName = CPLStrdup( pszFilename );
296 :
297 3 : fpOutput = VSIFOpenL( pszFilename, "wb" );
298 3 : if( fpOutput == NULL )
299 : {
300 : CPLError( CE_Failure, CPLE_OpenFailed,
301 : "Failed to create BNA file %s.",
302 0 : pszFilename );
303 0 : return FALSE;
304 : }
305 :
306 : /* EOL token */
307 3 : const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
308 :
309 3 : if( pszCRLFFormat == NULL )
310 : {
311 : #ifdef WIN32
312 : bUseCRLF = TRUE;
313 : #else
314 1 : bUseCRLF = FALSE;
315 : #endif
316 : }
317 2 : else if( EQUAL(pszCRLFFormat,"CRLF") )
318 1 : bUseCRLF = TRUE;
319 1 : else if( EQUAL(pszCRLFFormat,"LF") )
320 1 : bUseCRLF = FALSE;
321 : else
322 : {
323 : CPLError( CE_Warning, CPLE_AppDefined,
324 : "LINEFORMAT=%s not understood, use one of CRLF or LF.",
325 0 : pszCRLFFormat );
326 : #ifdef WIN32
327 : bUseCRLF = TRUE;
328 : #else
329 0 : bUseCRLF = FALSE;
330 : #endif
331 : }
332 :
333 : /* Multi line or single line format ? */
334 3 : bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE);
335 :
336 : /* Number of identifiers per record */
337 3 : const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS");
338 3 : if (pszNbOutID == NULL)
339 : {
340 3 : nbOutID = NB_MIN_BNA_IDS;
341 : }
342 0 : else if (EQUAL(pszNbOutID, "NB_SOURCE_FIELDS"))
343 : {
344 0 : nbOutID = -1;
345 : }
346 : else
347 : {
348 0 : nbOutID = atoi(pszNbOutID);
349 0 : if (nbOutID <= 0)
350 : {
351 : CPLError( CE_Warning, CPLE_AppDefined,
352 : "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
353 0 : pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
354 0 : nbOutID = NB_MIN_BNA_IDS;
355 : }
356 0 : if (nbOutID > NB_MAX_BNA_IDS)
357 : {
358 : CPLError( CE_Warning, CPLE_AppDefined,
359 : "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS",
360 0 : pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS );
361 0 : nbOutID = NB_MAX_BNA_IDS;
362 : }
363 : }
364 :
365 : /* Ellipses export as ellipses or polygons ? */
366 3 : bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE);
367 :
368 : /* Number of coordinate pairs per line */
369 3 : const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE");
370 3 : if (pszNbPairPerLine)
371 : {
372 0 : nbPairPerLine = atoi(pszNbPairPerLine);
373 0 : if (nbPairPerLine <= 0)
374 0 : nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
375 0 : if (bMultiLine == FALSE)
376 : {
377 0 : CPLError( CE_Warning, CPLE_AppDefined, "NB_PAIR_PER_LINE option is ignored when MULTILINE=NO");
378 : }
379 : }
380 : else
381 : {
382 3 : nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
383 : }
384 :
385 : /* Coordinate precision */
386 3 : const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION");
387 3 : if (pszCoordinatePrecision)
388 : {
389 2 : coordinatePrecision = atoi(pszCoordinatePrecision);
390 2 : if (coordinatePrecision <= 0)
391 0 : coordinatePrecision = 0;
392 2 : else if (coordinatePrecision >= 20)
393 0 : coordinatePrecision = 20;
394 : }
395 : else
396 : {
397 1 : coordinatePrecision = 10;
398 : }
399 :
400 3 : pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR");
401 3 : if (pszCoordinateSeparator == NULL)
402 3 : pszCoordinateSeparator = CPLStrdup(",");
403 : else
404 0 : pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator);
405 :
406 3 : return TRUE;
407 : }
|