Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sdext/source/pdfimport/pdfparse/pdfentries.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
21
#include <pdfparse.hxx>
22
23
#include <comphelper/hash.hxx>
24
25
#include <o3tl/numeric.hxx>
26
#include <rtl/strbuf.hxx>
27
#include <rtl/ustring.hxx>
28
#include <rtl/ustrbuf.hxx>
29
#include <rtl/digest.h>
30
#include <rtl/cipher.h>
31
#include <sal/log.hxx>
32
33
#include <zlib.h>
34
35
#include <math.h>
36
#include <map>
37
38
#include <string.h>
39
40
41
namespace pdfparse
42
{
43
44
struct EmitImplData
45
{
46
    // xref table: maps object number to a pair of (generation, buffer offset)
47
    typedef std::map< unsigned int, std::pair< unsigned int, unsigned int > > XRefTable;
48
    XRefTable m_aXRefTable;
49
    // container of all indirect objects (usually a PDFFile*)
50
    const PDFContainer* m_pObjectContainer;
51
    unsigned int m_nDecryptObject;
52
    unsigned int m_nDecryptGeneration;
53
54
    // returns true if the xref table was updated
55
    bool insertXref( unsigned int nObject, unsigned int nGeneration, unsigned int nOffset )
56
0
    {
57
0
        XRefTable::iterator it = m_aXRefTable.find( nObject );
58
0
        if( it == m_aXRefTable.end() )
59
0
        {
60
            // new entry
61
0
            m_aXRefTable[ nObject ] = std::pair<unsigned int, unsigned int>(nGeneration,nOffset);
62
0
            return true;
63
0
        }
64
        // update old entry, if generation number is higher
65
0
        if( it->second.first < nGeneration )
66
0
        {
67
0
            it->second = std::pair<unsigned int, unsigned int>(nGeneration,nOffset);
68
0
            return true;
69
0
        }
70
0
        return false;
71
0
    }
72
73
    explicit EmitImplData( const PDFContainer* pTopContainer ) :
74
0
        m_pObjectContainer( pTopContainer ),
75
0
        m_nDecryptObject( 0 ),
76
0
        m_nDecryptGeneration( 0 )
77
0
    {}
78
    void decrypt( const sal_uInt8* pInBuffer, sal_uInt32 nLen, sal_uInt8* pOutBuffer,
79
                  unsigned int nObject, unsigned int nGeneration ) const
80
0
    {
81
0
        const PDFFile* pFile = dynamic_cast<const PDFFile*>(m_pObjectContainer);
82
0
        pFile && pFile->decrypt( pInBuffer, nLen, pOutBuffer, nObject, nGeneration );
83
0
    }
84
85
    void setDecryptObject( unsigned int nObject, unsigned int nGeneration )
86
0
    {
87
0
        m_nDecryptObject = nObject;
88
0
        m_nDecryptGeneration = nGeneration;
89
0
    }
90
};
91
92
}
93
94
using namespace pdfparse;
95
96
EmitContext::EmitContext( const PDFContainer* pTop ) :
97
0
    m_bDeflate( false ),
98
0
    m_bDecrypt( false )
