LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/csv - ogrcsvlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 486 411 84.6 %
Date: 2012-12-26 Functions: 18 15 83.3 %

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

Generated by: LCOV version 1.7