LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/georss - ogrgeorssdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 191 229 83.4 %
Date: 2024-05-04 12:52:34 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoRSS Translator
       4             :  * Purpose:  Implements OGRGeoRSSDataSource class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "ogr_georss.h"
      31             : 
      32             : #include <cstdio>
      33             : #include <cstring>
      34             : 
      35             : #include "cpl_conv.h"
      36             : #include "cpl_csv.h"
      37             : #include "cpl_error.h"
      38             : #include "cpl_string.h"
      39             : #include "cpl_vsi.h"
      40             : #ifdef HAVE_EXPAT
      41             : #include "expat.h"
      42             : #endif
      43             : #include "ogr_core.h"
      44             : #include "ogr_expat.h"
      45             : #include "ogr_spatialref.h"
      46             : #include "ogrsf_frmts.h"
      47             : 
      48             : /************************************************************************/
      49             : /*                          OGRGeoRSSDataSource()                          */
      50             : /************************************************************************/
      51             : 
      52          55 : OGRGeoRSSDataSource::OGRGeoRSSDataSource()
      53             :     : pszName(nullptr), papoLayers(nullptr), nLayers(0), fpOutput(nullptr),
      54             : #ifdef HAVE_EXPAT
      55             :       validity(GEORSS_VALIDITY_UNKNOWN),
      56             : #endif
      57             :       eFormat(GEORSS_RSS), eGeomDialect(GEORSS_SIMPLE), bUseExtensions(false),
      58             :       bWriteHeaderAndFooter(true)
      59             : #ifdef HAVE_EXPAT
      60             :       ,
      61          55 :       oCurrentParser(nullptr), nDataHandlerCounter(0)
      62             : #endif
      63             : {
      64          55 : }
      65             : 
      66             : /************************************************************************/
      67             : /*                         ~OGRGeoRSSDataSource()                          */
      68             : /************************************************************************/
      69             : 
      70         110 : OGRGeoRSSDataSource::~OGRGeoRSSDataSource()
      71             : 
      72             : {
      73          55 :     if (fpOutput != nullptr)
      74             :     {
      75          39 :         if (bWriteHeaderAndFooter)
      76             :         {
      77          39 :             if (eFormat == GEORSS_RSS)
      78             :             {
      79          38 :                 VSIFPrintfL(fpOutput, "  </channel>\n");
      80          38 :                 VSIFPrintfL(fpOutput, "</rss>\n");
      81             :             }
      82             :             else
      83             :             {
      84           1 :                 VSIFPrintfL(fpOutput, "</feed>\n");
      85             :             }
      86             :         }
      87          39 :         VSIFCloseL(fpOutput);
      88             :     }
      89             : 
      90         123 :     for (int i = 0; i < nLayers; i++)
      91          68 :         delete papoLayers[i];
      92          55 :     CPLFree(papoLayers);
      93          55 :     CPLFree(pszName);
      94         110 : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           TestCapability()                           */
      98             : /************************************************************************/
      99             : 
     100          48 : int OGRGeoRSSDataSource::TestCapability(const char *pszCap)
     101             : 
     102             : {
     103          48 :     if (EQUAL(pszCap, ODsCCreateLayer))
     104          32 :         return TRUE;
     105             :     // else if( EQUAL(pszCap,ODsCDeleteLayer) )
     106             :     //    return FALSE;
     107          16 :     else if (EQUAL(pszCap, ODsCZGeometries))
     108           0 :         return TRUE;
     109             : 
     110          16 :     return FALSE;
     111             : }
     112             : 
     113             : /************************************************************************/
     114             : /*                              GetLayer()                              */
     115             : /************************************************************************/
     116             : 
     117          13 : OGRLayer *OGRGeoRSSDataSource::GetLayer(int iLayer)
     118             : 
     119             : {
     120          13 :     if (iLayer < 0 || iLayer >= nLayers)
     121           0 :         return nullptr;
     122             : 
     123          13 :     return papoLayers[iLayer];
     124             : }
     125             : 
     126             : /************************************************************************/
     127             : /*                           ICreateLayer()                             */
     128             : /************************************************************************/
     129             : 
     130             : OGRLayer *
     131          55 : OGRGeoRSSDataSource::ICreateLayer(const char *pszLayerName,
     132             :                                   const OGRGeomFieldDefn *poGeomFieldDefn,
     133             :                                   CSLConstList /*papszOptions*/)
     134             : {
     135          55 :     if (fpOutput == nullptr)
     136           0 :         return nullptr;
     137             : 
     138             :     const auto poSRS =
     139          55 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     140          55 :     if (poSRS != nullptr && eGeomDialect != GEORSS_GML)
     141             :     {
     142           1 :         OGRSpatialReference oSRS;
     143           1 :         oSRS.SetWellKnownGeogCS("WGS84");
     144           1 :         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     145           1 :         const char *const apszOptions[] = {
     146             :             "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
     147           1 :         if (!poSRS->IsSame(&oSRS, apszOptions))
     148             :         {
     149           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     150             :                      "For a non GML dialect, only WGS84 SRS is supported");
     151           1 :             return nullptr;
     152             :         }
     153             :     }
     154             : 
     155          54 :     nLayers++;
     156          54 :     papoLayers = static_cast<OGRGeoRSSLayer **>(
     157          54 :         CPLRealloc(papoLayers, nLayers * sizeof(OGRGeoRSSLayer *)));
     158          54 :     OGRSpatialReference *poSRSClone = nullptr;
     159          54 :     if (poSRS)
     160             :     {
     161           1 :         poSRSClone = poSRS->Clone();
     162           1 :         poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     163             :     }
     164          54 :     papoLayers[nLayers - 1] =
     165          54 :         new OGRGeoRSSLayer(pszName, pszLayerName, this, poSRSClone, TRUE);
     166          54 :     if (poSRSClone)
     167           1 :         poSRSClone->Release();
     168             : 
     169          54 :     return papoLayers[nLayers - 1];
     170             : }
     171             : 
     172             : #ifdef HAVE_EXPAT
     173             : /************************************************************************/
     174             : /*                startElementValidateCbk()                             */
     175             : /************************************************************************/
     176             : 
     177         335 : void OGRGeoRSSDataSource::startElementValidateCbk(const char *pszNameIn,
     178             :                                                   const char **ppszAttr)
     179             : {
     180         335 :     if (validity == GEORSS_VALIDITY_UNKNOWN)
     181             :     {
     182          15 :         if (strcmp(pszNameIn, "rss") == 0)
     183             :         {
     184          11 :             validity = GEORSS_VALIDITY_VALID;
     185          11 :             eFormat = GEORSS_RSS;
     186             :         }
     187           4 :         else if (strcmp(pszNameIn, "feed") == 0 ||
     188           1 :                  strcmp(pszNameIn, "atom:feed") == 0)
     189             :         {
     190           4 :             validity = GEORSS_VALIDITY_VALID;
     191           4 :             eFormat = GEORSS_ATOM;
     192             :         }
     193           0 :         else if (strcmp(pszNameIn, "rdf:RDF") == 0)
     194             :         {
     195           0 :             const char **ppszIter = ppszAttr;
     196           0 :             while (*ppszIter)
     197             :             {
     198           0 :                 if (strcmp(*ppszIter, "xmlns:georss") == 0)
     199             :                 {
     200           0 :                     validity = GEORSS_VALIDITY_VALID;
     201           0 :                     eFormat = GEORSS_RSS_RDF;
     202             :                 }
     203           0 :                 ppszIter += 2;
     204             :             }
     205             :         }
     206             :         else
     207             :         {
     208           0 :             validity = GEORSS_VALIDITY_INVALID;
     209             :         }
     210             :     }
     211         335 : }
     212             : 
     213             : /************************************************************************/
     214             : /*                      dataHandlerValidateCbk()                        */
     215             : /************************************************************************/
     216             : 
     217         986 : void OGRGeoRSSDataSource::dataHandlerValidateCbk(const char * /* data */,
     218             :                                                  int /* nLen */)
     219             : {
     220         986 :     nDataHandlerCounter++;
     221         986 :     if (nDataHandlerCounter >= PARSER_BUF_SIZE)
     222             :     {
     223           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     224             :                  "File probably corrupted (million laugh pattern)");
     225           0 :         XML_StopParser(oCurrentParser, XML_FALSE);
     226             :     }
     227         986 : }
     228             : 
     229         335 : static void XMLCALL startElementValidateCbk(void *pUserData,
     230             :                                             const char *pszName,
     231             :                                             const char **ppszAttr)
     232             : {
     233         335 :     OGRGeoRSSDataSource *poDS = static_cast<OGRGeoRSSDataSource *>(pUserData);
     234         335 :     poDS->startElementValidateCbk(pszName, ppszAttr);
     235         335 : }
     236             : 
     237         986 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data,
     238             :                                            int nLen)
     239             : {
     240         986 :     OGRGeoRSSDataSource *poDS = static_cast<OGRGeoRSSDataSource *>(pUserData);
     241         986 :     poDS->dataHandlerValidateCbk(data, nLen);
     242         986 : }
     243             : #endif
     244             : 
     245             : /************************************************************************/
     246             : /*                                Open()                                */
     247             : /************************************************************************/
     248             : 
     249          15 : int OGRGeoRSSDataSource::Open(const char *pszFilename, int bUpdateIn)
     250             : 
     251             : {
     252          15 :     if (bUpdateIn)
     253             :     {
     254           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     255             :                  "OGR/GeoRSS driver does not support opening a file "
     256             :                  "in update mode");
     257           0 :         return FALSE;
     258             :     }
     259             : #ifdef HAVE_EXPAT
     260          15 :     pszName = CPLStrdup(pszFilename);
     261             : 
     262             :     // Try to open the file.
     263          15 :     VSILFILE *fp = VSIFOpenL(pszFilename, "r");
     264          15 :     if (fp == nullptr)
     265           0 :         return FALSE;
     266             : 
     267          15 :     validity = GEORSS_VALIDITY_UNKNOWN;
     268             : 
     269          15 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     270          15 :     XML_SetUserData(oParser, this);
     271          15 :     XML_SetElementHandler(oParser, ::startElementValidateCbk, nullptr);
     272          15 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
     273          15 :     oCurrentParser = oParser;
     274             : 
     275          15 :     std::vector<char> aBuf(PARSER_BUF_SIZE);
     276          15 :     int nDone = 0;
     277          15 :     unsigned int nLen = 0;
     278          15 :     int nCount = 0;
     279             : 
     280             :     // Begin to parse the file and look for the <rss> or <feed> element.
     281             :     // It *MUST* be the first element of an XML file.
     282             :     // Once we have read the first element, we know if we can
     283             :     // handle the file or not with that driver.
     284           0 :     do
     285             :     {
     286          15 :         nDataHandlerCounter = 0;
     287          15 :         nLen = static_cast<unsigned int>(
     288          15 :             VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
     289          15 :         nDone = VSIFEofL(fp);
     290          15 :         if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
     291             :         {
     292           1 :             if (nLen <= PARSER_BUF_SIZE - 1)
     293           1 :                 aBuf[nLen] = 0;
     294             :             else
     295           0 :                 aBuf[PARSER_BUF_SIZE - 1] = 0;
     296             : 
     297           2 :             if (strstr(aBuf.data(), "<?xml") &&
     298           1 :                 (strstr(aBuf.data(), "<rss") || strstr(aBuf.data(), "<feed") ||
     299           0 :                  strstr(aBuf.data(), "<atom:feed")))
     300             :             {
     301           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     302             :                          "XML parsing of GeoRSS file failed: "
     303             :                          "%s at line %d, column %d",
     304             :                          XML_ErrorString(XML_GetErrorCode(oParser)),
     305           1 :                          static_cast<int>(XML_GetCurrentLineNumber(oParser)),
     306           1 :                          static_cast<int>(XML_GetCurrentColumnNumber(oParser)));
     307             :             }
     308           1 :             validity = GEORSS_VALIDITY_INVALID;
     309           1 :             break;
     310             :         }
     311          14 :         if (validity == GEORSS_VALIDITY_INVALID)
     312             :         {
     313           0 :             break;
     314             :         }
     315          14 :         else if (validity == GEORSS_VALIDITY_VALID)
     316             :         {
     317          14 :             break;
     318             :         }
     319             :         else
     320             :         {
     321             :             // After reading 50 * PARSER_BUF_SIZE bytes, and not finding whether the file
     322             :             // is GeoRSS or not, we give up and fail silently.
     323           0 :             nCount++;
     324           0 :             if (nCount == 50)
     325           0 :                 break;
     326             :         }
     327           0 :     } while (!nDone && nLen > 0);
     328             : 
     329          15 :     XML_ParserFree(oParser);
     330             : 
     331          15 :     VSIFCloseL(fp);
     332             : 
     333          15 :     if (validity == GEORSS_VALIDITY_VALID)
     334             :     {
     335          14 :         CPLDebug("GeoRSS", "%s seems to be a GeoRSS file.", pszFilename);
     336             : 
     337          14 :         nLayers = 1;
     338          14 :         papoLayers = static_cast<OGRGeoRSSLayer **>(
     339          14 :             CPLRealloc(papoLayers, nLayers * sizeof(OGRGeoRSSLayer *)));
     340          14 :         papoLayers[0] =
     341          14 :             new OGRGeoRSSLayer(pszName, "georss", this, nullptr, FALSE);
     342             :     }
     343             : 
     344          15 :     return validity == GEORSS_VALIDITY_VALID;
     345             : #else
     346             :     VSILFILE *fp = VSIFOpenL(pszFilename, "r");
     347             :     if (fp)
     348             :     {
     349             :         char aBuf[256];
     350             :         const unsigned int nLen =
     351             :             static_cast<unsigned int>(VSIFReadL(aBuf, 1, 255, fp));
     352             :         aBuf[nLen] = '\0';
     353             :         if (strstr(aBuf, "<?xml") &&
     354             :             (strstr(aBuf, "<rss") || strstr(aBuf, "<atom:feed") ||
     355             :              strstr(aBuf, "<feed")))
     356             :         {
     357             :             CPLError(CE_Failure, CPLE_NotSupported,
     358             :                      "OGR/GeoRSS driver has not been built with read support. "
     359             :                      "Expat library required");
     360             :         }
     361             :         VSIFCloseL(fp);
     362             :     }
     363             :     return FALSE;
     364             : #endif
     365             : }
     366             : 
     367             : /************************************************************************/
     368             : /*                               Create()                               */
     369             : /************************************************************************/
     370             : 
     371          40 : int OGRGeoRSSDataSource::Create(const char *pszFilename, char **papszOptions)
     372             : {
     373          40 :     if (fpOutput != nullptr)
     374             :     {
     375           0 :         CPLAssert(false);
     376             :         return FALSE;
     377             :     }
     378             : 
     379          40 :     if (strcmp(pszFilename, "/dev/stdout") == 0)
     380           0 :         pszFilename = "/vsistdout/";
     381             : 
     382             :     /* -------------------------------------------------------------------- */
     383             :     /*     Do not override exiting file.                                    */
     384             :     /* -------------------------------------------------------------------- */
     385             :     VSIStatBufL sStatBuf;
     386             : 
     387          40 :     if (VSIStatL(pszFilename, &sStatBuf) == 0)
     388             :     {
     389           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     390             :                  "You have to delete %s before being able to create it "
     391             :                  "with the GeoRSS driver",
     392             :                  pszFilename);
     393           0 :         return FALSE;
     394             :     }
     395             : 
     396             :     /* -------------------------------------------------------------------- */
     397             :     /*      Create the output file.                                         */
     398             :     /* -------------------------------------------------------------------- */
     399          40 :     pszName = CPLStrdup(pszFilename);
     400             : 
     401          40 :     fpOutput = VSIFOpenL(pszFilename, "w");
     402          40 :     if (fpOutput == nullptr)
     403             :     {
     404           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
     405             :                  "Failed to create GeoRSS file %s.", pszFilename);
     406           1 :         return FALSE;
     407             :     }
     408             : 
     409          39 :     const char *pszFormat = CSLFetchNameValue(papszOptions, "FORMAT");
     410          39 :     if (pszFormat)
     411             :     {
     412           1 :         if (EQUAL(pszFormat, "RSS"))
     413           0 :             eFormat = GEORSS_RSS;
     414           1 :         else if (EQUAL(pszFormat, "ATOM"))
     415           1 :             eFormat = GEORSS_ATOM;
     416             :         else
     417           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     418             :                      "Unsupported value for %s : %s", "FORMAT", pszFormat);
     419             :     }
     420             : 
     421             :     const char *pszGeomDialect =
     422          39 :         CSLFetchNameValue(papszOptions, "GEOM_DIALECT");
     423          39 :     if (pszGeomDialect)
     424             :     {
     425           3 :         if (EQUAL(pszGeomDialect, "GML"))
     426           2 :             eGeomDialect = GEORSS_GML;
     427           1 :         else if (EQUAL(pszGeomDialect, "SIMPLE"))
     428           0 :             eGeomDialect = GEORSS_SIMPLE;
     429           1 :         else if (EQUAL(pszGeomDialect, "W3C_GEO"))
     430           1 :             eGeomDialect = GEORSS_W3C_GEO;
     431             :         else
     432           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     433             :                      "Unsupported value for %s : %s", "GEOM_DIALECT",
     434             :                      pszGeomDialect);
     435             :     }
     436             : 
     437             :     const char *pszWriteHeaderAndFooter =
     438          39 :         CSLFetchNameValue(papszOptions, "WRITE_HEADER_AND_FOOTER");
     439          39 :     if (pszWriteHeaderAndFooter && !CPLTestBool(pszWriteHeaderAndFooter))
     440             :     {
     441           0 :         bWriteHeaderAndFooter = false;
     442           0 :         return TRUE;
     443             :     }
     444             : 
     445          39 :     const char *pszTitle = nullptr;
     446          39 :     const char *pszDescription = nullptr;
     447          39 :     const char *pszLink = nullptr;
     448          39 :     const char *pszUpdated = nullptr;
     449          39 :     const char *pszAuthorName = nullptr;
     450          39 :     const char *pszId = nullptr;
     451             : 
     452          39 :     const char *pszHeader = CSLFetchNameValue(papszOptions, "HEADER");
     453             : 
     454          39 :     if (eFormat == GEORSS_RSS && pszHeader == nullptr)
     455             :     {
     456          38 :         pszTitle = CSLFetchNameValue(papszOptions, "TITLE");
     457          38 :         if (pszTitle == nullptr)
     458          38 :             pszTitle = "title";
     459             : 
     460          38 :         pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
     461          38 :         if (pszDescription == nullptr)
     462          38 :             pszDescription = "channel_description";
     463             : 
     464          38 :         pszLink = CSLFetchNameValue(papszOptions, "LINK");
     465          38 :         if (pszLink == nullptr)
     466          38 :             pszLink = "channel_link";
     467             :     }
     468           1 :     else if (eFormat == GEORSS_ATOM && pszHeader == nullptr)
     469             :     {
     470           1 :         pszTitle = CSLFetchNameValue(papszOptions, "TITLE");
     471           1 :         if (pszTitle == nullptr)
     472           1 :             pszTitle = "title";
     473             : 
     474           1 :         pszUpdated = CSLFetchNameValue(papszOptions, "UPDATED");
     475           1 :         if (pszUpdated == nullptr)
     476           1 :             pszUpdated = "2009-01-01T00:00:00Z";
     477             : 
     478           1 :         pszAuthorName = CSLFetchNameValue(papszOptions, "AUTHOR_NAME");
     479           1 :         if (pszAuthorName == nullptr)
     480           1 :             pszAuthorName = "author";
     481             : 
     482           1 :         pszId = CSLFetchNameValue(papszOptions, "ID");
     483           1 :         if (pszId == nullptr)
     484           1 :             pszId = "id";
     485             :     }
     486             : 
     487             :     const char *pszUseExtensions =
     488          39 :         CSLFetchNameValue(papszOptions, "USE_EXTENSIONS");
     489          39 :     bUseExtensions = pszUseExtensions && CPLTestBool(pszUseExtensions);
     490             : 
     491             :     /* -------------------------------------------------------------------- */
     492             :     /*     Output header of GeoRSS file. */
     493             :     /* -------------------------------------------------------------------- */
     494          39 :     VSIFPrintfL(fpOutput, "<?xml version=\"1.0\"?>\n");
     495          39 :     if (eFormat == GEORSS_RSS)
     496             :     {
     497          38 :         VSIFPrintfL(fpOutput, "<rss version=\"2.0\" ");
     498          38 :         if (eGeomDialect == GEORSS_GML)
     499           2 :             VSIFPrintfL(fpOutput,
     500             :                         "xmlns:georss=\"http://www.georss.org/georss\" "
     501             :                         "xmlns:gml=\"http://www.opengis.net/gml\"");
     502          36 :         else if (eGeomDialect == GEORSS_SIMPLE)
     503          35 :             VSIFPrintfL(fpOutput,
     504             :                         "xmlns:georss=\"http://www.georss.org/georss\"");
     505             :         else
     506           1 :             VSIFPrintfL(
     507             :                 fpOutput,
     508             :                 "xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"");
     509          38 :         VSIFPrintfL(fpOutput, ">\n");
     510          38 :         VSIFPrintfL(fpOutput, "  <channel>\n");
     511          38 :         if (pszHeader)
     512             :         {
     513           0 :             VSIFPrintfL(fpOutput, "%s", pszHeader);
     514             :         }
     515             :         else
     516             :         {
     517          38 :             VSIFPrintfL(fpOutput, "    <title>%s</title>\n", pszTitle);
     518          38 :             VSIFPrintfL(fpOutput, "    <description>%s</description>\n",
     519             :                         pszDescription);
     520          38 :             VSIFPrintfL(fpOutput, "    <link>%s</link>\n", pszLink);
     521             :         }
     522             :     }
     523             :     else
     524             :     {
     525           1 :         VSIFPrintfL(fpOutput, "<feed xmlns=\"http://www.w3.org/2005/Atom\" ");
     526           1 :         if (eGeomDialect == GEORSS_GML)
     527           0 :             VSIFPrintfL(fpOutput, "xmlns:gml=\"http://www.opengis.net/gml\"");
     528           1 :         else if (eGeomDialect == GEORSS_SIMPLE)
     529           1 :             VSIFPrintfL(fpOutput,
     530             :                         "xmlns:georss=\"http://www.georss.org/georss\"");
     531             :         else
     532           0 :             VSIFPrintfL(
     533             :                 fpOutput,
     534             :                 "xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"");
     535           1 :         VSIFPrintfL(fpOutput, ">\n");
     536           1 :         if (pszHeader)
     537             :         {
     538           0 :             VSIFPrintfL(fpOutput, "%s", pszHeader);
     539             :         }
     540             :         else
     541             :         {
     542           1 :             VSIFPrintfL(fpOutput, "  <title>%s</title>\n", pszTitle);
     543           1 :             VSIFPrintfL(fpOutput, "  <updated>%s</updated>\n", pszUpdated);
     544           1 :             VSIFPrintfL(fpOutput, "  <author><name>%s</name></author>\n",
     545             :                         pszAuthorName);
     546           1 :             VSIFPrintfL(fpOutput, "  <id>%s</id>\n", pszId);
     547             :         }
     548             :     }
     549             : 
     550          39 :     return TRUE;
     551             : }

Generated by: LCOV version 1.14