99
0
{
100
0
    if( pTop )
101
0
        m_pImplData.reset( new EmitImplData( pTop ) );
102
0
}
103
104
EmitContext::~EmitContext()
105
0
{
106
0
}
107
108
PDFEntry::~PDFEntry()
109
0
{
110
0
}
111
112
EmitImplData* PDFEntry::getEmitData( EmitContext const & rContext )
113
0
{
114
0
    return rContext.m_pImplData.get();
115
0
}
116
117
void PDFEntry::setEmitData( EmitContext& rContext, EmitImplData* pNewEmitData )
118
0
{
119
0
    if( rContext.m_pImplData && rContext.m_pImplData.get() != pNewEmitData )
120
0
        rContext.m_pImplData.reset();
121
0
    rContext.m_pImplData.reset( pNewEmitData );
122
0
}
123
124
PDFValue::~PDFValue()
125
{
126
}
127
128
PDFComment::~PDFComment()
129
0
{
130
0
}
131
132
bool PDFComment::emit( EmitContext& rWriteContext ) const
133
0
{
134
0
    return rWriteContext.write( m_aComment.getStr(), m_aComment.getLength() );
135
0
}
136
137
PDFEntry* PDFComment::clone() const
138
0
{
139
0
    return new PDFComment( m_aComment );
140
0
}
141
142
PDFName::~PDFName()
143
0
{
144
0
}
145
146
bool PDFName::emit( EmitContext& rWriteContext ) const
147
0
{
148
0
    if( ! rWriteContext.write( " /", 2 ) )
149
0
        return false;
150
0
    return rWriteContext.write( m_aName.getStr(), m_aName.getLength() );
151
0
}
152
153
PDFEntry* PDFName::clone() const
154
0
{
155
0
    return new PDFName( m_aName );
156
0
}
157
158
OUString PDFName::getFilteredName() const
159
0
{
160
0
    OStringBuffer aFilter( m_aName.getLength() );
161
0
    const char* pStr = m_aName.getStr();
162
0
    unsigned int nLen = m_aName.getLength();
163
0
    for( unsigned int i = 0; i < nLen; i++ )
164
0
    {
165
0
        if( (i + 2 < nLen) && pStr[i] == '#' )
166
0
        {
167
0
            aFilter.append(o3tl::convertToHex<char, 0>(pStr[i + 1], pStr[i + 2]));
168
0
            i += 2;
169
0
        }
170
0
        else
171
0
            aFilter.append( pStr[i] );
172
0
    }
173
0
    return OStringToOUString( aFilter, RTL_TEXTENCODING_UTF8 );
174
0
}
175
176
PDFString::~PDFString()
177
0
{
178
0
}
179
180
bool PDFString::emit( EmitContext& rWriteContext ) const
181
0
{
182
0
    if( ! rWriteContext.write( " ", 1 ) )
183
0
        return false;
184
0
    EmitImplData* pEData = getEmitData( rWriteContext );
185
0
    if( rWriteContext.m_bDecrypt && pEData && pEData->m_nDecryptObject )
186
0
    {
187
0
        OString aFiltered( getFilteredString() );
188
        // decrypt inplace (evil since OString is supposed to be const
189
        // however in this case we know that getFilteredString returned a singular string instance
190
0
        pEData->decrypt( reinterpret_cast<sal_uInt8 const *>(aFiltered.getStr()), aFiltered.getLength(),
191
0
                         reinterpret_cast<sal_uInt8 *>(const_cast<char *>(aFiltered.getStr())),
192
0
                         pEData->m_nDecryptObject, pEData->m_nDecryptGeneration );
193
        // check for string or hex string
194
0
        const char* pStr = aFiltered.getStr();
195
0
        if( aFiltered.getLength() > 1 &&
196
0
           ( (static_cast<unsigned char>(pStr[0]) == 0xff && static_cast<unsigned char>(pStr[1]) == 0xfe) ||
197
0
             (static_cast<unsigned char>(pStr[0]) == 0xfe && static_cast<unsigned char>(pStr[1]) == 0xff) ) )
198
0
        {
199
0
            static const char pHexTab[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
200
0
                                              '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
201
0
            if( ! rWriteContext.write( "<", 1 ) )
202
0
                return false;
203
0
            for( sal_Int32 i = 0; i < aFiltered.getLength(); i++ )
204
0
            {
205
0
                if( ! rWriteContext.write( pHexTab + ((sal_uInt32(pStr[i]) >> 4) & 0x0f), 1 ) )
206
0
                    return false;
207
0
                if( ! rWriteContext.write( pHexTab + (sal_uInt32(pStr[i]) & 0x0f), 1 ) )
208
0
                    return false;
209
0
            }
210
0
            if( ! rWriteContext.write( ">", 1 ) )
211
0
                return false;
212
0
        }
213
0
        else
214
0
        {
215
0
            if( ! rWriteContext.write( "(", 1 ) )
216
0
                return false;
217
0
            if( ! rWriteContext.write( aFiltered.getStr(), aFiltered.getLength() ) )
218
0
                return false;
219
0
            if( ! rWriteContext.write( ")", 1 ) )
220
0
                return false;
221
0
        }
222
0
        return true;
223
0
    }
224
0
    return rWriteContext.write( m_aString.getStr(), m_aString.getLength() );
225
0
}
226
227
PDFEntry* PDFString::clone() const
228
0
{
229
0
    return new PDFString( m_aString );
230
0
}
231
232
OString PDFString::getFilteredString() const
233
0
{
234
0
    int nLen = m_aString.getLength();
235
0
    OStringBuffer aBuf( nLen );
236
237
0
    const char* pStr = m_aString.getStr();
238
0
    if( *pStr == '(' )
239
0
    {
240
0
        const char* pRun = pStr+1;
241
0
        while( pRun - pStr < nLen-1 )
242
0
        {
243
0
            if( *pRun == '\\' )
244
0
            {
245
0
                pRun++;
246
0
                if( pRun - pStr < nLen )
247
0
                {
248
0
                    char aEsc = 0;
249
0
                    if( *pRun == 'n' )
250
0
                        aEsc = '\n';
251
0
                    else if( *pRun == 'r' )
252
0
                        aEsc = '\r';
253
0
                    else if( *pRun == 't' )
254
0
                        aEsc = '\t';
255
0
                    else if( *pRun == 'b' )
256
0
                        aEsc = '\b';
257
0
                    else if( *pRun == 'f' )
258
0
                        aEsc = '\f';
259
0
                    else if( *pRun == '(' )
260
0
                        aEsc = '(';
261
0
                    else if( *pRun == ')' )
262
0
                        aEsc = ')';
263
0
                    else if( *pRun == '\\' )
264
0
                        aEsc = '\\';
265
0
                    else if( *pRun == '\n' )
266
0
                    {
267
0
                        pRun++;
268
0
                        continue;
269
0
                    }
270
0
                    else if( *pRun == '\r' )
271
0
                    {
272
0
                        pRun++;
273
0
                        if( *pRun == '\n' )
274
0
                            pRun++;
275
0
                        continue;
276
0
                    }
277
0
                    else
278
0
                    {
279
0
                        int i = 0;
280
0
                        while( i++ < 3 && *pRun >= '0' && *pRun <= '7' )
281
0
                            aEsc = 8*aEsc + (*pRun++ - '0');
282
                        // move pointer back to last character of octal sequence
283
0
                        pRun--;
284
0
                    }
285
0
                    aBuf.append( aEsc );
286
0
                }
287
0
            }
288
0
            else
289
0
                aBuf.append( *pRun );
290
            // move pointer to next character
291
0
            pRun++;
292
0
        }
293
0
    }
294
0
    else if( *pStr == '<' )
295
0
    {
296
0
        const char* pRun = pStr+1;
297
0
        while( *pRun != '>' && pRun - pStr < nLen )
298
0
        {
299
0
            char rResult = 0;
300
0
            if( *pRun >= '0' && *pRun <= '9' )
301
0
                rResult = char( ( *pRun-'0' ) << 4 );
302
0
            else if( *pRun >= 'a' && *pRun <= 'f' )
303
0
                rResult = char( ( *pRun-'a' + 10 ) << 4 );
304
0
            else if( *pRun >= 'A' && *pRun <= 'F' )
305
0
                rResult = char( ( *pRun-'A' + 10 ) << 4 );
306
0
            pRun++;
307
0
            if( *pRun != '>' && pRun - pStr < nLen )
308
0
            {
309
0
                if( *pRun >= '0' && *pRun <= '9' )
310
0
                    rResult |= char( *pRun-'0' );
311
0
                else if( *pRun >= 'a' && *pRun <= 'f' )
312
0
                    rResult |= char( *pRun-'a' + 10 );
313
0
                else if( *pRun >= 'A' && *pRun <= 'F' )
314
0
                    rResult |= char( *pRun-'A' + 10 );
315
0
            }
316
0
            pRun++;
317
0
            aBuf.append( rResult );
318
0
        }
319
0
    }
320
321
0
    return aBuf.makeStringAndClear();
322
0
}
323
324
PDFNumber::~PDFNumber()
325
{
326
}
327
328
bool PDFNumber::emit( EmitContext& rWriteContext ) const
329
0
{
330
0
    OStringBuffer aBuf( 32 );
331
0
    aBuf.append( ' ' );
332
333
0
    double fValue = m_fValue;
334
0
    bool bNeg = false;
335
0
    int nPrecision = 5;
336
0
    if( fValue < 0.0 )
337
0
    {
338
0
        bNeg = true;
339
0
        fValue=-fValue;
340
0
    }
341
342
0
    sal_Int64 nInt = static_cast<sal_Int64>(fValue);
343
0
    fValue -= static_cast<double>(nInt);
344
    // optimizing hardware may lead to a value of 1.0 after the subtraction
345
0
    if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
346
0
    {
347
0
        nInt++;
348
0
        fValue = 0.0;
349
0
    }
350
0
    sal_Int64 nFrac = 0;
351
0
    if( fValue )
352
0
    {
353
0
        fValue *= pow( 10.0, static_cast<double>(nPrecision) );
354
0
        nFrac = static_cast<sal_Int64>(fValue);
355
0
    }
356
0
    if( bNeg && ( nInt || nFrac ) )
357
0
        aBuf.append( '-' );
358
0
    aBuf.append( nInt );
359
0
    if( nFrac )
360
0
    {
361
0
        int i;
362
0
        aBuf.append( '.' );
363
0
        sal_Int64 nBound = static_cast<sal_Int64>(pow( 10.0, nPrecision - 1.0 )+0.5);
364
0
        for ( i = 0; ( i < nPrecision ) && nFrac; i++ )
365
0
        {
366
0
            sal_Int64 nNumb = nFrac / nBound;
367
0
            nFrac -= nNumb * nBound;
368
0
            aBuf.append( nNumb );
369
0
            nBound /= 10;
370
0
        }
371
0
    }
372
373
0
    return rWriteContext.write( aBuf.getStr(), aBuf.getLength() );
374
0
}
375
376
PDFEntry* PDFNumber::clone() const
377
0
{
378
0
    return new PDFNumber( m_fValue );
379
0
}
380
381
382
PDFBool::~PDFBool()
383
{
384
}
385
386
bool PDFBool::emit( EmitContext& rWriteContext ) const
387
0
{
388
0
    return m_bValue ? rWriteContext.write( " true", 5 ) : rWriteContext.write( " false", 6 );
389
0
}
390
391
PDFEntry* PDFBool::clone() const
392
0
{
393
0
    return new PDFBool( m_bValue );
394
0
}
395
396
PDFNull::~PDFNull()
397
{
398
}
399
400
bool PDFNull::emit( EmitContext& rWriteContext ) const
401
0
{
402
0
    return rWriteContext.write( " null", 5 );
403
0
}
404
405
PDFEntry* PDFNull::clone() const
406
0
{
407
0
    return new PDFNull();
408
0
}
409
410
411
PDFObjectRef::~PDFObjectRef()
412
{
413
}
414
415
bool PDFObjectRef::emit( EmitContext& rWriteContext ) const
416
0
{
417
0
    OString aBuf =
418
0
        " " +
419
0
        OString::number( sal_Int32( m_nNumber ) ) +
420
0
        " " +
421
0
        OString::number( sal_Int32( m_nGeneration ) ) +
422
0
        " R";
423
0
    return rWriteContext.write( aBuf.getStr(), aBuf.getLength() );
424
0
}
425
426
PDFEntry* PDFObjectRef::clone() const
427
0
{
428
0
    return new PDFObjectRef( m_nNumber, m_nGeneration );
429
0
}
430
431
PDFContainer::~PDFContainer()
432
0
{
433
0
}
434
435
bool PDFContainer::emitSubElements( EmitContext& rWriteContext ) const
436
0
{
437
0
    int nEle = m_aSubElements.size();
438
0
    for( int i = 0; i < nEle; i++ )
439
0
    {
440
0
        if( rWriteContext.m_bDecrypt )
441
0
        {
442
0
            const PDFName* pName = dynamic_cast<PDFName*>(m_aSubElements[i].get());
443
0
            if (pName && pName->m_aName == "Encrypt")
444
0
            {
445
0
                i++;
446
0
                continue;
447
0
            }
448
0
        }
449
0
        if( ! m_aSubElements[i]->emit( rWriteContext ) )
450
0
            return false;
451
0
    }
452
0
    return true;
453
0
}
454
455
void PDFContainer::cloneSubElements( std::vector<std::unique_ptr<PDFEntry>>& rNewSubElements ) const
456
0
{
457
0
    int nEle = m_aSubElements.size();
458
0
    for( int i = 0; i < nEle; i++ )
459
0
        rNewSubElements.emplace_back( m_aSubElements[i]->clone() );
460
0
}
461
462
PDFObject* PDFContainer::findObject( unsigned int nNumber, unsigned int nGeneration ) const
463
0
{
464
0
    unsigned int nEle = m_aSubElements.size();
465
0
    for( unsigned int i = 0; i < nEle; i++ )
466
0
    {
467
0
        PDFObject* pObject = dynamic_cast<PDFObject*>(m_aSubElements[i].get());
468
0
        if( pObject &&
469
0
            pObject->m_nNumber == nNumber &&
470
0
            pObject->m_nGeneration == nGeneration )
471
0
        {
472
0
            return pObject;
473
0
        }
474
0
    }
475
0
    return nullptr;
476
0
}
477
478
PDFArray::~PDFArray()
479
{
480
}
481
482
bool PDFArray::emit( EmitContext& rWriteContext ) const
483
0
{
484
0
    if( ! rWriteContext.write( "[", 1 ) )
485
0
        return false;
486
0
    if( ! emitSubElements( rWriteContext ) )
487
0
        return false;
488
0
    return rWriteContext.write( "]", 1 );
489
0
}
490
491
PDFEntry* PDFArray::clone() const
492
0
{
493
0
    PDFArray* pNewAr = new PDFArray();
494
0
    cloneSubElements( pNewAr->m_aSubElements );
495
0
    return pNewAr;
496
0
}
497
498
PDFDict::~PDFDict()
499
0
{
500
0
}
501
502
bool PDFDict::emit( EmitContext& rWriteContext ) const
503
0
{
504
0
    if( ! rWriteContext.write( "<<\n", 3 ) )
505
0
        return false;
506
0
    if( ! emitSubElements( rWriteContext ) )
507
0
        return false;
508
0
    return rWriteContext.write( "\n>>\n", 4 );
509
0
}
510
511
void PDFDict::insertValue( const OString& rName, std::unique_ptr<PDFEntry> pValue )
512
0
{
513
0
    if( ! pValue )
514
0
        eraseValue( rName );
515
516
0
    PDFEntry* pValueTmp = nullptr;
517
0
    std::unordered_map<OString,PDFEntry*>::iterator it = m_aMap.find( rName );
518
0
    if( it == m_aMap.end() )
519
0
    {
520
        // new name/value, pair, append it
521
0
        m_aSubElements.emplace_back(std::make_unique<PDFName>(rName));
522
0
        m_aSubElements.emplace_back( std::move(pValue) );
523
0
        pValueTmp = m_aSubElements.back().get();
524
0
    }
525
0
    else
526
0
    {
527
0
        unsigned int nSub = m_aSubElements.size();
528
0
        for( unsigned int i = 0; i < nSub; i++ )
529
0
            if( m_aSubElements[i].get() == it->second )
530
0
            {
531
0
                m_aSubElements[i] = std::move(pValue);
532
0
                pValueTmp = m_aSubElements[i].get();
533
0
                break;
534
0
            }
535
0
    }
536
0
    assert(pValueTmp);
537
0
    m_aMap[ rName ] = pValueTmp;
538
0
}
539
540
void PDFDict::eraseValue( std::string_view rName )
541
0
{
542
0
    unsigned int nEle = m_aSubElements.size();
543
0
    for( unsigned int i = 0; i < nEle; i++ )
544
0
    {
545
0
        PDFName* pName = dynamic_cast<PDFName*>(m_aSubElements[i].get());
546
0
        if( pName && pName->m_aName == rName )
547
0
        {
548
0
            for( unsigned int j = i+1; j < nEle; j++ )
549
0
            {
550
0
                if( dynamic_cast<PDFComment*>(m_aSubElements[j].get()) == nullptr )
551
0
                {
552
                    // remove and free subelements from vector
553
0
                    m_aSubElements.erase( m_aSubElements.begin()+j );
554
0
                    m_aSubElements.erase( m_aSubElements.begin()+i );
555
0
                    buildMap();
556
0
                    return;
557
0
                }
558
0
            }
559
0
        }
560
0
    }
561
0
}
562
563
PDFEntry* PDFDict::buildMap()
564
0
{
565
    // clear map
566
0
    m_aMap.clear();
567
    // build map
568
0
    unsigned int nEle = m_aSubElements.size();
569
0
    PDFName* pName = nullptr;
570
0
    for( unsigned int i = 0; i < nEle; i++ )
571
0
    {
572
0
        if( dynamic_cast<PDFComment*>(m_aSubElements[i].get()) == nullptr )
573
0
        {
574
0
            if( pName )
575
0
            {
576
0
                m_aMap[ pName->m_aName ] = m_aSubElements[i].get();
577
0
                pName = nullptr;
578
0
            }
579
0
            else if( (pName = dynamic_cast<PDFName*>(m_aSubElements[i].get())) == nullptr )
580
0
                return m_aSubElements[i].get();
581
0
        }
582
0
    }
583
0
    return pName;
584
0
}
585
586
PDFEntry* PDFDict::clone() const
587
0
{
588
0
    PDFDict* pNewDict = new PDFDict();
589
0
    cloneSubElements( pNewDict->m_aSubElements );
590
0
    pNewDict->buildMap();
591
0
    return pNewDict;
592
0
}
593
594
PDFStream::~PDFStream()
595
{
596
}
597
598
bool PDFStream::emit( EmitContext& rWriteContext ) const
599
0
{
600
0
    return rWriteContext.copyOrigBytes( m_nBeginOffset, m_nEndOffset-m_nBeginOffset );
601
0
}
602
603
PDFEntry* PDFStream::clone() const
604
0
{
605
0
    return new PDFStream( m_nBeginOffset, m_nEndOffset, nullptr );
606
0
}
607
608
unsigned int PDFStream::getDictLength( const PDFContainer* pContainer ) const
609
0
{
610
0
    if( ! m_pDict )
611
0
        return 0;
612
    // find /Length entry, can either be a direct or indirect number object
613
0
    std::unordered_map<OString,PDFEntry*>::const_iterator it =
614
0
        m_pDict->m_aMap.find( "Length"_ostr );
615
0
    if( it == m_pDict->m_aMap.end() )
616
0
        return 0;
617
0
    PDFNumber* pNum = dynamic_cast<PDFNumber*>(it->second);
618
0
    if( ! pNum && pContainer )
619
0
    {
620
0
        PDFObjectRef* pRef = dynamic_cast<PDFObjectRef*>(it->second);
621
0
        if( pRef )
622
0
        {
623
0
            int nEle = pContainer->m_aSubElements.size();
624
0
            for (int i = 0; i < nEle; i++)
625
0
            {
626
0
                PDFObject* pObj = dynamic_cast<PDFObject*>(pContainer->m_aSubElements[i].get());
627
0
                if( pObj &&
628
0
                    pObj->m_nNumber == pRef->m_nNumber &&
629
0
                    pObj->m_nGeneration == pRef->m_nGeneration )
630
0
                {
631
0
                    if( pObj->m_pObject )
632
0
                        pNum = dynamic_cast<PDFNumber*>(pObj->m_pObject);
633
0
                    break;
634
0
                }
635
0
            }
636
0
        }
637
0
    }
638
0
    return pNum ? static_cast<unsigned int>(pNum->m_fValue) : 0;
639
0
}
640
641
PDFObject::~PDFObject()
642
{
643
}
644
645
bool PDFObject::getDeflatedStream( std::unique_ptr<char[]>& rpStream, unsigned int* pBytes, const PDFContainer* pObjectContainer, EmitContext& rContext ) const
646
0
{
647
0
    bool bIsDeflated = false;
648
0
    if( m_pStream && m_pStream->m_pDict &&
649
0
        m_pStream->m_nEndOffset > m_pStream->m_nBeginOffset+15
650
0
        )
651
0
    {
652
0
        unsigned int nOuterStreamLen = m_pStream->m_nEndOffset - m_pStream->m_nBeginOffset;
653
0
        rpStream.reset(new char[ nOuterStreamLen ]);
654
0
        unsigned int nRead = rContext.readOrigBytes( m_pStream->m_nBeginOffset, nOuterStreamLen, rpStream.get() );
655
0
        if( nRead != nOuterStreamLen )
656
0
        {
657
0
            rpStream.reset();
658
0
            *pBytes = 0;
659
0
            return false;
660
0
        }
661
        // is there a filter entry ?
662
0
        std::unordered_map<OString,PDFEntry*>::const_iterator it =
663
0
            m_pStream->m_pDict->m_aMap.find( "Filter"_ostr );
664
0
        if( it != m_pStream->m_pDict->m_aMap.end() )
665
0
        {
666
0
            PDFName* pFilter = dynamic_cast<PDFName*>(it->second);
667
0
            if( ! pFilter )
668
0
            {
669
0
                PDFArray* pArray = dynamic_cast<PDFArray*>(it->second);
670
0
                if( pArray && ! pArray->m_aSubElements.empty() )
671
0
                {
672
0
                    pFilter = dynamic_cast<PDFName*>(pArray->m_aSubElements.front().get());
673
0
                }
674
0
            }
675
676
            // is the (first) filter FlateDecode ?
677
0
            if (pFilter && pFilter->m_aName == "FlateDecode")
678
0
            {
679
0
                bIsDeflated = true;
680
0
            }
681
0
        }
682
        // prepare compressed data section
683
0
        char* pStream = rpStream.get();
684
0
        if( pStream[0] == 's' )
685
0
            pStream += 6; // skip "stream"
686
        // "stream" is followed by CR LF or by LF alone, and the data starts after that
687
0
        if( *pStream == '\r' )
688
0
            pStream++;
689
0
        if( *pStream == '\n' )
690
0
            pStream++;
691
        // get the compressed length
692
0
        *pBytes = m_pStream->getDictLength( pObjectContainer );
693
0
        unsigned int nAvailable = nOuterStreamLen - static_cast<unsigned int>(pStream - rpStream.get());
694
0
        if (*pBytes > nAvailable)
695
0
        {
696
0
            SAL_WARN("sdext.pdfimport.pdfparse", "stream /Length " << *pBytes << " exceeds " << nAvailable << " available bytes");
697
0
            *pBytes = nAvailable;
698
0
        }
699
0
        if( pStream != rpStream.get() )
700
0
            memmove( rpStream.get(), pStream, *pBytes );
701
0
        if( rContext.m_bDecrypt )
702
0
        {
703
0
            EmitImplData* pEData = getEmitData( rContext );
704
0
            pEData->decrypt( reinterpret_cast<const sal_uInt8*>(rpStream.get()),
705
0
                             *pBytes,
706
0
                             reinterpret_cast<sal_uInt8*>(rpStream.get()),
707
0
                             m_nNumber,
708
0
                             m_nGeneration
709
0
                             ); // decrypt inplace
710
0
        }
711
0
    }
712
0
    else
713
0
    {
714
0
        *pBytes = 0;
715
0
    }
716
0
    return bIsDeflated;
717
0
}
718
719
static void unzipToBuffer( char* pBegin, unsigned int nLen,
720
                           sal_uInt8** pOutBuf, sal_uInt32* pOutLen )
721
0
{
722
0
    z_stream aZStr;
723
0
    aZStr.next_in       = reinterpret_cast<Bytef *>(pBegin);
724
0
    aZStr.avail_in      = nLen;
725
0
    aZStr.total_out = aZStr.total_in = 0;
726
0
    aZStr.zalloc        = nullptr;
727
0
    aZStr.zfree         = nullptr;
728
0
    aZStr.opaque        = nullptr;
729
730
0
    int err = inflateInit(&aZStr);
731
732
0
    const unsigned int buf_increment_size = 16384;
733
734
0
    if (auto p = static_cast<sal_uInt8*>(std::realloc(*pOutBuf, buf_increment_size)))
735
0
    {
736
0
        *pOutBuf = p;
737
0
        aZStr.next_out = reinterpret_cast<Bytef*>(*pOutBuf);
738
0
        aZStr.avail_out = buf_increment_size;
739
0
        *pOutLen = buf_increment_size;
740
0
    }
741
0
    else
742
0
        err = Z_MEM_ERROR;
743
0
    while( err != Z_STREAM_END && err >= Z_OK && aZStr.avail_in )
744
0
    {
745
0
        err = inflate( &aZStr, Z_NO_FLUSH );
746
0
        if( aZStr.avail_out == 0 )
747
0
        {
748
0
            if( err != Z_STREAM_END )
749
0
            {
750
0
                const int nNewAlloc = *pOutLen + buf_increment_size;
751
0
                if (auto p = static_cast<sal_uInt8*>(std::realloc(*pOutBuf, nNewAlloc)))
752
0
                {
753
0
                    *pOutBuf = p;
754
0
                    aZStr.next_out = reinterpret_cast<Bytef*>(*pOutBuf + *pOutLen);
755
0
                    aZStr.avail_out = buf_increment_size;
756
0
                    *pOutLen = nNewAlloc;
757
0
                }
758
0
                else
759
0
                    err = Z_MEM_ERROR;
760
0
            }
761
0
        }
762
0
    }
763
0
    if( err == Z_STREAM_END )
764
0
    {
765
0
        if( aZStr.avail_out > 0 )
766
0
            *pOutLen -= aZStr.avail_out;
767
0
    }
768
0
    inflateEnd(&aZStr);
769
0
    if( err < Z_OK )
770
0
    {
771
0
        std::free( *pOutBuf );
772
0
        *pOutBuf = nullptr;
773
0
        *pOutLen = 0;
774
0
    }
775
0
}
776
777
void PDFObject::writeStream( EmitContext& rWriteContext, const PDFFile* pParsedFile ) const
778
0
{
779
0
    if( !m_pStream )
780
0
        return;
781
782
0
    std::unique_ptr<char[]> pStream;
783
0
    unsigned int nBytes = 0;
784
0
    if( getDeflatedStream( pStream, &nBytes, pParsedFile, rWriteContext ) && nBytes && rWriteContext.m_bDeflate )
785
0
    {
786
0
        sal_uInt8* pOutBytes = nullptr;
787
0
        sal_uInt32 nOutBytes = 0;
788
0
        unzipToBuffer( pStream.get(), nBytes, &pOutBytes, &nOutBytes );
789
0
        rWriteContext.write( pOutBytes, nOutBytes );
790
0
        std::free( pOutBytes );
791
0
    }
792
0
    else if( pStream && nBytes )
793
0
        rWriteContext.write( pStream.get(), nBytes );
794
0
}
795
796
bool PDFObject::emit( EmitContext& rWriteContext ) const
797
0
{
798
0
    if( ! rWriteContext.write( "\n", 1 ) )
799
0
        return false;
800
801
0
    EmitImplData* pEData = getEmitData( rWriteContext );
802
0
    if( pEData )
803
0
        pEData->insertXref( m_nNumber, m_nGeneration, rWriteContext.getCurPos() );
804
805
0
    OString aBuf =
806
0
        OString::number( sal_Int32( m_nNumber ) ) +
807
0
        " " +
808
0
        OString::number( sal_Int32( m_nGeneration ) ) +
809
0
        " obj\n";
810
0
    if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) )
