Fix the issue that pdfium swallows 'fi' or 'ff' in some pdf files
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_parser.cpp
index 21b2fba..cd923f3 100644 (file)
@@ -4,6 +4,7 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -1732,9 +1733,7 @@ CPDF_SyntaxParser::CPDF_SyntaxParser() {
   m_bFileStream = FALSE;
 }
 CPDF_SyntaxParser::~CPDF_SyntaxParser() {
-  if (m_pFileBuf) {
-    FX_Free(m_pFileBuf);
-  }
+  FX_Free(m_pFileBuf);
 }
 FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) {
   FX_FILESIZE save_pos = m_Pos;
@@ -2377,8 +2376,9 @@ CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
         continue;
       }
       key = PDF_NameDecode(key);
-      CPDF_Object* pObj = GetObject(pObjList, objnum, gennum);
-      if (pObj == NULL) {
+      nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
+          GetObject(pObjList, objnum, gennum));
+      if (!obj) {
         if (pDict) {
           pDict->Release();
         }
@@ -2395,7 +2395,7 @@ CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
       }
       if (key.GetLength() > 1) {
         pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
-                        pObj);
+                        obj.release());
       }
     }
     if (pContext) {
@@ -2455,8 +2455,8 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
     len = pLenObj->GetInteger();
   }
   // Check whether end of line markers follow the keyword 'stream'.
-  unsigned int numMarkers = ReadEOLMarkers(m_Pos);
-  m_Pos += numMarkers;
+  // The stream starts after end of line markers.
+  m_Pos += ReadEOLMarkers(m_Pos);
   FX_FILESIZE streamStartPos = m_Pos;
   if (pContext) {
     pContext->m_DataStart = streamStartPos;
@@ -2467,19 +2467,18 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
       objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler;
   if (!pCryptoHandler) {
     FX_BOOL bSearchForKeyword = TRUE;
-    unsigned int prevMarkers = 0;
-    unsigned int nextMarkers = 0;
     if (len >= 0) {
       pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
       pos += len;
       if (pos.IsValid() && pos.ValueOrDie() < m_FileLen) {
         m_Pos = pos.ValueOrDie();
       }
-      prevMarkers = ReadEOLMarkers(m_Pos);
+      m_Pos += ReadEOLMarkers(m_Pos);
+      FXSYS_memset(m_WordBuffer, 0, ENDSTREAM_LEN + 1);
       GetNextWord();
-      nextMarkers = ReadEOLMarkers(m_Pos);
-      if (m_WordSize == ENDSTREAM_LEN && prevMarkers != 0 && nextMarkers != 0 &&
-          FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0) {
+      if (FXSYS_memcmp(m_WordBuffer, "endstream", ENDSTREAM_LEN) == 0 &&
+          IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
+                      FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
         bSearchForKeyword = FALSE;
       }
     }
@@ -2494,22 +2493,12 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
           // Can't find any "endstream".
           break;
         }
-        prevMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
-        nextMarkers =
-            ReadEOLMarkers(streamStartPos + endStreamOffset + ENDSTREAM_LEN);
-        if (prevMarkers != 0 && nextMarkers != 0) {
+        if (IsWholeWord(m_Pos - ENDSTREAM_LEN, m_FileLen,
+                        FX_BSTRC("endstream").GetPtr(), ENDSTREAM_LEN, TRUE)) {
           // Stop searching when the keyword "endstream" is found.
+          endStreamOffset = m_Pos - streamStartPos - ENDSTREAM_LEN;
           break;
-        } else {
-          unsigned char ch = 0x00;
-          GetCharAt(streamStartPos + endStreamOffset + ENDSTREAM_LEN, ch);
-          if (ch == 0x09 || ch == 0x20) {
-            //"endstream" is treated as a keyword
-            // when it is followed by a tab or whitespace
-            break;
-          }
         }
-        m_Pos += ENDSTREAM_LEN;
       }
       m_Pos = streamStartPos;
       FX_FILESIZE endObjOffset = 0;
@@ -2519,14 +2508,12 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
           // Can't find any "endobj".
           break;
         }
-        prevMarkers = ReadEOLMarkers(streamStartPos + endObjOffset - 1);
-        nextMarkers =
-            ReadEOLMarkers(streamStartPos + endObjOffset + ENDOBJ_LEN);
-        if (prevMarkers != 0 && nextMarkers != 0) {
+        if (IsWholeWord(m_Pos - ENDOBJ_LEN, m_FileLen,
+                        FX_BSTRC("endobj").GetPtr(), ENDOBJ_LEN, TRUE)) {
           // Stop searching when the keyword "endobj" is found.
+          endObjOffset = m_Pos - streamStartPos - ENDOBJ_LEN;
           break;
         }
-        m_Pos += ENDOBJ_LEN;
       }
       if (endStreamOffset < 0 && endObjOffset < 0) {
         // Can't find "endstream" or "endobj".
@@ -2542,7 +2529,7 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
         endStreamOffset = endObjOffset;
       }
       len = endStreamOffset;
-      numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
+      int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
       if (numMarkers == 2) {
         len -= 2;
       } else {
@@ -2579,8 +2566,9 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
     pContext->m_DataEnd = pContext->m_DataStart + len;
   }
   streamStartPos = m_Pos;
+  FXSYS_memset(m_WordBuffer, 0, ENDOBJ_LEN + 1);
   GetNextWord();
-  numMarkers = ReadEOLMarkers(m_Pos);
+  int numMarkers = ReadEOLMarkers(m_Pos);
   if (m_WordSize == ENDOBJ_LEN && numMarkers != 0 &&
       FXSYS_memcmp(m_WordBuffer, "endobj", ENDOBJ_LEN) == 0) {
     m_Pos = streamStartPos;
@@ -2589,10 +2577,7 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
 }
 void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess,
                                    FX_DWORD HeaderOffset) {
-  if (m_pFileBuf) {
-    FX_Free(m_pFileBuf);
-    m_pFileBuf = NULL;
-  }
+  FX_Free(m_pFileBuf);
   m_pFileBuf = FX_Alloc(uint8_t, m_BufSize);
   m_HeaderOffset = HeaderOffset;
   m_FileLen = pFileAccess->GetSize();
@@ -2614,7 +2599,8 @@ int32_t CPDF_SyntaxParser::GetDirectNum() {
 FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
                                        FX_FILESIZE limit,
                                        const uint8_t* tag,
-                                       FX_DWORD taglen) {
+                                       FX_DWORD taglen,
+                                       FX_BOOL checkKeyword) {
   uint8_t type = PDF_CharType[tag[0]];
   FX_BOOL bCheckLeft = type != 'D' && type != 'W';
   type = PDF_CharType[tag[taglen - 1]];
@@ -2623,13 +2609,13 @@ FX_BOOL CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
   if (bCheckRight && startpos + (int32_t)taglen <= limit &&
       GetCharAt(startpos + (int32_t)taglen, ch)) {
     uint8_t type = PDF_CharType[ch];
-    if (type == 'N' || type == 'R') {
+    if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
       return FALSE;
     }
   }
   if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
     uint8_t type = PDF_CharType[ch];
-    if (type == 'N' || type == 'R') {
+    if (type == 'N' || type == 'R' || (checkKeyword && type == 'D')) {
       return FALSE;
     }
   }
@@ -2685,7 +2671,8 @@ FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
         }
       }
       FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
