LCOV - code coverage report
Current view: top level - frmts/pdf - pdfobject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 679 827 82.1 %
Date: 2025-03-29 15:49:56 Functions: 109 119 91.6 %

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

Generated by: LCOV version 1.14