811
0
        return false;
812
813
0
    if( pEData )
814
0
        pEData->setDecryptObject( m_nNumber, m_nGeneration );
815
0
    if( (rWriteContext.m_bDeflate || rWriteContext.m_bDecrypt) && pEData )
816
0
    {
817
0
        std::unique_ptr<char[]> pStream;
818
0
        unsigned int nBytes = 0;
819
0
        bool bDeflate = getDeflatedStream( pStream, &nBytes, pEData->m_pObjectContainer, rWriteContext );
820
0
        if( pStream && nBytes )
821
0
        {
822
            // unzip the stream
823
0
            sal_uInt8* pOutBytes = nullptr;
824
0
            sal_uInt32 nOutBytes = 0;
825
0
            if( bDeflate && rWriteContext.m_bDeflate )
826
0
                unzipToBuffer( pStream.get(), nBytes, &pOutBytes, &nOutBytes );
827
0
            else
828
0
            {
829
                // nothing to deflate, but decryption has happened
830
0
                pOutBytes = reinterpret_cast<sal_uInt8*>(pStream.get());
831
0
                nOutBytes = static_cast<sal_uInt32>(nBytes);
832
0
            }
833
834
0
            if( nOutBytes )
835
0
            {
836
                // clone this object
837
0
                std::unique_ptr<PDFObject> pClone(static_cast<PDFObject*>(clone()));
838
                // set length in the dictionary to new stream length
839
0
                std::unique_ptr<PDFNumber> pNewLen(new PDFNumber( double(nOutBytes) ));
840
0
                pClone->m_pStream->m_pDict->insertValue( "Length"_ostr, std::move(pNewLen) );
841
842
0
                if( bDeflate && rWriteContext.m_bDeflate )
843
0
                {
844
                    // delete flatedecode filter
845
0
                    std::unordered_map<OString,PDFEntry*>::const_iterator it =
846
0
                    pClone->m_pStream->m_pDict->m_aMap.find( "Filter"_ostr );
847
0
                    if( it != pClone->m_pStream->m_pDict->m_aMap.end() )
848
0
                    {
849
0
                        PDFName* pFilter = dynamic_cast<PDFName*>(it->second);
850
0
                        if (pFilter && pFilter->m_aName == "FlateDecode")
851
0
                            pClone->m_pStream->m_pDict->eraseValue( "Filter" );
852
0
                        else
853
0
                        {
854
0
                            PDFArray* pArray = dynamic_cast<PDFArray*>(it->second);
855
0
                            if( pArray && ! pArray->m_aSubElements.empty() )
856
0
                            {
857
0
                                pFilter = dynamic_cast<PDFName*>(pArray->m_aSubElements.front().get());
858
0
                                if (pFilter && pFilter->m_aName == "FlateDecode")
859
0
                                {
860
0
                                    pArray->m_aSubElements.erase( pArray->m_aSubElements.begin() );
861
0
                                }
862
0
                            }
863
0
                        }
864
0
                    }
865
0
                }
866
867
                // write sub elements except stream
868
0
                bool bRet = true;
869
0
                unsigned int nEle = pClone->m_aSubElements.size();
870
0
                for( unsigned int i = 0; i < nEle && bRet; i++ )
871
0
                {
872
0
                    if( pClone->m_aSubElements[i].get() != pClone->m_pStream )
873
0
                        bRet = pClone->m_aSubElements[i]->emit( rWriteContext );
874
0
                }
875
0
                pClone.reset();
876
                // write stream
877
0
                if( bRet )
878
0
                    bRet = rWriteContext.write("stream\n", 7)
879
0
                           && rWriteContext.write(pOutBytes, nOutBytes)
880
0
                           && rWriteContext.write("\nendstream\nendobj\n", 18);
881
0
                if( pOutBytes != reinterpret_cast<sal_uInt8*>(pStream.get()) )
882
0
                    std::free( pOutBytes );
883
0
                pEData->setDecryptObject( 0, 0 );
884
0
                return bRet;
885
0
            }
886
0
            if( pOutBytes != reinterpret_cast<sal_uInt8*>(pStream.get()) )
887
0
                std::free( pOutBytes );
888
0
        }
889
0
    }
