LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/georss - ogrgeorsslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1071 935 87.3 %
Date: 2010-01-09 Functions: 34 32 94.1 %

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

Generated by: LCOV version 1.7