Set a recursion limit on CPDF_DataAvail::CheckPageNode
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_parser.cpp
index 514380e..dd416fb 100644 (file)
@@ -784,29 +784,20 @@ FX_BOOL CPDF_Parser::RebuildCrossRef() {
                 FX_FILESIZE obj_end = 0;
                 CPDF_Object* pObject = ParseIndirectObjectAtByStrict(
                     m_pDocument, obj_pos, objnum, NULL, &obj_end);
-                if (pObject) {
-                  int iType = pObject->GetType();
-                  if (iType == PDFOBJ_STREAM) {
-                    CPDF_Stream* pStream = (CPDF_Stream*)pObject;
-                    CPDF_Dictionary* pDict = pStream->GetDict();
-                    if (pDict) {
-                      if (pDict->KeyExist(FX_BSTRC("Type"))) {
-                        CFX_ByteString bsValue =
-                            pDict->GetString(FX_BSTRC("Type"));
-                        if (bsValue == FX_BSTRC("XRef") &&
-                            pDict->KeyExist(FX_BSTRC("Size"))) {
-                          CPDF_Object* pRoot =
-                              pDict->GetElement(FX_BSTRC("Root"));
-                          if (pRoot && pRoot->GetDict() &&
-                              pRoot->GetDict()->GetElement(FX_BSTRC("Pages"))) {
-                            if (m_pTrailer) {
-                              m_pTrailer->Release();
-                            }
-                            m_pTrailer = ToDictionary(pDict->Clone());
-                          }
+                if (CPDF_Stream* pStream = ToStream(pObject)) {
+                  if (CPDF_Dictionary* pDict = pStream->GetDict()) {
+                    if ((pDict->KeyExist(FX_BSTRC("Type"))) &&
+                        (pDict->GetString(FX_BSTRC("Type")) ==
+                             FX_BSTRC("XRef") &&
+                         pDict->KeyExist(FX_BSTRC("Size")))) {
+                      CPDF_Object* pRoot = pDict->GetElement(FX_BSTRC("Root"));
+                      if (pRoot && pRoot->GetDict() &&
+                          pRoot->GetDict()->GetElement(FX_BSTRC("Pages"))) {
+                        if (m_pTrailer)
+                          m_pTrailer->Release();
+                        m_pTrailer = ToDictionary(pDict->Clone());
                         }
                       }
-                    }
                   }
                 }
                 FX_FILESIZE offset = 0;
@@ -855,16 +846,12 @@ FX_BOOL CPDF_Parser::RebuildCrossRef() {
               m_Syntax.RestorePos(pos + i - m_Syntax.m_HeaderOffset);
               CPDF_Object* pObj = m_Syntax.GetObject(m_pDocument, 0, 0, 0);
               if (pObj) {
-                if (!pObj->IsDictionary() && pObj->GetType() != PDFOBJ_STREAM) {
+                if (!pObj->IsDictionary() && !pObj->AsStream()) {
                   pObj->Release();
                 } else {
-                  CPDF_Dictionary* pTrailer = NULL;
-                  if (pObj->GetType() == PDFOBJ_STREAM) {
-                    pTrailer = ((CPDF_Stream*)pObj)->GetDict();
-                  } else {
-                    pTrailer = pObj->AsDictionary();
-                  }
-                  if (pTrailer) {
+                  CPDF_Stream* pStream = pObj->AsStream();
+                  if (CPDF_Dictionary* pTrailer =
+                          pStream ? pStream->GetDict() : pObj->AsDictionary()) {
                     if (m_pTrailer) {
                       CPDF_Object* pRoot =
                           pTrailer->GetElement(FX_BSTRC("Root"));
@@ -886,7 +873,7 @@ FX_BOOL CPDF_Parser::RebuildCrossRef() {
                         pObj->Release();
                       }
                     } else {
-                      if (pObj->GetType() == PDFOBJ_STREAM) {
+                      if (pObj->IsStream()) {
                         m_pTrailer = ToDictionary(pTrailer->Clone());
                         pObj->Release();
                       } else {
@@ -1005,25 +992,25 @@ FX_BOOL CPDF_Parser::RebuildCrossRef() {
 FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos,
                                     FX_FILESIZE& prev,
                                     FX_BOOL bMainXRef) {
-  CPDF_Stream* pStream =
-      (CPDF_Stream*)ParseIndirectObjectAt(m_pDocument, pos, 0, NULL);
-  if (!pStream) {
+  CPDF_Object* pObject = ParseIndirectObjectAt(m_pDocument, pos, 0, nullptr);
+  if (!pObject)
     return FALSE;
-  }
+
   if (m_pDocument) {
     CPDF_Dictionary* pDict = m_pDocument->GetRoot();
-    if (!pDict || pDict->GetObjNum() != pStream->m_ObjNum) {
-      m_pDocument->InsertIndirectObject(pStream->m_ObjNum, pStream);
+    if (!pDict || pDict->GetObjNum() != pObject->m_ObjNum) {
+      m_pDocument->InsertIndirectObject(pObject->m_ObjNum, pObject);
     } else {
-      if (pStream->GetType() == PDFOBJ_STREAM) {
-        pStream->Release();
-      }
+      if (pObject->IsStream())
+        pObject->Release();
       return FALSE;
     }
   }
-  if (pStream->GetType() != PDFOBJ_STREAM) {
+
+  CPDF_Stream* pStream = pObject->AsStream();
+  if (!pStream)
     return FALSE;
-  }
+
   prev = pStream->GetDict()->GetInteger(FX_BSTRC("Prev"));
   int32_t size = pStream->GetDict()->GetInteger(FX_BSTRC("Size"));
   if (size < 0) {
@@ -1154,17 +1141,14 @@ FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos,
 }
 CPDF_Array* CPDF_Parser::GetIDArray() {
   CPDF_Object* pID = m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("ID")) : NULL;
-  if (pID == NULL) {
-    return NULL;
-  }
+  if (!pID)
+    return nullptr;
+
   if (pID->GetType() == PDFOBJ_REFERENCE) {
     pID = ParseIndirectObject(NULL, ((CPDF_Reference*)pID)->GetRefObjNum());
     m_pTrailer->SetAt(FX_BSTRC("ID"), pID);
   }
-  if (pID == NULL || pID->GetType() != PDFOBJ_ARRAY) {
-    return NULL;
-  }
-  return (CPDF_Array*)pID;
+  return ToArray(pID);
 }
 FX_DWORD CPDF_Parser::GetRootObjNum() {
   CPDF_Object* pRef =
@@ -1248,15 +1232,15 @@ CPDF_Object* CPDF_Parser::ParseIndirectObject(CPDF_IndirectObjects* pObjList,
 }
 
 CPDF_StreamAcc* CPDF_Parser::GetObjectStream(FX_DWORD objnum) {
-  CPDF_StreamAcc* pStreamAcc = NULL;
-  if (m_ObjectStreamMap.Lookup((void*)(uintptr_t)objnum, (void*&)pStreamAcc)) {
+  CPDF_StreamAcc* pStreamAcc = nullptr;
+  if (m_ObjectStreamMap.Lookup((void*)(uintptr_t)objnum, (void*&)pStreamAcc))
     return pStreamAcc;
-  }
+
   const CPDF_Stream* pStream =
-      m_pDocument ? (CPDF_Stream*)m_pDocument->GetIndirectObject(objnum) : NULL;
-  if (pStream == NULL || pStream->GetType() != PDFOBJ_STREAM) {
-    return NULL;
-  }
+      ToStream(m_pDocument ? m_pDocument->GetIndirectObject(objnum) : nullptr);
+  if (!pStream)
+    return nullptr;
+
   pStreamAcc = new CPDF_StreamAcc;
   pStreamAcc->LoadAllData(pStream);
   m_ObjectStreamMap.SetAt((void*)(uintptr_t)objnum, pStreamAcc);
@@ -2770,6 +2754,7 @@ class CPDF_DataAvail final : public IPDF_DataAvail {
  protected:
   static const int kMaxDataAvailRecursionDepth = 64;
   static int s_CurrentDataAvailRecursionDepth;
+  static const int kMaxPageRecursionDepth = 1024;
 
   FX_DWORD GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
   FX_BOOL IsObjectsAvail(CFX_PtrArray& obj_array,
@@ -2822,7 +2807,8 @@ class CPDF_DataAvail final : public IPDF_DataAvail {
   FX_BOOL CheckPageNode(CPDF_PageNode& pageNodes,
                         int32_t iPage,
                         int32_t& iCount,
-                        IFX_DownloadHints* pHints);
+                        IFX_DownloadHints* pHints,
+                        int level);
   FX_BOOL CheckUnkownPageNode(FX_DWORD dwPageNo,
                               CPDF_PageNode* pPageNode,
                               IFX_DownloadHints* pHints);
@@ -3474,7 +3460,7 @@ FX_BOOL CPDF_DataAvail::CheckPage(IFX_DownloadHints* pHints) {
       }
       continue;
     }
-    if (pObj->GetType() == PDFOBJ_ARRAY) {
+    if (pObj->IsArray()) {
       CPDF_Array* pArray = pObj->GetArray();
       if (pArray) {
         int32_t iSize = pArray->GetCount();
@@ -3543,7 +3529,7 @@ FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) {
       m_PageObjList.Add(pKid->GetRefObjNum());
     } break;
     case PDFOBJ_ARRAY: {
-      CPDF_Array* pKidsArray = (CPDF_Array*)pKids;
+      CPDF_Array* pKidsArray = pKids->AsArray();
       for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) {
         CPDF_Object* pKid = (CPDF_Object*)pKidsArray->GetElement(i);
         if (pKid && pKid->GetType() == PDFOBJ_REFERENCE) {
@@ -4116,13 +4102,15 @@ FX_BOOL CPDF_DataAvail::CheckArrayPageNode(FX_DWORD dwPageNo,
     }
     return FALSE;
   }
-  if (pPages->GetType() != PDFOBJ_ARRAY) {
+
+  CPDF_Array* pArray = pPages->AsArray();
+  if (!pArray) {
     pPages->Release();
     m_docStatus = PDF_DATAAVAIL_ERROR;
     return FALSE;
   }
+
   pPageNode->m_type = PDF_PAGENODE_PAGES;
-  CPDF_Array* pArray = (CPDF_Array*)pPages;
   for (FX_DWORD i = 0; i < pArray->GetCount(); ++i) {
     CPDF_Object* pKid = (CPDF_Object*)pArray->GetElement(i);
     if (!pKid || pKid->GetType() != PDFOBJ_REFERENCE) {
@@ -4151,7 +4139,7 @@ FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo,
     }
     return FALSE;
   }
-  if (pPage->GetType() == PDFOBJ_ARRAY) {
+  if (pPage->IsArray()) {
     pPageNode->m_dwPageNo = dwPageNo;
     pPageNode->m_type = PDF_PAGENODE_ARRAY;
     pPage->Release();
@@ -4180,7 +4168,7 @@ FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo,
         pNode->m_dwPageNo = pKid->GetRefObjNum();
       } break;
       case PDFOBJ_ARRAY: {
-        CPDF_Array* pKidsArray = (CPDF_Array*)pKids;
+        CPDF_Array* pKidsArray = pKids->AsArray();
         for (FX_DWORD i = 0; i < pKidsArray->GetCount(); ++i) {
           CPDF_Object* pKid = (CPDF_Object*)pKidsArray->GetElement(i);
           if (!pKid || pKid->GetType() != PDFOBJ_REFERENCE) {
@@ -4207,7 +4195,11 @@ FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo,
 FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_PageNode& pageNodes,
                                       int32_t iPage,
                                       int32_t& iCount,
-                                      IFX_DownloadHints* pHints) {
+                                      IFX_DownloadHints* pHints,
+                                      int level) {
+  if (level >= kMaxPageRecursionDepth) {
+    return FALSE;
+  }
   int32_t iSize = pageNodes.m_childNode.GetSize();
   if (iSize <= 0 || iPage >= iSize) {
     m_docStatus = PDF_DATAAVAIL_ERROR;
@@ -4232,7 +4224,7 @@ FX_BOOL CPDF_DataAvail::CheckPageNode(CPDF_PageNode& pageNodes,
         }
         break;
       case PDF_PAGENODE_PAGES:
-        if (!CheckPageNode(*pNode, iPage, iCount, pHints)) {
+        if (!CheckPageNode(*pNode, iPage, iCount, pHints, level + 1)) {
           return FALSE;
         }
         break;
@@ -4265,7 +4257,7 @@ FX_BOOL CPDF_DataAvail::LoadDocPage(int32_t iPage, IFX_DownloadHints* pHints) {
     return TRUE;
   }
   int32_t iCount = -1;
-  return CheckPageNode(m_pageNodes, iPage, iCount, pHints);
+  return CheckPageNode(m_pageNodes, iPage, iCount, pHints, 0);
 }
 FX_BOOL CPDF_DataAvail::CheckPageCount(IFX_DownloadHints* pHints) {
   FX_BOOL bExist = FALSE;