LCOV - code coverage report
Current view: top level - frmts/pdf - pdfobject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 684 827 82.7 %
Date: 2024-11-21 22:18:42 Functions: 110 119 92.4 %

          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        8419 : double ROUND_IF_CLOSE(double x, double eps)
      31             : {
      32        8419 :     if (eps == 0.0)
      33        6013 :         eps = fabs(x) < 1 ? 1e-10 : 1e-8;
      34        8419 :     const double dfRounded = std::round(x);
      35        8419 :     if (fabs(x - dfRounded) < eps)
      36        5488 :         return dfRounded;
      37             :     else
      38        2931 :         return x;
      39             : }
      40             : 
      41             : /************************************************************************/
      42             : /*                         GDALPDFGetPDFString()                        */
      43             : /************************************************************************/
      44             : 
      45         860 : static CPLString GDALPDFGetPDFString(const char *pszStr)
      46             : {
      47         860 :     const GByte *pabyData = reinterpret_cast<const GByte *>(pszStr);
      48             :     GByte ch;
      49       39010 :     for (size_t i = 0; (ch = pabyData[i]) != '\0'; i++)
      50             :     {
      51       38163 :         if (ch < 32 || ch > 127 || ch == '(' || ch == ')' || ch == '\\' ||
      52       38150 :             ch == '%' || ch == '#')
      53             :             break;
      54             :     }
      55         860 :     CPLString osStr;
      56         860 :     if (ch == 0)
      57             :     {
      58         847 :         osStr = "(";
      59         847 :         osStr += pszStr;
      60         847 :         osStr += ")";
      61         847 :         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        1813 : static std::string GDALPDFGetUTF8StringFromBytes(const GByte *pabySrc,
     100             :                                                  size_t nLen)
     101             : {
     102        1813 :     const bool bLEUnicodeMarker =
     103        1813 :         nLen >= 2 && pabySrc[0] == 0xFE && pabySrc[1] == 0xFF;
     104        1813 :     const bool bBEUnicodeMarker =
     105        1813 :         nLen >= 2 && pabySrc[0] == 0xFF && pabySrc[1] == 0xFE;
     106        1813 :     if (!bLEUnicodeMarker && !bBEUnicodeMarker)
     107             :     {
     108        2408 :         std::string osStr;
     109             :         try
     110             :         {
     111        1204 :             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        1204 :         osStr.assign(reinterpret_cast<const char *>(pabySrc), nLen);
     120        1204 :         const char *pszStr = osStr.c_str();
     121        1204 :         if (CPLIsUTF8(pszStr, -1))
     122        1204 :             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        3338 : static std::string GDALPDFGetPDFName(const std::string &osStr)
     186             : {
     187        3338 :     std::string osRet;
     188       28299 :     for (const char ch : osStr)
     189             :     {
     190       24961 :         if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
     191          19 :               (ch >= '0' && ch <= '9') || ch == '-'))
     192           0 :             osRet += '_';
     193             :         else
     194       24961 :             osRet += ch;
     195             :     }
     196        3338 :     return osRet;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /* ==================================================================== */
     201             : /*                            GDALPDFObject                             */
     202             : /* ==================================================================== */
     203             : /************************************************************************/
     204             : 
     205             : /************************************************************************/
     206             : /*                            ~GDALPDFObject()                          */
     207             : /************************************************************************/
     208             : 
     209       45756 : GDALPDFObject::~GDALPDFObject()
     210             : {
     211       45756 : }
     212             : 
     213             : /************************************************************************/
     214             : /*                            LookupObject()                            */
     215             : /************************************************************************/
     216             : 
     217        2792 : GDALPDFObject *GDALPDFObject::LookupObject(const char *pszPath)
     218             : {
     219        2792 :     if (GetType() != PDFObjectType_Dictionary)
     220           0 :         return nullptr;
     221        2792 :     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       16658 : void GDALPDFObject::Serialize(CPLString &osStr, bool bEmitRef)
     260             : {
     261       16658 :     auto nRefNum = GetRefNum();
     262       16658 :     if (bEmitRef && nRefNum.toBool())
     263             :     {
     264        3163 :         int nRefGen = GetRefGen();
     265        3163 :         osStr.append(CPLSPrintf("%d %d R", nRefNum.toInt(), nRefGen));
     266        3163 :         return;
     267             :     }
     268             : 
     269       13495 :     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        3903 :         case PDFObjectType_Int:
     278        3903 :             osStr.append(CPLSPrintf("%d", GetInt()));
     279        3903 :             return;
     280        2901 :         case PDFObjectType_Real:
     281             :         {
     282             :             char szReal[512];
     283        2901 :             double dfRealNonRounded = GetReal();
     284        2901 :             double dfReal = ROUND_IF_CLOSE(dfRealNonRounded);
     285        2901 :             if (dfReal >=
     286        2901 :                     static_cast<double>(std::numeric_limits<GIntBig>::min()) &&
     287             :                 dfReal <=
     288        5802 :                     static_cast<double>(std::numeric_limits<GIntBig>::max()) &&
     289        2901 :                 dfReal == static_cast<double>(static_cast<GIntBig>(dfReal)))
     290             :             {
     291        2036 :                 snprintf(szReal, sizeof(szReal), CPL_FRMT_GIB,
     292             :                          static_cast<GIntBig>(dfReal));
     293             :             }
     294         865 :             else if (CanRepresentRealAsString())
     295             :             {
     296             :                 /* Used for OGC BP numeric values */
     297          78 :                 CPLsnprintf(szReal, sizeof(szReal), "(%.*g)", GetPrecision(),
     298             :                             dfReal);
     299             :             }
     300             :             else
     301             :             {
     302         787 :                 CPLsnprintf(szReal, sizeof(szReal), "%.*f", GetPrecision(),
     303             :                             dfReal);
     304             : 
     305             :                 /* Remove non significant trailing zeroes */
     306         787 :                 char *pszDot = strchr(szReal, '.');
     307         787 :                 if (pszDot)
     308             :                 {
     309         787 :                     int iDot = static_cast<int>(pszDot - szReal);
     310         787 :                     int nLen = static_cast<int>(strlen(szReal));
     311        2997 :                     for (int i = nLen - 1; i > iDot; i--)
     312             :                     {
     313        2997 :                         if (szReal[i] == '0')
     314        2210 :                             szReal[i] = '\0';
     315             :                         else
     316         787 :                             break;
     317             :                     }
     318             :                 }
     319             :             }
     320        2901 :             osStr.append(szReal);
     321        2901 :             return;
     322             :         }
     323         860 :         case PDFObjectType_String:
     324         860 :             osStr.append(GDALPDFGetPDFString(GetString().c_str()));
     325         860 :             return;
     326        3338 :         case PDFObjectType_Name:
     327        3338 :             osStr.append("/");
     328        3338 :             osStr.append(GDALPDFGetPDFName(GetName()));
     329        3338 :             return;
     330        1257 :         case PDFObjectType_Array:
     331        1257 :             GetArray()->Serialize(osStr);
     332        1257 :             return;
     333        1198 :         case PDFObjectType_Dictionary:
     334        1198 :             GetDictionary()->Serialize(osStr);
     335        1198 :             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         332 : GDALPDFObjectRW *GDALPDFObject::Clone()
     349             : {
     350         332 :     auto nRefNum = GetRefNum();
     351         332 :     if (nRefNum.toBool())
     352             :     {
     353         134 :         int nRefGen = GetRefGen();
     354         134 :         return GDALPDFObjectRW::CreateIndirect(nRefNum, nRefGen);
     355             :     }
     356             : 
     357         198 :     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         106 :         case PDFObjectType_Int:
     364         106 :             return GDALPDFObjectRW::CreateInt(GetInt());
     365          16 :         case PDFObjectType_Real:
     366          16 :             return GDALPDFObjectRW::CreateReal(GetReal());
     367           0 :         case PDFObjectType_String:
     368           0 :             return GDALPDFObjectRW::CreateString(GetString().c_str());
     369          32 :         case PDFObjectType_Name:
     370          32 :             return GDALPDFObjectRW::CreateName(GetName().c_str());
     371          44 :         case PDFObjectType_Array:
     372          44 :             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       11898 : GDALPDFDictionary::~GDALPDFDictionary()
     393             : {
     394       11898 : }
     395             : 
     396             : /************************************************************************/
     397             : /*                            LookupObject()                            */
     398             : /************************************************************************/
     399             : 
     400        3707 : GDALPDFObject *GDALPDFDictionary::LookupObject(const char *pszPath)
     401             : {
     402        3707 :     GDALPDFObject *poCurObj = nullptr;
     403        3707 :     char **papszTokens = CSLTokenizeString2(pszPath, ".", 0);
     404        8529 :     for (int i = 0; papszTokens[i] != nullptr; i++)
     405             :     {
     406        6460 :         int iElt = -1;
     407        6460 :         char *pszBracket = strchr(papszTokens[i], '[');
     408        6460 :         if (pszBracket != nullptr)
     409             :         {
     410           0 :             iElt = atoi(pszBracket + 1);
     411           0 :             *pszBracket = '\0';
     412             :         }
     413             : 
     414        6460 :         if (i == 0)
     415             :         {
     416        3707 :             poCurObj = Get(papszTokens[i]);
     417             :         }
     418             :         else
     419             :         {
     420        2753 :             if (poCurObj->GetType() != PDFObjectType_Dictionary)
     421             :             {
     422           0 :                 poCurObj = nullptr;
     423           0 :                 break;
     424             :             }
     425        2753 :             poCurObj = poCurObj->GetDictionary()->Get(papszTokens[i]);
     426             :         }
     427             : 
     428        6460 :         if (poCurObj == nullptr)
     429             :         {
     430        1638 :             poCurObj = nullptr;
     431        1638 :             break;
     432             :         }
     433             : 
     434        4822 :         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        3707 :     CSLDestroy(papszTokens);
     445        3707 :     return poCurObj;
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                             Serialize()                              */
     450             : /************************************************************************/
     451             : 
     452        3175 : void GDALPDFDictionary::Serialize(CPLString &osStr)
     453             : {
     454        3175 :     osStr.append("<< ");
     455       14022 :     for (const auto &oIter : GetValues())
     456             :     {
     457       10847 :         const char *pszKey = oIter.first.c_str();
     458       10847 :         GDALPDFObject *poObj = oIter.second;
     459       10847 :         osStr.append("/");
     460       10847 :         osStr.append(pszKey);
     461       10847 :         osStr.append(" ");
     462       10847 :         poObj->Serialize(osStr);
     463       10847 :         osStr.append(" ");
     464             :     }
     465        3175 :     osStr.append(">>");
     466        3175 : }
     467             : 
     468             : /************************************************************************/
     469             : /*                               Clone()                                */
     470             : /************************************************************************/
     471             : 
     472          32 : GDALPDFDictionaryRW *GDALPDFDictionary::Clone()
     473             : {
     474          32 :     GDALPDFDictionaryRW *poDict = new GDALPDFDictionaryRW();
     475         242 :     for (const auto &oIter : GetValues())
     476             :     {
     477         210 :         const char *pszKey = oIter.first.c_str();
     478         210 :         GDALPDFObject *poObj = oIter.second;
     479         210 :         poDict->Add(pszKey, poObj->Clone());
     480             :     }
     481          32 :     return poDict;
     482             : }
     483             : 
     484             : /************************************************************************/
     485             : /* ==================================================================== */
     486             : /*                           GDALPDFArray                               */
     487             : /* ==================================================================== */
     488             : /************************************************************************/
     489             : 
     490             : /************************************************************************/
     491             : /*                           ~GDALPDFArray()                            */
     492             : /************************************************************************/
     493             : 
     494        3826 : GDALPDFArray::~GDALPDFArray()
     495             : {
     496        3826 : }
     497             : 
     498             : /************************************************************************/
     499             : /*                             Serialize()                              */
     500             : /************************************************************************/
     501             : 
     502        1385 : void GDALPDFArray::Serialize(CPLString &osStr)
     503             : {
     504        1385 :     int nLength = GetLength();
     505             :     int i;
     506             : 
     507        1385 :     osStr.append("[ ");
     508        6312 :     for (i = 0; i < nLength; i++)
     509             :     {
     510        4927 :         Get(i)->Serialize(osStr);
     511        4927 :         osStr.append(" ");
     512             :     }
     513        1385 :     osStr.append("]");
     514        1385 : }
     515             : 
     516             : /************************************************************************/
     517             : /*                               Clone()                                */
     518             : /************************************************************************/
     519             : 
     520          44 : GDALPDFArrayRW *GDALPDFArray::Clone()
     521             : {
     522          44 :     GDALPDFArrayRW *poArray = new GDALPDFArrayRW();
     523          44 :     int nLength = GetLength();
     524             :     int i;
     525         166 :     for (i = 0; i < nLength; i++)
     526             :     {
     527         122 :         poArray->Add(Get(i)->Clone());
     528             :     }
     529          44 :     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       16822 : GDALPDFObjectRW::GDALPDFObjectRW(GDALPDFObjectType eType) : m_eType(eType)
     555             : {
     556       16822 : }
     557             : 
     558             : /************************************************************************/
     559             : /*                             ~GDALPDFObjectRW()                       */
     560             : /************************************************************************/
     561             : 
     562       33644 : GDALPDFObjectRW::~GDALPDFObjectRW()
     563             : {
     564       16822 :     delete m_poDict;
     565       16822 :     delete m_poArray;
     566       33644 : }
     567             : 
     568             : /************************************************************************/
     569             : /*                            CreateIndirect()                          */
     570             : /************************************************************************/
     571             : 
     572        3237 : GDALPDFObjectRW *GDALPDFObjectRW::CreateIndirect(const GDALPDFObjectNum &nNum,
     573             :                                                  int nGen)
     574             : {
     575        3237 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Unknown);
     576        3237 :     poObj->m_nNum = nNum;
     577        3237 :     poObj->m_nGen = nGen;
     578        3237 :     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        3951 : GDALPDFObjectRW *GDALPDFObjectRW::CreateInt(int nVal)
     606             : {
     607        3951 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Int);
     608        3951 :     poObj->m_nVal = nVal;
     609        3951 :     return poObj;
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                            CreateReal()                              */
     614             : /************************************************************************/
     615             : 
     616        2841 : GDALPDFObjectRW *GDALPDFObjectRW::CreateReal(double dfVal,
     617             :                                              int bCanRepresentRealAsString)
     618             : {
     619        2841 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Real);
     620        2841 :     poObj->m_dfVal = dfVal;
     621        2841 :     poObj->m_bCanRepresentRealAsString = bCanRepresentRealAsString;
     622        2841 :     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         860 : GDALPDFObjectRW *GDALPDFObjectRW::CreateString(const char *pszStr)
     643             : {
     644         860 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_String);
     645         860 :     poObj->m_osVal = pszStr;
     646         860 :     return poObj;
     647             : }
     648             : 
     649             : /************************************************************************/
     650             : /*                            CreateName()                              */
     651             : /************************************************************************/
     652             : 
     653        3342 : GDALPDFObjectRW *GDALPDFObjectRW::CreateName(const char *pszName)
     654             : {
     655        3342 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Name);
     656        3342 :     poObj->m_osVal = pszName;
     657        3342 :     return poObj;
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                          CreateDictionary()                          */
     662             : /************************************************************************/
     663             : 
     664        1200 : GDALPDFObjectRW *GDALPDFObjectRW::CreateDictionary(GDALPDFDictionaryRW *poDict)
     665             : {
     666        1200 :     CPLAssert(poDict);
     667        1200 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Dictionary);
     668        1200 :     poObj->m_poDict = poDict;
     669        1200 :     return poObj;
     670             : }
     671             : 
     672             : /************************************************************************/
     673             : /*                            CreateArray()                             */
     674             : /************************************************************************/
     675             : 
     676        1289 : GDALPDFObjectRW *GDALPDFObjectRW::CreateArray(GDALPDFArrayRW *poArray)
     677             : {
     678        1289 :     CPLAssert(poArray);
     679        1289 :     GDALPDFObjectRW *poObj = new GDALPDFObjectRW(PDFObjectType_Array);
     680        1289 :     poObj->m_poArray = poArray;
     681        1289 :     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       13463 : GDALPDFObjectType GDALPDFObjectRW::GetType()
     699             : {
     700       13463 :     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        3887 : int GDALPDFObjectRW::GetInt()
     720             : {
     721        3887 :     if (m_eType == PDFObjectType_Int)
     722        3887 :         return m_nVal;
     723             : 
     724           0 :     return 0;
     725             : }
     726             : 
     727             : /************************************************************************/
     728             : /*                              GetReal()                               */
     729             : /************************************************************************/
     730             : 
     731        2901 : double GDALPDFObjectRW::GetReal()
     732             : {
     733        2901 :     return m_dfVal;
     734             : }
     735             : 
     736             : /************************************************************************/
     737             : /*                             GetString()                              */
     738             : /************************************************************************/
     739             : 
     740         860 : const CPLString &GDALPDFObjectRW::GetString()
     741             : {
     742         860 :     return m_osVal;
     743             : }
     744             : 
     745             : /************************************************************************/
     746             : /*                              GetName()                               */
     747             : /************************************************************************/
     748             : 
     749        3322 : const CPLString &GDALPDFObjectRW::GetName()
     750             : {
     751        3322 :     return m_osVal;
     752             : }
     753             : 
     754             : /************************************************************************/
     755             : /*                            GetDictionary()                           */
     756             : /************************************************************************/
     757             : 
     758        1198 : GDALPDFDictionary *GDALPDFObjectRW::GetDictionary()
     759             : {
     760        1198 :     return m_poDict;
     761             : }
     762             : 
     763             : /************************************************************************/
     764             : /*                              GetArray()                              */
     765             : /************************************************************************/
     766             : 
     767        1257 : GDALPDFArray *GDALPDFObjectRW::GetArray()
     768             : {
     769        1257 :     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       16630 : GDALPDFObjectNum GDALPDFObjectRW::GetRefNum()
     786             : {
     787       16630 :     return m_nNum;
     788             : }
     789             : 
     790             : /************************************************************************/
     791             : /*                              GetRefGen()                             */
     792             : /************************************************************************/
     793             : 
     794        3167 : int GDALPDFObjectRW::GetRefGen()
     795             : {
     796        3167 :     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        4423 : GDALPDFDictionaryRW::~GDALPDFDictionaryRW()
     816             : {
     817        3191 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
     818        3191 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
     819       14148 :     for (; oIter != oEnd; ++oIter)
     820       10957 :         delete oIter->second;
     821        4423 : }
     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        3175 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryRW::GetValues()
     840             : {
     841        3175 :     return m_map;
     842             : }
     843             : 
     844             : /************************************************************************/
     845             : /*                                 Add()                                */
     846             : /************************************************************************/
     847             : 
     848       10969 : GDALPDFDictionaryRW &GDALPDFDictionaryRW::Add(const char *pszKey,
     849             :                                               GDALPDFObject *poVal)
     850             : {
     851       10969 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
     852       10969 :     if (oIter != m_map.end())
     853             :     {
     854           0 :         delete oIter->second;
     855           0 :         oIter->second = poVal;
     856             :     }
     857             :     else
     858       10969 :         m_map[pszKey] = poVal;
     859             : 
     860       10969 :     return *this;
     861             : }
     862             : 
     863             : /************************************************************************/
     864             : /*                                Remove()                              */
     865             : /************************************************************************/
     866             : 
     867          34 : GDALPDFDictionaryRW &GDALPDFDictionaryRW::Remove(const char *pszKey)
     868             : {
     869          34 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
     870          34 :     if (oIter != m_map.end())
     871             :     {
     872          12 :         delete oIter->second;
     873          12 :         m_map.erase(pszKey);
     874             :     }
     875             : 
     876          34 :     return *this;
     877             : }
     878             : 
     879             : /************************************************************************/
     880             : /* ==================================================================== */
     881             : /*                            GDALPDFArrayRW                            */
     882             : /* ==================================================================== */
     883             : /************************************************************************/
     884             : 
     885             : /************************************************************************/
     886             : /*                             GDALPDFArrayRW()                         */
     887             : /************************************************************************/
     888             : 
     889        1417 : GDALPDFArrayRW::GDALPDFArrayRW()
     890             : {
     891        1417 : }
     892             : 
     893             : /************************************************************************/
     894             : /*                            ~GDALPDFArrayRW()                         */
     895             : /************************************************************************/
     896             : 
     897        2706 : GDALPDFArrayRW::~GDALPDFArrayRW()
     898             : {
     899        6418 :     for (size_t i = 0; i < m_array.size(); i++)
     900        5001 :         delete m_array[i];
     901        2706 : }
     902             : 
     903             : /************************************************************************/
     904             : /*                               GetLength()                             */
     905             : /************************************************************************/
     906             : 
     907        6314 : int GDALPDFArrayRW::GetLength()
     908             : {
     909        6314 :     return static_cast<int>(m_array.size());
     910             : }
     911             : 
     912             : /************************************************************************/
     913             : /*                                  Get()                               */
     914             : /************************************************************************/
     915             : 
     916        4927 : GDALPDFObject *GDALPDFArrayRW::Get(int nIndex)
     917             : {
     918        4927 :     if (nIndex < 0 || nIndex >= GetLength())
     919           0 :         return nullptr;
     920        4927 :     return m_array[nIndex];
     921             : }
     922             : 
     923             : /************************************************************************/
     924             : /*                                  Add()                               */
     925             : /************************************************************************/
     926             : 
     927        4925 : GDALPDFArrayRW &GDALPDFArrayRW::Add(GDALPDFObject *poObj)
     928             : {
     929        4925 :     m_array.push_back(poObj);
     930        4925 :     return *this;
     931             : }
     932             : 
     933             : /************************************************************************/
     934             : /*                                  Add()                               */
     935             : /************************************************************************/
     936             : 
     937          12 : GDALPDFArrayRW &GDALPDFArrayRW::Add(double *padfVal, int nCount,
     938             :                                     int bCanRepresentRealAsString)
     939             : {
     940          88 :     for (int i = 0; i < nCount; i++)
     941         152 :         m_array.push_back(
     942          76 :             GDALPDFObjectRW::CreateReal(padfVal[i], bCanRepresentRealAsString));
     943          12 :     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        3477 :     GDALPDFDictionaryPoppler(Dict *poDict) : m_poDict(poDict)
     964             :     {
     965        3477 :     }
     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             :     Array *m_poArray;
     983             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
     984             : 
     985             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPoppler)
     986             : 
     987             :   public:
     988        1066 :     GDALPDFArrayPoppler(Array *poArray) : m_poArray(poArray)
     989             :     {
     990        1066 :     }
     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         322 :     GDALPDFStreamPoppler(Stream *poStream) : m_poStream(poStream)
    1013             :     {
    1014         322 :     }
    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       24617 : GDALPDFObjectPoppler::~GDALPDFObjectPoppler()
    1034             : {
    1035       12403 :     if (m_bDestroy)
    1036       11836 :         delete m_po;
    1037       12403 :     delete m_poDict;
    1038       12403 :     delete m_poArray;
    1039       12403 :     delete m_poStream;
    1040       24617 : }
    1041             : 
    1042             : /************************************************************************/
    1043             : /*                              GetType()                               */
    1044             : /************************************************************************/
    1045             : 
    1046       51365 : GDALPDFObjectType GDALPDFObjectPoppler::GetType()
    1047             : {
    1048       51365 :     switch (m_po->getType())
    1049             :     {
    1050         158 :         case objNull:
    1051         158 :             return PDFObjectType_Null;
    1052           0 :         case objBool:
    1053           0 :             return PDFObjectType_Bool;
    1054       15285 :         case objInt:
    1055       15285 :             return PDFObjectType_Int;
    1056        4200 :         case objReal:
    1057        4200 :             return PDFObjectType_Real;
    1058        2727 :         case objString:
    1059        2727 :             return PDFObjectType_String;
    1060        5470 :         case objName:
    1061        5470 :             return PDFObjectType_Name;
    1062       11735 :         case objArray:
    1063       11735 :             return PDFObjectType_Array;
    1064        8478 :         case objDict:
    1065        8478 :             return PDFObjectType_Dictionary;
    1066        3312 :         case objStream:
    1067        3312 :             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        4861 : int GDALPDFObjectPoppler::GetInt()
    1099             : {
    1100        4861 :     if (GetType() == PDFObjectType_Int)
    1101        4861 :         return m_po->getInt();
    1102             :     else
    1103           0 :         return 0;
    1104             : }
    1105             : 
    1106             : /************************************************************************/
    1107             : /*                               GetReal()                              */
    1108             : /************************************************************************/
    1109             : 
    1110        1048 : double GDALPDFObjectPoppler::GetReal()
    1111             : {
    1112        1048 :     if (GetType() == PDFObjectType_Real)
    1113        1048 :         return m_po->getReal();
    1114             :     else
    1115           0 :         return 0.0;
    1116             : }
    1117             : 
    1118             : /************************************************************************/
    1119             : /*                              GetString()                             */
    1120             : /************************************************************************/
    1121             : 
    1122        1180 : const std::string &GDALPDFObjectPoppler::GetString()
    1123             : {
    1124        1180 :     if (GetType() == PDFObjectType_String)
    1125             :     {
    1126        1180 :         const GooString *gooString = m_po->getString();
    1127        1180 :         const std::string &osStdStr = gooString->toStr();
    1128             :         const bool bLEUnicodeMarker =
    1129        1317 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFE &&
    1130         137 :             static_cast<uint8_t>(osStdStr[1]) == 0xFF;
    1131             :         const bool bBEUnicodeMarker =
    1132        1234 :             osStdStr.size() >= 2 && static_cast<uint8_t>(osStdStr[0]) == 0xFF &&
    1133          54 :             static_cast<uint8_t>(osStdStr[1]) == 0xFE;
    1134        1180 :         if (!bLEUnicodeMarker && !bBEUnicodeMarker)
    1135             :         {
    1136         989 :             if (CPLIsUTF8(osStdStr.c_str(), -1))
    1137             :             {
    1138         989 :                 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        2315 : const std::string &GDALPDFObjectPoppler::GetName()
    1162             : {
    1163        2315 :     if (GetType() == PDFObjectType_Name)
    1164        2315 :         return (osStr = m_po->getName());
    1165             :     else
    1166           0 :         return (osStr = "");
    1167             : }
    1168             : 
    1169             : /************************************************************************/
    1170             : /*                            GetDictionary()                           */
    1171             : /************************************************************************/
    1172             : 
    1173        5412 : GDALPDFDictionary *GDALPDFObjectPoppler::GetDictionary()
    1174             : {
    1175        5412 :     if (GetType() != PDFObjectType_Dictionary)
    1176           0 :         return nullptr;
    1177             : 
    1178        5412 :     if (m_poDict)
    1179        1935 :         return m_poDict;
    1180             : 
    1181        3477 :     Dict *poDict = (m_po->getType() == objStream) ? m_po->getStream()->getDict()
    1182        2648 :                                                   : m_po->getDict();
    1183        3477 :     if (poDict == nullptr)
    1184           0 :         return nullptr;
    1185        3477 :     m_poDict = new GDALPDFDictionaryPoppler(poDict);
    1186        3477 :     return m_poDict;
    1187             : }
    1188             : 
    1189             : /************************************************************************/
    1190             : /*                              GetArray()                              */
    1191             : /************************************************************************/
    1192             : 
    1193        5851 : GDALPDFArray *GDALPDFObjectPoppler::GetArray()
    1194             : {
    1195        5851 :     if (GetType() != PDFObjectType_Array)
    1196           0 :         return nullptr;
    1197             : 
    1198        5851 :     if (m_poArray)
    1199        4823 :         return m_poArray;
    1200             : 
    1201        1028 :     Array *poArray = m_po->getArray();
    1202        1028 :     if (poArray == nullptr)
    1203           0 :         return nullptr;
    1204        1028 :     m_poArray = new GDALPDFArrayPoppler(poArray);
    1205        1028 :     return m_poArray;
    1206             : }
    1207             : 
    1208             : /************************************************************************/
    1209             : /*                             GetStream()                              */
    1210             : /************************************************************************/
    1211             : 
    1212         463 : GDALPDFStream *GDALPDFObjectPoppler::GetStream()
    1213             : {
    1214         463 :     if (m_po->getType() != objStream)
    1215          14 :         return nullptr;
    1216             : 
    1217         449 :     if (m_poStream)
    1218         127 :         return m_poStream;
    1219         322 :     m_poStream = new GDALPDFStreamPoppler(m_po->getStream());
    1220         322 :     return m_poStream;
    1221             : }
    1222             : 
    1223             : /************************************************************************/
    1224             : /*                           SetRefNumAndGen()                          */
    1225             : /************************************************************************/
    1226             : 
    1227       12025 : void GDALPDFObjectPoppler::SetRefNumAndGen(const GDALPDFObjectNum &nNum,
    1228             :                                            int nGen)
    1229             : {
    1230       12025 :     m_nRefNum = nNum;
    1231       12025 :     m_nRefGen = nGen;
    1232       12025 : }
    1233             : 
    1234             : /************************************************************************/
    1235             : /*                               GetRefNum()                            */
    1236             : /************************************************************************/
    1237             : 
    1238        1219 : GDALPDFObjectNum GDALPDFObjectPoppler::GetRefNum()
    1239             : {
    1240        1219 :     return m_nRefNum;
    1241             : }
    1242             : 
    1243             : /************************************************************************/
    1244             : /*                               GetRefGen()                            */
    1245             : /************************************************************************/
    1246             : 
    1247         820 : int GDALPDFObjectPoppler::GetRefGen()
    1248             : {
    1249         820 :     return m_nRefGen;
    1250             : }
    1251             : 
    1252             : /************************************************************************/
    1253             : /* ==================================================================== */
    1254             : /*                        GDALPDFDictionaryPoppler                      */
    1255             : /* ==================================================================== */
    1256             : /************************************************************************/
    1257             : 
    1258             : /************************************************************************/
    1259             : /*                       ~GDALPDFDictionaryPoppler()                    */
    1260             : /************************************************************************/
    1261             : 
    1262        6954 : GDALPDFDictionaryPoppler::~GDALPDFDictionaryPoppler()
    1263             : {
    1264        3477 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1265        3477 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1266       10726 :     for (; oIter != oEnd; ++oIter)
    1267        7249 :         delete oIter->second;
    1268        6954 : }
    1269             : 
    1270             : /************************************************************************/
    1271             : /*                                  Get()                               */
    1272             : /************************************************************************/
    1273             : 
    1274       11280 : GDALPDFObject *GDALPDFDictionaryPoppler::Get(const char *pszKey)
    1275             : {
    1276       11280 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1277       11280 :     if (oIter != m_map.end())
    1278        2072 :         return oIter->second;
    1279             : 
    1280        9208 :     auto &&o(m_poDict->lookupNF(pszKey));
    1281        9208 :     if (!o.isNull())
    1282             :     {
    1283        7249 :         GDALPDFObjectNum nRefNum;
    1284        7249 :         int nRefGen = 0;
    1285        7249 :         if (o.isRef())
    1286             :         {
    1287        2224 :             nRefNum = o.getRefNum();
    1288        2224 :             nRefGen = o.getRefGen();
    1289        2224 :             Object o2(m_poDict->lookup(pszKey));
    1290        2224 :             if (!o2.isNull())
    1291             :             {
    1292             :                 GDALPDFObjectPoppler *poObj =
    1293        2224 :                     new GDALPDFObjectPoppler(new Object(std::move(o2)), TRUE);
    1294        2224 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1295        2224 :                 m_map[pszKey] = poObj;
    1296        2224 :                 return poObj;
    1297             :             }
    1298             :         }
    1299             :         else
    1300             :         {
    1301             :             GDALPDFObjectPoppler *poObj =
    1302        5025 :                 new GDALPDFObjectPoppler(new Object(o.copy()), TRUE);
    1303        5025 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1304        5025 :             m_map[pszKey] = poObj;
    1305        5025 :             return poObj;
    1306             :         }
    1307             :     }
    1308        1959 :     return nullptr;
    1309             : }
    1310             : 
    1311             : /************************************************************************/
    1312             : /*                                GetValues()                           */
    1313             : /************************************************************************/
    1314             : 
    1315         408 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPoppler::GetValues()
    1316             : {
    1317         408 :     int i = 0;
    1318         408 :     int nLength = m_poDict->getLength();
    1319        1827 :     for (i = 0; i < nLength; i++)
    1320             :     {
    1321        1419 :         const char *pszKey = m_poDict->getKey(i);
    1322        1419 :         Get(pszKey);
    1323             :     }
    1324         408 :     return m_map;
    1325             : }
    1326             : 
    1327             : /************************************************************************/
    1328             : /* ==================================================================== */
    1329             : /*                          GDALPDFArrayPoppler                         */
    1330             : /* ==================================================================== */
    1331             : /************************************************************************/
    1332             : 
    1333             : /************************************************************************/
    1334             : /*                           GDALPDFCreateArray()                       */
    1335             : /************************************************************************/
    1336             : 
    1337          38 : GDALPDFArray *GDALPDFCreateArray(Array *array)
    1338             : {
    1339          38 :     return new GDALPDFArrayPoppler(array);
    1340             : }
    1341             : 
    1342             : /************************************************************************/
    1343             : /*                               GetLength()                            */
    1344             : /************************************************************************/
    1345             : 
    1346        7999 : int GDALPDFArrayPoppler::GetLength()
    1347             : {
    1348        7999 :     return m_poArray->getLength();
    1349             : }
    1350             : 
    1351             : /************************************************************************/
    1352             : /*                                 Get()                                */
    1353             : /************************************************************************/
    1354             : 
    1355        5455 : GDALPDFObject *GDALPDFArrayPoppler::Get(int nIndex)
    1356             : {
    1357        5455 :     if (nIndex < 0 || nIndex >= GetLength())
    1358           0 :         return nullptr;
    1359             : 
    1360        5455 :     if (m_v.empty())
    1361        1044 :         m_v.resize(GetLength());
    1362             : 
    1363        5455 :     if (m_v[nIndex] != nullptr)
    1364         868 :         return m_v[nIndex].get();
    1365             : 
    1366        4587 :     auto &&o(m_poArray->getNF(nIndex));
    1367        4587 :     if (!o.isNull())
    1368             :     {
    1369        4587 :         GDALPDFObjectNum nRefNum;
    1370        4587 :         int nRefGen = 0;
    1371        4587 :         if (o.isRef())
    1372             :         {
    1373         543 :             nRefNum = o.getRefNum();
    1374         543 :             nRefGen = o.getRefGen();
    1375         543 :             Object o2(m_poArray->get(nIndex));
    1376         543 :             if (!o2.isNull())
    1377             :             {
    1378             :                 auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1379        1086 :                     new Object(std::move(o2)), TRUE);
    1380         543 :                 poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1381         543 :                 m_v[nIndex] = std::move(poObj);
    1382         543 :                 return m_v[nIndex].get();
    1383             :             }
    1384             :         }
    1385             :         else
    1386             :         {
    1387             :             auto poObj = std::make_unique<GDALPDFObjectPoppler>(
    1388        8088 :                 new Object(o.copy()), TRUE);
    1389        4044 :             poObj->SetRefNumAndGen(nRefNum, nRefGen);
    1390        4044 :             m_v[nIndex] = std::move(poObj);
    1391        4044 :             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         530 : int64_t GDALPDFStreamPoppler::GetLength(int64_t nMaxSize)
    1408             : {
    1409         530 :     if (m_nLength >= 0)
    1410         292 :         return m_nLength;
    1411             : 
    1412         238 :     m_poStream->reset();
    1413         238 :     m_nLength = 0;
    1414             :     unsigned char readBuf[4096];
    1415             :     int readChars;
    1416         476 :     while ((readChars = m_poStream->doGetChars(4096, readBuf)) != 0)
    1417             :     {
    1418         238 :         m_nLength += readChars;
    1419         238 :         if (nMaxSize != 0 && m_nLength > nMaxSize)
    1420             :         {
    1421           0 :             m_nLength = -1;
    1422           0 :             return std::numeric_limits<int64_t>::max();
    1423             :         }
    1424             :     }
    1425         238 :     return m_nLength;
    1426             : }
    1427             : 
    1428             : /************************************************************************/
    1429             : /*                         GooStringToCharStart()                       */
    1430             : /************************************************************************/
    1431             : 
    1432         388 : static char *GooStringToCharStart(GooString &gstr)
    1433             : {
    1434         388 :     auto nLength = gstr.getLength();
    1435         388 :     if (nLength)
    1436             :     {
    1437         387 :         char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    1438         387 :         if (pszContent)
    1439             :         {
    1440         387 :             const char *srcStr = gstr.c_str();
    1441         387 :             memcpy(pszContent, srcStr, nLength);
    1442         387 :             pszContent[nLength] = '\0';
    1443             :         }
    1444         387 :         return pszContent;
    1445             :     }
    1446           1 :     return nullptr;
    1447             : }
    1448             : 
    1449             : /************************************************************************/
    1450             : /*                               GetBytes()                             */
    1451             : /************************************************************************/
    1452             : 
    1453         386 : char *GDALPDFStreamPoppler::GetBytes()
    1454             : {
    1455         772 :     GooString gstr;
    1456             :     try
    1457             :     {
    1458         386 :         m_poStream->fillGooString(&gstr);
    1459             :     }
    1460           0 :     catch (const std::exception &e)
    1461             :     {
    1462           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1463           0 :                  "GDALPDFStreamPoppler::GetBytes(): %s", e.what());
    1464           0 :         return nullptr;
    1465             :     }
    1466         386 :     m_nLength = static_cast<int64_t>(gstr.toStr().size());
    1467         386 :     return GooStringToCharStart(gstr);
    1468             : }
    1469             : 
    1470             : /************************************************************************/
    1471             : /*                            GetRawLength()                            */
    1472             : /************************************************************************/
    1473             : 
    1474          63 : int64_t GDALPDFStreamPoppler::GetRawLength()
    1475             : {
    1476          63 :     if (m_nRawLength >= 0)
    1477           2 :         return m_nRawLength;
    1478             : 
    1479          61 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1480          61 :     undecodeStream->reset();
    1481          61 :     m_nRawLength = 0;
    1482       25531 :     while (undecodeStream->getChar() != EOF)
    1483       25470 :         m_nRawLength++;
    1484          61 :     return m_nRawLength;
    1485             : }
    1486             : 
    1487             : /************************************************************************/
    1488             : /*                             GetRawBytes()                            */
    1489             : /************************************************************************/
    1490             : 
    1491           2 : char *GDALPDFStreamPoppler::GetRawBytes()
    1492             : {
    1493           4 :     GooString gstr;
    1494           2 :     auto undecodeStream = m_poStream->getUndecodedStream();
    1495             :     try
    1496             :     {
    1497           2 :         undecodeStream->fillGooString(&gstr);
    1498             :     }
    1499           0 :     catch (const std::exception &e)
    1500             :     {
    1501           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1502           0 :                  "GDALPDFStreamPoppler::GetRawBytes(): %s", e.what());
    1503           0 :         return nullptr;
    1504             :     }
    1505           2 :     m_nRawLength = gstr.getLength();
    1506           2 :     return GooStringToCharStart(gstr);
    1507             : }
    1508             : 
    1509             : #endif  // HAVE_POPPLER
    1510             : 
    1511             : #ifdef HAVE_PODOFO
    1512             : 
    1513             : /************************************************************************/
    1514             : /* ==================================================================== */
    1515             : /*                         GDALPDFDictionaryPodofo                      */
    1516             : /* ==================================================================== */
    1517             : /************************************************************************/
    1518             : 
    1519             : class GDALPDFDictionaryPodofo : public GDALPDFDictionary
    1520             : {
    1521             :   private:
    1522             :     const PoDoFo::PdfDictionary *m_poDict;
    1523             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1524             :     std::map<CPLString, GDALPDFObject *> m_map{};
    1525             : 
    1526             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFDictionaryPodofo)
    1527             : 
    1528             :   public:
    1529             :     GDALPDFDictionaryPodofo(const PoDoFo::PdfDictionary *poDict,
    1530             :                             const PoDoFo::PdfVecObjects &poObjects)
    1531             :         : m_poDict(poDict), m_poObjects(poObjects)
    1532             :     {
    1533             :     }
    1534             : 
    1535             :     virtual ~GDALPDFDictionaryPodofo();
    1536             : 
    1537             :     virtual GDALPDFObject *Get(const char *pszKey) override;
    1538             :     virtual std::map<CPLString, GDALPDFObject *> &GetValues() override;
    1539             : };
    1540             : 
    1541             : /************************************************************************/
    1542             : /* ==================================================================== */
    1543             : /*                           GDALPDFArrayPodofo                         */
    1544             : /* ==================================================================== */
    1545             : /************************************************************************/
    1546             : 
    1547             : class GDALPDFArrayPodofo : public GDALPDFArray
    1548             : {
    1549             :   private:
    1550             :     const PoDoFo::PdfArray *m_poArray;
    1551             :     const PoDoFo::PdfVecObjects &m_poObjects;
    1552             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    1553             : 
    1554             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPodofo)
    1555             : 
    1556             :   public:
    1557             :     GDALPDFArrayPodofo(const PoDoFo::PdfArray *poArray,
    1558             :                        const PoDoFo::PdfVecObjects &poObjects)
    1559             :         : m_poArray(poArray), m_poObjects(poObjects)
    1560             :     {
    1561             :     }
    1562             : 
    1563             :     virtual int GetLength() override;
    1564             :     virtual GDALPDFObject *Get(int nIndex) override;
    1565             : };
    1566             : 
    1567             : /************************************************************************/
    1568             : /* ==================================================================== */
    1569             : /*                          GDALPDFStreamPodofo                         */
    1570             : /* ==================================================================== */
    1571             : /************************************************************************/
    1572             : 
    1573             : class GDALPDFStreamPodofo : public GDALPDFStream
    1574             : {
    1575             :   private:
    1576             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1577             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1578             :     const PoDoFo::PdfObjectStream *m_pStream;
    1579             : #else
    1580             :     const PoDoFo::PdfStream *m_pStream;
    1581             : #endif
    1582             : 
    1583             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFStreamPodofo)
    1584             : 
    1585             :   public:
    1586             :     GDALPDFStreamPodofo(
    1587             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1588             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1589             :         const PoDoFo::PdfObjectStream *
    1590             : #else
    1591             :         const PoDoFo::PdfStream *
    1592             : #endif
    1593             :             pStream)
    1594             :         : m_pStream(pStream)
    1595             :     {
    1596             :     }
    1597             : 
    1598             :     virtual ~GDALPDFStreamPodofo()
    1599             :     {
    1600             :     }
    1601             : 
    1602             :     virtual int64_t GetLength(int64_t nMaxSize = 0) override;
    1603             :     virtual char *GetBytes() override;
    1604             : 
    1605             :     virtual int64_t GetRawLength() override;
    1606             :     virtual char *GetRawBytes() override;
    1607             : };
    1608             : 
    1609             : /************************************************************************/
    1610             : /* ==================================================================== */
    1611             : /*                          GDALPDFObjectPodofo                         */
    1612             : /* ==================================================================== */
    1613             : /************************************************************************/
    1614             : 
    1615             : /************************************************************************/
    1616             : /*                          GDALPDFObjectPodofo()                       */
    1617             : /************************************************************************/
    1618             : 
    1619             : GDALPDFObjectPodofo::GDALPDFObjectPodofo(const PoDoFo::PdfObject *po,
    1620             :                                          const PoDoFo::PdfVecObjects &poObjects)
    1621             :     : m_po(po), m_poObjects(poObjects)
    1622             : {
    1623             :     try
    1624             :     {
    1625             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1626             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1627             :         if (m_po->GetDataType() == PoDoFo::PdfDataType::Reference)
    1628             :         {
    1629             :             PoDoFo::PdfObject *poObj =
    1630             :                 m_poObjects.GetObject(m_po->GetReference());
    1631             :             if (poObj)
    1632             :                 m_po = poObj;
    1633             :         }
    1634             : #else
    1635             :         if (m_po->GetDataType() == PoDoFo::ePdfDataType_Reference)
    1636             :         {
    1637             :             PoDoFo::PdfObject *poObj =
    1638             :                 m_poObjects.GetObject(m_po->GetReference());
    1639             :             if (poObj)
    1640             :                 m_po = poObj;
    1641             :         }
    1642             : #endif
    1643             :     }
    1644             :     catch (PoDoFo::PdfError &oError)
    1645             :     {
    1646             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1647             :                  oError.what());
    1648             :     }
    1649             : }
    1650             : 
    1651             : /************************************************************************/
    1652             : /*                         ~GDALPDFObjectPodofo()                       */
    1653             : /************************************************************************/
    1654             : 
    1655             : GDALPDFObjectPodofo::~GDALPDFObjectPodofo()
    1656             : {
    1657             :     delete m_poDict;
    1658             :     delete m_poArray;
    1659             :     delete m_poStream;
    1660             : }
    1661             : 
    1662             : /************************************************************************/
    1663             : /*                               GetType()                              */
    1664             : /************************************************************************/
    1665             : 
    1666             : GDALPDFObjectType GDALPDFObjectPodofo::GetType()
    1667             : {
    1668             :     try
    1669             :     {
    1670             :         switch (m_po->GetDataType())
    1671             :         {
    1672             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1673             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1674             :             case PoDoFo::PdfDataType::Null:
    1675             :                 return PDFObjectType_Null;
    1676             :             case PoDoFo::PdfDataType::Bool:
    1677             :                 return PDFObjectType_Bool;
    1678             :             case PoDoFo::PdfDataType::Number:
    1679             :                 return PDFObjectType_Int;
    1680             :             case PoDoFo::PdfDataType::Real:
    1681             :                 return PDFObjectType_Real;
    1682             :             case PoDoFo::PdfDataType::String:
    1683             :                 return PDFObjectType_String;
    1684             :             case PoDoFo::PdfDataType::Name:
    1685             :                 return PDFObjectType_Name;
    1686             :             case PoDoFo::PdfDataType::Array:
    1687             :                 return PDFObjectType_Array;
    1688             :             case PoDoFo::PdfDataType::Dictionary:
    1689             :                 return PDFObjectType_Dictionary;
    1690             :             default:
    1691             :                 return PDFObjectType_Unknown;
    1692             : #else
    1693             :             case PoDoFo::ePdfDataType_Null:
    1694             :                 return PDFObjectType_Null;
    1695             :             case PoDoFo::ePdfDataType_Bool:
    1696             :                 return PDFObjectType_Bool;
    1697             :             case PoDoFo::ePdfDataType_Number:
    1698             :                 return PDFObjectType_Int;
    1699             :             case PoDoFo::ePdfDataType_Real:
    1700             :                 return PDFObjectType_Real;
    1701             :             case PoDoFo::ePdfDataType_HexString:
    1702             :                 return PDFObjectType_String;
    1703             :             case PoDoFo::ePdfDataType_String:
    1704             :                 return PDFObjectType_String;
    1705             :             case PoDoFo::ePdfDataType_Name:
    1706             :                 return PDFObjectType_Name;
    1707             :             case PoDoFo::ePdfDataType_Array:
    1708             :                 return PDFObjectType_Array;
    1709             :             case PoDoFo::ePdfDataType_Dictionary:
    1710             :                 return PDFObjectType_Dictionary;
    1711             :             default:
    1712             :                 return PDFObjectType_Unknown;
    1713             : #endif
    1714             :         }
    1715             :     }
    1716             :     catch (PoDoFo::PdfError &oError)
    1717             :     {
    1718             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1719             :                  oError.what());
    1720             :         return PDFObjectType_Unknown;
    1721             :     }
    1722             : }
    1723             : 
    1724             : /************************************************************************/
    1725             : /*                          GetTypeNameNative()                         */
    1726             : /************************************************************************/
    1727             : 
    1728             : const char *GDALPDFObjectPodofo::GetTypeNameNative()
    1729             : {
    1730             :     try
    1731             :     {
    1732             :         return m_po->GetDataTypeString();
    1733             :     }
    1734             :     catch (PoDoFo::PdfError &oError)
    1735             :     {
    1736             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : %s",
    1737             :                  oError.what());
    1738             :         return "unknown";
    1739             :     }
    1740             : }
    1741             : 
    1742             : /************************************************************************/
    1743             : /*                              GetBool()                               */
    1744             : /************************************************************************/
    1745             : 
    1746             : int GDALPDFObjectPodofo::GetBool()
    1747             : {
    1748             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1749             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1750             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Bool)
    1751             : #else
    1752             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Bool)
    1753             : #endif
    1754             :         return m_po->GetBool();
    1755             :     else
    1756             :         return 0;
    1757             : }
    1758             : 
    1759             : /************************************************************************/
    1760             : /*                              GetInt()                                */
    1761             : /************************************************************************/
    1762             : 
    1763             : int GDALPDFObjectPodofo::GetInt()
    1764             : {
    1765             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1766             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1767             :     if (m_po->GetDataType() == PoDoFo::PdfDataType::Number)
    1768             : #else
    1769             :     if (m_po->GetDataType() == PoDoFo::ePdfDataType_Number)
    1770             : #endif
    1771             :         return static_cast<int>(m_po->GetNumber());
    1772             :     else
    1773             :         return 0;
    1774             : }
    1775             : 
    1776             : /************************************************************************/
    1777             : /*                              GetReal()                               */
    1778             : /************************************************************************/
    1779             : 
    1780             : double GDALPDFObjectPodofo::GetReal()
    1781             : {
    1782             :     if (GetType() == PDFObjectType_Real)
    1783             :         return m_po->GetReal();
    1784             :     else
    1785             :         return 0.0;
    1786             : }
    1787             : 
    1788             : /************************************************************************/
    1789             : /*                              GetString()                             */
    1790             : /************************************************************************/
    1791             : 
    1792             : const std::string &GDALPDFObjectPodofo::GetString()
    1793             : {
    1794             :     if (GetType() == PDFObjectType_String)
    1795             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1796             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1797             :         return (osStr = m_po->GetString().GetString());
    1798             : #else
    1799             :         return (osStr = m_po->GetString().GetStringUtf8());
    1800             : #endif
    1801             :     else
    1802             :         return (osStr = "");
    1803             : }
    1804             : 
    1805             : /************************************************************************/
    1806             : /*                              GetName()                               */
    1807             : /************************************************************************/
    1808             : 
    1809             : const std::string &GDALPDFObjectPodofo::GetName()
    1810             : {
    1811             :     if (GetType() == PDFObjectType_Name)
    1812             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1813             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1814             :         return (osStr = m_po->GetName().GetString());
    1815             : #else
    1816             :         return (osStr = m_po->GetName().GetName());
    1817             : #endif
    1818             :     else
    1819             :         return (osStr = "");
    1820             : }
    1821             : 
    1822             : /************************************************************************/
    1823             : /*                             GetDictionary()                          */
    1824             : /************************************************************************/
    1825             : 
    1826             : GDALPDFDictionary *GDALPDFObjectPodofo::GetDictionary()
    1827             : {
    1828             :     if (GetType() != PDFObjectType_Dictionary)
    1829             :         return nullptr;
    1830             : 
    1831             :     if (m_poDict)
    1832             :         return m_poDict;
    1833             : 
    1834             :     m_poDict = new GDALPDFDictionaryPodofo(&m_po->GetDictionary(), m_poObjects);
    1835             :     return m_poDict;
    1836             : }
    1837             : 
    1838             : /************************************************************************/
    1839             : /*                                GetArray()                            */
    1840             : /************************************************************************/
    1841             : 
    1842             : GDALPDFArray *GDALPDFObjectPodofo::GetArray()
    1843             : {
    1844             :     if (GetType() != PDFObjectType_Array)
    1845             :         return nullptr;
    1846             : 
    1847             :     if (m_poArray)
    1848             :         return m_poArray;
    1849             : 
    1850             :     m_poArray = new GDALPDFArrayPodofo(&m_po->GetArray(), m_poObjects);
    1851             :     return m_poArray;
    1852             : }
    1853             : 
    1854             : /************************************************************************/
    1855             : /*                               GetStream()                            */
    1856             : /************************************************************************/
    1857             : 
    1858             : GDALPDFStream *GDALPDFObjectPodofo::GetStream()
    1859             : {
    1860             :     try
    1861             :     {
    1862             :         if (!m_po->HasStream())
    1863             :             return nullptr;
    1864             :     }
    1865             :     catch (PoDoFo::PdfError &oError)
    1866             :     {
    1867             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object : %s",
    1868             :                  oError.what());
    1869             :         return nullptr;
    1870             :     }
    1871             :     catch (...)
    1872             :     {
    1873             :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid object");
    1874             :         return nullptr;
    1875             :     }
    1876             : 
    1877             :     if (m_poStream == nullptr)
    1878             :         m_poStream = new GDALPDFStreamPodofo(m_po->GetStream());
    1879             :     return m_poStream;
    1880             : }
    1881             : 
    1882             : /************************************************************************/
    1883             : /*                               GetRefNum()                            */
    1884             : /************************************************************************/
    1885             : 
    1886             : GDALPDFObjectNum GDALPDFObjectPodofo::GetRefNum()
    1887             : {
    1888             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1889             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1890             :     return GDALPDFObjectNum(m_po->GetIndirectReference().ObjectNumber());
    1891             : #else
    1892             :     return GDALPDFObjectNum(m_po->Reference().ObjectNumber());
    1893             : #endif
    1894             : }
    1895             : 
    1896             : /************************************************************************/
    1897             : /*                               GetRefGen()                            */
    1898             : /************************************************************************/
    1899             : 
    1900             : int GDALPDFObjectPodofo::GetRefGen()
    1901             : {
    1902             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1903             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1904             :     return m_po->GetIndirectReference().GenerationNumber();
    1905             : #else
    1906             :     return m_po->Reference().GenerationNumber();
    1907             : #endif
    1908             : }
    1909             : 
    1910             : /************************************************************************/
    1911             : /* ==================================================================== */
    1912             : /*                         GDALPDFDictionaryPodofo                      */
    1913             : /* ==================================================================== */
    1914             : /************************************************************************/
    1915             : 
    1916             : /************************************************************************/
    1917             : /*                         ~GDALPDFDictionaryPodofo()                   */
    1918             : /************************************************************************/
    1919             : 
    1920             : GDALPDFDictionaryPodofo::~GDALPDFDictionaryPodofo()
    1921             : {
    1922             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    1923             :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    1924             :     for (; oIter != oEnd; ++oIter)
    1925             :         delete oIter->second;
    1926             : }
    1927             : 
    1928             : /************************************************************************/
    1929             : /*                                  Get()                               */
    1930             : /************************************************************************/
    1931             : 
    1932             : GDALPDFObject *GDALPDFDictionaryPodofo::Get(const char *pszKey)
    1933             : {
    1934             :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    1935             :     if (oIter != m_map.end())
    1936             :         return oIter->second;
    1937             : 
    1938             :     const PoDoFo::PdfObject *poVal = m_poDict->GetKey(PoDoFo::PdfName(pszKey));
    1939             :     if (poVal)
    1940             :     {
    1941             :         GDALPDFObjectPodofo *poObj =
    1942             :             new GDALPDFObjectPodofo(poVal, m_poObjects);
    1943             :         m_map[pszKey] = poObj;
    1944             :         return poObj;
    1945             :     }
    1946             :     else
    1947             :     {
    1948             :         return nullptr;
    1949             :     }
    1950             : }
    1951             : 
    1952             : /************************************************************************/
    1953             : /*                              GetValues()                             */
    1954             : /************************************************************************/
    1955             : 
    1956             : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPodofo::GetValues()
    1957             : {
    1958             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    1959             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    1960             :     for (const auto &oIter : *m_poDict)
    1961             :     {
    1962             :         Get(oIter.first.GetString().c_str());
    1963             :     }
    1964             : #else
    1965             :     for (const auto &oIter : m_poDict->GetKeys())
    1966             :     {
    1967             :         Get(oIter.first.GetName().c_str());
    1968             :     }
    1969             : #endif
    1970             :     return m_map;
    1971             : }
    1972             : 
    1973             : /************************************************************************/
    1974             : /* ==================================================================== */
    1975             : /*                           GDALPDFArrayPodofo                         */
    1976             : /* ==================================================================== */
    1977             : /************************************************************************/
    1978             : 
    1979             : /************************************************************************/
    1980             : /*                              GetLength()                             */
    1981             : /************************************************************************/
    1982             : 
    1983             : int GDALPDFArrayPodofo::GetLength()
    1984             : {
    1985             :     return static_cast<int>(m_poArray->GetSize());
    1986             : }
    1987             : 
    1988             : /************************************************************************/
    1989             : /*                                Get()                                 */
    1990             : /************************************************************************/
    1991             : 
    1992             : GDALPDFObject *GDALPDFArrayPodofo::Get(int nIndex)
    1993             : {
    1994             :     if (nIndex < 0 || nIndex >= GetLength())
    1995             :         return nullptr;
    1996             : 
    1997             :     if (m_v.empty())
    1998             :         m_v.resize(GetLength());
    1999             : 
    2000             :     if (m_v[nIndex] != nullptr)
    2001             :         return m_v[nIndex].get();
    2002             : 
    2003             :     const PoDoFo::PdfObject &oVal = (*m_poArray)[nIndex];
    2004             :     m_v[nIndex] = std::make_unique<GDALPDFObjectPodofo>(&oVal, m_poObjects);
    2005             :     return m_v[nIndex].get();
    2006             : }
    2007             : 
    2008             : /************************************************************************/
    2009             : /* ==================================================================== */
    2010             : /*                           GDALPDFStreamPodofo                        */
    2011             : /* ==================================================================== */
    2012             : /************************************************************************/
    2013             : 
    2014             : /************************************************************************/
    2015             : /*                              GetLength()                             */
    2016             : /************************************************************************/
    2017             : 
    2018             : int64_t GDALPDFStreamPodofo::GetLength(int64_t /* nMaxSize */)
    2019             : {
    2020             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2021             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2022             :     PoDoFo::charbuff str;
    2023             :     try
    2024             :     {
    2025             :         m_pStream->CopyToSafe(str);
    2026             :     }
    2027             :     catch (PoDoFo::PdfError &e)
    2028             :     {
    2029             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2030             :                  e.what());
    2031             :         return 0;
    2032             :     }
    2033             :     return static_cast<int64_t>(str.size());
    2034             : #else
    2035             :     char *pBuffer = nullptr;
    2036             :     PoDoFo::pdf_long nLen = 0;
    2037             :     try
    2038             :     {
    2039             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2040             :         PoDoFo::podofo_free(pBuffer);
    2041             :         return static_cast<int64_t>(nLen);
    2042             :     }
    2043             :     catch (PoDoFo::PdfError &e)
    2044             :     {
    2045             :     }
    2046             :     return 0;
    2047             : #endif
    2048             : }
    2049             : 
    2050             : /************************************************************************/
    2051             : /*                               GetBytes()                             */
    2052             : /************************************************************************/
    2053             : 
    2054             : char *GDALPDFStreamPodofo::GetBytes()
    2055             : {
    2056             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2057             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2058             :     PoDoFo::charbuff str;
    2059             :     try
    2060             :     {
    2061             :         m_pStream->CopyToSafe(str);
    2062             :     }
    2063             :     catch (PoDoFo::PdfError &e)
    2064             :     {
    2065             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2066             :                  e.what());
    2067             :         return nullptr;
    2068             :     }
    2069             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2070             :     if (!pszContent)
    2071             :     {
    2072             :         return nullptr;
    2073             :     }
    2074             :     memcpy(pszContent, str.data(), str.size());
    2075             :     pszContent[str.size()] = '\0';
    2076             :     return pszContent;
    2077             : #else
    2078             :     char *pBuffer = nullptr;
    2079             :     PoDoFo::pdf_long nLen = 0;
    2080             :     try
    2081             :     {
    2082             :         m_pStream->GetFilteredCopy(&pBuffer, &nLen);
    2083             :     }
    2084             :     catch (PoDoFo::PdfError &e)
    2085             :     {
    2086             :         return nullptr;
    2087             :     }
    2088             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2089             :     if (!pszContent)
    2090             :     {
    2091             :         PoDoFo::podofo_free(pBuffer);
    2092             :         return nullptr;
    2093             :     }
    2094             :     memcpy(pszContent, pBuffer, nLen);
    2095             :     PoDoFo::podofo_free(pBuffer);
    2096             :     pszContent[nLen] = '\0';
    2097             :     return pszContent;
    2098             : #endif
    2099             : }
    2100             : 
    2101             : /************************************************************************/
    2102             : /*                             GetRawLength()                           */
    2103             : /************************************************************************/
    2104             : 
    2105             : int64_t GDALPDFStreamPodofo::GetRawLength()
    2106             : {
    2107             :     try
    2108             :     {
    2109             :         auto nLen = m_pStream->GetLength();
    2110             :         return static_cast<int64_t>(nLen);
    2111             :     }
    2112             :     catch (PoDoFo::PdfError &e)
    2113             :     {
    2114             :     }
    2115             :     return 0;
    2116             : }
    2117             : 
    2118             : /************************************************************************/
    2119             : /*                              GetRawBytes()                           */
    2120             : /************************************************************************/
    2121             : 
    2122             : char *GDALPDFStreamPodofo::GetRawBytes()
    2123             : {
    2124             : #if PODOFO_VERSION_MAJOR > 0 ||                                                \
    2125             :     (PODOFO_VERSION_MAJOR == 0 && PODOFO_VERSION_MINOR >= 10)
    2126             :     PoDoFo::charbuff str;
    2127             :     try
    2128             :     {
    2129             :         PoDoFo::StringStreamDevice stream(str);
    2130             : #ifdef USE_HACK_BECAUSE_PdfInputStream_constructor_is_not_exported_in_podofo_0_11
    2131             :         auto *poNonConstStream =
    2132             :             const_cast<PoDoFo::PdfObjectStream *>(m_pStream);
    2133             :         auto inputStream = poNonConstStream->GetProvider().GetInputStream(
    2134             :             poNonConstStream->GetParent());
    2135             :         inputStream->CopyTo(stream);
    2136             : #else
    2137             :         // Should work but fails to link because PdfInputStream destructor
    2138             :         // is not exported
    2139             :         auto inputStream = m_pStream->GetInputStream(/*raw=*/true);
    2140             :         inputStream.CopyTo(stream);
    2141             : #endif
    2142             :         stream.Flush();
    2143             :     }
    2144             :     catch (PoDoFo::PdfError &e)
    2145             :     {
    2146             :         CPLError(CE_Failure, CPLE_AppDefined, "CopyToSafe() failed: %s",
    2147             :                  e.what());
    2148             :         return nullptr;
    2149             :     }
    2150             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(str.size() + 1));
    2151             :     if (!pszContent)
    2152             :     {
    2153             :         return nullptr;
    2154             :     }
    2155             :     memcpy(pszContent, str.data(), str.size());
    2156             :     pszContent[str.size()] = '\0';
    2157             :     return pszContent;
    2158             : #else
    2159             :     char *pBuffer = nullptr;
    2160             :     PoDoFo::pdf_long nLen = 0;
    2161             :     try
    2162             :     {
    2163             :         m_pStream->GetCopy(&pBuffer, &nLen);
    2164             :     }
    2165             :     catch (PoDoFo::PdfError &e)
    2166             :     {
    2167             :         return nullptr;
    2168             :     }
    2169             :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
    2170             :     if (!pszContent)
    2171             :     {
    2172             :         PoDoFo::podofo_free(pBuffer);
    2173             :         return nullptr;
    2174             :     }
    2175             :     memcpy(pszContent, pBuffer, nLen);
    2176             :     PoDoFo::podofo_free(pBuffer);
    2177             :     pszContent[nLen] = '\0';
    2178             :     return pszContent;
    2179             : #endif
    2180             : }
    2181             : 
    2182             : #endif  // HAVE_PODOFO
    2183             : 
    2184             : #ifdef HAVE_PDFIUM
    2185             : 
    2186             : /************************************************************************/
    2187             : /* ==================================================================== */
    2188             : /*                         GDALPDFDictionaryPdfium                      */
    2189             : /* ==================================================================== */
    2190             : /************************************************************************/
    2191             : 
    2192             : class GDALPDFDictionaryPdfium : public GDALPDFDictionary
    2193             : {
    2194             :   private:
    2195             :     RetainPtr<const CPDF_Dictionary> m_poDict;
    2196             :     std::map<CPLString, GDALPDFObject *> m_map{};
    2197             : 
    2198             :   public:
    2199        5230 :     GDALPDFDictionaryPdfium(RetainPtr<const CPDF_Dictionary> poDict)
    2200        5230 :         : m_poDict(std::move(poDict))
    2201             :     {
    2202        5230 :     }
    2203             : 
    2204             :     virtual ~GDALPDFDictionaryPdfium();
    2205             : 
    2206             :     virtual GDALPDFObject *Get(const char *pszKey) override;
    2207             :     virtual std::map<CPLString, GDALPDFObject *> &GetValues() override;
    2208             : };
    2209             : 
    2210             : /************************************************************************/
    2211             : /* ==================================================================== */
    2212             : /*                           GDALPDFArrayPdfium                         */
    2213             : /* ==================================================================== */
    2214             : /************************************************************************/
    2215             : 
    2216             : class GDALPDFArrayPdfium : public GDALPDFArray
    2217             : {
    2218             :   private:
    2219             :     const CPDF_Array *m_poArray;
    2220             :     std::vector<std::unique_ptr<GDALPDFObject>> m_v{};
    2221             : 
    2222             :     CPL_DISALLOW_COPY_ASSIGN(GDALPDFArrayPdfium)
    2223             : 
    2224             :   public:
    2225        1343 :     GDALPDFArrayPdfium(const CPDF_Array *poArray) : m_poArray(poArray)
    2226             :     {
    2227        1343 :     }
    2228             : 
    2229             :     virtual int GetLength() override;
    2230             :     virtual GDALPDFObject *Get(int nIndex) override;
    2231             : };
    2232             : 
    2233             : /************************************************************************/
    2234             : /* ==================================================================== */
    2235             : /*                          GDALPDFStreamPdfium                         */
    2236             : /* ==================================================================== */
    2237             : /************************************************************************/
    2238             : 
    2239             : class GDALPDFStreamPdfium : public GDALPDFStream
    2240             : {
    2241             :   private:
    2242             :     RetainPtr<const CPDF_Stream> m_pStream;
    2243             :     int64_t m_nSize = 0;
    2244             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pData = nullptr;
    2245             :     int64_t m_nRawSize = 0;
    2246             :     std::unique_ptr<uint8_t, VSIFreeReleaser> m_pRawData = nullptr;
    2247             : 
    2248             :     void Decompress();
    2249             :     void FillRaw();
    2250             : 
    2251             :   public:
    2252         489 :     GDALPDFStreamPdfium(RetainPtr<const CPDF_Stream> pStream)
    2253         489 :         : m_pStream(std::move(pStream))
    2254             :     {
    2255         489 :     }
    2256             : 
    2257             :     virtual int64_t GetLength(int64_t nMaxSize = 0) override;
    2258             :     virtual char *GetBytes() override;
    2259             : 
    2260             :     virtual int64_t GetRawLength() override;
    2261             :     virtual char *GetRawBytes() override;
    2262             : };
    2263             : 
    2264             : /************************************************************************/
    2265             : /* ==================================================================== */
    2266             : /*                          GDALPDFObjectPdfium                         */
    2267             : /* ==================================================================== */
    2268             : /************************************************************************/
    2269             : 
    2270             : /************************************************************************/
    2271             : /*                          GDALPDFObjectPdfium()                       */
    2272             : /************************************************************************/
    2273             : 
    2274       16531 : GDALPDFObjectPdfium::GDALPDFObjectPdfium(RetainPtr<const CPDF_Object> obj)
    2275       16531 :     : m_obj(std::move(obj))
    2276             : {
    2277       16531 :     CPLAssert(m_obj != nullptr);
    2278       16531 : }
    2279             : 
    2280             : /************************************************************************/
    2281             : /*                         ~GDALPDFObjectPdfium()                       */
    2282             : /************************************************************************/
    2283             : 
    2284       33062 : GDALPDFObjectPdfium::~GDALPDFObjectPdfium()
    2285             : {
    2286       16531 :     delete m_poDict;
    2287       16531 :     delete m_poArray;
    2288       16531 :     delete m_poStream;
    2289       33062 : }
    2290             : 
    2291             : /************************************************************************/
    2292             : /*                               Build()                                */
    2293             : /************************************************************************/
    2294             : 
    2295             : GDALPDFObjectPdfium *
    2296       19705 : GDALPDFObjectPdfium::Build(RetainPtr<const CPDF_Object> obj)
    2297             : {
    2298       19705 :     if (obj == nullptr)
    2299        3174 :         return nullptr;
    2300       16531 :     if (obj->GetType() == CPDF_Object::Type::kReference)
    2301             :     {
    2302        3948 :         obj = obj->GetDirect();
    2303        3948 :         if (obj == nullptr)
    2304             :         {
    2305           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2306             :                      "Cannot resolve indirect object");
    2307           0 :             return nullptr;
    2308             :         }
    2309             :     }
    2310       16531 :     return new GDALPDFObjectPdfium(std::move(obj));
    2311             : }
    2312             : 
    2313             : /************************************************************************/
    2314             : /*                               GetType()                              */
    2315             : /************************************************************************/
    2316             : 
    2317       59415 : GDALPDFObjectType GDALPDFObjectPdfium::GetType()
    2318             : {
    2319       59415 :     switch (m_obj->GetType())
    2320             :     {
    2321           0 :         case CPDF_Object::Type::kNullobj:
    2322           0 :             return PDFObjectType_Null;
    2323           0 :         case CPDF_Object::Type::kBoolean:
    2324           0 :             return PDFObjectType_Bool;
    2325       15813 :         case CPDF_Object::Type::kNumber:
    2326             :             return (cpl::down_cast<const CPDF_Number *>(m_obj.Get()))
    2327       15813 :                            ->IsInteger()
    2328       15813 :                        ? PDFObjectType_Int
    2329       15813 :                        : PDFObjectType_Real;
    2330        3692 :         case CPDF_Object::Type::kString:
    2331        3692 :             return PDFObjectType_String;
    2332        6775 :         case CPDF_Object::Type::kName:
    2333        6775 :             return PDFObjectType_Name;
    2334       14314 :         case CPDF_Object::Type::kArray:
    2335       14314 :             return PDFObjectType_Array;
    2336       14528 :         case CPDF_Object::Type::kDictionary:
    2337       14528 :             return PDFObjectType_Dictionary;
    2338        4293 :         case CPDF_Object::Type::kStream:
    2339        4293 :             return PDFObjectType_Dictionary;
    2340           0 :         case CPDF_Object::Type::kReference:
    2341             :             // unresolved reference
    2342           0 :             return PDFObjectType_Unknown;
    2343           0 :         default:
    2344           0 :             CPLAssert(false);
    2345             :             return PDFObjectType_Unknown;
    2346             :     }
    2347             : }
    2348             : 
    2349             : /************************************************************************/
    2350             : /*                          GetTypeNameNative()                         */
    2351             : /************************************************************************/
    2352             : 
    2353           0 : const char *GDALPDFObjectPdfium::GetTypeNameNative()
    2354             : {
    2355           0 :     if (m_obj->GetType() == CPDF_Object::Type::kStream)
    2356           0 :         return "stream";
    2357             :     else
    2358           0 :         return "";
    2359             : }
    2360             : 
    2361             : /************************************************************************/
    2362             : /*                              GetBool()                               */
    2363             : /************************************************************************/
    2364             : 
    2365           0 : int GDALPDFObjectPdfium::GetBool()
    2366             : {
    2367           0 :     return m_obj->GetInteger();
    2368             : }
    2369             : 
    2370             : /************************************************************************/
    2371             : /*                              GetInt()                                */
    2372             : /************************************************************************/
    2373             : 
    2374        5647 : int GDALPDFObjectPdfium::GetInt()
    2375             : {
    2376        5647 :     return m_obj->GetInteger();
    2377             : }
    2378             : 
    2379             : /************************************************************************/
    2380             : /*                       CPLRoundToMoreLikelyDouble()                   */
    2381             : /************************************************************************/
    2382             : 
    2383             : // We try to compensate for rounding errors when converting the number
    2384             : // in the PDF expressed as a string (e.g 297.84) to float32 by pdfium :
    2385             : // 297.8399963378906 Which is technically correct per the PDF spec, but in
    2386             : // practice poppler or podofo use double and Geospatial PDF are often encoded
    2387             : // with double precision.
    2388             : 
    2389        1266 : static double CPLRoundToMoreLikelyDouble(float f)
    2390             : {
    2391        1266 :     if (std::round(f) == f)
    2392           0 :         return f;
    2393             : 
    2394             :     char szBuffer[80];
    2395        1266 :     CPLsnprintf(szBuffer, 80, "%f\n", f);
    2396        1266 :     double d = f;
    2397        1266 :     char *pszDot = strchr(szBuffer, '.');
    2398        1266 :     if (pszDot == nullptr)
    2399           0 :         return d;
    2400        1266 :     pszDot++;
    2401        1266 :     if (pszDot[0] == 0 || pszDot[1] == 0)
    2402           0 :         return d;
    2403        1266 :     if (STARTS_WITH(pszDot + 2, "99"))
    2404             :     {
    2405           9 :         pszDot[2] = 0;
    2406           9 :         double d2 = CPLAtof(szBuffer) + 0.01;
    2407           9 :         float f2 = static_cast<float>(d2);
    2408          18 :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2409           9 :             nextafterf(f, f - 1.0f) == f2)
    2410           0 :             d = d2;
    2411             :     }
    2412        1257 :     else if (STARTS_WITH(pszDot + 2, "00"))
    2413             :     {
    2414          89 :         pszDot[2] = 0;
    2415          89 :         double d2 = CPLAtof(szBuffer);
    2416          89 :         float f2 = static_cast<float>(d2);
    2417         100 :         if (f == f2 || nextafterf(f, f + 1.0f) == f2 ||
    2418          11 :             nextafterf(f, f - 1.0f) == f2)
    2419          86 :             d = d2;
    2420             :     }
    2421        1266 :     return d;
    2422             : }
    2423             : 
    2424             : /************************************************************************/
    2425             : /*                              GetReal()                               */
    2426             : /************************************************************************/
    2427             : 
    2428        1266 : double GDALPDFObjectPdfium::GetReal()
    2429             : {
    2430        1266 :     return CPLRoundToMoreLikelyDouble(m_obj->GetNumber());
    2431             : }
    2432             : 
    2433             : /************************************************************************/
    2434             : /*                              GetString()                             */
    2435             : /************************************************************************/
    2436             : 
    2437        1623 : const std::string &GDALPDFObjectPdfium::GetString()
    2438             : {
    2439        1623 :     if (GetType() == PDFObjectType_String)
    2440             :     {
    2441        3246 :         const auto bs = m_obj->GetString();
    2442             :         // If empty string, code crashes
    2443        1623 :         if (bs.IsEmpty())
    2444           1 :             return (osStr = "");
    2445        1622 :         return (osStr = GDALPDFGetUTF8StringFromBytes(
    2446        1622 :                     reinterpret_cast<const GByte *>(bs.c_str()),
    2447        3244 :                     static_cast<int>(bs.GetLength())));
    2448             :     }
    2449             :     else
    2450           0 :         return (osStr = "");
    2451             : }
    2452             : 
    2453             : /************************************************************************/
    2454             : /*                              GetName()                               */
    2455             : /************************************************************************/
    2456             : 
    2457        3010 : const std::string &GDALPDFObjectPdfium::GetName()
    2458             : {
    2459        3010 :     if (GetType() == PDFObjectType_Name)
    2460        3010 :         return (osStr = m_obj->GetString().c_str());
    2461             :     else
    2462           0 :         return (osStr = "");
    2463             : }
    2464             : 
    2465             : /************************************************************************/
    2466             : /*                             GetDictionary()                          */
    2467             : /************************************************************************/
    2468             : 
    2469        8611 : GDALPDFDictionary *GDALPDFObjectPdfium::GetDictionary()
    2470             : {
    2471        8611 :     if (GetType() != PDFObjectType_Dictionary)
    2472           0 :         return nullptr;
    2473             : 
    2474        8611 :     if (m_poDict)
    2475        3381 :         return m_poDict;
    2476             : 
    2477        5230 :     m_poDict = new GDALPDFDictionaryPdfium(m_obj->GetDict());
    2478        5230 :     return m_poDict;
    2479             : }
    2480             : 
    2481             : /************************************************************************/
    2482             : /*                                GetArray()                            */
    2483             : /************************************************************************/
    2484             : 
    2485        7108 : GDALPDFArray *GDALPDFObjectPdfium::GetArray()
    2486             : {
    2487        7108 :     if (GetType() != PDFObjectType_Array)
    2488           0 :         return nullptr;
    2489             : 
    2490        7108 :     if (m_poArray)
    2491        5765 :         return m_poArray;
    2492             : 
    2493        1343 :     m_poArray =
    2494        1343 :         new GDALPDFArrayPdfium(cpl::down_cast<const CPDF_Array *>(m_obj.Get()));
    2495        1343 :     return m_poArray;
    2496             : }
    2497             : 
    2498             : /************************************************************************/
    2499             : /*                               GetStream()                            */
    2500             : /************************************************************************/
    2501             : 
    2502         638 : GDALPDFStream *GDALPDFObjectPdfium::GetStream()
    2503             : {
    2504         638 :     if (m_obj->GetType() != CPDF_Object::Type::kStream)
    2505          16 :         return nullptr;
    2506             : 
    2507         622 :     if (m_poStream)
    2508         133 :         return m_poStream;
    2509         978 :     auto pStream = pdfium::WrapRetain(m_obj->AsStream());
    2510         489 :     if (pStream)
    2511             :     {
    2512         489 :         m_poStream = new GDALPDFStreamPdfium(std::move(pStream));
    2513         489 :         return m_poStream;
    2514             :     }
    2515             :     else
    2516           0 :         return nullptr;
    2517             : }
    2518             : 
    2519             : /************************************************************************/
    2520             : /*                               GetRefNum()                            */
    2521             : /************************************************************************/
    2522             : 
    2523        2188 : GDALPDFObjectNum GDALPDFObjectPdfium::GetRefNum()
    2524             : {
    2525        2188 :     return GDALPDFObjectNum(m_obj->GetObjNum());
    2526             : }
    2527             : 
    2528             : /************************************************************************/
    2529             : /*                               GetRefGen()                            */
    2530             : /************************************************************************/
    2531             : 
    2532        1580 : int GDALPDFObjectPdfium::GetRefGen()
    2533             : {
    2534        1580 :     return m_obj->GetGenNum();
    2535             : }
    2536             : 
    2537             : /************************************************************************/
    2538             : /* ==================================================================== */
    2539             : /*                         GDALPDFDictionaryPdfium                      */
    2540             : /* ==================================================================== */
    2541             : /************************************************************************/
    2542             : 
    2543             : /************************************************************************/
    2544             : /*                         ~GDALPDFDictionaryPdfium()                   */
    2545             : /************************************************************************/
    2546             : 
    2547       10460 : GDALPDFDictionaryPdfium::~GDALPDFDictionaryPdfium()
    2548             : {
    2549        5230 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.begin();
    2550        5230 :     std::map<CPLString, GDALPDFObject *>::iterator oEnd = m_map.end();
    2551       15276 :     for (; oIter != oEnd; ++oIter)
    2552       10046 :         delete oIter->second;
    2553       10460 : }
    2554             : 
    2555             : /************************************************************************/
    2556             : /*                                  Get()                               */
    2557             : /************************************************************************/
    2558             : 
    2559       13712 : GDALPDFObject *GDALPDFDictionaryPdfium::Get(const char *pszKey)
    2560             : {
    2561       13712 :     std::map<CPLString, GDALPDFObject *>::iterator oIter = m_map.find(pszKey);
    2562       13712 :     if (oIter != m_map.end())
    2563        2368 :         return oIter->second;
    2564             : 
    2565       22688 :     ByteString pdfiumKey(pszKey);
    2566             :     GDALPDFObjectPdfium *poObj =
    2567       11344 :         GDALPDFObjectPdfium::Build(m_poDict->GetObjectFor(pdfiumKey));
    2568       11344 :     if (poObj)
    2569             :     {
    2570        8364 :         m_map[pszKey] = poObj;
    2571        8364 :         return poObj;
    2572             :     }
    2573             :     else
    2574             :     {
    2575        2980 :         return nullptr;
    2576             :     }
    2577             : }
    2578             : 
    2579             : /************************************************************************/
    2580             : /*                              GetValues()                             */
    2581             : /************************************************************************/
    2582             : 
    2583         485 : std::map<CPLString, GDALPDFObject *> &GDALPDFDictionaryPdfium::GetValues()
    2584             : {
    2585         485 :     CPDF_DictionaryLocker dictIterator(m_poDict);
    2586        2360 :     for (const auto &iter : dictIterator)
    2587             :     {
    2588             :         // No object for this key
    2589        1875 :         if (!iter.second)
    2590           0 :             continue;
    2591             : 
    2592        1875 :         const char *pszKey = iter.first.c_str();
    2593             :         // Objects exists in the map
    2594        1875 :         if (m_map.find(pszKey) != m_map.end())
    2595         193 :             continue;
    2596        1682 :         GDALPDFObjectPdfium *poObj = GDALPDFObjectPdfium::Build(iter.second);
    2597        1682 :         if (poObj == nullptr)
    2598           0 :             continue;
    2599        1682 :         m_map[pszKey] = poObj;
    2600             :     }
    2601             : 
    2602         970 :     return m_map;
    2603             : }
    2604             : 
    2605             : /************************************************************************/
    2606             : /* ==================================================================== */
    2607             : /*                           GDALPDFArrayPdfium                         */
    2608             : /* ==================================================================== */
    2609             : /************************************************************************/
    2610             : 
    2611             : /************************************************************************/
    2612             : /*                              GetLength()                             */
    2613             : /************************************************************************/
    2614             : 
    2615       10015 : int GDALPDFArrayPdfium::GetLength()
    2616             : {
    2617       10015 :     return static_cast<int>(m_poArray->size());
    2618             : }
    2619             : 
    2620             : /************************************************************************/
    2621             : /*                                Get()                                 */
    2622             : /************************************************************************/
    2623             : 
    2624        6801 : GDALPDFObject *GDALPDFArrayPdfium::Get(int nIndex)
    2625             : {
    2626        6801 :     if (nIndex < 0 || nIndex >= GetLength())
    2627           0 :         return nullptr;
    2628             : 
    2629        6801 :     if (m_v.empty())
    2630        1308 :         m_v.resize(GetLength());
    2631             : 
    2632        6801 :     if (m_v[nIndex] != nullptr)
    2633        1046 :         return m_v[nIndex].get();
    2634             : 
    2635             :     auto poObj = std::unique_ptr<GDALPDFObjectPdfium>(
    2636       11510 :         GDALPDFObjectPdfium::Build(m_poArray->GetObjectAt(nIndex)));
    2637        5755 :     if (poObj == nullptr)
    2638           0 :         return nullptr;
    2639        5755 :     m_v[nIndex] = std::move(poObj);
    2640        5755 :     return m_v[nIndex].get();
    2641             : }
    2642             : 
    2643             : /************************************************************************/
    2644             : /* ==================================================================== */
    2645             : /*                           GDALPDFStreamPdfium                        */
    2646             : /* ==================================================================== */
    2647             : /************************************************************************/
    2648             : 
    2649        1148 : void GDALPDFStreamPdfium::Decompress()
    2650             : {
    2651        1148 :     if (m_pData != nullptr)
    2652         661 :         return;
    2653         974 :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2654         487 :     acc->LoadAllDataFiltered();
    2655         487 :     m_nSize = static_cast<int64_t>(acc->GetSize());
    2656         487 :     m_pData.reset();
    2657         487 :     const auto nSize = static_cast<size_t>(m_nSize);
    2658         487 :     if (static_cast<int64_t>(nSize) != m_nSize)
    2659             :     {
    2660           0 :         m_nSize = 0;
    2661             :     }
    2662         487 :     if (m_nSize)
    2663             :     {
    2664         485 :         m_pData.reset(static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(nSize)));
    2665         485 :         if (!m_pData)
    2666           0 :             m_nSize = 0;
    2667             :         else
    2668         485 :             memcpy(&m_pData.get()[0], acc->DetachData().data(), nSize);
    2669             :     }
    2670             : }
    2671             : 
    2672             : /************************************************************************/
    2673             : /*                              GetLength()                             */
    2674             : /************************************************************************/
    2675             : 
    2676        1148 : int64_t GDALPDFStreamPdfium::GetLength(int64_t /* nMaxSize */)
    2677             : {
    2678        1148 :     Decompress();
    2679        1148 :     return m_nSize;
    2680             : }
    2681             : 
    2682             : /************************************************************************/
    2683             : /*                               GetBytes()                             */
    2684             : /************************************************************************/
    2685             : 
    2686         559 : char *GDALPDFStreamPdfium::GetBytes()
    2687             : {
    2688         559 :     size_t nLength = static_cast<size_t>(GetLength());
    2689         559 :     if (nLength == 0)
    2690           2 :         return nullptr;
    2691         557 :     char *pszContent = static_cast<char *>(VSI_MALLOC_VERBOSE(nLength + 1));
    2692         557 :     if (!pszContent)
    2693           0 :         return nullptr;
    2694         557 :     memcpy(pszContent, m_pData.get(), nLength);
    2695         557 :     pszContent[nLength] = '\0';
    2696         557 :     return pszContent;
    2697             : }
    2698             : 
    2699             : /************************************************************************/
    2700             : /*                                FillRaw()                             */
    2701             : /************************************************************************/
    2702             : 
    2703          65 : void GDALPDFStreamPdfium::FillRaw()
    2704             : {
    2705          65 :     if (m_pRawData != nullptr)
    2706           2 :         return;
    2707         126 :     auto acc(pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream));
    2708          63 :     acc->LoadAllDataRaw();
    2709          63 :     m_nRawSize = static_cast<int64_t>(acc->GetSize());
    2710          63 :     m_pRawData.reset();
    2711          63 :     const auto nSize = static_cast<size_t>(m_nRawSize);
    2712          63 :     if (static_cast<int64_t>(nSize) != m_nRawSize)
    2713             :     {
    2714           0 :         m_nRawSize = 0;
    2715             :     }
    2716          63 :     if (m_nRawSize)
    2717             :     {
    2718         126 :         m_pRawData.reset(
    2719          63 :             static_cast<uint8_t *>(VSI_MALLOC_VERBOSE(m_nRawSize)));
    2720          63 :         if (!m_pRawData)
    2721           0 :             m_nRawSize = 0;
    2722             :         else
    2723          63 :             memcpy(&m_pRawData.get()[0], acc->DetachData().data(), m_nRawSize);
    2724             :     }
    2725             : }
    2726             : 
    2727             : /************************************************************************/
    2728             : /*                            GetRawLength()                            */
    2729             : /************************************************************************/
    2730             : 
    2731          65 : int64_t GDALPDFStreamPdfium::GetRawLength()
    2732             : {
    2733          65 :     FillRaw();
    2734          65 :     return m_nRawSize;
    2735             : }
    2736             : 
    2737             : /************************************************************************/
    2738             : /*                             GetRawBytes()                            */
    2739             : /************************************************************************/
    2740             : 
    2741           2 : char *GDALPDFStreamPdfium::GetRawBytes()
    2742             : {
    2743           2 :     size_t nLength = static_cast<size_t>(GetRawLength());
    2744           2 :     if (nLength == 0)
    2745           0 :         return nullptr;
    2746             :     char *pszContent =
    2747           2 :         static_cast<char *>(VSI_MALLOC_VERBOSE(sizeof(char) * (nLength + 1)));
    2748           2 :     if (!pszContent)
    2749           0 :         return nullptr;
    2750           2 :     memcpy(pszContent, m_pRawData.get(), nLength);
    2751           2 :     pszContent[nLength] = '\0';
    2752           2 :     return pszContent;
    2753             : }
    2754             : 
    2755             : #endif  // HAVE_PDFIUM

Generated by: LCOV version 1.14