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

Generated by: LCOV version 1.14