2020-01-18 11:38:54 +01:00
// Copyright (C) 2018-2020 Jakub Melka
2018-11-17 16:48:30 +01:00
//
2020-12-20 19:03:58 +01:00
// This file is part of Pdf4Qt.
2018-11-17 16:48:30 +01:00
//
2020-12-20 19:03:58 +01:00
// Pdf4Qt is free software: you can redistribute it and/or modify
2018-11-17 16:48:30 +01:00
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
2020-12-20 19:03:58 +01:00
// Pdf4Qt is distributed in the hope that it will be useful,
2018-11-17 16:48:30 +01:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
2020-12-20 19:03:58 +01:00
// along with Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
2018-11-17 16:48:30 +01:00
# include "pdfdocument.h"
2018-12-02 17:53:19 +01:00
# include "pdfencoding.h"
2019-04-29 17:03:19 +02:00
# include "pdfexception.h"
2019-02-09 18:40:56 +01:00
# include "pdfstreamfilters.h"
# include "pdfconstants.h"
2018-11-17 16:48:30 +01:00
2018-12-02 17:53:19 +01:00
namespace pdf
{
static constexpr const char * PDF_DOCUMENT_INFO_ENTRY = " Info " ;
2020-03-29 18:53:04 +02:00
QByteArray PDFObjectStorage : : getDecodedStream ( const PDFStream * stream ) const
{
return PDFStreamFilterStorage : : getDecodedStream ( stream , std : : bind ( QOverload < const PDFObject & > : : of ( & PDFObjectStorage : : getObject ) , this , std : : placeholders : : _1 ) , getSecurityHandler ( ) ) ;
}
2020-05-30 18:31:50 +02:00
PDFDocument : : ~ PDFDocument ( )
{
}
2020-05-02 18:04:25 +02:00
bool PDFDocument : : operator = = ( const PDFDocument & other ) const
{
// Document is considered equal, if storage is equal
return m_pdfObjectStorage = = other . m_pdfObjectStorage ;
}
2019-02-09 18:40:56 +01:00
QByteArray PDFDocument : : getDecodedStream ( const PDFStream * stream ) const
{
2020-03-29 18:53:04 +02:00
return m_pdfObjectStorage . getDecodedStream ( stream ) ;
2019-06-28 18:11:05 +02:00
}
2019-02-09 18:40:56 +01:00
2019-06-28 18:11:05 +02:00
const PDFDictionary * PDFDocument : : getTrailerDictionary ( ) const
{
const PDFObject & trailerDictionary = m_pdfObjectStorage . getTrailerDictionary ( ) ;
2019-02-09 18:40:56 +01:00
2019-06-28 18:11:05 +02:00
// Trailer object should be dictionary/stream here. It is verified in the document reader.
Q_ASSERT ( trailerDictionary . isDictionary ( ) | | trailerDictionary . isStream ( ) ) ;
2019-02-09 18:40:56 +01:00
2019-06-28 18:11:05 +02:00
if ( trailerDictionary . isDictionary ( ) )
2019-02-09 18:40:56 +01:00
{
2019-06-28 18:11:05 +02:00
return trailerDictionary . getDictionary ( ) ;
2019-02-09 18:40:56 +01:00
}
2019-06-28 18:11:05 +02:00
else if ( trailerDictionary . isStream ( ) )
2019-02-09 18:40:56 +01:00
{
2019-06-28 18:11:05 +02:00
return trailerDictionary . getStream ( ) - > getDictionary ( ) ;
2019-02-09 18:40:56 +01:00
}
2019-06-28 18:11:05 +02:00
return nullptr ;
2019-02-09 18:40:56 +01:00
}
2019-12-21 15:02:11 +01:00
QByteArray PDFDocument : : getVersion ( ) const
{
QByteArray result = m_catalog . getVersion ( ) ;
if ( result . isEmpty ( ) & & m_info . version . isValid ( ) )
{
result = QString ( " %1.%2 " ) . arg ( m_info . version . major ) . arg ( m_info . version . minor ) . toLatin1 ( ) ;
}
return result ;
}
2018-12-02 17:53:19 +01:00
void PDFDocument : : init ( )
{
initInfo ( ) ;
2018-12-24 17:09:23 +01:00
2019-06-28 18:11:05 +02:00
const PDFDictionary * dictionary = getTrailerDictionary ( ) ;
2018-12-24 17:09:23 +01:00
Q_ASSERT ( dictionary ) ;
m_catalog = PDFCatalog : : parse ( getObject ( dictionary - > get ( " Root " ) ) , this ) ;
2018-12-02 17:53:19 +01:00
}
void PDFDocument : : initInfo ( )
{
// Trailer object should be dictionary here. It is verified in the document reader.
2019-06-28 18:11:05 +02:00
const PDFDictionary * dictionary = getTrailerDictionary ( ) ;
2018-12-02 17:53:19 +01:00
Q_ASSERT ( dictionary ) ;
if ( dictionary - > hasKey ( PDF_DOCUMENT_INFO_ENTRY ) )
{
2020-07-16 19:43:51 +02:00
m_info = PDFDocumentInfo : : parse ( dictionary - > get ( PDF_DOCUMENT_INFO_ENTRY ) , & m_pdfObjectStorage ) ;
2018-12-02 17:53:19 +01:00
}
}
2020-05-02 18:04:25 +02:00
bool PDFObjectStorage : : operator = = ( const PDFObjectStorage & other ) const
{
// We compare just content. Security handler just defines encryption behavior.
return m_objects = = other . m_objects & &
m_trailerDictionary = = other . m_trailerDictionary ;
}
2018-12-02 17:53:19 +01:00
const PDFObject & PDFObjectStorage : : getObject ( PDFObjectReference reference ) const
{
if ( reference . objectNumber > = 0 & &
reference . objectNumber < static_cast < PDFInteger > ( m_objects . size ( ) ) & &
m_objects [ reference . objectNumber ] . generation = = reference . generation )
{
return m_objects [ reference . objectNumber ] . object ;
}
else
{
static const PDFObject dummy ;
return dummy ;
}
}
2020-03-19 18:17:08 +01:00
PDFObjectReference PDFObjectStorage : : addObject ( PDFObject object )
{
PDFObjectReference reference ( m_objects . size ( ) , 0 ) ;
m_objects . emplace_back ( 0 , qMove ( object ) ) ;
return reference ;
}
2020-03-21 16:36:27 +01:00
void PDFObjectStorage : : setObject ( PDFObjectReference reference , PDFObject object )
{
m_objects [ reference . objectNumber ] = Entry ( reference . generation , qMove ( object ) ) ;
}
2020-03-21 18:18:08 +01:00
void PDFObjectStorage : : updateTrailerDictionary ( PDFObject trailerDictionary )
{
m_trailerDictionary = PDFObjectManipulator : : merge ( m_trailerDictionary , trailerDictionary , PDFObjectManipulator : : RemoveNullObjects ) ;
}
2020-03-29 18:53:04 +02:00
PDFDocumentDataLoaderDecorator : : PDFDocumentDataLoaderDecorator ( const PDFDocument * document )
: m_storage ( & document - > getStorage ( ) )
{
}
2020-04-18 19:01:49 +02:00
QByteArray PDFDocumentDataLoaderDecorator : : readName ( const PDFObject & object ) const
2019-03-30 18:45:30 +01:00
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-03-30 18:45:30 +01:00
if ( dereferencedObject . isName ( ) )
{
return dereferencedObject . getString ( ) ;
}
return QByteArray ( ) ;
}
2020-04-18 19:01:49 +02:00
QByteArray PDFDocumentDataLoaderDecorator : : readString ( const PDFObject & object ) const
2019-03-31 18:08:36 +02:00
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-03-31 18:08:36 +02:00
if ( dereferencedObject . isString ( ) )
{
return dereferencedObject . getString ( ) ;
}
return QByteArray ( ) ;
}
2018-12-24 17:09:23 +01:00
PDFInteger PDFDocumentDataLoaderDecorator : : readInteger ( const PDFObject & object , PDFInteger defaultValue ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2018-12-24 17:09:23 +01:00
if ( dereferencedObject . isInt ( ) )
{
return dereferencedObject . getInteger ( ) ;
}
return defaultValue ;
}
2019-02-23 15:44:14 +01:00
PDFReal PDFDocumentDataLoaderDecorator : : readNumber ( const PDFObject & object , PDFReal defaultValue ) const
2019-02-16 18:26:16 +01:00
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-02-16 18:26:16 +01:00
if ( dereferencedObject . isReal ( ) )
{
return dereferencedObject . getReal ( ) ;
} else if ( dereferencedObject . isInt ( ) )
{
return dereferencedObject . getInteger ( ) ;
}
return defaultValue ;
}
2019-03-25 18:44:45 +01:00
bool PDFDocumentDataLoaderDecorator : : readBoolean ( const PDFObject & object , bool defaultValue ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-03-25 18:44:45 +01:00
if ( dereferencedObject . isBool ( ) )
{
return dereferencedObject . getBool ( ) ;
}
return defaultValue ;
}
2018-12-24 17:09:23 +01:00
QString PDFDocumentDataLoaderDecorator : : readTextString ( const PDFObject & object , const QString & defaultValue ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2018-12-24 17:09:23 +01:00
if ( dereferencedObject . isString ( ) )
{
return PDFEncoding : : convertTextString ( dereferencedObject . getString ( ) ) ;
}
return defaultValue ;
}
2018-12-26 18:00:17 +01:00
QRectF PDFDocumentDataLoaderDecorator : : readRectangle ( const PDFObject & object , const QRectF & defaultValue ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2018-12-26 18:00:17 +01:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
if ( array - > getCount ( ) = = 4 )
{
std : : array < PDFReal , 4 > items ;
for ( size_t i = 0 ; i < 4 ; + + i )
{
2020-03-29 18:53:04 +02:00
const PDFObject & object = m_storage - > getObject ( array - > getItem ( i ) ) ;
2018-12-26 18:00:17 +01:00
if ( object . isReal ( ) )
{
items [ i ] = object . getReal ( ) ;
}
else if ( object . isInt ( ) )
{
items [ i ] = object . getInteger ( ) ;
}
else
{
return defaultValue ;
}
}
const PDFReal xMin = qMin ( items [ 0 ] , items [ 2 ] ) ;
const PDFReal xMax = qMax ( items [ 0 ] , items [ 2 ] ) ;
const PDFReal yMin = qMin ( items [ 1 ] , items [ 3 ] ) ;
const PDFReal yMax = qMax ( items [ 1 ] , items [ 3 ] ) ;
return QRectF ( xMin , yMin , xMax - xMin , yMax - yMin ) ;
}
}
return defaultValue ;
}
2020-04-18 19:01:49 +02:00
QMatrix PDFDocumentDataLoaderDecorator : : readMatrixFromDictionary ( const PDFDictionary * dictionary , const char * key , QMatrix defaultValue ) const
2019-08-25 18:16:37 +02:00
{
if ( dictionary - > hasKey ( key ) )
{
std : : vector < PDFReal > matrixNumbers = readNumberArrayFromDictionary ( dictionary , key ) ;
if ( matrixNumbers . size ( ) ! = 6 )
{
throw PDFRendererException ( RenderErrorType : : Error , PDFTranslationContext : : tr ( " Invalid number of matrix elements. Expected 6, actual %1. " ) . arg ( matrixNumbers . size ( ) ) ) ;
}
return QMatrix ( matrixNumbers [ 0 ] , matrixNumbers [ 1 ] , matrixNumbers [ 2 ] , matrixNumbers [ 3 ] , matrixNumbers [ 4 ] , matrixNumbers [ 5 ] ) ;
}
return defaultValue ;
}
2019-09-08 17:17:12 +02:00
std : : vector < PDFReal > PDFDocumentDataLoaderDecorator : : readNumberArrayFromDictionary ( const PDFDictionary * dictionary ,
const char * key ,
2020-04-18 19:01:49 +02:00
std : : vector < PDFReal > defaultValue ) const
2019-03-07 19:57:03 +01:00
{
if ( dictionary - > hasKey ( key ) )
{
2019-09-08 17:17:12 +02:00
return readNumberArray ( dictionary - > get ( key ) , defaultValue ) ;
2019-03-07 19:57:03 +01:00
}
2019-09-08 17:17:12 +02:00
return defaultValue ;
2019-03-07 19:57:03 +01:00
}
2020-04-18 19:01:49 +02:00
std : : vector < PDFInteger > PDFDocumentDataLoaderDecorator : : readIntegerArrayFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
2019-03-07 19:57:03 +01:00
{
if ( dictionary - > hasKey ( key ) )
{
return readIntegerArray ( dictionary - > get ( key ) ) ;
}
return std : : vector < PDFInteger > ( ) ;
}
2019-02-16 18:26:16 +01:00
PDFReal PDFDocumentDataLoaderDecorator : : readNumberFromDictionary ( const PDFDictionary * dictionary , const char * key , PDFReal defaultValue ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readNumber ( dictionary - > get ( key ) , defaultValue ) ;
}
return defaultValue ;
}
2019-09-01 14:42:32 +02:00
PDFReal PDFDocumentDataLoaderDecorator : : readNumberFromDictionary ( const PDFDictionary * dictionary , const QByteArray & key , PDFReal defaultValue ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readNumber ( dictionary - > get ( key ) , defaultValue ) ;
}
return defaultValue ;
}
2019-02-16 18:26:16 +01:00
PDFInteger PDFDocumentDataLoaderDecorator : : readIntegerFromDictionary ( const PDFDictionary * dictionary , const char * key , PDFInteger defaultValue ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readInteger ( dictionary - > get ( key ) , defaultValue ) ;
}
return defaultValue ;
}
2019-06-23 18:35:32 +02:00
QString PDFDocumentDataLoaderDecorator : : readTextStringFromDictionary ( const PDFDictionary * dictionary , const char * key , const QString & defaultValue ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readTextString ( dictionary - > get ( key ) , defaultValue ) ;
}
return defaultValue ;
}
2020-04-18 19:01:49 +02:00
std : : vector < PDFObjectReference > PDFDocumentDataLoaderDecorator : : readReferenceArrayFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
2019-06-23 18:35:32 +02:00
{
if ( dictionary - > hasKey ( key ) )
{
return readReferenceArray ( dictionary - > get ( key ) ) ;
}
return std : : vector < PDFObjectReference > ( ) ;
}
2019-09-08 17:17:12 +02:00
std : : vector < PDFReal > PDFDocumentDataLoaderDecorator : : readNumberArray ( const PDFObject & object , std : : vector < PDFReal > defaultValue ) const
2019-02-23 15:44:14 +01:00
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-02-23 15:44:14 +01:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
std : : vector < PDFReal > result ;
const size_t count = array - > getCount ( ) ;
result . reserve ( count ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
const PDFReal number = readNumber ( array - > getItem ( i ) , std : : numeric_limits < PDFReal > : : quiet_NaN ( ) ) ;
if ( std : : isnan ( number ) )
{
2019-09-08 17:17:12 +02:00
return defaultValue ;
2019-02-23 15:44:14 +01:00
}
result . push_back ( number ) ;
}
// We assume, that RVO (return value optimization) will not work for this function
// (multiple return points).
return std : : move ( result ) ;
}
2019-09-08 17:17:12 +02:00
return defaultValue ;
2019-02-23 15:44:14 +01:00
}
2019-03-07 19:57:03 +01:00
std : : vector < PDFInteger > PDFDocumentDataLoaderDecorator : : readIntegerArray ( const PDFObject & object ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-03-07 19:57:03 +01:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
std : : vector < PDFInteger > result ;
const size_t count = array - > getCount ( ) ;
result . reserve ( count ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
// This value is not representable in the current PDF parser. So we assume we
// can't get this value.
constexpr const PDFInteger INVALID_VALUE = std : : numeric_limits < PDFInteger > : : max ( ) ;
const PDFReal number = readInteger ( array - > getItem ( i ) , INVALID_VALUE ) ;
if ( number = = INVALID_VALUE )
{
return std : : vector < PDFInteger > ( ) ;
}
result . push_back ( number ) ;
}
// We assume, that RVO (return value optimization) will not work for this function
// (multiple return points).
return std : : move ( result ) ;
}
return std : : vector < PDFInteger > ( ) ;
}
2020-08-07 19:29:22 +02:00
PDFObjectReference PDFDocumentDataLoaderDecorator : : readReference ( const PDFObject & object ) const
{
if ( object . isReference ( ) )
{
return object . getReference ( ) ;
}
return PDFObjectReference ( ) ;
}
2020-03-05 18:28:07 +01:00
PDFObjectReference PDFDocumentDataLoaderDecorator : : readReferenceFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
{
const PDFObject & object = dictionary - > get ( key ) ;
if ( object . isReference ( ) )
{
return object . getReference ( ) ;
}
return PDFObjectReference ( ) ;
}
2019-06-23 18:35:32 +02:00
std : : vector < PDFObjectReference > PDFDocumentDataLoaderDecorator : : readReferenceArray ( const PDFObject & object ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-06-23 18:35:32 +02:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
std : : vector < PDFObjectReference > result ;
const size_t count = array - > getCount ( ) ;
result . reserve ( count ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
const PDFObject & referenceObject = array - > getItem ( i ) ;
if ( referenceObject . isReference ( ) )
{
result . push_back ( referenceObject . getReference ( ) ) ;
}
else
{
result . clear ( ) ;
break ;
}
}
// We assume, that RVO (return value optimization) will not work for this function
// (multiple return points).
return std : : move ( result ) ;
}
return std : : vector < PDFObjectReference > ( ) ;
}
std : : vector < QByteArray > PDFDocumentDataLoaderDecorator : : readNameArray ( const PDFObject & object ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-06-23 18:35:32 +02:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
std : : vector < QByteArray > result ;
const size_t count = array - > getCount ( ) ;
result . reserve ( count ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
const PDFObject & nameObject = array - > getItem ( i ) ;
if ( nameObject . isName ( ) )
{
result . push_back ( nameObject . getString ( ) ) ;
}
else
{
result . clear ( ) ;
break ;
}
}
// We assume, that RVO (return value optimization) will not work for this function
// (multiple return points).
return std : : move ( result ) ;
}
return std : : vector < QByteArray > ( ) ;
}
std : : vector < QByteArray > PDFDocumentDataLoaderDecorator : : readNameArrayFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readNameArray ( dictionary - > get ( key ) ) ;
}
return std : : vector < QByteArray > ( ) ;
}
2019-03-25 18:44:45 +01:00
bool PDFDocumentDataLoaderDecorator : : readBooleanFromDictionary ( const PDFDictionary * dictionary , const char * key , bool defaultValue ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readBoolean ( dictionary - > get ( key ) , defaultValue ) ;
}
return defaultValue ;
}
2020-04-18 19:01:49 +02:00
QByteArray PDFDocumentDataLoaderDecorator : : readNameFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
2019-03-30 18:45:30 +01:00
{
if ( dictionary - > hasKey ( key ) )
{
return readName ( dictionary - > get ( key ) ) ;
}
return QByteArray ( ) ;
}
2020-04-18 19:01:49 +02:00
QByteArray PDFDocumentDataLoaderDecorator : : readStringFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
2019-03-31 18:08:36 +02:00
{
if ( dictionary - > hasKey ( key ) )
{
return readString ( dictionary - > get ( key ) ) ;
}
return QByteArray ( ) ;
}
2019-11-23 19:02:24 +01:00
std : : vector < QByteArray > PDFDocumentDataLoaderDecorator : : readStringArrayFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readStringArray ( dictionary - > get ( key ) ) ;
}
return std : : vector < QByteArray > ( ) ;
}
2020-04-10 20:52:05 +02:00
QStringList PDFDocumentDataLoaderDecorator : : readTextStringList ( const PDFObject & object )
{
QStringList result ;
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
const size_t count = array - > getCount ( ) ;
result . reserve ( int ( count ) ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
result < < readTextString ( array - > getItem ( i ) , QString ( ) ) ;
}
}
return result ;
}
2020-08-08 18:18:08 +02:00
QColor PDFDocumentDataLoaderDecorator : : readRGBColorFromDictionary ( const PDFDictionary * dictionary , const char * key , QColor defaultColor )
{
std : : vector < PDFReal > colors = readNumberArrayFromDictionary ( dictionary , key ) ;
if ( colors . size ( ) = = 3 )
{
const PDFReal red = qBound ( 0.0 , colors [ 0 ] , 1.0 ) ;
const PDFReal green = qBound ( 0.0 , colors [ 1 ] , 1.0 ) ;
const PDFReal blue = qBound ( 0.0 , colors [ 2 ] , 1.0 ) ;
return QColor : : fromRgbF ( red , green , blue ) ;
}
return defaultColor ;
}
2020-04-18 19:01:49 +02:00
std : : optional < QByteArray > PDFDocumentDataLoaderDecorator : : readOptionalStringFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
{
if ( dictionary - > hasKey ( key ) )
{
return readStringFromDictionary ( dictionary , key ) ;
}
return std : : nullopt ;
}
std : : optional < PDFInteger > PDFDocumentDataLoaderDecorator : : readOptionalIntegerFromDictionary ( const PDFDictionary * dictionary , const char * key ) const
{
if ( dictionary - > hasKey ( key ) )
{
PDFInteger integer = readIntegerFromDictionary ( dictionary , key , std : : numeric_limits < PDFInteger > : : max ( ) ) ;
if ( integer ! = std : : numeric_limits < PDFInteger > : : max ( ) )
{
return integer ;
}
}
return std : : nullopt ;
}
2019-11-23 19:02:24 +01:00
std : : vector < QByteArray > PDFDocumentDataLoaderDecorator : : readStringArray ( const PDFObject & object ) const
{
2020-03-29 18:53:04 +02:00
const PDFObject & dereferencedObject = m_storage - > getObject ( object ) ;
2019-11-23 19:02:24 +01:00
if ( dereferencedObject . isArray ( ) )
{
const PDFArray * array = dereferencedObject . getArray ( ) ;
std : : vector < QByteArray > result ;
const size_t count = array - > getCount ( ) ;
result . reserve ( count ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
const PDFObject & stringObject = array - > getItem ( i ) ;
if ( stringObject . isString ( ) )
{
result . push_back ( stringObject . getString ( ) ) ;
}
else
{
result . clear ( ) ;
break ;
}
}
// We assume, that RVO (return value optimization) will not work for this function
// (multiple return points).
return std : : move ( result ) ;
}
return std : : vector < QByteArray > ( ) ;
}
2018-12-02 17:53:19 +01:00
} // namespace pdf