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 1220 : OGRBNADataSource::OGRBNADataSource()
41 :
42 : {
43 1220 : papoLayers = NULL;
44 1220 : nLayers = 0;
45 :
46 1220 : fpOutput = NULL;
47 :
48 1220 : pszName = NULL;
49 :
50 1220 : pszCoordinateSeparator = NULL;
51 :
52 1220 : bUpdate = FALSE;
53 1220 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRBNADataSource() */
57 : /************************************************************************/
58 :
59 1220 : OGRBNADataSource::~OGRBNADataSource()
60 :
61 : {
62 1220 : if ( fpOutput != NULL )
63 : {
64 6 : VSIFCloseL( fpOutput);
65 : }
66 :
67 1302 : for( int i = 0; i < nLayers; i++ )
68 82 : delete papoLayers[i];
69 1220 : CPLFree( papoLayers );
70 :
71 1220 : CPLFree( pszCoordinateSeparator );
72 :
73 1220 : CPLFree( pszName );
74 1220 : }
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 202 : OGRLayer *OGRBNADataSource::GetLayer( int iLayer )
96 :
97 : {
98 202 : if( iLayer < 0 || iLayer >= nLayers )
99 0 : return NULL;
100 : else
101 202 : return papoLayers[iLayer];
102 : }
103 :
104 : /************************************************************************/
105 : /* CreateLayer() */
106 : /************************************************************************/
107 :
108 24 : OGRLayer * OGRBNADataSource::CreateLayer( const char * pszLayerName,
109 : OGRSpatialReference *poSRS,
110 : OGRwkbGeometryType eType,
111 : char ** papszOptions )
112 :
113 : {
114 : BNAFeatureType bnaFeatureType;
115 :
116 24 : switch(eType)
117 : {
118 : case wkbPolygon:
119 : case wkbPolygon25D:
120 : case wkbMultiPolygon:
121 : case wkbMultiPolygon25D:
122 12 : bnaFeatureType = BNA_POLYGON;
123 12 : break;
124 :
125 : case wkbPoint:
126 : case wkbPoint25D:
127 6 : bnaFeatureType = BNA_POINT;
128 6 : break;
129 :
130 : case wkbLineString:
131 : case wkbLineString25D:
132 6 : bnaFeatureType = BNA_POLYLINE;
133 6 : 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 24 : nLayers++;
143 24 : papoLayers = (OGRBNALayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRBNALayer*));
144 24 : papoLayers[nLayers-1] = new OGRBNALayer( pszName, pszLayerName, bnaFeatureType, eType, TRUE, this );
145 :
146 24 : return papoLayers[nLayers-1];
147 : }
148 :
149 : /************************************************************************/
150 : /* Open() */
151 : /************************************************************************/
152 :
153 1214 : int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn)
154 :
155 : {
156 1214 : int ok = FALSE;
157 :
158 1214 : pszName = CPLStrdup( pszFilename );
159 1214 : bUpdate = bUpdateIn;
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Determine what sort of object this is. */
163 : /* -------------------------------------------------------------------- */
164 : VSIStatBufL sStatBuf;
165 :
166 1214 : if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0 )
167 342 : return FALSE;
168 :
169 : // --------------------------------------------------------------------
170 : // Does this appear to be a .bna file?
171 : // --------------------------------------------------------------------
172 872 : if( !(EQUAL( CPLGetExtension(pszFilename), "bna" )
173 : || ((EQUALN( pszFilename, "/vsigzip/", 9) || EQUALN( pszFilename, "/vsizip/", 8)) &&
174 : (strstr( pszFilename, ".bna") || strstr( pszFilename, ".BNA")))) )
175 856 : return FALSE;
176 :
177 16 : VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
178 16 : if (fp)
179 : {
180 : BNARecord* record;
181 16 : int curLine = 0;
182 16 : const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"};
183 16 : 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 16 : int nFeatures[4] = { 0, 0, 0, 0 };
201 16 : OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL };
202 16 : int nIDs[4] = {0, 0, 0, 0};
203 16 : int partialIndexTable = TRUE;
204 :
205 116 : while(1)
206 : {
207 132 : int offset = (int) VSIFTellL(fp);
208 132 : int line = curLine;
209 132 : record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE);
210 132 : if (ok == FALSE)
211 : {
212 0 : BNA_FreeRecord(record);
213 0 : if (line != 0)
214 0 : ok = TRUE;
215 0 : break;
216 : }
217 132 : if (record == NULL)
218 : {
219 : /* end of file */
220 16 : ok = TRUE;
221 :
222 : /* and we have finally build the whole index table */
223 16 : partialIndexTable = FALSE;
224 16 : break;
225 : }
226 :
227 116 : if (record->nIDs > nIDs[record->featureType])
228 58 : nIDs[record->featureType] = record->nIDs;
229 :
230 116 : nFeatures[record->featureType]++;
231 116 : offsetAndLineFeaturesTable[record->featureType] =
232 116 : (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType],
233 232 : nFeatures[record->featureType] * sizeof(OffsetAndLine));
234 116 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset;
235 116 : offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line;
236 :
237 116 : BNA_FreeRecord(record);
238 : }
239 :
240 16 : nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0);
241 16 : papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*));
242 16 : int iLayer = 0;
243 80 : for(i=0;i<4;i++)
244 : {
245 64 : if (nFeatures[i])
246 : {
247 58 : papoLayers[iLayer] = new OGRBNALayer( pszFilename,
248 : layerRadixName[i],
249 : (BNAFeatureType)i,
250 : wkbGeomTypes[i],
251 : FALSE,
252 : this,
253 116 : nIDs[i]);
254 58 : papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i],
255 : offsetAndLineFeaturesTable[i],
256 116 : partialIndexTable);
257 58 : iLayer++;
258 : }
259 : }
260 : #endif
261 16 : VSIFCloseL(fp);
262 : }
263 :
264 16 : return ok;
265 : }
266 :
267 :
268 : /************************************************************************/
269 : /* Create() */
270 : /************************************************************************/
271 :
272 6 : int OGRBNADataSource::Create( const char *pszFilename,
273 : char **papszOptions )
274 : {
275 6 : if( fpOutput != NULL)
276 : {
277 0 : CPLAssert( FALSE );
278 0 : return FALSE;
279 : }
280 :
281 6 : if( strcmp(pszFilename,"/dev/stdout") == 0 )
282 0 : pszFilename = "/vsistdout/";
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Do not override exiting file. */
286 : /* -------------------------------------------------------------------- */
287 : VSIStatBufL sStatBuf;
288 :
289 6 : if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
290 0 : return FALSE;
291 :
292 : /* -------------------------------------------------------------------- */
293 : /* Create the output file. */
294 : /* -------------------------------------------------------------------- */
295 6 : pszName = CPLStrdup( pszFilename );
296 :
297 6 : fpOutput = VSIFOpenL( pszFilename, "wb" );
298 6 : 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 6 : const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
308 :
309 6 : if( pszCRLFFormat == NULL )
310 : {
311 : #ifdef WIN32
312 : bUseCRLF = TRUE;
313 : #else
314 2 : bUseCRLF = FALSE;
315 : #endif
316 : }
317 4 : else if( EQUAL(pszCRLFFormat,"CRLF") )
318 2 : bUseCRLF = TRUE;
319 2 : else if( EQUAL(pszCRLFFormat,"LF") )
320 2 : 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 6 : bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE);
335 :
336 : /* Number of identifiers per record */
337 6 : const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS");
338 6 : if (pszNbOutID == NULL)
339 : {
340 6 : 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 6 : bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE);
367 :
368 : /* Number of coordinate pairs per line */
369 6 : const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE");
370 6 : 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 6 : nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1;
383 : }
384 :
385 : /* Coordinate precision */
386 6 : const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION");
387 6 : if (pszCoordinatePrecision)
388 : {
389 4 : coordinatePrecision = atoi(pszCoordinatePrecision);
390 4 : if (coordinatePrecision <= 0)
391 0 : coordinatePrecision = 0;
392 4 : else if (coordinatePrecision >= 20)
393 0 : coordinatePrecision = 20;
394 : }
395 : else
396 : {
397 2 : coordinatePrecision = 10;
398 : }
399 :
400 6 : pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR");
401 6 : if (pszCoordinateSeparator == NULL)
402 6 : pszCoordinateSeparator = CPLStrdup(",");
403 : else
404 0 : pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator);
405 :
406 6 : return TRUE;
407 : }
|