890
891
0
    bool bRet = emitSubElements( rWriteContext ) &&
892
0
                rWriteContext.write( "\nendobj\n", 8 );
893
0
    if( pEData )
894
0
        pEData->setDecryptObject( 0, 0 );
895
0
    return bRet;
896
0
}
897
898
PDFEntry* PDFObject::clone() const
899
0
{
900
0
    PDFObject* pNewOb = new PDFObject( m_nNumber, m_nGeneration );
901
0
    cloneSubElements( pNewOb->m_aSubElements );
902
0
    unsigned int nEle = m_aSubElements.size();
903
0
    for( unsigned int i = 0; i < nEle; i++ )
904
0
    {
905
0
        if( m_aSubElements[i].get() == m_pObject )
906
0
            pNewOb->m_pObject = pNewOb->m_aSubElements[i].get();
907
0
        else if( m_aSubElements[i].get() == m_pStream && pNewOb->m_pObject )
908
0
        {
909
0
            pNewOb->m_pStream = dynamic_cast<PDFStream*>(pNewOb->m_aSubElements[i].get());
910
0
            PDFDict* pNewDict = dynamic_cast<PDFDict*>(pNewOb->m_pObject);
911
0
            if (pNewDict && pNewOb->m_pStream)
912
0
                pNewOb->m_pStream->m_pDict = pNewDict;
913
0
        }
914
0
    }
915
0
    return pNewOb;
916
0
}
917
918
PDFTrailer::~PDFTrailer()
919
{
920
}
921
922
bool PDFTrailer::emit( EmitContext& rWriteContext ) const
923
0
{
924
    // get xref offset
925
0
    unsigned int nXRefPos = rWriteContext.getCurPos();
926
    // begin xref section, object 0 is always free
927
0
    if( ! rWriteContext.write( "xref\r\n"
928
0
                               "0 1\r\n"
929
0
                               "0000000000 65535 f\r\n", 31 ) )
930
0
        return false;
931
    // check if we are emitting a complete PDF file
932
0
    EmitImplData* pEData = getEmitData( rWriteContext );
933
0
    if( pEData )
934
0
    {
935
        // emit object xrefs
936
0
        const EmitImplData::XRefTable& rXRefs = pEData->m_aXRefTable;
937
0
        EmitImplData::XRefTable::const_iterator section_begin, section_end;
938
0
        section_begin = rXRefs.begin();
939
0
        while( section_begin != rXRefs.end() )
940
0
        {
941
            // find end of continuous object numbers
942
0
            section_end = section_begin;
943
0
            unsigned int nLast = section_begin->first;
944
0
            while( (++section_end) != rXRefs.end() &&
945
0
                   section_end->first == nLast+1 )
946
0
                nLast = section_end->first;
947
            // write first object number and number of following entries
948
0
            OStringBuffer aBuf =
949
0
                OString::number(sal_Int32( section_begin->first ) )
950
0
                + " "
951
0
                + OString::number(sal_Int32(nLast - section_begin->first + 1))
952
0
                + "\r\n";
953
0
            if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) )
954
0
                return false;
955
0
            while( section_begin != section_end )
956
0
            {
957
                // write 20 char entry of form
958
                // 0000offset 00gen n\r\n
959
0
                aBuf.setLength( 0 );
960
0
                OString aOffset( OString::number( section_begin->second.second ) );
961
0
                int nPad = 10 - aOffset.getLength();
962
0
                for( int i = 0; i < nPad; i++ )
963
0
                    aBuf.append( '0' );
964
0
                aBuf.append( aOffset +  " " );
965
0
                OString aGeneration( OString::number( section_begin->second.first ) );
966
0
                nPad = 5 - aGeneration.getLength();
967
0
                for( int i = 0; i < nPad; i++ )
968
0
                    aBuf.append( '0' );
969
0
                aBuf.append( aGeneration + " n\r\n" );
970
0
                if( ! rWriteContext.write( aBuf.getStr(), 20 ) )
971
0
                    return false;
972
0
                ++section_begin;
973
0
            }
974
0
        }
