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

Generated by: LCOV version 1.14