LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/csv - ogrcsvlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 536 457 85.3 %
Date: 2013-03-30 Functions: 19 16 84.2 %

       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                 : }

Generated by: LCOV version 1.7