LCOV - code coverage report
Current view: top level - frmts/pdf - pdfobject.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 690 836 82.5 %
Date: 2024-05-04 12:52:34 Functions: 116 126 92.1 %

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

Generated by: LCOV version 1.14