1 : /******************************************************************************
2 : * $Id: ogrcsvlayer.cpp 25807 2013-03-26 18:56:05Z 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 25807 2013-03-26 18:56:05Z rouault $");
37 :
38 :
39 :
40 : /************************************************************************/
41 : /* CSVSplitLine() */
42 : /* */
43 : /* Tokenize a CSV line into fields in the form of a string */
44 : /* list. This is used instead of the CPLTokenizeString() */
45 : /* because it provides correct CSV escaping and quoting */
46 : /* semantics. */
47 : /************************************************************************/
48 :
49 11154 : static char **CSVSplitLine( const char *pszString, char chDelimiter )
50 :
51 : {
52 11154 : char **papszRetList = NULL;
53 : char *pszToken;
54 : int nTokenMax, nTokenLen;
55 :
56 11154 : pszToken = (char *) CPLCalloc(10,1);
57 11154 : nTokenMax = 10;
58 :
59 56234 : while( pszString != NULL && *pszString != '\0' )
60 : {
61 33926 : int bInString = FALSE;
62 :
63 33926 : nTokenLen = 0;
64 :
65 : /* Try to find the next delimeter, marking end of token */
66 346047 : for( ; *pszString != '\0'; pszString++ )
67 : {
68 :
69 : /* End if this is a delimeter skip it and break. */
70 335008 : if( !bInString && *pszString == chDelimiter )
71 : {
72 22887 : pszString++;
73 22887 : break;
74 : }
75 :
76 312121 : if( *pszString == '"' )
77 : {
78 1516 : if( !bInString || pszString[1] != '"' )
79 : {
80 1054 : bInString = !bInString;
81 1054 : continue;
82 : }
83 : else /* doubled quotes in string resolve to one quote */
84 : {
85 462 : pszString++;
86 : }
87 : }
88 :
89 311067 : if( nTokenLen >= nTokenMax-2 )
90 : {
91 11131 : nTokenMax = nTokenMax * 2 + 10;
92 11131 : pszToken = (char *) CPLRealloc( pszToken, nTokenMax );
93 : }
94 :
95 311067 : pszToken[nTokenLen] = *pszString;
96 311067 : nTokenLen++;
97 : }
98 :
99 33926 : pszToken[nTokenLen] = '\0';
100 33926 : papszRetList = CSLAddString( papszRetList, pszToken );
101 :
102 : /* If the last token is an empty token, then we have to catch
103 : * it now, otherwise we won't reenter the loop and it will be lost.
104 : */
105 33926 : if ( *pszString == '\0' && *(pszString-1) == chDelimiter )
106 : {
107 115 : papszRetList = CSLAddString( papszRetList, "" );
108 : }
109 : }
110 :
111 11154 : if( papszRetList == NULL )
112 0 : papszRetList = (char **) CPLCalloc(sizeof(char *),1);
113 :
114 11154 : CPLFree( pszToken );
115 :
116 11154 : return papszRetList;
117 : }
118 :
119 : /************************************************************************/
120 : /* OGRCSVReadParseLineL() */
121 : /* */
122 : /* Read one line, and return split into fields. The return */
123 : /* result is a stringlist, in the sense of the CSL functions. */
124 : /************************************************************************/
125 :
126 11280 : char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStrings )
127 :
128 : {
129 : const char *pszLine;
130 : char *pszWorkLine;
131 : char **papszReturn;
132 :
133 11280 : pszLine = CPLReadLineL( fp );
134 11280 : if( pszLine == NULL )
135 126 : return( NULL );
136 :
137 : /* Skip BOM */
138 11154 : GByte* pabyData = (GByte*) pszLine;
139 11154 : if (pabyData[0] == 0xEF && pabyData[1] == 0xBB && pabyData[2] == 0xBF)
140 6 : pszLine += 3;
141 :
142 : /* Special fix to read NdfcFacilities.xls that has non-balanced double quotes */
143 11154 : if (chDelimiter == '\t' && bDontHonourStrings)
144 : {
145 0 : return CSLTokenizeStringComplex(pszLine, "\t", FALSE, TRUE);
146 : }
147 :
148 : /* -------------------------------------------------------------------- */
149 : /* If there are no quotes, then this is the simple case. */
150 : /* Parse, and return tokens. */
151 : /* -------------------------------------------------------------------- */
152 11154 : if( strchr(pszLine,'\"') == NULL )
153 10917 : return CSVSplitLine( pszLine, chDelimiter );
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* We must now count the quotes in our working string, and as */
157 : /* long as it is odd, keep adding new lines. */
158 : /* -------------------------------------------------------------------- */
159 237 : pszWorkLine = CPLStrdup( pszLine );
160 :
161 237 : int i = 0, nCount = 0;
162 237 : int nWorkLineLength = strlen(pszWorkLine);
163 :
164 748 : while( TRUE )
165 : {
166 55818 : for( ; pszWorkLine[i] != '\0'; i++ )
167 : {
168 56736 : if( pszWorkLine[i] == '\"'
169 1903 : && (i == 0 || pszWorkLine[i-1] != '\\') )
170 1978 : nCount++;
171 : }
172 :
173 985 : if( nCount % 2 == 0 )
174 237 : break;
175 :
176 748 : pszLine = CPLReadLineL( fp );
177 748 : if( pszLine == NULL )
178 0 : break;
179 :
180 748 : int nLineLen = strlen(pszLine);
181 :
182 : char* pszWorkLineTmp = (char *)
183 : VSIRealloc(pszWorkLine,
184 748 : nWorkLineLength + nLineLen + 2);
185 748 : if (pszWorkLineTmp == NULL)
186 0 : break;
187 748 : pszWorkLine = pszWorkLineTmp;
188 748 : strcat( pszWorkLine + nWorkLineLength, "\n" ); // This gets lost in CPLReadLine().
189 748 : strcat( pszWorkLine + nWorkLineLength, pszLine );
190 :
191 748 : nWorkLineLength += nLineLen + 1;
192 : }
193 :
194 237 : papszReturn = CSVSplitLine( pszWorkLine, chDelimiter );
195 :
196 237 : CPLFree( pszWorkLine );
197 :
198 237 : return papszReturn;
199 : }
200 :
201 : /************************************************************************/
202 : /* OGRCSVLayer() */
203 : /* */
204 : /* Note that the OGRCSVLayer assumes ownership of the passed */
205 : /* file pointer. */
206 : /************************************************************************/
207 :
208 222 : OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
209 : VSILFILE * fp, const char *pszFilename, int bNew, int bInWriteMode,
210 : char chDelimiter, const char* pszNfdcGeomField,
211 222 : const char* pszGeonamesGeomFieldPrefix)
212 :
213 : {
214 222 : fpCSV = fp;
215 :
216 222 : iWktGeomReadField = -1;
217 222 : iNfdcLatitudeS = iNfdcLongitudeS = -1;
218 222 : iLatitudeField = iLongitudeField = -1;
219 222 : this->bInWriteMode = bInWriteMode;
220 222 : this->bNew = bNew;
221 222 : this->pszFilename = CPLStrdup(pszFilename);
222 222 : this->chDelimiter = chDelimiter;
223 :
224 222 : bFirstFeatureAppendedDuringSession = TRUE;
225 222 : bUseCRLF = FALSE;
226 222 : bNeedRewindBeforeRead = FALSE;
227 222 : eGeometryFormat = OGR_CSV_GEOM_NONE;
228 :
229 222 : nNextFID = 1;
230 :
231 222 : poFeatureDefn = new OGRFeatureDefn( pszLayerNameIn );
232 222 : poFeatureDefn->Reference();
233 222 : poFeatureDefn->SetGeomType( wkbNone );
234 :
235 222 : bCreateCSVT = FALSE;
236 222 : bDontHonourStrings = FALSE;
237 222 : bWriteBOM = FALSE;
238 :
239 222 : bIsEurostatTSV = FALSE;
240 222 : nEurostatDims = 0;
241 :
242 222 : nTotalFeatures = -1;
243 :
244 : /* -------------------------------------------------------------------- */
245 : /* If this is not a new file, read ahead to establish if it is */
246 : /* already in CRLF (DOS) mode, or just a normal unix CR mode. */
247 : /* -------------------------------------------------------------------- */
248 222 : if( !bNew && bInWriteMode )
249 : {
250 96 : int nBytesRead = 0;
251 : char chNewByte;
252 :
253 52548 : while( nBytesRead < 10000 && VSIFReadL( &chNewByte, 1, 1, fpCSV ) == 1 )
254 : {
255 52365 : if( chNewByte == 13 )
256 : {
257 9 : bUseCRLF = TRUE;
258 9 : break;
259 : }
260 52356 : nBytesRead ++;
261 : }
262 96 : VSIRewindL( fpCSV );
263 : }
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Check if the first record seems to be field definitions or */
267 : /* not. We assume it is field definitions if none of the */
268 : /* values are strictly numeric. */
269 : /* -------------------------------------------------------------------- */
270 222 : char **papszTokens = NULL;
271 222 : int nFieldCount=0, iField;
272 : CPLValueType eType;
273 :
274 222 : if( !bNew )
275 : {
276 196 : const char *pszLine = NULL;
277 : char szDelimiter[2];
278 196 : szDelimiter[0] = chDelimiter; szDelimiter[1] = '\0';
279 :
280 196 : pszLine = CPLReadLineL( fpCSV );
281 196 : if ( pszLine != NULL )
282 : {
283 : /* Detect and remove UTF-8 BOM marker if found (#4623) */
284 208 : if (pszLine[0] == (char)0xEF &&
285 6 : pszLine[1] == (char)0xBB &&
286 6 : pszLine[2] == (char)0xBF)
287 : {
288 6 : pszLine += 3;
289 : }
290 :
291 : /* tokenize the strings and preserve quotes, so we can separate string from numeric */
292 : /* this is only used in the test for bHasFeldNames (bug #4361) */
293 : papszTokens = CSLTokenizeString2( pszLine, szDelimiter,
294 : (CSLT_HONOURSTRINGS |
295 : CSLT_ALLOWEMPTYTOKENS |
296 196 : CSLT_PRESERVEQUOTES) );
297 196 : nFieldCount = CSLCount( papszTokens );
298 196 : bHasFieldNames = TRUE;
299 :
300 818 : for( iField = 0; iField < nFieldCount && bHasFieldNames; iField++ )
301 : {
302 622 : eType = CPLGetValueType(papszTokens[iField]);
303 622 : if ( (eType == CPL_VALUE_INTEGER ||
304 : eType == CPL_VALUE_REAL) ) {
305 : /* we have a numeric field, therefore do not consider the first line as field names */
306 29 : bHasFieldNames = FALSE;
307 : }
308 : }
309 :
310 196 : CPLString osExt = OGRCSVDataSource::GetRealExtension(pszFilename);
311 :
312 : /* Eurostat .tsv files */
313 196 : if( EQUAL(osExt, "tsv") && nFieldCount > 1 &&
314 : strchr(papszTokens[0], ',') != NULL && strchr(papszTokens[0], '\\') != NULL )
315 : {
316 1 : bHasFieldNames = TRUE;
317 1 : bIsEurostatTSV = TRUE;
318 : }
319 :
320 : /* tokenize without quotes to get the actual values */
321 196 : CSLDestroy( papszTokens );
322 : // papszTokens = OGRCSVReadParseLineL( fpCSV, chDelimiter, FALSE );
323 : papszTokens = CSLTokenizeString2( pszLine, szDelimiter,
324 : (CSLT_HONOURSTRINGS |
325 196 : CSLT_ALLOWEMPTYTOKENS));
326 196 : nFieldCount = CSLCount( papszTokens );
327 : }
328 : }
329 : else
330 26 : bHasFieldNames = FALSE;
331 :
332 222 : if( !bNew && !bHasFieldNames )
333 28 : VSIRewindL( fpCSV );
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Check for geonames.org tables */
337 : /* -------------------------------------------------------------------- */
338 222 : if( !bHasFieldNames && nFieldCount == 19 )
339 : {
340 0 : if (CPLGetValueType(papszTokens[0]) == CPL_VALUE_INTEGER &&
341 0 : CPLGetValueType(papszTokens[4]) == CPL_VALUE_REAL &&
342 0 : CPLGetValueType(papszTokens[5]) == CPL_VALUE_REAL &&
343 0 : CPLAtof(papszTokens[4]) >= -90 && CPLAtof(papszTokens[4]) <= 90 &&
344 0 : CPLAtof(papszTokens[5]) >= -180 && CPLAtof(papszTokens[4]) <= 180)
345 : {
346 0 : bHasFieldNames = TRUE;
347 0 : CSLDestroy(papszTokens);
348 0 : papszTokens = NULL;
349 :
350 : static const struct {
351 : const char* pszName;
352 : OGRFieldType eType;
353 : }
354 : asGeonamesFieldDesc[] =
355 : {
356 : { "GEONAMEID", OFTString },
357 : { "NAME", OFTString },
358 : { "ASCIINAME", OFTString },
359 : { "ALTNAMES", OFTString },
360 : { "LATITUDE", OFTReal },
361 : { "LONGITUDE", OFTReal },
362 : { "FEATCLASS", OFTString },
363 : { "FEATCODE", OFTString },
364 : { "COUNTRY", OFTString },
365 : { "CC2", OFTString },
366 : { "ADMIN1", OFTString },
367 : { "ADMIN2", OFTString },
368 : { "ADMIN3", OFTString },
369 : { "ADMIN4", OFTString },
370 : { "POPULATION", OFTReal },
371 : { "ELEVATION", OFTInteger },
372 : { "GTOPO30", OFTInteger },
373 : { "TIMEZONE", OFTString },
374 : { "MODDATE", OFTString }
375 : };
376 0 : for(iField = 0; iField < nFieldCount; iField++)
377 : {
378 : OGRFieldDefn oFieldDefn(asGeonamesFieldDesc[iField].pszName,
379 0 : asGeonamesFieldDesc[iField].eType);
380 0 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
381 : }
382 :
383 0 : iLatitudeField = 4;
384 0 : iLongitudeField = 5;
385 :
386 0 : nFieldCount = 0;
387 : }
388 : }
389 :
390 :
391 : /* -------------------------------------------------------------------- */
392 : /* Search a csvt file for types */
393 : /* -------------------------------------------------------------------- */
394 222 : char** papszFieldTypes = NULL;
395 222 : if (!bNew) {
396 196 : char* dname = strdup(CPLGetDirname(pszFilename));
397 196 : char* fname = strdup(CPLGetBasename(pszFilename));
398 196 : VSILFILE* fpCSVT = VSIFOpenL(CPLFormFilename(dname, fname, ".csvt"), "r");
399 196 : free(dname);
400 196 : free(fname);
401 196 : if (fpCSVT!=NULL) {
402 36 : VSIRewindL(fpCSVT);
403 36 : papszFieldTypes = OGRCSVReadParseLineL(fpCSVT, ',', FALSE);
404 36 : VSIFCloseL(fpCSVT);
405 : }
406 : }
407 :
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Build field definitions. */
411 : /* -------------------------------------------------------------------- */
412 894 : for( iField = 0; !bIsEurostatTSV && iField < nFieldCount; iField++ )
413 : {
414 674 : char *pszFieldName = NULL;
415 : char szFieldNameBuffer[100];
416 :
417 674 : if( bHasFieldNames )
418 : {
419 591 : pszFieldName = papszTokens[iField];
420 :
421 : // trim white space.
422 1182 : while( *pszFieldName == ' ' )
423 0 : pszFieldName++;
424 :
425 1743 : while( pszFieldName[0] != '\0'
426 561 : && pszFieldName[strlen(pszFieldName)-1] == ' ' )
427 0 : pszFieldName[strlen(pszFieldName)-1] = '\0';
428 :
429 591 : if (*pszFieldName == '\0')
430 30 : pszFieldName = NULL;
431 : }
432 :
433 674 : if (pszFieldName == NULL)
434 : {
435 : /* Re-read single column CSV files that have a trailing comma */
436 : /* in the header line */
437 113 : if( iField == 1 && nFieldCount == 2 && papszTokens[1][0] == '\0' )
438 : {
439 2 : nFieldCount = 1;
440 2 : break;
441 : }
442 111 : pszFieldName = szFieldNameBuffer;
443 111 : sprintf( szFieldNameBuffer, "field_%d", iField+1 );
444 : }
445 :
446 672 : OGRFieldDefn oField(pszFieldName, OFTString);
447 672 : if (papszFieldTypes!=NULL && iField<CSLCount(papszFieldTypes)) {
448 :
449 178 : char* pszLeftParenthesis = strchr(papszFieldTypes[iField], '(');
450 242 : if (pszLeftParenthesis && pszLeftParenthesis != papszFieldTypes[iField] &&
451 64 : pszLeftParenthesis[1] >= '0' && pszLeftParenthesis[1] <= '9')
452 : {
453 32 : int nWidth = 0;
454 32 : int nPrecision = 0;
455 :
456 32 : char* pszDot = strchr(pszLeftParenthesis, '.');
457 32 : if (pszDot) *pszDot = 0;
458 32 : *pszLeftParenthesis = 0;
459 :
460 32 : if (pszLeftParenthesis[-1] == ' ')
461 2 : pszLeftParenthesis[-1] = 0;
462 :
463 32 : nWidth = atoi(pszLeftParenthesis+1);
464 32 : if (pszDot)
465 11 : nPrecision = atoi(pszDot+1);
466 :
467 32 : oField.SetWidth(nWidth);
468 32 : oField.SetPrecision(nPrecision);
469 : }
470 :
471 178 : if (EQUAL(papszFieldTypes[iField], "Integer"))
472 23 : oField.SetType(OFTInteger);
473 155 : else if (EQUAL(papszFieldTypes[iField], "Real"))
474 75 : oField.SetType(OFTReal);
475 80 : else if (EQUAL(papszFieldTypes[iField], "String"))
476 49 : oField.SetType(OFTString);
477 31 : else if (EQUAL(papszFieldTypes[iField], "Date"))
478 10 : oField.SetType(OFTDate);
479 21 : else if (EQUAL(papszFieldTypes[iField], "Time"))
480 10 : oField.SetType(OFTTime);
481 11 : else if (EQUAL(papszFieldTypes[iField], "DateTime"))
482 11 : oField.SetType(OFTDateTime);
483 : else
484 0 : CPLError(CE_Warning, CPLE_NotSupported, "Unknown type : %s", papszFieldTypes[iField]);
485 : }
486 :
487 672 : if( EQUAL(oField.GetNameRef(),"WKT")
488 : && oField.GetType() == OFTString
489 : && iWktGeomReadField == -1 )
490 : {
491 34 : iWktGeomReadField = iField;
492 34 : poFeatureDefn->SetGeomType( wkbUnknown );
493 : }
494 :
495 : /*http://www.faa.gov/airports/airport_safety/airportdata_5010/menu/index.cfm specific */
496 672 : if ( pszNfdcGeomField != NULL &&
497 : EQUALN(oField.GetNameRef(), pszNfdcGeomField, strlen(pszNfdcGeomField)) &&
498 : EQUAL(oField.GetNameRef() + strlen(pszNfdcGeomField), "LatitudeS") )
499 0 : iNfdcLatitudeS = iField;
500 672 : else if ( pszNfdcGeomField != NULL &&
501 : EQUALN(oField.GetNameRef(), pszNfdcGeomField, strlen(pszNfdcGeomField)) &&
502 : EQUAL(oField.GetNameRef() + strlen(pszNfdcGeomField), "LongitudeS") )
503 0 : iNfdcLongitudeS = iField;
504 :
505 : /* GNIS specific */
506 672 : else if ( pszGeonamesGeomFieldPrefix != NULL &&
507 : EQUALN(oField.GetNameRef(), pszGeonamesGeomFieldPrefix, strlen(pszGeonamesGeomFieldPrefix)) &&
508 : (EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LAT_DEC") ||
509 : EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LATITUDE_DEC") ||
510 : EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LATITUDE")) )
511 : {
512 0 : oField.SetType(OFTReal);
513 0 : iLatitudeField = iField;
514 : }
515 672 : else if ( pszGeonamesGeomFieldPrefix != NULL &&
516 : EQUALN(oField.GetNameRef(), pszGeonamesGeomFieldPrefix, strlen(pszGeonamesGeomFieldPrefix)) &&
517 : (EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LONG_DEC") ||
518 : EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LONGITUDE_DEC") ||
519 : EQUAL(oField.GetNameRef() + strlen(pszGeonamesGeomFieldPrefix), "_LONGITUDE")) )
520 : {
521 0 : oField.SetType(OFTReal);
522 0 : iLongitudeField = iField;
523 : }
524 :
525 672 : poFeatureDefn->AddFieldDefn( &oField );
526 :
527 : }
528 :
529 222 : if ( iNfdcLatitudeS != -1 && iNfdcLongitudeS != -1 )
530 : {
531 0 : bDontHonourStrings = TRUE;
532 0 : poFeatureDefn->SetGeomType( wkbPoint );
533 : }
534 222 : else if ( iLatitudeField != -1 && iLongitudeField != -1 )
535 : {
536 0 : poFeatureDefn->SetGeomType( wkbPoint );
537 : }
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Build field definitions for Eurostat TSV files. */
541 : /* -------------------------------------------------------------------- */
542 :
543 222 : CPLString osSeqDim;
544 226 : for( iField = 0; bIsEurostatTSV && iField < nFieldCount; iField++ )
545 : {
546 4 : if( iField == 0 )
547 : {
548 1 : char** papszDims = CSLTokenizeString2( papszTokens[0], ",\\", 0 );
549 1 : nEurostatDims = CSLCount(papszDims) - 1;
550 3 : for(int iSubField = 0; iSubField < nEurostatDims; iSubField++)
551 : {
552 2 : OGRFieldDefn oField(papszDims[iSubField], OFTString);
553 2 : poFeatureDefn->AddFieldDefn( &oField );
554 : }
555 :
556 1 : osSeqDim = papszDims[nEurostatDims];
557 1 : CSLDestroy(papszDims);
558 : }
559 : else
560 : {
561 12 : if( papszTokens[iField][0] != '\0'
562 9 : && papszTokens[iField][strlen(papszTokens[iField])-1] == ' ' )
563 3 : papszTokens[iField][strlen(papszTokens[iField])-1] = '\0';
564 :
565 3 : OGRFieldDefn oField(CPLSPrintf("%s_%s", osSeqDim.c_str(), papszTokens[iField]), OFTReal);
566 3 : poFeatureDefn->AddFieldDefn( &oField );
567 :
568 3 : OGRFieldDefn oField2(CPLSPrintf("%s_%s_flag", osSeqDim.c_str(), papszTokens[iField]), OFTString);
569 3 : poFeatureDefn->AddFieldDefn( &oField2 );
570 : }
571 : }
572 :
573 : /* -------------------------------------------------------------------- */
574 : /* Cleanup. */
575 : /* -------------------------------------------------------------------- */
576 :
577 222 : CSLDestroy( papszTokens );
578 222 : CSLDestroy( papszFieldTypes );
579 222 : }
580 :
581 : /************************************************************************/
582 : /* ~OGRCSVLayer() */
583 : /************************************************************************/
584 :
585 222 : OGRCSVLayer::~OGRCSVLayer()
586 :
587 : {
588 222 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
589 : {
590 : CPLDebug( "CSV", "%d features read on layer '%s'.",
591 : (int) m_nFeaturesRead,
592 136 : poFeatureDefn->GetName() );
593 : }
594 :
595 : // Make sure the header file is written even if no features are written.
596 222 : if (bInWriteMode)
597 122 : WriteHeader();
598 :
599 222 : poFeatureDefn->Release();
600 222 : CPLFree(pszFilename);
601 :
602 222 : if (fpCSV)
603 222 : VSIFCloseL( fpCSV );
604 222 : }
605 :
606 : /************************************************************************/
607 : /* ResetReading() */
608 : /************************************************************************/
609 :
610 223 : void OGRCSVLayer::ResetReading()
611 :
612 : {
613 223 : if (fpCSV)
614 223 : VSIRewindL( fpCSV );
615 :
616 223 : if( bHasFieldNames )
617 195 : CSLDestroy( OGRCSVReadParseLineL( fpCSV, chDelimiter, bDontHonourStrings ) );
618 :
619 223 : bNeedRewindBeforeRead = FALSE;
620 :
621 223 : nNextFID = 1;
622 223 : }
623 :
624 : /************************************************************************/
625 : /* GetNextUnfilteredFeature() */
626 : /************************************************************************/
627 :
628 10845 : OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
629 :
630 : {
631 10845 : if (fpCSV == NULL)
632 0 : return NULL;
633 :
634 : /* -------------------------------------------------------------------- */
635 : /* Read the CSV record. */
636 : /* -------------------------------------------------------------------- */
637 : char **papszTokens;
638 :
639 0 : while(TRUE)
640 : {
641 10845 : papszTokens = OGRCSVReadParseLineL( fpCSV, chDelimiter, bDontHonourStrings );
642 10845 : if( papszTokens == NULL )
643 124 : return NULL;
644 :
645 10721 : if( papszTokens[0] != NULL )
646 : break;
647 :
648 0 : CSLDestroy(papszTokens);
649 : }
650 :
651 : /* -------------------------------------------------------------------- */
652 : /* Create the OGR feature. */
653 : /* -------------------------------------------------------------------- */
654 : OGRFeature *poFeature;
655 :
656 21442 : poFeature = new OGRFeature( poFeatureDefn );
657 :
658 : /* -------------------------------------------------------------------- */
659 : /* Set attributes for any indicated attribute records. */
660 : /* -------------------------------------------------------------------- */
661 : int iAttr;
662 10735 : int nAttrCount = MIN(CSLCount(papszTokens),
663 : poFeatureDefn->GetFieldCount() );
664 : CPLValueType eType;
665 :
666 43158 : for( iAttr = 0; !bIsEurostatTSV && iAttr < nAttrCount; iAttr++)
667 : {
668 32437 : if( iAttr == iWktGeomReadField && papszTokens[iAttr][0] != '\0' )
669 : {
670 41 : char *pszWKT = papszTokens[iAttr];
671 41 : OGRGeometry *poGeom = NULL;
672 :
673 41 : if( OGRGeometryFactory::createFromWkt( &pszWKT, NULL, &poGeom )
674 : == OGRERR_NONE )
675 41 : poFeature->SetGeometryDirectly( poGeom );
676 : }
677 :
678 32437 : OGRFieldType eFieldType = poFeatureDefn->GetFieldDefn(iAttr)->GetType();
679 32671 : if ( eFieldType == OFTReal || eFieldType == OFTInteger )
680 : {
681 234 : if (chDelimiter == ';' && eFieldType == OFTReal)
682 : {
683 0 : char* chComma = strchr(papszTokens[iAttr], ',');
684 0 : if (chComma)
685 0 : *chComma = '.';
686 : }
687 234 : eType = CPLGetValueType(papszTokens[iAttr]);
688 234 : if ( (papszTokens[iAttr][0] != '\0') &&
689 : ( eType == CPL_VALUE_INTEGER ||
690 : eType == CPL_VALUE_REAL ) )
691 : {
692 166 : poFeature->SetField( iAttr, papszTokens[iAttr] );
693 : }
694 : }
695 32203 : else if (eFieldType != OFTString)
696 : {
697 96 : if (papszTokens[iAttr][0] != '\0')
698 57 : poFeature->SetField( iAttr, papszTokens[iAttr] );
699 : }
700 : else
701 32107 : poFeature->SetField( iAttr, papszTokens[iAttr] );
702 :
703 : }
704 :
705 : /* -------------------------------------------------------------------- */
706 : /* Eurostat TSV files. */
707 : /* -------------------------------------------------------------------- */
708 :
709 10725 : for( iAttr = 0; bIsEurostatTSV && iAttr < nAttrCount; iAttr++)
710 : {
711 4 : if( iAttr == 0 )
712 : {
713 1 : char** papszDims = CSLTokenizeString2( papszTokens[0], ",", 0 );
714 1 : if( CSLCount(papszDims) != nEurostatDims )
715 : {
716 0 : CSLDestroy(papszDims);
717 0 : break;
718 : }
719 3 : for( int iSubAttr = 0; iSubAttr < nEurostatDims; iSubAttr ++ )
720 : {
721 2 : poFeature->SetField( iSubAttr, papszDims[iSubAttr] );
722 : }
723 1 : CSLDestroy(papszDims);
724 : }
725 : else
726 : {
727 3 : char** papszVals = CSLTokenizeString2( papszTokens[iAttr], " ", 0 );
728 3 : eType = CPLGetValueType(papszVals[0]);
729 3 : if ( (papszVals[0][0] != '\0') &&
730 : ( eType == CPL_VALUE_INTEGER ||
731 : eType == CPL_VALUE_REAL ) )
732 : {
733 2 : poFeature->SetField( nEurostatDims + 2 * (iAttr - 1), papszVals[0] );
734 : }
735 3 : if( CSLCount(papszVals) == 2 )
736 : {
737 1 : poFeature->SetField( nEurostatDims + 2 * (iAttr - 1) + 1, papszVals[1] );
738 : }
739 3 : CSLDestroy(papszVals);
740 : }
741 : }
742 :
743 : /* -------------------------------------------------------------------- */
744 : /*http://www.faa.gov/airports/airport_safety/airportdata_5010/menu/index.cfm specific */
745 : /* -------------------------------------------------------------------- */
746 :
747 10721 : if ( iNfdcLatitudeS != -1 &&
748 : iNfdcLongitudeS != -1 &&
749 : nAttrCount > iNfdcLatitudeS &&
750 : nAttrCount > iNfdcLongitudeS &&
751 0 : papszTokens[iNfdcLongitudeS][0] != 0 &&
752 0 : papszTokens[iNfdcLatitudeS][0] != 0)
753 : {
754 0 : double dfLon = atof(papszTokens[iNfdcLongitudeS]) / 3600;
755 0 : if (strchr(papszTokens[iNfdcLongitudeS], 'W'))
756 0 : dfLon *= -1;
757 0 : double dfLat = atof(papszTokens[iNfdcLatitudeS]) / 3600;
758 0 : if (strchr(papszTokens[iNfdcLatitudeS], 'S'))
759 0 : dfLat *= -1;
760 0 : poFeature->SetGeometryDirectly( new OGRPoint(dfLon, dfLat) );
761 : }
762 :
763 : /* -------------------------------------------------------------------- */
764 : /* GNIS specific */
765 : /* -------------------------------------------------------------------- */
766 10721 : else if ( iLatitudeField != -1 &&
767 : iLongitudeField != -1 &&
768 : nAttrCount > iLatitudeField &&
769 : nAttrCount > iLongitudeField &&
770 0 : papszTokens[iLongitudeField][0] != 0 &&
771 0 : papszTokens[iLatitudeField][0] != 0)
772 : {
773 : /* Some records have dummy 0,0 value */
774 0 : if (papszTokens[iLongitudeField][0] != '0' ||
775 0 : papszTokens[iLongitudeField][1] != '\0' ||
776 0 : papszTokens[iLatitudeField][0] != '0' ||
777 0 : papszTokens[iLatitudeField][1] != '\0')
778 : {
779 0 : double dfLon = atof(papszTokens[iLongitudeField]);
780 0 : double dfLat = atof(papszTokens[iLatitudeField]);
781 0 : poFeature->SetGeometryDirectly( new OGRPoint(dfLon, dfLat) );
782 : }
783 : }
784 :
785 10721 : CSLDestroy( papszTokens );
786 :
787 : /* -------------------------------------------------------------------- */
788 : /* Translate the record id. */
789 : /* -------------------------------------------------------------------- */
790 10721 : poFeature->SetFID( nNextFID++ );
791 :
792 10721 : m_nFeaturesRead++;
793 :
794 10721 : return poFeature;
795 : }
796 :
797 :
798 : /************************************************************************/
799 : /* GetNextFeature() */
800 : /************************************************************************/
801 :
802 10792 : OGRFeature *OGRCSVLayer::GetNextFeature()
803 :
804 : {
805 10792 : OGRFeature *poFeature = NULL;
806 :
807 10792 : if( bNeedRewindBeforeRead )
808 3 : ResetReading();
809 :
810 : /* -------------------------------------------------------------------- */
811 : /* Read features till we find one that satisfies our current */
812 : /* spatial criteria. */
813 : /* -------------------------------------------------------------------- */
814 53 : while( TRUE )
815 : {
816 10845 : poFeature = GetNextUnfilteredFeature();
817 10845 : if( poFeature == NULL )
818 124 : break;
819 :
820 10721 : if( (m_poFilterGeom == NULL
821 : || FilterGeometry( poFeature->GetGeometryRef() ) )
822 : && (m_poAttrQuery == NULL
823 : || m_poAttrQuery->Evaluate( poFeature )) )
824 10668 : break;
825 :
826 53 : delete poFeature;
827 : }
828 :
829 10792 : return poFeature;
830 : }
831 :
832 : /************************************************************************/
833 : /* TestCapability() */
834 : /************************************************************************/
835 :
836 50 : int OGRCSVLayer::TestCapability( const char * pszCap )
837 :
838 : {
839 50 : if( EQUAL(pszCap,OLCSequentialWrite) )
840 2 : return bInWriteMode;
841 48 : else if( EQUAL(pszCap,OLCCreateField) )
842 0 : return bNew && !bHasFieldNames;
843 : else
844 48 : return FALSE;
845 : }
846 :
847 : /************************************************************************/
848 : /* CreateField() */
849 : /************************************************************************/
850 :
851 83 : OGRErr OGRCSVLayer::CreateField( OGRFieldDefn *poNewField, int bApproxOK )
852 :
853 : {
854 : /* -------------------------------------------------------------------- */
855 : /* If we have already written our field names, then we are not */
856 : /* allowed to add new fields. */
857 : /* -------------------------------------------------------------------- */
858 83 : if( bHasFieldNames || !bNew )
859 : {
860 : CPLError( CE_Failure, CPLE_AppDefined,
861 0 : "Unable to create new fields after first feature written.");
862 0 : return OGRERR_FAILURE;
863 : }
864 :
865 : /* -------------------------------------------------------------------- */
866 : /* Does this duplicate an existing field? */
867 : /* -------------------------------------------------------------------- */
868 83 : if( poFeatureDefn->GetFieldIndex( poNewField->GetNameRef() ) != -1 )
869 : {
870 : CPLError( CE_Failure, CPLE_AppDefined,
871 : "Attempt to create field %s, but a field with this name already exists.",
872 0 : poNewField->GetNameRef() );
873 :
874 0 : return OGRERR_FAILURE;
875 : }
876 :
877 : /* -------------------------------------------------------------------- */
878 : /* Is this a legal field type for CSV? For now we only allow */
879 : /* simple integer, real and string fields. */
880 : /* -------------------------------------------------------------------- */
881 83 : switch( poNewField->GetType() )
882 : {
883 : case OFTInteger:
884 : case OFTReal:
885 : case OFTString:
886 : // these types are OK.
887 80 : break;
888 :
889 : default:
890 3 : if( bApproxOK )
891 : {
892 : CPLError( CE_Warning, CPLE_AppDefined,
893 : "Attempt to create field of type %s, but this is not supported\n"
894 : "for .csv files. Just treating as a plain string.",
895 3 : poNewField->GetFieldTypeName( poNewField->GetType() ) );
896 : }
897 : else
898 : {
899 : CPLError( CE_Failure, CPLE_AppDefined,
900 : "Attempt to create field of type %s, but this is not supported\n"
901 : "for .csv files.",
902 0 : poNewField->GetFieldTypeName( poNewField->GetType() ) );
903 0 : return OGRERR_FAILURE;
904 : }
905 : }
906 :
907 : /* -------------------------------------------------------------------- */
908 : /* Seems ok, add to field list. */
909 : /* -------------------------------------------------------------------- */
910 83 : poFeatureDefn->AddFieldDefn( poNewField );
911 :
912 83 : return OGRERR_NONE;
913 : }
914 :
915 : /************************************************************************/
916 : /* WriteHeader() */
917 : /* */
918 : /* Write the header, and possibly the .csvt file if they */
919 : /* haven't already been written. */
920 : /************************************************************************/
921 :
922 148 : OGRErr OGRCSVLayer::WriteHeader()
923 : {
924 148 : if( bHasFieldNames )
925 122 : return OGRERR_NONE;
926 :
927 : /* -------------------------------------------------------------------- */
928 : /* Write field names if we haven't written them yet. */
929 : /* Write .csvt file if needed */
930 : /* -------------------------------------------------------------------- */
931 26 : bHasFieldNames = TRUE;
932 :
933 56 : for(int iFile=0;iFile<((bCreateCSVT) ? 2 : 1);iFile++)
934 : {
935 30 : VSILFILE* fpCSVT = NULL;
936 34 : if (bCreateCSVT && iFile == 0)
937 : {
938 4 : char* pszDirName = CPLStrdup(CPLGetDirname(pszFilename));
939 4 : char* pszBaseName = CPLStrdup(CPLGetBasename(pszFilename));
940 4 : fpCSVT = VSIFOpenL(CPLFormFilename(pszDirName, pszBaseName, ".csvt"), "wb");
941 4 : CPLFree(pszDirName);
942 4 : CPLFree(pszBaseName);
943 : }
944 : else
945 : {
946 27 : if( strncmp(pszFilename, "/vsistdout/", 11) == 0 ||
947 : strncmp(pszFilename, "/vsizip/", 8) == 0 )
948 1 : fpCSV = VSIFOpenL( pszFilename, "wb" );
949 : else
950 25 : fpCSV = VSIFOpenL( pszFilename, "w+b" );
951 :
952 26 : if( fpCSV == NULL )
953 : {
954 : CPLError( CE_Failure, CPLE_OpenFailed,
955 : "Failed to create %s:\n%s",
956 0 : pszFilename, VSIStrerror( errno ) );
957 0 : return OGRERR_FAILURE;
958 : }
959 : }
960 :
961 30 : if (bWriteBOM && fpCSV)
962 : {
963 2 : VSIFWriteL("\xEF\xBB\xBF", 1, 3, fpCSV);
964 : }
965 :
966 30 : if (eGeometryFormat == OGR_CSV_GEOM_AS_WKT)
967 : {
968 4 : if (fpCSV) VSIFPrintfL( fpCSV, "%s", "WKT");
969 4 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", "String");
970 4 : if (poFeatureDefn->GetFieldCount() > 0)
971 : {
972 4 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
973 4 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", ",");
974 : }
975 : }
976 26 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ)
977 : {
978 2 : if (fpCSV) VSIFPrintfL( fpCSV, "X%cY%cZ", chDelimiter, chDelimiter);
979 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", "Real,Real,Real");
980 2 : if (poFeatureDefn->GetFieldCount() > 0)
981 : {
982 2 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
983 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", ",");
984 : }
985 : }
986 24 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XY)
987 : {
988 2 : if (fpCSV) VSIFPrintfL( fpCSV, "X%cY", chDelimiter);
989 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", "Real,Real");
990 2 : if (poFeatureDefn->GetFieldCount() > 0)
991 : {
992 2 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
993 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", ",");
994 : }
995 : }
996 22 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_YX)
997 : {
998 2 : if (fpCSV) VSIFPrintfL( fpCSV, "Y%cX", chDelimiter);
999 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", "Real,Real");
1000 2 : if (poFeatureDefn->GetFieldCount() > 0)
1001 : {
1002 2 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
1003 2 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", ",");
1004 : }
1005 : }
1006 :
1007 125 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
1008 : {
1009 : char *pszEscaped;
1010 :
1011 95 : if( iField > 0 )
1012 : {
1013 65 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
1014 65 : if (fpCSVT) VSIFPrintfL( fpCSVT, "%s", ",");
1015 : }
1016 :
1017 : pszEscaped =
1018 : CPLEscapeString( poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
1019 95 : -1, CPLES_CSV );
1020 :
1021 95 : if (fpCSV) VSIFPrintfL( fpCSV, "%s", pszEscaped );
1022 95 : CPLFree( pszEscaped );
1023 :
1024 95 : if (fpCSVT)
1025 : {
1026 12 : switch( poFeatureDefn->GetFieldDefn(iField)->GetType() )
1027 : {
1028 2 : case OFTInteger: VSIFPrintfL( fpCSVT, "%s", "Integer"); break;
1029 2 : case OFTReal: VSIFPrintfL( fpCSVT, "%s", "Real"); break;
1030 1 : case OFTDate: VSIFPrintfL( fpCSVT, "%s", "Date"); break;
1031 1 : case OFTTime: VSIFPrintfL( fpCSVT, "%s", "Time"); break;
1032 1 : case OFTDateTime: VSIFPrintfL( fpCSVT, "%s", "DateTime"); break;
1033 5 : default: VSIFPrintfL( fpCSVT, "%s", "String"); break;
1034 : }
1035 :
1036 12 : int nWidth = poFeatureDefn->GetFieldDefn(iField)->GetWidth();
1037 12 : int nPrecision = poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
1038 12 : if (nWidth != 0)
1039 : {
1040 3 : if (nPrecision != 0)
1041 1 : VSIFPrintfL( fpCSVT, "(%d.%d)", nWidth, nPrecision);
1042 : else
1043 2 : VSIFPrintfL( fpCSVT, "(%d)", nWidth);
1044 : }
1045 : }
1046 : }
1047 :
1048 : /* The CSV driver will not recognize single column tables, so add */
1049 : /* a fake second blank field */
1050 30 : if( poFeatureDefn->GetFieldCount() == 1 )
1051 : {
1052 11 : if (fpCSV) VSIFPrintfL( fpCSV, "%c", chDelimiter );
1053 : }
1054 :
1055 30 : if( bUseCRLF )
1056 : {
1057 1 : if (fpCSV) VSIFPutcL( 13, fpCSV );
1058 1 : if (fpCSVT) VSIFPutcL( 13, fpCSVT );
1059 : }
1060 30 : if (fpCSV) VSIFPutcL( '\n', fpCSV );
1061 30 : if (fpCSVT) VSIFPutcL( '\n', fpCSVT );
1062 30 : if (fpCSVT) VSIFCloseL(fpCSVT);
1063 : }
1064 :
1065 26 : if (fpCSV == NULL)
1066 0 : return OGRERR_FAILURE;
1067 : else
1068 26 : return OGRERR_NONE;
1069 : }
1070 :
1071 : /************************************************************************/
1072 : /* CreateFeature() */
1073 : /************************************************************************/
1074 :
1075 60 : OGRErr OGRCSVLayer::CreateFeature( OGRFeature *poNewFeature )
1076 :
1077 : {
1078 : int iField;
1079 :
1080 60 : if( !bInWriteMode )
1081 : {
1082 : CPLError( CE_Failure, CPLE_AppDefined,
1083 0 : "The CreateFeature() operation is not permitted on a read-only CSV." );
1084 0 : return OGRERR_FAILURE;
1085 : }
1086 :
1087 : /* If we need rewind, it means that we have just written a feature before */
1088 : /* so there's no point seeking to the end of the file, as we're already */
1089 : /* at the end */
1090 60 : int bNeedSeekEnd = !bNeedRewindBeforeRead;
1091 :
1092 60 : bNeedRewindBeforeRead = TRUE;
1093 :
1094 : /* -------------------------------------------------------------------- */
1095 : /* Write field names if we haven't written them yet. */
1096 : /* Write .csvt file if needed */
1097 : /* -------------------------------------------------------------------- */
1098 60 : if( !bHasFieldNames )
1099 : {
1100 26 : OGRErr eErr = WriteHeader();
1101 26 : if (eErr != OGRERR_NONE)
1102 0 : return eErr;
1103 26 : bNeedSeekEnd = FALSE;
1104 : }
1105 :
1106 60 : if (fpCSV == NULL)
1107 0 : return OGRERR_FAILURE;
1108 :
1109 : /* -------------------------------------------------------------------- */
1110 : /* Make sure we are at the end of the file. */
1111 : /* -------------------------------------------------------------------- */
1112 60 : if (bNeedSeekEnd)
1113 : {
1114 13 : if (bFirstFeatureAppendedDuringSession)
1115 : {
1116 : /* Add a newline character to the end of the file if necessary */
1117 13 : bFirstFeatureAppendedDuringSession = FALSE;
1118 13 : VSIFSeekL( fpCSV, 0, SEEK_END );
1119 13 : VSIFSeekL( fpCSV, VSIFTellL(fpCSV) - 1, SEEK_SET);
1120 : char chLast;
1121 13 : VSIFReadL( &chLast, 1, 1, fpCSV );
1122 13 : VSIFSeekL( fpCSV, 0, SEEK_END );
1123 13 : if (chLast != '\n')
1124 : {
1125 0 : if( bUseCRLF )
1126 0 : VSIFPutcL( 13, fpCSV );
1127 0 : VSIFPutcL( '\n', fpCSV );
1128 : }
1129 : }
1130 : else
1131 : {
1132 0 : VSIFSeekL( fpCSV, 0, SEEK_END );
1133 : }
1134 : }
1135 :
1136 : /* -------------------------------------------------------------------- */
1137 : /* Write out the geometry */
1138 : /* -------------------------------------------------------------------- */
1139 60 : if (eGeometryFormat == OGR_CSV_GEOM_AS_WKT)
1140 : {
1141 4 : OGRGeometry *poGeom = poNewFeature->GetGeometryRef();
1142 4 : char* pszWKT = NULL;
1143 4 : if (poGeom && poGeom->exportToWkt(&pszWKT) == OGRERR_NONE)
1144 : {
1145 4 : VSIFPrintfL( fpCSV, "\"%s\"", pszWKT);
1146 : }
1147 : else
1148 : {
1149 0 : VSIFPrintfL( fpCSV, "\"\"");
1150 : }
1151 4 : CPLFree(pszWKT);
1152 4 : if (poFeatureDefn->GetFieldCount() > 0)
1153 4 : VSIFPrintfL( fpCSV, "%c", chDelimiter);
1154 : }
1155 56 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ ||
1156 : eGeometryFormat == OGR_CSV_GEOM_AS_XY ||
1157 : eGeometryFormat == OGR_CSV_GEOM_AS_YX)
1158 : {
1159 4 : OGRGeometry *poGeom = poNewFeature->GetGeometryRef();
1160 4 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1161 : {
1162 3 : OGRPoint* poPoint = (OGRPoint*) poGeom;
1163 : char szBuffer[75];
1164 3 : if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ )
1165 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3);
1166 2 : else if (eGeometryFormat == OGR_CSV_GEOM_AS_XY )
1167 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getX(), poPoint->getY(), 0, 2);
1168 : else
1169 1 : OGRMakeWktCoordinate(szBuffer, poPoint->getY(), poPoint->getX(), 0, 2);
1170 3 : char* pc = szBuffer;
1171 17 : while(*pc != '\0')
1172 : {
1173 11 : if (*pc == ' ')
1174 4 : *pc = chDelimiter;
1175 11 : pc ++;
1176 : }
1177 3 : VSIFPrintfL( fpCSV, "%s", szBuffer );
1178 : }
1179 : else
1180 : {
1181 1 : VSIFPrintfL( fpCSV, "%c", chDelimiter );
1182 1 : if (eGeometryFormat == OGR_CSV_GEOM_AS_XYZ)
1183 0 : VSIFPrintfL( fpCSV, "%c", chDelimiter );
1184 : }
1185 4 : if (poFeatureDefn->GetFieldCount() > 0)
1186 4 : VSIFPrintfL( fpCSV, "%c", chDelimiter );
1187 : }
1188 :
1189 : /* -------------------------------------------------------------------- */
1190 : /* Write out all the field values. */
1191 : /* -------------------------------------------------------------------- */
1192 60 : int bNonEmptyLine = FALSE;
1193 490 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
1194 : {
1195 : char *pszEscaped;
1196 :
1197 430 : if( iField > 0 )
1198 370 : VSIFPrintfL( fpCSV, "%c", chDelimiter );
1199 :
1200 430 : if (poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTReal)
1201 : {
1202 5 : pszEscaped = CPLStrdup(poNewFeature->GetFieldAsString(iField));
1203 : /* Use point as decimal separator */
1204 5 : char* pszComma = strchr(pszEscaped, ',');
1205 5 : if (pszComma)
1206 0 : *pszComma = '.';
1207 : }
1208 : else
1209 : {
1210 : pszEscaped =
1211 : CPLEscapeString( poNewFeature->GetFieldAsString(iField),
1212 425 : -1, CPLES_CSV );
1213 : }
1214 :
1215 430 : int nLen = (int)strlen(pszEscaped);
1216 430 : bNonEmptyLine |= (nLen != 0);
1217 430 : VSIFWriteL( pszEscaped, 1, nLen, fpCSV );
1218 430 : CPLFree( pszEscaped );
1219 : }
1220 :
1221 60 : if( poFeatureDefn->GetFieldCount() == 1 && !bNonEmptyLine )
1222 1 : VSIFPrintfL( fpCSV, "%c", chDelimiter );
1223 :
1224 60 : if( bUseCRLF )
1225 5 : VSIFPutcL( 13, fpCSV );
1226 60 : VSIFPutcL( '\n', fpCSV );
1227 :
1228 60 : return OGRERR_NONE;
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* SetCRLF() */
1233 : /************************************************************************/
1234 :
1235 26 : void OGRCSVLayer::SetCRLF( int bNewValue )
1236 :
1237 : {
1238 26 : bUseCRLF = bNewValue;
1239 26 : }
1240 :
1241 : /************************************************************************/
1242 : /* SetWriteGeometry() */
1243 : /************************************************************************/
1244 :
1245 7 : void OGRCSVLayer::SetWriteGeometry(OGRCSVGeometryFormat eGeometryFormat)
1246 : {
1247 7 : this->eGeometryFormat = eGeometryFormat;
1248 7 : }
1249 :
1250 : /************************************************************************/
1251 : /* SetCreateCSVT() */
1252 : /************************************************************************/
1253 :
1254 4 : void OGRCSVLayer::SetCreateCSVT(int bCreateCSVT)
1255 : {
1256 4 : this->bCreateCSVT = bCreateCSVT;
1257 4 : }
1258 :
1259 : /************************************************************************/
1260 : /* SetWriteBOM() */
1261 : /************************************************************************/
1262 :
1263 2 : void OGRCSVLayer::SetWriteBOM(int bWriteBOM)
1264 : {
1265 2 : this->bWriteBOM = bWriteBOM;
1266 2 : }
1267 :
1268 : /************************************************************************/
1269 : /* GetFeatureCount() */
1270 : /************************************************************************/
1271 :
1272 5 : int OGRCSVLayer::GetFeatureCount( int bForce )
1273 : {
1274 5 : if (bInWriteMode || m_poFilterGeom != NULL || m_poAttrQuery != NULL)
1275 3 : return OGRLayer::GetFeatureCount(bForce);
1276 :
1277 2 : if (nTotalFeatures >= 0)
1278 0 : return nTotalFeatures;
1279 :
1280 2 : if (fpCSV == NULL)
1281 0 : return 0;
1282 :
1283 2 : ResetReading();
1284 :
1285 : char **papszTokens;
1286 2 : nTotalFeatures = 0;
1287 6 : while(TRUE)
1288 : {
1289 8 : papszTokens = OGRCSVReadParseLineL( fpCSV, chDelimiter, bDontHonourStrings );
1290 8 : if( papszTokens == NULL )
1291 : break;
1292 :
1293 6 : if( papszTokens[0] != NULL )
1294 6 : nTotalFeatures ++;
1295 :
1296 6 : CSLDestroy(papszTokens);
1297 : }
1298 :
1299 2 : ResetReading();
1300 :
1301 2 : return nTotalFeatures;
1302 : }
|