975
0
    }
976
0
    if( ! rWriteContext.write( "trailer\n", 8 ) )
977
0
        return false;
978
0
    if( ! emitSubElements( rWriteContext ) )
979
0
        return false;
980
0
    if( ! rWriteContext.write( "startxref\n", 10 ) )
981
0
        return false;
982
0
    OString aOffset( OString::number( nXRefPos ) );
983
0
    if( ! rWriteContext.write( aOffset.getStr(), aOffset.getLength() ) )
984
0
        return false;
985
0
    return rWriteContext.write( "\n%%EOF\n", 7 );
986
0
}
987
988
PDFEntry* PDFTrailer::clone() const
989
0
{
990
0
    PDFTrailer* pNewTr = new PDFTrailer();
991
0
    cloneSubElements( pNewTr->m_aSubElements );
992
0
    unsigned int nEle = m_aSubElements.size();
993
0
    for( unsigned int i = 0; i < nEle; i++ )
994
0
    {
995
0
        if( m_aSubElements[i].get() == m_pDict )
996
0
        {
997
0
            pNewTr->m_pDict = dynamic_cast<PDFDict*>(pNewTr->m_aSubElements[i].get());
998
0
            break;
999
0
        }
1000
0
    }
1001
0
    return pNewTr;
1002
0
}
1003
1004
0
#define ENCRYPTION_KEY_LEN 16
1005
#define ENCRYPTION_BUF_LEN 32
1006
1007
namespace pdfparse {
1008
struct PDFFileImplData
1009
{
1010
    bool        m_bIsEncrypted;
1011
    bool        m_bStandardHandler;
1012
    sal_uInt32  m_nAlgoVersion;
1013
    sal_uInt32  m_nStandardRevision;
1014
    sal_uInt32  m_nKeyLength;
1015
    sal_uInt8   m_aOEntry[32] = {};
1016
    sal_uInt8   m_aUEntry[32] = {};
1017
    sal_uInt32  m_nPEntry;
1018
    OString     m_aDocID;
1019
    rtlCipher   m_aCipher;
1020
1021
    sal_uInt8   m_aDecryptionKey[ENCRYPTION_KEY_LEN+5] = {}; // maximum handled key length
1022
1023
    PDFFileImplData() :
1024
0
        m_bIsEncrypted( false ),
1025
0
        m_bStandardHandler( false ),
1026
0
        m_nAlgoVersion( 0 ),
1027
0
        m_nStandardRevision( 0 ),
1028
0
        m_nKeyLength( 0 ),
1029
0
        m_nPEntry( 0 ),
1030
0
        m_aCipher( nullptr )
1031
0
    {
1032
0
    }
1033
1034
    ~PDFFileImplData()
1035
0
    {
1036
0
        if( m_aCipher )
1037
0
            rtl_cipher_destroyARCFOUR( m_aCipher );
1038
0
    }
1039
};
1040
}
1041
1042
PDFFile::PDFFile()
1043
0
   :  m_nMajor( 0 ), m_nMinor( 0 )
