Coverage Report

Created: 2025-06-09 07:02

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