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-05-07 02:17:31 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        4556 : double ROUND_IF_CLOSE(double x, double eps)
      33             : {
      34        4556 :     if (eps == 0.0)
      35        3323 :         eps = fabs(x) < 1 ? 1e-10 : 1e-8;
      36        4556 :     const double dfRounded = std::round(x);
      37        4556 :     if (fabs(x - dfRounded) < eps)
      38        3546 :         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       26516 : GDALPDFObject::~GDALPDFObject()
     212             : {
     213       26516 : }
     214             : 
     215             : /************************************************************************/
     216             : /*                            LookupObject()                            */
     217             : /************************************************************************/
     218             : 
     219        1234 : GDALPDFObject *GDALPDFObject::LookupObject(const char *pszPath)
     220             : {
     221        1234 :     if (GetType() != PDFObjectType_Dictionary)
     222           0 :         return nullptr;
     223        1234 :     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        6965 : GDALPDFDictionary::~GDALPDFDictionary()
     395             : {
     396        6965 : }
     397             : 
     398             : /************************************************************************/
     399             : /*                            LookupObject()                            */
     400             : /************************************************************************/
     401             : 
     402        1716 : GDALPDFObject *GDALPDFDictionary::LookupObject(const char *pszPath)
     403             : {
     404        1716 :     GDALPDFObject *poCurObj = nullptr;
     405        3432 :     CPLStringList aosTokens(CSLTokenizeString2(pszPath, ".", 0));
     406        4113 :     for (int i = 0; i < aosTokens.size(); i++)
     407             :     {
     408        3093 :         int iElt = -1;
     409        3093 :         char *pszBracket = strchr(aosTokens[i], '[');
     410        3093 :         if (pszBracket != nullptr)
     411             :         {
     412           0 :             iElt = atoi(pszBracket + 1);
     413           0 :             *pszBracket = '\0';
     414             :         }
     415             : 
     416        3093 :         if (i == 0)
     417             :         {
     418        1716 :             poCurObj = Get(aosTokens[i]);
     419             :         }
     420             :         else
     421             :         {
     422        1377 :             if (poCurObj->GetType() != PDFObjectType_Dictionary)
     423             :             {
     424           0 :                 return nullptr;
     425             :             }
     426        1377 :             auto poDict = poCurObj->GetDictionary();
     427        1377 :             assert(poDict);
     428        1377 :             poCurObj = poDict->Get(aosTokens[i]);
     429             :         }
     430             : 
     431        3093 :         if (poCurObj == nullptr)
     432             :         {
     433         696 :             return nullptr;
     434             :         }
     435             : 
     436        2397 :         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        1020 :     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        2225 : GDALPDFArray::~GDALPDFArray()
     504             : {
     505        2225 : }
     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        4753 :     GDALPDFDictionaryPoppler(Dict *poDict) : m_poDict(poDict)
     973             :     {
     974        4753 :     }
     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        1294 :     GDALPDFArrayPoppler(const Array *poArray) : m_poArray(poArray)
     998             :     {
     999        1294 :     }
    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         458 :     GDALPDFStreamPoppler(Stream *poStream) : m_poStream(poStream)
    1022             :     {
    1023         458 :     }
    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       31111 : GDALPDFObjectPoppler::~GDALPDFObjectPoppler()
    1043             : {
    1044       15665 :     delete m_poToDestroy;
    1045       15665 :     delete m_poDict;
    1046       15665 :     delete m_poArray;
    1047       15665 :     delete m_poStream;
    1048       31111 : }
    1049             : 
    1050             : /************************************************************************/
    1051             : /*                              GetType()                               */
    1052             : /************************************************************************/
    1053             : 
    1054       61246 : GDALPDFObjectType GDALPDFObjectPoppler::GetType()
    1055             : {
    1056       61246 :     switch (m_poConst->getType())
    1057             :     {
    1058         180 :         case objNull:
    1059         180 :             return PDFObjectType_Null;
    1060           0 :         case objBool:
    1061           0 :             return PDFObjectType_Bool;
    1062       17162 :         case objInt:
    1063       17162 :             return PDFObjectType_Int;
    1064        4876 :         case objReal:
    1065        4876 :             return PDFObjectType_Real;
    1066        2741 :         case objString:
    1067        2741 :             return PDFObjectType_String;
    1068        6671 :         case objName:
    1069        6671 :             return PDFObjectType_Name;
    1070       13343 :         case objArray:
    1071       13343 :             return PDFObjectType_Array;
    1072       12050 :         case objDict:
    1073       12050 :             return PDFObjectType_Dictionary;
    1074        4223 :         case objStream:
    1075        4223 :             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        5484 : int GDALPDFObjectPoppler::GetInt()
    1107             : {
    1108        5484 :     if (GetType() == PDFObjectType_Int)
    1109        5484 :         return m_poConst->getInt();
    1110             :     else
    1111           0 :         return 0;
    1112             : }
    1113             : 
    1114             : /************************************************************************/
    1115             : /*                              GetReal()                               */
    1116             : /************************************************************************/
    1117             : 
    1118        1214 : double GDALPDFObjectPoppler::GetReal()
    1119             : {
    1120        1214 :     if (GetType() == PDFObjectType_Real)
    1121        1214 :         return m_poConst->getReal();
    1122             :     else
    1123           0 :         return 0.0;
    1124             : }
    1125             : 
    1126             : /************************************************************************/
    1127             : /*                             GetString()                              */
    1128             : /************************************************************************/
    1129             : 
    1130        1397 : const std::string &GDALPDFObjectPoppler::GetString()
    1131             : {
    1132        1397 :     if (GetType() == PDFObjectType_String)
    1133             :     {
    1134             :         const std::string &osStdStr = *(
    1135        1397 :             [](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        1397 :                     return &(obj->toStr());
    1150             :                 }
    1151        1397 :             }(m_poConst->getString()));
    1152             :         const bool bLEUnicodeMarker =
    1153        1743 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFE &&
    1154         346 :             static_cast<uint8_t>(osStdStr[1]) == 0xFF;
    1155             :         const bool bBEUnicodeMarker =
    1156        1487 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFF &&
    1157          90 :             static_cast<uint8_t>(osStdStr[1]) == 0xFE;
    1158        1397 :         if (!bLEUnicodeMarker && !bBEUnicodeMarker)
    1159             :         {
    1160         961 :             if (CPLIsUTF8(osStdStr.c_str(), -1))
    1161             :             {
    1162         961 :                 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        2942 : const std::string &GDALPDFObjectPoppler::GetName()
    1186             : {
    1187        2942 :     if (GetType() == PDFObjectType_Name)
    1188        2942 :         return (osStr = m_poConst->getName());
    1189             :     else
    1190           0 :         return (osStr = "");
    1191             : }
    1192             : 
    1193             : /************************************************************************/
    1194             : /*                           GetDictionary()                            */
    1195             : /************************************************************************/
    1196             : 
    1197        7559 : GDALPDFDictionary *GDALPDFObjectPoppler::GetDictionary()
    1198             : {
    1199        7559 :     if (GetType() != PDFObjectType_Dictionary)
    1200           0 :         return nullptr;
    1201             : 
    1202        7559 :     if (m_poDict)
    1203        2806 :         return m_poDict;
    1204             : 
    1205        4753 :     Dict *poDict = (m_poConst->getType() == objStream)
    1206        4753 :                        ? m_poConst->getStream()->getDict()
    1207        3686 :                        : m_poConst->getDict();
    1208        4753 :     if (poDict == nullptr)
    1209           0 :         return nullptr;
    1210        4753 :     m_poDict = new GDALPDFDictionaryPoppler(poDict);
    1211        4753 :     return m_poDict;
    1212             : }
    1213             : 
    1214             : /************************************************************************/
    1215             : /*                              GetArray()                              */
    1216             : /************************************************************************/
    1217             : 
    1218        6652 : GDALPDFArray *GDALPDFObjectPoppler::GetArray()
    1219             : {
    1220        6652 :     if (GetType() != PDFObjectType_Array)
    1221           0 :         return nullptr;
    1222             : 
    1223        6652 :     if (m_poArray)
    1224        5421 :         return m_poArray;
    1225             : 
    1226        1231 :     Array *poArray = m_poConst->getArray();
    1227        1231 :     if (poArray == nullptr)
    1228           0 :         return nullptr;
    1229        1231 :     m_poArray = new GDALPDFArrayPoppler(poArray);
    1230        1231 :     return m_poArray;
    1231             : }
    1232             : 
    1233             : /************************************************************************/
    1234             : /*                             GetStream()                              */
    1235             : /************************************************************************/
    1236             : 
    1237         605 : GDALPDFStream *GDALPDFObjectPoppler::GetStream()
    1238             : {
    1239         605 :     if (m_poConst->getType() != objStream)
    1240          14 :         return nullptr;
    1241             : 
    1242         591 :     if (m_poStream)
    1243         133 :         return m_poStream;
    1244         458 :     m_poStream = new GDALPDFStreamPoppler(m_poConst->getStream());
    1245         458 :     return m_poStream;
    1246             : }
    1247             : 
    1248             : /************************************************************************/
    1249             : /*                          SetRefNumAndGen()                           */
    1250             : /************************************************************************/
    1251             : 
    1252       15227 : void GDALPDFObjectPoppler::SetRefNumAndGen(const GDALPDFObjectNum &nNum,
    1253             :                                            int nGen)
    1254             : {
    1255       15227 :     m_nRefNum = nNum;
    1256       15227 :     m_nRefGen = nGen;
    1257       15227 : }
    1258             : 
    1259             : /************************************************************************/
    1260             : /*                             GetRefNum()                              */
    1261             : /************************************************************************/
    1262             : 
    1263        2640 : GDALPDFObjectNum GDALPDFObjectPoppler::GetRefNum()
    1264             : {
    1265        2640 :     return m_nRefNum;
    1266             : }
    1267             : 
    1268             : /************************************************************************/
    1269             : /*                             GetRefGen()                              */
    1270             : /************************************************************************/
    1271             : 
    1272        1660 : int GDALPDFObjectPoppler::GetRefGen()
    1273             : {
    1274        1660 :     return m_nRefGen;
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /* ==================================================================== */
    1279             : /*                        GDALPDFDictionaryPoppler                      */
    1280             : /* ==================================================================== */
    1281             : /************************************************************************/
    1282             : 
    1283             : /************************************************************************/
    1284             : /*                     ~GDALPDFDictionaryPoppler()                      */
    1285             : /************************************************************************/
    1286             : 
    1287        9506 : GDALPDFDictionaryPoppler::~GDALPDFDictionaryPoppler()
    1288             : {
    1289        4753 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1290        4753 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1291       14260 :     for (; oIter != oEnd; ++oIter)
    1292        9507 :         delete oIter->second;
    1293        9506 : }
    1294             : 
    1295             : /************************************************************************/
    1296             : /*                                Get()                                 */
    1297             : /************************************************************************/
    1298             : 
    1299       14347 : GDALPDFObject *GDALPDFDictionaryPoppler::Get(const char *pszKey)
    1300             : {
    1301       14347 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1302       14347 :     if (oIter != m_map.end())
    1303        2439 :         return oIter->second;
    1304             : 
    1305       11908 :     auto &&o(m_poDict->lookupNF(pszKey));
    1306       11908 :     if (!o.isNull())
    1307             :     {
    1308        9507 :         GDALPDFObjectNum nRefNum;
    1309        9507 :         int nRefGen = 0;
    1310        9507 :         if (o.isRef())
    1311             :         {
    1312        3023 :             nRefNum = o.getRefNum();
    1313        3023 :             nRefGen = o.getRefGen();
    1314        3023 :             Object o2(m_poDict->lookup(pszKey));
    1315        3023 :             if (!o2.isNull())
    1316             :             {
    1317             :                 GDALPDFObjectPoppler *poObj =
    1318        3023 :                     new GDALPDFObjectPoppler(new Object(std::move(o2)), TRUE);
    1319        3023 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1320        3023 :                 m_map[pszKey] = poObj;
    1321        3023 :                 return poObj;
    1322             :             }
    1323             :         }
    1324             :         else
    1325             :         {
    1326             :             GDALPDFObjectPoppler *poObj =
    1327        6484 :                 new GDALPDFObjectPoppler(new Object(o.copy()), TRUE);
    1328        6484 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1329        6484 :             m_map[pszKey] = poObj;
    1330        6484 :             return poObj;
    1331             :         }
    1332             :     }
    1333        2401 :     return nullptr;
    1334             : }
    1335             : 
    1336             : /************************************************************************/
    1337             : /*                             GetValues()                              */
    1338             : /************************************************************************/
    1339             : 
    1340         478 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPoppler::GetValues()
    1341             : {
    1342         478 :     int i = 0;
    1343         478 :     int nLength = m_poDict->getLength();
    1344        2350 :     for (i = 0; i < nLength; i++)
    1345             :     {
    1346        1872 :         const char *pszKey = m_poDict->getKey(i);
    1347        1872 :         Get(pszKey);
    1348             :     }
    1349         478 :     return m_map;
    1350             : }
    1351             : 
    1352             : /************************************************************************/
    1353             : /* ==================================================================== */
    1354             : /*                          GDALPDFArrayPoppler                         */
    1355             : /* ==================================================================== */
    1356             : /************************************************************************/
    1357             : 
    1358             : /************************************************************************/
    1359             : /*                         GDALPDFCreateArray()                         */
    1360             : /************************************************************************/
    1361             : 
    1362          63 : GDALPDFArray *GDALPDFCreateArray(const Array *array)
    1363             : {
    1364          63 :     return new GDALPDFArrayPoppler(array);
    1365             : }
    1366             : 
    1367             : /************************************************************************/
    1368             : /*                             GetLength()                              */
    1369             : /************************************************************************/
    1370             : 
    1371        9487 : int GDALPDFArrayPoppler::GetLength()
    1372             : {
    1373        9487 :     return m_poArray->getLength();
    1374             : }
    1375             : 
    1376             : /************************************************************************/
    1377             : /*                                Get()                                 */
    1378             : /************************************************************************/
    1379             : 
    1380        6383 : GDALPDFObject *GDALPDFArrayPoppler::Get(int nIndex)
    1381             : {
    1382        6383 :     if (nIndex < 0 || nIndex >= GetLength())
    1383           0 :         return nullptr;
    1384             : 
    1385        6383 :     if (m_v.empty())
    1386        1259 :         m_v.resize(GetLength());
    1387             : 
    1388        6383 :     if (m_v[nIndex] != nullptr)
    1389         882 :         return m_v[nIndex].get();
    1390             : 
    1391        5501 :     auto &&o(m_poArray->getNF(nIndex));
    1392        5501 :     if (!o.isNull())
    1393             :     {
    1394        5501 :         GDALPDFObjectNum nRefNum;
    1395        5501 :         int nRefGen = 0;
    1396        5501 :         if (o.isRef())
    1397             :         {
    1398         872 :             nRefNum = o.getRefNum();
    1399         872 :             nRefGen = o.getRefGen();
    1400         872 :             Object o2(m_poArray->get(nIndex));
    1401         872 :             if (!o2.isNull())
    1402             :             {
    1403             :                 auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1404        1744 :                     new Object(std::move(o2)), TRUE);
    1405         872 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1406         872 :                 m_v[nIndex] = std::move(poObj);
    1407         872 :                 return m_v[nIndex].get();
    1408             :             }
    1409             :         }
    1410             :         else
    1411             :         {
    1412             :             auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1413        9258 :                 new Object(o.copy()), TRUE);
    1414        4629 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1415        4629 :             m_v[nIndex] = std::move(poObj);
    1416        4629 :             return m_v[nIndex].get();
    1417             :         }
    1418             :     }
    1419           0 :     return nullptr;
    1420             : }
    1421             : 
    1422             : /************************************************************************/
    1423             : /* ==================================================================== */
    1424             : /*                          GDALPDFStreamPoppler                        */
    1425             : /* ==================================================================== */
    1426             : /************************************************************************/
    1427             : 
    1428             : /************************************************************************/
    1429             : /*                             GetLength()                              */
    1430             : /************************************************************************/
    1431             : 
    1432         556 : int64_t GDALPDFStreamPoppler::GetLength(int64_t nMaxSize)
    1433             : {
    1434         556 :     if (m_nLength >= 0)
    1435         292 :         return m_nLength;
    1436             : 
    1437             : #if POPPLER_MAJOR_VERSION > 25
    1438             :     if (!m_poStream->rewind())
    1439             :         return 0;
    1440             : #elif POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2
    1441             :     if (!m_poStream->reset())
    1442             :         return 0;
    1443             : #else
    1444         264 :     m_poStream->reset();
    1445             : #endif
    1446         264 :     m_nLength = 0;
    1447             :     unsigned char readBuf[4096];
    1448             :     int readChars;
    1449         528 :     while ((readChars = m_poStream->doGetChars(4096, readBuf)) != 0)
    1450             :     {
    1451         264 :         m_nLength += readChars;
    1452         264 :         if (nMaxSize != 0 && m_nLength > nMaxSize)
    1453             :         {
    1454           0 :             m_nLength = -1;
    1455           0 :             return std::numeric_limits<int64_t>::max();
    1456             :         }
    1457             :     }
    1458         264 :     return m_nLength;
    1459             : }
    1460             : 
    1461             : /************************************************************************/
    1462             : /*                        GooStringToCharStart()                        */
    1463             : /************************************************************************/
    1464             : 
    1465         530 : static char *GooStringToCharStart(GooString &gstr)
    1466             : {
    1467             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
    1468             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 10)
    1469             :     const auto nLength = gstr.size();
    1470             : #else
    1471         530 :     const auto nLength = gstr.getLength();
    1472             : #endif
    1473         530 :     if (nLength)
    1474             :     {
    1475         528 :         char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    1476         528 :         if (pszContent)
    1477             :         {
    1478         528 :             const char *srcStr = gstr.c_str();
    1479         528 :             memcpy(pszContent, srcStr, nLength);
    1480         528 :             pszContent[nLength] = '\0';
    1481             :         }
    1482         528 :         return pszContent;
    1483             :     }
    1484           2 :     return nullptr;
    1485             : }
    1486             : 
    1487             : /************************************************************************/
    1488             : /*                              GetBytes()                              */
    1489             : /************************************************************************/
    1490             : 
    1491         528 : char *GDALPDFStreamPoppler::GetBytes()
    1492             : {
    1493        1056 :     GooString gstr;
    1494             :     try
    1495             :     {
    1496         528 :         m_poStream->fillGooString(&gstr);
    1497             :     }
    1498           0 :     catch (const std::exception &e)
    1499             :     {
    1500           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1501           0 :                  "GDALPDFStreamPoppler::GetBytes(): %s", e.what());
    1502           0 :         return nullptr;
    1503             :     }
    1504         528 :     m_nLength = static_cast<int64_t>(gstr.toStr().size());
    1505         528 :     return GooStringToCharStart(gstr);
    1506             : }
    1507             : 
    1508             : /************************************************************************/
    1509             : /*                            GetRawLength()                            */
    1510             : /************************************************************************/
    1511             : 
    1512          63 : int64_t GDALPDFStreamPoppler::GetRawLength()
    1513             : {
    1514          63 :     if (m_nRawLength >= 0)
    1515           2 :         return m_nRawLength;
    1516             : 
    1517          61 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1518             : #if POPPLER_MAJOR_VERSION > 25
    1519             :     if (!undecodeStream->rewind())
    1520             :         return 0;
    1521             : #elif POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 2
    1522             :     if (!undecodeStream->reset())
    1523             :         return 0;
    1524             : #else
    1525          61 :     undecodeStream->reset();
    1526             : #endif
    1527          61 :     m_nRawLength = 0;
    1528       25531 :     while (undecodeStream->getChar() != EOF)
    1529       25470 :         m_nRawLength++;
    1530          61 :     return m_nRawLength;
    1531             : }
    1532             : 
    1533             : /************************************************************************/
    1534             : /*                            GetRawBytes()                             */
    1535             : /************************************************************************/
    1536             : 
    1537           2 : char *GDALPDFStreamPoppler::GetRawBytes()
    1538             : {
    1539           4 :     GooString gstr;
    1540           2 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1541             :     try
    1542             :     {
    1543           2 :         undecodeStream->fillGooString(&gstr);
    1544             :     }
    1545           0 :     catch (const std::exception &e)
    1546             :     {
    1547           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1548           0 :                  "GDALPDFStreamPoppler::GetRawBytes(): %s", e.what());
    1549           0 :         return nullptr;
    1550             :     }
    1551             : #if POPPLER_MAJOR_VERSION > 25 ||                                              \
    1552             :     (POPPLER_MAJOR_VERSION == 25 && POPPLER_MINOR_VERSION >= 10)
    1553             :     m_nRawLength = gstr.size();
    1554             : #else
    1555           2 :     m_nRawLength = gstr.getLength();
    1556             : #endif
    1557           2 :     return GooStringToCharStart(gstr);
    1558             : }
    1559             : 
    1560             : #endif  // HAVE_POPPLER
    1561             : 
    1562             : #ifdef HAVE_PODOFO
    1563             : 
    1564             : /************************************************************************/
    1565             : /* ==================================================================== */
    1566             : /*                         GDALPDFDictionaryPodofo                      */
    1567             : /* ==================================================================== */
    1568             : /************************************************************************/
    1569             : 
    1570             : class GDALPDFDictionaryPodofo final : public GDALPDFDictionary
    1571             : {
    1572             :   private:
    1573             :     const PoDoFo::PdfDictionary *m_poDict;
    1574             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1575             :     std::map<CPLString, GDALPDFObject *> m_map{};
    1576             : 
    1577             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFDictionaryPodofo)
    1578             : 
    1579             :   public:
    1580             :     GDALPDFDictionaryPodofo(const PoDoFo::PdfDictionary *poDict,
    1581             :                             const PoDoFo::PdfVecObjects &poObjects)
    1582             :         : m_poDict(poDict), m_poObjects(poObjects)
    1583             :     {
    1584             :     }
    1585             : 
    1586             :     ~GDALPDFDictionaryPodofo() override;
    1587             : 
    1588             :     GDALPDFObject *Get(const char *pszKey) override;
    1589             :     std::map<CPLString, GDALPDFObject *> &GetValues() override;
    1590             : };
    1591             : 
    1592             : /************************************************************************/
    1593             : /* ==================================================================== */
    1594             : /*                           GDALPDFArrayPodofo                         */
    1595             : /* ==================================================================== */
    1596             : /************************************************************************/
    1597             : 
    1598             : class GDALPDFArrayPodofo final : public GDALPDFArray
    1599             : {
    1600             :   private:
    1601             :     const PoDoFo::PdfArray *m_poArray;
    1602             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1603             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    1604             : 
    1605             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPodofo)
    1606             : 
    1607             :   public:
    1608             :     GDALPDFArrayPodofo(const PoDoFo::PdfArray *poArray,
    1609             :                        const PoDoFo::PdfVecObjects &poObjects)
    1610             :         : m_poArray(poArray), m_poObjects(poObjects)
    1611             :     {
    1612             :     }
    1613             : 
    1614             :     int GetLength() override;
    1615             :     GDALPDFObject *Get(int nIndex) override;
    1616             : };
    1617             : 
    1618             : /************************************************************************/
    1619             : /* ==================================================================== */
    1620             : /*                          GDALPDFStreamPodofo                         */
    1621             : /* ==================================================================== */
    1622             : /************************************************************************/
    1623             : 
    1624             : class GDALPDFStreamPodofo final : public GDALPDFStream
    1625             : {
    1626             :   private:
    1627             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1628             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1629             :     const PoDoFo::PdfObjectStream *m_pStream;
    1630             : #else
    1631             :     const PoDoFo::PdfStream *m_pStream;
    1632             : #endif
    1633             : 
    1634             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFStreamPodofo)
    1635             : 
    1636             :   public:
    1637             :     GDALPDFStreamPodofo(
    1638             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1639             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1640             :         const PoDoFo::PdfObjectStream *
    1641             : #else
    1642             :         const PoDoFo::PdfStream *
    1643             : #endif
    1644             :             pStream)
    1645             :         : m_pStream(pStream)
    1646             :     {
    1647             :     }
    1648             : 
    1649             :     int64_t GetLength(int64_t nMaxSize = 0) override;
    1650             :     char *GetBytes() override;
    1651             : 
    1652             :     int64_t GetRawLength() override;
    1653             :     char *GetRawBytes() override;
    1654             : };
    1655             : 
    1656             : /************************************************************************/
    1657             : /* ==================================================================== */
    1658             : /*                          GDALPDFObjectPodofo                         */
    1659             : /* ==================================================================== */
    1660             : /************************************************************************/
    1661             : 
    1662             : /************************************************************************/
    1663             : /*                        GDALPDFObjectPodofo()                         */
    1664             : /************************************************************************/
    1665             : 
    1666             : GDALPDFObjectPodofo::GDALPDFObjectPodofo(const PoDoFo::PdfObject *po,
    1667             :                                          const PoDoFo::PdfVecObjects &poObjects)
    1668             :     : m_po(po), m_poObjects(poObjects)
    1669             : {
    1670             :     try
    1671             :     {
    1672             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1673             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1674             :         if (m_po->GetDataType() == PoDoFo::PdfDataType::Reference)
    1675             :         {
    1676             :             PoDoFo::PdfObject *poObj =
    1677             :                 m_poObjects.GetObject(m_po->GetReference());
    1678             :             if (poObj)
    1679             :                 m_po = poObj;
    1680             :         }
    1681             : #else
    1682             :         if (m_po->GetDataType() == PoDoFo::ePdfDataType_Reference)
    1683             :         {
    1684             :             PoDoFo::PdfObject *poObj =
    1685             :                 m_poObjects.GetObject(m_po->GetReference());
    1686             :             if (poObj)
    1687             :                 m_po = poObj;
    1688             :         }
    1689             : #endif
    1690             :     }
    1691             :     catch (PoDoFo::PdfError &oError)
    1692             :     {
    1693             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1694             :                  oError.what());
    1695             :     }
    1696             : }
    1697             : 
    1698             : /************************************************************************/
    1699             : /*                        ~GDALPDFObjectPodofo()                        */
    1700             : /************************************************************************/
    1701             : 
    1702             : GDALPDFObjectPodofo::~GDALPDFObjectPodofo()
    1703             : {
    1704             :     delete m_poDict;
    1705             :     delete m_poArray;
    1706             :     delete m_poStream;
    1707             : }
    1708             : 
    1709             : /************************************************************************/
    1710             : /*                              GetType()                               */
    1711             : /************************************************************************/
    1712             : 
    1713             : GDALPDFObjectType GDALPDFObjectPodofo::GetType()
    1714             : {
    1715             :     try
    1716             :     {
    1717             :         switch (m_po->GetDataType())
    1718             :         {
    1719             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1720             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1721             :             case PoDoFo::PdfDataType::Null:
    1722             :                 return PDFObjectType_Null;
    1723             :             case PoDoFo::PdfDataType::Bool:
    1724             :                 return PDFObjectType_Bool;
    1725             :             case PoDoFo::PdfDataType::Number:
    1726             :                 return PDFObjectType_Int;
    1727             :             case PoDoFo::PdfDataType::Real:
    1728             :                 return PDFObjectType_Real;
    1729             :             case PoDoFo::PdfDataType::String:
    1730             :                 return PDFObjectType_String;
    1731             :             case PoDoFo::PdfDataType::Name:
    1732             :                 return PDFObjectType_Name;
    1733             :             case PoDoFo::PdfDataType::Array:
    1734             :                 return PDFObjectType_Array;
    1735             :             case PoDoFo::PdfDataType::Dictionary:
    1736             :                 return PDFObjectType_Dictionary;
    1737             :             default:
    1738             :                 return PDFObjectType_Unknown;
    1739             : #else
    1740             :             case PoDoFo::ePdfDataType_Null:
    1741             :                 return PDFObjectType_Null;
    1742             :             case PoDoFo::ePdfDataType_Bool:
    1743             :                 return PDFObjectType_Bool;
    1744             :             case PoDoFo::ePdfDataType_Number:
    1745             :                 return PDFObjectType_Int;
    1746             :             case PoDoFo::ePdfDataType_Real:
    1747             :                 return PDFObjectType_Real;
    1748             :             case PoDoFo::ePdfDataType_HexString:
    1749             :                 return PDFObjectType_String;
    1750             :             case PoDoFo::ePdfDataType_String:
    1751             :                 return PDFObjectType_String;
    1752             :             case PoDoFo::ePdfDataType_Name:
    1753             :                 return PDFObjectType_Name;
    1754             :             case PoDoFo::ePdfDataType_Array:
    1755             :                 return PDFObjectType_Array;
    1756             :             case PoDoFo::ePdfDataType_Dictionary:
    1757             :                 return PDFObjectType_Dictionary;
    1758             :             default:
    1759             :                 return PDFObjectType_Unknown;
    1760             : #endif
    1761             :         }
    1762             :     }
    1763             :     catch (PoDoFo::PdfError &oError)
    1764             :     {
    1765             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1766             :                  oError.what());
    1767             :         return PDFObjectType_Unknown;
    1768             :     }
    1769             : }
    1770             : 
    1771             : /************************************************************************/
    1772             : /*                         GetTypeNameNative()                          */
    1773             : /************************************************************************/
    1774             : 
    1775             : const char *GDALPDFObjectPodofo::GetTypeNameNative()
    1776             : {
    1777             :     try
    1778             :     {
    1779             :         osStr = m_po->GetDataTypeString();
    1780             :         return osStr.c_str();
    1781             :     }
    1782             :     catch (PoDoFo::PdfError &oError)
    1783             :     {
    1784             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1785             :                  oError.what());
    1786             :         return "unknown";
    1787             :     }
    1788             : }
    1789             : 
    1790             : /************************************************************************/
    1791             : /*                              GetBool()                               */
    1792             : /************************************************************************/
    1793             : 
    1794             : int GDALPDFObjectPodofo::GetBool()
    1795             : {
    1796             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1797             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1798             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Bool)
    1799             : #else
    1800             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Bool)
    1801             : #endif
    1802             :         return m_po->GetBool();
    1803             :     else
    1804             :         return 0;
    1805             : }
    1806             : 
    1807             : /************************************************************************/
    1808             : /*                               GetInt()                               */
    1809             : /************************************************************************/
    1810             : 
    1811             : int GDALPDFObjectPodofo::GetInt()
    1812             : {
    1813             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1814             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1815             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Number)
    1816             : #else
    1817             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Number)
    1818             : #endif
    1819             :         return static_cast<int>(m_po->GetNumber());
    1820             :     else
    1821             :         return 0;
    1822             : }
    1823             : 
    1824             : /************************************************************************/
    1825             : /*                              GetReal()                               */
    1826             : /************************************************************************/
    1827             : 
    1828             : double GDALPDFObjectPodofo::GetReal()
    1829             : {
    1830             :     if (GetType() == PDFObjectType_Real)
    1831             :         return m_po->GetReal();
    1832             :     else
    1833             :         return 0.0;
    1834             : }
    1835             : 
    1836             : /************************************************************************/
    1837             : /*                             GetString()                              */
    1838             : /************************************************************************/
    1839             : 
    1840             : const std::string &GDALPDFObjectPodofo::GetString()
    1841             : {
    1842             :     if (GetType() == PDFObjectType_String)
    1843             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1844             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1845             :         return (osStr = m_po->GetString().GetString());
    1846             : #else
    1847             :         return (osStr = m_po->GetString().GetStringUtf8());
    1848             : #endif
    1849             :     else
    1850             :         return (osStr = "");
    1851             : }
    1852             : 
    1853             : /************************************************************************/
    1854             : /*                              GetName()                               */
    1855             : /************************************************************************/
    1856             : 
    1857             : const std::string &GDALPDFObjectPodofo::GetName()
    1858             : {
    1859             :     if (GetType() == PDFObjectType_Name)
    1860             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1861             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1862             :         return (osStr = m_po->GetName().GetString());
    1863             : #else
    1864             :         return (osStr = m_po->GetName().GetName());
    1865             : #endif
    1866             :     else
    1867             :         return (osStr = "");
    1868             : }
    1869             : 
    1870             : /************************************************************************/
    1871             : /*                           GetDictionary()                            */
    1872             : /************************************************************************/
    1873             : 
    1874             : GDALPDFDictionary *GDALPDFObjectPodofo::GetDictionary()
    1875             : {
    1876             :     if (GetType() != PDFObjectType_Dictionary)
    1877             :         return nullptr;
    1878             : 
    1879             :     if (m_poDict)
    1880             :         return m_poDict;
    1881             : 
    1882             :     m_poDict = new GDALPDFDictionaryPodofo(&m_po->GetDictionary(), m_poObjects);
    1883             :     return m_poDict;
    1884             : }
    1885             : 
    1886             : /************************************************************************/
    1887             : /*                              GetArray()                              */
    1888             : /************************************************************************/
    1889             : 
    1890             : GDALPDFArray *GDALPDFObjectPodofo::GetArray()
    1891             : {
    1892             :     if (GetType() != PDFObjectType_Array)
    1893             :         return nullptr;
    1894             : 
    1895             :     if (m_poArray)
    1896             :         return m_poArray;
    1897             : 
    1898             :     m_poArray = new GDALPDFArrayPodofo(&m_po->GetArray(), m_poObjects);
    1899             :     return m_poArray;
    1900             : }
    1901             : 
    1902             : /************************************************************************/
    1903             : /*                             GetStream()                              */
    1904             : /************************************************************************/
    1905             : 
    1906             : GDALPDFStream *GDALPDFObjectPodofo::GetStream()
    1907             : {
    1908             :     try
    1909             :     {
    1910             :         if (!m_po->HasStream())
    1911             :             return nullptr;
    1912             :     }
    1913             :     catch (PoDoFo::PdfError &oError)
    1914             :     {
    1915             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object : %s",
    1916             :                  oError.what());
    1917             :         return nullptr;
    1918             :     }
    1919             :     catch (...)
    1920             :     {
    1921             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object");
    1922             :         return nullptr;
    1923             :     }
    1924             : 
    1925             :     if (m_poStream == nullptr)
    1926             :         m_poStream = new GDALPDFStreamPodofo(m_po->GetStream());
    1927             :     return m_poStream;
    1928             : }
    1929             : 
    1930             : /************************************************************************/
    1931             : /*                             GetRefNum()                              */
    1932             : /************************************************************************/
    1933             : 
    1934             : GDALPDFObjectNum GDALPDFObjectPodofo::GetRefNum()
    1935             : {
    1936             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1937             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1938             :     return GDALPDFObjectNum(m_po->GetIndirectReference().ObjectNumber());
    1939             : #else
    1940             :     return GDALPDFObjectNum(m_po->Reference().ObjectNumber());
    1941             : #endif
    1942             : }
    1943             : 
    1944             : /************************************************************************/
    1945             : /*                             GetRefGen()                              */
    1946             : /************************************************************************/
    1947             : 
    1948             : int GDALPDFObjectPodofo::GetRefGen()
    1949             : {
    1950             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1951             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1952             :     return m_po->GetIndirectReference().GenerationNumber();
    1953             : #else
    1954             :     return m_po->Reference().GenerationNumber();
    1955             : #endif
    1956             : }
    1957             : 
    1958             : /************************************************************************/
    1959             : /* ==================================================================== */
    1960             : /*                         GDALPDFDictionaryPodofo                      */
    1961             : /* ==================================================================== */
    1962             : /************************************************************************/
    1963             : 
    1964             : /************************************************************************/
    1965             : /*                      ~GDALPDFDictionaryPodofo()                      */
    1966             : /************************************************************************/
    1967             : 
    1968             : GDALPDFDictionaryPodofo::~GDALPDFDictionaryPodofo()
    1969             : {
    1970             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1971             :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1972             :     for (; oIter != oEnd; ++oIter)
    1973             :         delete oIter->second;
    1974             : }
    1975             : 
    1976             : /************************************************************************/
    1977             : /*                                Get()                                 */
    1978             : /************************************************************************/
    1979             : 
    1980             : GDALPDFObject *GDALPDFDictionaryPodofo::Get(const char *pszKey)
    1981             : {
    1982             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1983             :     if (oIter != m_map.end())
    1984             :         return oIter->second;
    1985             : 
    1986             :     const PoDoFo::PdfObject *poVal = m_poDict->GetKey(PoDoFo::PdfName(pszKey));
    1987             :     if (poVal)
    1988             :     {
    1989             :         GDALPDFObjectPodofo *poObj =
    1990             :             new GDALPDFObjectPodofo(poVal, m_poObjects);
    1991             :         m_map[pszKey] = poObj;
    1992             :         return poObj;
    1993             :     }
    1994             :     else
    1995             :     {
    1996             :         return nullptr;
    1997             :     }
    1998             : }
    1999             : 
    2000             : /************************************************************************/
    2001             : /*                             GetValues()                              */
    2002             : /************************************************************************/
    2003             : 
    2004             : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPodofo::GetValues()
    2005             : {
    2006             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2007             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2008             :     for (const auto &oIter : *m_poDict)
    2009             :     {
    2010             :         const std::string osTmp(oIter.first.GetString());
    2011             :         Get(osTmp.c_str());
    2012             :     }
    2013             : #else
    2014             :     for (const auto &oIter : m_poDict->GetKeys())
    2015             :     {
    2016             :         Get(oIter.first.GetName().c_str());
    2017             :     }
    2018             : #endif
    2019             :     return m_map;
    2020             : }
    2021             : 
    2022             : /************************************************************************/
    2023             : /* ==================================================================== */
    2024             : /*                           GDALPDFArrayPodofo                         */
    2025             : /* ==================================================================== */
    2026             : /************************************************************************/
    2027             : 
    2028             : /************************************************************************/
    2029             : /*                             GetLength()                              */
    2030             : /************************************************************************/
    2031             : 
    2032             : int GDALPDFArrayPodofo::GetLength()
    2033             : {
    2034             :     return static_cast<int>(m_poArray->GetSize());
    2035             : }
    2036             : 
    2037             : /************************************************************************/
    2038             : /*                                Get()                                 */
    2039             : /************************************************************************/
    2040             : 
    2041             : GDALPDFObject *GDALPDFArrayPodofo::Get(int nIndex)
    2042             : {
    2043             :     if (nIndex < 0 || nIndex >= GetLength())
    2044             :         return nullptr;
    2045             : 
    2046             :     if (m_v.empty())
    2047             :         m_v.resize(GetLength());
    2048             : 
    2049             :     if (m_v[nIndex] != nullptr)
    2050             :         return m_v[nIndex].get();
    2051             : 
    2052             :     const PoDoFo::PdfObject &oVal = (*m_poArray)[nIndex];
    2053             :     m_v[nIndex] = std::make_unique<GDALPDFObjectPodofo>(&oVal, m_poObjects);
    2054             :     return m_v[nIndex].get();
    2055             : }
    2056             : 
    2057             : /************************************************************************/
    2058             : /* ==================================================================== */
    2059             : /*                           GDALPDFStreamPodofo                        */
    2060             : /* ==================================================================== */
    2061             : /************************************************************************/
    2062             : 
    2063             : /************************************************************************/
    2064             : /*                             GetLength()                              */
    2065             : /************************************************************************/
    2066             : 
    2067             : int64_t GDALPDFStreamPodofo::GetLength(int64_t /* nMaxSize */)
    2068             : {
    2069             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2070             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2071             :     PoDoFo::charbuff str;
    2072             :     try
    2073             :     {
    2074             :         m_pStream->CopyToSafe(str);
    2075             :     }
    2076             :     catch (PoDoFo::PdfError &e)
    2077             :     {
    2078             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2079             :                  e.what());
    2080             :         return 0;
    2081             :     }
    2082             :     return static_cast<int64_t>(str.size());
    2083             : #else
    2084             :     char *pBuffer = nullptr;
    2085             :     PoDoFo::pdf_long nLen = 0;
    2086             :     try
    2087             :     {
    2088             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2089             :         PoDoFo::podofo_free(pBuffer);
    2090             :         return static_cast<int64_t>(nLen);
    2091             :     }
    2092             :     catch (PoDoFo::PdfError &e)
    2093             :     {
    2094             :     }
    2095             :     return 0;
    2096             : #endif
    2097             : }
    2098             : 
    2099             : /************************************************************************/
    2100             : /*                              GetBytes()                              */
    2101             : /************************************************************************/
    2102             : 
    2103             : char *GDALPDFStreamPodofo::GetBytes()
    2104             : {
    2105             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2106             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2107             :     PoDoFo::charbuff str;
    2108             :     try
    2109             :     {
    2110             :         m_pStream->CopyToSafe(str);
    2111             :     }
    2112             :     catch (PoDoFo::PdfError &e)
    2113             :     {
    2114             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2115             :                  e.what());
    2116             :         return nullptr;
    2117             :     }
    2118             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2119             :     if (!pszContent)
    2120             :     {
    2121             :         return nullptr;
    2122             :     }
    2123             :     memcpy(pszContent, str.data(), str.size());
    2124             :     pszContent[str.size()] = '\0';
    2125             :     return pszContent;
    2126             : #else
    2127             :     char *pBuffer = nullptr;
    2128             :     PoDoFo::pdf_long nLen = 0;
    2129             :     try
    2130             :     {
    2131             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2132             :     }
    2133             :     catch (PoDoFo::PdfError &e)
    2134             :     {
    2135             :         return nullptr;
    2136             :     }
    2137             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2138             :     if (!pszContent)
    2139             :     {
    2140             :         PoDoFo::podofo_free(pBuffer);
    2141             :         return nullptr;
    2142             :     }
    2143             :     memcpy(pszContent, pBuffer, nLen);
    2144             :     PoDoFo::podofo_free(pBuffer);
    2145             :     pszContent[nLen] = '\0';
    2146             :     return pszContent;
    2147             : #endif
    2148             : }
    2149             : 
    2150             : /************************************************************************/
    2151             : /*                            GetRawLength()                            */
    2152             : /************************************************************************/
    2153             : 
    2154             : int64_t GDALPDFStreamPodofo::GetRawLength()
    2155             : {
    2156             :     try
    2157             :     {
    2158             :         auto nLen = m_pStream->GetLength();
    2159             :         return static_cast<int64_t>(nLen);
    2160             :     }
    2161             :     catch (PoDoFo::PdfError &e)
    2162             :     {
    2163             :     }
    2164             :     return 0;
    2165             : }
    2166             : 
    2167             : /************************************************************************/
    2168             : /*                            GetRawBytes()                             */
    2169             : /************************************************************************/
    2170             : 
    2171             : char *GDALPDFStreamPodofo::GetRawBytes()
    2172             : {
    2173             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2174             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2175             :     PoDoFo::charbuff str;
    2176             :     try
    2177             :     {
    2178             :         PoDoFo::StringStreamDevice stream(str);
    2179             : #ifdef USE_HACK_BECAUSE_PdfInputStream_constructor_is_not_exported_in_podofo_0_11
    2180             :         auto *poNonConstStream =
    2181             :             const_cast<PoDoFo::PdfObjectStream *>(m_pStream);
    2182             :         auto inputStream = poNonConstStream->GetProvider().GetInputStream(
    2183             :             poNonConstStream->GetParent());
    2184             :         inputStream->CopyTo(stream);
    2185             : #else
    2186             :         // Should work but fails to link because PdfInputStream destructor
    2187             :         // is not exported
    2188             :         auto inputStream = m_pStream->GetInputStream(/*raw=*/true);
    2189             :         inputStream.CopyTo(stream);
    2190             : #endif
    2191             :         stream.Flush();
    2192             :     }
    2193             :     catch (PoDoFo::PdfError &e)
    2194             :     {
    2195             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2196             :                  e.what());
    2197             :         return nullptr;
    2198             :     }
    2199             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2200             :     if (!pszContent)
    2201             :     {
    2202             :         return nullptr;
    2203             :     }
    2204             :     memcpy(pszContent, str.data(), str.size());
    2205             :     pszContent[str.size()] = '\0';
    2206             :     return pszContent;
    2207             : #else
    2208             :     char *pBuffer = nullptr;
    2209             :     PoDoFo::pdf_long nLen = 0;
    2210             :     try
    2211             :     {
    2212             :         m_pStream->GetCopy(&pBuffer, &nLen);
    2213             :     }
    2214             :     catch (PoDoFo::PdfError &e)
    2215             :     {
    2216             :         return nullptr;
    2217             :     }
    2218             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2219             :     if (!pszContent)
    2220             :     {
    2221             :         PoDoFo::podofo_free(pBuffer);
    2222             :         return nullptr;
    2223             :     }
    2224             :     memcpy(pszContent, pBuffer, nLen);
    2225             :     PoDoFo::podofo_free(pBuffer);
    2226             :     pszContent[nLen] = '\0';
    2227             :     return pszContent;
    2228             : #endif
    2229             : }
    2230             : 
    2231             : #endif  // HAVE_PODOFO
    2232             : 
    2233             : #ifdef HAVE_PDFIUM
    2234             : 
    2235             : /************************************************************************/
    2236             : /* ==================================================================== */
    2237             : /*                         GDALPDFDictionaryPdfium                      */
    2238             : /* ==================================================================== */
    2239             : /************************************************************************/
    2240             : 
    2241             : class GDALPDFDictionaryPdfium final : public GDALPDFDictionary
    2242             : {
    2243             :   private:
    2244             :     RetainPtr<const CPDF_Dictionary> m_poDict;
    2245             :     std::map<CPLString, GDALPDFObject *> m_map{};
    2246             : 
    2247             :   public:
    2248             :     GDALPDFDictionaryPdfium(RetainPtr<const CPDF_Dictionary> poDict)
    2249             :         : m_poDict(std::move(poDict))
    2250             :     {
    2251             :     }
    2252             : 
    2253             :     ~GDALPDFDictionaryPdfium() override;
    2254             : 
    2255             :     GDALPDFObject *Get(const char *pszKey) override;
    2256             :     std::map<CPLString, GDALPDFObject *> &GetValues() override;
    2257             : };
    2258             : 
    2259             : /************************************************************************/
    2260             : /* ==================================================================== */
    2261             : /*                           GDALPDFArrayPdfium                         */
    2262             : /* ==================================================================== */
    2263             : /************************************************************************/
    2264             : 
    2265             : class GDALPDFArrayPdfium final : public GDALPDFArray
    2266             : {
    2267             :   private:
    2268             :     const CPDF_Array *m_poArray;
    2269             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    2270             : 
    2271             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPdfium)
    2272             : 
    2273             :   public:
    2274             :     GDALPDFArrayPdfium(const CPDF_Array *poArray) : m_poArray(poArray)
    2275             :     {
    2276             :     }
    2277             : 
    2278             :     int GetLength() override;
    2279             :     GDALPDFObject *Get(int nIndex) override;
    2280             : };
    2281             : 
    2282             : /************************************************************************/
    2283             : /* ==================================================================== */
    2284             : /*                          GDALPDFStreamPdfium                         */
    2285             : /* ==================================================================== */
    2286             : /************************************************************************/
    2287             : 
    2288             : class GDALPDFStreamPdfium final : public GDALPDFStream
    2289             : {
    2290             :   private:
    2291             :     RetainPtr<const CPDF_Stream> m_pStream;
    2292             :     int64_t m_nSize = 0;
    2293             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pData = nullptr;
    2294             :     int64_t m_nRawSize = 0;
    2295             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pRawData = nullptr;
    2296             : 
    2297             :     void Decompress();
    2298             :     void FillRaw();
    2299             : 
    2300             :   public:
    2301             :     GDALPDFStreamPdfium(RetainPtr<const CPDF_Stream> pStream)
    2302             :         : m_pStream(std::move(pStream))
    2303             :     {
    2304             :     }
    2305             : 
    2306             :     int64_t GetLength(int64_t nMaxSize = 0) override;
    2307             :     char *GetBytes() override;
    2308             : 
    2309             :     int64_t GetRawLength() override;
    2310             :     char *GetRawBytes() override;
    2311             : };
    2312             : 
    2313             : /************************************************************************/
    2314             : /* ==================================================================== */
    2315             : /*                          GDALPDFObjectPdfium                         */
    2316             : /* ==================================================================== */
    2317             : /************************************************************************/
    2318             : 
    2319             : /************************************************************************/
    2320             : /*                        GDALPDFObjectPdfium()                         */
    2321             : /************************************************************************/
    2322             : 
    2323             : GDALPDFObjectPdfium::GDALPDFObjectPdfium(RetainPtr<const CPDF_Object> obj)
    2324             :     : m_obj(std::move(obj))
    2325             : {
    2326             :     CPLAssert(m_obj != nullptr);
    2327             : }
    2328             : 
    2329             : /************************************************************************/
    2330             : /*                        ~GDALPDFObjectPdfium()                        */
    2331             : /************************************************************************/
    2332             : 
    2333             : GDALPDFObjectPdfium::~GDALPDFObjectPdfium()
    2334             : {
    2335             :     delete m_poDict;
    2336             :     delete m_poArray;
    2337             :     delete m_poStream;
    2338             : }
    2339             : 
    2340             : /************************************************************************/
    2341             : /*                               Build()                                */
    2342             : /************************************************************************/
    2343             : 
    2344             : GDALPDFObjectPdfium *
    2345             : GDALPDFObjectPdfium::Build(RetainPtr<const CPDF_Object> obj)
    2346             : {
    2347             :     if (obj == nullptr)
    2348             :         return nullptr;
    2349             :     if (obj->GetType() == CPDF_Object::Type::kReference)
    2350             :     {
    2351             :         obj = obj->GetDirect();
    2352             :         if (obj == nullptr)
    2353             :         {
    2354             :             CPLError(CE_Failure, CPLE_AppDefined,
    2355             :                      "Cannot resolve indirect object");
    2356             :             return nullptr;
    2357             :         }
    2358             :     }
    2359             :     return new GDALPDFObjectPdfium(std::move(obj));
    2360             : }
    2361             : 
    2362             : /************************************************************************/
    2363             : /*                              GetType()                               */
    2364             : /************************************************************************/
    2365             : 
    2366             : GDALPDFObjectType GDALPDFObjectPdfium::GetType()
    2367             : {
    2368             :     switch (m_obj->GetType())
    2369             :     {
    2370             :         case CPDF_Object::Type::kNullobj:
    2371             :             return PDFObjectType_Null;
    2372             :         case CPDF_Object::Type::kBoolean:
    2373             :             return PDFObjectType_Bool;
    2374             :         case CPDF_Object::Type::kNumber:
    2375             :             return (cpl::down_cast<const CPDF_Number *>(m_obj.Get()))
    2376             :                            ->IsInteger()
    2377             :                        ? PDFObjectType_Int
    2378             :                        : PDFObjectType_Real;
    2379             :         case CPDF_Object::Type::kString:
    2380             :             return PDFObjectType_String;
    2381             :         case CPDF_Object::Type::kName:
    2382             :             return PDFObjectType_Name;
    2383             :         case CPDF_Object::Type::kArray:
    2384             :             return PDFObjectType_Array;
    2385             :         case CPDF_Object::Type::kDictionary:
    2386             :             return PDFObjectType_Dictionary;
    2387             :         case CPDF_Object::Type::kStream:
    2388             :             return PDFObjectType_Dictionary;
    2389             :         case CPDF_Object::Type::kReference:
    2390             :             // unresolved reference
    2391             :             return PDFObjectType_Unknown;
    2392             :         default:
    2393             :             CPLAssert(false);
    2394             :             return PDFObjectType_Unknown;
    2395             :     }
    2396             : }
    2397             : 
    2398             : /************************************************************************/
    2399             : /*                         GetTypeNameNative()                          */
    2400             : /************************************************************************/
    2401             : 
    2402             : const char *GDALPDFObjectPdfium::GetTypeNameNative()
    2403             : {
    2404             :     if (m_obj->GetType() == CPDF_Object::Type::kStream)
    2405             :         return "stream";
    2406             :     else
    2407             :         return "";
    2408             : }
    2409             : 
    2410             : /************************************************************************/
    2411             : /*                              GetBool()                               */
    2412             : /************************************************************************/
    2413             : 
    2414             : int GDALPDFObjectPdfium::GetBool()
    2415             : {
    2416             :     return m_obj->GetInteger();
    2417             : }
    2418             : 
    2419             : /************************************************************************/
    2420             : /*                               GetInt()                               */
    2421             : /************************************************************************/
    2422             : 
    2423             : int GDALPDFObjectPdfium::GetInt()
    2424             : {
    2425             :     return m_obj->GetInteger();
    2426             : }
    2427             : 
    2428             : /************************************************************************/
    2429             : /*                     CPLRoundToMoreLikelyDouble()                     */
    2430             : /************************************************************************/
    2431             : 
    2432             : // We try to compensate for rounding errors when converting the number
    2433             : // in the PDF expressed as a string (e.g 297.84) to float32 by pdfium :
    2434             : // 297.8399963378906 Which is technically correct per the PDF spec, but in
    2435             : // practice poppler or podofo use double and Geospatial PDF are often encoded
    2436             : // with double precision.
    2437             : 
    2438             : static double CPLRoundToMoreLikelyDouble(float f)
    2439             : {
    2440             :     if (std::round(f) == f)
    2441             :         return f;
    2442             : 
    2443             :     char szBuffer[80];
    2444             :     CPLsnprintf(szBuffer, 80, "%f\n", f);
    2445             :     double d = f;
    2446             :     char *pszDot = strchr(szBuffer, '.');
    2447             :     if (pszDot == nullptr)
    2448             :         return d;
    2449             :     pszDot++;
    2450             :     if (pszDot[0] == 0 || pszDot[1] == 0)
    2451             :         return d;
    2452             :     if (STARTS_WITH(pszDot + 2, "99"))
    2453             :     {
    2454             :         pszDot[2] = 0;
    2455             :         double d2 = CPLAtof(szBuffer) + 0.01;
    2456             :         float f2 = static_cast<float>(d2);
    2457             :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2458             :             nextafterf(f, f - 1.0f) == f2)
    2459             :             d = d2;
    2460             :     }
    2461             :     else if (STARTS_WITH(pszDot + 2, "00"))
    2462             :     {
    2463             :         pszDot[2] = 0;
    2464             :         double d2 = CPLAtof(szBuffer);
    2465             :         float f2 = static_cast<float>(d2);
    2466             :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2467             :             nextafterf(f, f - 1.0f) == f2)
    2468             :             d = d2;
    2469             :     }
    2470             :     return d;
    2471             : }
    2472             : 
    2473             : /************************************************************************/
    2474             : /*                              GetReal()                               */
    2475             : /************************************************************************/
    2476             : 
    2477             : double GDALPDFObjectPdfium::GetReal()
    2478             : {
    2479             :     return CPLRoundToMoreLikelyDouble(m_obj->GetNumber());
    2480             : }
    2481             : 
    2482             : /************************************************************************/
    2483             : /*                             GetString()                              */
    2484             : /************************************************************************/
    2485             : 
    2486             : const std::string &GDALPDFObjectPdfium::GetString()
    2487             : {
    2488             :     if (GetType() == PDFObjectType_String)
    2489             :     {
    2490             :         const auto bs = m_obj->GetString();
    2491             :         // If empty string, code crashes
    2492             :         if (bs.IsEmpty())
    2493             :             return (osStr = "");
    2494             :         return (osStr = GDALPDFGetUTF8StringFromBytes(
    2495             :                     reinterpret_cast<const GByte *>(bs.c_str()),
    2496             :                     static_cast<int>(bs.GetLength())));
    2497             :     }
    2498             :     else
    2499             :         return (osStr = "");
    2500             : }
    2501             : 
    2502             : /************************************************************************/
    2503             : /*                              GetName()                               */
    2504             : /************************************************************************/
    2505             : 
    2506             : const std::string &GDALPDFObjectPdfium::GetName()
    2507             : {
    2508             :     if (GetType() == PDFObjectType_Name)
    2509             :         return (osStr = m_obj->GetString().c_str());
    2510             :     else
    2511             :         return (osStr = "");
    2512             : }
    2513             : 
    2514             : /************************************************************************/
    2515             : /*                           GetDictionary()                            */
    2516             : /************************************************************************/
    2517             : 
    2518             : GDALPDFDictionary *GDALPDFObjectPdfium::GetDictionary()
    2519             : {
    2520             :     if (GetType() != PDFObjectType_Dictionary)
    2521             :         return nullptr;
    2522             : 
    2523             :     if (m_poDict)
    2524             :         return m_poDict;
    2525             : 
    2526             :     m_poDict = new GDALPDFDictionaryPdfium(m_obj->GetDict());
    2527             :     return m_poDict;
    2528             : }
    2529             : 
    2530             : /************************************************************************/
    2531             : /*                              GetArray()                              */
    2532             : /************************************************************************/
    2533             : 
    2534             : GDALPDFArray *GDALPDFObjectPdfium::GetArray()
    2535             : {
    2536             :     if (GetType() != PDFObjectType_Array)
    2537             :         return nullptr;
    2538             : 
    2539             :     if (m_poArray)
    2540             :         return m_poArray;
    2541             : 
    2542             :     m_poArray =
    2543             :         new GDALPDFArrayPdfium(cpl::down_cast<const CPDF_Array *>(m_obj.Get()));
    2544             :     return m_poArray;
    2545             : }
    2546             : 
    2547             : /************************************************************************/
    2548             : /*                             GetStream()                              */
    2549             : /************************************************************************/
    2550             : 
    2551             : GDALPDFStream *GDALPDFObjectPdfium::GetStream()
    2552             : {
    2553             :     if (m_obj->GetType() != CPDF_Object::Type::kStream)
    2554             :         return nullptr;
    2555             : 
    2556             :     if (m_poStream)
    2557             :         return m_poStream;
    2558             :     auto pStream = pdfium::WrapRetain(m_obj->AsStream());
    2559             :     if (pStream)
    2560             :     {
    2561             :         m_poStream = new GDALPDFStreamPdfium(std::move(pStream));
    2562             :         return m_poStream;
    2563             :     }
    2564             :     else
    2565             :         return nullptr;
    2566             : }
    2567             : 
    2568             : /************************************************************************/
    2569             : /*                             GetRefNum()                              */
    2570             : /************************************************************************/
    2571             : 
    2572             : GDALPDFObjectNum GDALPDFObjectPdfium::GetRefNum()
    2573             : {
    2574             :     return GDALPDFObjectNum(m_obj->GetObjNum());
    2575             : }
    2576             : 
    2577             : /************************************************************************/
    2578             : /*                             GetRefGen()                              */
    2579             : /************************************************************************/
    2580             : 
    2581             : int GDALPDFObjectPdfium::GetRefGen()
    2582             : {
    2583             :     return m_obj->GetGenNum();
    2584             : }
    2585             : 
    2586             : /************************************************************************/
    2587             : /* ==================================================================== */
    2588             : /*                         GDALPDFDictionaryPdfium                      */
    2589             : /* ==================================================================== */
    2590             : /************************************************************************/
    2591             : 
    2592             : /************************************************************************/
    2593             : /*                      ~GDALPDFDictionaryPdfium()                      */
    2594             : /************************************************************************/
    2595             : 
    2596             : GDALPDFDictionaryPdfium::~GDALPDFDictionaryPdfium()
    2597             : {
    2598             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    2599             :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    2600             :     for (; oIter != oEnd; ++oIter)
    2601             :         delete oIter->second;
    2602             : }
    2603             : 
    2604             : /************************************************************************/
    2605             : /*                                Get()                                 */
    2606             : /************************************************************************/
    2607             : 
    2608             : GDALPDFObject *GDALPDFDictionaryPdfium::Get(const char *pszKey)
    2609             : {
    2610             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    2611             :     if (oIter != m_map.end())
    2612             :         return oIter->second;
    2613             : 
    2614             :     ByteStringView pdfiumKey(pszKey);
    2615             :     GDALPDFObjectPdfium *poObj =
    2616             :         GDALPDFObjectPdfium::Build(m_poDict->GetObjectFor(pdfiumKey));
    2617             :     if (poObj)
    2618             :     {
    2619             :         m_map[pszKey] = poObj;
    2620             :         return poObj;
    2621             :     }
    2622             :     else
    2623             :     {
    2624             :         return nullptr;
    2625             :     }
    2626             : }
    2627             : 
    2628             : /************************************************************************/
    2629             : /*                             GetValues()                              */
    2630             : /************************************************************************/
    2631             : 
    2632             : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPdfium::GetValues()
    2633             : {
    2634             :     CPDF_DictionaryLocker dictIterator(m_poDict);
    2635             :     for (const auto &iter : dictIterator)
    2636             :     {
    2637             :         // No object for this key
    2638             :         if (!iter.second)
    2639             :             continue;
    2640             : 
    2641             :         const char *pszKey = iter.first.c_str();
    2642             :         // Objects exists in the map
    2643             :         if (m_map.find(pszKey) != m_map.end())
    2644             :             continue;
    2645             :         GDALPDFObjectPdfium *poObj = GDALPDFObjectPdfium::Build(iter.second);
    2646             :         if (poObj == nullptr)
    2647             :             continue;
    2648             :         m_map[pszKey] = poObj;
    2649             :     }
    2650             : 
    2651             :     return m_map;
    2652             : }
    2653             : 
    2654             : /************************************************************************/
    2655             : /* ==================================================================== */
    2656             : /*                           GDALPDFArrayPdfium                         */
    2657             : /* ==================================================================== */
    2658             : /************************************************************************/
    2659             : 
    2660             : /************************************************************************/
    2661             : /*                             GetLength()                              */
    2662             : /************************************************************************/
    2663             : 
    2664             : int GDALPDFArrayPdfium::GetLength()
    2665             : {
    2666             :     return static_cast<int>(m_poArray->size());
    2667             : }
    2668             : 
    2669             : /************************************************************************/
    2670             : /*                                Get()                                 */
    2671             : /************************************************************************/
    2672             : 
    2673             : GDALPDFObject *GDALPDFArrayPdfium::Get(int nIndex)
    2674             : {
    2675             :     if (nIndex < 0 || nIndex >= GetLength())
    2676             :         return nullptr;
    2677             : 
    2678             :     if (m_v.empty())
    2679             :         m_v.resize(GetLength());
    2680             : 
    2681             :     if (m_v[nIndex] != nullptr)
    2682             :         return m_v[nIndex].get();
    2683             : 
    2684             :     auto poObj = std::unique_ptr<GDALPDFObjectPdfium>(
    2685             :         GDALPDFObjectPdfium::Build(m_poArray->GetObjectAt(nIndex)));
    2686             :     if (poObj == nullptr)
    2687             :         return nullptr;
    2688             :     m_v[nIndex] = std::move(poObj);
    2689             :     return m_v[nIndex].get();
    2690             : }
    2691             : 
    2692             : /************************************************************************/
    2693             : /* ==================================================================== */
    2694             : /*                           GDALPDFStreamPdfium                        */
    2695             : /* ==================================================================== */
    2696             : /************************************************************************/
    2697             : 
    2698             : void GDALPDFStreamPdfium::Decompress()
    2699             : {
    2700             :     if (m_pData != nullptr)
    2701             :         return;
    2702             :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2703             :     acc->LoadAllDataFiltered();
    2704             :     m_nSize = static_cast<int64_t>(acc->GetSize());
    2705             :     m_pData.reset();
    2706             :     const auto nSize = static_cast<size_t>(m_nSize);
    2707             :     if (static_cast<int64_t>(nSize) != m_nSize)
    2708             :     {
    2709             :         m_nSize = 0;
    2710             :     }
    2711             :     if (m_nSize)
    2712             :     {
    2713             :         m_pData.reset(static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(nSize)));
    2714             :         if (!m_pData)
    2715             :             m_nSize = 0;
    2716             :         else
    2717             :             memcpy(&m_pData.get()[0], acc->DetachData().data(), nSize);
    2718             :     }
    2719             : }
    2720             : 
    2721             : /************************************************************************/
    2722             : /*                             GetLength()                              */
    2723             : /************************************************************************/
    2724             : 
    2725             : int64_t GDALPDFStreamPdfium::GetLength(int64_t /* nMaxSize */)
    2726             : {
    2727             :     Decompress();
    2728             :     return m_nSize;
    2729             : }
    2730             : 
    2731             : /************************************************************************/
    2732             : /*                              GetBytes()                              */
    2733             : /************************************************************************/
    2734             : 
    2735             : char *GDALPDFStreamPdfium::GetBytes()
    2736             : {
    2737             :     size_t nLength = static_cast<size_t>(GetLength());
    2738             :     if (nLength == 0)
    2739             :         return nullptr;
    2740             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    2741             :     if (!pszContent)
    2742             :         return nullptr;
    2743             :     memcpy(pszContent, m_pData.get(), nLength);
    2744             :     pszContent[nLength] = '\0';
    2745             :     return pszContent;
    2746             : }
    2747             : 
    2748             : /************************************************************************/
    2749             : /*                              FillRaw()                               */
    2750             : /************************************************************************/
    2751             : 
    2752             : void GDALPDFStreamPdfium::FillRaw()
    2753             : {
    2754             :     if (m_pRawData != nullptr)
    2755             :         return;
    2756             :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2757             :     acc->LoadAllDataRaw();
    2758             :     m_nRawSize = static_cast<int64_t>(acc->GetSize());
    2759             :     m_pRawData.reset();
    2760             :     const auto nSize = static_cast<size_t>(m_nRawSize);
    2761             :     if (static_cast<int64_t>(nSize) != m_nRawSize)
    2762             :     {
    2763             :         m_nRawSize = 0;
    2764             :     }
    2765             :     if (m_nRawSize)
    2766             :     {
    2767             :         m_pRawData.reset(
    2768             :             static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(m_nRawSize)));
    2769             :         if (!m_pRawData)
    2770             :             m_nRawSize = 0;
    2771             :         else
    2772             :             memcpy(&m_pRawData.get()[0], acc->DetachData().data(), m_nRawSize);
    2773             :     }
    2774             : }
    2775             : 
    2776             : /************************************************************************/
    2777             : /*                            GetRawLength()                            */
    2778             : /************************************************************************/
    2779             : 
    2780             : int64_t GDALPDFStreamPdfium::GetRawLength()
    2781             : {
    2782             :     FillRaw();
    2783             :     return m_nRawSize;
    2784             : }
    2785             : 
    2786             : /************************************************************************/
    2787             : /*                            GetRawBytes()                             */
    2788             : /************************************************************************/
    2789             : 
    2790             : char *GDALPDFStreamPdfium::GetRawBytes()
    2791             : {
    2792             :     size_t nLength = static_cast<size_t>(GetRawLength());
    2793             :     if (nLength == 0)
    2794             :         return nullptr;
    2795             :     char *pszContent =
    2796             :         static_cast<char *>(VSI_MALLOC_VERBOSE(sizeof(char) * (nLength + 1)));
    2797             :     if (!pszContent)
    2798             :         return nullptr;
    2799             :     memcpy(pszContent, m_pRawData.get(), nLength);
    2800             :     pszContent[nLength] = '\0';
    2801             :     return pszContent;
    2802             : }
    2803             : 
    2804             : #endif  // HAVE_PDFIUM

Generated by: LCOV version 1.14