1044
0
{
1045
0
}
1046
1047
PDFFile::~PDFFile()
1048
0
{
1049
0
}
1050
1051
bool PDFFile::isEncrypted() const
1052
0
{
1053
0
    return impl_getData()->m_bIsEncrypted;
1054
0
}
1055
1056
bool PDFFile::decrypt( const sal_uInt8* pInBuffer, sal_uInt32 nLen, sal_uInt8* pOutBuffer,
1057
                       unsigned int nObject, unsigned int nGeneration ) const
1058
0
{
1059
0
    if( ! isEncrypted() )
1060
0
        return false;
1061
1062
0
    if( ! m_pData->m_aCipher )
1063
0
        m_pData->m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1064
1065
    // modify encryption key
1066
0
    sal_uInt32 i = m_pData->m_nKeyLength;
1067
0
    m_pData->m_aDecryptionKey[i++] = sal_uInt8(nObject&0xff);
1068
0
    m_pData->m_aDecryptionKey[i++] = sal_uInt8((nObject>>8)&0xff);
1069
0
    m_pData->m_aDecryptionKey[i++] = sal_uInt8((nObject>>16)&0xff);
1070
0
    m_pData->m_aDecryptionKey[i++] = sal_uInt8(nGeneration&0xff);
1071
0
    m_pData->m_aDecryptionKey[i++] = sal_uInt8((nGeneration>>8)&0xff);
1072
1073
0
    ::std::vector<unsigned char> const aSum(::comphelper::Hash::calculateHash(
1074
0
                m_pData->m_aDecryptionKey, i, ::comphelper::HashType::MD5));
1075
1076
0
    if( i > 16 )
1077
0
        i = 16;
1078
1079
0
    rtlCipherError aErr = rtl_cipher_initARCFOUR( m_pData->m_aCipher,
1080
0
                                                  rtl_Cipher_DirectionDecode,
1081
0
                                                  aSum.data(), i,
1082
0
                                                  nullptr, 0 );
1083
0
    if( aErr == rtl_Cipher_E_None )
1084
0
        aErr = rtl_cipher_decodeARCFOUR( m_pData->m_aCipher,
1085
0
                                         pInBuffer, nLen,
1086
0
                                         pOutBuffer, nLen );
1087
0
    return aErr == rtl_Cipher_E_None;
1088
0
}
1089
1090
const sal_uInt8 nPadString[32] =
1091
{
1092
    0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
1093
    0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
1094
};
1095
1096
static void pad_or_truncate_to_32( const OString& rStr, char* pBuffer )
1097
0
{
1098
0
    int nLen = rStr.getLength();
1099
0
    if( nLen > 32 )
1100
0
        nLen = 32;
1101
0
    const char* pStr = rStr.getStr();
1102
0
    memcpy( pBuffer, pStr, nLen );
1103
0
    int i = 0;
1104
0
    while( nLen < 32 )
1105
0
        pBuffer[nLen++] = nPadString[i++];
1106
0
}
1107
1108
// pass at least pData->m_nKeyLength bytes in
1109
static sal_uInt32 password_to_key( const OString& rPwd, sal_uInt8* pOutKey, PDFFileImplData const * pData, bool bComputeO )
1110
0
{
1111
    // see PDF reference 1.4 Algorithm 3.2
1112
    // encrypt pad string
1113
0
    char aPadPwd[ENCRYPTION_BUF_LEN];
1114
0
    pad_or_truncate_to_32( rPwd, aPadPwd );
1115
0
    ::comphelper::Hash aDigest(::comphelper::HashType::MD5);
1116
0
    aDigest.update(aPadPwd, sizeof(aPadPwd));
1117
0
    if( ! bComputeO )
1118
0
    {
1119
0
        aDigest.update(pData->m_aOEntry, 32);
1120
0
        sal_uInt8 aPEntry[4];
1121
0
        aPEntry[0] = static_cast<sal_uInt8>(pData->m_nPEntry & 0xff);
1122
0
        aPEntry[1] = static_cast<sal_uInt8>((pData->m_nPEntry >> 8 ) & 0xff);
1123
0
        aPEntry[2] = static_cast<sal_uInt8>((pData->m_nPEntry >> 16) & 0xff);
1124
0
        aPEntry[3] = static_cast<sal_uInt8>((pData->m_nPEntry >> 24) & 0xff);
1125
0
        aDigest.update(aPEntry, sizeof(aPEntry));
1126
0
        aDigest.update(pData->m_aDocID.getStr(), pData->m_aDocID.getLength());
1127
0
    }
1128
0
    ::std::vector<unsigned char> nSum(aDigest.finalize());
1129
0
    if( pData->m_nStandardRevision == 3 )
1130
0
    {
1131
0
        for( int i = 0; i < 50; i++ )
1132
0
        {
1133
0
            nSum = ::comphelper::Hash::calculateHash(nSum.data(), nSum.size(),
1134
0
                    ::comphelper::HashType::MD5);
1135
0
        }
1136
0
    }
1137
0
    sal_uInt32 nLen = pData->m_nKeyLength;
1138
0
    if( nLen > RTL_DIGEST_LENGTH_MD5 )
1139
0
        nLen = RTL_DIGEST_LENGTH_MD5;
1140
0
    memcpy( pOutKey, nSum.data(), nLen );
1141
0
    return nLen;
1142
0
}
1143
1144
static bool check_user_password( const OString& rPwd, PDFFileImplData* pData )
1145
0
{
1146
    // see PDF reference 1.4 Algorithm 3.6
1147
0
    bool bValid = false;
1148
0
    sal_uInt8 aKey[ENCRYPTION_KEY_LEN];
1149
0
    sal_uInt32 nKeyLen = password_to_key( rPwd, aKey, pData, false );
1150
    // save (at this time potential) decryption key for later use
1151
0
    memcpy( pData->m_aDecryptionKey, aKey, nKeyLen );
1152
0
    if( pData->m_nStandardRevision == 2 )
1153
0
    {
1154
0
        sal_uInt8 nEncryptedEntry[ENCRYPTION_BUF_LEN] = {};
1155
        // see PDF reference 1.4 Algorithm 3.4
1156
        // encrypt pad string
1157
0
        if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode,
1158
0
                                    aKey, nKeyLen,
1159
0
                                    nullptr, 0 )
1160
0
            != rtl_Cipher_E_None)
