LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/georss - ogrgeorssdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 216 176 81.5 %
Date: 2011-12-18 Functions: 14 10 71.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgeorssdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $
       3                 :  *
       4                 :  * Project:  GeoRSS Translator
       5                 :  * Purpose:  Implements OGRGeoRSSDataSource 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_string.h"
      33                 : #include "cpl_csv.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrgeorssdatasource.cpp 23557 2011-12-12 22:08:17Z rouault $");
      36                 : 
      37                 : /************************************************************************/
      38                 : /*                          OGRGeoRSSDataSource()                          */
      39                 : /************************************************************************/
      40                 : 
      41             102 : OGRGeoRSSDataSource::OGRGeoRSSDataSource()
      42                 : 
      43                 : {
      44             102 :     papoLayers = NULL;
      45             102 :     nLayers = 0;
      46                 : 
      47             102 :     fpOutput = NULL;
      48                 : 
      49             102 :     pszName = NULL;
      50                 : 
      51             102 :     eFormat = GEORSS_RSS;
      52             102 :     eGeomDialect = GEORSS_SIMPLE;
      53             102 :     bUseExtensions = FALSE;
      54             102 :     bWriteHeaderAndFooter = TRUE;
      55             102 : }
      56                 : 
      57                 : /************************************************************************/
      58                 : /*                         ~OGRGeoRSSDataSource()                          */
      59                 : /************************************************************************/
      60                 : 
      61             102 : OGRGeoRSSDataSource::~OGRGeoRSSDataSource()
      62                 : 
      63                 : {
      64             102 :     if ( fpOutput != NULL )
      65                 :     {
      66               7 :         if (bWriteHeaderAndFooter)
      67                 :         {
      68               7 :             if (eFormat == GEORSS_RSS)
      69                 :             {
      70               6 :                 VSIFPrintfL(fpOutput, "  </channel>\n");
      71               6 :                 VSIFPrintfL(fpOutput, "</rss>\n");
      72                 :             }
      73                 :             else
      74                 :             {
      75               1 :                 VSIFPrintfL(fpOutput, "</feed>\n");
      76                 :             }
      77                 :         }
      78               7 :         VSIFCloseL( fpOutput);
      79                 :     }
      80                 : 
      81             121 :     for( int i = 0; i < nLayers; i++ )
      82              19 :         delete papoLayers[i];
      83             102 :     CPLFree( papoLayers );
      84             102 :     CPLFree( pszName );
      85             102 : }
      86                 : 
      87                 : /************************************************************************/
      88                 : /*                           TestCapability()                           */
      89                 : /************************************************************************/
      90                 : 
      91               0 : int OGRGeoRSSDataSource::TestCapability( const char * pszCap )
      92                 : 
      93                 : {
      94               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
      95               0 :         return TRUE;
      96               0 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
      97               0 :         return FALSE;
      98                 :     else
      99               0 :         return FALSE;
     100                 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                              GetLayer()                              */
     104                 : /************************************************************************/
     105                 : 
     106              12 : OGRLayer *OGRGeoRSSDataSource::GetLayer( int iLayer )
     107                 : 
     108                 : {
     109              12 :     if( iLayer < 0 || iLayer >= nLayers )
     110               0 :         return NULL;
     111                 :     else
     112              12 :         return papoLayers[iLayer];
     113                 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                            CreateLayer()                             */
     117                 : /************************************************************************/
     118                 : 
     119               7 : OGRLayer * OGRGeoRSSDataSource::CreateLayer( const char * pszLayerName,
     120                 :                                              OGRSpatialReference *poSRS,
     121                 :                                              OGRwkbGeometryType eType,
     122                 :                                              char ** papszOptions )
     123                 : 
     124                 : {
     125               7 :     if (fpOutput == NULL)
     126               0 :         return NULL;
     127                 : 
     128               7 :     if (poSRS != NULL && eGeomDialect != GEORSS_GML)
     129                 :     {
     130               1 :         OGRSpatialReference oSRS;
     131               1 :         oSRS.SetWellKnownGeogCS("WGS84");
     132               1 :         if (poSRS->IsSame(&oSRS) == FALSE)
     133                 :         {
     134                 :             CPLError(CE_Failure, CPLE_NotSupported,
     135               1 :                      "For a non GML dialect, only WGS84 SRS is supported");
     136               1 :             return NULL;
     137               0 :         }
     138                 :     }
     139                 : 
     140               6 :     nLayers++;
     141               6 :     papoLayers = (OGRGeoRSSLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGeoRSSLayer*));
     142               6 :     papoLayers[nLayers-1] = new OGRGeoRSSLayer( pszName, pszLayerName, this, poSRS, TRUE );
     143                 :     
     144               6 :     return papoLayers[nLayers-1];
     145                 : }
     146                 : 
     147                 : #ifdef HAVE_EXPAT
     148                 : /************************************************************************/
     149                 : /*                startElementValidateCbk()                             */
     150                 : /************************************************************************/
     151                 : 
     152             831 : void OGRGeoRSSDataSource::startElementValidateCbk(const char *pszName, const char **ppszAttr)
     153                 : {
     154             831 :     if (validity == GEORSS_VALIDITY_UNKNOWN)
     155                 :     {
     156              21 :         if (strcmp(pszName, "rss") == 0)
     157                 :         {
     158              11 :             validity = GEORSS_VALIDITY_VALID;
     159              11 :             eFormat = GEORSS_RSS;
     160                 :         }
     161              10 :         else if (strcmp(pszName, "feed") == 0)
     162                 :         {
     163               3 :             validity = GEORSS_VALIDITY_VALID;
     164               3 :             eFormat = GEORSS_ATOM;
     165                 :         }
     166               7 :         else if (strcmp(pszName, "rdf:RDF") == 0)
     167                 :         {
     168               0 :             const char** ppszIter = ppszAttr;
     169               0 :             while(*ppszIter)
     170                 :             {
     171               0 :                 if (strcmp(*ppszIter, "xmlns:georss") == 0)
     172                 :                 {
     173               0 :                     validity = GEORSS_VALIDITY_VALID;
     174               0 :                     eFormat = GEORSS_RSS_RDF;
     175                 :                 }
     176               0 :                 ppszIter += 2;
     177                 :             }
     178                 :         }
     179                 :         else
     180                 :         {
     181               7 :             validity = GEORSS_VALIDITY_INVALID;
     182                 :         }
     183                 :     }
     184             831 : }
     185                 : 
     186                 : 
     187                 : /************************************************************************/
     188                 : /*                      dataHandlerValidateCbk()                        */
     189                 : /************************************************************************/
     190                 : 
     191            2335 : void OGRGeoRSSDataSource::dataHandlerValidateCbk(const char *data, int nLen)
     192                 : {
     193            2335 :     nDataHandlerCounter ++;
     194            2335 :     if (nDataHandlerCounter >= BUFSIZ)
     195                 :     {
     196               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
     197               0 :         XML_StopParser(oCurrentParser, XML_FALSE);
     198                 :     }
     199            2335 : }
     200                 : 
     201                 : 
     202             831 : static void XMLCALL startElementValidateCbk(void *pUserData, const char *pszName, const char **ppszAttr)
     203                 : {
     204             831 :     OGRGeoRSSDataSource* poDS = (OGRGeoRSSDataSource*) pUserData;
     205             831 :     poDS->startElementValidateCbk(pszName, ppszAttr);
     206             831 : }
     207                 : 
     208            2335 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, int nLen)
     209                 : {
     210            2335 :     OGRGeoRSSDataSource* poDS = (OGRGeoRSSDataSource*) pUserData;
     211            2335 :     poDS->dataHandlerValidateCbk(data, nLen);
     212            2335 : }
     213                 : #endif
     214                 : 
     215                 : /************************************************************************/
     216                 : /*                                Open()                                */
     217                 : /************************************************************************/
     218                 : 
     219              95 : int OGRGeoRSSDataSource::Open( const char * pszFilename, int bUpdateIn)
     220                 : 
     221                 : {
     222              95 :     if (bUpdateIn)
     223                 :     {
     224                 :         CPLError(CE_Failure, CPLE_NotSupported,
     225               0 :                     "OGR/GeoRSS driver does not support opening a file in update mode");
     226               0 :         return FALSE;
     227                 :     }
     228                 : #ifdef HAVE_EXPAT
     229              95 :     pszName = CPLStrdup( pszFilename );
     230                 : 
     231                 : /* -------------------------------------------------------------------- */
     232                 : /*      Try to open the file.                                           */
     233                 : /* -------------------------------------------------------------------- */
     234              95 :     VSILFILE* fp = VSIFOpenL(pszFilename, "r");
     235              95 :     if (fp == NULL)
     236              37 :         return FALSE;
     237                 :     
     238              58 :     validity = GEORSS_VALIDITY_UNKNOWN;
     239                 :     
     240              58 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     241              58 :     XML_SetUserData(oParser, this);
     242              58 :     XML_SetElementHandler(oParser, ::startElementValidateCbk, NULL);
     243              58 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
     244              58 :     oCurrentParser = oParser;
     245                 :     
     246                 :     char aBuf[BUFSIZ];
     247                 :     int nDone;
     248                 :     unsigned int nLen;
     249              58 :     int nCount = 0;
     250                 :     
     251                 :     /* Begin to parse the file and look for the <rss> or <feed> element */
     252                 :     /* It *MUST* be the first element of an XML file */
     253                 :     /* So once we have read the first element, we know if we can */
     254                 :     /* handle the file or not with that driver */
     255               0 :     do
     256                 :     {
     257              58 :         nDataHandlerCounter = 0;
     258              58 :         nLen = (unsigned int) VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
     259              58 :         nDone = VSIFEofL(fp);
     260              58 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
     261                 :         {
     262              38 :             if (nLen <= BUFSIZ-1)
     263              34 :                 aBuf[nLen] = 0;
     264                 :             else
     265               4 :                 aBuf[BUFSIZ-1] = 0;
     266              38 :             if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<feed")))
     267                 :             {
     268                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     269                 :                         "XML parsing of GeoRSS file failed : %s at line %d, column %d",
     270                 :                         XML_ErrorString(XML_GetErrorCode(oParser)),
     271                 :                         (int)XML_GetCurrentLineNumber(oParser),
     272               1 :                         (int)XML_GetCurrentColumnNumber(oParser));
     273                 :             }
     274              38 :             validity = GEORSS_VALIDITY_INVALID;
     275              38 :             break;
     276                 :         }
     277              20 :         if (validity == GEORSS_VALIDITY_INVALID)
     278                 :         {
     279               7 :             break;
     280                 :         }
     281              13 :         else if (validity == GEORSS_VALIDITY_VALID)
     282                 :         {
     283              13 :             break;
     284                 :         }
     285                 :         else
     286                 :         {
     287                 :             /* After reading 50 * BUFSIZ bytes, and not finding whether the file */
     288                 :             /* is GeoRSS or not, we give up and fail silently */
     289               0 :             nCount ++;
     290               0 :             if (nCount == 50)
     291               0 :                 break;
     292                 :         }
     293                 :     } while (!nDone && nLen > 0 );
     294                 :     
     295              58 :     XML_ParserFree(oParser);
     296                 :     
     297              58 :     VSIFCloseL(fp);
     298                 :     
     299              58 :     if (validity == GEORSS_VALIDITY_VALID)
     300                 :     {
     301              13 :         CPLDebug("GeoRSS", "%s seems to be a GeoRSS file.", pszFilename);
     302                 : 
     303              13 :         nLayers = 1;
     304              13 :         papoLayers = (OGRGeoRSSLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGeoRSSLayer*));
     305              13 :         papoLayers[0] = new OGRGeoRSSLayer( pszName, "georss", this, NULL, FALSE );
     306                 :     }
     307                 : 
     308              58 :     return (validity == GEORSS_VALIDITY_VALID);
     309                 : #else
     310                 :     char aBuf[256];
     311                 :     VSILFILE* fp = VSIFOpenL(pszFilename, "r");
     312                 :     if (fp)
     313                 :     {
     314                 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, 255, fp );
     315                 :         aBuf[nLen] = 0;
     316                 :         if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<feed")))
     317                 :         {
     318                 :             CPLError(CE_Failure, CPLE_NotSupported,
     319                 :                     "OGR/GeoRSS driver has not been built with read support. Expat library required");
     320                 :         }
     321                 :         VSIFCloseL(fp);
     322                 :     }
     323                 :     return FALSE;
     324                 : #endif
     325                 : }
     326                 : 
     327                 : 
     328                 : /************************************************************************/
     329                 : /*                               Create()                               */
     330                 : /************************************************************************/
     331                 : 
     332               7 : int OGRGeoRSSDataSource::Create( const char *pszFilename, 
     333                 :                                  char **papszOptions )
     334                 : {
     335               7 :     if( fpOutput != NULL)
     336                 :     {
     337               0 :         CPLAssert( FALSE );
     338               0 :         return FALSE;
     339                 :     }
     340                 : 
     341               7 :     if (strcmp(pszFilename, "/dev/stdout") == 0)
     342               0 :         pszFilename = "/vsistdout/";
     343                 : 
     344                 : /* -------------------------------------------------------------------- */
     345                 : /*     Do not override exiting file.                                    */
     346                 : /* -------------------------------------------------------------------- */
     347                 :     VSIStatBufL sStatBuf;
     348                 : 
     349               7 :     if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
     350                 :     {
     351                 :         CPLError(CE_Failure, CPLE_NotSupported,
     352                 :                  "You have to delete %s before being able to create it with the GeoRSS driver",
     353               0 :                  pszFilename);
     354               0 :         return FALSE;
     355                 :     }
     356                 :     
     357                 : /* -------------------------------------------------------------------- */
     358                 : /*      Create the output file.                                         */
     359                 : /* -------------------------------------------------------------------- */
     360               7 :     pszName = CPLStrdup( pszFilename );
     361                 : 
     362               7 :     fpOutput = VSIFOpenL( pszFilename, "w" );
     363               7 :     if( fpOutput == NULL )
     364                 :     {
     365                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     366                 :                   "Failed to create GeoRSS file %s.", 
     367               0 :                   pszFilename );
     368               0 :         return FALSE;
     369                 :     }
     370                 : 
     371               7 :     const char* pszFormat = CSLFetchNameValue(papszOptions, "FORMAT");
     372               7 :     if (pszFormat)
     373                 :     {
     374               1 :         if (EQUAL(pszFormat, "RSS"))
     375               0 :             eFormat = GEORSS_RSS;
     376               1 :         else if (EQUAL(pszFormat, "ATOM"))
     377               1 :             eFormat = GEORSS_ATOM;
     378                 :         else
     379                 :         {
     380                 :             CPLError(CE_Warning, CPLE_NotSupported,
     381               0 :                      "Unsupported value for %s : %s", "FORMAT", pszFormat);
     382                 :         }
     383                 :     }
     384                 : 
     385               7 :     const char* pszGeomDialect = CSLFetchNameValue(papszOptions, "GEOM_DIALECT");
     386               7 :     if (pszGeomDialect)
     387                 :     {
     388               3 :         if (EQUAL(pszGeomDialect, "GML"))
     389               2 :             eGeomDialect = GEORSS_GML;
     390               1 :         else if (EQUAL(pszGeomDialect, "SIMPLE"))
     391               0 :             eGeomDialect = GEORSS_SIMPLE;
     392               1 :         else if (EQUAL(pszGeomDialect, "W3C_GEO"))
     393               1 :             eGeomDialect = GEORSS_W3C_GEO;
     394                 :         else
     395                 :         {
     396                 :             CPLError(CE_Warning, CPLE_NotSupported,
     397               0 :                      "Unsupported value for %s : %s", "GEOM_DIALECT", pszGeomDialect);
     398                 :         }
     399                 :     }
     400                 : 
     401               7 :     const char* pszWriteHeaderAndFooter = CSLFetchNameValue(papszOptions, "WRITE_HEADER_AND_FOOTER");
     402               7 :     if (pszWriteHeaderAndFooter && CSLTestBoolean(pszWriteHeaderAndFooter) == FALSE)
     403                 :     {
     404               0 :         bWriteHeaderAndFooter = FALSE;
     405               0 :         return TRUE;
     406                 :     }
     407                 : 
     408               7 :     const char* pszHeader = NULL;
     409               7 :     const char* pszTitle = NULL;
     410               7 :     const char* pszDescription = NULL;
     411               7 :     const char* pszLink = NULL;
     412               7 :     const char* pszUpdated = NULL;
     413               7 :     const char* pszAuthorName = NULL;
     414               7 :     const char* pszId = NULL;
     415                 : 
     416               7 :     pszHeader = CSLFetchNameValue(papszOptions, "HEADER");
     417                 : 
     418              13 :     if (eFormat == GEORSS_RSS && pszHeader == NULL)
     419                 :     {
     420               6 :         pszTitle = CSLFetchNameValue(papszOptions, "TITLE");
     421               6 :         if (pszTitle == NULL)
     422               6 :             pszTitle = "title";
     423                 : 
     424               6 :         pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
     425               6 :         if (pszDescription == NULL)
     426               6 :             pszDescription = "channel_description";
     427                 : 
     428               6 :         pszLink = CSLFetchNameValue(papszOptions, "LINK");
     429               6 :         if (pszLink == NULL)
     430               6 :             pszLink = "channel_link";
     431                 : 
     432                 :     }
     433               1 :     else if (eFormat == GEORSS_ATOM && pszHeader == NULL)
     434                 :     {
     435               1 :         pszTitle = CSLFetchNameValue(papszOptions, "TITLE");
     436               1 :         if (pszTitle == NULL)
     437               1 :             pszTitle = "title";
     438                 : 
     439               1 :         pszUpdated = CSLFetchNameValue(papszOptions, "UPDATED");
     440               1 :         if (pszUpdated == NULL)
     441               1 :             pszUpdated = "2009-01-01T00:00:00Z";
     442                 : 
     443               1 :         pszAuthorName = CSLFetchNameValue(papszOptions, "AUTHOR_NAME");
     444               1 :         if (pszAuthorName == NULL)
     445               1 :             pszAuthorName = "author";
     446                 : 
     447               1 :         pszId = CSLFetchNameValue(papszOptions, "ID");
     448               1 :         if (pszId == NULL)
     449               1 :             pszId = "id";
     450                 :     }
     451                 : 
     452               7 :     const char* pszUseExtensions = CSLFetchNameValue( papszOptions, "USE_EXTENSIONS");
     453               7 :     bUseExtensions =  (pszUseExtensions && CSLTestBoolean(pszUseExtensions));
     454                 : 
     455                 : /* -------------------------------------------------------------------- */
     456                 : /*     Output header of GeoRSS file.                                       */
     457                 : /* -------------------------------------------------------------------- */
     458               7 :     VSIFPrintfL(fpOutput, "<?xml version=\"1.0\"?>\n");
     459               7 :     if (eFormat == GEORSS_RSS)
     460                 :     {
     461               6 :         VSIFPrintfL(fpOutput, "<rss version=\"2.0\" ");
     462               6 :         if (eGeomDialect == GEORSS_GML)
     463               2 :             VSIFPrintfL(fpOutput, "xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\"");
     464               4 :         else if (eGeomDialect == GEORSS_SIMPLE)
     465               3 :             VSIFPrintfL(fpOutput, "xmlns:georss=\"http://www.georss.org/georss\"");
     466                 :         else
     467               1 :             VSIFPrintfL(fpOutput, "xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"");
     468               6 :         VSIFPrintfL(fpOutput, ">\n");
     469               6 :         VSIFPrintfL(fpOutput, "  <channel>\n");
     470               6 :         if (pszHeader)
     471                 :         {
     472               0 :             VSIFPrintfL(fpOutput, "%s", pszHeader);
     473                 :         }
     474                 :         else
     475                 :         {
     476               6 :             VSIFPrintfL(fpOutput, "    <title>%s</title>\n", pszTitle);
     477               6 :             VSIFPrintfL(fpOutput, "    <description>%s</description>\n", pszDescription);
     478               6 :             VSIFPrintfL(fpOutput, "    <link>%s</link>\n", pszLink);
     479                 :         }
     480                 :     }
     481                 :     else
     482                 :     {
     483               1 :         VSIFPrintfL(fpOutput, "<feed xmlns=\"http://www.w3.org/2005/Atom\" ");
     484               1 :         if (eGeomDialect == GEORSS_GML)
     485               0 :             VSIFPrintfL(fpOutput, "xmlns:gml=\"http://www.opengis.net/gml\"");
     486               1 :         else if (eGeomDialect == GEORSS_SIMPLE)
     487               1 :             VSIFPrintfL(fpOutput, "xmlns:georss=\"http://www.georss.org/georss\"");
     488                 :         else
     489               0 :             VSIFPrintfL(fpOutput, "xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"");
     490               1 :         VSIFPrintfL(fpOutput, ">\n");
     491               1 :         if (pszHeader)
     492                 :         {
     493               0 :             VSIFPrintfL(fpOutput, "%s", pszHeader);
     494                 :         }
     495                 :         else
     496                 :         {
     497               1 :             VSIFPrintfL(fpOutput, "  <title>%s</title>\n", pszTitle);
     498               1 :             VSIFPrintfL(fpOutput, "  <updated>%s</updated>\n", pszUpdated);
     499               1 :             VSIFPrintfL(fpOutput, "  <author><name>%s</name></author>\n", pszAuthorName);
     500               1 :             VSIFPrintfL(fpOutput, "  <id>%s</id>\n", pszId);
     501                 :         }
     502                 :     }
     503                 : 
     504               7 :     return TRUE;
     505                 : }

Generated by: LCOV version 1.7