LCOV - code coverage report
Current view: top level - frmts/pdf - pdfobject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 480 599 80.1 %
Date: 2025-09-10 17:48:50 Functions: 79 87 90.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  PDF driver
       4             :  * Purpose:  GDALDataset driver for PDF dataset.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  *
       9             :  * Support for open-source PDFium library
      10             :  *
      11             :  * Copyright (C) 2015 Klokan Technologies GmbH (http://www.klokantech.com/)
      12             :  * Author: Martin Mikita <martin.mikita@klokantech.com>, xmikit00 @ FIT VUT Brno
      13             :  *
      14             :  ******************************************************************************
      15             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      16             :  *
      17             :  * SPDX-License-Identifier: MIT
      18             :  ****************************************************************************/
      19             : 
      20             : #include "gdal_pdf.h"
      21             : 
      22             : #include <limits>
      23             : #include <vector>
      24             : #include "pdfobject.h"
      25             : 
      26             : /************************************************************************/
      27             : /*                        ROUND_IF_CLOSE()                       */
      28             : /************************************************************************/
      29             : 
      30        4515 : double ROUND_IF_CLOSE(double x, double eps)
      31             : {
      32        4515 :     if (eps == 0.0)
      33        3313 :         eps = fabs(x) < 1 ? 1e-10 : 1e-8;
      34        4515 :     const double dfRounded = std::round(x);
      35        4515 :     if (fabs(x - dfRounded) < eps)
      36        3515 :         return dfRounded;
      37             :     else
      38        1000 :         return x;
      39             : }
      40             : 
      41             : /************************************************************************/
      42             : /*                         GDALPDFGetPDFString()                        */
      43             : /************************************************************************/
      44             : 
      45         631 : static CPLString GDALPDFGetPDFString(const char *pszStr)
      46             : {
      47         631 :     const GByte *pabyData = reinterpret_cast<const GByte *>(pszStr);
      48             :     GByte ch;
      49       20934 :     for (size_t i = 0; (ch = pabyData[i]) != '\0'; i++)
      50             :     {
      51       20311 :         if (ch < 32 || ch > 127 || ch == '(' || ch == ')' || ch == '\\' ||
      52       20303 :             ch == '%' || ch == '#')
      53             :             break;
      54             :     }
      55         631 :     CPLString osStr;
      56         631 :     if (ch == 0)
      57             :     {
      58         623 :         osStr = "(";
      59         623 :         osStr += pszStr;
      60         623 :         osStr += ")";
      61         623 :         return osStr;
      62             :     }
      63             : 
      64           8 :     wchar_t *pwszDest = CPLRecodeToWChar(pszStr, CPL_ENC_UTF8, CPL_ENC_UCS2);
      65           8 :     osStr = "<FEFF";
      66         480 :     for (size_t i = 0; pwszDest[i] != 0; i++)
      67             :     {
      68             : #ifndef _WIN32
      69         472 :         if (pwszDest[i] >= 0x10000 /* && pwszDest[i] <= 0x10FFFF */)
      70             :         {
      71             :             /* Generate UTF-16 surrogate pairs (on Windows, CPLRecodeToWChar
      72             :              * does it for us)  */
      73           0 :             int nHeadSurrogate = ((pwszDest[i] - 0x10000) >> 10) | 0xd800;
      74           0 :             int nTrailSurrogate = ((pwszDest[i] - 0x10000) & 0x3ff) | 0xdc00;
      75           0 :             osStr += CPLSPrintf("%02X", (nHeadSurrogate >> 8) & 0xff);
      76           0 :             osStr += CPLSPrintf("%02X", (nHeadSurrogate)&0xff);
      77           0 :             osStr += CPLSPrintf("%02X", (nTrailSurrogate >> 8) & 0xff);
      78           0 :             osStr += CPLSPrintf("%02X", (nTrailSurrogate)&0xff);
      79             :         }
      80             :         else
      81             : #endif
      82             :         {
      83             :             osStr +=
      84         472 :                 CPLSPrintf("%02X", static_cast<int>(pwszDest[i] >> 8) & 0xff);
      85         472 :             osStr += CPLSPrintf("%02X", static_cast<int>(pwszDest[i]) & 0xff);
      86             :         }
      87             :     }
      88           8 :     osStr += ">";
      89           8 :     CPLFree(pwszDest);
      90           8 :     return osStr;
      91             : }
      92             : 
      93             : #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM)
      94             : 
      95             : /************************************************************************/
      96             : /*                     GDALPDFGetUTF8StringFromBytes()                  */
      97             : /************************************************************************/
      98             : 
      99         436 : static std::string GDALPDFGetUTF8StringFromBytes(const GByte *pabySrc,
     100             :                                                  size_t nLen)
     101             : {
     102         436 :     const bool bLEUnicodeMarker =
     103         436 :         nLen >= 2 && pabySrc[0] == 0xFE && pabySrc[1] == 0xFF;
     104         436 :     const bool bBEUnicodeMarker =
     105         436 :         nLen >= 2 && pabySrc[0] == 0xFF && pabySrc[1] == 0xFE;
     106         436 :     if (!bLEUnicodeMarker && !bBEUnicodeMarker)
     107             :     {
     108           0 :         std::string osStr;
     109             :         try
     110             :         {
     111           0 :             osStr.reserve(nLen);
     112             :         }
     113           0 :         catch (const std::exception &e)
     114             :         {
     115           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     116           0 :                      "GDALPDFGetUTF8StringFromBytes(): %s", e.what());
     117           0 :             return osStr;
     118             :         }
     119           0 :         osStr.assign(reinterpret_cast<const char *>(pabySrc), nLen);
     120           0 :         const char *pszStr = osStr.c_str();
     121           0 :         if (CPLIsUTF8(pszStr, -1))
     122           0 :             return osStr;
     123             :         else
     124             :         {
     125           0 :             char *pszUTF8 = CPLRecode(pszStr, CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     126           0 :             std::string osRet = pszUTF8;
     127           0 :             CPLFree(pszUTF8);
     128           0 :             return osRet;
     129             :         }
     130             :     }
     131             : 
     132             :     /* This is UTF-16 content */
     133         436 :     pabySrc += 2;
     134         436 :     nLen = (nLen - 2) / 2;
     135         872 :     std::wstring awszSource;
     136         436 :     awszSource.resize(nLen + 1);
     137         436 :     size_t j = 0;
     138        6541 :     for (size_t i = 0; i < nLen; i++, j++)
     139             :     {
     140        6105 :         if (!bBEUnicodeMarker)
     141        5105 :             awszSource[j] = (pabySrc[2 * i] << 8) + pabySrc[2 * i + 1];
     142             :         else
     143        1000 :             awszSource[j] = (pabySrc[2 * i + 1] << 8) + pabySrc[2 * i];
     144             : #ifndef _WIN32
     145             :         /* Is there a surrogate pair ? See http://en.wikipedia.org/wiki/UTF-16
     146             :          */
     147             :         /* On Windows, CPLRecodeFromWChar does this for us, because wchar_t is
     148             :          * only */
     149             :         /* 2 bytes wide, whereas on Unix it is 32bits */
     150        6105 :         if (awszSource[j] >= 0xD800 && awszSource[j] <= 0xDBFF && i + 1 < nLen)
     151             :         {
     152             :             /* should be in the range 0xDC00... 0xDFFF */
     153             :             wchar_t nTrailSurrogate;
     154           0 :             if (!bBEUnicodeMarker)
     155           0 :                 nTrailSurrogate =
     156           0 :                     (pabySrc[2 * (i + 1)] << 8) + pabySrc[2 * (i + 1) + 1];
     157             :             else
     158           0 :                 nTrailSurrogate =
     159           0 :                     (pabySrc[2 * (i + 1) + 1] << 8) + pabySrc[2 * (i + 1)];
     160           0 :             if (nTrailSurrogate >= 0xDC00 && nTrailSurrogate <= 0xDFFF)
     161             :             {
     162           0 :                 awszSource[j] = ((awszSource[j] - 0xD800) << 10) +
     163           0 :                                 (nTrailSurrogate - 0xDC00) + 0x10000;
     164           0 :                 i++;
     165             :             }
     166             :         }
     167             : #endif
     168             :     }
     169         436 :     awszSource[j] = 0;
     170             : 
     171             :     char *pszUTF8 =
     172         436 :         CPLRecodeFromWChar(awszSource.data(), CPL_ENC_UCS2, CPL_ENC_UTF8);
     173         436 :     awszSource.clear();
     174         872 :     std::string osStrUTF8(pszUTF8);
     175         436 :     CPLFree(pszUTF8);
     176         436 :     return osStrUTF8;
     177             : }
     178             : 
     179             : #endif  // defined(HAVE_POPPLER) || defined(HAVE_PDFIUM)
     180             : 
     181             : /************************************************************************/
     182             : /*                          GDALPDFGetPDFName()                         */
     183             : /************************************************************************/
     184             : 
     185        2147 : static std::string GDALPDFGetPDFName(const std::string &osStr)
     186             : {
     187        2147 :     std::string osRet;
     188       18209 :     for (const char ch : osStr)
     189             :     {
     190       16062 :         if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
     191          12 :               (ch >= '0' && ch <= '9') || ch == '-'))
     192           0 :             osRet += '_';
     193             :         else
     194       16062 :             osRet += ch;
     195             :     }
     196        2147 :     return osRet;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /* ==================================================================== */
     201             : /*                            GDALPDFObject                             */
     202             : /* ==================================================================== */
     203             : /************************************************************************/
     204             : 
     205             : /************************************************************************/
     206             : /*                            ~GDALPDFObject()                          */
     207             : /************************************************************************/
     208             : 
     209       26291 : GDALPDFObject::~GDALPDFObject()
     210             : {
     211       26291 : }
     212             : 
     213             : /************************************************************************/
     214             : /*                            LookupObject()                            */
     215             : /************************************************************************/
     216             : 
     217        1214 : GDALPDFObject *GDALPDFObject::LookupObject(const char *pszPath)
     218             : {
     219        1214 :     if (GetType() != PDFObjectType_Dictionary)
     220           0 :         return nullptr;
     221        1214 :     return GetDictionary()->LookupObject(pszPath);
     222             : }
     223             : 
     224             : /************************************************************************/
     225             : /*                             GetTypeName()                            */
     226             : /************************************************************************/
     227             : 
     228          70 : const char *GDALPDFObject::GetTypeName()
     229             : {
     230          70 :     switch (GetType())
     231             :     {
     232           0 :         case PDFObjectType_Unknown:
     233           0 :             return GetTypeNameNative();
     234           0 :         case PDFObjectType_Null:
     235           0 :             return "null";
     236           0 :         case PDFObjectType_Bool:
     237           0 :             return "bool";
     238           0 :         case PDFObjectType_Int:
     239           0 :             return "int";
     240           0 :         case PDFObjectType_Real:
     241           0 :             return "real";
     242           0 :         case PDFObjectType_String:
     243           0 :             return "string";
     244           0 :         case PDFObjectType_Name:
     245           0 :             return "name";
     246           3 :         case PDFObjectType_Array:
     247           3 :             return "array";
     248          67 :         case PDFObjectType_Dictionary:
     249          67 :             return "dictionary";
     250           0 :         default:
     251           0 :             return GetTypeNameNative();
     252             :     }
     253             : }
     254             : 
     255             : /************************************************************************/
     256             : /*                             Serialize()                              */
     257             : /************************************************************************/
     258             : 
     259       10768 : void GDALPDFObject::Serialize(CPLString &osStr, bool bEmitRef)
     260             : {
     261       10768 :     auto nRefNum = GetRefNum();
     262       10768 :     if (bEmitRef && nRefNum.toBool())
     263             :     {
     264        2088 :         int nRefGen = GetRefGen();
     265        2088 :         osStr.append(CPLSPrintf("%d %d R", nRefNum.toInt(), nRefGen));
     266        2088 :         return;
     267             :     }
     268             : 
     269        8680 :     switch (GetType())
     270             :     {
     271          12 :         case PDFObjectType_Null:
     272          12 :             osStr.append("null");
     273          12 :             return;
     274          23 :         case PDFObjectType_Bool:
     275          23 :             osStr.append(GetBool() ? "true" : "false");
     276          23 :             return;
     277        2453 :         case PDFObjectType_Int:
     278        2453 :             osStr.append(CPLSPrintf("%d", GetInt()));
     279        2453 :             return;
     280        1653 :         case PDFObjectType_Real:
     281             :         {
     282             :             char szReal[512];
     283        1653 :             double dfRealNonRounded = GetReal();
     284        1653 :             double dfReal = ROUND_IF_CLOSE(dfRealNonRounded);
     285        1653 :             if (dfReal >=
     286        1653 :                     static_cast<double>(std::numeric_limits<GIntBig>::min()) &&
     287             :                 dfReal <=
     288        3306 :                     static_cast<double>(std::numeric_limits<GIntBig>::max()) &&
     289        1653 :                 dfReal == static_cast<double>(static_cast<GIntBig>(dfReal)))
     290             :             {
     291        1225 :                 snprintf(szReal, sizeof(szReal), CPL_FRMT_GIB,
     292             :                          static_cast<GIntBig>(dfReal));
     293             :             }
     294         428 :             else if (CanRepresentRealAsString())
     295             :             {
     296             :                 /* Used for OGC BP numeric values */
     297           0 :                 CPLsnprintf(szReal, sizeof(szReal), "(%.*g)", GetPrecision(),
     298             :                             dfReal);
     299             :             }
     300             :             else
     301             :             {
     302         428 :                 CPLsnprintf(szReal, sizeof(szReal), "%.*f", GetPrecision(),
     303             :                             dfReal);
     304             : 
     305             :                 /* Remove non significant trailing zeroes */
     306         428 :                 char *pszDot = strchr(szReal, '.');
     307         428 :                 if (pszDot)
     308             :                 {
     309         428 :                     int iDot = static_cast<int>(pszDot - szReal);
     310         428 :                     int nLen = static_cast<int>(strlen(szReal));
     311        2174 :                     for (int i = nLen - 1; i > iDot; i--)
     312             :                     {
     313        2174 :                         if (szReal[i] == '0')
     314        1746 :                             szReal[i] = '\0';
     315             :                         else
     316         428 :                             break;
     317             :                     }
     318             :                 }
     319             :             }
     320        1653 :             osStr.append(szReal);
     321        1653 :             return;
     322             :         }
     323         631 :         case PDFObjectType_String:
     324         631 :             osStr.append(GDALPDFGetPDFString(GetString().c_str()));
     325         631 :             return;
     326        2147 :         case PDFObjectType_Name:
     327        2147 :             osStr.append("/");
     328        2147 :             osStr.append(GDALPDFGetPDFName(GetName()));
     329        2147 :             return;
     330         839 :         case PDFObjectType_Array:
     331         839 :             GetArray()->Serialize(osStr);
     332         839 :             return;
     333         922 :         case PDFObjectType_Dictionary:
     334         922 :             GetDictionary()->Serialize(osStr);
     335         922 :             return;
     336           0 :         case PDFObjectType_Unknown:
     337             :         default:
     338           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     339             :                      "Serializing unknown object !");
     340           0 :             return;
     341             :     }
     342             : }
     343             : 
     344             : /************************************************************************/
     345             : /*                               Clone()                                */
     346             : /************************************************************************/
     347             : 
     348         158 : GDALPDFObjectRW *GDALPDFObject::Clone()
     349             : {
     350         158 :     auto nRefNum = GetRefNum();
     351         158 :     if (nRefNum.toBool())
     352             :     {
     353          63 :         int nRefGen = GetRefGen();
     354          63 :         return GDALPDFObjectRW::CreateIndirect(nRefNum, nRefGen);
     355             :     }
     356             : 
     357          95 :     switch (GetType())
     358             :     {
     359           0 :         case PDFObjectType_Null:
     360           0 :             return GDALPDFObjectRW::CreateNull();
     361           0 :         case PDFObjectType_Bool:
     362           0 :             return GDALPDFObjectRW::CreateBool(GetBool());
     363          54 :         case PDFObjectType_Int:
     364          54 :             return GDALPDFObjectRW::CreateInt(GetInt());
     365           4 :         case PDFObjectType_Real:
     366           4 :             return GDALPDFObjectRW::CreateReal(GetReal());
     367           0 :         case PDFObjectType_String:
     368           0 :             return GDALPDFObjectRW::CreateString(GetString().c_str());
     369          15 :         case PDFObjectType_Name:
     370          15 :             return GDALPDFObjectRW::CreateName(GetName().c_str());
     371          22 :         case PDFObjectType_Array:
     372          22 :             return GDALPDFObjectRW::CreateArray(GetArray()->Clone());
     373           0 :         case PDFObjectType_Dictionary:
     374           0 :             return GDALPDFObjectRW::CreateDictionary(GetDictionary()->Clone());
     375           0 :         case PDFObjectType_Unknown:
     376             :         default:
     377           0 :             CPLError(CE_Warning, CPLE_AppDefined, "Cloning unknown object !");
     378           0 :             return nullptr;
     379             :     }
     380             : }
     381             : 
     382             : /************************************************************************/
     383             : /* ==================================================================== */
     384             : /*                         GDALPDFDictionary                            */
     385             : /* ==================================================================== */
     386             : /************************************************************************/
     387             : 
     388             : /************************************************************************/
     389             : /*                        ~GDALPDFDictionary()                          */
     390             : /************************************************************************/
     391             : 
     392        6905 : GDALPDFDictionary::~GDALPDFDictionary()
     393             : {
     394        6905 : }
     395             : 
     396             : /************************************************************************/
     397             : /*                            LookupObject()                            */
     398             : /************************************************************************/
     399             : 
     400        1681 : GDALPDFObject *GDALPDFDictionary::LookupObject(const char *pszPath)
     401             : {
     402        1681 :     GDALPDFObject *poCurObj = nullptr;
     403        1681 :     char **papszTokens = CSLTokenizeString2(pszPath, ".", 0);
     404        4026 :     for (int i = 0; papszTokens[i] != nullptr; i++)
     405             :     {
     406        3028 :         int iElt = -1;
     407        3028 :         char *pszBracket = strchr(papszTokens[i], '[');
     408        3028 :         if (pszBracket != nullptr)
     409             :         {
     410           0 :             iElt = atoi(pszBracket + 1);
     411           0 :             *pszBracket = '\0';
     412             :         }
     413             : 
     414        3028 :         if (i == 0)
     415             :         {
     416        1681 :             poCurObj = Get(papszTokens[i]);
     417             :         }
     418             :         else
     419             :         {
     420        1347 :             if (poCurObj->GetType() != PDFObjectType_Dictionary)
     421             :             {
     422           0 :                 poCurObj = nullptr;
     423           0 :                 break;
     424             :             }
     425        1347 :             poCurObj = poCurObj->GetDictionary()->Get(papszTokens[i]);
     426             :         }
     427             : 
     428        3028 :         if (poCurObj == nullptr)
     429             :         {
     430         683 :             poCurObj = nullptr;
     431         683 :             break;
     432             :         }
     433             : 
     434        2345 :         if (iElt >= 0)
     435             :         {
     436           0 :             if (poCurObj->GetType() != PDFObjectType_Array)
     437             :             {
     438           0 :                 poCurObj = nullptr;
     439           0 :                 break;
     440             :             }
     441           0 :             poCurObj = poCurObj->GetArray()->Get(iElt);
     442             :         }
     443             :     }
     444        1681 :     CSLDestroy(papszTokens);
     445        1681 :     return poCurObj;
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                             Serialize()                              */
     450             : /************************************************************************/
     451             : 
     452        2204 : void GDALPDFDictionary::Serialize(CPLString &osStr)
     453             : {
     454        2204 :     osStr.append("<< ");
     455        9359 :     for (const auto &oIter : GetValues())
     456             :     {
     457        7155 :         const char *pszKey = oIter.first.c_str();
     458        7155 :         GDALPDFObject *poObj = oIter.second;
     459        7155 :         osStr.append("/");
     460        7155 :         osStr.append(pszKey);
     461        7155 :         osStr.append(" ");
     462        7155 :         poObj->Serialize(osStr);
     463        7155 :         osStr.append(" ");
     464             :     }
     465        2204 :     osStr.append(">>");
     466        2204 : }
     467             : 
     468             : /************************************************************************/
     469             : /*                               Clone()                                */
     470             : /************************************************************************/
     471             : 
     472          15 : GDALPDFDictionaryRW *GDALPDFDictionary::Clone()
     473             : {
     474          15 :     GDALPDFDictionaryRW *poDict = new GDALPDFDictionaryRW();
     475         115 :     for (const auto &oIter : GetValues())
     476             :     {
     477         100 :         const char *pszKey = oIter.first.c_str();
     478         100 :         GDALPDFObject *poObj = oIter.second;
     479         100 :         poDict->Add(pszKey, poObj->Clone());
     480             :     }
     481          15 :     return poDict;
     482             : }
     483             : 
     484             : /************************************************************************/
     485             : /* ==================================================================== */
     486             : /*                           GDALPDFArray                               */
     487             : /* ==================================================================== */
     488             : /************************************************************************/
     489             : 
     490             : /************************************************************************/
     491             : /*                           ~GDALPDFArray()                            */
     492             : /************************************************************************/
     493             : 
     494        2210 : GDALPDFArray::~GDALPDFArray()
     495             : {
     496        2210 : }
     497             : 
     498             : /************************************************************************/
     499             : /*                             Serialize()                              */
     500             : /************************************************************************/
     501             : 
     502         914 : void GDALPDFArray::Serialize(CPLString &osStr)
     503             : {
     504         914 :     int nLength = GetLength();
     505             :     int i;
     506             : 
     507         914 :     osStr.append("[ ");
     508        4059 :     for (i = 0; i < nLength; i++)
     509             :     {
     510        3145 :         Get(i)->Serialize(osStr);
     511        3145 :         osStr.append(" ");
     512             :     }
     513         914 :     osStr.append("]");
     514         914 : }
     515             : 
     516             : /************************************************************************/
     517             : /*                               Clone()                                */
     518             : /************************************************************************/
     519             : 
     520          22 : GDALPDFArrayRW *GDALPDFArray::Clone()
     521             : {
     522          22 :     GDALPDFArrayRW *poArray = new GDALPDFArrayRW();
     523          22 :     int nLength = GetLength();
     524             :     int i;
     525          80 :     for (i = 0; i < nLength; i++)
     526             :     {
     527          58 :         poArray->Add(Get(i)->Clone());
     528             :     }
     529          22 :     return poArray;
     530             : }
     531             : 
     532             : /************************************************************************/
     533             : /* ==================================================================== */
     534             : /*                           GDALPDFStream                              */
     535             : /* ==================================================================== */
     536             : /************************************************************************/
     537             : 
     538             : /************************************************************************/
     539             : /*                           ~GDALPDFStream()                           */
     540             : /************************************************************************/
     541             : 
     542             : GDALPDFStream::~GDALPDFStream() = default;
     543             : 
     544             : /************************************************************************/
     545             : /* ==================================================================== */
     546             : /*                           GDALPDFObjectRW                            */
     547             : /* ==================================================================== */
     548             : /************************************************************************/
     549             : 
     550             : /************************************************************************/
     551             : /*                           GDALPDFObjectRW()                          */
     552             : /************************************************************************/
     553             : 
     554       10851 : GDALPDFObjectRW::GDALPDFObjectRW(GDALPDFObjectType eType) : m_eType(eType)
     555             : {
     556       10851 : }
     557             : 
     558             : /************************************************************************/
     559             : /*                             ~GDALPDFObjectRW()                       */
     560             : /************************************************************************/
     561             : 
     562       21702 : GDALPDFObjectRW::~GDALPDFObjectRW()
     563             : {
     564       10851 :     delete m_poDict;
     565       10851 :     delete m_poArray;
     566       21702 : }
     567             : 
     568             : /************************************************************************/
     569             : /*                            CreateIndirect()                          */
     570             : /************************************************************************/
     571             : 
     572        2125 : GDALPDFObjectRW *GDALPDFObjectRW::CreateIndirect(const GDALPDFObjectNum &nNum,
     573             :                                                  int nGen)
     574             : {
     575        2125 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Unknown);
     576        2125 :     poObj->m_nNum = nNum;
     577        2125 :     poObj->m_nGen = nGen;
     578        2125 :     return poObj;
     579             : }
     580             : 
     581             : /************************************************************************/
     582             : /*                             CreateNull()                             */
     583             : /************************************************************************/
     584             : 
     585          12 : GDALPDFObjectRW *GDALPDFObjectRW::CreateNull()
     586             : {
     587          12 :     return new GDALPDFObjectRW(PDFObjectType_Null);
     588             : }
     589             : 
     590             : /************************************************************************/
     591             : /*                             CreateBool()                             */
     592             : /************************************************************************/
     593             : 
     594          23 : GDALPDFObjectRW *GDALPDFObjectRW::CreateBool(int bVal)
     595             : {
     596          23 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Bool);
     597          23 :     poObj->m_nVal = bVal;
     598          23 :     return poObj;
     599             : }
     600             : 
     601             : /************************************************************************/
     602             : /*                             CreateInt()                              */
     603             : /************************************************************************/
     604             : 
     605        2477 : GDALPDFObjectRW *GDALPDFObjectRW::CreateInt(int nVal)
     606             : {
     607        2477 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Int);
     608        2477 :     poObj->m_nVal = nVal;
     609        2477 :     return poObj;
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                            CreateReal()                              */
     614             : /************************************************************************/
     615             : 
     616        1591 : GDALPDFObjectRW *GDALPDFObjectRW::CreateReal(double dfVal,
     617             :                                              int bCanRepresentRealAsString)
     618             : {
     619        1591 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Real);
     620        1591 :     poObj->m_dfVal = dfVal;
     621        1591 :     poObj->m_bCanRepresentRealAsString = bCanRepresentRealAsString;
     622        1591 :     return poObj;
     623             : }
     624             : 
     625             : /************************************************************************/
     626             : /*                       CreateRealWithPrecision()                      */
     627             : /************************************************************************/
     628             : 
     629          64 : GDALPDFObjectRW *GDALPDFObjectRW::CreateRealWithPrecision(double dfVal,
     630             :                                                           int nPrecision)
     631             : {
     632          64 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Real);
     633          64 :     poObj->m_dfVal = dfVal;
     634          64 :     poObj->m_nPrecision = nPrecision;
     635          64 :     return poObj;
     636             : }
     637             : 
     638             : /************************************************************************/
     639             : /*                           CreateString()                             */
     640             : /************************************************************************/
     641             : 
     642         631 : GDALPDFObjectRW *GDALPDFObjectRW::CreateString(const char *pszStr)
     643             : {
     644         631 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_String);
     645         631 :     poObj->m_osVal = pszStr;
     646         631 :     return poObj;
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                            CreateName()                              */
     651             : /************************************************************************/
     652             : 
     653        2149 : GDALPDFObjectRW *GDALPDFObjectRW::CreateName(const char *pszName)
     654             : {
     655        2149 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Name);
     656        2149 :     poObj->m_osVal = pszName;
     657        2149 :     return poObj;
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                          CreateDictionary()                          */
     662             : /************************************************************************/
     663             : 
     664         923 : GDALPDFObjectRW *GDALPDFObjectRW::CreateDictionary(GDALPDFDictionaryRW *poDict)
     665             : {
     666         923 :     CPLAssert(poDict);
     667         923 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Dictionary);
     668         923 :     poObj->m_poDict = poDict;
     669         923 :     return poObj;
     670             : }
     671             : 
     672             : /************************************************************************/
     673             : /*                            CreateArray()                             */
     674             : /************************************************************************/
     675             : 
     676         856 : GDALPDFObjectRW *GDALPDFObjectRW::CreateArray(GDALPDFArrayRW *poArray)
     677             : {
     678         856 :     CPLAssert(poArray);
     679         856 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Array);
     680         856 :     poObj->m_poArray = poArray;
     681         856 :     return poObj;
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                          GetTypeNameNative()                         */
     686             : /************************************************************************/
     687             : 
     688           0 : const char *GDALPDFObjectRW::GetTypeNameNative()
     689             : {
     690           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Should not go here");
     691           0 :     return "";
     692             : }
     693             : 
     694             : /************************************************************************/
     695             : /*                             GetType()                                */
     696             : /************************************************************************/
     697             : 
     698        8664 : GDALPDFObjectType GDALPDFObjectRW::GetType()
     699             : {
     700        8664 :     return m_eType;
     701             : }
     702             : 
     703             : /************************************************************************/
     704             : /*                             GetBool()                                */
     705             : /************************************************************************/
     706             : 
     707          23 : int GDALPDFObjectRW::GetBool()
     708             : {
     709          23 :     if (m_eType == PDFObjectType_Bool)
     710          23 :         return m_nVal;
     711             : 
     712           0 :     return FALSE;
     713             : }
     714             : 
     715             : /************************************************************************/
     716             : /*                               GetInt()                               */
     717             : /************************************************************************/
     718             : 
     719        2445 : int GDALPDFObjectRW::GetInt()
     720             : {
     721        2445 :     if (m_eType == PDFObjectType_Int)
     722        2445 :         return m_nVal;
     723             : 
     724           0 :     return 0;
     725             : }
     726             : 
     727             : /************************************************************************/
     728             : /*                              GetReal()                               */
     729             : /************************************************************************/
     730             : 
     731        1653 : double GDALPDFObjectRW::GetReal()
     732             : {
     733        1653 :     return m_dfVal;
     734             : }
     735             : 
     736             : /************************************************************************/
     737             : /*                             GetString()                              */
     738             : /************************************************************************/
     739             : 
     740         631 : const CPLString &GDALPDFObjectRW::GetString()
     741             : {
     742         631 :     return m_osVal;
     743             : }
     744             : 
     745             : /************************************************************************/
     746             : /*                              GetName()                               */
     747             : /************************************************************************/
     748             : 
     749        2139 : const CPLString &GDALPDFObjectRW::GetName()
     750             : {
     751        2139 :     return m_osVal;
     752             : }
     753             : 
     754             : /************************************************************************/
     755             : /*                            GetDictionary()                           */
     756             : /************************************************************************/
     757             : 
     758         922 : GDALPDFDictionary *GDALPDFObjectRW::GetDictionary()
     759             : {
     760         922 :     return m_poDict;
     761             : }
     762             : 
     763             : /************************************************************************/
     764             : /*                              GetArray()                              */
     765             : /************************************************************************/
     766             : 
     767         839 : GDALPDFArray *GDALPDFObjectRW::GetArray()
     768             : {
     769         839 :     return m_poArray;
     770             : }
     771             : 
     772             : /************************************************************************/
     773             : /*                              GetStream()                             */
     774             : /************************************************************************/
     775             : 
     776           0 : GDALPDFStream *GDALPDFObjectRW::GetStream()
     777             : {
     778           0 :     return nullptr;
     779             : }
     780             : 
     781             : /************************************************************************/
     782             : /*                              GetRefNum()                             */
     783             : /************************************************************************/
     784             : 
     785       10754 : GDALPDFObjectNum GDALPDFObjectRW::GetRefNum()
     786             : {
     787       10754 :     return m_nNum;
     788             : }
     789             : 
     790             : /************************************************************************/
     791             : /*                              GetRefGen()                             */
     792             : /************************************************************************/
     793             : 
     794        2090 : int GDALPDFObjectRW::GetRefGen()
     795             : {
     796        2090 :     return m_nGen;
     797             : }
     798             : 
     799             : /************************************************************************/
     800             : /* ==================================================================== */
     801             : /*                          GDALPDFDictionaryRW                         */
     802             : /* ==================================================================== */
     803             : /************************************************************************/
     804             : 
     805             : /************************************************************************/
     806             : /*                           GDALPDFDictionaryRW()                      */
     807             : /************************************************************************/
     808             : 
     809             : GDALPDFDictionaryRW::GDALPDFDictionaryRW() = default;
     810             : 
     811             : /************************************************************************/
     812             : /*                          ~GDALPDFDictionaryRW()                      */
     813             : /************************************************************************/
     814             : 
     815        3150 : GDALPDFDictionaryRW::~GDALPDFDictionaryRW()
     816             : {
     817        2212 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
     818        2212 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
     819        9422 :     for (; oIter != oEnd; ++oIter)
     820        7210 :         delete oIter->second;
     821        3150 : }
     822             : 
     823             : /************************************************************************/
     824             : /*                                   Get()                              */
     825             : /************************************************************************/
     826             : 
     827           3 : GDALPDFObject *GDALPDFDictionaryRW::Get(const char *pszKey)
     828             : {
     829           3 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
     830           3 :     if (oIter != m_map.end())
     831           2 :         return oIter->second;
     832           1 :     return nullptr;
     833             : }
     834             : 
     835             : /************************************************************************/
     836             : /*                               GetValues()                            */
     837             : /************************************************************************/
     838             : 
     839        2204 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryRW::GetValues()
     840             : {
     841        2204 :     return m_map;
     842             : }
     843             : 
     844             : /************************************************************************/
     845             : /*                                 Add()                                */
     846             : /************************************************************************/
     847             : 
     848        7216 : GDALPDFDictionaryRW &GDALPDFDictionaryRW::Add(const char *pszKey,
     849             :                                               GDALPDFObject *poVal)
     850             : {
     851        7216 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
     852        7216 :     if (oIter != m_map.end())
     853             :     {
     854           0 :         delete oIter->second;
     855           0 :         oIter->second = poVal;
     856             :     }
     857             :     else
     858        7216 :         m_map[pszKey] = poVal;
     859             : 
     860        7216 :     return *this;
     861             : }
     862             : 
     863             : /************************************************************************/
     864             : /*                                Remove()                              */
     865             : /************************************************************************/
     866             : 
     867          15 : GDALPDFDictionaryRW &GDALPDFDictionaryRW::Remove(const char *pszKey)
     868             : {
     869          15 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
     870          15 :     if (oIter != m_map.end())
     871             :     {
     872           6 :         delete oIter->second;
     873           6 :         m_map.erase(pszKey);
     874             :     }
     875             : 
     876          15 :     return *this;
     877             : }
     878             : 
     879             : /************************************************************************/
     880             : /* ==================================================================== */
     881             : /*                            GDALPDFArrayRW                            */
     882             : /* ==================================================================== */
     883             : /************************************************************************/
     884             : 
     885             : /************************************************************************/
     886             : /*                             GDALPDFArrayRW()                         */
     887             : /************************************************************************/
     888             : 
     889         931 : GDALPDFArrayRW::GDALPDFArrayRW()
     890             : {
     891         931 : }
     892             : 
     893             : /************************************************************************/
     894             : /*                            ~GDALPDFArrayRW()                         */
     895             : /************************************************************************/
     896             : 
     897        1787 : GDALPDFArrayRW::~GDALPDFArrayRW()
     898             : {
     899        4114 :     for (size_t i = 0; i < m_array.size(); i++)
     900        3183 :         delete m_array[i];
     901        1787 : }
     902             : 
     903             : /************************************************************************/
     904             : /*                               GetLength()                             */
     905             : /************************************************************************/
     906             : 
     907        4060 : int GDALPDFArrayRW::GetLength()
     908             : {
     909        4060 :     return static_cast<int>(m_array.size());
     910             : }
     911             : 
     912             : /************************************************************************/
     913             : /*                                  Get()                               */
     914             : /************************************************************************/
     915             : 
     916        3145 : GDALPDFObject *GDALPDFArrayRW::Get(int nIndex)
     917             : {
     918        3145 :     if (nIndex < 0 || nIndex >= GetLength())
     919           0 :         return nullptr;
     920        3145 :     return m_array[nIndex];
     921             : }
     922             : 
     923             : /************************************************************************/
     924             : /*                                  Add()                               */
     925             : /************************************************************************/
     926             : 
     927        3183 : GDALPDFArrayRW &GDALPDFArrayRW::Add(GDALPDFObject *poObj)
     928             : {
     929        3183 :     m_array.push_back(poObj);
     930        3183 :     return *this;
     931             : }
     932             : 
     933             : /************************************************************************/
     934             : /*                                  Add()                               */
     935             : /************************************************************************/
     936             : 
     937           0 : GDALPDFArrayRW &GDALPDFArrayRW::Add(double *padfVal, int nCount,
     938             :                                     int bCanRepresentRealAsString)
     939             : {
     940           0 :     for (int i = 0; i < nCount; i++)
     941           0 :         m_array.push_back(
     942           0 :             GDALPDFObjectRW::CreateReal(padfVal[i], bCanRepresentRealAsString));
     943           0 :     return *this;
     944             : }
     945             : 
     946             : #ifdef HAVE_POPPLER
     947             : 
     948             : /************************************************************************/
     949             : /* ==================================================================== */
     950             : /*                         GDALPDFDictionaryPoppler                     */
     951             : /* ==================================================================== */
     952             : /************************************************************************/
     953             : 
     954             : class GDALPDFDictionaryPoppler final : public GDALPDFDictionary
     955             : {
     956             :   private:
     957             :     Dict *m_poDict;
     958             :     std::map<CPLString, GDALPDFObject *> m_map{};
     959             : 
     960             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFDictionaryPoppler)
     961             : 
     962             :   public:
     963        4693 :     GDALPDFDictionaryPoppler(Dict *poDict) : m_poDict(poDict)
     964             :     {
     965        4693 :     }
     966             : 
     967             :     ~GDALPDFDictionaryPoppler() override;
     968             : 
     969             :     GDALPDFObject *Get(const char *pszKey) override;
     970             :     std::map<CPLString, GDALPDFObject *> &GetValues() override;
     971             : };
     972             : 
     973             : /************************************************************************/
     974             : /* ==================================================================== */
     975             : /*                           GDALPDFArrayPoppler                        */
     976             : /* ==================================================================== */
     977             : /************************************************************************/
     978             : 
     979             : class GDALPDFArrayPoppler final : public GDALPDFArray
     980             : {
     981             :   private:
     982             :     const Array *m_poArray;
     983             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
     984             : 
     985             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPoppler)
     986             : 
     987             :   public:
     988        1279 :     GDALPDFArrayPoppler(const Array *poArray) : m_poArray(poArray)
     989             :     {
     990        1279 :     }
     991             : 
     992             :     int GetLength() override;
     993             :     GDALPDFObject *Get(int nIndex) override;
     994             : };
     995             : 
     996             : /************************************************************************/
     997             : /* ==================================================================== */
     998             : /*                           GDALPDFStreamPoppler                       */
     999             : /* ==================================================================== */
    1000             : /************************************************************************/
    1001             : 
    1002             : class GDALPDFStreamPoppler final : public GDALPDFStream
    1003             : {
    1004             :   private:
    1005             :     int64_t m_nLength = -1;
    1006             :     Stream *m_poStream;
    1007             :     int64_t m_nRawLength = -1;
    1008             : 
    1009             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFStreamPoppler)
    1010             : 
    1011             :   public:
    1012         451 :     GDALPDFStreamPoppler(Stream *poStream) : m_poStream(poStream)
    1013             :     {
    1014         451 :     }
    1015             : 
    1016             :     int64_t GetLength(int64_t nMaxSize = 0) override;
    1017             :     char *GetBytes() override;
    1018             : 
    1019             :     int64_t GetRawLength() override;
    1020             :     char *GetRawBytes() override;
    1021             : };
    1022             : 
    1023             : /************************************************************************/
    1024             : /* ==================================================================== */
    1025             : /*                         GDALPDFObjectPoppler                         */
    1026             : /* ==================================================================== */
    1027             : /************************************************************************/
    1028             : 
    1029             : /************************************************************************/
    1030             : /*                          ~GDALPDFObjectPoppler()                     */
    1031             : /************************************************************************/
    1032             : 
    1033       30666 : GDALPDFObjectPoppler::~GDALPDFObjectPoppler()
    1034             : {
    1035       15440 :     delete m_poToDestroy;
    1036       15440 :     delete m_poDict;
    1037       15440 :     delete m_poArray;
    1038       15440 :     delete m_poStream;
    1039       30666 : }
    1040             : 
    1041             : /************************************************************************/
    1042             : /*                              GetType()                               */
    1043             : /************************************************************************/
    1044             : 
    1045       60248 : GDALPDFObjectType GDALPDFObjectPoppler::GetType()
    1046             : {
    1047       60248 :     switch (m_poConst->getType())
    1048             :     {
    1049         175 :         case objNull:
    1050         175 :             return PDFObjectType_Null;
    1051           0 :         case objBool:
    1052           0 :             return PDFObjectType_Bool;
    1053       16777 :         case objInt:
    1054       16777 :             return PDFObjectType_Int;
    1055        4876 :         case objReal:
    1056        4876 :             return PDFObjectType_Real;
    1057        2636 :         case objString:
    1058        2636 :             return PDFObjectType_String;
    1059        6617 :         case objName:
    1060        6617 :             return PDFObjectType_Name;
    1061       13083 :         case objArray:
    1062       13083 :             return PDFObjectType_Array;
    1063       11906 :         case objDict:
    1064       11906 :             return PDFObjectType_Dictionary;
    1065        4178 :         case objStream:
    1066        4178 :             return PDFObjectType_Dictionary;
    1067           0 :         default:
    1068           0 :             return PDFObjectType_Unknown;
    1069             :     }
    1070             : }
    1071             : 
    1072             : /************************************************************************/
    1073             : /*                          GetTypeNameNative()                         */
    1074             : /************************************************************************/
    1075             : 
    1076           0 : const char *GDALPDFObjectPoppler::GetTypeNameNative()
    1077             : {
    1078           0 :     return m_poConst->getTypeName();
    1079             : }
    1080             : 
    1081             : /************************************************************************/
    1082             : /*                               GetBool()                              */
    1083             : /************************************************************************/
    1084             : 
    1085           0 : int GDALPDFObjectPoppler::GetBool()
    1086             : {
    1087           0 :     if (GetType() == PDFObjectType_Bool)
    1088           0 :         return m_poConst->getBool();
    1089             :     else
    1090           0 :         return 0;
    1091             : }
    1092             : 
    1093             : /************************************************************************/
    1094             : /*                               GetInt()                               */
    1095             : /************************************************************************/
    1096             : 
    1097        5358 : int GDALPDFObjectPoppler::GetInt()
    1098             : {
    1099        5358 :     if (GetType() == PDFObjectType_Int)
    1100        5358 :         return m_poConst->getInt();
    1101             :     else
    1102           0 :         return 0;
    1103             : }
    1104             : 
    1105             : /************************************************************************/
    1106             : /*                               GetReal()                              */
    1107             : /************************************************************************/
    1108             : 
    1109        1214 : double GDALPDFObjectPoppler::GetReal()
    1110             : {
    1111        1214 :     if (GetType() == PDFObjectType_Real)
    1112        1214 :         return m_poConst->getReal();
    1113             :     else
    1114           0 :         return 0.0;
    1115             : }
    1116             : 
    1117             : /************************************************************************/
    1118             : /*                              GetString()                             */
    1119             : /************************************************************************/
    1120             : 
    1121        1357 : const std::string &GDALPDFObjectPoppler::GetString()
    1122             : {
    1123        1357 :     if (GetType() == PDFObjectType_String)
    1124             :     {
    1125        1357 :         const GooString *gooString = m_poConst->getString();
    1126        1357 :         const std::string &osStdStr = gooString->toStr();
    1127             :         const bool bLEUnicodeMarker =
    1128        1703 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFE &&
    1129         346 :             static_cast<uint8_t>(osStdStr[1]) == 0xFF;
    1130             :         const bool bBEUnicodeMarker =
    1131        1447 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFF &&
    1132          90 :             static_cast<uint8_t>(osStdStr[1]) == 0xFE;
    1133        1357 :         if (!bLEUnicodeMarker && !bBEUnicodeMarker)
    1134             :         {
    1135         921 :             if (CPLIsUTF8(osStdStr.c_str(), -1))
    1136             :             {
    1137         921 :                 return osStdStr;
    1138             :             }
    1139             :             else
    1140             :             {
    1141             :                 char *pszUTF8 =
    1142           0 :                     CPLRecode(osStdStr.data(), CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
    1143           0 :                 osStr = pszUTF8;
    1144           0 :                 CPLFree(pszUTF8);
    1145           0 :                 return osStr;
    1146             :             }
    1147             :         }
    1148        1308 :         return (osStr = GDALPDFGetUTF8StringFromBytes(
    1149         436 :                     reinterpret_cast<const GByte *>(osStdStr.data()),
    1150         436 :                     osStdStr.size()));
    1151             :     }
    1152             :     else
    1153           0 :         return (osStr = "");
    1154             : }
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                               GetName()                              */
    1158             : /************************************************************************/
    1159             : 
    1160        2910 : const std::string &GDALPDFObjectPoppler::GetName()
    1161             : {
    1162        2910 :     if (GetType() == PDFObjectType_Name)
    1163        2910 :         return (osStr = m_poConst->getName());
    1164             :     else
    1165           0 :         return (osStr = "");
    1166             : }
    1167             : 
    1168             : /************************************************************************/
    1169             : /*                            GetDictionary()                           */
    1170             : /************************************************************************/
    1171             : 
    1172        7485 : GDALPDFDictionary *GDALPDFObjectPoppler::GetDictionary()
    1173             : {
    1174        7485 :     if (GetType() != PDFObjectType_Dictionary)
    1175           0 :         return nullptr;
    1176             : 
    1177        7485 :     if (m_poDict)
    1178        2792 :         return m_poDict;
    1179             : 
    1180        4693 :     Dict *poDict = (m_poConst->getType() == objStream)
    1181        4693 :                        ? m_poConst->getStream()->getDict()
    1182        3636 :                        : m_poConst->getDict();
    1183        4693 :     if (poDict == nullptr)
    1184           0 :         return nullptr;
    1185        4693 :     m_poDict = new GDALPDFDictionaryPoppler(poDict);
    1186        4693 :     return m_poDict;
    1187             : }
    1188             : 
    1189             : /************************************************************************/
    1190             : /*                              GetArray()                              */
    1191             : /************************************************************************/
    1192             : 
    1193        6522 : GDALPDFArray *GDALPDFObjectPoppler::GetArray()
    1194             : {
    1195        6522 :     if (GetType() != PDFObjectType_Array)
    1196           0 :         return nullptr;
    1197             : 
    1198        6522 :     if (m_poArray)
    1199        5306 :         return m_poArray;
    1200             : 
    1201        1216 :     Array *poArray = m_poConst->getArray();
    1202        1216 :     if (poArray == nullptr)
    1203           0 :         return nullptr;
    1204        1216 :     m_poArray = new GDALPDFArrayPoppler(poArray);
    1205        1216 :     return m_poArray;
    1206             : }
    1207             : 
    1208             : /************************************************************************/
    1209             : /*                             GetStream()                              */
    1210             : /************************************************************************/
    1211             : 
    1212         598 : GDALPDFStream *GDALPDFObjectPoppler::GetStream()
    1213             : {
    1214         598 :     if (m_poConst->getType() != objStream)
    1215          14 :         return nullptr;
    1216             : 
    1217         584 :     if (m_poStream)
    1218         133 :         return m_poStream;
    1219         451 :     m_poStream = new GDALPDFStreamPoppler(m_poConst->getStream());
    1220         451 :     return m_poStream;
    1221             : }
    1222             : 
    1223             : /************************************************************************/
    1224             : /*                           SetRefNumAndGen()                          */
    1225             : /************************************************************************/
    1226             : 
    1227       15012 : void GDALPDFObjectPoppler::SetRefNumAndGen(const GDALPDFObjectNum &nNum,
    1228             :                                            int nGen)
    1229             : {
    1230       15012 :     m_nRefNum = nNum;
    1231       15012 :     m_nRefGen = nGen;
    1232       15012 : }
    1233             : 
    1234             : /************************************************************************/
    1235             : /*                               GetRefNum()                            */
    1236             : /************************************************************************/
    1237             : 
    1238        2635 : GDALPDFObjectNum GDALPDFObjectPoppler::GetRefNum()
    1239             : {
    1240        2635 :     return m_nRefNum;
    1241             : }
    1242             : 
    1243             : /************************************************************************/
    1244             : /*                               GetRefGen()                            */
    1245             : /************************************************************************/
    1246             : 
    1247        1655 : int GDALPDFObjectPoppler::GetRefGen()
    1248             : {
    1249        1655 :     return m_nRefGen;
    1250             : }
    1251             : 
    1252             : /************************************************************************/
    1253             : /* ==================================================================== */
    1254             : /*                        GDALPDFDictionaryPoppler                      */
    1255             : /* ==================================================================== */
    1256             : /************************************************************************/
    1257             : 
    1258             : /************************************************************************/
    1259             : /*                       ~GDALPDFDictionaryPoppler()                    */
    1260             : /************************************************************************/
    1261             : 
    1262        9386 : GDALPDFDictionaryPoppler::~GDALPDFDictionaryPoppler()
    1263             : {
    1264        4693 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1265        4693 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1266       14065 :     for (; oIter != oEnd; ++oIter)
    1267        9372 :         delete oIter->second;
    1268        9386 : }
    1269             : 
    1270             : /************************************************************************/
    1271             : /*                                  Get()                               */
    1272             : /************************************************************************/
    1273             : 
    1274       14156 : GDALPDFObject *GDALPDFDictionaryPoppler::Get(const char *pszKey)
    1275             : {
    1276       14156 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1277       14156 :     if (oIter != m_map.end())
    1278        2424 :         return oIter->second;
    1279             : 
    1280       11732 :     auto &&o(m_poDict->lookupNF(pszKey));
    1281       11732 :     if (!o.isNull())
    1282             :     {
    1283        9372 :         GDALPDFObjectNum nRefNum;
    1284        9372 :         int nRefGen = 0;
    1285        9372 :         if (o.isRef())
    1286             :         {
    1287        2986 :             nRefNum = o.getRefNum();
    1288        2986 :             nRefGen = o.getRefGen();
    1289        2986 :             Object o2(m_poDict->lookup(pszKey));
    1290        2986 :             if (!o2.isNull())
    1291             :             {
    1292             :                 GDALPDFObjectPoppler *poObj =
    1293        2986 :                     new GDALPDFObjectPoppler(new Object(std::move(o2)), TRUE);
    1294        2986 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1295        2986 :                 m_map[pszKey] = poObj;
    1296        2986 :                 return poObj;
    1297             :             }
    1298             :         }
    1299             :         else
    1300             :         {
    1301             :             GDALPDFObjectPoppler *poObj =
    1302        6386 :                 new GDALPDFObjectPoppler(new Object(o.copy()), TRUE);
    1303        6386 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1304        6386 :             m_map[pszKey] = poObj;
    1305        6386 :             return poObj;
    1306             :         }
    1307             :     }
    1308        2360 :     return nullptr;
    1309             : }
    1310             : 
    1311             : /************************************************************************/
    1312             : /*                                GetValues()                           */
    1313             : /************************************************************************/
    1314             : 
    1315         473 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPoppler::GetValues()
    1316             : {
    1317         473 :     int i = 0;
    1318         473 :     int nLength = m_poDict->getLength();
    1319        2340 :     for (i = 0; i < nLength; i++)
    1320             :     {
    1321        1867 :         const char *pszKey = m_poDict->getKey(i);
    1322        1867 :         Get(pszKey);
    1323             :     }
    1324         473 :     return m_map;
    1325             : }
    1326             : 
    1327             : /************************************************************************/
    1328             : /* ==================================================================== */
    1329             : /*                          GDALPDFArrayPoppler                         */
    1330             : /* ==================================================================== */
    1331             : /************************************************************************/
    1332             : 
    1333             : /************************************************************************/
    1334             : /*                           GDALPDFCreateArray()                       */
    1335             : /************************************************************************/
    1336             : 
    1337          63 : GDALPDFArray *GDALPDFCreateArray(const Array *array)
    1338             : {
    1339          63 :     return new GDALPDFArrayPoppler(array);
    1340             : }
    1341             : 
    1342             : /************************************************************************/
    1343             : /*                               GetLength()                            */
    1344             : /************************************************************************/
    1345             : 
    1346        9397 : int GDALPDFArrayPoppler::GetLength()
    1347             : {
    1348        9397 :     return m_poArray->getLength();
    1349             : }
    1350             : 
    1351             : /************************************************************************/
    1352             : /*                                 Get()                                */
    1353             : /************************************************************************/
    1354             : 
    1355        6328 : GDALPDFObject *GDALPDFArrayPoppler::Get(int nIndex)
    1356             : {
    1357        6328 :     if (nIndex < 0 || nIndex >= GetLength())
    1358           0 :         return nullptr;
    1359             : 
    1360        6328 :     if (m_v.empty())
    1361        1244 :         m_v.resize(GetLength());
    1362             : 
    1363        6328 :     if (m_v[nIndex] != nullptr)
    1364         902 :         return m_v[nIndex].get();
    1365             : 
    1366        5426 :     auto &&o(m_poArray->getNF(nIndex));
    1367        5426 :     if (!o.isNull())
    1368             :     {
    1369        5426 :         GDALPDFObjectNum nRefNum;
    1370        5426 :         int nRefGen = 0;
    1371        5426 :         if (o.isRef())
    1372             :         {
    1373         867 :             nRefNum = o.getRefNum();
    1374         867 :             nRefGen = o.getRefGen();
    1375         867 :             Object o2(m_poArray->get(nIndex));
    1376         867 :             if (!o2.isNull())
    1377             :             {
    1378             :                 auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1379        1734 :                     new Object(std::move(o2)), TRUE);
    1380         867 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1381         867 :                 m_v[nIndex] = std::move(poObj);
    1382         867 :                 return m_v[nIndex].get();
    1383             :             }
    1384             :         }
    1385             :         else
    1386             :         {
    1387             :             auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1388        9118 :                 new Object(o.copy()), TRUE);
    1389        4559 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1390        4559 :             m_v[nIndex] = std::move(poObj);
    1391        4559 :             return m_v[nIndex].get();
    1392             :         }
    1393             :     }
    1394           0 :     return nullptr;
    1395             : }
    1396             : 
    1397             : /************************************************************************/
    1398             : /* ==================================================================== */
    1399             : /*                          GDALPDFStreamPoppler                        */
    1400             : /* ==================================================================== */
    1401             : /************************************************************************/
    1402             : 
    1403             : /************************************************************************/
    1404             : /*                               GetLength()                            */
    1405             : /************************************************************************/
    1406             : 
    1407         549 : int64_t GDALPDFStreamPoppler::GetLength(int64_t nMaxSize)
    1408             : {
    1409         549 :     if (m_nLength >= 0)
    1410         292 :         return m_nLength;
    1411             : 
    1412             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
    1413             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
    1414             :     if (!m_poStream->reset())
    1415             :         return 0;
    1416             : #else
    1417         257 :     m_poStream->reset();
    1418             : #endif
    1419         257 :     m_nLength = 0;
    1420             :     unsigned char readBuf[4096];
    1421             :     int readChars;
    1422         514 :     while ((readChars = m_poStream->doGetChars(4096, readBuf)) != 0)
    1423             :     {
    1424         257 :         m_nLength += readChars;
    1425         257 :         if (nMaxSize != 0 && m_nLength > nMaxSize)
    1426             :         {
    1427           0 :             m_nLength = -1;
    1428           0 :             return std::numeric_limits<int64_t>::max();
    1429             :         }
    1430             :     }
    1431         257 :     return m_nLength;
    1432             : }
    1433             : 
    1434             : /************************************************************************/
    1435             : /*                         GooStringToCharStart()                       */
    1436             : /************************************************************************/
    1437             : 
    1438         523 : static char *GooStringToCharStart(GooString &gstr)
    1439             : {
    1440         523 :     auto nLength = gstr.getLength();
    1441         523 :     if (nLength)
    1442             :     {
    1443         521 :         char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    1444         521 :         if (pszContent)
    1445             :         {
    1446         521 :             const char *srcStr = gstr.c_str();
    1447         521 :             memcpy(pszContent, srcStr, nLength);
    1448         521 :             pszContent[nLength] = '\0';
    1449             :         }
    1450         521 :         return pszContent;
    1451             :     }
    1452           2 :     return nullptr;
    1453             : }
    1454             : 
    1455             : /************************************************************************/
    1456             : /*                               GetBytes()                             */
    1457             : /************************************************************************/
    1458             : 
    1459         521 : char *GDALPDFStreamPoppler::GetBytes()
    1460             : {
    1461        1042 :     GooString gstr;
    1462             :     try
    1463             :     {
    1464         521 :         m_poStream->fillGooString(&gstr);
    1465             :     }
    1466           0 :     catch (const std::exception &e)
    1467             :     {
    1468           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1469           0 :                  "GDALPDFStreamPoppler::GetBytes(): %s", e.what());
    1470           0 :         return nullptr;
    1471             :     }
    1472         521 :     m_nLength = static_cast<int64_t>(gstr.toStr().size());
    1473         521 :     return GooStringToCharStart(gstr);
    1474             : }
    1475             : 
    1476             : /************************************************************************/
    1477             : /*                            GetRawLength()                            */
    1478             : /************************************************************************/
    1479             : 
    1480          63 : int64_t GDALPDFStreamPoppler::GetRawLength()
    1481             : {
    1482          63 :     if (m_nRawLength >= 0)
    1483           2 :         return m_nRawLength;
    1484             : 
    1485          61 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1486             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
    1487             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2)
    1488             :     if (!undecodeStream->reset())
    1489             :         return 0;
    1490             : #else
    1491          61 :     undecodeStream->reset();
    1492             : #endif
    1493          61 :     m_nRawLength = 0;
    1494       25531 :     while (undecodeStream->getChar() != EOF)
    1495       25470 :         m_nRawLength++;
    1496          61 :     return m_nRawLength;
    1497             : }
    1498             : 
    1499             : /************************************************************************/
    1500             : /*                             GetRawBytes()                            */
    1501             : /************************************************************************/
    1502             : 
    1503           2 : char *GDALPDFStreamPoppler::GetRawBytes()
    1504             : {
    1505           4 :     GooString gstr;
    1506           2 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1507             :     try
    1508             :     {
    1509           2 :         undecodeStream->fillGooString(&gstr);
    1510             :     }
    1511           0 :     catch (const std::exception &e)
    1512             :     {
    1513           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1514           0 :                  "GDALPDFStreamPoppler::GetRawBytes(): %s", e.what());
    1515           0 :         return nullptr;
    1516             :     }
    1517           2 :     m_nRawLength = gstr.getLength();
    1518           2 :     return GooStringToCharStart(gstr);
    1519             : }
    1520             : 
    1521             : #endif  // HAVE_POPPLER
    1522             : 
    1523             : #ifdef HAVE_PODOFO
    1524             : 
    1525             : /************************************************************************/
    1526             : /* ==================================================================== */
    1527             : /*                         GDALPDFDictionaryPodofo                      */
    1528             : /* ==================================================================== */
    1529             : /************************************************************************/
    1530             : 
    1531             : class GDALPDFDictionaryPodofo final : public GDALPDFDictionary
    1532             : {
    1533             :   private:
    1534             :     const PoDoFo::PdfDictionary *m_poDict;
    1535             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1536             :     std::map<CPLString, GDALPDFObject *> m_map{};
    1537             : 
    1538             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFDictionaryPodofo)
    1539             : 
    1540             :   public:
    1541             :     GDALPDFDictionaryPodofo(const PoDoFo::PdfDictionary *poDict,
    1542             :                             const PoDoFo::PdfVecObjects &poObjects)
    1543             :         : m_poDict(poDict), m_poObjects(poObjects)
    1544             :     {
    1545             :     }
    1546             : 
    1547             :     ~GDALPDFDictionaryPodofo() override;
    1548             : 
    1549             :     GDALPDFObject *Get(const char *pszKey) override;
    1550             :     std::map<CPLString, GDALPDFObject *> &GetValues() override;
    1551             : };
    1552             : 
    1553             : /************************************************************************/
    1554             : /* ==================================================================== */
    1555             : /*                           GDALPDFArrayPodofo                         */
    1556             : /* ==================================================================== */
    1557             : /************************************************************************/
    1558             : 
    1559             : class GDALPDFArrayPodofo final : public GDALPDFArray
    1560             : {
    1561             :   private:
    1562             :     const PoDoFo::PdfArray *m_poArray;
    1563             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1564             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    1565             : 
    1566             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPodofo)
    1567             : 
    1568             :   public:
    1569             :     GDALPDFArrayPodofo(const PoDoFo::PdfArray *poArray,
    1570             :                        const PoDoFo::PdfVecObjects &poObjects)
    1571             :         : m_poArray(poArray), m_poObjects(poObjects)
    1572             :     {
    1573             :     }
    1574             : 
    1575             :     int GetLength() override;
    1576             :     GDALPDFObject *Get(int nIndex) override;
    1577             : };
    1578             : 
    1579             : /************************************************************************/
    1580             : /* ==================================================================== */
    1581             : /*                          GDALPDFStreamPodofo                         */
    1582             : /* ==================================================================== */
    1583             : /************************************************************************/
    1584             : 
    1585             : class GDALPDFStreamPodofo final : public GDALPDFStream
    1586             : {
    1587             :   private:
    1588             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1589             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1590             :     const PoDoFo::PdfObjectStream *m_pStream;
    1591             : #else
    1592             :     const PoDoFo::PdfStream *m_pStream;
    1593             : #endif
    1594             : 
    1595             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFStreamPodofo)
    1596             : 
    1597             :   public:
    1598             :     GDALPDFStreamPodofo(
    1599             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1600             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1601             :         const PoDoFo::PdfObjectStream *
    1602             : #else
    1603             :         const PoDoFo::PdfStream *
    1604             : #endif
    1605             :             pStream)
    1606             :         : m_pStream(pStream)
    1607             :     {
    1608             :     }
    1609             : 
    1610             :     int64_t GetLength(int64_t nMaxSize = 0) override;
    1611             :     char *GetBytes() override;
    1612             : 
    1613             :     int64_t GetRawLength() override;
    1614             :     char *GetRawBytes() override;
    1615             : };
    1616             : 
    1617             : /************************************************************************/
    1618             : /* ==================================================================== */
    1619             : /*                          GDALPDFObjectPodofo                         */
    1620             : /* ==================================================================== */
    1621             : /************************************************************************/
    1622             : 
    1623             : /************************************************************************/
    1624             : /*                          GDALPDFObjectPodofo()                       */
    1625             : /************************************************************************/
    1626             : 
    1627             : GDALPDFObjectPodofo::GDALPDFObjectPodofo(const PoDoFo::PdfObject *po,
    1628             :                                          const PoDoFo::PdfVecObjects &poObjects)
    1629             :     : m_po(po), m_poObjects(poObjects)
    1630             : {
    1631             :     try
    1632             :     {
    1633             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1634             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1635             :         if (m_po->GetDataType() == PoDoFo::PdfDataType::Reference)
    1636             :         {
    1637             :             PoDoFo::PdfObject *poObj =
    1638             :                 m_poObjects.GetObject(m_po->GetReference());
    1639             :             if (poObj)
    1640             :                 m_po = poObj;
    1641             :         }
    1642             : #else
    1643             :         if (m_po->GetDataType() == PoDoFo::ePdfDataType_Reference)
    1644             :         {
    1645             :             PoDoFo::PdfObject *poObj =
    1646             :                 m_poObjects.GetObject(m_po->GetReference());
    1647             :             if (poObj)
    1648             :                 m_po = poObj;
    1649             :         }
    1650             : #endif
    1651             :     }
    1652             :     catch (PoDoFo::PdfError &oError)
    1653             :     {
    1654             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1655             :                  oError.what());
    1656             :     }
    1657             : }
    1658             : 
    1659             : /************************************************************************/
    1660             : /*                         ~GDALPDFObjectPodofo()                       */
    1661             : /************************************************************************/
    1662             : 
    1663             : GDALPDFObjectPodofo::~GDALPDFObjectPodofo()
    1664             : {
    1665             :     delete m_poDict;
    1666             :     delete m_poArray;
    1667             :     delete m_poStream;
    1668             : }
    1669             : 
    1670             : /************************************************************************/
    1671             : /*                               GetType()                              */
    1672             : /************************************************************************/
    1673             : 
    1674             : GDALPDFObjectType GDALPDFObjectPodofo::GetType()
    1675             : {
    1676             :     try
    1677             :     {
    1678             :         switch (m_po->GetDataType())
    1679             :         {
    1680             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1681             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1682             :             case PoDoFo::PdfDataType::Null:
    1683             :                 return PDFObjectType_Null;
    1684             :             case PoDoFo::PdfDataType::Bool:
    1685             :                 return PDFObjectType_Bool;
    1686             :             case PoDoFo::PdfDataType::Number:
    1687             :                 return PDFObjectType_Int;
    1688             :             case PoDoFo::PdfDataType::Real:
    1689             :                 return PDFObjectType_Real;
    1690             :             case PoDoFo::PdfDataType::String:
    1691             :                 return PDFObjectType_String;
    1692             :             case PoDoFo::PdfDataType::Name:
    1693             :                 return PDFObjectType_Name;
    1694             :             case PoDoFo::PdfDataType::Array:
    1695             :                 return PDFObjectType_Array;
    1696             :             case PoDoFo::PdfDataType::Dictionary:
    1697             :                 return PDFObjectType_Dictionary;
    1698             :             default:
    1699             :                 return PDFObjectType_Unknown;
    1700             : #else
    1701             :             case PoDoFo::ePdfDataType_Null:
    1702             :                 return PDFObjectType_Null;
    1703             :             case PoDoFo::ePdfDataType_Bool:
    1704             :                 return PDFObjectType_Bool;
    1705             :             case PoDoFo::ePdfDataType_Number:
    1706             :                 return PDFObjectType_Int;
    1707             :             case PoDoFo::ePdfDataType_Real:
    1708             :                 return PDFObjectType_Real;
    1709             :             case PoDoFo::ePdfDataType_HexString:
    1710             :                 return PDFObjectType_String;
    1711             :             case PoDoFo::ePdfDataType_String:
    1712             :                 return PDFObjectType_String;
    1713             :             case PoDoFo::ePdfDataType_Name:
    1714             :                 return PDFObjectType_Name;
    1715             :             case PoDoFo::ePdfDataType_Array:
    1716             :                 return PDFObjectType_Array;
    1717             :             case PoDoFo::ePdfDataType_Dictionary:
    1718             :                 return PDFObjectType_Dictionary;
    1719             :             default:
    1720             :                 return PDFObjectType_Unknown;
    1721             : #endif
    1722             :         }
    1723             :     }
    1724             :     catch (PoDoFo::PdfError &oError)
    1725             :     {
    1726             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1727             :                  oError.what());
    1728             :         return PDFObjectType_Unknown;
    1729             :     }
    1730             : }
    1731             : 
    1732             : /************************************************************************/
    1733             : /*                          GetTypeNameNative()                         */
    1734             : /************************************************************************/
    1735             : 
    1736             : const char *GDALPDFObjectPodofo::GetTypeNameNative()
    1737             : {
    1738             :     try
    1739             :     {
    1740             :         return m_po->GetDataTypeString();
    1741             :     }
    1742             :     catch (PoDoFo::PdfError &oError)
    1743             :     {
    1744             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1745             :                  oError.what());
    1746             :         return "unknown";
    1747             :     }
    1748             : }
    1749             : 
    1750             : /************************************************************************/
    1751             : /*                              GetBool()                               */
    1752             : /************************************************************************/
    1753             : 
    1754             : int GDALPDFObjectPodofo::GetBool()
    1755             : {
    1756             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1757             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1758             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Bool)
    1759             : #else
    1760             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Bool)
    1761             : #endif
    1762             :         return m_po->GetBool();
    1763             :     else
    1764             :         return 0;
    1765             : }
    1766             : 
    1767             : /************************************************************************/
    1768             : /*                              GetInt()                                */
    1769             : /************************************************************************/
    1770             : 
    1771             : int GDALPDFObjectPodofo::GetInt()
    1772             : {
    1773             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1774             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1775             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Number)
    1776             : #else
    1777             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Number)
    1778             : #endif
    1779             :         return static_cast<int>(m_po->GetNumber());
    1780             :     else
    1781             :         return 0;
    1782             : }
    1783             : 
    1784             : /************************************************************************/
    1785             : /*                              GetReal()                               */
    1786             : /************************************************************************/
    1787             : 
    1788             : double GDALPDFObjectPodofo::GetReal()
    1789             : {
    1790             :     if (GetType() == PDFObjectType_Real)
    1791             :         return m_po->GetReal();
    1792             :     else
    1793             :         return 0.0;
    1794             : }
    1795             : 
    1796             : /************************************************************************/
    1797             : /*                              GetString()                             */
    1798             : /************************************************************************/
    1799             : 
    1800             : const std::string &GDALPDFObjectPodofo::GetString()
    1801             : {
    1802             :     if (GetType() == PDFObjectType_String)
    1803             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1804             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1805             :         return (osStr = m_po->GetString().GetString());
    1806             : #else
    1807             :         return (osStr = m_po->GetString().GetStringUtf8());
    1808             : #endif
    1809             :     else
    1810             :         return (osStr = "");
    1811             : }
    1812             : 
    1813             : /************************************************************************/
    1814             : /*                              GetName()                               */
    1815             : /************************************************************************/
    1816             : 
    1817             : const std::string &GDALPDFObjectPodofo::GetName()
    1818             : {
    1819             :     if (GetType() == PDFObjectType_Name)
    1820             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1821             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1822             :         return (osStr = m_po->GetName().GetString());
    1823             : #else
    1824             :         return (osStr = m_po->GetName().GetName());
    1825             : #endif
    1826             :     else
    1827             :         return (osStr = "");
    1828             : }
    1829             : 
    1830             : /************************************************************************/
    1831             : /*                             GetDictionary()                          */
    1832             : /************************************************************************/
    1833             : 
    1834             : GDALPDFDictionary *GDALPDFObjectPodofo::GetDictionary()
    1835             : {
    1836             :     if (GetType() != PDFObjectType_Dictionary)
    1837             :         return nullptr;
    1838             : 
    1839             :     if (m_poDict)
    1840             :         return m_poDict;
    1841             : 
    1842             :     m_poDict = new GDALPDFDictionaryPodofo(&m_po->GetDictionary(), m_poObjects);
    1843             :     return m_poDict;
    1844             : }
    1845             : 
    1846             : /************************************************************************/
    1847             : /*                                GetArray()                            */
    1848             : /************************************************************************/
    1849             : 
    1850             : GDALPDFArray *GDALPDFObjectPodofo::GetArray()
    1851             : {
    1852             :     if (GetType() != PDFObjectType_Array)
    1853             :         return nullptr;
    1854             : 
    1855             :     if (m_poArray)
    1856             :         return m_poArray;
    1857             : 
    1858             :     m_poArray = new GDALPDFArrayPodofo(&m_po->GetArray(), m_poObjects);
    1859             :     return m_poArray;
    1860             : }
    1861             : 
    1862             : /************************************************************************/
    1863             : /*                               GetStream()                            */
    1864             : /************************************************************************/
    1865             : 
    1866             : GDALPDFStream *GDALPDFObjectPodofo::GetStream()
    1867             : {
    1868             :     try
    1869             :     {
    1870             :         if (!m_po->HasStream())
    1871             :             return nullptr;
    1872             :     }
    1873             :     catch (PoDoFo::PdfError &oError)
    1874             :     {
    1875             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object : %s",
    1876             :                  oError.what());
    1877             :         return nullptr;
    1878             :     }
    1879             :     catch (...)
    1880             :     {
    1881             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object");
    1882             :         return nullptr;
    1883             :     }
    1884             : 
    1885             :     if (m_poStream == nullptr)
    1886             :         m_poStream = new GDALPDFStreamPodofo(m_po->GetStream());
    1887             :     return m_poStream;
    1888             : }
    1889             : 
    1890             : /************************************************************************/
    1891             : /*                               GetRefNum()                            */
    1892             : /************************************************************************/
    1893             : 
    1894             : GDALPDFObjectNum GDALPDFObjectPodofo::GetRefNum()
    1895             : {
    1896             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1897             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1898             :     return GDALPDFObjectNum(m_po->GetIndirectReference().ObjectNumber());
    1899             : #else
    1900             :     return GDALPDFObjectNum(m_po->Reference().ObjectNumber());
    1901             : #endif
    1902             : }
    1903             : 
    1904             : /************************************************************************/
    1905             : /*                               GetRefGen()                            */
    1906             : /************************************************************************/
    1907             : 
    1908             : int GDALPDFObjectPodofo::GetRefGen()
    1909             : {
    1910             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1911             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1912             :     return m_po->GetIndirectReference().GenerationNumber();
    1913             : #else
    1914             :     return m_po->Reference().GenerationNumber();
    1915             : #endif
    1916             : }
    1917             : 
    1918             : /************************************************************************/
    1919             : /* ==================================================================== */
    1920             : /*                         GDALPDFDictionaryPodofo                      */
    1921             : /* ==================================================================== */
    1922             : /************************************************************************/
    1923             : 
    1924             : /************************************************************************/
    1925             : /*                         ~GDALPDFDictionaryPodofo()                   */
    1926             : /************************************************************************/
    1927             : 
    1928             : GDALPDFDictionaryPodofo::~GDALPDFDictionaryPodofo()
    1929             : {
    1930             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1931             :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1932             :     for (; oIter != oEnd; ++oIter)
    1933             :         delete oIter->second;
    1934             : }
    1935             : 
    1936             : /************************************************************************/
    1937             : /*                                  Get()                               */
    1938             : /************************************************************************/
    1939             : 
    1940             : GDALPDFObject *GDALPDFDictionaryPodofo::Get(const char *pszKey)
    1941             : {
    1942             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1943             :     if (oIter != m_map.end())
    1944             :         return oIter->second;
    1945             : 
    1946             :     const PoDoFo::PdfObject *poVal = m_poDict->GetKey(PoDoFo::PdfName(pszKey));
    1947             :     if (poVal)
    1948             :     {
    1949             :         GDALPDFObjectPodofo *poObj =
    1950             :             new GDALPDFObjectPodofo(poVal, m_poObjects);
    1951             :         m_map[pszKey] = poObj;
    1952             :         return poObj;
    1953             :     }
    1954             :     else
    1955             :     {
    1956             :         return nullptr;
    1957             :     }
    1958             : }
    1959             : 
    1960             : /************************************************************************/
    1961             : /*                              GetValues()                             */
    1962             : /************************************************************************/
    1963             : 
    1964             : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPodofo::GetValues()
    1965             : {
    1966             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1967             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1968             :     for (const auto &oIter : *m_poDict)
    1969             :     {
    1970             :         Get(oIter.first.GetString().c_str());
    1971             :     }
    1972             : #else
    1973             :     for (const auto &oIter : m_poDict->GetKeys())
    1974             :     {
    1975             :         Get(oIter.first.GetName().c_str());
    1976             :     }
    1977             : #endif
    1978             :     return m_map;
    1979             : }
    1980             : 
    1981             : /************************************************************************/
    1982             : /* ==================================================================== */
    1983             : /*                           GDALPDFArrayPodofo                         */
    1984             : /* ==================================================================== */
    1985             : /************************************************************************/
    1986             : 
    1987             : /************************************************************************/
    1988             : /*                              GetLength()                             */
    1989             : /************************************************************************/
    1990             : 
    1991             : int GDALPDFArrayPodofo::GetLength()
    1992             : {
    1993             :     return static_cast<int>(m_poArray->GetSize());
    1994             : }
    1995             : 
    1996             : /************************************************************************/
    1997             : /*                                Get()                                 */
    1998             : /************************************************************************/
    1999             : 
    2000             : GDALPDFObject *GDALPDFArrayPodofo::Get(int nIndex)
    2001             : {
    2002             :     if (nIndex < 0 || nIndex >= GetLength())
    2003             :         return nullptr;
    2004             : 
    2005             :     if (m_v.empty())
    2006             :         m_v.resize(GetLength());
    2007             : 
    2008             :     if (m_v[nIndex] != nullptr)
    2009             :         return m_v[nIndex].get();
    2010             : 
    2011             :     const PoDoFo::PdfObject &oVal = (*m_poArray)[nIndex];
    2012             :     m_v[nIndex] = std::make_unique<GDALPDFObjectPodofo>(&oVal, m_poObjects);
    2013             :     return m_v[nIndex].get();
    2014             : }
    2015             : 
    2016             : /************************************************************************/
    2017             : /* ==================================================================== */
    2018             : /*                           GDALPDFStreamPodofo                        */
    2019             : /* ==================================================================== */
    2020             : /************************************************************************/
    2021             : 
    2022             : /************************************************************************/
    2023             : /*                              GetLength()                             */
    2024             : /************************************************************************/
    2025             : 
    2026             : int64_t GDALPDFStreamPodofo::GetLength(int64_t /* nMaxSize */)
    2027             : {
    2028             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2029             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2030             :     PoDoFo::charbuff str;
    2031             :     try
    2032             :     {
    2033             :         m_pStream->CopyToSafe(str);
    2034             :     }
    2035             :     catch (PoDoFo::PdfError &e)
    2036             :     {
    2037             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2038             :                  e.what());
    2039             :         return 0;
    2040             :     }
    2041             :     return static_cast<int64_t>(str.size());
    2042             : #else
    2043             :     char *pBuffer = nullptr;
    2044             :     PoDoFo::pdf_long nLen = 0;
    2045             :     try
    2046             :     {
    2047             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2048             :         PoDoFo::podofo_free(pBuffer);
    2049             :         return static_cast<int64_t>(nLen);
    2050             :     }
    2051             :     catch (PoDoFo::PdfError &e)
    2052             :     {
    2053             :     }
    2054             :     return 0;
    2055             : #endif
    2056             : }
    2057             : 
    2058             : /************************************************************************/
    2059             : /*                               GetBytes()                             */
    2060             : /************************************************************************/
    2061             : 
    2062             : char *GDALPDFStreamPodofo::GetBytes()
    2063             : {
    2064             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2065             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2066             :     PoDoFo::charbuff str;
    2067             :     try
    2068             :     {
    2069             :         m_pStream->CopyToSafe(str);
    2070             :     }
    2071             :     catch (PoDoFo::PdfError &e)
    2072             :     {
    2073             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2074             :                  e.what());
    2075             :         return nullptr;
    2076             :     }
    2077             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2078             :     if (!pszContent)
    2079             :     {
    2080             :         return nullptr;
    2081             :     }
    2082             :     memcpy(pszContent, str.data(), str.size());
    2083             :     pszContent[str.size()] = '\0';
    2084             :     return pszContent;
    2085             : #else
    2086             :     char *pBuffer = nullptr;
    2087             :     PoDoFo::pdf_long nLen = 0;
    2088             :     try
    2089             :     {
    2090             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2091             :     }
    2092             :     catch (PoDoFo::PdfError &e)
    2093             :     {
    2094             :         return nullptr;
    2095             :     }
    2096             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2097             :     if (!pszContent)
    2098             :     {
    2099             :         PoDoFo::podofo_free(pBuffer);
    2100             :         return nullptr;
    2101             :     }
    2102             :     memcpy(pszContent, pBuffer, nLen);
    2103             :     PoDoFo::podofo_free(pBuffer);
    2104             :     pszContent[nLen] = '\0';
    2105             :     return pszContent;
    2106             : #endif
    2107             : }
    2108             : 
    2109             : /************************************************************************/
    2110             : /*                             GetRawLength()                           */
    2111             : /************************************************************************/
    2112             : 
    2113             : int64_t GDALPDFStreamPodofo::GetRawLength()
    2114             : {
    2115             :     try
    2116             :     {
    2117             :         auto nLen = m_pStream->GetLength();
    2118             :         return static_cast<int64_t>(nLen);
    2119             :     }
    2120             :     catch (PoDoFo::PdfError &e)
    2121             :     {
    2122             :     }
    2123             :     return 0;
    2124             : }
    2125             : 
    2126             : /************************************************************************/
    2127             : /*                              GetRawBytes()                           */
    2128             : /************************************************************************/
    2129             : 
    2130             : char *GDALPDFStreamPodofo::GetRawBytes()
    2131             : {
    2132             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2133             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2134             :     PoDoFo::charbuff str;
    2135             :     try
    2136             :     {
    2137             :         PoDoFo::StringStreamDevice stream(str);
    2138             : #ifdef USE_HACK_BECAUSE_PdfInputStream_constructor_is_not_exported_in_podofo_0_11
    2139             :         auto *poNonConstStream =
    2140             :             const_cast<PoDoFo::PdfObjectStream *>(m_pStream);
    2141             :         auto inputStream = poNonConstStream->GetProvider().GetInputStream(
    2142             :             poNonConstStream->GetParent());
    2143             :         inputStream->CopyTo(stream);
    2144             : #else
    2145             :         // Should work but fails to link because PdfInputStream destructor
    2146             :         // is not exported
    2147             :         auto inputStream = m_pStream->GetInputStream(/*raw=*/true);
    2148             :         inputStream.CopyTo(stream);
    2149             : #endif
    2150             :         stream.Flush();
    2151             :     }
    2152             :     catch (PoDoFo::PdfError &e)
    2153             :     {
    2154             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2155             :                  e.what());
    2156             :         return nullptr;
    2157             :     }
    2158             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2159             :     if (!pszContent)
    2160             :     {
    2161             :         return nullptr;
    2162             :     }
    2163             :     memcpy(pszContent, str.data(), str.size());
    2164             :     pszContent[str.size()] = '\0';
    2165             :     return pszContent;
    2166             : #else
    2167             :     char *pBuffer = nullptr;
    2168             :     PoDoFo::pdf_long nLen = 0;
    2169             :     try
    2170             :     {
    2171             :         m_pStream->GetCopy(&pBuffer, &nLen);
    2172             :     }
    2173             :     catch (PoDoFo::PdfError &e)
    2174             :     {
    2175             :         return nullptr;
    2176             :     }
    2177             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2178             :     if (!pszContent)
    2179             :     {
    2180             :         PoDoFo::podofo_free(pBuffer);
    2181             :         return nullptr;
    2182             :     }
    2183             :     memcpy(pszContent, pBuffer, nLen);
    2184             :     PoDoFo::podofo_free(pBuffer);
    2185             :     pszContent[nLen] = '\0';
    2186             :     return pszContent;
    2187             : #endif
    2188             : }
    2189             : 
    2190             : #endif  // HAVE_PODOFO
    2191             : 
    2192             : #ifdef HAVE_PDFIUM
    2193             : 
    2194             : /************************************************************************/
    2195             : /* ==================================================================== */
    2196             : /*                         GDALPDFDictionaryPdfium                      */
    2197             : /* ==================================================================== */
    2198             : /************************************************************************/
    2199             : 
    2200             : class GDALPDFDictionaryPdfium final : public GDALPDFDictionary
    2201             : {
    2202             :   private:
    2203             :     RetainPtr<const CPDF_Dictionary> m_poDict;
    2204             :     std::map<CPLString, GDALPDFObject *> m_map{};
    2205             : 
    2206             :   public:
    2207             :     GDALPDFDictionaryPdfium(RetainPtr<const CPDF_Dictionary> poDict)
    2208             :         : m_poDict(std::move(poDict))
    2209             :     {
    2210             :     }
    2211             : 
    2212             :     ~GDALPDFDictionaryPdfium() override;
    2213             : 
    2214             :     GDALPDFObject *Get(const char *pszKey) override;
    2215             :     std::map<CPLString, GDALPDFObject *> &GetValues() override;
    2216             : };
    2217             : 
    2218             : /************************************************************************/
    2219             : /* ==================================================================== */
    2220             : /*                           GDALPDFArrayPdfium                         */
    2221             : /* ==================================================================== */
    2222             : /************************************************************************/
    2223             : 
    2224             : class GDALPDFArrayPdfium final : public GDALPDFArray
    2225             : {
    2226             :   private:
    2227             :     const CPDF_Array *m_poArray;
    2228             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    2229             : 
    2230             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPdfium)
    2231             : 
    2232             :   public:
    2233             :     GDALPDFArrayPdfium(const CPDF_Array *poArray) : m_poArray(poArray)
    2234             :     {
    2235             :     }
    2236             : 
    2237             :     int GetLength() override;
    2238             :     GDALPDFObject *Get(int nIndex) override;
    2239             : };
    2240             : 
    2241             : /************************************************************************/
    2242             : /* ==================================================================== */
    2243             : /*                          GDALPDFStreamPdfium                         */
    2244             : /* ==================================================================== */
    2245             : /************************************************************************/
    2246             : 
    2247             : class GDALPDFStreamPdfium final : public GDALPDFStream
    2248             : {
    2249             :   private:
    2250             :     RetainPtr<const CPDF_Stream> m_pStream;
    2251             :     int64_t m_nSize = 0;
    2252             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pData = nullptr;
    2253             :     int64_t m_nRawSize = 0;
    2254             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pRawData = nullptr;
    2255             : 
    2256             :     void Decompress();
    2257             :     void FillRaw();
    2258             : 
    2259             :   public:
    2260             :     GDALPDFStreamPdfium(RetainPtr<const CPDF_Stream> pStream)
    2261             :         : m_pStream(std::move(pStream))
    2262             :     {
    2263             :     }
    2264             : 
    2265             :     int64_t GetLength(int64_t nMaxSize = 0) override;
    2266             :     char *GetBytes() override;
    2267             : 
    2268             :     int64_t GetRawLength() override;
    2269             :     char *GetRawBytes() override;
    2270             : };
    2271             : 
    2272             : /************************************************************************/
    2273             : /* ==================================================================== */
    2274             : /*                          GDALPDFObjectPdfium                         */
    2275             : /* ==================================================================== */
    2276             : /************************************************************************/
    2277             : 
    2278             : /************************************************************************/
    2279             : /*                          GDALPDFObjectPdfium()                       */
    2280             : /************************************************************************/
    2281             : 
    2282             : GDALPDFObjectPdfium::GDALPDFObjectPdfium(RetainPtr<const CPDF_Object> obj)
    2283             :     : m_obj(std::move(obj))
    2284             : {
    2285             :     CPLAssert(m_obj != nullptr);
    2286             : }
    2287             : 
    2288             : /************************************************************************/
    2289             : /*                         ~GDALPDFObjectPdfium()                       */
    2290             : /************************************************************************/
    2291             : 
    2292             : GDALPDFObjectPdfium::~GDALPDFObjectPdfium()
    2293             : {
    2294             :     delete m_poDict;
    2295             :     delete m_poArray;
    2296             :     delete m_poStream;
    2297             : }
    2298             : 
    2299             : /************************************************************************/
    2300             : /*                               Build()                                */
    2301             : /************************************************************************/
    2302             : 
    2303             : GDALPDFObjectPdfium *
    2304             : GDALPDFObjectPdfium::Build(RetainPtr<const CPDF_Object> obj)
    2305             : {
    2306             :     if (obj == nullptr)
    2307             :         return nullptr;
    2308             :     if (obj->GetType() == CPDF_Object::Type::kReference)
    2309             :     {
    2310             :         obj = obj->GetDirect();
    2311             :         if (obj == nullptr)
    2312             :         {
    2313             :             CPLError(CE_Failure, CPLE_AppDefined,
    2314             :                      "Cannot resolve indirect object");
    2315             :             return nullptr;
    2316             :         }
    2317             :     }
    2318             :     return new GDALPDFObjectPdfium(std::move(obj));
    2319             : }
    2320             : 
    2321             : /************************************************************************/
    2322             : /*                               GetType()                              */
    2323             : /************************************************************************/
    2324             : 
    2325             : GDALPDFObjectType GDALPDFObjectPdfium::GetType()
    2326             : {
    2327             :     switch (m_obj->GetType())
    2328             :     {
    2329             :         case CPDF_Object::Type::kNullobj:
    2330             :             return PDFObjectType_Null;
    2331             :         case CPDF_Object::Type::kBoolean:
    2332             :             return PDFObjectType_Bool;
    2333             :         case CPDF_Object::Type::kNumber:
    2334             :             return (cpl::down_cast<const CPDF_Number *>(m_obj.Get()))
    2335             :                            ->IsInteger()
    2336             :                        ? PDFObjectType_Int
    2337             :                        : PDFObjectType_Real;
    2338             :         case CPDF_Object::Type::kString:
    2339             :             return PDFObjectType_String;
    2340             :         case CPDF_Object::Type::kName:
    2341             :             return PDFObjectType_Name;
    2342             :         case CPDF_Object::Type::kArray:
    2343             :             return PDFObjectType_Array;
    2344             :         case CPDF_Object::Type::kDictionary:
    2345             :             return PDFObjectType_Dictionary;
    2346             :         case CPDF_Object::Type::kStream:
    2347             :             return PDFObjectType_Dictionary;
    2348             :         case CPDF_Object::Type::kReference:
    2349             :             // unresolved reference
    2350             :             return PDFObjectType_Unknown;
    2351             :         default:
    2352             :             CPLAssert(false);
    2353             :             return PDFObjectType_Unknown;
    2354             :     }
    2355             : }
    2356             : 
    2357             : /************************************************************************/
    2358             : /*                          GetTypeNameNative()                         */
    2359             : /************************************************************************/
    2360             : 
    2361             : const char *GDALPDFObjectPdfium::GetTypeNameNative()
    2362             : {
    2363             :     if (m_obj->GetType() == CPDF_Object::Type::kStream)
    2364             :         return "stream";
    2365             :     else
    2366             :         return "";
    2367             : }
    2368             : 
    2369             : /************************************************************************/
    2370             : /*                              GetBool()                               */
    2371             : /************************************************************************/
    2372             : 
    2373             : int GDALPDFObjectPdfium::GetBool()
    2374             : {
    2375             :     return m_obj->GetInteger();
    2376             : }
    2377             : 
    2378             : /************************************************************************/
    2379             : /*                              GetInt()                                */
    2380             : /************************************************************************/
    2381             : 
    2382             : int GDALPDFObjectPdfium::GetInt()
    2383             : {
    2384             :     return m_obj->GetInteger();
    2385             : }
    2386             : 
    2387             : /************************************************************************/
    2388             : /*                       CPLRoundToMoreLikelyDouble()                   */
    2389             : /************************************************************************/
    2390             : 
    2391             : // We try to compensate for rounding errors when converting the number
    2392             : // in the PDF expressed as a string (e.g 297.84) to float32 by pdfium :
    2393             : // 297.8399963378906 Which is technically correct per the PDF spec, but in
    2394             : // practice poppler or podofo use double and Geospatial PDF are often encoded
    2395             : // with double precision.
    2396             : 
    2397             : static double CPLRoundToMoreLikelyDouble(float f)
    2398             : {
    2399             :     if (std::round(f) == f)
    2400             :         return f;
    2401             : 
    2402             :     char szBuffer[80];
    2403             :     CPLsnprintf(szBuffer, 80, "%f\n", f);
    2404             :     double d = f;
    2405             :     char *pszDot = strchr(szBuffer, '.');
    2406             :     if (pszDot == nullptr)
    2407             :         return d;
    2408             :     pszDot++;
    2409             :     if (pszDot[0] == 0 || pszDot[1] == 0)
    2410             :         return d;
    2411             :     if (STARTS_WITH(pszDot + 2, "99"))
    2412             :     {
    2413             :         pszDot[2] = 0;
    2414             :         double d2 = CPLAtof(szBuffer) + 0.01;
    2415             :         float f2 = static_cast<float>(d2);
    2416             :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2417             :             nextafterf(f, f - 1.0f) == f2)
    2418             :             d = d2;
    2419             :     }
    2420             :     else if (STARTS_WITH(pszDot + 2, "00"))
    2421             :     {
    2422             :         pszDot[2] = 0;
    2423             :         double d2 = CPLAtof(szBuffer);
    2424             :         float f2 = static_cast<float>(d2);
    2425             :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2426             :             nextafterf(f, f - 1.0f) == f2)
    2427             :             d = d2;
    2428             :     }
    2429             :     return d;
    2430             : }
    2431             : 
    2432             : /************************************************************************/
    2433             : /*                              GetReal()                               */
    2434             : /************************************************************************/
    2435             : 
    2436             : double GDALPDFObjectPdfium::GetReal()
    2437             : {
    2438             :     return CPLRoundToMoreLikelyDouble(m_obj->GetNumber());
    2439             : }
    2440             : 
    2441             : /************************************************************************/
    2442             : /*                              GetString()                             */
    2443             : /************************************************************************/
    2444             : 
    2445             : const std::string &GDALPDFObjectPdfium::GetString()
    2446             : {
    2447             :     if (GetType() == PDFObjectType_String)
    2448             :     {
    2449             :         const auto bs = m_obj->GetString();
    2450             :         // If empty string, code crashes
    2451             :         if (bs.IsEmpty())
    2452             :             return (osStr = "");
    2453             :         return (osStr = GDALPDFGetUTF8StringFromBytes(
    2454             :                     reinterpret_cast<const GByte *>(bs.c_str()),
    2455             :                     static_cast<int>(bs.GetLength())));
    2456             :     }
    2457             :     else
    2458             :         return (osStr = "");
    2459             : }
    2460             : 
    2461             : /************************************************************************/
    2462             : /*                              GetName()                               */
    2463             : /************************************************************************/
    2464             : 
    2465             : const std::string &GDALPDFObjectPdfium::GetName()
    2466             : {
    2467             :     if (GetType() == PDFObjectType_Name)
    2468             :         return (osStr = m_obj->GetString().c_str());
    2469             :     else
    2470             :         return (osStr = "");
    2471             : }
    2472             : 
    2473             : /************************************************************************/
    2474             : /*                             GetDictionary()                          */
    2475             : /************************************************************************/
    2476             : 
    2477             : GDALPDFDictionary *GDALPDFObjectPdfium::GetDictionary()
    2478             : {
    2479             :     if (GetType() != PDFObjectType_Dictionary)
    2480             :         return nullptr;
    2481             : 
    2482             :     if (m_poDict)
    2483             :         return m_poDict;
    2484             : 
    2485             :     m_poDict = new GDALPDFDictionaryPdfium(m_obj->GetDict());
    2486             :     return m_poDict;
    2487             : }
    2488             : 
    2489             : /************************************************************************/
    2490             : /*                                GetArray()                            */
    2491             : /************************************************************************/
    2492             : 
    2493             : GDALPDFArray *GDALPDFObjectPdfium::GetArray()
    2494             : {
    2495             :     if (GetType() != PDFObjectType_Array)
    2496             :         return nullptr;
    2497             : 
    2498             :     if (m_poArray)
    2499             :         return m_poArray;
    2500             : 
    2501             :     m_poArray =
    2502             :         new GDALPDFArrayPdfium(cpl::down_cast<const CPDF_Array *>(m_obj.Get()));
    2503             :     return m_poArray;
    2504             : }
    2505             : 
    2506             : /************************************************************************/
    2507             : /*                               GetStream()                            */
    2508             : /************************************************************************/
    2509             : 
    2510             : GDALPDFStream *GDALPDFObjectPdfium::GetStream()
    2511             : {
    2512             :     if (m_obj->GetType() != CPDF_Object::Type::kStream)
    2513             :         return nullptr;
    2514             : 
    2515             :     if (m_poStream)
    2516             :         return m_poStream;
    2517             :     auto pStream = pdfium::WrapRetain(m_obj->AsStream());
    2518             :     if (pStream)
    2519             :     {
    2520             :         m_poStream = new GDALPDFStreamPdfium(std::move(pStream));
    2521             :         return m_poStream;
    2522             :     }
    2523             :     else
    2524             :         return nullptr;
    2525             : }
    2526             : 
    2527             : /************************************************************************/
    2528             : /*                               GetRefNum()                            */
    2529             : /************************************************************************/
    2530             : 
    2531             : GDALPDFObjectNum GDALPDFObjectPdfium::GetRefNum()
    2532             : {
    2533             :     return GDALPDFObjectNum(m_obj->GetObjNum());
    2534             : }
    2535             : 
    2536             : /************************************************************************/
    2537             : /*                               GetRefGen()                            */
    2538             : /************************************************************************/
    2539             : 
    2540             : int GDALPDFObjectPdfium::GetRefGen()
    2541             : {
    2542             :     return m_obj->GetGenNum();
    2543             : }
    2544             : 
    2545             : /************************************************************************/
    2546             : /* ==================================================================== */
    2547             : /*                         GDALPDFDictionaryPdfium                      */
    2548             : /* ==================================================================== */
    2549             : /************************************************************************/
    2550             : 
    2551             : /************************************************************************/
    2552             : /*                         ~GDALPDFDictionaryPdfium()                   */
    2553             : /************************************************************************/
    2554             : 
    2555             : GDALPDFDictionaryPdfium::~GDALPDFDictionaryPdfium()
    2556             : {
    2557             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    2558             :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    2559             :     for (; oIter != oEnd; ++oIter)
    2560             :         delete oIter->second;
    2561             : }
    2562             : 
    2563             : /************************************************************************/
    2564             : /*                                  Get()                               */
    2565             : /************************************************************************/
    2566             : 
    2567             : GDALPDFObject *GDALPDFDictionaryPdfium::Get(const char *pszKey)
    2568             : {
    2569             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    2570             :     if (oIter != m_map.end())
    2571             :         return oIter->second;
    2572             : 
    2573             :     ByteStringView pdfiumKey(pszKey);
    2574             :     GDALPDFObjectPdfium *poObj =
    2575             :         GDALPDFObjectPdfium::Build(m_poDict->GetObjectFor(pdfiumKey));
    2576             :     if (poObj)
    2577             :     {
    2578             :         m_map[pszKey] = poObj;
    2579             :         return poObj;
    2580             :     }
    2581             :     else
    2582             :     {
    2583             :         return nullptr;
    2584             :     }
    2585             : }
    2586             : 
    2587             : /************************************************************************/
    2588             : /*                              GetValues()                             */
    2589             : /************************************************************************/
    2590             : 
    2591             : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPdfium::GetValues()
    2592             : {
    2593             :     CPDF_DictionaryLocker dictIterator(m_poDict);
    2594             :     for (const auto &iter : dictIterator)
    2595             :     {
    2596             :         // No object for this key
    2597             :         if (!iter.second)
    2598             :             continue;
    2599             : 
    2600             :         const char *pszKey = iter.first.c_str();
    2601             :         // Objects exists in the map
    2602             :         if (m_map.find(pszKey) != m_map.end())
    2603             :             continue;
    2604             :         GDALPDFObjectPdfium *poObj = GDALPDFObjectPdfium::Build(iter.second);
    2605             :         if (poObj == nullptr)
    2606             :             continue;
    2607             :         m_map[pszKey] = poObj;
    2608             :     }
    2609             : 
    2610             :     return m_map;
    2611             : }
    2612             : 
    2613             : /************************************************************************/
    2614             : /* ==================================================================== */
    2615             : /*                           GDALPDFArrayPdfium                         */
    2616             : /* ==================================================================== */
    2617             : /************************************************************************/
    2618             : 
    2619             : /************************************************************************/
    2620             : /*                              GetLength()                             */
    2621             : /************************************************************************/
    2622             : 
    2623             : int GDALPDFArrayPdfium::GetLength()
    2624             : {
    2625             :     return static_cast<int>(m_poArray->size());
    2626             : }
    2627             : 
    2628             : /************************************************************************/
    2629             : /*                                Get()                                 */
    2630             : /************************************************************************/
    2631             : 
    2632             : GDALPDFObject *GDALPDFArrayPdfium::Get(int nIndex)
    2633             : {
    2634             :     if (nIndex < 0 || nIndex >= GetLength())
    2635             :         return nullptr;
    2636             : 
    2637             :     if (m_v.empty())
    2638             :         m_v.resize(GetLength());
    2639             : 
    2640             :     if (m_v[nIndex] != nullptr)
    2641             :         return m_v[nIndex].get();
    2642             : 
    2643             :     auto poObj = std::unique_ptr<GDALPDFObjectPdfium>(
    2644             :         GDALPDFObjectPdfium::Build(m_poArray->GetObjectAt(nIndex)));
    2645             :     if (poObj == nullptr)
    2646             :         return nullptr;
    2647             :     m_v[nIndex] = std::move(poObj);
    2648             :     return m_v[nIndex].get();
    2649             : }
    2650             : 
    2651             : /************************************************************************/
    2652             : /* ==================================================================== */
    2653             : /*                           GDALPDFStreamPdfium                        */
    2654             : /* ==================================================================== */
    2655             : /************************************************************************/
    2656             : 
    2657             : void GDALPDFStreamPdfium::Decompress()
    2658             : {
    2659             :     if (m_pData != nullptr)
    2660             :         return;
    2661             :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2662             :     acc->LoadAllDataFiltered();
    2663             :     m_nSize = static_cast<int64_t>(acc->GetSize());
    2664             :     m_pData.reset();
    2665             :     const auto nSize = static_cast<size_t>(m_nSize);
    2666             :     if (static_cast<int64_t>(nSize) != m_nSize)
    2667             :     {
    2668             :         m_nSize = 0;
    2669             :     }
    2670             :     if (m_nSize)
    2671             :     {
    2672             :         m_pData.reset(static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(nSize)));
    2673             :         if (!m_pData)
    2674             :             m_nSize = 0;
    2675             :         else
    2676             :             memcpy(&m_pData.get()[0], acc->DetachData().data(), nSize);
    2677             :     }
    2678             : }
    2679             : 
    2680             : /************************************************************************/
    2681             : /*                              GetLength()                             */
    2682             : /************************************************************************/
    2683             : 
    2684             : int64_t GDALPDFStreamPdfium::GetLength(int64_t /* nMaxSize */)
    2685             : {
    2686             :     Decompress();
    2687             :     return m_nSize;
    2688             : }
    2689             : 
    2690             : /************************************************************************/
    2691             : /*                               GetBytes()                             */
    2692             : /************************************************************************/
    2693             : 
    2694             : char *GDALPDFStreamPdfium::GetBytes()
    2695             : {
    2696             :     size_t nLength = static_cast<size_t>(GetLength());
    2697             :     if (nLength == 0)
    2698             :         return nullptr;
    2699             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    2700             :     if (!pszContent)
    2701             :         return nullptr;
    2702             :     memcpy(pszContent, m_pData.get(), nLength);
    2703             :     pszContent[nLength] = '\0';
    2704             :     return pszContent;
    2705             : }
    2706             : 
    2707             : /************************************************************************/
    2708             : /*                                FillRaw()                             */
    2709             : /************************************************************************/
    2710             : 
    2711             : void GDALPDFStreamPdfium::FillRaw()
    2712             : {
    2713             :     if (m_pRawData != nullptr)
    2714             :         return;
    2715             :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2716             :     acc->LoadAllDataRaw();
    2717             :     m_nRawSize = static_cast<int64_t>(acc->GetSize());
    2718             :     m_pRawData.reset();
    2719             :     const auto nSize = static_cast<size_t>(m_nRawSize);
    2720             :     if (static_cast<int64_t>(nSize) != m_nRawSize)
    2721             :     {
    2722             :         m_nRawSize = 0;
    2723             :     }
    2724             :     if (m_nRawSize)
    2725             :     {
    2726             :         m_pRawData.reset(
    2727             :             static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(m_nRawSize)));
    2728             :         if (!m_pRawData)
    2729             :             m_nRawSize = 0;
    2730             :         else
    2731             :             memcpy(&m_pRawData.get()[0], acc->DetachData().data(), m_nRawSize);
    2732             :     }
    2733             : }
    2734             : 
    2735             : /************************************************************************/
    2736             : /*                            GetRawLength()                            */
    2737             : /************************************************************************/
    2738             : 
    2739             : int64_t GDALPDFStreamPdfium::GetRawLength()
    2740             : {
    2741             :     FillRaw();
    2742             :     return m_nRawSize;
    2743             : }
    2744             : 
    2745             : /************************************************************************/
    2746             : /*                             GetRawBytes()                            */
    2747             : /************************************************************************/
    2748             : 
    2749             : char *GDALPDFStreamPdfium::GetRawBytes()
    2750             : {
    2751             :     size_t nLength = static_cast<size_t>(GetRawLength());
    2752             :     if (nLength == 0)
    2753             :         return nullptr;
    2754             :     char *pszContent =
    2755             :         static_cast<char *>(VSI_MALLOC_VERBOSE(sizeof(char) * (nLength + 1)));
    2756             :     if (!pszContent)
    2757             :         return nullptr;
    2758             :     memcpy(pszContent, m_pRawData.get(), nLength);
    2759             :     pszContent[nLength] = '\0';
    2760             :     return pszContent;
    2761             : }
    2762             : 
    2763             : #endif  // HAVE_PDFIUM

Generated by: LCOV version 1.14