1161
0
        {
1162
0
            return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1163
0
        }
1164
0
        rtl_cipher_encodeARCFOUR( pData->m_aCipher, nPadString, sizeof( nPadString ),
1165
0
                                  nEncryptedEntry, sizeof( nEncryptedEntry ) );
1166
0
        bValid = (memcmp( nEncryptedEntry, pData->m_aUEntry, 32 ) == 0);
1167
0
    }
1168
0
    else if( pData->m_nStandardRevision == 3 )
1169
0
    {
1170
        // see PDF reference 1.4 Algorithm 3.5
1171
0
        ::comphelper::Hash aDigest(::comphelper::HashType::MD5);
1172
0
        aDigest.update(nPadString, sizeof(nPadString));
1173
0
        aDigest.update(pData->m_aDocID.getStr(), pData->m_aDocID.getLength());
1174
0
        ::std::vector<unsigned char> nEncryptedEntry(aDigest.finalize());
1175
0
        if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode,
1176
0
                                    aKey, sizeof(aKey), nullptr, 0 )
1177
0
            != rtl_Cipher_E_None)
1178
0
        {
1179
0
            return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1180
0
        }
1181
0
        rtl_cipher_encodeARCFOUR( pData->m_aCipher,
1182
0
                                  nEncryptedEntry.data(), 16,
1183
0
                                  nEncryptedEntry.data(), 16 ); // encrypt in place
1184
0
        for( int i = 1; i <= 19; i++ ) // do it 19 times, start with 1
1185
0
        {
1186
0
            sal_uInt8 aTempKey[ENCRYPTION_KEY_LEN];
1187
0
            for( size_t j = 0; j < sizeof(aTempKey); j++ )
1188
0
                aTempKey[j] = static_cast<sal_uInt8>( aKey[j] ^ i );
1189
1190
0
            if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode,
1191
0
                                        aTempKey, sizeof(aTempKey), nullptr, 0 )
1192
0
                != rtl_Cipher_E_None)
1193
0
            {
1194
0
                return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1195
0
            }
1196
0
            rtl_cipher_encodeARCFOUR( pData->m_aCipher,
1197
0
                                      nEncryptedEntry.data(), 16,
1198
0
                                      nEncryptedEntry.data(), 16 ); // encrypt in place
1199
0
        }
1200
0
        bValid = (memcmp( nEncryptedEntry.data(), pData->m_aUEntry, 16 ) == 0);
1201
0
    }
1202
0
    return bValid;
