1 : /******************************************************************************
2 : * $Id: ogrcsvlayer.cpp 19643 2010-05-08 21:56:18Z rouault $
3 : *
4 : * Project: CSV Translator
5 : * Purpose: Implements OGRCSVLayer class.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
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_csv.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_csv.h"
34 : #include "ogr_p.h"
35 :
36 : CPL_CVSID("$Id: ogrcsvlayer.cpp 19643 2010-05-08 21:56:18Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRCSVLayer() */
40 : /* */
41 : /* Note that the OGRCSVLayer assumes ownership of the passed */
42 : /* file pointer. */
43 : /************************************************************************/
44 :
45 : OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
46 : FILE * fp, const char *pszFilename, int bNew, int bInWriteMode,
47 61 : char chDelimiter)
48 :
49 : {
50 61 : fpCSV = fp;
51 :
52 61 : iWktGeomReadField = -1;
53 61 : this->bInWriteMode = bInWriteMode;
54 61 : this->bNew = bNew;
55 61 : this->pszFilename = CPLStrdup(pszFilename);
56 61 : this->chDelimiter = chDelimiter;
57 :
58 61 : bFirstFeatureAppendedDuringSession = TRUE;
59 61 : bUseCRLF = FALSE;
60 61 : bNeedRewindBeforeRead = FALSE;
61 61 : eGeometryFormat = OGR_CSV_GEOM_NONE;
62 :
63 61 : nNextFID = 1;
64 :
65 61 : poFeatureDefn = new OGRFeatureDefn( pszLayerNameIn );
66 61 : poFeatureDefn->Reference();
67 61 : poFeatureDefn->SetGeomType( wkbNone );
68 :
69 61 : bCreateCSVT = FALSE;
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* If this is not a new file, read ahead to establish if it is */
73 : /* already in CRLF (DOS) mode, or just a normal unix CR mode. */
74 : /* -------------------------------------------------------------------- */
75 61 : if( !bNew )
76 : {
77 53 : int nBytesRead = 0;
78 : char chNewByte;
79 :
80 6726 : while( nBytesRead < 10000 && VSIFRead( &chNewByte, 1, 1, fpCSV ) == 1 )
81 : {
82 6632 : if( chNewByte == 13 )
83 : {
84 12 : bUseCRLF = TRUE;
85 12 : break;
86 : }
87 : }
88 53 : VSIRewind( fpCSV );
89 : }
90 :
91 : /* -------------------------------------------------------------------- */
92 : /* Check if the first record seems to be field definitions or */
93 : /* not. We assume it is field definitions if none of the */
94 : /* values are strictly numeric. */
95 : /* -------------------------------------------------------------------- */
96 61 : char **papszTokens = NULL;
97 61 : int nFieldCount=0, iField;
98 :
99 61 : if( !bNew )
100 : {
101 53 : papszTokens = CSVReadParseLine2( fpCSV, chDelimiter );
102 53 : nFieldCount = CSLCount( papszTokens );
103 53 : bHasFieldNames = TRUE;
104 : }
105 : else
106 8 : bHasFieldNames = FALSE;
107 :
108 282 : for( iField = 0; iField < nFieldCount && bHasFieldNames; iField++ )
109 : {
110 221 : const char *pszToken = papszTokens[iField];
111 221 : int bAllNumeric = TRUE;
112 :
113 221 : if (*pszToken != '\0')
114 : {
115 663 : while( *pszToken != '\0' && bAllNumeric )
116 : {
117 221 : if( *pszToken != '.' && *pszToken != '-'
118 : && (*pszToken < '0' || *pszToken > '9') )
119 221 : bAllNumeric = FALSE;
120 221 : pszToken++;
121 : }
122 :
123 221 : if( bAllNumeric )
124 0 : bHasFieldNames = FALSE;
125 : }
126 : }
127 :
128 61 : if( !bHasFieldNames )
129 8 : VSIRewind( fpCSV );
130 :
131 :
132 : /* -------------------------------------------------------------------- */
133 : /* Search a csvt file for types */
134 : /* -------------------------------------------------------------------- */
135 61 : char** papszFieldTypes = NULL;
136 61 : if (!bNew) {
137 53 : char* dname = strdup(CPLGetDirname(pszFilename));
138 53 : char* fname = strdup(CPLGetBasename(pszFilename));
139 53 : FILE* fpCSVT = fopen(CPLFormFilename(dname, fname, ".csvt"), "r");
140 53 : free(dname);
141 53 : free(fname);
142 53 : if (fpCSVT!=NULL) {
143 18 : VSIRewind(fpCSVT);
144 18 : papszFieldTypes = CSVReadParseLine(fpCSVT);
145 18 : fclose(fpCSVT);
146 : }
147 : }
148 :
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Build field definitions. */
152 : /* -------------------------------------------------------------------- */
153 282 : for( iField = 0; iField < nFieldCount; iField++ )
154 : {
155 221 : char *pszFieldName = NULL;
156 : char szFieldNameBuffer[100];
157 :
158 221 : if( bHasFieldNames )
159 : {
160 221 : pszFieldName = papszTokens[iField];
161 :
162 : // trim white space.
163 442 : while( *pszFieldName == ' ' )
164 0 : pszFieldName++;
165 :
166 442 : while( pszFieldName[0] != '\0'
167 : && pszFieldName[strlen(pszFieldName)-1] == ' ' )
168 0 : pszFieldName[strlen(pszFieldName)-1] = '\0';
169 :
170 221 : if (*pszFieldName == '\0')
171 0 : pszFieldName = NULL;
172 : }
173 :
174 221 : if (pszFieldName == NULL)
175 : {
176 0 : pszFieldName = szFieldNameBuffer;
177 0 : sprintf( szFieldNameBuffer, "field_%d", iField+1 );
178 : }
179 :
180 221 : OGRFieldDefn oField(pszFieldName, OFTString);
181 221 : if (papszFieldTypes!=NULL && iField<CSLCount(papszFieldTypes)) {
182 :
183 94 : char* pszLeftParenthesis = strchr(papszFieldTypes[iField], '(');
184 94 : if (pszLeftParenthesis && pszLeftParenthesis != papszFieldTypes[iField] &&
185 : pszLeftParenthesis[1] >= '0' && pszLeftParenthesis[1] <= '9')
186 : {
187 18 : int nWidth = 0;
188 18 : int nPrecision = 0;
189 :
190 18 : char* pszDot = strchr(pszLeftParenthesis, '.');
191 18 : if (pszDot) *pszDot = 0;
192 18 : *pszLeftParenthesis = 0;
193 :
194 18 : if (pszLeftParenthesis[-1] == ' ')
195 1 : pszLeftParenthesis[-1] = 0;
196 :
197 18 : nWidth = atoi(pszLeftParenthesis+1);
198 18 : if (pszDot)
199 6 : nPrecision = atoi(pszDot+1);
200 :
201 18 : oField.SetWidth(nWidth);
202 18 : oField.SetPrecision(nPrecision);
203 : }
204 :
205 94 : if (EQUAL(papszFieldTypes[iField], "Integer"))
206 12 : oField.SetType(OFTInteger);
207 82 : else if (EQUAL(papszFieldTypes[iField], "Real"))
208 37 : oField.SetType(OFTReal);
209 45 : else if (EQUAL(papszFieldTypes[iField], "String"))
210 26 : oField.SetType(OFTString);
211 19 : else if (EQUAL(papszFieldTypes[iField], "Date"))
212 6 : oField.SetType(OFTDate);
213 13 : else if (EQUAL(papszFieldTypes[iField], "Time"))
214 6 : oField.SetType(OFTTime);
215 7 : else if (EQUAL(papszFieldTypes[iField], "DateTime"))
216 7 : oField.SetType(OFTDateTime);
217 : else
218 0 : CPLError(CE_Warning, CPLE_NotSupported, "Unknown type : %s", papszFieldTypes[iField]);
219 : }
220 :
221 221 : poFeatureDefn->AddFieldDefn( &oField );
222 :
223 221 : if( EQUAL(oField.GetNameRef(),"WKT")
224 : && oField.GetType() == OFTString
225 : && iWktGeomReadField == -1 )
226 : {
227 19 : iWktGeomReadField = iField;
228 19 : poFeatureDefn->SetGeomType( wkbUnknown );
229 : }
230 : }
231 :
232 61 : CSLDestroy( papszTokens );
233 61 : CSLDestroy( papszFieldTypes );
234 61 : }
235 :
236 : /************************************************************************/
237 : /* ~OGRCSVLayer() */
238 : /************************************************************************/
239 :
240 61 : OGRCSVLayer::~OGRCSVLayer()
241 :
242 : {
243 61 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
244 : {
245 : CPLDebug( "CSV", "%d features read on layer '%s'.",
246 : (int) m_nFeaturesRead,
247 39 : poFeatureDefn->GetName() );
248 : }
249 :
250 61 : poFeatureDefn->Release();
251 61 : CPLFree(pszFilename);
252 :
253 61 : VSIFClose( fpCSV );
254 61 : }
255 :
256 : /************************************************************************/
257 : /* ResetReading() */
258 : /************************************************************************/
259 :
260 96 : void OGRCSVLayer::ResetReading()
261 :
262 : {
263 96 : VSIRewind( fpCSV );
264 :
265 96 : if( bHasFieldNames )
266 96 : CSLDestroy( CSVReadParseLine2( fpCSV, chDelimiter ) );
267 :
268 96 : bNeedRewindBeforeRead = FALSE;
269 :
270 96 : nNextFID = 1;
271 96 : }
272 :
273 : /************************************************************************/
274 : /* GetNextUnfilteredFeature() */
275 : /************************************************************************/
276 :
277 271 : OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
278 :
279 : {
280 : /* -------------------------------------------------------------------- */
281 : /* Read the CSV record. */
282 : /* -------------------------------------------------------------------- */
283 271 : char **papszTokens = CSVReadParseLine2( fpCSV, chDelimiter );
284 :
285 271 : if( papszTokens == NULL )
286 62 : return NULL;
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* Create the OGR feature. */
290 : /* -------------------------------------------------------------------- */
291 : OGRFeature *poFeature;
292 :
293 209 : poFeature = new OGRFeature( poFeatureDefn );
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Set attributes for any indicated attribute records. */
297 : /* -------------------------------------------------------------------- */
298 : int iAttr;
299 209 : int nAttrCount = MIN(CSLCount(papszTokens),
300 : poFeatureDefn->GetFieldCount() );
301 :
302 1117 : for( iAttr = 0; iAttr < nAttrCount; iAttr++)
303 : {
304 908 : if( iAttr == iWktGeomReadField && papszTokens[iAttr][0] != '\0' )
305 : {
306 24 : char *pszWKT = papszTokens[iAttr];
307 24 : OGRGeometry *poGeom = NULL;
308 :
309 24 : if( OGRGeometryFactory::createFromWkt( &pszWKT, NULL, &poGeom )
310 : == OGRERR_NONE )
311 24 : poFeature->SetGeometryDirectly( poGeom );
312 : }
313 :
314 908 : if (poFeatureDefn->GetFieldDefn(iAttr)->GetType() == OFTReal)
315 : {
316 119 : if (papszTokens[iAttr][0] != '\0')
317 87 : poFeature->SetField( iAttr, CPLAtof(papszTokens[iAttr]) );
318 : }
319 789 : else if (poFeatureDefn->GetFieldDefn(iAttr)->GetType() != OFTString)
320 : {
321 187 : if (papszTokens[iAttr][0] != '\0')
322 122 : poFeature->SetField( iAttr, papszTokens[iAttr] );
323 : }
324 : else
325 602 : poFeature->SetField( iAttr, papszTokens[iAttr] );
326 :
327 : }
328 :
329 209 : CSLDestroy( papszTokens );
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Translate the record id. */
333 : /* -------------------------------------------------------------------- */
334 209 : poFeature->SetFID( nNextFID++ );
335 :
336 209 : m_nFeaturesRead++;
337 :
338 209 : return poFeature;
339 : }
340 :
341 :
342 : /************************************************************************/
343 : /* GetNextFeature() */
344 : /************************************************************************/
345 :
346 237 : OGRFeature *OGRCSVLayer::GetNextFeature()
347 :
348 : {
349 237 : OGRFeature *poFeature = NULL;
350 :
351 237 : if( bNeedRewindBeforeRead )
352 3 : ResetReading();
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Read features till we find one that satisfies our current */
356 : /* spatial criteria. */
357 : /* -------------------------------------------------------------------- */
358 34 : while( TRUE )
359 : {
360 271 : poFeature = GetNextUnfilteredFeature();
361 271 : if( poFeature == NULL )
362 62 : break;
363 :
364 209 : if( (m_poFilterGeom == NULL
365 : || FilterGeometry( poFeature->GetGeometryRef() ) )
366 : && (m_poAttrQuery == NULL
367 : || m_poAttrQuery->Evaluate( poFeature )) )
368 175 : break;
369 :
370 34 : delete poFeature;
371 : }
372 :
373 237 : return poFeature;
374 : }
375 :
376 : /************************************************************************/
377 : /* TestCapability() */
378 : /************************************************************************/
379 :
380 5 : int OGRCSVLayer::TestCapability( const char * pszCap )
381 :
382 : {
383 5 : if( EQUAL(pszCap,OLCSequentialWrite) )
384 2 : return bInWriteMode;
385 3 : else if( EQUAL(pszCap,OLCCreateField) )
386 0 : return bNew && !bHasFieldNames;
387 : else
388 3 : return FALSE;
389 : }
390 :
391 : /************************************************************************/
392 : /* CreateField() */
393 : /************************************************************************/
394 :
395 19 : OGRErr OGRCSVLayer::CreateField( OGRFieldDefn *poNewField, int bApproxOK )
396 :
397 : {
398 : /* -------------------------------------------------------------------- */
399 : /* If we have already written our field names, then we are not */
400 : /* allowed to add new fields. */
401 : /* -------------------------------------------------------------------- */
402 19 : if( bHasFieldNames || !bNew )
403 : {
404 : CPLError( CE_Failure, CPLE_AppDefined,
405 0 : "Unable to create new fields after first feature written.");
406 0 : return OGRERR_FAILURE;
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Does this duplicate an existing field? */
411 : /* -------------------------------------------------------------------- */
412 19 : if( poFeatureDefn->GetFieldIndex( poNewField->GetNameRef() ) != -1 )
413 : {
414 : CPLError( CE_Failure, CPLE_AppDefined,
415 : "Attempt to create field %s, but a field with this name already exists.",
416 0 : poNewField->GetNameRef() );
417 :
418 0 : return OGRERR_FAILURE;
419 : }
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Is this a legal field type for CSV? For now we only allow */
423 : /* simple integer, real and string fields. */
424 : /* -------------------------------------------------------------------- */
425 19 : switch( poNewField->GetType() )
426 : {
427 : case OFTInteger:
428 : case OFTReal:
429 : case OFTString:
430 : // these types are OK.
431 16 : break;
432 :
433 : default:
434 3 : if( bApproxOK )
435 : {
436 : CPLError( CE_Warning, CPLE_AppDefined,
437 : "Attempt to create field of type %s, but this is not supported\n"
438 : "for .csv files. Just treating as a plain string.",
439 3 : poNewField->GetFieldTypeName( poNewField->GetType() ) );
440 : }
441 : else
442 : {
443 : CPLError( CE_Failure, CPLE_AppDefined,
444 : "Attempt to create field of type %s, but this is not supported\n"
445 : "for .csv files.",
446 0 : poNewField->GetFieldTypeName( poNewField->GetType() ) );
447 0 : return OGRERR_FAILURE;
448 : }
449 : }
450 :
451 : /* -------------------------------------------------------------------- */
452 : /* Seems ok, add to field list. */
453 : /* -------------------------------------------------------------------- */
454 19 : poFeatureDefn->AddFieldDefn( poNewField );
455 :
456 19 : return OGRERR_NONE;
457 : }
458 :
459 : /************************************************************************/
460 : /* CreateFeature() */
461 : /************************************************************************/
462 :
463 23 : OGRErr OGRCSVLayer::CreateFeature( OGRFeature *poNewFeature )
464 :
465 : {
466 : int iField;
467 :
468 23 : if( !bInWriteMode )
469 : {
470 : CPLError( CE_Failure, CPLE_AppDefined,
471 0 : "The CreateFeature() operation is not permitted on a read-only CSV." );
472 0 : return OGRERR_FAILURE;
473 : }
474 :
475 : /* If we need rewind, it means that we have just written a feature before */
476 : /* so there's no point seeking to the end of the file, as we're already */
477 : /* at the end */
478 23 : int bNeedSeekEnd = !bNeedRewindBeforeRead;
479 :
480 23 : bNeedRewindBeforeRead = TRUE;
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* Write field names if we haven't written them yet. */
484 : /* Write .csvt file if needed */
485 : /* -------------------------------------------------------------------- */
486 23 : if( !bHasFieldNames )
487 : {
488 8 : FILE* fpCSVT = NULL;
489 8 : if (bCreateCSVT)
490 : {
491 4 : char* pszDirName = CPLStrdup(CPLGetDirname(pszFilename));
492 4 : char* pszBaseName = CPLStrdup(CPLGetBasename(pszFilename));
493 4 : fpCSVT = fopen(CPLFormFilename(pszDirName, pszBaseName, ".csvt"), "wt");
494 4 : CPLFree(pszDirName);
495 4 : CPLFree(pszBaseName);
496 : }
497 :
498 8 : if (eGeometryFormat == OGR_CSV_GEOM_AS_WKT)
499 : {
500 1 : VSIFPrintf( fpCSV, "%s", "WKT");
501 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", "String");
502 1 : if (poFeatureDefn->GetFieldCount() > 0)
503 : {
504 1 : VSIFPrintf( fpCSV, "%c", chDelimiter );
505 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", ",");
506 : }
507 : }
508 7 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ)
509 : {
510 1 : VSIFPrintf( fpCSV, "X%cY%cZ", chDelimiter, chDelimiter);
511 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", "Real,Real,Real");
512 1 : if (poFeatureDefn->GetFieldCount() > 0)
513 : {
514 1 : VSIFPrintf( fpCSV, "%c", chDelimiter );
515 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", ",");
516 : }
517 : }
518 6 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XY)
519 : {
520 1 : VSIFPrintf( fpCSV, "X%cY", chDelimiter);
521 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", "Real,Real");
522 1 : if (poFeatureDefn->GetFieldCount() > 0)
523 : {
524 1 : VSIFPrintf( fpCSV, "%c", chDelimiter );
525 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", ",");
526 : }
527 : }
528 5 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_YX)
529 : {
530 1 : VSIFPrintf( fpCSV, "Y%cX", chDelimiter);
531 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", "Real,Real");
532 1 : if (poFeatureDefn->GetFieldCount() > 0)
533 : {
534 1 : VSIFPrintf( fpCSV, "%c", chDelimiter );
535 1 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", ",");
536 : }
537 : }
538 :
539 27 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
540 : {
541 : char *pszEscaped;
542 :
543 19 : if( iField > 0 )
544 : {
545 11 : VSIFPrintf( fpCSV, "%c", chDelimiter );
546 11 : if (fpCSVT) VSIFPrintf( fpCSVT, "%s", ",");
547 : }
548 :
549 : pszEscaped =
550 : CPLEscapeString( poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
551 19 : -1, CPLES_CSV );
552 :
553 19 : VSIFPrintf( fpCSV, "%s", pszEscaped );
554 19 : CPLFree( pszEscaped );
555 :
556 19 : if (fpCSVT)
557 : {
558 12 : switch( poFeatureDefn->GetFieldDefn(iField)->GetType() )
559 : {
560 2 : case OFTInteger: VSIFPrintf( fpCSVT, "%s", "Integer"); break;
561 2 : case OFTReal: VSIFPrintf( fpCSVT, "%s", "Real"); break;
562 1 : case OFTDate: VSIFPrintf( fpCSVT, "%s", "Date"); break;
563 1 : case OFTTime: VSIFPrintf( fpCSVT, "%s", "Time"); break;
564 1 : case OFTDateTime: VSIFPrintf( fpCSVT, "%s", "DateTime"); break;
565 5 : default: VSIFPrintf( fpCSVT, "%s", "String"); break;
566 : }
567 :
568 12 : int nWidth = poFeatureDefn->GetFieldDefn(iField)->GetWidth();
569 12 : int nPrecision = poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
570 12 : if (nWidth != 0)
571 : {
572 3 : if (nPrecision != 0)
573 1 : VSIFPrintf( fpCSVT, "(%d.%d)", nWidth, nPrecision);
574 : else
575 2 : VSIFPrintf( fpCSVT, "(%d)", nWidth);
576 : }
577 : }
578 : }
579 8 : if( bUseCRLF )
580 : {
581 1 : VSIFPutc( 13, fpCSV );
582 1 : if (fpCSVT) VSIFPutc( 13, fpCSVT );
583 : }
584 8 : VSIFPutc( '\n', fpCSV );
585 8 : if (fpCSVT) VSIFPutc( '\n', fpCSVT );
586 8 : if (fpCSVT) VSIFClose(fpCSVT);
587 :
588 8 : bHasFieldNames = TRUE;
589 8 : bNeedSeekEnd = FALSE;
590 : }
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Make sure we are at the end of the file. */
594 : /* -------------------------------------------------------------------- */
595 23 : if (bNeedSeekEnd)
596 : {
597 4 : if (bFirstFeatureAppendedDuringSession)
598 : {
599 : /* Add a newline character to the end of the file if necessary */
600 4 : bFirstFeatureAppendedDuringSession = FALSE;
601 4 : VSIFSeek( fpCSV, 0, SEEK_END );
602 4 : VSIFSeek( fpCSV, VSIFTell(fpCSV) - 1, SEEK_SET);
603 4 : char chLast = VSIFGetc( fpCSV );
604 4 : VSIFSeek( fpCSV, 0, SEEK_END );
605 4 : if (chLast != '\n')
606 : {
607 0 : if( bUseCRLF )
608 0 : VSIFPutc( 13, fpCSV );
609 0 : VSIFPutc( '\n', fpCSV );
610 : }
611 : }
612 : else
613 : {
614 0 : VSIFSeek( fpCSV, 0, SEEK_END );
615 : }
616 : }
617 :
618 : /* -------------------------------------------------------------------- */
619 : /* Write out the geometry */
620 : /* -------------------------------------------------------------------- */
621 23 : if (eGeometryFormat == OGR_CSV_GEOM_AS_WKT)
622 : {
623 1 : OGRGeometry *poGeom = poNewFeature->GetGeometryRef();
624 1 : char* pszWKT = NULL;
625 1 : if (poGeom && poGeom->exportToWkt(&pszWKT) == OGRERR_NONE)
626 : {
627 1 : VSIFPrintf( fpCSV, "\"%s\"", pszWKT);
628 : }
629 : else
630 : {
631 0 : VSIFPrintf( fpCSV, "\"\"");
632 : }
633 1 : CPLFree(pszWKT);
634 1 : if (poFeatureDefn->GetFieldCount() > 0)
635 1 : VSIFPrintf( fpCSV, "%c", chDelimiter);
636 : }
637 22 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ ||
638 : eGeometryFormat == OGR_CSV_GEOM_AS_XY ||
639 : eGeometryFormat == OGR_CSV_GEOM_AS_YX)
640 : {
641 4 : OGRGeometry *poGeom = poNewFeature->GetGeometryRef();
642 4 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
643 : {
644 3 : OGRPoint* poPoint = (OGRPoint*) poGeom;
645 : char szBuffer[75];
646 3 : if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ )
647 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3);
648 2 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XY )
649 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getX(), poPoint->getY(), 0, 2);
650 : else
651 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getY(), poPoint->getX(), 0, 2);
652 3 : char* pc = szBuffer;
653 17 : while(*pc != '\0')
654 : {
655 11 : if (*pc == ' ')
656 4 : *pc = chDelimiter;
657 11 : pc ++;
658 : }
659 3 : VSIFPrintf( fpCSV, "%s", szBuffer );
660 : }
661 : else
662 : {
663 1 : VSIFPrintf( fpCSV, "%c", chDelimiter );
664 1 : if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ)
665 0 : VSIFPrintf( fpCSV, "%c", chDelimiter );
666 : }
667 4 : if (poFeatureDefn->GetFieldCount() > 0)
668 4 : VSIFPrintf( fpCSV, "%c", chDelimiter );
669 : }
670 :
671 : /* -------------------------------------------------------------------- */
672 : /* Write out all the field values. */
673 : /* -------------------------------------------------------------------- */
674 82 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
675 : {
676 : char *pszEscaped;
677 :
678 59 : if( iField > 0 )
679 36 : fprintf( fpCSV, "%c", chDelimiter );
680 :
681 : pszEscaped =
682 : CPLEscapeString( poNewFeature->GetFieldAsString(iField),
683 59 : -1, CPLES_CSV );
684 :
685 59 : if (poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTReal)
686 : {
687 : /* Use point as decimal separator */
688 4 : char* pszComma = strchr(pszEscaped, ',');
689 4 : if (pszComma)
690 0 : *pszComma = '.';
691 : }
692 :
693 59 : VSIFWrite( pszEscaped, 1, strlen(pszEscaped), fpCSV );
694 59 : CPLFree( pszEscaped );
695 : }
696 :
697 23 : if( bUseCRLF )
698 5 : VSIFPutc( 13, fpCSV );
699 23 : VSIFPutc( '\n', fpCSV );
700 :
701 23 : return OGRERR_NONE;
702 : }
703 :
704 : /************************************************************************/
705 : /* SetCRLF() */
706 : /************************************************************************/
707 :
708 8 : void OGRCSVLayer::SetCRLF( int bNewValue )
709 :
710 : {
711 8 : bUseCRLF = bNewValue;
712 8 : }
713 :
714 : /************************************************************************/
715 : /* SetWriteGeometry() */
716 : /************************************************************************/
717 :
718 4 : void OGRCSVLayer::SetWriteGeometry(OGRCSVGeometryFormat eGeometryFormat)
719 : {
720 4 : this->eGeometryFormat = eGeometryFormat;
721 4 : }
722 :
723 : /************************************************************************/
724 : /* SetCreateCSVT() */
725 : /************************************************************************/
726 :
727 4 : void OGRCSVLayer::SetCreateCSVT(int bCreateCSVT)
728 : {
729 4 : this->bCreateCSVT = bCreateCSVT;
730 4 : }
|