LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/georss - ogrgeorsslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1062 906 85.3 %
Date: 2013-03-30 Functions: 35 30 85.7 %

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

Generated by: LCOV version 1.7