LCOV - code coverage report
Current view: top level - frmts/pdf - pdfobject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 481 600 80.2 %
Date: 2026-04-09 00:01:40 Functions: 80 88 90.9 %

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

Generated by: LCOV version 1.14