LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/georss - ogrgeorsslayer.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 1096
Code covered: 86.1 % Executed lines: 944

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgeorsslayer.cpp 19643 2010-05-08 21:56:18Z rouault $
       3                 :  *
       4                 :  * Project:  GeoRSS Translator
       5                 :  * Purpose:  Implements OGRGeoRSSLayer class.
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2008, Even Rouault
      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_georss.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_minixml.h"
      33                 : #include "ogr_api.h"
      34                 : #include "ogr_p.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ogrgeorsslayer.cpp 19643 2010-05-08 21:56:18Z rouault $");
      37                 : 
      38                 : static const char* apszAllowedATOMFieldNamesWithSubElements[] = { "author", "contributor", NULL };
      39                 : 
      40                 : static
      41                 : const char* apszAllowedRSSFieldNames[] = {  "title", "link", "description", "author",
      42                 :                                             "category", "category_domain",
      43                 :                                             "comments",
      44                 :                                             "enclosure_url", "enclosure_length", "enclosure_type",
      45                 :                                             "guid", "guid_isPermaLink",
      46                 :                                             "pubDate",
      47                 :                                             "source", "source_url", NULL};
      48                 : 
      49                 : static
      50                 : const char* apszAllowedATOMFieldNames[] = { "category_term", "category_scheme", "category_label",
      51                 :                                             "content", "content_type", "content_xml_lang", "content_xml_base",
      52                 :                                             "summary", "summary_type", "summary_xml_lang", "summary_xml_base",
      53                 :                                             "author_name", "author_uri", "author_email",
      54                 :                                             "contributor_name", "contributor_uri", "contributor_email",
      55                 :                                             "link_href", "link_rel", "link_type", "link_length",
      56                 :                                             "id", "published", "rights", "source",
      57                 :                                             "title", "updated", NULL };
      58                 : 
      59                 : #define IS_LAT_ELEMENT(pszName) (strncmp(pszName, "geo:lat", strlen("geo:lat")) == 0 || \
      60                 :                                  strncmp(pszName, "icbm:lat", strlen("icbm:lat")) == 0 || \
      61                 :                                  strncmp(pszName, "geourl:lat", strlen("geourl:lat")) == 0)
      62                 : 
      63                 : #define IS_LON_ELEMENT(pszName) (strncmp(pszName, "geo:lon", strlen("geo:lon")) == 0 || \
      64                 :                                  strncmp(pszName, "icbm:lon", strlen("icbm:lon")) == 0 || \
      65                 :                                  strncmp(pszName, "geourl:lon", strlen("geourl:lon")) == 0)
      66                 : 
      67                 : #define IS_GEO_ELEMENT(pszName) (strcmp(pszName, "georss:point") == 0 || \
      68                 :                                  strcmp(pszName, "georss:line") == 0 || \
      69                 :                                  strcmp(pszName, "georss:box") == 0 || \
      70                 :                                  strcmp(pszName, "georss:polygon") == 0 || \
      71                 :                                  strcmp(pszName, "georss:where") == 0 || \
      72                 :                                  strncmp(pszName, "gml:", strlen("gml:")) == 0 || \
      73                 :                                  strncmp(pszName, "geo:", strlen("geo:")) == 0 || \
      74                 :                                  strncmp(pszName, "icbm:", strlen("icbm:")) == 0 || \
      75                 :                                  strncmp(pszName, "geourl:", strlen("geourl:")) == 0)
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                            OGRGeoRSSLayer()                          */
      79                 : /************************************************************************/
      80                 : 
      81                 : OGRGeoRSSLayer::OGRGeoRSSLayer( const char* pszFilename,
      82                 :                                 const char* pszLayerName,
      83                 :                                 OGRGeoRSSDataSource* poDS,
      84                 :                                 OGRSpatialReference *poSRSIn,
      85              19 :                                 int bWriteMode)
      86                 : 
      87                 : {
      88              19 :     eof = FALSE;
      89              19 :     nNextFID = 0;
      90                 : 
      91              19 :     this->poDS = poDS;
      92              19 :     this->bWriteMode = bWriteMode;
      93                 : 
      94              19 :     eFormat = poDS->GetFormat();
      95                 : 
      96              19 :     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
      97              19 :     poFeatureDefn->Reference();
      98                 : 
      99              19 :     poSRS = poSRSIn;
     100              19 :     if (poSRS)
     101               1 :         poSRS->Reference();
     102                 : 
     103              19 :     nTotalFeatureCount = 0;
     104                 : 
     105              19 :     ppoFeatureTab = NULL;
     106              19 :     nFeatureTabIndex = 0;
     107              19 :     nFeatureTabLength = 0;
     108              19 :     pszSubElementName = NULL;
     109              19 :     pszSubElementValue = NULL;
     110              19 :     nSubElementValueLen = 0;
     111              19 :     pszGMLSRSName = NULL;
     112              19 :     pszTagWithSubTag = NULL;
     113              19 :     bStopParsing = FALSE;
     114              19 :     bHasReadSchema = FALSE;
     115              19 :     setOfFoundFields = NULL;
     116              19 :     poGlobalGeom = NULL;
     117              19 :     hasFoundLat = FALSE;
     118              19 :     hasFoundLon = FALSE;
     119                 : 
     120              19 :     poFeature = NULL;
     121                 : 
     122                 : #ifdef HAVE_EXPAT
     123              19 :     oParser = NULL;
     124                 : #endif
     125                 : 
     126              19 :     if (bWriteMode == FALSE)
     127                 :     {
     128              13 :         fpGeoRSS = VSIFOpenL( pszFilename, "r" );
     129              13 :         if( fpGeoRSS == NULL )
     130                 :         {
     131               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
     132               0 :             return;
     133                 :         }
     134                 :     }
     135                 :     else
     136               6 :         fpGeoRSS = NULL;
     137                 : 
     138              19 :     ResetReading();
     139               0 : }
     140                 : 
     141                 : /************************************************************************/
     142                 : /*                            ~OGRGeoRSSLayer()                            */
     143                 : /************************************************************************/
     144                 : 
     145              19 : OGRGeoRSSLayer::~OGRGeoRSSLayer()
     146                 : 
     147                 : {
     148                 : #ifdef HAVE_EXPAT
     149              19 :     if (oParser)
     150              13 :         XML_ParserFree(oParser);
     151                 : #endif
     152              19 :     poFeatureDefn->Release();
     153                 :     
     154              19 :     if( poSRS != NULL )
     155              10 :         poSRS->Release();
     156                 : 
     157              19 :     CPLFree(pszSubElementName);
     158              19 :     CPLFree(pszSubElementValue);
     159              19 :     CPLFree(pszGMLSRSName);
     160              19 :     CPLFree(pszTagWithSubTag);
     161              19 :     if (setOfFoundFields)
     162              12 :         CPLHashSetDestroy(setOfFoundFields);
     163              19 :     if (poGlobalGeom)
     164               0 :         delete poGlobalGeom;
     165                 : 
     166                 :     int i;
     167              19 :     for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
     168               0 :         delete ppoFeatureTab[i];
     169              19 :     CPLFree(ppoFeatureTab);
     170                 : 
     171              19 :     if (poFeature)
     172               0 :         delete poFeature;
     173                 : 
     174              19 :     if (fpGeoRSS)
     175              13 :         VSIFCloseL( fpGeoRSS );
     176              19 : }
     177                 : 
     178                 : 
     179                 : /************************************************************************/
     180                 : /*                            GetLayerDefn()                            */
     181                 : /************************************************************************/
     182                 : 
     183              17 : OGRFeatureDefn * OGRGeoRSSLayer::GetLayerDefn()
     184                 : {
     185              17 :     if (!bHasReadSchema)
     186               8 :         LoadSchema();
     187                 : 
     188              17 :     return poFeatureDefn;
     189                 : }
     190                 : 
     191                 : 
     192                 : 
     193                 : #ifdef HAVE_EXPAT
     194                 : 
     195                 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
     196             276 :                                     const char **ppszAttr)
     197                 : {
     198             276 :     ((OGRGeoRSSLayer*)pUserData)->startElementCbk(pszName, ppszAttr);
     199             276 : }
     200                 : 
     201             276 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
     202                 : {
     203             276 :     ((OGRGeoRSSLayer*)pUserData)->endElementCbk(pszName);
     204             276 : }
     205                 : 
     206             792 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
     207                 : {
     208             792 :     ((OGRGeoRSSLayer*)pUserData)->dataHandlerCbk(data, nLen);
     209             792 : }
     210                 : 
     211                 : #endif
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                            ResetReading()                            */
     215                 : /************************************************************************/
     216                 : 
     217              19 : void OGRGeoRSSLayer::ResetReading()
     218                 : 
     219                 : {
     220              19 :     if (bWriteMode)
     221               6 :         return;
     222                 : 
     223              13 :     eof = FALSE;
     224              13 :     nNextFID = 0;
     225              13 :     if (fpGeoRSS)
     226                 :     {
     227              13 :         VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
     228                 : #ifdef HAVE_EXPAT
     229              13 :         if (oParser)
     230               0 :             XML_ParserFree(oParser);
     231                 :         
     232              13 :         oParser = OGRCreateExpatXMLParser();
     233              13 :         XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
     234              13 :         XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
     235              13 :         XML_SetUserData(oParser, this);
     236                 : #endif
     237                 :     }
     238              13 :     bInFeature = FALSE;
     239              13 :     hasFoundLat = FALSE;
     240              13 :     hasFoundLon = FALSE;
     241              13 :     bInSimpleGeometry = FALSE;
     242              13 :     bInGMLGeometry = FALSE;
     243              13 :     bInGeoLat = FALSE;
     244              13 :     bInGeoLong = FALSE;
     245              13 :     eGeomType = wkbUnknown;
     246              13 :     CPLFree(pszSubElementName);
     247              13 :     pszSubElementName = NULL;
     248              13 :     CPLFree(pszSubElementValue);
     249              13 :     pszSubElementValue = NULL;
     250              13 :     nSubElementValueLen = 0;
     251              13 :     CPLFree(pszGMLSRSName);
     252              13 :     pszGMLSRSName = NULL;
     253                 : 
     254              13 :     if (setOfFoundFields)
     255               0 :         CPLHashSetDestroy(setOfFoundFields);
     256              13 :     setOfFoundFields = NULL;
     257                 : 
     258                 :     int i;
     259              13 :     for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
     260               0 :         delete ppoFeatureTab[i];
     261              13 :     CPLFree(ppoFeatureTab);
     262              13 :     nFeatureTabIndex = 0;
     263              13 :     nFeatureTabLength = 0;
     264              13 :     ppoFeatureTab = NULL;
     265              13 :     if (poFeature)
     266               0 :         delete poFeature;
     267              13 :     poFeature = NULL;
     268                 : 
     269              13 :     currentDepth = 0;
     270              13 :     featureDepth = 0;
     271              13 :     geometryDepth = 0;
     272              13 :     bInTagWithSubTag = FALSE;
     273              13 :     CPLFree(pszTagWithSubTag);
     274              13 :     pszTagWithSubTag = NULL;
     275                 : }
     276                 : 
     277                 : #ifdef HAVE_EXPAT
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                      AddStrToSubElementValue()                       */
     281                 : /************************************************************************/
     282                 : 
     283             188 : void OGRGeoRSSLayer::AddStrToSubElementValue(const char* pszStr)
     284                 : {
     285             188 :     int len = strlen(pszStr);
     286                 :     char* pszNewSubElementValue = (char*)
     287             188 :             VSIRealloc(pszSubElementValue, nSubElementValueLen + len + 1);
     288             188 :     if (pszNewSubElementValue == NULL)
     289                 :     {
     290               0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     291               0 :         XML_StopParser(oParser, XML_FALSE);
     292               0 :         bStopParsing = TRUE;
     293               0 :         return;
     294                 :     }
     295             188 :     pszSubElementValue = pszNewSubElementValue;
     296                 : 
     297             188 :     memcpy(pszSubElementValue + nSubElementValueLen, pszStr, len);
     298             188 :     nSubElementValueLen += len;
     299                 : }
     300                 : 
     301                 : /************************************************************************/
     302                 : /*              OGRGeoRSS_GetOGRCompatibleTagName()                     */
     303                 : /************************************************************************/
     304                 : 
     305                 : /** Replace ':' from XML NS element name by '_' more OGR friendly */
     306             312 : static char* OGRGeoRSS_GetOGRCompatibleTagName(const char* pszName)
     307                 : {
     308             312 :     char* pszModName = CPLStrdup(pszName);
     309                 :     int i;
     310            2712 :     for(i=0;pszModName[i] != 0;i++)
     311                 :     {
     312            2400 :         if (pszModName[i] == ':')
     313              24 :             pszModName[i] = '_';
     314                 :     }
     315             312 :     return pszModName;
     316                 : }
     317                 : 
     318                 : /************************************************************************/
     319                 : /*               OGRGeoRSSLayerATOMTagHasSubElement()                   */
     320                 : /************************************************************************/
     321                 : 
     322              80 : static int OGRGeoRSSLayerATOMTagHasSubElement(const char* pszName)
     323                 : {
     324                 :     unsigned int i;
     325             208 :     for(i=0;apszAllowedATOMFieldNamesWithSubElements[i] != NULL;i++)
     326                 :     {
     327             152 :         if (strcmp(pszName, apszAllowedATOMFieldNamesWithSubElements[i]) == 0)
     328              24 :             return TRUE;
     329                 :     }
     330              56 :     return FALSE;
     331                 : }
     332                 : 
     333                 : /************************************************************************/
     334                 : /*                        startElementCbk()                            */
     335                 : /************************************************************************/
     336                 : 
     337             276 : void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
     338                 : {
     339             276 :     int bSerializeTag = FALSE;
     340                 : 
     341             276 :     if (bStopParsing) return;
     342                 : 
     343             303 :     if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
     344                 :         (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
     345                 :     {
     346              27 :         featureDepth = currentDepth;
     347                 : 
     348              27 :         if (poFeature)
     349               0 :             delete poFeature;
     350                 : 
     351              27 :         poFeature = new OGRFeature( poFeatureDefn );
     352              27 :         poFeature->SetFID( nNextFID++ );
     353                 : 
     354              27 :         bInFeature = TRUE;
     355              27 :         hasFoundLat = FALSE;
     356              27 :         hasFoundLon = FALSE;
     357              27 :         bInSimpleGeometry = FALSE;
     358              27 :         bInGMLGeometry = FALSE;
     359              27 :         bInGeoLat = FALSE;
     360              27 :         bInGeoLong = FALSE;
     361              27 :         eGeomType = wkbUnknown;
     362              27 :         geometryDepth = 0;
     363              27 :         bInTagWithSubTag = FALSE;
     364                 : 
     365              27 :         if (setOfFoundFields)
     366              15 :             CPLHashSetDestroy(setOfFoundFields);
     367              27 :         setOfFoundFields = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
     368                 :     }
     369             259 :     else if (bInFeature && bInTagWithSubTag && currentDepth == 3)
     370                 :     {
     371              10 :         char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
     372                 : 
     373              10 :         CPLFree(pszSubElementName);
     374              10 :         pszSubElementName = NULL;
     375              10 :         CPLFree(pszSubElementValue);
     376              10 :         pszSubElementValue = NULL;
     377              10 :         nSubElementValueLen = 0;
     378                 : 
     379              10 :         iCurrentField = poFeatureDefn->GetFieldIndex(pszFieldName);
     380              10 :         if (iCurrentField >= 0)
     381              10 :             pszSubElementName = CPLStrdup(pszFieldName);
     382                 : 
     383              10 :         CPLFree(pszFieldName);
     384                 :     }
     385             239 :     else if (bInFeature && eFormat == GEORSS_ATOM &&
     386                 :              currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
     387                 :     {
     388               6 :         CPLFree(pszTagWithSubTag);
     389               6 :         pszTagWithSubTag = CPLStrdup(pszName);
     390                 : 
     391               6 :         int count = 1;
     392              14 :         while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
     393                 :         {
     394               2 :             count ++;
     395               2 :             CPLFree(pszTagWithSubTag);
     396               2 :             pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
     397                 :         }
     398               6 :         CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszTagWithSubTag));
     399                 : 
     400               6 :         bInTagWithSubTag = TRUE;
     401                 :     }
     402             233 :     else if (bInGMLGeometry)
     403                 :     {
     404              17 :         bSerializeTag = TRUE;
     405                 :     }
     406             216 :     else if (bInSimpleGeometry || bInGeoLat || bInGeoLong)
     407                 :     {
     408                 :         /* Shouldn't happen for a valid document */
     409                 :     }
     410             217 :     else if (IS_LAT_ELEMENT(pszName))
     411                 :     {
     412               1 :         CPLFree(pszSubElementValue);
     413               1 :         pszSubElementValue = NULL;
     414               1 :         nSubElementValueLen = 0;
     415               1 :         bInGeoLat = TRUE;
     416                 :     }
     417             216 :     else if (IS_LON_ELEMENT(pszName))
     418                 :     {
     419               1 :         CPLFree(pszSubElementValue);
     420               1 :         pszSubElementValue = NULL;
     421               1 :         nSubElementValueLen = 0;
     422               1 :         bInGeoLong = TRUE;
     423                 :     }
     424             224 :     else if (strcmp(pszName, "georss:point") == 0 ||
     425                 :              strcmp(pszName, "georss:line") == 0 ||
     426                 :              strcmp(pszName, "geo:line") == 0 ||
     427                 :              strcmp(pszName, "georss:polygon") == 0 ||
     428                 :              strcmp(pszName, "georss:box") == 0)
     429                 :     {
     430              10 :         CPLFree(pszSubElementValue);
     431              10 :         pszSubElementValue = NULL;
     432              10 :         nSubElementValueLen = 0;
     433                 :         eGeomType = strcmp(pszName, "georss:point") == 0 ?   wkbPoint :
     434                 :                       (strcmp(pszName, "georss:line") == 0 ||
     435                 :                        strcmp(pszName, "geo:line") == 0)  ?  wkbLineString :
     436                 :                       (strcmp(pszName, "georss:polygon") == 0  ||
     437                 :                        strcmp(pszName, "georss:box") == 0) ? wkbPolygon :
     438              10 :                                                              wkbUnknown;
     439              10 :         bInSimpleGeometry = TRUE;
     440              10 :         geometryDepth = currentDepth;
     441                 :     }
     442             214 :     else if (strcmp(pszName, "gml:Point") == 0 ||
     443                 :              strcmp(pszName, "gml:LineString") == 0 ||
     444                 :              strcmp(pszName, "gml:Polygon") == 0 ||
     445                 :              strcmp(pszName, "gml:Envelope") == 0)
     446                 :     {
     447              10 :         CPLFree(pszSubElementValue);
     448              10 :         pszSubElementValue = NULL;
     449              10 :         nSubElementValueLen = 0;
     450              10 :         AddStrToSubElementValue(CPLSPrintf("<%s>", pszName));
     451              10 :         bInGMLGeometry = TRUE;
     452              10 :         geometryDepth = currentDepth;
     453              10 :         CPLFree(pszGMLSRSName);
     454              10 :         pszGMLSRSName = NULL;
     455              11 :         for (int i = 0; ppszAttr[i]; i += 2)
     456                 :         {
     457               1 :             if (strcmp(ppszAttr[i], "srsName") == 0)
     458                 :             {
     459               1 :                 if (pszGMLSRSName == NULL)
     460               1 :                     pszGMLSRSName = CPLStrdup(ppszAttr[i+1]);
     461                 :             }
     462                 :         }
     463                 :     }
     464             324 :     else if (bInFeature && currentDepth == featureDepth + 1)
     465                 :     {
     466             130 :         CPLFree(pszSubElementName);
     467             130 :         pszSubElementName = NULL;
     468             130 :         CPLFree(pszSubElementValue);
     469             130 :         pszSubElementValue = NULL;
     470             130 :         nSubElementValueLen = 0;
     471             130 :         iCurrentField = -1;
     472                 : 
     473             130 :         pszSubElementName = CPLStrdup(pszName);
     474             130 :         int count = 1;
     475             267 :         while(CPLHashSetLookup(setOfFoundFields, pszSubElementName) != NULL)
     476                 :         {
     477               7 :             count ++;
     478               7 :             CPLFree(pszSubElementName);
     479               7 :             pszSubElementName = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
     480                 :         }
     481             130 :         CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszSubElementName));
     482                 : 
     483             130 :         char* pszCompatibleName = OGRGeoRSS_GetOGRCompatibleTagName(pszSubElementName);
     484             130 :         iCurrentField = poFeatureDefn->GetFieldIndex(pszCompatibleName);
     485             130 :         CPLFree(pszSubElementName);
     486                 : 
     487             161 :         for(int i = 0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL; i+=2)
     488                 :         {
     489                 :             char* pszAttrCompatibleName =
     490              31 :                     OGRGeoRSS_GetOGRCompatibleTagName(CPLSPrintf("%s_%s", pszCompatibleName, ppszAttr[i]));
     491              31 :             int iAttrField = poFeatureDefn->GetFieldIndex(pszAttrCompatibleName);
     492              31 :             if (iAttrField >= 0)
     493                 :             {
     494              31 :                 if (poFeatureDefn->GetFieldDefn(iAttrField)->GetType() == OFTReal)
     495               0 :                     poFeature->SetField( iAttrField, CPLAtof(ppszAttr[i+1]) );
     496                 :                 else
     497              31 :                     poFeature->SetField( iAttrField, ppszAttr[i+1] );
     498                 :             }
     499              31 :             CPLFree(pszAttrCompatibleName);
     500                 :         }
     501                 : 
     502             130 :         if (iCurrentField < 0)
     503                 :         {
     504              14 :             pszSubElementName = NULL;
     505                 :         }
     506                 :         else
     507                 :         {
     508             116 :             pszSubElementName = CPLStrdup(pszCompatibleName);
     509                 :         }
     510             130 :         CPLFree(pszCompatibleName);
     511                 :     }
     512              64 :     else if (bInFeature && currentDepth > featureDepth + 1 && pszSubElementName != NULL)
     513                 :     {
     514               6 :         bSerializeTag = TRUE;
     515                 :     }
     516                 : 
     517             276 :     if (bSerializeTag)
     518                 :     {
     519              23 :         AddStrToSubElementValue("<");
     520              23 :         AddStrToSubElementValue(pszName);
     521              25 :         for(int i = 0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL; i+=2)
     522                 :         {
     523               2 :             AddStrToSubElementValue(" ");
     524               2 :             AddStrToSubElementValue(ppszAttr[i]);
     525               2 :             AddStrToSubElementValue("=\"");
     526               2 :             AddStrToSubElementValue(ppszAttr[i+1]);
     527               2 :             AddStrToSubElementValue("\"");
     528                 :         }
     529              23 :         AddStrToSubElementValue(">");
     530                 :     }
     531                 : 
     532             276 :     currentDepth++;
     533                 : }
     534                 : 
     535                 : /************************************************************************/
     536                 : /*                  OGRGeoRSS_GetGMLEnvelope()                          */
     537                 : /************************************************************************/
     538                 : 
     539               1 : static OGRGeometry* OGRGeoRSS_GetGMLEnvelope(const char* pszGML)
     540                 : {
     541               1 :     OGRGeometry* poGeom = NULL;
     542               1 :     CPLXMLNode* poNode = CPLParseXMLString(pszGML);
     543               1 :     const char* pszLowerCorner = CPLGetXMLValue(poNode, "gml:lowerCorner", NULL);
     544               1 :     const char* pszUpperCorner = CPLGetXMLValue(poNode, "gml:upperCorner", NULL);
     545               1 :     if (pszLowerCorner && pszUpperCorner)
     546                 :     {
     547                 :         char **papszTokensLower;
     548                 :         char **papszTokensUpper;
     549                 : 
     550                 :         papszTokensLower = CSLTokenizeStringComplex( 
     551               1 :             pszLowerCorner, " ,", FALSE, FALSE );
     552                 :         papszTokensUpper = CSLTokenizeStringComplex( 
     553               1 :             pszUpperCorner, " ,", FALSE, FALSE );
     554               1 :         if (CSLCount(papszTokensLower) == 2 &&
     555                 :             CSLCount(papszTokensUpper) == 2)
     556                 :         {
     557               1 :             OGRPolygon* poPolygon = new OGRPolygon();
     558               2 :             OGRLinearRing* poLinearRing = new OGRLinearRing();
     559               1 :             poPolygon->addRingDirectly(poLinearRing);
     560               1 :             double x1 = CPLAtof(papszTokensLower[0]);
     561               1 :             double y1 = CPLAtof(papszTokensLower[1]);
     562               1 :             double x2 = CPLAtof(papszTokensUpper[0]);
     563               1 :             double y2 = CPLAtof(papszTokensUpper[1]);
     564               1 :             poLinearRing->addPoint( x1, y1 );
     565               1 :             poLinearRing->addPoint( x2, y1 );
     566               1 :             poLinearRing->addPoint( x2, y2 );
     567               1 :             poLinearRing->addPoint( x1, y2 );
     568               1 :             poLinearRing->addPoint( x1, y1 );
     569                 : 
     570               1 :             poGeom = poPolygon;
     571                 :         }
     572                 : 
     573               1 :         CSLDestroy(papszTokensLower);
     574               1 :         CSLDestroy(papszTokensUpper);
     575                 :     }
     576               1 :     CPLDestroyXMLNode(poNode);
     577               1 :     return poGeom;
     578                 : }
     579                 : 
     580                 : 
     581                 : /************************************************************************/
     582                 : /*            OGRGeoRSSLayerTrimLeadingAndTrailingSpaces()              */
     583                 : /************************************************************************/
     584                 : 
     585              10 : static void OGRGeoRSSLayerTrimLeadingAndTrailingSpaces(char* pszStr)
     586                 : {
     587                 :     int i;
     588                 : 
     589                 :     /* Trim leading spaces, tabs and newlines */
     590              10 :     i = 0;
     591              23 :     while(pszStr[i] != '\0' &&
     592                 :           (pszStr[i] == ' ' || pszStr[i] == '\t' || pszStr[i] == '\n'))
     593               3 :         i ++;
     594              10 :     memmove(pszStr, pszStr + i, strlen(pszStr + i) + 1);
     595                 : 
     596                 :     /* Trim trailing spaces, tabs and newlines */
     597              10 :     i = strlen(pszStr) - 1;
     598              23 :     while(i >= 0 &&
     599                 :           (pszStr[i] == ' ' || pszStr[i] == '\t' || pszStr[i] == '\n'))
     600                 :     {
     601               3 :         pszStr[i] = '\0';
     602               3 :         i --;
     603                 :     }
     604              10 : }
     605                 : 
     606                 : /************************************************************************/
     607                 : /*                           endElementCbk()                            */
     608                 : /************************************************************************/
     609                 : 
     610             276 : void OGRGeoRSSLayer::endElementCbk(const char *pszName)
     611                 : {
     612             276 :     OGRGeometry* poGeom = NULL;
     613                 : 
     614             276 :     if (bStopParsing) return;
     615                 : 
     616             276 :     currentDepth--;
     617                 : 
     618             276 :     if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
     619                 :         (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
     620                 :     {
     621              27 :         bInFeature = FALSE;
     622              27 :         bInTagWithSubTag = FALSE;
     623                 : 
     624              28 :         if (hasFoundLat && hasFoundLon)
     625               1 :             poFeature->SetGeometryDirectly( new OGRPoint( lonVal, latVal ) );
     626              26 :         else if (poFeature->GetGeometryRef() == NULL && poGlobalGeom != NULL)
     627               0 :             poFeature->SetGeometry(poGlobalGeom);
     628                 : 
     629              27 :         hasFoundLat = FALSE;
     630              27 :         hasFoundLon = FALSE;
     631                 : 
     632              27 :         if (poSRS != NULL && poFeature->GetGeometryRef() != NULL)
     633              19 :             poFeature->GetGeometryRef()->assignSpatialReference(poSRS);
     634                 : 
     635              27 :         if( (m_poFilterGeom == NULL
     636                 :                 || FilterGeometry( poFeature->GetGeometryRef() ) )
     637                 :             && (m_poAttrQuery == NULL
     638                 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     639                 :         {
     640                 :             ppoFeatureTab = (OGRFeature**)
     641                 :                     CPLRealloc(ppoFeatureTab,
     642              27 :                                 sizeof(OGRFeature*) * (nFeatureTabLength + 1));
     643              27 :             ppoFeatureTab[nFeatureTabLength] = poFeature;
     644              27 :             nFeatureTabLength++;
     645                 :         }
     646                 :         else
     647                 :         {
     648               0 :             delete poFeature;
     649                 :         }
     650              27 :         poFeature = NULL;
     651              27 :         return;
     652                 :     }
     653                 : 
     654             259 :     if (bInTagWithSubTag && currentDepth == 3)
     655                 :     {
     656              10 :         char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
     657                 : 
     658              10 :         if (iCurrentField != -1 && pszSubElementName &&
     659                 :             strcmp(pszFieldName, pszSubElementName) == 0 && poFeature &&
     660                 :             pszSubElementValue && nSubElementValueLen)
     661                 :         {
     662              10 :             pszSubElementValue[nSubElementValueLen] = 0;
     663              10 :             if (poFeatureDefn->GetFieldDefn(iCurrentField)->GetType() == OFTReal)
     664               0 :                 poFeature->SetField( iCurrentField, CPLAtof(pszSubElementValue) );
     665                 :             else
     666              10 :                 poFeature->SetField( iCurrentField, pszSubElementValue);
     667                 :         }
     668                 : 
     669              10 :         CPLFree(pszSubElementName);
     670              10 :         pszSubElementName = NULL;
     671              10 :         CPLFree(pszSubElementValue);
     672              10 :         pszSubElementValue = NULL;
     673              10 :         nSubElementValueLen = 0;
     674                 : 
     675              10 :         CPLFree(pszFieldName);
     676                 :     }
     677             239 :     else if (bInFeature && eFormat == GEORSS_ATOM &&
     678                 :              currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
     679                 :     {
     680               6 :         bInTagWithSubTag = FALSE;
     681                 :     }
     682             233 :     else if (bInGMLGeometry)
     683                 :     {
     684              27 :         AddStrToSubElementValue("</");
     685              27 :         AddStrToSubElementValue(pszName);
     686              27 :         AddStrToSubElementValue(">");
     687              27 :         if (currentDepth > geometryDepth)
     688                 :         {
     689                 :         }
     690                 :         else
     691                 :         {
     692              10 :             pszSubElementValue[nSubElementValueLen] = 0;
     693              10 :             CPLAssert(strncmp(pszName, "gml:", 4) == 0);
     694              10 :             if (strcmp(pszName, "gml:Envelope") == 0)
     695               1 :                 poGeom =  OGRGeoRSS_GetGMLEnvelope(pszSubElementValue);
     696                 :             else
     697               9 :                 poGeom = (OGRGeometry*) OGR_G_CreateFromGML(pszSubElementValue);
     698                 : 
     699              10 :             if (poGeom != NULL && !poGeom->IsEmpty() )
     700                 :             {
     701               9 :                 int bSwapCoordinates = FALSE;
     702               9 :                 if (pszGMLSRSName)
     703                 :                 {
     704               1 :                     OGRSpatialReference* poSRSFeature = new OGRSpatialReference();
     705               1 :                     poSRSFeature->importFromURN(pszGMLSRSName);
     706               1 :                     poGeom->assignSpatialReference(poSRSFeature);
     707               1 :                     poSRSFeature->Release();
     708                 :                 }
     709                 :                 else
     710               8 :                     bSwapCoordinates = TRUE; /* lat, lon WGS 84 */
     711                 : 
     712               9 :                 if (bSwapCoordinates)
     713                 :                 {
     714               8 :                     switch ( wkbFlatten(poGeom->getGeometryType()) )
     715                 :                     {
     716                 :                         case wkbPoint:
     717                 :                         {
     718               2 :                             OGRPoint* poPoint = (OGRPoint*) poGeom;
     719               2 :                             double x = poPoint->getX();
     720               2 :                             double y = poPoint->getY();
     721               2 :                             poPoint->setX(y);
     722               2 :                             poPoint->setY(x);
     723               2 :                             break;
     724                 :                         }
     725                 : 
     726                 :                         case wkbLineString:
     727                 :                         {
     728               2 :                             OGRLineString* poLineString = (OGRLineString*) poGeom;
     729               2 :                             int n = poLineString->getNumPoints();
     730               8 :                             for(int i=0;i<n;i++)
     731                 :                             {
     732               6 :                                 double x = poLineString->getX(i);
     733               6 :                                 double y = poLineString->getY(i);
     734               6 :                                 if (poLineString->getCoordinateDimension() == 2)
     735               6 :                                     poLineString->setPoint(i, y, x);
     736                 :                                 else
     737               0 :                                     poLineString->setPoint(i, y, x, poLineString->getZ(i));
     738                 :                             }
     739               2 :                             break;
     740                 :                         }
     741                 : 
     742                 :                         case wkbPolygon:
     743                 :                         {
     744               4 :                             OGRPolygon* poPolygon = (OGRPolygon*) poGeom;
     745               4 :                             OGRLineString* poLineString = poPolygon->getExteriorRing();
     746               4 :                             int n = poLineString->getNumPoints();
     747              24 :                             for(int i=0;i<n;i++)
     748                 :                             {
     749              20 :                                 double x = poLineString->getX(i);
     750              20 :                                 double y = poLineString->getY(i);
     751              20 :                                 if (poLineString->getCoordinateDimension() == 2)
     752              20 :                                     poLineString->setPoint(i, y, x);
     753                 :                                 else
     754               0 :                                     poLineString->setPoint(i, y, x, poLineString->getZ(i));
     755                 : 
     756                 :                             }
     757                 :                             break;
     758                 :                         }
     759                 : 
     760                 :                         default:
     761                 :                             break;
     762                 :                     }
     763                 :                 }
     764                 :             }
     765              10 :             bInGMLGeometry = FALSE;
     766                 :         }
     767                 :     }
     768             206 :     else if (bInSimpleGeometry)
     769                 :     {
     770              10 :         if (currentDepth > geometryDepth)
     771                 :         {
     772                 :             /* Shouldn't happen for a valid document */
     773                 :         }
     774                 :         else
     775                 :         {
     776              10 :             if (pszSubElementValue)
     777                 :             {
     778              10 :                 pszSubElementValue[nSubElementValueLen] = 0;
     779                 : 
     780                 :                 /* Trim any leading and trailing spaces, tabs, newlines, etc... */
     781              10 :                 OGRGeoRSSLayerTrimLeadingAndTrailingSpaces(pszSubElementValue);
     782                 : 
     783                 :                 /* Caution : Order is latitude, longitude */
     784                 :                 char** papszTokens =
     785                 :                         CSLTokenizeStringComplex( pszSubElementValue,
     786              10 :                                                     " ,", TRUE, FALSE );
     787                 : 
     788              10 :                 int nTokens = CSLCount(papszTokens);
     789              11 :                 if ((nTokens % 2) != 0 ||
     790                 :                      (eGeomType == wkbPoint && nTokens != 2) ||
     791                 :                      (eGeomType == wkbLineString && nTokens < 4) ||
     792                 :                      (strcmp(pszName, "georss:polygon") == 0 && nTokens < 6) ||
     793                 :                      (strcmp(pszName, "georss:box") == 0 && nTokens != 4))
     794                 :                 {
     795                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     796                 :                              "Wrong number of coordinates in %s",
     797               1 :                              pszSubElementValue);
     798                 :                 }
     799               9 :                 else if (eGeomType == wkbPoint)
     800                 :                 {
     801                 :                     poGeom = new OGRPoint( CPLAtof(papszTokens[1]),
     802               3 :                                            CPLAtof(papszTokens[0]) );
     803                 :                 }
     804               6 :                 else if (eGeomType == wkbLineString)
     805                 :                 {
     806               2 :                     OGRLineString* poLineString = new OGRLineString ();
     807               2 :                     poGeom = poLineString;
     808                 :                     int i;
     809               8 :                     for(i=0;i<nTokens;i+=2)
     810                 :                     {
     811                 :                         poLineString->addPoint( CPLAtof(papszTokens[i+1]),
     812               6 :                                               CPLAtof(papszTokens[i]) );
     813                 :                     }
     814                 :                 }
     815               4 :                 else if (eGeomType == wkbPolygon)
     816                 :                 {
     817               4 :                     OGRPolygon* poPolygon = new OGRPolygon();
     818               8 :                     OGRLinearRing* poLinearRing = new OGRLinearRing();
     819               4 :                     poGeom = poPolygon;
     820               4 :                     poPolygon->addRingDirectly(poLinearRing);
     821               4 :                     if (strcmp(pszName, "georss:polygon") == 0)
     822                 :                     {
     823                 :                         int i;
     824              18 :                         for(i=0;i<nTokens;i+=2)
     825                 :                         {
     826                 :                             poLinearRing->addPoint( CPLAtof(papszTokens[i+1]),
     827              15 :                                                     CPLAtof(papszTokens[i]) );
     828                 :                         }
     829                 :                     }
     830                 :                     else
     831                 :                     {
     832               1 :                         double lat1 = CPLAtof(papszTokens[0]);
     833               1 :                         double lon1 = CPLAtof(papszTokens[1]);
     834               1 :                         double lat2 = CPLAtof(papszTokens[2]);
     835               1 :                         double lon2 = CPLAtof(papszTokens[3]);
     836               1 :                         poLinearRing->addPoint( lon1, lat1 );
     837               1 :                         poLinearRing->addPoint( lon1, lat2 );
     838               1 :                         poLinearRing->addPoint( lon2, lat2 );
     839               1 :                         poLinearRing->addPoint( lon2, lat1 );
     840               1 :                         poLinearRing->addPoint( lon1, lat1 );
     841                 :                     }
     842                 :                 }
     843                 : 
     844              10 :                 CSLDestroy(papszTokens);
     845                 :             }
     846              10 :             bInSimpleGeometry = FALSE;
     847                 :         }
     848                 :     }
     849             197 :     else if (IS_LAT_ELEMENT(pszName))
     850                 :     {
     851               1 :         if (pszSubElementValue)
     852                 :         {
     853               1 :             hasFoundLat = TRUE;
     854               1 :             pszSubElementValue[nSubElementValueLen] = 0;
     855               1 :             latVal = CPLAtof(pszSubElementValue);
     856                 :         }
     857               1 :         bInGeoLat = FALSE;
     858                 :     }
     859             196 :     else if (IS_LON_ELEMENT(pszName))
     860                 :     {
     861               1 :         if (pszSubElementValue)
     862                 :         {
     863               1 :             hasFoundLon = TRUE;
     864               1 :             pszSubElementValue[nSubElementValueLen] = 0;
     865               1 :             lonVal = CPLAtof(pszSubElementValue);
     866                 :         }
     867               1 :         bInGeoLong = FALSE;
     868                 :     }
     869             324 :     else if (bInFeature && currentDepth == featureDepth + 1)
     870                 :     {
     871             130 :         if (iCurrentField != -1 && pszSubElementName &&
     872                 :             poFeature && pszSubElementValue && nSubElementValueLen)
     873                 :         {
     874             116 :             pszSubElementValue[nSubElementValueLen] = 0;
     875             116 :             if (poFeatureDefn->GetFieldDefn(iCurrentField)->GetType() == OFTDateTime)
     876                 :             {
     877                 :                 int year, month, day, hour, minute, TZ;
     878                 :                 int nsecond;
     879                 :                 float fsecond;
     880              25 :                 if (OGRParseRFC822DateTime(pszSubElementValue, &year, &month, &day,
     881                 :                                                  &hour, &minute, &nsecond, &TZ))
     882                 :                 {
     883                 :                     poFeature->SetField(iCurrentField, year, month, day,
     884              21 :                                         hour, minute, nsecond, TZ);
     885                 :                 }
     886               4 :                 else if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day,
     887                 :                                                    &hour, &minute, &fsecond, &TZ))
     888                 :                 {
     889                 :                     poFeature->SetField(iCurrentField, year, month, day,
     890               4 :                                         hour, minute, (int)(fsecond + .5), TZ);
     891                 :                 }
     892                 :                 else
     893                 :                 {
     894                 :                     CPLError(CE_Warning, CPLE_AppDefined,
     895               0 :                                 "Could not parse %s as a valid dateTime", pszSubElementValue);
     896                 :                 }
     897                 :             }
     898                 :             else
     899                 :             {
     900              91 :                 if (poFeatureDefn->GetFieldDefn(iCurrentField)->GetType() == OFTReal)
     901               0 :                     poFeature->SetField( iCurrentField, CPLAtof(pszSubElementValue) );
     902                 :                 else
     903              91 :                     poFeature->SetField( iCurrentField, pszSubElementValue);
     904                 :             }
     905                 :         }
     906                 : 
     907             130 :         CPLFree(pszSubElementName);
     908             130 :         pszSubElementName = NULL;
     909             130 :         CPLFree(pszSubElementValue);
     910             130 :         pszSubElementValue = NULL;
     911             130 :         nSubElementValueLen = 0;
     912                 :     }
     913              64 :     else if (bInFeature && currentDepth > featureDepth + 1 && pszSubElementName != NULL)
     914                 :     {
     915               6 :         AddStrToSubElementValue("</");
     916               6 :         AddStrToSubElementValue(pszName);
     917               6 :         AddStrToSubElementValue(">");
     918                 :     }
     919                 : 
     920             249 :     if (poGeom != NULL)
     921                 :     {
     922              18 :         if (poFeature != NULL)
     923                 :         {
     924              18 :             poFeature->SetGeometryDirectly(poGeom);
     925                 :         }
     926               0 :         else if (!bInFeature)
     927                 :         {
     928               0 :             if (poGlobalGeom != NULL)
     929               0 :                 delete poGlobalGeom;
     930               0 :             poGlobalGeom = poGeom;
     931                 :         }
     932                 :         else
     933               0 :             delete poGeom;
     934                 :     }
     935             231 :     else if (!bInFeature && hasFoundLat && hasFoundLon)
     936                 :     {
     937               0 :         if (poGlobalGeom != NULL)
     938               0 :                 delete poGlobalGeom;
     939               0 :         poGlobalGeom = new OGRPoint( lonVal, latVal );
     940               0 :         hasFoundLat = hasFoundLon = FALSE;
     941                 :     }
     942                 : }
     943                 : 
     944                 : /************************************************************************/
     945                 : /*                          dataHandlerCbk()                            */
     946                 : /************************************************************************/
     947                 : 
     948             792 : void OGRGeoRSSLayer::dataHandlerCbk(const char *data, int nLen)
     949                 : {
     950             792 :     if (bStopParsing) return;
     951                 : 
     952             792 :     if (bInGMLGeometry == TRUE || bInSimpleGeometry == TRUE ||
     953                 :         bInGeoLat == TRUE || bInGeoLong == TRUE ||
     954                 :         pszSubElementName != NULL)
     955                 :     {
     956                 :         char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue,
     957             190 :                                                nSubElementValueLen + nLen + 1);
     958             190 :         if (pszNewSubElementValue == NULL)
     959                 :         {
     960               0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
     961               0 :             XML_StopParser(oSchemaParser, XML_FALSE);
     962               0 :             bStopParsing = TRUE;
     963               0 :             return;
     964                 :         }
     965             190 :         pszSubElementValue = pszNewSubElementValue;
     966             190 :         memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
     967             190 :         nSubElementValueLen += nLen;
     968                 :     }
     969                 : }
     970                 : #endif
     971                 : 
     972                 : /************************************************************************/
     973                 : /*                           GetNextFeature()                           */
     974                 : /************************************************************************/
     975                 : 
     976              27 : OGRFeature *OGRGeoRSSLayer::GetNextFeature()
     977                 : {
     978              27 :     if (bWriteMode)
     979                 :     {
     980                 :         CPLError(CE_Failure, CPLE_NotSupported,
     981               0 :                  "Cannot read features when writing a GeoRSS file");
     982               0 :         return NULL;
     983                 :     }
     984                 : 
     985              27 :     if (fpGeoRSS == NULL)
     986               0 :         return NULL;
     987                 : 
     988              27 :     if (!bHasReadSchema)
     989               4 :         LoadSchema();
     990                 : 
     991              27 :     if (bStopParsing)
     992               0 :         return NULL;
     993                 : 
     994                 : #ifdef HAVE_EXPAT
     995              27 :     if (nFeatureTabIndex < nFeatureTabLength)
     996                 :     {
     997              15 :         return ppoFeatureTab[nFeatureTabIndex++];
     998                 :     }
     999                 :     
    1000              12 :     if (VSIFEofL(fpGeoRSS))
    1001               0 :         return NULL;
    1002                 :     
    1003                 :     char aBuf[BUFSIZ];
    1004                 :     
    1005              12 :     CPLFree(ppoFeatureTab);
    1006              12 :     ppoFeatureTab = NULL;
    1007              12 :     nFeatureTabLength = 0;
    1008              12 :     nFeatureTabIndex = 0;
    1009                 : 
    1010                 :     int nDone;
    1011              12 :     do
    1012                 :     {
    1013                 :         unsigned int nLen =
    1014              12 :                 (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGeoRSS );
    1015              12 :         nDone = VSIFEofL(fpGeoRSS);
    1016              12 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1017                 :         {
    1018                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1019                 :                      "XML parsing of GeoRSS file failed : %s "
    1020                 :                      "at line %d, column %d",
    1021                 :                      XML_ErrorString(XML_GetErrorCode(oParser)),
    1022                 :                      (int)XML_GetCurrentLineNumber(oParser),
    1023               0 :                      (int)XML_GetCurrentColumnNumber(oParser));
    1024               0 :             bStopParsing = TRUE;
    1025                 :         }
    1026                 :     } while (!nDone && !bStopParsing && nFeatureTabLength == 0);
    1027                 :     
    1028              12 :     return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
    1029                 : #else
    1030                 :     return NULL;
    1031                 : #endif
    1032                 : }
    1033                 : 
    1034                 : /************************************************************************/
    1035                 : /*                           GetSpatialRef()                            */
    1036                 : /************************************************************************/
    1037                 : 
    1038              20 : OGRSpatialReference *OGRGeoRSSLayer::GetSpatialRef()
    1039                 : 
    1040                 : {
    1041              20 :     if (!bWriteMode && !bHasReadSchema)
    1042               6 :         LoadSchema();
    1043                 : 
    1044              20 :     return poSRS;
    1045                 : }
    1046                 : 
    1047                 : /************************************************************************/
    1048                 : /*              OGRGeoRSSLayerIsStandardFieldInternal()                 */
    1049                 : /************************************************************************/
    1050                 : 
    1051                 : static int OGRGeoRSSLayerIsStandardFieldInternal(const char* pszName,
    1052              91 :                                                  const char** papszNames)
    1053                 : {
    1054                 :     unsigned int i;
    1055             687 :     for( i = 0; papszNames[i] != NULL; i++)
    1056                 :     {
    1057             681 :         if (strcmp(pszName, papszNames[i]) == 0)
    1058                 :         {
    1059              74 :             return TRUE;
    1060                 :         }
    1061                 : 
    1062             607 :         const char* pszUnderscore = strchr(papszNames[i], '_');
    1063             607 :         if (pszUnderscore == NULL)
    1064                 :         {
    1065             251 :             int nLen = strlen(papszNames[i]);
    1066             251 :             if (strncmp(pszName, papszNames[i], nLen) == 0)
    1067                 :             {
    1068              12 :                 int k = nLen;
    1069              30 :                 while(pszName[k] >= '0' && pszName[k] <= '9')
    1070               6 :                     k++;
    1071              12 :                 if (pszName[k] == '\0')
    1072               3 :                     return TRUE;
    1073                 :             }
    1074                 :         }
    1075                 :         else
    1076                 :         {
    1077             356 :             int nLen = pszUnderscore - papszNames[i];
    1078             356 :             if (strncmp(pszName, papszNames[i], nLen) == 0)
    1079                 :             {
    1080              23 :                 int k = nLen;
    1081              60 :                 while(pszName[k] >= '0' && pszName[k] <= '9')
    1082              14 :                     k++;
    1083              23 :                 if (pszName[k] == '_' && strcmp(pszName + k, pszUnderscore) == 0)
    1084               8 :                     return TRUE;
    1085                 :             }
    1086                 :         }
    1087                 :     }
    1088               6 :     return FALSE;
    1089                 : }
    1090                 : 
    1091                 : /************************************************************************/
    1092                 : /*               OGRGeoRSSLayer::IsStandardField()                      */
    1093                 : /************************************************************************/
    1094                 : 
    1095              91 : int OGRGeoRSSLayer::IsStandardField(const char* pszName)
    1096                 : {
    1097              91 :     if (eFormat == GEORSS_RSS)
    1098                 :     {
    1099                 :         return OGRGeoRSSLayerIsStandardFieldInternal(pszName,
    1100              69 :                 apszAllowedRSSFieldNames);
    1101                 :     }
    1102                 :     else
    1103                 :     {
    1104                 :         return OGRGeoRSSLayerIsStandardFieldInternal(pszName,
    1105              22 :                 apszAllowedATOMFieldNames);
    1106                 :     }
    1107                 : }
    1108                 : 
    1109                 : /************************************************************************/
    1110                 : /*                 OGRGeoRSSLayerSplitComposedField()                   */
    1111                 : /************************************************************************/
    1112                 : 
    1113                 : static void OGRGeoRSSLayerSplitComposedField(const char* pszName,
    1114                 :                                              char** ppszElementName,
    1115                 :                                              char** ppszNumber,
    1116             103 :                                              char** ppszAttributeName)
    1117                 : {
    1118             103 :     *ppszElementName = CPLStrdup(pszName);
    1119                 : 
    1120             103 :     int i = 0;
    1121             854 :     while(pszName[i] != '\0' && pszName[i] != '_' &&
    1122                 :           !(pszName[i] >= '0' && pszName[i] <= '9'))
    1123                 :     {
    1124             648 :         i++;
    1125                 :     }
    1126                 : 
    1127             103 :     (*ppszElementName)[i] = '\0';
    1128                 : 
    1129             118 :     if (pszName[i] >= '0' && pszName[i] <= '9')
    1130                 :     {
    1131              15 :         *ppszNumber = CPLStrdup(pszName + i);
    1132              15 :         char* pszUnderscore = strchr(*ppszNumber, '_');
    1133              15 :         if (pszUnderscore)
    1134                 :         {
    1135              11 :             *pszUnderscore = '\0';
    1136              11 :             *ppszAttributeName = CPLStrdup(pszUnderscore + 1);
    1137                 :         }
    1138                 :         else
    1139                 :         {
    1140               4 :             *ppszAttributeName = NULL;
    1141                 :         }
    1142                 :     }
    1143                 :     else
    1144                 :     {
    1145              88 :         *ppszNumber = CPLStrdup("");
    1146              88 :         if (pszName[i] == '_')
    1147                 :         {
    1148              29 :             *ppszAttributeName = CPLStrdup(pszName + i + 1);
    1149                 :         }
    1150                 :         else
    1151                 :         {
    1152              59 :             *ppszAttributeName = NULL;
    1153                 :         }
    1154                 :     }
    1155             103 : }
    1156                 : 
    1157                 : /************************************************************************/
    1158                 : /*                 OGRGeoRSSLayerWriteSimpleElement()                   */
    1159                 : /************************************************************************/
    1160                 : 
    1161                 : static void OGRGeoRSSLayerWriteSimpleElement(FILE* fp,
    1162                 :                                              const char* pszElementName,
    1163                 :                                              const char* pszNumber,
    1164                 :                                              const char** papszNames,
    1165                 :                                              OGRFeatureDefn* poFeatureDefn,
    1166               8 :                                              OGRFeature* poFeature)
    1167                 : {
    1168               8 :     VSIFPrintfL(fp, "      <%s", pszElementName);
    1169                 : 
    1170                 :     unsigned k;
    1171             152 :     for( k = 0; papszNames[k] != NULL ; k++)
    1172                 :     {
    1173             144 :         if (strncmp(papszNames[k], pszElementName, strlen(pszElementName)) == 0 &&
    1174                 :             papszNames[k][strlen(pszElementName)] == '_')
    1175                 :         {
    1176              14 :             const char* pszAttributeName = papszNames[k] + strlen(pszElementName) + 1;
    1177              14 :             char* pszFieldName = CPLStrdup(CPLSPrintf("%s%s_%s", pszElementName, pszNumber, pszAttributeName));
    1178              14 :             int iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1179              14 :             if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1180                 :             {
    1181                 :                 char* pszValue =
    1182              13 :                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1183              13 :                 if (poFeatureDefn->GetFieldDefn(iIndex)->GetType() == OFTReal)
    1184                 :                 {
    1185               0 :                     char* pszComma = strchr(pszValue, ',');
    1186               0 :                     if (pszComma)
    1187               0 :                         *pszComma = '.';
    1188                 :                 }
    1189              13 :                 VSIFPrintfL(fp, " %s=\"%s\"", pszAttributeName, pszValue);
    1190              13 :                 CPLFree(pszValue);
    1191                 :             }
    1192              14 :             CPLFree(pszFieldName);
    1193                 :         }
    1194                 :     }
    1195                 : 
    1196               8 :     char* pszFieldName = CPLStrdup(CPLSPrintf("%s%s", pszElementName, pszNumber));
    1197               8 :     int iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1198               8 :     if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1199                 :     {
    1200               6 :         VSIFPrintfL(fp, ">");
    1201                 : 
    1202                 :         char* pszValue =
    1203               6 :                 OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1204               6 :         if (poFeatureDefn->GetFieldDefn(iIndex)->GetType() == OFTReal)
    1205                 :         {
    1206               0 :             char* pszComma = strchr(pszValue, ',');
    1207               0 :             if (pszComma)
    1208               0 :                 *pszComma = '.';
    1209                 :         }
    1210               6 :         VSIFPrintfL(fp, "%s", pszValue);
    1211               6 :         CPLFree(pszValue);
    1212                 : 
    1213               6 :         VSIFPrintfL(fp, "</%s>\n", pszElementName);
    1214                 :     }
    1215                 :     else
    1216                 :     {
    1217               2 :         VSIFPrintfL(fp, "/>\n");
    1218                 :     }
    1219               8 :     CPLFree(pszFieldName);
    1220               8 : }
    1221                 : 
    1222                 : /************************************************************************/
    1223                 : /*                           CreateFeature()                            */
    1224                 : /************************************************************************/
    1225                 : 
    1226              15 : OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
    1227                 : 
    1228                 : {
    1229              15 :     FILE* fp = poDS->GetOutputFP();
    1230              15 :     if (fp == NULL)
    1231               0 :         return CE_Failure;
    1232                 : 
    1233              15 :     nNextFID ++;
    1234                 : 
    1235                 :     /* Verify that compulsory feeds are set. Otherwise put some default value in them */
    1236              15 :     if (eFormat == GEORSS_RSS)
    1237                 :     {
    1238              14 :         int iFieldTitle = poFeatureDefn->GetFieldIndex( "title" );
    1239              14 :         int iFieldDescription = poFeatureDefn->GetFieldIndex( "description" );
    1240                 : 
    1241              14 :         VSIFPrintfL(fp, "    <item>\n");
    1242                 : 
    1243              14 :         if ((iFieldTitle == -1 || poFeature->IsFieldSet( iFieldTitle ) == FALSE) &&
    1244                 :             (iFieldDescription == -1 || poFeature->IsFieldSet( iFieldDescription ) == FALSE))
    1245                 :         {
    1246               2 :             VSIFPrintfL(fp, "      <title>Feature %d</title>\n", nNextFID);
    1247                 :         }
    1248                 :     }
    1249                 :     else
    1250                 :     {
    1251               1 :         VSIFPrintfL(fp, "    <entry>\n");
    1252                 : 
    1253               1 :         int iFieldId = poFeatureDefn->GetFieldIndex( "id" );
    1254               1 :         int iFieldTitle = poFeatureDefn->GetFieldIndex( "title" );
    1255               1 :         int iFieldUpdated = poFeatureDefn->GetFieldIndex( "updated" );
    1256                 : 
    1257               1 :         if (iFieldId == -1 || poFeature->IsFieldSet( iFieldId ) == FALSE)
    1258                 :         {
    1259               0 :             VSIFPrintfL(fp, "      <id>Feature %d</id>\n", nNextFID);
    1260                 :         }
    1261                 : 
    1262               1 :         if (iFieldTitle == -1 || poFeature->IsFieldSet( iFieldTitle ) == FALSE)
    1263                 :         {
    1264               0 :             VSIFPrintfL(fp, "      <title>Title for feature %d</title>\n", nNextFID);
    1265                 :         }
    1266                 : 
    1267               1 :         if (iFieldUpdated == -1 || poFeature->IsFieldSet(iFieldUpdated ) == FALSE)
    1268                 :         {
    1269               0 :             VSIFPrintfL(fp, "      <updated>2009-01-01T00:00:00Z</updated>\n");
    1270                 :         }
    1271                 :     }
    1272                 : 
    1273              15 :     int nFieldCount = poFeatureDefn->GetFieldCount();
    1274              15 :     int* pbUsed = (int*)CPLCalloc(sizeof(int), nFieldCount);
    1275                 : 
    1276             146 :     for(int i = 0; i < nFieldCount; i ++)
    1277                 :     {
    1278             131 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
    1279             131 :         const char* pszName = poFieldDefn->GetNameRef();
    1280                 : 
    1281             131 :         if ( ! poFeature->IsFieldSet( i ) )
    1282              48 :             continue;
    1283                 : 
    1284                 :         char* pszElementName;
    1285                 :         char* pszNumber;
    1286                 :         char* pszAttributeName;
    1287              83 :         OGRGeoRSSLayerSplitComposedField(pszName, &pszElementName, &pszNumber, &pszAttributeName);
    1288                 : 
    1289              83 :         int bWillSkip = FALSE;
    1290                 :         /* Handle Atom entries with elements with sub-elements like */
    1291                 :         /* <author><name>...</name><uri>...</uri></author */
    1292              83 :         if (eFormat == GEORSS_ATOM)
    1293                 :         {
    1294                 :             unsigned int k;
    1295              52 :             for (k=0;apszAllowedATOMFieldNamesWithSubElements[k] != NULL;k++)
    1296                 :             {
    1297              37 :                 if (strcmp(pszElementName, apszAllowedATOMFieldNamesWithSubElements[k]) == 0 &&
    1298                 :                     pszAttributeName != NULL)
    1299                 :                 {
    1300               5 :                     bWillSkip = TRUE;
    1301               5 :                     if (pbUsed[i])
    1302               2 :                         break;
    1303                 : 
    1304               3 :                     VSIFPrintfL(fp, "      <%s>\n", pszElementName);
    1305                 : 
    1306                 :                     int j;
    1307              23 :                     for(j = i; j < nFieldCount; j ++)
    1308                 :                     {
    1309              20 :                         poFieldDefn = poFeatureDefn->GetFieldDefn( j );
    1310              20 :                         if ( ! poFeature->IsFieldSet( j ) )
    1311               0 :                             continue;
    1312                 : 
    1313                 :                         char* pszElementName2;
    1314                 :                         char* pszNumber2;
    1315                 :                         char* pszAttributeName2;
    1316                 :                         OGRGeoRSSLayerSplitComposedField(poFieldDefn->GetNameRef(),
    1317              20 :                                 &pszElementName2, &pszNumber2, &pszAttributeName2);
    1318                 : 
    1319              20 :                         if (strcmp(pszElementName2, pszElementName) == 0 &&
    1320                 :                             strcmp(pszNumber, pszNumber2) == 0 && pszAttributeName2 != NULL)
    1321                 :                         {
    1322               5 :                             pbUsed[j] = TRUE;
    1323                 : 
    1324                 :                             char* pszValue =
    1325               5 :                                     OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( j ));
    1326               5 :                             if (poFeatureDefn->GetFieldDefn(j)->GetType() == OFTReal)
    1327                 :                             {
    1328               0 :                                 char* pszComma = strchr(pszValue, ',');
    1329               0 :                                 if (pszComma)
    1330               0 :                                     *pszComma = '.';
    1331                 :                             }
    1332               5 :                             VSIFPrintfL(fp, "        <%s>%s</%s>\n", pszAttributeName2, pszValue, pszAttributeName2);
    1333               5 :                             CPLFree(pszValue);
    1334                 :                         }
    1335              20 :                         CPLFree(pszElementName2);
    1336              20 :                         CPLFree(pszNumber2);
    1337              20 :                         CPLFree(pszAttributeName2);
    1338                 :                     }
    1339                 : 
    1340               3 :                     VSIFPrintfL(fp, "      </%s>\n", pszElementName);
    1341                 : 
    1342               3 :                     break;
    1343                 :                 }
    1344                 :             }
    1345                 :         }
    1346                 : 
    1347              83 :         if (bWillSkip)
    1348                 :         {
    1349                 :             /* Do nothing */
    1350                 :         }
    1351              90 :         else if (eFormat == GEORSS_RSS &&
    1352                 :             strcmp(pszName, "pubDate") == 0)
    1353                 :         {
    1354                 :             int year, month, day, hour, minute, second, TZFlag;
    1355              12 :             if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
    1356                 :                                                     &hour, &minute, &second, &TZFlag))
    1357                 :             {
    1358              12 :                 char* pszDate = OGRGetRFC822DateTime(year, month, day, hour, minute, second, TZFlag);
    1359                 :                 VSIFPrintfL(fp, "      <%s>%s</%s>\n",
    1360              12 :                         pszName, pszDate, pszName);
    1361              12 :                 CPLFree(pszDate);
    1362                 :             }
    1363                 :         }
    1364              68 :         else if (eFormat == GEORSS_ATOM &&
    1365                 :                  (strcmp(pszName, "updated") == 0 || strcmp(pszName, "published") == 0))
    1366                 :         {
    1367                 :             int year, month, day, hour, minute, second, TZFlag;
    1368               2 :             if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
    1369                 :                                                     &hour, &minute, &second, &TZFlag))
    1370                 :             {
    1371               2 :                 char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
    1372                 :                 VSIFPrintfL(fp, "      <%s>%s</%s>\n",
    1373               2 :                         pszName, pszDate, pszName);
    1374               2 :                 CPLFree(pszDate);
    1375                 :             }
    1376                 :         }
    1377              64 :         else if (strcmp(pszName, "dc_date") == 0)
    1378                 :         {
    1379                 :             int year, month, day, hour, minute, second, TZFlag;
    1380               0 :             if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
    1381                 :                                                     &hour, &minute, &second, &TZFlag))
    1382                 :             {
    1383               0 :                 char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
    1384                 :                 VSIFPrintfL(fp, "      <%s>%s</%s>\n",
    1385               0 :                         "dc:date", pszDate, "dc:date");
    1386               0 :                 CPLFree(pszDate);
    1387                 :             }
    1388                 :         }
    1389                 :         /* RSS fields with content and attributes */
    1390              76 :         else if (eFormat == GEORSS_RSS &&
    1391                 :                  (strcmp(pszElementName, "category") == 0 ||
    1392                 :                   strcmp(pszElementName, "guid") == 0 ||
    1393                 :                   strcmp(pszElementName, "source") == 0 ))
    1394                 :         {
    1395              12 :             if (pszAttributeName == NULL)
    1396                 :             {
    1397                 :                 OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
    1398               6 :                                        apszAllowedRSSFieldNames, poFeatureDefn, poFeature);
    1399                 :             }
    1400                 :         }
    1401                 :         /* RSS field with attribute only */
    1402              52 :         else if (eFormat == GEORSS_RSS &&
    1403                 :                  strcmp(pszElementName, "enclosure") == 0)
    1404                 :         {
    1405               0 :             if (pszAttributeName != NULL && strcmp(pszAttributeName, "url") == 0)
    1406                 :             {
    1407                 :                 OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
    1408               0 :                                        apszAllowedRSSFieldNames, poFeatureDefn, poFeature);
    1409                 :             }
    1410                 :         }
    1411                 :         /* ATOM fields with attribute only */
    1412              59 :         else if (eFormat == GEORSS_ATOM &&
    1413                 :                  (strcmp(pszElementName, "category") == 0 || strcmp(pszElementName, "link") == 0))
    1414                 :         {
    1415               7 :             if (pszAttributeName != NULL &&
    1416                 :                 ((strcmp(pszElementName, "category") == 0 && strcmp(pszAttributeName, "term") == 0) ||
    1417                 :                  (strcmp(pszElementName, "link") == 0 && strcmp(pszAttributeName, "href") == 0)))
    1418                 :             {
    1419                 :                 OGRGeoRSSLayerWriteSimpleElement(fp, pszElementName, pszNumber,
    1420               2 :                                        apszAllowedATOMFieldNames, poFeatureDefn, poFeature);
    1421                 :             }
    1422                 :         }
    1423              49 :         else if (eFormat == GEORSS_ATOM &&
    1424                 :                  (strncmp(pszName, "content", strlen("content")) == 0 ||
    1425                 :                   strncmp(pszName, "summary", strlen("summary")) == 0))
    1426                 :         {
    1427                 :             char* pszFieldName;
    1428                 :             int iIndex;
    1429               4 :             if (strchr(pszName, '_') == NULL)
    1430                 :             {
    1431               1 :                 VSIFPrintfL(fp, "      <%s", pszName);
    1432                 : 
    1433               1 :                 int bIsXHTML = FALSE;
    1434               1 :                 pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "type"));
    1435               1 :                 iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1436               1 :                 if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1437                 :                 {
    1438               1 :                     bIsXHTML = strcmp(poFeature->GetFieldAsString( iIndex ), "xhtml") == 0;
    1439                 :                     char* pszValue =
    1440               1 :                             OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1441               1 :                     VSIFPrintfL(fp, " %s=\"%s\"", "type", pszValue);
    1442               1 :                     CPLFree(pszValue);
    1443                 :                 }
    1444               1 :                 CPLFree(pszFieldName);
    1445                 : 
    1446               1 :                 pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_lang"));
    1447               1 :                 iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1448               1 :                 if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1449                 :                 {
    1450                 :                     char* pszValue =
    1451               1 :                             OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1452               1 :                     VSIFPrintfL(fp, " %s=\"%s\"", "xml:lang", pszValue);
    1453               1 :                     CPLFree(pszValue);
    1454                 :                 }
    1455               1 :                 CPLFree(pszFieldName);
    1456                 : 
    1457               1 :                 pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_base"));
    1458               1 :                 iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1459               1 :                 if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1460                 :                 {
    1461                 :                     char* pszValue =
    1462               1 :                             OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1463               1 :                     VSIFPrintfL(fp, " %s=\"%s\"", "xml:base", pszValue);
    1464               1 :                     CPLFree(pszValue);
    1465                 :                 }
    1466               1 :                 CPLFree(pszFieldName);
    1467                 : 
    1468               1 :                 VSIFPrintfL(fp, ">");
    1469               1 :                 if (bIsXHTML)
    1470               1 :                     VSIFPrintfL(fp, "%s", poFeature->GetFieldAsString(i));
    1471                 :                 else
    1472                 :                 {
    1473                 :                     char* pszValue =
    1474               0 :                             OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
    1475               0 :                     VSIFPrintfL(fp, "%s", pszValue);
    1476               0 :                     CPLFree(pszValue);
    1477                 :                 }
    1478               1 :                 VSIFPrintfL(fp, "      </%s>\n", pszName);
    1479                 :             }
    1480                 :         }
    1481              41 :         else if (strncmp(pszName, "dc_subject", strlen("dc_subject")) == 0)
    1482                 :         {
    1483                 :             char* pszFieldName;
    1484                 :             int iIndex;
    1485               0 :             if (strchr(pszName+strlen("dc_subject"), '_') == NULL)
    1486                 :             {
    1487               0 :                 VSIFPrintfL(fp, "      <%s", "dc:subject");
    1488                 : 
    1489               0 :                 pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszName, "xml_lang"));
    1490               0 :                 iIndex = poFeatureDefn->GetFieldIndex(pszFieldName);
    1491               0 :                 if (iIndex != -1 && poFeature->IsFieldSet( iIndex ))
    1492                 :                 {
    1493                 :                     char* pszValue =
    1494               0 :                             OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
    1495               0 :                     VSIFPrintfL(fp, " %s=\"%s\"", "xml:lang", pszValue);
    1496               0 :                     CPLFree(pszValue);
    1497                 :                 }
    1498               0 :                 CPLFree(pszFieldName);
    1499                 : 
    1500                 :                 char* pszValue =
    1501               0 :                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
    1502               0 :                 VSIFPrintfL(fp, ">%s</%s>\n", pszValue, "dc:subject");
    1503               0 :                 CPLFree(pszValue);
    1504                 :             }
    1505                 :         }
    1506                 :         else
    1507                 :         {
    1508              41 :             char* pszTagName = CPLStrdup(pszName);
    1509              41 :             if (IsStandardField(pszName) == FALSE)
    1510                 :             {
    1511                 :                 int j;
    1512               3 :                 int nCountUnderscore = 0;
    1513              29 :                 for(j=0;pszTagName[j] != 0;j++)
    1514                 :                 {
    1515              26 :                     if (pszTagName[j] == '_')
    1516                 :                     {
    1517               2 :                         if (nCountUnderscore == 0)
    1518               2 :                             pszTagName[j] = ':';
    1519               2 :                         nCountUnderscore ++;
    1520                 :                     }
    1521              24 :                     else if (pszTagName[j] == ' ')
    1522               0 :                         pszTagName[j] = '_';
    1523                 :                 }
    1524               3 :                 if (nCountUnderscore == 0)
    1525                 :                 {
    1526               1 :                     char* pszTemp = CPLStrdup(CPLSPrintf("ogr:%s", pszTagName));
    1527               1 :                     CPLFree(pszTagName);
    1528               1 :                     pszTagName = pszTemp;
    1529                 :                 }
    1530                 :             }
    1531                 :             char* pszValue =
    1532              41 :                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
    1533              41 :             if (poFeatureDefn->GetFieldDefn(i)->GetType() == OFTReal)
    1534                 :             {
    1535               0 :                 char* pszComma = strchr(pszValue, ',');
    1536               0 :                 if (pszComma)
    1537               0 :                     *pszComma = '.';
    1538                 :             }
    1539              41 :             VSIFPrintfL(fp, "      <%s>%s</%s>\n", pszTagName, pszValue, pszTagName);
    1540              41 :             CPLFree(pszValue);
    1541              41 :             CPLFree(pszTagName);
    1542                 :         }
    1543                 : 
    1544              83 :         CPLFree(pszElementName);
    1545              83 :         CPLFree(pszNumber);
    1546              83 :         CPLFree(pszAttributeName);
    1547                 :     }
    1548                 : 
    1549              15 :     CPLFree(pbUsed);
    1550                 : 
    1551              15 :     OGRGeoRSSGeomDialect eGeomDialect = poDS->GetGeomDialect();
    1552              15 :     OGRGeometry* poGeom = poFeature->GetGeometryRef();
    1553              15 :     if ( poGeom != NULL && !poGeom->IsEmpty() )
    1554                 :     {
    1555              13 :         char* pszURN = NULL;
    1556              13 :         int bSwapCoordinates = FALSE;
    1557              13 :         if (eGeomDialect == GEORSS_GML)
    1558                 :         {
    1559               5 :             if (poSRS != NULL)
    1560                 :             {
    1561               1 :                 const char* pszAuthorityName = poSRS->GetAuthorityName(NULL);
    1562               1 :                 const char* pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
    1563               2 :                 if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") &&
    1564                 :                     pszAuthorityCode != NULL)
    1565                 :                 {
    1566               1 :                     if (!EQUAL(pszAuthorityCode, "4326"))
    1567               1 :                         pszURN = CPLStrdup(CPLSPrintf("urn:ogc:def:crs:EPSG::%s", pszAuthorityCode));
    1568                 : 
    1569                 :                     /* In case the SRS is a geographic SRS and that we have no axis */
    1570                 :                     /* defintion, we assume that the order is lon/lat */
    1571               1 :                     const char* pszAxisName = poSRS->GetAxis(NULL, 0, NULL);
    1572               1 :                     if (poSRS->IsGeographic() &&
    1573                 :                         (pszAxisName == NULL || EQUALN(pszAxisName, "Lon", 3)))
    1574                 :                     {
    1575               0 :                         bSwapCoordinates = TRUE;
    1576                 :                     }
    1577                 :                 }
    1578                 :                 else
    1579                 :                 {
    1580                 :                     static int bOnce = FALSE;
    1581               0 :                     if (!bOnce)
    1582                 :                     {
    1583               0 :                         bOnce = TRUE;
    1584               0 :                         CPLError(CE_Warning, CPLE_AppDefined, "Could not translate SRS into GML urn");
    1585                 :                     }
    1586                 :                 }
    1587                 :             }
    1588                 :             else
    1589                 :             {
    1590               4 :                 bSwapCoordinates = TRUE;
    1591                 :             }
    1592                 :         }
    1593                 : 
    1594                 :         char szCoord[75];
    1595              13 :         switch( wkbFlatten(poGeom->getGeometryType()) )
    1596                 :         {
    1597                 :             case wkbPoint:
    1598                 :             {
    1599               4 :                 OGRPoint* poPoint = (OGRPoint*)poGeom;
    1600               4 :                 double x = poPoint->getX();
    1601               4 :                 double y = poPoint->getY();
    1602               4 :                 if (eGeomDialect == GEORSS_GML)
    1603                 :                 {
    1604               2 :                     VSIFPrintfL(fp, "      <georss:where><gml:Point");
    1605               2 :                     if (pszURN != NULL)
    1606               1 :                         VSIFPrintfL(fp, " srsName=\"%s\"", pszURN);
    1607               2 :                     if (poGeom->getCoordinateDimension() == 3)
    1608                 :                     {
    1609                 :                         OGRMakeWktCoordinate(szCoord, (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y,
    1610               0 :                                              poPoint->getZ(), 3);
    1611               0 :                         VSIFPrintfL(fp, " srsDimension=\"3\"><gml:pos>%s", szCoord);
    1612                 :                     }
    1613                 :                     else
    1614                 :                     {
    1615                 :                         OGRMakeWktCoordinate(szCoord, (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y,
    1616               2 :                                              0, 2);
    1617               2 :                         VSIFPrintfL(fp, "><gml:pos>%s", szCoord);
    1618                 :                     }
    1619               2 :                     VSIFPrintfL(fp, "</gml:pos></gml:Point></georss:where>\n");
    1620                 :                 }
    1621               2 :                 else if (eGeomDialect == GEORSS_SIMPLE)
    1622                 :                 {
    1623               1 :                     OGRMakeWktCoordinate(szCoord, y, x, 0, 2);
    1624               1 :                     VSIFPrintfL(fp, "      <georss:point>%s</georss:point>\n", szCoord);
    1625                 :                 }
    1626               1 :                 else if (eGeomDialect == GEORSS_W3C_GEO)
    1627                 :                 {
    1628               1 :                     OGRFormatDouble( szCoord, sizeof(szCoord), y, '.' );
    1629               1 :                     VSIFPrintfL(fp, "      <geo:lat>%s</geo:lat>\n", szCoord);
    1630               1 :                     OGRFormatDouble( szCoord, sizeof(szCoord), x, '.' );
    1631               1 :                     VSIFPrintfL(fp, "      <geo:long>%s</geo:long>\n", szCoord);
    1632                 :                 }
    1633               4 :                 break;
    1634                 :             }
    1635                 : 
    1636                 :             case wkbLineString:
    1637                 :             {
    1638               3 :                 OGRLineString* poLineString = (OGRLineString*)poGeom;
    1639               3 :                 if (eGeomDialect == GEORSS_GML)
    1640                 :                 {
    1641               1 :                     VSIFPrintfL(fp, "      <georss:where><gml:LineString");
    1642               1 :                     if (pszURN != NULL)
    1643               0 :                         VSIFPrintfL(fp, " srsName=\"%s\"", pszURN);
    1644               1 :                     VSIFPrintfL(fp, "><gml:posList>\n");
    1645               1 :                     int n = poLineString->getNumPoints();
    1646               4 :                     for(int i=0;i<n;i++)
    1647                 :                     {
    1648               3 :                         double x = poLineString->getX(i);
    1649               3 :                         double y = poLineString->getY(i);
    1650                 :                         OGRMakeWktCoordinate(szCoord, (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y,
    1651               3 :                                              0, 2);
    1652               3 :                         VSIFPrintfL(fp, "%s ", szCoord);
    1653                 :                     }
    1654               1 :                     VSIFPrintfL(fp, "</gml:posList></gml:LineString></georss:where>\n");
    1655                 :                 }
    1656               2 :                 else if (eGeomDialect == GEORSS_SIMPLE)
    1657                 :                 {
    1658               1 :                     VSIFPrintfL(fp, "      <georss:line>\n");
    1659               1 :                     int n = poLineString->getNumPoints();
    1660               4 :                     for(int i=0;i<n;i++)
    1661                 :                     {
    1662               3 :                         double x = poLineString->getX(i);
    1663               3 :                         double y = poLineString->getY(i);
    1664               3 :                         OGRMakeWktCoordinate(szCoord, y, x, 0, 2);
    1665               3 :                         VSIFPrintfL(fp, "%s ", szCoord);
    1666                 :                     }
    1667               1 :                     VSIFPrintfL(fp, "</georss:line>\n");
    1668                 :                 }
    1669                 :                 else
    1670                 :                 {
    1671                 :                     /* Not supported */
    1672                 :                 }
    1673               3 :                 break;
    1674                 :             }
    1675                 : 
    1676                 :             case wkbPolygon:
    1677                 :             {
    1678               6 :                 OGRPolygon* poPolygon = (OGRPolygon*)poGeom;
    1679               6 :                 OGRLineString* poLineString = poPolygon->getExteriorRing();
    1680               6 :                 if (poLineString == NULL)
    1681               0 :                     break;
    1682                 : 
    1683               6 :                 if (eGeomDialect == GEORSS_GML)
    1684                 :                 {
    1685               2 :                     VSIFPrintfL(fp, "      <georss:where><gml:Polygon");
    1686               2 :                     if (pszURN != NULL)
    1687               0 :                         VSIFPrintfL(fp, " srsName=\"%s\"", pszURN);
    1688               2 :                     VSIFPrintfL(fp, "><gml:exterior><gml:LinearRing><gml:posList>\n");
    1689               2 :                     int n = poLineString->getNumPoints();
    1690              12 :                     for(int i=0;i<n;i++)
    1691                 :                     {
    1692              10 :                         double x = poLineString->getX(i);
    1693              10 :                         double y = poLineString->getY(i);
    1694                 :                         OGRMakeWktCoordinate(szCoord, (bSwapCoordinates) ? y : x, (bSwapCoordinates) ? x : y,
    1695              10 :                                              0, 2);
    1696              10 :                         VSIFPrintfL(fp, "%s ", szCoord);
    1697                 :                     }
    1698               2 :                     VSIFPrintfL(fp, "</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></georss:where>\n");
    1699                 :                 }
    1700               4 :                 else if (eGeomDialect == GEORSS_SIMPLE)
    1701                 :                 {
    1702               2 :                     VSIFPrintfL(fp, "      <georss:polygon>\n");
    1703               2 :                     int n = poLineString->getNumPoints();
    1704              12 :                     for(int i=0;i<n;i++)
    1705                 :                     {
    1706              10 :                         double x = poLineString->getX(i);
    1707              10 :                         double y = poLineString->getY(i);
    1708              10 :                         OGRMakeWktCoordinate(szCoord, y, x, 0, 2);
    1709              10 :                         VSIFPrintfL(fp, "%s ", szCoord);
    1710                 :                     }
    1711               2 :                     VSIFPrintfL(fp, "</georss:polygon>\n");
    1712                 :                 }
    1713                 :                 else
    1714                 :                 {
    1715                 :                     /* Not supported */
    1716                 :                 }
    1717                 :                 break;
    1718                 :             }
    1719                 : 
    1720                 :             default:
    1721                 :                 /* Not supported */
    1722                 :                 break;
    1723                 :         }
    1724              13 :         CPLFree(pszURN);
    1725                 :     }
    1726                 : 
    1727              15 :     if (eFormat == GEORSS_RSS)
    1728              14 :         VSIFPrintfL(fp, "    </item>\n");
    1729                 :     else
    1730               1 :         VSIFPrintfL(fp, "    </entry>\n");
    1731                 : 
    1732              15 :     return OGRERR_NONE;
    1733                 : }
    1734                 : 
    1735                 : 
    1736                 : 
    1737                 : /************************************************************************/
    1738                 : /*                            CreateField()                             */
    1739                 : /************************************************************************/
    1740                 : 
    1741              50 : OGRErr OGRGeoRSSLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
    1742                 : 
    1743                 : {
    1744              50 :     const char* pszName = poFieldDefn->GetNameRef();
    1745              50 :     if (((eFormat == GEORSS_RSS && strcmp(pszName, "pubDate") == 0) ||
    1746                 :          (eFormat == GEORSS_ATOM && (strcmp(pszName, "updated") == 0 ||
    1747                 :                                      strcmp(pszName, "published") == 0 )) ||
    1748                 :           strcmp(pszName, "dc:date") == 0) &&
    1749                 :         poFieldDefn->GetType() != OFTDateTime)
    1750                 :     {
    1751               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s", pszName);
    1752               0 :         return OGRERR_FAILURE;
    1753                 :     }
    1754                 : 
    1755             351 :     for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
    1756                 :     {
    1757             301 :         if (strcmp(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    1758                 :                    pszName ) == 0)
    1759                 :         {
    1760               0 :             return OGRERR_FAILURE;
    1761                 :         }
    1762                 :     }
    1763                 : 
    1764              50 :     if (IsStandardField(pszName))
    1765                 :     {
    1766              47 :         poFeatureDefn->AddFieldDefn( poFieldDefn );
    1767              47 :         return OGRERR_NONE;
    1768                 :     }
    1769                 : 
    1770               3 :     if (poDS->GetUseExtensions() == FALSE)
    1771                 :     {
    1772                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1773                 :                 "Field of name '%s' is not supported in %s schema. "
    1774                 :                  "Use USE_EXTENSIONS creation option to allow use of extensions.",
    1775               0 :                  pszName, (eFormat == GEORSS_RSS) ? "RSS" : "ATOM");
    1776               0 :         return OGRERR_FAILURE;
    1777                 :     }
    1778                 :     else
    1779                 :     {
    1780               3 :         poFeatureDefn->AddFieldDefn( poFieldDefn );
    1781               3 :         return OGRERR_NONE;
    1782                 :     }
    1783                 : }
    1784                 : 
    1785                 : #ifdef HAVE_EXPAT
    1786                 : 
    1787             276 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData, const char *pszName, const char **ppszAttr)
    1788                 : {
    1789             276 :     ((OGRGeoRSSLayer*)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
    1790             276 : }
    1791                 : 
    1792             276 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData, const char *pszName)
    1793                 : {
    1794             276 :     ((OGRGeoRSSLayer*)pUserData)->endElementLoadSchemaCbk(pszName);
    1795             276 : }
    1796                 : 
    1797             792 : static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data, int nLen)
    1798                 : {
    1799             792 :     ((OGRGeoRSSLayer*)pUserData)->dataHandlerLoadSchemaCbk(data, nLen);
    1800             792 : }
    1801                 : 
    1802                 : 
    1803                 : /************************************************************************/
    1804                 : /*                       LoadSchema()                         */
    1805                 : /************************************************************************/
    1806                 : 
    1807                 : /** This function parses the whole file to detect the fields */
    1808              18 : void OGRGeoRSSLayer::LoadSchema()
    1809                 : {
    1810              18 :     if (bHasReadSchema)
    1811               0 :         return;
    1812                 : 
    1813              18 :     bHasReadSchema = TRUE;
    1814                 : 
    1815              18 :     if (fpGeoRSS == NULL)
    1816               6 :         return;
    1817                 : 
    1818              12 :     oSchemaParser = OGRCreateExpatXMLParser();
    1819              12 :     XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk, ::endElementLoadSchemaCbk);
    1820              12 :     XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk);
    1821              12 :     XML_SetUserData(oSchemaParser, this);
    1822                 : 
    1823              12 :     VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
    1824                 : 
    1825              12 :     bInFeature = FALSE;
    1826              12 :     currentDepth = 0;
    1827              12 :     currentFieldDefn = NULL;
    1828              12 :     pszSubElementName = NULL;
    1829              12 :     pszSubElementValue = NULL;
    1830              12 :     nSubElementValueLen = 0;
    1831              12 :     bSameSRS = TRUE;
    1832              12 :     CPLFree(pszGMLSRSName);
    1833              12 :     pszGMLSRSName = NULL;
    1834              12 :     eGeomType = wkbUnknown;
    1835              12 :     bFoundGeom = FALSE;
    1836              12 :     bInTagWithSubTag = FALSE;
    1837              12 :     pszTagWithSubTag = NULL;
    1838              12 :     bStopParsing = FALSE;
    1839              12 :     nWithoutEventCounter = 0;
    1840              12 :     nTotalFeatureCount = 0;
    1841              12 :     setOfFoundFields = NULL;
    1842                 : 
    1843                 :     char aBuf[BUFSIZ];
    1844                 :     int nDone;
    1845              12 :     do
    1846                 :     {
    1847              12 :         nDataHandlerCounter = 0;
    1848              12 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fpGeoRSS );
    1849              12 :         nDone = VSIFEofL(fpGeoRSS);
    1850              12 :         if (XML_Parse(oSchemaParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
    1851                 :         {
    1852                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1853                 :                      "XML parsing of GeoRSS file failed : %s at line %d, column %d",
    1854                 :                      XML_ErrorString(XML_GetErrorCode(oSchemaParser)),
    1855                 :                      (int)XML_GetCurrentLineNumber(oSchemaParser),
    1856               0 :                      (int)XML_GetCurrentColumnNumber(oSchemaParser));
    1857               0 :             bStopParsing = TRUE;
    1858                 :         }
    1859              12 :         nWithoutEventCounter ++;
    1860                 :     } while (!nDone && !bStopParsing && nWithoutEventCounter < 10);
    1861                 : 
    1862              12 :     XML_ParserFree(oSchemaParser);
    1863                 : 
    1864              12 :     if (nWithoutEventCounter == 10)
    1865                 :     {
    1866                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1867               0 :                  "Too much data inside one element. File probably corrupted");
    1868               0 :         bStopParsing = TRUE;
    1869                 :     }
    1870                 : 
    1871              12 :     CPLAssert(poSRS == NULL);
    1872              12 :     if (bSameSRS && bFoundGeom)
    1873                 :     {
    1874               9 :         if (pszGMLSRSName == NULL)
    1875                 :         {
    1876               8 :             poSRS = new OGRSpatialReference();
    1877               8 :             poSRS->SetWellKnownGeogCS( "WGS84" ); /* no AXIS definition ! */
    1878                 :         }
    1879                 :         else
    1880                 :         {
    1881               1 :             poSRS = new OGRSpatialReference();
    1882               1 :             poSRS->importFromURN(pszGMLSRSName);
    1883                 :         }
    1884                 :     }
    1885                 : 
    1886              12 :     if (eGeomType != wkbUnknown)
    1887               5 :         poFeatureDefn->SetGeomType(eGeomType);
    1888                 : 
    1889              12 :     if (setOfFoundFields)
    1890              12 :         CPLHashSetDestroy(setOfFoundFields);
    1891              12 :     setOfFoundFields = NULL;
    1892              12 :     CPLFree(pszGMLSRSName);
    1893              12 :     pszGMLSRSName = NULL;
    1894              12 :     CPLFree(pszTagWithSubTag);
    1895              12 :     pszTagWithSubTag = NULL;
    1896                 : 
    1897              12 :     VSIFSeekL( fpGeoRSS, 0, SEEK_SET );
    1898                 : }
    1899                 : 
    1900                 : 
    1901                 : /************************************************************************/
    1902                 : /*                         OGRGeoRSSIsInt()                             */
    1903                 : /************************************************************************/
    1904                 : 
    1905               3 : static int OGRGeoRSSIsInt(const char* pszStr)
    1906                 : {
    1907                 :     int i;
    1908                 : 
    1909               6 :     while(*pszStr == ' ')
    1910               0 :         pszStr++;
    1911                 : 
    1912              12 :     for(i=0;pszStr[i];i++)
    1913                 :     {
    1914               9 :         if (pszStr[i] == '+' || pszStr[i] == '-')
    1915                 :         {
    1916               0 :             if (i != 0)
    1917               0 :                 return FALSE;
    1918                 :         }
    1919               9 :         else if (!(pszStr[i] >= '0' && pszStr[i] <= '9'))
    1920               0 :             return FALSE;
    1921                 :     }
    1922               3 :     return TRUE;
    1923                 : }
    1924                 : 
    1925                 : /************************************************************************/
    1926                 : /*                  startElementLoadSchemaCbk()                         */
    1927                 : /************************************************************************/
    1928                 : 
    1929             276 : void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr)
    1930                 : {
    1931             276 :     if (bStopParsing) return;
    1932                 : 
    1933             276 :     nWithoutEventCounter = 0;
    1934                 : 
    1935             303 :     if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
    1936                 :         (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
    1937                 :     {
    1938              27 :         bInFeature = TRUE;
    1939              27 :         featureDepth = currentDepth;
    1940                 : 
    1941              27 :         nTotalFeatureCount ++;
    1942                 : 
    1943              27 :         if (setOfFoundFields)
    1944              15 :             CPLHashSetDestroy(setOfFoundFields);
    1945              27 :         setOfFoundFields = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
    1946                 :     }
    1947             259 :     else if (bInTagWithSubTag && currentDepth == 3)
    1948                 :     {
    1949              10 :         char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
    1950              10 :         if (poFeatureDefn->GetFieldIndex(pszFieldName) == -1)
    1951                 :         {
    1952              10 :             OGRFieldDefn newFieldDefn(pszFieldName, OFTString);
    1953              10 :             poFeatureDefn->AddFieldDefn(&newFieldDefn);
    1954                 : 
    1955              10 :             if (poFeatureDefn->GetFieldCount() == 100)
    1956                 :             {
    1957                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1958               0 :                         "Too many fields. File probably corrupted");
    1959               0 :                 XML_StopParser(oSchemaParser, XML_FALSE);
    1960               0 :                 bStopParsing = TRUE;
    1961              10 :             }
    1962                 :         }
    1963              10 :         CPLFree(pszFieldName);
    1964                 :     }
    1965             239 :     else if (bInFeature && eFormat == GEORSS_ATOM &&
    1966                 :              currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
    1967                 :     {
    1968               6 :         CPLFree(pszTagWithSubTag);
    1969               6 :         pszTagWithSubTag = CPLStrdup(pszName);
    1970                 : 
    1971               6 :         int count = 1;
    1972              14 :         while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
    1973                 :         {
    1974               2 :             count ++;
    1975               2 :             CPLFree(pszTagWithSubTag);
    1976               2 :             pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
    1977                 :         }
    1978               6 :         CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszTagWithSubTag));
    1979                 : 
    1980               6 :         bInTagWithSubTag = TRUE;
    1981                 :     }
    1982             353 :     else if (bInFeature && currentDepth == featureDepth + 1 && !IS_GEO_ELEMENT(pszName))
    1983                 :     {
    1984             120 :         CPLFree(pszSubElementName);
    1985             120 :         pszSubElementName = CPLStrdup(pszName);
    1986                 : 
    1987             120 :         int count = 1;
    1988             247 :         while(CPLHashSetLookup(setOfFoundFields, pszSubElementName) != NULL)
    1989                 :         {
    1990               7 :             count ++;
    1991               7 :             CPLFree(pszSubElementName);
    1992               7 :             pszSubElementName = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
    1993                 :         }
    1994             120 :         CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszSubElementName));
    1995                 : 
    1996                 :         /* Create field definition for element */
    1997             120 :         char* pszCompatibleName = OGRGeoRSS_GetOGRCompatibleTagName(pszSubElementName);
    1998             120 :         int iField = poFeatureDefn->GetFieldIndex(pszCompatibleName);
    1999             120 :         if (iField >= 0)
    2000                 :         {
    2001              66 :             currentFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    2002                 :         }
    2003              54 :         else if ( ! (eFormat == GEORSS_RSS && strcmp(pszName, "enclosure") == 0) &&
    2004                 :                   ! (eFormat == GEORSS_ATOM && strcmp(pszName, "link") == 0) &&
    2005                 :                   ! (eFormat == GEORSS_ATOM && strcmp(pszName, "category") == 0))
    2006                 :         {
    2007                 :             OGRFieldType eFieldType;
    2008              60 :             if ((eFormat == GEORSS_RSS && strcmp(pszName, "pubDate") == 0) ||
    2009                 :                 (eFormat == GEORSS_ATOM && strcmp(pszName, "updated") == 0) ||
    2010                 :                 (eFormat == GEORSS_ATOM && strcmp(pszName, "published") == 0) ||
    2011                 :                 strcmp(pszName, "dc:date") == 0)
    2012              10 :                 eFieldType = OFTDateTime;
    2013                 :             else
    2014              40 :                 eFieldType = OFTInteger;
    2015                 : 
    2016              50 :             OGRFieldDefn newFieldDefn(pszCompatibleName, eFieldType);
    2017              50 :             poFeatureDefn->AddFieldDefn(&newFieldDefn);
    2018              50 :             currentFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
    2019                 : 
    2020              50 :             if (poFeatureDefn->GetFieldCount() == 100)
    2021                 :             {
    2022                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2023               0 :                         "Too many fields. File probably corrupted");
    2024               0 :                 XML_StopParser(oSchemaParser, XML_FALSE);
    2025               0 :                 bStopParsing = TRUE;
    2026              50 :             }
    2027                 :         }
    2028                 : 
    2029                 :         /* Create field definitions for attributes */
    2030             151 :         for(int i=0; ppszAttr[i] != NULL && ppszAttr[i+1] != NULL && !bStopParsing; i+= 2)
    2031                 :         {
    2032                 :             char* pszAttrCompatibleName =
    2033              31 :                     OGRGeoRSS_GetOGRCompatibleTagName(CPLSPrintf("%s_%s", pszSubElementName, ppszAttr[i]));
    2034              31 :             iField = poFeatureDefn->GetFieldIndex(pszAttrCompatibleName);
    2035                 :             OGRFieldDefn* currentAttrFieldDefn;
    2036              31 :             if (iField >= 0)
    2037                 :             {
    2038               0 :                 currentAttrFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    2039                 :             }
    2040                 :             else
    2041                 :             {
    2042              31 :                 OGRFieldDefn newFieldDefn(pszAttrCompatibleName, OFTInteger);
    2043              31 :                 poFeatureDefn->AddFieldDefn(&newFieldDefn);
    2044              31 :                 currentAttrFieldDefn = poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount() - 1);
    2045                 : 
    2046              31 :                 if (poFeatureDefn->GetFieldCount() == 100)
    2047                 :                 {
    2048                 :                     CPLError(CE_Failure, CPLE_AppDefined,
    2049               0 :                             "Too many fields. File probably corrupted");
    2050               0 :                     XML_StopParser(oSchemaParser, XML_FALSE);
    2051               0 :                     bStopParsing = TRUE;
    2052              31 :                 }
    2053                 :             }
    2054              31 :             if (currentAttrFieldDefn->GetType() == OFTInteger ||
    2055                 :                 currentAttrFieldDefn->GetType() == OFTReal)
    2056                 :             {
    2057              31 :                 char* pszRemainingStr = NULL;
    2058              31 :                 CPLStrtod(ppszAttr[i + 1], &pszRemainingStr);
    2059              33 :                 if (pszRemainingStr == NULL ||
    2060                 :                     *pszRemainingStr == 0 ||
    2061                 :                     *pszRemainingStr == ' ')
    2062                 :                 {
    2063               2 :                     if (currentAttrFieldDefn->GetType() == OFTInteger)
    2064                 :                     {
    2065               2 :                         if (OGRGeoRSSIsInt(ppszAttr[i + 1]) == FALSE)
    2066                 :                         {
    2067               0 :                             currentAttrFieldDefn->SetType(OFTReal);
    2068                 :                         }
    2069                 :                     }
    2070                 :                 }
    2071                 :                 else
    2072                 :                 {
    2073              29 :                     currentAttrFieldDefn->SetType(OFTString);
    2074                 :                 }
    2075                 :             }
    2076              31 :             CPLFree(pszAttrCompatibleName);
    2077                 :         }
    2078                 : 
    2079             120 :         CPLFree(pszCompatibleName);
    2080                 :     }
    2081             124 :     else if (strcmp(pszName, "georss:point") == 0 ||
    2082                 :              strcmp(pszName, "georss:line") == 0 ||
    2083                 :              strcmp(pszName, "geo:line") == 0 ||
    2084                 :              IS_LAT_ELEMENT(pszName) ||
    2085                 :              strcmp(pszName, "georss:polygon") == 0 ||
    2086                 :              strcmp(pszName, "georss:box") == 0)
    2087                 :     {
    2088              11 :         if (bSameSRS)
    2089                 :         {
    2090              11 :             if (pszGMLSRSName != NULL)
    2091               0 :                 bSameSRS = FALSE;
    2092                 :         }
    2093                 :     }
    2094             102 :     else if (strcmp(pszName, "gml:Point") == 0 ||
    2095                 :              strcmp(pszName, "gml:LineString") == 0 ||
    2096                 :              strcmp(pszName, "gml:Polygon") == 0 ||
    2097                 :              strcmp(pszName, "gml:Envelope") == 0)
    2098                 :     {
    2099              10 :         if (bSameSRS)
    2100                 :         {
    2101              10 :             int bFoundSRS = FALSE;
    2102              10 :             for(int i = 0; ppszAttr[i] != NULL; i+=2)
    2103                 :             {
    2104               1 :                 if (strcmp(ppszAttr[i], "srsName") == 0)
    2105                 :                 {
    2106               1 :                     bFoundSRS = TRUE;
    2107               1 :                     if (pszGMLSRSName != NULL)
    2108                 :                     {
    2109               0 :                         if (strcmp(pszGMLSRSName , ppszAttr[i+1]) != 0)
    2110               0 :                             bSameSRS = FALSE;
    2111                 :                     }
    2112                 :                     else
    2113               1 :                         pszGMLSRSName = CPLStrdup(ppszAttr[i+1]);
    2114               1 :                     break;
    2115                 :                 }
    2116                 :             }
    2117              10 :             if (!bFoundSRS && pszGMLSRSName != NULL)
    2118               0 :                 bSameSRS = FALSE;
    2119                 :         }
    2120                 :     }
    2121                 : 
    2122             276 :     if (!bInFeature || currentDepth >= featureDepth + 1)
    2123                 :     {
    2124             249 :         int nDimension = 2;
    2125             317 :         for(int i = 0; ppszAttr[i] != NULL; i+=2)
    2126                 :         {
    2127              68 :             if (strcmp(ppszAttr[i], "srsDimension") == 0)
    2128                 :             {
    2129               0 :                 nDimension = atoi(ppszAttr[i+1]);
    2130               0 :                 break;
    2131                 :             }
    2132                 :         }
    2133                 : 
    2134             249 :         OGRwkbGeometryType eFoundGeomType = wkbUnknown;
    2135             256 :         if (strcmp(pszName, "georss:point") == 0 ||
    2136                 :             IS_LAT_ELEMENT(pszName) ||
    2137                 :             strcmp(pszName, "gml:Point") == 0)
    2138                 :         {
    2139               7 :             eFoundGeomType = wkbPoint;
    2140                 :         }
    2141             247 :         else if (strcmp(pszName, "georss:line") == 0 ||
    2142                 :                 strcmp(pszName, "geo:line") == 0 ||
    2143                 :                 strcmp(pszName, "gml:LineString") == 0)
    2144                 :         {
    2145               5 :             eFoundGeomType = wkbLineString;
    2146                 :         }
    2147             237 :         else if (strcmp(pszName, "georss:polygon") == 0 ||
    2148                 :                  strcmp(pszName, "gml:Polygon") == 0 ||
    2149                 :                  strcmp(pszName, "gml:Envelope") == 0 ||
    2150                 :                  strcmp(pszName, "georss:box") == 0)
    2151                 :         {
    2152               9 :             eFoundGeomType = wkbPolygon;
    2153                 :         }
    2154                 : 
    2155             249 :         if (eFoundGeomType != wkbUnknown)
    2156                 :         {
    2157              21 :             if (!bFoundGeom)
    2158                 :             {
    2159               9 :                 eGeomType = eFoundGeomType;
    2160               9 :                 bFoundGeom = TRUE;
    2161                 :             }
    2162              12 :             else if (wkbFlatten(eGeomType) != eFoundGeomType)
    2163              12 :                 eGeomType = wkbUnknown;
    2164                 : 
    2165              21 :             if (nDimension == 3)
    2166               0 :                 eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
    2167                 :         }
    2168                 :     }
    2169                 : 
    2170             276 :     currentDepth++;
    2171                 : }
    2172                 : 
    2173                 : /************************************************************************/
    2174                 : /*                   endElementLoadSchemaCbk()                          */
    2175                 : /************************************************************************/
    2176                 : 
    2177             276 : void OGRGeoRSSLayer::endElementLoadSchemaCbk(const char *pszName)
    2178                 : {
    2179             276 :     if (bStopParsing) return;
    2180                 : 
    2181             276 :     nWithoutEventCounter = 0;
    2182                 : 
    2183             276 :     currentDepth--;
    2184                 : 
    2185             276 :     if (!bInFeature)
    2186              58 :         return;
    2187                 : 
    2188             245 :     if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
    2189                 :         (eFormat == GEORSS_RSS && currentDepth == 2 && strcmp(pszName, "item") == 0))
    2190                 :     {
    2191              27 :         bInFeature = FALSE;
    2192                 :     }
    2193             191 :     else if (bInFeature && eFormat == GEORSS_ATOM &&
    2194                 :                 currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
    2195                 :     {
    2196               6 :         bInTagWithSubTag = FALSE;
    2197                 :     }
    2198             185 :     else if (currentDepth == featureDepth + 1 && pszSubElementName)
    2199                 :     {
    2200                 :         /* Patch field type */
    2201             120 :         if (pszSubElementValue && nSubElementValueLen && currentFieldDefn)
    2202                 :         {
    2203             116 :             pszSubElementValue[nSubElementValueLen] = 0;
    2204             116 :             if (currentFieldDefn->GetType() == OFTInteger ||
    2205                 :                 currentFieldDefn->GetType() == OFTReal)
    2206                 :             {
    2207              40 :                 char* pszRemainingStr = NULL;
    2208              40 :                 CPLStrtod(pszSubElementValue, &pszRemainingStr);
    2209              41 :                 if (pszRemainingStr == NULL ||
    2210                 :                     *pszRemainingStr == 0 ||
    2211                 :                     *pszRemainingStr == ' ')
    2212                 :                 {
    2213               1 :                     if (currentFieldDefn->GetType() == OFTInteger)
    2214                 :                     {
    2215               1 :                         if (OGRGeoRSSIsInt(pszSubElementValue) == FALSE)
    2216                 :                         {
    2217               0 :                             currentFieldDefn->SetType(OFTReal);
    2218                 :                         }
    2219                 :                     }
    2220                 :                 }
    2221                 :                 else
    2222                 :                 {
    2223              39 :                     currentFieldDefn->SetType(OFTString);
    2224                 :                 }
    2225                 :             }
    2226                 :         }
    2227                 : 
    2228             120 :         CPLFree(pszSubElementName);
    2229             120 :         pszSubElementName = NULL;
    2230             120 :         CPLFree(pszSubElementValue);
    2231             120 :         pszSubElementValue = NULL;
    2232             120 :         nSubElementValueLen = 0;
    2233             120 :         currentFieldDefn = NULL;
    2234                 :     }
    2235                 : }
    2236                 : 
    2237                 : /************************************************************************/
    2238                 : /*                   dataHandlerLoadSchemaCbk()                         */
    2239                 : /************************************************************************/
    2240                 : 
    2241             792 : void OGRGeoRSSLayer::dataHandlerLoadSchemaCbk(const char *data, int nLen)
    2242                 : {
    2243             792 :     if (bStopParsing) return;
    2244                 : 
    2245             792 :     nDataHandlerCounter ++;
    2246             792 :     if (nDataHandlerCounter >= BUFSIZ)
    2247                 :     {
    2248               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
    2249               0 :         XML_StopParser(oSchemaParser, XML_FALSE);
    2250               0 :         bStopParsing = TRUE;
    2251               0 :         return;
    2252                 :     }
    2253                 : 
    2254             792 :     nWithoutEventCounter = 0;
    2255                 : 
    2256             792 :     if (pszSubElementName)
    2257                 :     {
    2258             125 :         char* pszNewSubElementValue = (char*) VSIRealloc(pszSubElementValue, nSubElementValueLen + nLen + 1);
    2259             125 :         if (pszNewSubElementValue == NULL)
    2260                 :         {
    2261               0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    2262               0 :             XML_StopParser(oSchemaParser, XML_FALSE);
    2263               0 :             bStopParsing = TRUE;
    2264               0 :             return;
    2265                 :         }
    2266             125 :         pszSubElementValue = pszNewSubElementValue;
    2267             125 :         memcpy(pszSubElementValue + nSubElementValueLen, data, nLen);
    2268             125 :         nSubElementValueLen += nLen;
    2269             125 :         if (nSubElementValueLen > 100000)
    2270                 :         {
    2271                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2272               0 :                      "Too much data inside one element. File probably corrupted");
    2273               0 :             XML_StopParser(oSchemaParser, XML_FALSE);
    2274               0 :             bStopParsing = TRUE;
    2275                 :         }
    2276                 :     }
    2277                 : }
    2278                 : #else
    2279                 : void OGRGeoRSSLayer::LoadSchema()
    2280                 : {
    2281                 : }
    2282                 : #endif
    2283                 : 
    2284                 : /************************************************************************/
    2285                 : /*                           TestCapability()                           */
    2286                 : /************************************************************************/
    2287                 : 
    2288               0 : int OGRGeoRSSLayer::TestCapability( const char * pszCap )
    2289                 : 
    2290                 : {
    2291               0 :     if( EQUAL(pszCap,OLCFastFeatureCount) )
    2292                 :         return !bWriteMode && bHasReadSchema &&
    2293               0 :                 m_poFilterGeom == NULL && m_poAttrQuery == NULL;
    2294                 : 
    2295               0 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    2296               0 :         return TRUE;
    2297                 : 
    2298               0 :     else if( EQUAL(pszCap,OLCSequentialWrite) )
    2299               0 :         return bWriteMode;
    2300                 :     else 
    2301               0 :         return FALSE;
    2302                 : }
    2303                 : 
    2304                 : /************************************************************************/
    2305                 : /*                          GetFeatureCount()                           */
    2306                 : /************************************************************************/
    2307                 : 
    2308               0 : int OGRGeoRSSLayer::GetFeatureCount( int bForce )
    2309                 : 
    2310                 : {
    2311               0 :     if (bWriteMode)
    2312                 :     {
    2313                 :         CPLError(CE_Failure, CPLE_NotSupported,
    2314               0 :                  "Cannot read features when writing a GeoRSS file");
    2315               0 :         return 0;
    2316                 :     }
    2317                 : 
    2318               0 :     if (!bHasReadSchema)
    2319               0 :         LoadSchema();
    2320                 : 
    2321               0 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
    2322               0 :         return OGRLayer::GetFeatureCount( bForce );
    2323                 :     else
    2324               0 :         return nTotalFeatureCount;
    2325                 : }

Generated by: LTP GCOV extension version 1.5