LCOV - code coverage report
Current view: top level - ogr - ogr_xerces.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 173 204 84.8 %
Date: 2024-11-21 22:18:42 Functions: 25 30 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GML Reader
       4             :  * Purpose:  Convenience functions for parsing with Xerces-C library
       5             :  *           Functions for translating back and forth between XMLCh and char.
       6             :  *           We assume that XMLCh is a simple numeric type that we can
       7             :  *           correspond 1:1 with char values, but that it likely is larger
       8             :  *           than a char.
       9             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
      10             :  * Author:   Even Rouault, <even.rouault at spatialys.com>
      11             :  *
      12             :  ******************************************************************************
      13             :  * Copyright (c) 2002, Frank Warmerdam
      14             :  * Copyright (c) 2016, Even Rouault <even.rouault at spatialys.com>
      15             :  *
      16             :  * SPDX-License-Identifier: MIT
      17             :  ****************************************************************************/
      18             : 
      19             : #include "ogr_xerces.h"
      20             : 
      21             : #include "cpl_port.h"
      22             : #include "cpl_error.h"
      23             : #include "cpl_multiproc.h"
      24             : #include "cpl_string.h"
      25             : 
      26             : #include <algorithm>
      27             : #include <limits>
      28             : #include <map>
      29             : 
      30             : #ifdef HAVE_XERCES
      31             : 
      32             : class OGRXercesStandardMemoryManager;
      33             : class OGRXercesInstrumentedMemoryManager;
      34             : 
      35             : /************************************************************************/
      36             : /*                        CPLGettimeofday()                             */
      37             : /************************************************************************/
      38             : 
      39             : #if defined(_WIN32) && !defined(__CYGWIN__)
      40             : #include <sys/timeb.h>
      41             : 
      42             : namespace
      43             : {
      44             : struct CPLTimeVal
      45             : {
      46             :     time_t tv_sec; /* seconds */
      47             :     long tv_usec;  /* and microseconds */
      48             : };
      49             : }  // namespace
      50             : 
      51             : static int CPLGettimeofday(struct CPLTimeVal *tp, void * /* timezonep*/)
      52             : {
      53             :     struct _timeb theTime;
      54             : 
      55             :     _ftime(&theTime);
      56             :     tp->tv_sec = static_cast<time_t>(theTime.time);
      57             :     tp->tv_usec = theTime.millitm * 1000;
      58             :     return 0;
      59             : }
      60             : #else
      61             : #include <sys/time.h> /* for gettimeofday() */
      62             : #define CPLTimeVal timeval
      63             : #define CPLGettimeofday(t, u) gettimeofday(t, u)
      64             : #endif
      65             : 
      66             : namespace
      67             : {
      68             : struct LimitationStruct
      69             : {
      70             :     size_t maxMemAlloc = 0;
      71             :     std::string osMsgMaxMemAlloc{};
      72             :     double timeOut = 0;
      73             :     std::string osMsgTimeout{};
      74             : 
      75             :     CPLTimeVal initTV{0, 0};
      76             :     CPLTimeVal lastTV{0, 0};
      77             :     size_t totalAllocSize = 0;
      78             :     size_t allocCount = 0;
      79             : };
      80             : }  // namespace
      81             : 
      82             : static CPLMutex *hOGRXercesMutex = nullptr;
      83             : static int nCounter = 0;
      84             : static bool bXercesWasAlreadyInitializedBeforeUs = false;
      85             : static OGRXercesStandardMemoryManager *gpExceptionMemoryManager = nullptr;
      86             : static OGRXercesInstrumentedMemoryManager *gpMemoryManager = nullptr;
      87             : static std::map<GIntBig, LimitationStruct> *gpoMapThreadTimeout = nullptr;
      88             : 
      89             : /************************************************************************/
      90             : /*                    OGRXercesStandardMemoryManager                    */
      91             : /************************************************************************/
      92             : 
      93             : class OGRXercesStandardMemoryManager final : public MemoryManager
      94             : {
      95             :   public:
      96         161 :     OGRXercesStandardMemoryManager() = default;
      97             : 
      98           0 :     MemoryManager *getExceptionMemoryManager() override
      99             :     {
     100           0 :         return this;
     101             :     }
     102             : 
     103             :     void *allocate(XMLSize_t size) override;
     104             : 
     105             :     void deallocate(void *p) override;
     106             : };
     107             : 
     108         777 : void *OGRXercesStandardMemoryManager::allocate(XMLSize_t size)
     109             : {
     110         777 :     void *memptr = VSIMalloc(size);
     111         777 :     if (memptr == nullptr && size != 0)
     112           0 :         throw OutOfMemoryException();
     113         777 :     return memptr;
     114             : }
     115             : 
     116         777 : void OGRXercesStandardMemoryManager::deallocate(void *p)
     117             : {
     118         777 :     if (p)
     119         777 :         VSIFree(p);
     120         777 : }
     121             : 
     122             : /************************************************************************/
     123             : /*               OGRXercesInstrumentedMemoryManager                     */
     124             : /************************************************************************/
     125             : 
     126             : class OGRXercesInstrumentedMemoryManager final : public MemoryManager
     127             : {
     128             :   public:
     129         161 :     OGRXercesInstrumentedMemoryManager() = default;
     130             : 
     131         262 :     MemoryManager *getExceptionMemoryManager() override
     132             :     {
     133         262 :         return gpExceptionMemoryManager;
     134             :     }
     135             : 
     136             :     void *allocate(XMLSize_t size) override;
     137             : 
     138             :     void deallocate(void *p) override;
     139             : };
     140             : 
     141    22360000 : void *OGRXercesInstrumentedMemoryManager::allocate(XMLSize_t size)
     142             : {
     143    22360000 :     if (size > std::numeric_limits<size_t>::max() - 8U)
     144           0 :         throw OutOfMemoryException();
     145    22360000 :     void *memptr = VSIMalloc(size + 8);
     146    22360000 :     if (memptr == nullptr)
     147           0 :         throw OutOfMemoryException();
     148    22360000 :     memcpy(memptr, &size, sizeof(XMLSize_t));
     149             : 
     150    22360000 :     LimitationStruct *pLimitation = nullptr;
     151             :     {
     152    44720000 :         CPLMutexHolderD(&hOGRXercesMutex);
     153             : 
     154    22360000 :         if (gpoMapThreadTimeout)
     155             :         {
     156    13890100 :             auto iter = gpoMapThreadTimeout->find(CPLGetPID());
     157    13890100 :             if (iter != gpoMapThreadTimeout->end())
     158             :             {
     159    13890100 :                 pLimitation = &(iter->second);
     160             :             }
     161             :         }
     162             :     }
     163             : 
     164             :     // Big memory allocation can happen in cases like
     165             :     // https://issues.apache.org/jira/browse/XERCESC-1051
     166    22360000 :     if (pLimitation && pLimitation->maxMemAlloc > 0)
     167             :     {
     168    13890100 :         if (pLimitation->totalAllocSize + size > pLimitation->maxMemAlloc)
     169             :         {
     170           1 :             pLimitation->maxMemAlloc = 0;
     171           1 :             VSIFree(memptr);
     172           1 :             if (!pLimitation->osMsgMaxMemAlloc.empty())
     173             :             {
     174           1 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s",
     175             :                          pLimitation->osMsgMaxMemAlloc.c_str());
     176             :             }
     177           1 :             throw OutOfMemoryException();
     178             :         }
     179             :     }
     180             : 
     181             :     // Quite a hack, but some pathologic schema can cause excessive
     182             :     // processing time. As memory allocations are regularly done, we
     183             :     // measure the time of those consecutive allocations and check it
     184             :     // does not exceed a threshold set by OGRStartXercesTimeoutForThisThread()
     185             :     // Can happen in cases like
     186             :     // https://issues.apache.org/jira/browse/XERCESC-1051
     187    22360000 :     if (pLimitation && pLimitation->timeOut > 0)
     188             :     {
     189     6609120 :         ++pLimitation->allocCount;
     190     6609120 :         if (pLimitation->allocCount == 1000)
     191             :         {
     192        6490 :             pLimitation->allocCount = 0;
     193             : 
     194             :             CPLTimeVal tv;
     195        6490 :             CPLGettimeofday(&tv, nullptr);
     196       12765 :             if (pLimitation->initTV.tv_sec == 0 ||
     197             :                 // Reset the counter if the delay between the last 1000 memory
     198             :                 // allocations is too large. This enables being tolerant to
     199             :                 // network requests.
     200        6275 :                 tv.tv_sec + tv.tv_usec * 1e-6 -
     201        6275 :                         (pLimitation->lastTV.tv_sec +
     202        6275 :                          pLimitation->lastTV.tv_usec * 1e-6) >
     203       12765 :                     std::min(0.1, pLimitation->timeOut / 10))
     204             :             {
     205         220 :                 pLimitation->initTV = tv;
     206             :             }
     207        6270 :             else if (tv.tv_sec + tv.tv_usec * 1e-6 -
     208        6270 :                          (pLimitation->initTV.tv_sec +
     209        6270 :                           pLimitation->initTV.tv_usec * 1e-6) >
     210        6270 :                      pLimitation->timeOut)
     211             :             {
     212           1 :                 pLimitation->timeOut = 0;
     213           1 :                 VSIFree(memptr);
     214           1 :                 if (!pLimitation->osMsgTimeout.empty())
     215             :                 {
     216           1 :                     CPLError(CE_Failure, CPLE_AppDefined, "%s",
     217             :                              pLimitation->osMsgTimeout.c_str());
     218             :                 }
     219           1 :                 throw OutOfMemoryException();
     220             :             }
     221        6489 :             pLimitation->lastTV = tv;
     222             :         }
     223             :     }
     224             : 
     225    22360000 :     if (pLimitation && pLimitation->maxMemAlloc > 0)
     226             :     {
     227    13890100 :         pLimitation->totalAllocSize += size;
     228             :     }
     229             : 
     230    22360000 :     return static_cast<char *>(memptr) + 8;
     231             : }
     232             : 
     233    18087500 : void OGRXercesInstrumentedMemoryManager::deallocate(void *p)
     234             : {
     235    18087500 :     if (p)
     236             :     {
     237    14934700 :         void *rawptr =
     238    14934700 :             reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) - 8);
     239             :         XMLSize_t size;
     240    14934700 :         memcpy(&size, rawptr, sizeof(XMLSize_t));
     241    14934700 :         VSIFree(rawptr);
     242             : 
     243    14934700 :         LimitationStruct *pLimitation = nullptr;
     244             :         {
     245    29869500 :             CPLMutexHolderD(&hOGRXercesMutex);
     246             : 
     247    14934700 :             if (gpoMapThreadTimeout)
     248             :             {
     249     3275040 :                 auto iter = gpoMapThreadTimeout->find(CPLGetPID());
     250     3275040 :                 if (iter != gpoMapThreadTimeout->end())
     251             :                 {
     252     3275040 :                     pLimitation = &(iter->second);
     253             :                 }
     254             :             }
     255             :         }
     256    14934700 :         if (pLimitation && pLimitation->maxMemAlloc > 0)
     257             :         {
     258             :             // Memory allocations aren't necessarily paired within
     259             :             // a OGRStartXercesLimitsForThisThread() /
     260             :             // OGRStopXercesLimitsForThisThread() session. Probably due to
     261             :             // some caching with Xerces. So handle this gracefully to avoid
     262             :             // unsigned integer underflow.
     263     3274790 :             if (pLimitation->totalAllocSize >= size)
     264     3274790 :                 pLimitation->totalAllocSize -= size;
     265             :             else
     266           0 :                 pLimitation->totalAllocSize = 0;
     267             :         }
     268             :     }
     269    18087500 : }
     270             : 
     271             : /************************************************************************/
     272             : /*                  OGRStartXercesLimitsForThisThread()                 */
     273             : /************************************************************************/
     274             : 
     275         259 : void OGRStartXercesLimitsForThisThread(size_t nMaxMemAlloc,
     276             :                                        const char *pszMsgMaxMemAlloc,
     277             :                                        double dfTimeoutSecond,
     278             :                                        const char *pszMsgTimeout)
     279             : {
     280         518 :     CPLMutexHolderD(&hOGRXercesMutex);
     281         259 :     if (gpoMapThreadTimeout == nullptr)
     282             :     {
     283         259 :         gpoMapThreadTimeout = new std::map<GIntBig, LimitationStruct>();
     284             :     }
     285         259 :     LimitationStruct limitation;
     286         259 :     limitation.maxMemAlloc = nMaxMemAlloc;
     287         259 :     if (pszMsgMaxMemAlloc)
     288         259 :         limitation.osMsgMaxMemAlloc = pszMsgMaxMemAlloc;
     289         259 :     limitation.timeOut = dfTimeoutSecond;
     290         259 :     if (pszMsgTimeout)
     291         259 :         limitation.osMsgTimeout = pszMsgTimeout;
     292         259 :     (*gpoMapThreadTimeout)[CPLGetPID()] = std::move(limitation);
     293         259 : }
     294             : 
     295             : /************************************************************************/
     296             : /*                  OGRStopXercesLimitsForThisThread()                  */
     297             : /************************************************************************/
     298             : 
     299         259 : void OGRStopXercesLimitsForThisThread()
     300             : {
     301         518 :     CPLMutexHolderD(&hOGRXercesMutex);
     302         259 :     (*gpoMapThreadTimeout).erase(CPLGetPID());
     303         259 :     if (gpoMapThreadTimeout->empty())
     304             :     {
     305         259 :         delete gpoMapThreadTimeout;
     306         259 :         gpoMapThreadTimeout = nullptr;
     307             :     }
     308         259 : }
     309             : 
     310             : /************************************************************************/
     311             : /*                      OGRXercesBinInputStream                         */
     312             : /************************************************************************/
     313             : 
     314             : class OGRXercesBinInputStream final : public BinInputStream
     315             : {
     316             :     CPL_DISALLOW_COPY_ASSIGN(OGRXercesBinInputStream)
     317             : 
     318             :     VSILFILE *fp = nullptr;
     319             :     bool bOwnFP = false;
     320             :     XMLCh emptyString = 0;
     321             : 
     322             :   public:
     323             :     explicit OGRXercesBinInputStream(VSILFILE *fpIn, bool bOwnFPIn);
     324             :     ~OGRXercesBinInputStream() override;
     325             : 
     326             :     XMLFilePos curPos() const override;
     327             :     XMLSize_t readBytes(XMLByte *const toFill,
     328             :                         const XMLSize_t maxToRead) override;
     329             : 
     330           0 :     const XMLCh *getContentType() const override
     331             :     {
     332           0 :         return &emptyString;
     333             :     }
     334             : };
     335             : 
     336             : /************************************************************************/
     337             : /*                      OGRXercesNetAccessor                            */
     338             : /************************************************************************/
     339             : 
     340             : class OGRXercesNetAccessor final : public XMLNetAccessor
     341             : {
     342             :   public:
     343         161 :     OGRXercesNetAccessor() = default;
     344             : 
     345             :     BinInputStream *makeNew(const XMLURL &urlSource,
     346             :                             const XMLNetHTTPInfo *httpInfo) override;
     347             : 
     348           0 :     const XMLCh *getId() const override
     349             :     {
     350           0 :         return fgMyName;
     351             :     }
     352             : 
     353             :   private:
     354             :     static const XMLCh fgMyName[];
     355             : 
     356             :     OGRXercesNetAccessor(const OGRXercesNetAccessor &);
     357             :     OGRXercesNetAccessor &operator=(const OGRXercesNetAccessor &);
     358             : };
     359             : 
     360             : const XMLCh OGRXercesNetAccessor::fgMyName[] = {
     361             :     chLatin_O, chLatin_G, chLatin_R, chLatin_X, chLatin_e, chLatin_r, chLatin_c,
     362             :     chLatin_e, chLatin_s, chLatin_N, chLatin_e, chLatin_t, chLatin_A, chLatin_c,
     363             :     chLatin_c, chLatin_e, chLatin_s, chLatin_s, chLatin_o, chLatin_r, chNull};
     364             : 
     365             : BinInputStream *
     366           0 : OGRXercesNetAccessor::makeNew(const XMLURL &urlSource,
     367             :                               const XMLNetHTTPInfo * /*httpInfo*/)
     368             : {
     369             :     const std::string osURL =
     370           0 :         "/vsicurl_streaming/" + transcode(urlSource.getURLText());
     371           0 :     VSILFILE *fp = VSIFOpenL(osURL.c_str(), "rb");
     372           0 :     if (!fp)
     373           0 :         return nullptr;
     374           0 :     return new OGRXercesBinInputStream(fp, true);
     375             : }
     376             : 
     377             : /************************************************************************/
     378             : /*                        OGRInitializeXerces()                         */
     379             : /************************************************************************/
     380             : 
     381         200 : bool OGRInitializeXerces()
     382             : {
     383         400 :     CPLMutexHolderD(&hOGRXercesMutex);
     384             : 
     385         200 :     if (nCounter > 0)
     386             :     {
     387          39 :         nCounter++;
     388          39 :         return true;
     389             :     }
     390             : 
     391         161 :     if (XMLPlatformUtils::fgMemoryManager != nullptr)
     392             :     {
     393           0 :         CPLDebug("OGR", "Xerces-C already initialized before GDAL");
     394           0 :         bXercesWasAlreadyInitializedBeforeUs = true;
     395           0 :         nCounter = 1;
     396           0 :         return true;
     397             :     }
     398             :     else
     399             :     {
     400         161 :         gpExceptionMemoryManager = new OGRXercesStandardMemoryManager();
     401         161 :         gpMemoryManager = new OGRXercesInstrumentedMemoryManager();
     402             : 
     403             :         try
     404             :         {
     405         161 :             CPLDebug("OGR", "XMLPlatformUtils::Initialize()");
     406         161 :             XMLPlatformUtils::Initialize(XMLUni::fgXercescDefaultLocale,
     407             :                                          nullptr, /* nlsHome */
     408             :                                          nullptr, /* panicHandler */
     409             :                                          gpMemoryManager);
     410             : 
     411             :             // Install our own network accessor instead of the default Xerces-C
     412             :             // one This enables us in particular to honour GDAL_HTTP_TIMEOUT
     413         161 :             if (CPLTestBool(CPLGetConfigOption(
     414             :                     "OGR_XERCES_USE_OGR_NET_ACCESSOR", "YES")))
     415             :             {
     416         161 :                 auto oldNetAccessor = XMLPlatformUtils::fgNetAccessor;
     417         161 :                 XMLPlatformUtils::fgNetAccessor = new OGRXercesNetAccessor();
     418         161 :                 delete oldNetAccessor;
     419             :             }
     420             : 
     421         161 :             nCounter = 1;
     422         161 :             return true;
     423             :         }
     424           0 :         catch (const XMLException &toCatch)
     425             :         {
     426           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     427             :                      "Exception initializing Xerces: %s",
     428           0 :                      transcode(toCatch.getMessage()).c_str());
     429           0 :             return false;
     430             :         }
     431             :     }
     432             : }
     433             : 
     434             : /************************************************************************/
     435             : /*                       OGRDeinitializeXerces()                        */
     436             : /************************************************************************/
     437             : 
     438         200 : void OGRDeinitializeXerces()
     439             : {
     440         200 :     CPLMutexHolderD(&hOGRXercesMutex);
     441         200 :     if (nCounter == 0)
     442             :     {
     443           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     444             :                  "Unpaired OGRInitializeXerces / OGRDeinitializeXerces calls");
     445           0 :         return;
     446             :     }
     447         200 :     nCounter--;
     448         200 :     if (nCounter == 0)
     449             :     {
     450         322 :         if (!bXercesWasAlreadyInitializedBeforeUs &&
     451         161 :             CPLTestBool(CPLGetConfigOption("OGR_XERCES_TERMINATE", "YES")))
     452             :         {
     453         161 :             CPLDebug("OGR", "XMLPlatformUtils::Terminate()");
     454         161 :             XMLPlatformUtils::Terminate();
     455             : 
     456         161 :             delete gpMemoryManager;
     457         161 :             gpMemoryManager = nullptr;
     458         161 :             delete gpExceptionMemoryManager;
     459         161 :             gpExceptionMemoryManager = nullptr;
     460             :         }
     461             :     }
     462             : }
     463             : 
     464             : /************************************************************************/
     465             : /*                       OGRCleanupXercesMutex()                        */
     466             : /************************************************************************/
     467             : 
     468         933 : void OGRCleanupXercesMutex()
     469             : {
     470         933 :     if (hOGRXercesMutex != nullptr)
     471           3 :         CPLDestroyMutex(hOGRXercesMutex);
     472         933 :     hOGRXercesMutex = nullptr;
     473         933 : }
     474             : 
     475             : namespace OGR
     476             : {
     477             : 
     478             : /************************************************************************/
     479             : /*                            transcode()                               */
     480             : /************************************************************************/
     481             : 
     482     3790250 : CPLString transcode(const XMLCh *panXMLString, int nLimitingChars)
     483             : {
     484     3790250 :     CPLString osRet;
     485     3790250 :     transcode(panXMLString, osRet, nLimitingChars);
     486     3790250 :     return osRet;
     487             : }
     488             : 
     489     4323200 : CPLString &transcode(const XMLCh *panXMLString, CPLString &osRet,
     490             :                      int nLimitingChars)
     491             : {
     492     4323200 :     if (panXMLString == nullptr)
     493             :     {
     494           0 :         osRet = "(null)";
     495           0 :         return osRet;
     496             :     }
     497             : 
     498     4323200 :     osRet.clear();
     499     4323200 :     if (nLimitingChars > 0)
     500      106306 :         osRet.reserve(nLimitingChars);
     501             : 
     502     4323200 :     bool bSimpleASCII = true;
     503     4323200 :     int nChars = 0;
     504     4323200 :     for (int i = 0;
     505   144855000 :          panXMLString[i] != 0 && (nLimitingChars < 0 || i < nLimitingChars);
     506             :          i++)
     507             :     {
     508   140532000 :         if (panXMLString[i] > 127)
     509             :         {
     510        2416 :             bSimpleASCII = false;
     511             :         }
     512   140532000 :         osRet += static_cast<char>(panXMLString[i]);
     513   140532000 :         nChars++;
     514             :     }
     515             : 
     516     4323200 :     if (bSimpleASCII)
     517     4322000 :         return osRet;
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      The simple translation was wrong, because the source is not     */
     521             :     /*      all simple ASCII characters.  Redo using the more expensive     */
     522             :     /*      recoding API.                                                   */
     523             :     /* -------------------------------------------------------------------- */
     524             :     wchar_t *pwszSource =
     525        1199 :         static_cast<wchar_t *>(CPLMalloc(sizeof(wchar_t) * (nChars + 1)));
     526      664922 :     for (int i = 0; i < nChars; i++)
     527      663723 :         pwszSource[i] = panXMLString[i];
     528        1199 :     pwszSource[nChars] = 0;
     529             : 
     530        1199 :     char *pszResult = CPLRecodeFromWChar(pwszSource, "WCHAR_T", CPL_ENC_UTF8);
     531             : 
     532        1199 :     osRet = pszResult;
     533             : 
     534        1199 :     CPLFree(pwszSource);
     535        1199 :     CPLFree(pszResult);
     536             : 
     537        1199 :     return osRet;
     538             : }
     539             : 
     540             : }  // namespace OGR
     541             : 
     542             : /************************************************************************/
     543             : /*                       OGRXercesInputSource                           */
     544             : /************************************************************************/
     545             : 
     546          28 : class OGRXercesInputSource : public InputSource
     547             : {
     548             :     OGRXercesBinInputStream *pBinInputStream;
     549             : 
     550             :     CPL_DISALLOW_COPY_ASSIGN(OGRXercesInputSource)
     551             : 
     552             :   public:
     553             :     explicit OGRXercesInputSource(
     554             :         VSILFILE *fp,
     555             :         MemoryManager *const manager = XMLPlatformUtils::fgMemoryManager);
     556             :     ~OGRXercesInputSource() override;
     557             : 
     558          14 :     BinInputStream *makeStream() const override
     559             :     {
     560          14 :         return pBinInputStream;
     561             :     }
     562             : };
     563             : 
     564             : /************************************************************************/
     565             : /*                      OGRXercesBinInputStream()                       */
     566             : /************************************************************************/
     567             : 
     568          14 : OGRXercesBinInputStream::OGRXercesBinInputStream(VSILFILE *fpIn, bool bOwnFPIn)
     569          14 :     : fp(fpIn), bOwnFP(bOwnFPIn)
     570             : {
     571          14 : }
     572             : 
     573             : /************************************************************************/
     574             : /*                     ~OGRXercesBinInputStream()                       */
     575             : /************************************************************************/
     576             : 
     577          28 : OGRXercesBinInputStream::~OGRXercesBinInputStream()
     578             : {
     579          14 :     if (bOwnFP)
     580           0 :         VSIFCloseL(fp);
     581          28 : }
     582             : 
     583             : /************************************************************************/
     584             : /*                              curPos()                                */
     585             : /************************************************************************/
     586             : 
     587           0 : XMLFilePos OGRXercesBinInputStream::curPos() const
     588             : {
     589           0 :     return static_cast<XMLFilePos>(VSIFTellL(fp));
     590             : }
     591             : 
     592             : /************************************************************************/
     593             : /*                            readBytes()                               */
     594             : /************************************************************************/
     595             : 
     596          47 : XMLSize_t OGRXercesBinInputStream::readBytes(XMLByte *const toFill,
     597             :                                              const XMLSize_t maxToRead)
     598             : {
     599          47 :     return static_cast<XMLSize_t>(VSIFReadL(toFill, 1, maxToRead, fp));
     600             : }
     601             : 
     602             : /************************************************************************/
     603             : /*                       OGRXercesInputSource()                         */
     604             : /************************************************************************/
     605             : 
     606          14 : OGRXercesInputSource::OGRXercesInputSource(VSILFILE *fp,
     607          14 :                                            MemoryManager *const manager)
     608             :     : InputSource(manager),
     609          14 :       pBinInputStream(new OGRXercesBinInputStream(fp, false))
     610             : {
     611          14 : }
     612             : 
     613             : /************************************************************************/
     614             : /*                      ~OGRXercesInputSource()                         */
     615             : /************************************************************************/
     616             : 
     617             : OGRXercesInputSource::~OGRXercesInputSource() = default;
     618             : 
     619             : /************************************************************************/
     620             : /*                     OGRCreateXercesInputSource()                     */
     621             : /************************************************************************/
     622             : 
     623          14 : InputSource *OGRCreateXercesInputSource(VSILFILE *fp)
     624             : {
     625          14 :     return new OGRXercesInputSource(fp);
     626             : }
     627             : 
     628             : /************************************************************************/
     629             : /*                     OGRDestroyXercesInputSource()                    */
     630             : /************************************************************************/
     631             : 
     632         531 : void OGRDestroyXercesInputSource(InputSource *is)
     633             : {
     634         531 :     delete is;
     635         531 : }
     636             : 
     637             : #endif  // HAVE_XERCES

Generated by: LCOV version 1.14