-      if (!bWholeWord || IsWholeWord(startpos, limit, tag.GetPtr(), taglen)) {
+      if (!bWholeWord ||
+          IsWholeWord(startpos, limit, tag.GetPtr(), taglen, FALSE)) {
         m_Pos = startpos;
         return TRUE;
       }
@@ -2742,7 +2729,7 @@ int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
         if (pPatterns[i].m_Offset == pPatterns[i].m_Len) {
           if (!bWholeWord ||
               IsWholeWord(pos - pPatterns[i].m_Len, limit, pPatterns[i].m_pTag,
-                          pPatterns[i].m_Len)) {
+                          pPatterns[i].m_Len, FALSE)) {
             found = i;
             goto end;
           } else {
@@ -2815,7 +2802,7 @@ void CPDF_SyntaxParser::GetBinary(uint8_t* buffer, FX_DWORD size) {
 class CPDF_DataAvail final : public IPDF_DataAvail {
  public:
   CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);
-  ~CPDF_DataAvail();
+  ~CPDF_DataAvail() override;
 
   virtual FX_BOOL IsDocAvail(IFX_DownloadHints* pHints) override;
 
@@ -3008,9 +2995,8 @@ class CPDF_DataAvail final : public IPDF_DataAvail {
 
   CPDF_PageNode m_pageNodes;
 
-  CFX_CMapDWordToDWord* m_pageMapCheckState;
-
-  CFX_CMapDWordToDWord* m_pagesLoadState;
+  std::set<FX_DWORD> m_pageMapCheckState;
+  std::set<FX_DWORD> m_pagesLoadState;
 };
 
 IPDF_DataAvail::IPDF_DataAvail(IFX_FileAvail* pFileAvail,
@@ -3068,13 +3054,11 @@ CPDF_DataAvail::CPDF_DataAvail(IFX_FileAvail* pFileAvail,
   m_pAcroForm = NULL;
   m_pPageDict = NULL;
   m_pPageResource = NULL;
-  m_pageMapCheckState = NULL;
   m_docStatus = PDF_DATAAVAIL_HEADER;
   m_parser.m_bOwnFileRead = FALSE;
   m_bTotalLoadPageTree = FALSE;
   m_bCurPageDictLoadOK = FALSE;
   m_bLinearedDataOK = FALSE;
-  m_pagesLoadState = NULL;
 }
 CPDF_DataAvail::~CPDF_DataAvail() {
   if (m_pLinearized) {
@@ -3086,8 +3070,6 @@ CPDF_DataAvail::~CPDF_DataAvail() {
   if (m_pTrailer) {
     m_pTrailer->Release();
   }
-  delete m_pageMapCheckState;
-  delete m_pagesLoadState;
   int32_t i = 0;
   int32_t iSize = m_arrayAcroforms.GetSize();
   for (i = 0; i < iSize; ++i) {
@@ -3522,29 +3504,14 @@ FX_BOOL CPDF_DataAvail::PreparePageItem() {
   return TRUE;
 }
 FX_BOOL CPDF_DataAvail::IsFirstCheck(int iPage) {
-  if (NULL == m_pageMapCheckState) {
-    m_pageMapCheckState = new CFX_CMapDWordToDWord();
-  }
-  FX_DWORD dwValue = 0;
-  if (!m_pageMapCheckState->Lookup(iPage, dwValue)) {
-    m_pageMapCheckState->SetAt(iPage, 1);
-    return TRUE;
-  }
-  if (dwValue != 0) {
+  if (m_pageMapCheckState.find(iPage) != m_pageMapCheckState.end())
     return FALSE;
-  }
-  m_pageMapCheckState->SetAt(iPage, 1);
+
+  m_pageMapCheckState.insert(iPage);
   return TRUE;
 }
 void CPDF_DataAvail::ResetFirstCheck(int iPage) {
-  if (NULL == m_pageMapCheckState) {
-    m_pageMapCheckState = new CFX_CMapDWordToDWord();
-  }
-  FX_DWORD dwValue = 1;
-  if (!m_pageMapCheckState->Lookup(iPage, dwValue)) {
-    return;
-  }
-  m_pageMapCheckState->SetAt(iPage, 0);
+  m_pageMapCheckState.erase(iPage);
 }
 FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) {
   FX_DWORD iPageObjs = m_PageObjList.GetSize();
@@ -4133,13 +4100,11 @@ FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) {
       return FALSE;
     }
     CPDF_Dictionary* pTrailerDict = pTrailer->GetDict();
-    if (pTrailerDict) {
-      CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt");
-      if (pEncrypt && pEncrypt->GetType() == PDFOBJ_REFERENCE) {
-        m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
-        pTrailer->Release();
-        return TRUE;
-      }
+    CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt");
+    if (pEncrypt && pEncrypt->GetType() == PDFOBJ_REFERENCE) {
+      m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
+      pTrailer->Release();
+      return TRUE;
     }
     FX_DWORD xrefpos = GetDirectInteger(pTrailer->GetDict(), FX_BSTRC("Prev"));
     if (xrefpos) {
@@ -4256,8 +4221,7 @@ FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo,
   }
   pPageNode->m_dwPageNo = dwPageNo;
   CPDF_Dictionary* pDict = pPage->GetDict();
-  CFX_ByteString type =
-      pDict ? pDict->GetString(FX_BSTRC("Type")) : CFX_ByteString();
+  CFX_ByteString type = pDict->GetString(FX_BSTRC("Type"));
   if (type == FX_BSTRC("Pages")) {
     pPageNode->m_type = PDF_PAGENODE_PAGES;
     CPDF_Object* pKids = pDict->GetElement(FX_BSTRC("Kids"));
@@ -4518,16 +4482,12 @@ FX_BOOL CPDF_DataAvail::IsPageAvail(int32_t iPage, IFX_DownloadHints* pHints) {
     m_objs_array.RemoveAll();
     m_objnum_array.RemoveAll();
   }
-  if (m_pagesLoadState == NULL) {
-    m_pagesLoadState = new CFX_CMapDWordToDWord();
-  }
-  FX_DWORD dwPageLoad = 0;
-  if (m_pagesLoadState->Lookup(iPage, dwPageLoad) && dwPageLoad != 0) {
+  if (m_pagesLoadState.find(iPage) != m_pagesLoadState.end()) {
     return TRUE;
   }
   if (m_bLinearized) {
     if ((FX_DWORD)iPage == m_dwFirstPageNo) {
-      m_pagesLoadState->SetAt(iPage, TRUE);
+      m_pagesLoadState.insert(iPage);
       return TRUE;
     }
     if (!CheckLinearizedData(pHints)) {
@@ -4622,7 +4582,7 @@ FX_BOOL CPDF_DataAvail::IsPageAvail(int32_t iPage, IFX_DownloadHints* pHints) {
   m_bAnnotsLoad = FALSE;
   m_bCurPageDictLoadOK = FALSE;
   ResetFirstCheck(iPage);
-  m_pagesLoadState->SetAt(iPage, TRUE);
+  m_pagesLoadState.insert(iPage);
   return TRUE;
 }
 FX_BOOL CPDF_DataAvail::CheckResources(IFX_DownloadHints* pHints) {