#
# Fixes: Podofo failing to load valid pdf file when '/Type/Sig' is declared after '/Contents' in a signature dictionary.
#
--- src/base/PdfTokenizer.h	Thu Oct 12 12:46:35 2017
+++ src/base/PdfTokenizer.h	Thu Apr 05 13:50:07 2018
@@ -125,7 +125,7 @@
      *  \param rVariant write the read variant to this value
      *  \param pEncrypt an encryption object which is used to decrypt strings during parsing
      */
-    void GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt );
+    EPdfDataType GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex = false );
 
     /** Returns true if the given character is a whitespace 
      *  according to the pdf reference
@@ -181,7 +181,7 @@
      *  \param rVariant write the read variant to this value
      *  \param pEncrypt an encryption object which is used to decrypt strings during parsing
      */
-    void GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt );
+     EPdfDataType GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex = false );
 
     /** Determine the possible datatype of a token.
      *  Numbers, reals, bools or NULL values are parsed directly by this function
@@ -191,7 +191,7 @@
      */
     EPdfDataType DetermineDataType( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant );
 
-    void ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt );
+    void ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex = false );
 
     /** Read a dictionary from the input device
      *  and store it into a variant.
@@ -223,7 +223,7 @@
      *  \param rVariant store the hex string into this variable
      *  \param pEncrypt an encryption object which is used to decrypt strings during parsing
      */
-    void ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt );
+    void ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRaw = false );
 
     /** Read a name from the input device
      *  and store it into a variant.
--- src/base/PdfTokenizer.cpp	Thu Oct 12 12:46:34 2017
+++ src/base/PdfTokenizer.cpp	Thu Apr 05 13:51:21 2018
@@ -375,7 +375,7 @@
     return l;
 }
 
-void PdfTokenizer::GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt )
+EPdfDataType PdfTokenizer::GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex )
 {
    EPdfTokenType eTokenType;
    const char*   pszRead;
@@ -386,10 +386,10 @@
        PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected variant." );
    }
 
-   this->GetNextVariant( pszRead, eTokenType, rVariant, pEncrypt );
+   return this->GetNextVariant( pszRead, eTokenType, rVariant, pEncrypt, getRawHex );
 }
 
-void PdfTokenizer::GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt )
+EPdfDataType PdfTokenizer::GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex )
 {
     EPdfDataType eDataType = this->DetermineDataType( pszToken, eType, rVariant );
 
@@ -400,10 +400,11 @@
         eDataType == ePdfDataType_Reference )
     {
         // the data was already read into rVariant by the DetermineDataType function
-        return;
+        return eDataType;
     }
 
-    this->ReadDataType( eDataType, rVariant, pEncrypt );
+    this->ReadDataType( eDataType, rVariant, pEncrypt, getRawHex );
+    return eDataType;
 }
 
 EPdfDataType PdfTokenizer::DetermineDataType( const char* pszToken, EPdfTokenType eTokenType, PdfVariant& rVariant )
@@ -552,7 +553,7 @@
     return ePdfDataType_Unknown;
 }
 
-void PdfTokenizer::ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt )
+void PdfTokenizer::ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRawHex )
 {
     switch( eDataType )
     {
@@ -566,7 +567,7 @@
             this->ReadString( rVariant, pEncrypt );
             break;
         case ePdfDataType_HexString:
-            this->ReadHexString( rVariant, pEncrypt );
+            this->ReadHexString( rVariant, pEncrypt, getRawHex );
             break;
         case ePdfDataType_Name:
             this->ReadName( rVariant );
@@ -597,6 +598,7 @@
     PdfDictionary dict;
     EPdfTokenType eType;
     const char *  pszToken;
+    bool          processRawHexContents = false;
 
     for( ;; )
     {
@@ -612,18 +614,37 @@
         // Convert the read variant to a name; throws InvalidDataType if not a name.
         key = val.GetName();
 
-        // 'Contents' key of a /Type/Sig dictionary is an unencrypted Hex string
-        bool bIsSigContents = key == PdfName( "Contents" ) &&
-            dict.HasKey( "Type" ) &&
-            dict.GetKey( "Type" )->GetDataType() == ePdfDataType_Name &&
-            dict.GetKey( "Type" )->GetName() == PdfName( "Sig" );
+        // 'Contents' key of a signature dictionary is an unencrypted hex string.
+        // Since '/Type/Sig' may be located after 'Contents' key, we can't check for it here and have to postpone the check.
+        bool bIsContents = ( key == PdfName( "Contents" ) );
 
         // Get the next variant. If there isn't one, it'll throw UnexpectedEOF.
-        this->GetNextVariant( val, bIsSigContents ? NULL : pEncrypt );
+        // If we have the 'Contents' key and it is a hex string, we will get the raw, unprocessed string.
+        // We will process the raw string at the end, after all keys have been read, so the check for '/Type/Sig' is valid.
+        EPdfDataType dataType = this->GetNextVariant( val, pEncrypt, bIsContents );
+        processRawHexContents |= ( bIsContents && dataType == ePdfDataType_HexString );
 
         dict.AddKey( key, val );
     }
 
+    // Process raw hex contents, decrypting it if we don't have a signature dicionary.
+    if ( processRawHexContents )
+    {
+        // Check if signature dictionary
+        bool isSigDict = dict.HasKey( "Type" ) &&
+            dict.GetKey( "Type" )->GetDataType() == ePdfDataType_Name &&
+            dict.GetKey( "Type" )->GetName() == PdfName( "Sig" );
+
+        // Read raw hex contents from dictionary.
+        PdfString rawContents = dict.GetKey( "Contents" )->GetString(), processedContents;
+
+        // Process raw hex contents (decrypting if NOT sig dict)
+        processedContents.SetHexData( rawContents.GetString(), rawContents.GetLength(), isSigDict ? NULL : pEncrypt );
+
+        // Overwrite raw hex content in dictionary with processed one.
+        dict.AddKey( "Contents", processedContents );
+    }    
+
     rVariant = dict;
 }
 
@@ -762,7 +783,7 @@
     }
 }
 
-void PdfTokenizer::ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt )
+void PdfTokenizer::ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt, bool getRaw )
 {
     int        c;
 
@@ -785,10 +806,16 @@
     if( m_vecBuffer.size() % 2 )
         m_vecBuffer.push_back( '0' );
 
-    PdfString string;
-    string.SetHexData( m_vecBuffer.size() ? &(m_vecBuffer[0]) : "", m_vecBuffer.size(), pEncrypt );
-
-    rVariant = string;
+    if ( getRaw )
+    {
+        rVariant = PdfString( m_vecBuffer.size() ? &( m_vecBuffer [0] ) : "" );
+    }
+    else
+    {
+        PdfString string;
+        string.SetHexData( m_vecBuffer.size() ? &( m_vecBuffer [0] ) : "", m_vecBuffer.size(), pEncrypt );
+        rVariant = string;
+    }
 }
 
 void PdfTokenizer::ReadName( PdfVariant& rVariant )
