LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/georss - ogrgeorsslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1090 934 85.7 %
Date: 2012-04-28 Functions: 36 31 86.1 %

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

Generated by: LCOV version 1.7