1203
0
}
1204
1205
bool PDFFile::usesSupportedEncryptionFormat() const
1206
0
{
1207
0
    return m_pData->m_bStandardHandler &&
1208
0
        m_pData->m_nAlgoVersion >= 1 &&
1209
0
        m_pData->m_nAlgoVersion <= 2 &&
1210
0
        m_pData->m_nStandardRevision >= 2 &&
1211
0
        m_pData->m_nStandardRevision <= 3;
1212
0
}
1213
1214
bool PDFFile::setupDecryptionData( const OString& rPwd ) const
1215
0
{
1216
0
    if( !impl_getData()->m_bIsEncrypted )
1217
0
        return rPwd.isEmpty();
1218
1219
    // check if we can handle this encryption at all
1220
0
    if( ! usesSupportedEncryptionFormat() )
1221
0
        return false;
1222
1223
0
    if( ! m_pData->m_aCipher )
1224
0
        m_pData->m_aCipher = rtl_cipher_createARCFOUR(rtl_Cipher_ModeStream);
1225
1226
    // first try user password
1227
0
    bool bValid = check_user_password( rPwd, m_pData.get() );
1228
1229
0
    if( ! bValid )
1230
0
    {
1231
        // try owner password
1232
        // see PDF reference 1.4 Algorithm 3.7
1233
0
        sal_uInt8 aKey[ENCRYPTION_KEY_LEN];
1234
0
        sal_uInt8 nPwd[ENCRYPTION_BUF_LEN] = {};
1235
0
        sal_uInt32 nKeyLen = password_to_key( rPwd, aKey, m_pData.get(), true );
1236
0
        if( m_pData->m_nStandardRevision == 2 )
1237
0
        {
1238
0
            if (rtl_cipher_initARCFOUR( m_pData->m_aCipher, rtl_Cipher_DirectionDecode,
1239
0
                                        aKey, nKeyLen, nullptr, 0 )
1240
0
                != rtl_Cipher_E_None)
1241
0
            {
1242
0
                return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1243
0
            }
1244
0
            rtl_cipher_decodeARCFOUR( m_pData->m_aCipher,
1245
0
                                      m_pData->m_aOEntry, 32,
1246
0
                                      nPwd, 32 );
1247
0
        }
1248
0
        else if( m_pData->m_nStandardRevision == 3 )
1249
0
        {
1250
0
            memcpy( nPwd, m_pData->m_aOEntry, 32 );
1251
0
            for( int i = 19; i >= 0; i-- )
1252
0
            {
1253
0
                sal_uInt8 nTempKey[ENCRYPTION_KEY_LEN];
1254
0
                for( size_t j = 0; j < sizeof(nTempKey); j++ )
1255
0
                    nTempKey[j] = sal_uInt8(aKey[j] ^ i);
1256
0
                if (rtl_cipher_initARCFOUR( m_pData->m_aCipher, rtl_Cipher_DirectionDecode,
1257
0
                                            nTempKey, nKeyLen, nullptr, 0 )
1258
0
                    != rtl_Cipher_E_None)
1259
0
                {
1260
0
                    return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1261
0
                }
1262
0
                rtl_cipher_decodeARCFOUR( m_pData->m_aCipher,
1263
0
                                          nPwd, 32,
1264
0
                                          nPwd, 32 ); // decrypt inplace
1265
0
            }
1266
0
        }
1267
0
        bValid = check_user_password( OString( reinterpret_cast<char*>(nPwd), 32 ), m_pData.get() );
1268
0
    }
1269
1270
0
    return bValid;
1271
0
}
1272
1273
PDFFileImplData* PDFFile::impl_getData() const
1274
0
{
1275
0
    if( m_pData )
1276
0
        return m_pData.get();
1277
0
    m_pData.reset( new PDFFileImplData );
1278
    // check for encryption dict in a trailer
1279
0
    unsigned int nElements = m_aSubElements.size();
1280
0
    while( nElements-- > 0 )
1281
0
    {
1282
0
        PDFTrailer* pTrailer = dynamic_cast<PDFTrailer*>(m_aSubElements[nElements].get());
1283
0
        if( pTrailer && pTrailer->m_pDict )
1284
0
        {
1285
            // search doc id
1286
0
            PDFDict::Map::iterator doc_id = pTrailer->m_pDict->m_aMap.find( "ID"_ostr );
1287
0
            if( doc_id != pTrailer->m_pDict->m_aMap.end() )
1288
0
            {
1289
0
                PDFArray* pArr = dynamic_cast<PDFArray*>(doc_id->second);
1290
0
                if( pArr && !pArr->m_aSubElements.empty() )
1291
0
                {
1292
0
                    PDFString* pStr = dynamic_cast<PDFString*>(pArr->m_aSubElements[0].get());
1293
0
                    if( pStr )
1294
0
                        m_pData->m_aDocID = pStr->getFilteredString();
1295
#if OSL_DEBUG_LEVEL > 0
1296
                    OUStringBuffer aTmp;
1297
                    for( int i = 0; i < m_pData->m_aDocID.getLength(); i++ )
1298
                        aTmp.append(static_cast<sal_Int32>(sal_uInt8(m_pData->m_aDocID[i])), 16);
1299
                    SAL_INFO("sdext.pdfimport.pdfparse", "DocId is <" << aTmp.makeStringAndClear() << ">");
1300
#endif
1301
0
                }
1302
0
            }
1303
            // search Encrypt entry
1304
0
            PDFDict::Map::iterator enc =
1305
0
                pTrailer->m_pDict->m_aMap.find( "Encrypt"_ostr );
1306
0
            if( enc != pTrailer->m_pDict->m_aMap.end() )
1307
0
            {
1308
0
                PDFDict* pDict = dynamic_cast<PDFDict*>(enc->second);
1309
0
                if( ! pDict )
1310
0
                {
1311
0
                    PDFObjectRef* pRef = dynamic_cast<PDFObjectRef*>(enc->second);
1312
0
                    if( pRef )
1313
0
                    {
1314
0
                        PDFObject* pObj = findObject( pRef );
1315
0
                        if( pObj && pObj->m_pObject )
1316
0
                            pDict = dynamic_cast<PDFDict*>(pObj->m_pObject);
1317
0
                    }
1318
0
                }
1319
0
                if( pDict )
1320
0
                {
1321
0
                    PDFDict::Map::iterator filter = pDict->m_aMap.find( "Filter"_ostr );
1322
0
                    PDFDict::Map::iterator version = pDict->m_aMap.find( "V"_ostr );
1323
0
                    PDFDict::Map::iterator len = pDict->m_aMap.find( "Length"_ostr );
1324
0
                    PDFDict::Map::iterator o_ent = pDict->m_aMap.find( "O"_ostr );
1325
0
                    PDFDict::Map::iterator u_ent = pDict->m_aMap.find( "U"_ostr );
1326
0
                    PDFDict::Map::iterator r_ent = pDict->m_aMap.find( "R"_ostr );
1327
0
                    PDFDict::Map::iterator p_ent = pDict->m_aMap.find( "P"_ostr );
1328
0
                    if( filter != pDict->m_aMap.end() )
1329
0
                    {
1330
0
                        m_pData->m_bIsEncrypted = true;
1331
0
                        m_pData->m_nKeyLength = 5;
1332
0
                        if( version != pDict->m_aMap.end() )
1333
0
                        {
1334
0
                            PDFNumber* pNum = dynamic_cast<PDFNumber*>(version->second);
1335
0
                            if( pNum )
1336
0
                                m_pData->m_nAlgoVersion = static_cast<sal_uInt32>(pNum->m_fValue);
1337
0
                        }
1338
0
                        if( m_pData->m_nAlgoVersion >= 3 )
1339
0
                            m_pData->m_nKeyLength = 16;
1340
0
                        if( len != pDict->m_aMap.end() )
1341
0
                        {
1342
0
                            PDFNumber* pNum = dynamic_cast<PDFNumber*>(len->second);
1343
0
                            if( pNum )
1344
0
                            {
1345
0
                                sal_uInt32 nKeyLength = static_cast<sal_uInt32>(pNum->m_fValue) / 8;
1346
0
                                if (nKeyLength > ENCRYPTION_KEY_LEN)
1347
0
                                {
1348
0
                                    SAL_WARN("sdext.pdfimport.pdfparse", "entry has length " << nKeyLength << " which is greater than " << ENCRYPTION_KEY_LEN);
1349
0
                                    nKeyLength = ENCRYPTION_KEY_LEN;
1350
0
                                }
1351
0
                                m_pData->m_nKeyLength = nKeyLength;
1352
0
                            }
1353
0
                        }
1354
0
                        PDFName* pFilter = dynamic_cast<PDFName*>(filter->second);
1355
0
                        if( pFilter && pFilter->getFilteredName() == "Standard" )
1356
0
                            m_pData->m_bStandardHandler = true;
1357
0
                        if( o_ent != pDict->m_aMap.end() )
1358
0
                        {
1359
0
                            PDFString* pString = dynamic_cast<PDFString*>(o_ent->second);
1360
0
                            if( pString )
1361
0
                            {
1362
0
                                OString aEnt = pString->getFilteredString();
1363
0
                                if( aEnt.getLength() == 32 )
1364
0
                                    memcpy( m_pData->m_aOEntry, aEnt.getStr(), 32 );
1365
#if OSL_DEBUG_LEVEL > 0
1366
                                else
1367
                                {
1368
                                    OUStringBuffer aTmp;
1369
                                    for( int i = 0; i < aEnt.getLength(); i++ )
1370
                                        aTmp.append(" " + OUString::number(sal_uInt8(aEnt[i]), 16));
1371
                                    SAL_WARN("sdext.pdfimport.pdfparse",
1372
                                             "O entry has length " << static_cast<int>(aEnt.getLength()) << ", should be 32 <" << aTmp.makeStringAndClear() << ">" );
1373
                                }
1374
#endif
1375
0
                            }
1376
0
                        }
1377
0
                        if( u_ent != pDict->m_aMap.end() )
1378
0
                        {
1379
0
                            PDFString* pString = dynamic_cast<PDFString*>(u_ent->second);
1380
0
                            if( pString )
1381
0
                            {
1382
0
                                OString aEnt = pString->getFilteredString();
1383
0
                                if( aEnt.getLength() == 32 )
1384
0
                                    memcpy( m_pData->m_aUEntry, aEnt.getStr(), 32 );
1385
#if OSL_DEBUG_LEVEL > 0
1386
                                else
1387
                                {
1388
                                    OUStringBuffer aTmp;
1389
                                    for( int i = 0; i < aEnt.getLength(); i++ )
1390
                                        aTmp.append(" " + OUString::number(sal_uInt8(aEnt[i]), 16));
1391
                                    SAL_WARN("sdext.pdfimport.pdfparse",
1392
                                             "U entry has length " << static_cast<int>(aEnt.getLength()) << ", should be 32 <" << aTmp.makeStringAndClear() << ">" );
1393
                                }
1394
#endif
1395
0
                            }
1396
0
                        }
1397
0
                        if( r_ent != pDict->m_aMap.end() )
1398
0
                        {
1399
0
                            PDFNumber* pNum = dynamic_cast<PDFNumber*>(r_ent->second);
1400
0
                            if( pNum )
1401
0
                                m_pData->m_nStandardRevision = static_cast<sal_uInt32>(pNum->m_fValue);
1402
0
                        }
1403
0
                        if( p_ent != pDict->m_aMap.end() )
1404
0
                        {
1405
0
                            PDFNumber* pNum = dynamic_cast<PDFNumber*>(p_ent->second);
1406
0
                            if( pNum )
1407
0
                                m_pData->m_nPEntry = static_cast<sal_uInt32>(static_cast<sal_Int32>(pNum->m_fValue));
1408
0
                            SAL_INFO("sdext.pdfimport.pdfparse", "p entry is " << m_pData->m_nPEntry );
1409
0
                        }
1410
1411
0
                        SAL_INFO("sdext.pdfimport.pdfparse", "Encryption dict: sec handler: " << (pFilter ? pFilter->getFilteredName() : u"<unknown>"_ustr) << ", version = " << static_cast<int>(m_pData->m_nAlgoVersion) << ", revision = " << static_cast<int>(m_pData->m_nStandardRevision) << ", key length = " << m_pData->m_nKeyLength );
1412
0
                        break;
1413
0
                    }
1414
0
                }
1415
0
            }
1416
0
        }
1417
0
    }
1418
1419
0
    return m_pData.get();
1420
0
}
1421
1422
bool PDFFile::emit( EmitContext& rWriteContext ) const
1423
0
{
1424
0
    setEmitData(  rWriteContext, new EmitImplData( this ) );
1425
1426
0
    OString aBuf =
1427
0
        "%PDF-" +
1428
0
        OString::number( sal_Int32( m_nMajor ) ) +
1429
0
        "." +
1430
0
        OString::number( sal_Int32( m_nMinor ) ) +
1431
0
        "\n";
1432
0
    if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) )
1433
0
        return false;
1434
0
    return emitSubElements( rWriteContext );
1435
0
}
1436
1437
PDFEntry* PDFFile::clone() const
1438
0
{
1439
0
    PDFFile* pNewFl = new PDFFile();
1440
0
    pNewFl->m_nMajor = m_nMajor;
1441
0
    pNewFl->m_nMinor = m_nMinor;
1442
0
    cloneSubElements( pNewFl->m_aSubElements );
1443
0
    return pNewFl;
1444
0
}
1445
1446
PDFPart::~PDFPart()
1447
{
1448
}
1449
1450
bool PDFPart::emit( EmitContext& rWriteContext ) const
1451
0
{
1452
0
    return emitSubElements( rWriteContext );
1453
0
}
1454
1455
PDFEntry* PDFPart::clone() const
1456
0
{
1457
0
    PDFPart* pNewPt = new PDFPart();
1458
0
    cloneSubElements( pNewPt->m_aSubElements );
1459
0
    return pNewPt;
1460
0
}
1461
1462
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */