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