Fix a leak in CPDF_SyntaxParser::GetObject().
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_parser.cpp
index b436ba1..27cc868 100644 (file)
@@ -45,10 +45,8 @@ int32_t GetHeaderOffset(IFX_FileRead* pFile) {
 }
 
 int32_t GetDirectInteger(CPDF_Dictionary* pDict, const CFX_ByteStringC& key) {
-  CPDF_Object* pObj = pDict->GetElement(key);
-  if (pObj && (pObj->GetType() == PDFOBJ_NUMBER))
-    return ((CPDF_Number*)pObj)->GetInteger();
-  return 0;
+  CPDF_Number* pObj = ToNumber(pDict->GetElement(key));
+  return pObj ? pObj->GetInteger() : 0;
 }
 
 bool CheckDirectType(CPDF_Dictionary* pDict,
@@ -98,7 +96,6 @@ CPDF_Parser::CPDF_Parser() {
   m_pDocument = NULL;
   m_pTrailer = NULL;
   m_pEncryptDict = NULL;
-  m_pSecurityHandler = NULL;
   m_pLinearized = NULL;
   m_dwFirstPageNo = 0;
   m_dwXrefStartObjNum = 0;
@@ -261,11 +258,9 @@ FX_DWORD CPDF_Parser::StartParse(IFX_FileRead* pFileAccess,
   }
   if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) {
     CPDF_Reference* pMetadata =
-        (CPDF_Reference*)m_pDocument->GetRoot()->GetElement(
-            FX_BSTRC("Metadata"));
-    if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) {
+        ToReference(m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata")));
+    if (pMetadata)
       m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum();
-    }
   }
   return PDFPARSE_ERROR_SUCCESS;
 }
@@ -279,64 +274,54 @@ FX_DWORD CPDF_Parser::SetEncryptHandler() {
   if (pEncryptObj) {
     if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) {
       SetEncryptDictionary(pEncryptDict);
-    } else if (pEncryptObj->GetType() == PDFOBJ_REFERENCE) {
-      pEncryptObj = m_pDocument->GetIndirectObject(
-          ((CPDF_Reference*)pEncryptObj)->GetRefObjNum());
-      if (pEncryptObj) {
+    } else if (CPDF_Reference* pRef = pEncryptObj->AsReference()) {
+      pEncryptObj = m_pDocument->GetIndirectObject(pRef->GetRefObjNum());
+      if (pEncryptObj)
         SetEncryptDictionary(pEncryptObj->GetDict());
-      }
     }
   }
   if (m_bForceUseSecurityHandler) {
     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
-    if (m_pSecurityHandler == NULL) {
+    if (!m_pSecurityHandler) {
       return PDFPARSE_ERROR_HANDLER;
     }
     if (!m_pSecurityHandler->OnInit(this, m_pEncryptDict)) {
       return err;
     }
-    CPDF_CryptoHandler* pCryptoHandler =
-        m_pSecurityHandler->CreateCryptoHandler();
-    if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler)) {
-      delete pCryptoHandler;
-      pCryptoHandler = NULL;
+    nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
+        m_pSecurityHandler->CreateCryptoHandler());
+    if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
       return PDFPARSE_ERROR_HANDLER;
     }
-    m_Syntax.SetEncrypt(pCryptoHandler);
+    m_Syntax.SetEncrypt(pCryptoHandler.release());
   } else if (m_pEncryptDict) {
     CFX_ByteString filter = m_pEncryptDict->GetString(FX_BSTRC("Filter"));
-    CPDF_SecurityHandler* pSecurityHandler = NULL;
+    nonstd::unique_ptr<CPDF_SecurityHandler> pSecurityHandler;
     FX_DWORD err = PDFPARSE_ERROR_HANDLER;
     if (filter == FX_BSTRC("Standard")) {
-      pSecurityHandler = FPDF_CreateStandardSecurityHandler();
+      pSecurityHandler.reset(FPDF_CreateStandardSecurityHandler());
       err = PDFPARSE_ERROR_PASSWORD;
     }
-    if (pSecurityHandler == NULL) {
+    if (!pSecurityHandler) {
       return PDFPARSE_ERROR_HANDLER;
     }
     if (!pSecurityHandler->OnInit(this, m_pEncryptDict)) {
-      delete pSecurityHandler;
-      pSecurityHandler = NULL;
       return err;
     }
-    m_pSecurityHandler = pSecurityHandler;
-    CPDF_CryptoHandler* pCryptoHandler =
-        pSecurityHandler->CreateCryptoHandler();
-    if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler)) {
-      delete pCryptoHandler;
-      pCryptoHandler = NULL;
+    m_pSecurityHandler = nonstd::move(pSecurityHandler);
+    nonstd::unique_ptr<CPDF_CryptoHandler> pCryptoHandler(
+        m_pSecurityHandler->CreateCryptoHandler());
+    if (!pCryptoHandler->Init(m_pEncryptDict, m_pSecurityHandler.get())) {
       return PDFPARSE_ERROR_HANDLER;
     }
-    m_Syntax.SetEncrypt(pCryptoHandler);
+    m_Syntax.SetEncrypt(pCryptoHandler.release());
   }
   return PDFPARSE_ERROR_SUCCESS;
 }
 void CPDF_Parser::ReleaseEncryptHandler() {
-  delete m_Syntax.m_pCryptoHandler;
-  m_Syntax.m_pCryptoHandler = NULL;
+  m_Syntax.m_pCryptoHandler.reset();
   if (!m_bForceUseSecurityHandler) {
-    delete m_pSecurityHandler;
-    m_pSecurityHandler = NULL;
+    m_pSecurityHandler.reset();
   }
 }
 FX_FILESIZE CPDF_Parser::GetObjectOffset(FX_DWORD objnum) {
@@ -449,24 +434,22 @@ FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos,
   FX_DWORD start_objnum = 0;
   FX_DWORD count = dwObjCount;
   FX_FILESIZE SavedPos = m_Syntax.SavePos();
-  int32_t recordsize = 20;
-  char* pBuf = FX_Alloc(char, 1024 * recordsize + 1);
-  pBuf[1024 * recordsize] = '\0';
+  const int32_t recordsize = 20;
+  std::vector<char> buf(1024 * recordsize + 1);
+  buf[1024 * recordsize] = '\0';
   int32_t nBlocks = count / 1024 + 1;
   for (int32_t block = 0; block < nBlocks; block++) {
     int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
     FX_DWORD dwReadSize = block_size * recordsize;
     if ((FX_FILESIZE)(dwStartPos + dwReadSize) > m_Syntax.m_FileLen) {
-      FX_Free(pBuf);
       return FALSE;
     }
-    if (!m_Syntax.ReadBlock((uint8_t*)pBuf, dwReadSize)) {
-      FX_Free(pBuf);
+    if (!m_Syntax.ReadBlock((uint8_t*)buf.data(), dwReadSize)) {
       return FALSE;
     }
     for (int32_t i = 0; i < block_size; i++) {
       FX_DWORD objnum = start_objnum + block * 1024 + i;
-      char* pEntry = pBuf + i * recordsize;
+      char* pEntry = buf.data() + i * recordsize;
       if (pEntry[17] == 'f') {
         m_CrossRef.SetAtGrow(objnum, 0);
         m_V5Type.SetAtGrow(objnum, 0);
@@ -475,7 +458,6 @@ FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos,
         if (offset == 0) {
           for (int32_t c = 0; c < 10; c++) {
             if (pEntry[c] < '0' || pEntry[c] > '9') {
-              FX_Free(pBuf);
               return FALSE;
             }
           }
@@ -498,7 +480,6 @@ FX_BOOL CPDF_Parser::LoadLinearizedCrossRefV4(FX_FILESIZE pos,
       }
     }
   }
-  FX_Free(pBuf);
   m_Syntax.RestorePos(SavedPos + count * recordsize);
   return TRUE;
 }
@@ -541,21 +522,21 @@ bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos,
     m_Syntax.ToNextWord();
     SavedPos = m_Syntax.SavePos();
     FX_BOOL bFirstItem = FALSE;
-    int32_t recordsize = 20;
+    const int32_t recordsize = 20;
     if (bFirst)
       bFirstItem = TRUE;
     m_dwXrefStartObjNum = start_objnum;
     if (!bSkip) {
-      char* pBuf = FX_Alloc(char, 1024 * recordsize + 1);
-      pBuf[1024 * recordsize] = '\0';
+      std::vector<char> buf(1024 * recordsize + 1);
+      buf[1024 * recordsize] = '\0';
       int32_t nBlocks = count / 1024 + 1;
       FX_BOOL bFirstBlock = TRUE;
       for (int32_t block = 0; block < nBlocks; block++) {
         int32_t block_size = block == nBlocks - 1 ? count % 1024 : 1024;
-        m_Syntax.ReadBlock((uint8_t*)pBuf, block_size * recordsize);
+        m_Syntax.ReadBlock((uint8_t*)buf.data(), block_size * recordsize);
         for (int32_t i = 0; i < block_size; i++) {
           FX_DWORD objnum = start_objnum + block * 1024 + i;
-          char* pEntry = pBuf + i * recordsize;
+          char* pEntry = buf.data() + i * recordsize;
           if (pEntry[17] == 'f') {
             if (bFirstItem) {
               objnum = 0;
@@ -576,7 +557,6 @@ bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos,
             if (offset == 0) {
               for (int32_t c = 0; c < 10; c++) {
                 if (pEntry[c] < '0' || pEntry[c] > '9') {
-                  FX_Free(pBuf);
                   return false;
                 }
               }
@@ -598,7 +578,6 @@ bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos,
           }
         }
       }
-      FX_Free(pBuf);
     }
     m_Syntax.RestorePos(SavedPos + count * recordsize);
   }
@@ -786,29 +765,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;
@@ -857,25 +827,21 @@ 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"));
-                      if (pRoot == NULL ||
-                          (pRoot->GetType() == PDFOBJ_REFERENCE &&
+                      CPDF_Reference* pRef = ToReference(pRoot);
+                      if (!pRoot ||
+                          (pRef &&
                            (FX_DWORD)m_CrossRef.GetSize() >
-                               ((CPDF_Reference*)pRoot)->GetRefObjNum() &&
-                           m_CrossRef.GetAt(((CPDF_Reference*)pRoot)
-                                                ->GetRefObjNum()) != 0)) {
+                               pRef->GetRefObjNum() &&
+                           m_CrossRef.GetAt(pRef->GetRefObjNum()) != 0)) {
                         FX_POSITION pos = pTrailer->GetStartPos();
                         while (pos) {
                           CFX_ByteString key;
@@ -888,7 +854,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 {
@@ -1007,25 +973,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) {
@@ -1048,8 +1014,7 @@ FX_BOOL CPDF_Parser::LoadCrossRefV5(FX_FILESIZE pos,
     for (FX_DWORD i = 0; i < nPairSize; i++) {
       CPDF_Object* pStartNumObj = pArray->GetElement(i * 2);
       CPDF_Object* pCountObj = pArray->GetElement(i * 2 + 1);
-      if (pStartNumObj && pStartNumObj->GetType() == PDFOBJ_NUMBER &&
-          pCountObj && pCountObj->GetType() == PDFOBJ_NUMBER) {
+      if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) {
         int nStartNum = pStartNumObj->GetInteger();
         int nCount = pCountObj->GetInteger();
         if (nStartNum >= 0 && nCount > 0) {
@@ -1157,33 +1122,24 @@ 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->GetType() == PDFOBJ_REFERENCE) {
-    pID = ParseIndirectObject(NULL, ((CPDF_Reference*)pID)->GetRefObjNum());
+  if (!pID)
+    return nullptr;
+
+  if (CPDF_Reference* pRef = pID->AsReference()) {
+    pID = ParseIndirectObject(nullptr, pRef->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 =
-      m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Root")) : NULL;
-  if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
-    return 0;
-  }
-  return ((CPDF_Reference*)pRef)->GetRefObjNum();
+  CPDF_Reference* pRef = ToReference(
+      m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Root")) : nullptr);
+  return pRef ? pRef->GetRefObjNum() : 0;
 }
 FX_DWORD CPDF_Parser::GetInfoObjNum() {
-  CPDF_Object* pRef =
-      m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Info")) : NULL;
-  if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
-    return 0;
-  }
-  return ((CPDF_Reference*)pRef)->GetRefObjNum();
+  CPDF_Reference* pRef = ToReference(
+      m_pTrailer ? m_pTrailer->GetElement(FX_BSTRC("Info")) : nullptr);
+  return pRef ? pRef->GetRefObjNum() : 0;
 }
 FX_BOOL CPDF_Parser::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) {
   bForm = FALSE;
@@ -1251,15 +1207,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);
@@ -1495,7 +1451,7 @@ CPDF_Dictionary* CPDF_Parser::LoadTrailerV4() {
 }
 
 FX_DWORD CPDF_Parser::GetPermissions(FX_BOOL bCheckRevision) {
-  if (m_pSecurityHandler == NULL) {
+  if (!m_pSecurityHandler) {
     return (FX_DWORD)-1;
   }
   FX_DWORD dwPermission = m_pSecurityHandler->GetPermissions();
@@ -1514,17 +1470,12 @@ FX_BOOL CPDF_Parser::IsOwner() {
 }
 void CPDF_Parser::SetSecurityHandler(CPDF_SecurityHandler* pSecurityHandler,
                                      FX_BOOL bForced) {
-  ASSERT(m_pSecurityHandler == NULL);
-  if (!m_bForceUseSecurityHandler) {
-    delete m_pSecurityHandler;
-    m_pSecurityHandler = NULL;
-  }
   m_bForceUseSecurityHandler = bForced;
-  m_pSecurityHandler = pSecurityHandler;
+  m_pSecurityHandler.reset(pSecurityHandler);
   if (m_bForceUseSecurityHandler) {
     return;
   }
-  m_Syntax.m_pCryptoHandler = pSecurityHandler->CreateCryptoHandler();
+  m_Syntax.m_pCryptoHandler.reset(pSecurityHandler->CreateCryptoHandler());
   m_Syntax.m_pCryptoHandler->Init(NULL, pSecurityHandler);
 }
 FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess,
@@ -1551,10 +1502,12 @@ FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess,
   if (!m_pLinearized) {
     return FALSE;
   }
-  if (m_pLinearized->GetDict() &&
-      m_pLinearized->GetDict()->GetElement(FX_BSTRC("Linearized"))) {
+
+  CPDF_Dictionary* pDict = m_pLinearized->GetDict();
+  if (pDict && pDict->GetElement(FX_BSTRC("Linearized"))) {
     m_Syntax.GetNextWord(bIsNumber);
-    CPDF_Object* pLen = m_pLinearized->GetDict()->GetElement(FX_BSTRC("L"));
+
+    CPDF_Object* pLen = pDict->GetElement(FX_BSTRC("L"));
     if (!pLen) {
       m_pLinearized->Release();
       m_pLinearized = NULL;
@@ -1563,14 +1516,13 @@ FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess,
     if (pLen->GetInteger() != (int)pFileAccess->GetSize()) {
       return FALSE;
     }
-    CPDF_Object* pNo = m_pLinearized->GetDict()->GetElement(FX_BSTRC("P"));
-    if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
+
+    if (CPDF_Number* pNo = ToNumber(pDict->GetElement(FX_BSTRC("P"))))
       m_dwFirstPageNo = pNo->GetInteger();
-    }
-    CPDF_Object* pTable = m_pLinearized->GetDict()->GetElement(FX_BSTRC("T"));
-    if (pTable && pTable->GetType() == PDFOBJ_NUMBER) {
+
+    if (CPDF_Number* pTable = ToNumber(pDict->GetElement(FX_BSTRC("T"))))
       m_LastXRefOffset = pTable->GetInteger();
-    }
+
     return TRUE;
   }
   m_pLinearized->Release();
@@ -1655,11 +1607,9 @@ FX_DWORD CPDF_Parser::StartAsynParse(IFX_FileRead* pFileAccess,
     }
   }
   if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) {
-    CPDF_Object* pMetadata =
-        m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata"));
-    if (pMetadata && pMetadata->GetType() == PDFOBJ_REFERENCE) {
-      m_Syntax.m_MetadataObjnum = ((CPDF_Reference*)pMetadata)->GetRefObjNum();
-    }
+    if (CPDF_Reference* pMetadata = ToReference(
+            m_pDocument->GetRoot()->GetElement(FX_BSTRC("Metadata"))))
+      m_Syntax.m_MetadataObjnum = pMetadata->GetRefObjNum();
   }
   return PDFPARSE_ERROR_SUCCESS;
 }
@@ -1722,7 +1672,6 @@ int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0;
 
 CPDF_SyntaxParser::CPDF_SyntaxParser() {
   m_pFileAccess = NULL;
-  m_pCryptoHandler = NULL;
   m_pFileBuf = NULL;
   m_BufSize = CPDF_ModuleMgr::kFileBufSize;
   m_pFileBuf = NULL;
@@ -2190,6 +2139,13 @@ CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList,
 
       ++nKeys;
       key = PDF_NameDecode(key);
+      if (key.IsEmpty())
+        continue;
+
+      CFX_ByteStringC keyNoSlash(key.c_str() + 1, key.GetLength() - 1);
+      if (keyNoSlash.IsEmpty())
+        continue;
+
       if (key == FX_BSTRC("/Contents"))
         dwSignValuePos = m_Pos;
 
@@ -2197,14 +2153,12 @@ CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjects* pObjList,
       if (!pObj)
         continue;
 
-      if (key.GetLength() >= 1) {
-        if (nKeys < 32) {
-          pDict->SetAt(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
-                       pObj);
-        } else {
-          pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
-                          pObj);
-        }
+      // TODO(thestig): Remove this conditional once CPDF_Dictionary has a
+      // better underlying map implementation.
+      if (nKeys < 32) {
+        pDict->SetAt(keyNoSlash, pObj);
+      } else {
+        pDict->AddValue(keyNoSlash, pObj);
       }
     }
 
@@ -2413,11 +2367,13 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
                                            FX_DWORD gennum) {
   CPDF_Object* pLenObj = pDict->GetElement(FX_BSTRC("Length"));
   FX_FILESIZE len = -1;
-  if (pLenObj && ((pLenObj->GetType() != PDFOBJ_REFERENCE) ||
-                  ((((CPDF_Reference*)pLenObj)->GetObjList()) &&
-                   ((CPDF_Reference*)pLenObj)->GetRefObjNum() != objnum))) {
+  CPDF_Reference* pLenObjRef = ToReference(pLenObj);
+
+  bool differingObjNum = !pLenObjRef || (pLenObjRef->GetObjList() &&
+                                         pLenObjRef->GetRefObjNum() != objnum);
+  if (pLenObj && differingObjNum)
     len = pLenObj->GetInteger();
-  }
+
   // Locate the start of stream.
   ToNextLine();
   FX_FILESIZE streamStartPos = m_Pos;
@@ -2427,7 +2383,7 @@ CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
   const unsigned int ENDSTREAM_LEN = sizeof("endstream") - 1;
   const unsigned int ENDOBJ_LEN = sizeof("endobj") - 1;
   CPDF_CryptoHandler* pCryptoHandler =
-      objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler;
+      objnum == (FX_DWORD)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get();
   if (!pCryptoHandler) {
     FX_BOOL bSearchForKeyword = TRUE;
     if (len >= 0) {
@@ -2772,6 +2728,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,
@@ -2824,7 +2781,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);
@@ -3101,7 +3059,7 @@ FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array,
         }
       } break;
       case PDFOBJ_REFERENCE: {
-        CPDF_Reference* pRef = (CPDF_Reference*)pObj;
+        CPDF_Reference* pRef = pObj->AsReference();
         FX_DWORD dwNum = pRef->GetRefObjNum();
         FX_FILESIZE offset;
         FX_DWORD original_size = GetObjectSize(dwNum, offset);
@@ -3143,13 +3101,10 @@ FX_BOOL CPDF_DataAvail::IsObjectsAvail(CFX_PtrArray& obj_array,
     int32_t iSize = new_obj_array.GetSize();
     for (i = 0; i < iSize; ++i) {
       CPDF_Object* pObj = (CPDF_Object*)new_obj_array[i];
-      int32_t type = pObj->GetType();
-      if (type == PDFOBJ_REFERENCE) {
-        CPDF_Reference* pRef = (CPDF_Reference*)pObj;
+      if (CPDF_Reference* pRef = pObj->AsReference()) {
         FX_DWORD dwNum = pRef->GetRefObjNum();
-        if (!m_objnum_array.Find(dwNum)) {
+        if (!m_objnum_array.Find(dwNum))
           ret_array.Add(pObj);
-        }
       } else {
         ret_array.Add(pObj);
       }
@@ -3417,37 +3372,37 @@ FX_BOOL CPDF_DataAvail::CheckRoot(IFX_DownloadHints* pHints) {
     m_docStatus = PDF_DATAAVAIL_ERROR;
     return FALSE;
   }
-  CPDF_Reference* pRef = (CPDF_Reference*)pDict->GetElement(FX_BSTRC("Pages"));
-  if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
+  CPDF_Reference* pRef = ToReference(pDict->GetElement(FX_BSTRC("Pages")));
+  if (!pRef) {
     m_docStatus = PDF_DATAAVAIL_ERROR;
     return FALSE;
   }
+
   m_PagesObjNum = pRef->GetRefObjNum();
   CPDF_Reference* pAcroFormRef =
-      (CPDF_Reference*)m_pRoot->GetDict()->GetElement(FX_BSTRC("AcroForm"));
-  if (pAcroFormRef && pAcroFormRef->GetType() == PDFOBJ_REFERENCE) {
+      ToReference(m_pRoot->GetDict()->GetElement(FX_BSTRC("AcroForm")));
+  if (pAcroFormRef) {
     m_bHaveAcroForm = TRUE;
     m_dwAcroFormObjNum = pAcroFormRef->GetRefObjNum();
   }
+
   if (m_dwInfoObjNum) {
     m_docStatus = PDF_DATAAVAIL_INFO;
   } else {
-    if (m_bHaveAcroForm) {
-      m_docStatus = PDF_DATAAVAIL_ACROFORM;
-    } else {
-      m_docStatus = PDF_DATAAVAIL_PAGETREE;
-    }
+    m_docStatus =
+        m_bHaveAcroForm ? PDF_DATAAVAIL_ACROFORM : PDF_DATAAVAIL_PAGETREE;
   }
   return TRUE;
 }
 FX_BOOL CPDF_DataAvail::PreparePageItem() {
   CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
   CPDF_Reference* pRef =
-      pRoot ? (CPDF_Reference*)pRoot->GetElement(FX_BSTRC("Pages")) : NULL;
-  if (pRef == NULL || pRef->GetType() != PDFOBJ_REFERENCE) {
+      ToReference(pRoot ? pRoot->GetElement(FX_BSTRC("Pages")) : nullptr);
+  if (!pRef) {
     m_docStatus = PDF_DATAAVAIL_ERROR;
     return FALSE;
   }
+
   m_PagesObjNum = pRef->GetRefObjNum();
   m_pCurrentParser = (CPDF_Parser*)m_pDocument->GetParser();
   m_docStatus = PDF_DATAAVAIL_PAGETREE;
@@ -3476,16 +3431,13 @@ 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();
-        CPDF_Object* pItem = NULL;
         for (int32_t j = 0; j < iSize; ++j) {
-          pItem = pArray->GetElement(j);
-          if (pItem && pItem->GetType() == PDFOBJ_REFERENCE) {
-            UnavailObjList.Add(((CPDF_Reference*)pItem)->GetRefObjNum());
-          }
+          if (CPDF_Reference* pRef = ToReference(pArray->GetElement(j)))
+            UnavailObjList.Add(pRef->GetRefObjNum());
         }
       }
     }
@@ -3540,17 +3492,14 @@ FX_BOOL CPDF_DataAvail::GetPageKids(CPDF_Parser* pParser, CPDF_Object* pPages) {
     return TRUE;
   }
   switch (pKids->GetType()) {
-    case PDFOBJ_REFERENCE: {
-      CPDF_Reference* pKid = (CPDF_Reference*)pKids;
-      m_PageObjList.Add(pKid->GetRefObjNum());
-    } break;
+    case PDFOBJ_REFERENCE:
+      m_PageObjList.Add(pKids->AsReference()->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) {
-          m_PageObjList.Add(((CPDF_Reference*)pKid)->GetRefObjNum());
-        }
+        if (CPDF_Reference* pRef = ToReference(pKidsArray->GetElement(i)))
+          m_PageObjList.Add(pRef->GetRefObjNum());
       }
     } break;
     default:
@@ -3621,7 +3570,7 @@ FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints* pHints) {
     return FALSE;
   }
   FX_BOOL bNeedDownLoad = FALSE;
-  if (pEndOffSet->GetType() == PDFOBJ_NUMBER) {
+  if (pEndOffSet->IsNumber()) {
     FX_DWORD dwEnd = pEndOffSet->GetInteger();
     dwEnd += 512;
     if ((FX_FILESIZE)dwEnd > m_dwFileLen) {
@@ -3636,12 +3585,12 @@ FX_BOOL CPDF_DataAvail::CheckFirstPage(IFX_DownloadHints* pHints) {
   }
   m_dwLastXRefOffset = 0;
   FX_FILESIZE dwFileLen = 0;
-  if (pXRefOffset->GetType() == PDFOBJ_NUMBER) {
+  if (pXRefOffset->IsNumber())
     m_dwLastXRefOffset = pXRefOffset->GetInteger();
-  }
-  if (pFileLen->GetType() == PDFOBJ_NUMBER) {
+
+  if (pFileLen->IsNumber())
     dwFileLen = pFileLen->GetInteger();
-  }
+
   if (!m_pFileAvail->IsDataAvail(m_dwLastXRefOffset,
                                  (FX_DWORD)(dwFileLen - m_dwLastXRefOffset))) {
     if (m_docStatus == PDF_DATAAVAIL_FIRSTPAGE) {
@@ -3733,9 +3682,10 @@ FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) {
   if (!m_pLinearized) {
     return FALSE;
   }
-  if (m_pLinearized->GetDict() &&
-      m_pLinearized->GetDict()->GetElement(FX_BSTRC("Linearized"))) {
-    CPDF_Object* pLen = m_pLinearized->GetDict()->GetElement(FX_BSTRC("L"));
+
+  CPDF_Dictionary* pDict = m_pLinearized->GetDict();
+  if (pDict && pDict->GetElement(FX_BSTRC("Linearized"))) {
+    CPDF_Object* pLen = pDict->GetElement(FX_BSTRC("L"));
     if (!pLen) {
       return FALSE;
     }
@@ -3743,10 +3693,10 @@ FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) {
       return FALSE;
     }
     m_bLinearized = TRUE;
-    CPDF_Object* pNo = m_pLinearized->GetDict()->GetElement(FX_BSTRC("P"));
-    if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
+
+    if (CPDF_Number* pNo = ToNumber(pDict->GetElement(FX_BSTRC("P"))))
       m_dwFirstPageNo = pNo->GetInteger();
-    }
+
     return TRUE;
   }
   return FALSE;
@@ -3808,8 +3758,9 @@ int32_t CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints,
       return 0;
     }
     CPDF_Dictionary* pDict = pObj->GetDict();
-    CPDF_Object* pName = pDict ? pDict->GetElement(FX_BSTRC("Type")) : NULL;
-    if (pName && pName->GetType() == PDFOBJ_NAME) {
+    CPDF_Name* pName =
+        ToName(pDict ? pDict->GetElement(FX_BSTRC("Type")) : nullptr);
+    if (pName) {
       if (pName->GetString() == FX_BSTRC("XRef")) {
         m_Pos += m_parser.m_Syntax.SavePos();
         xref_offset = pObj->GetDict()->GetInteger(FX_BSTRC("Prev"));
@@ -4047,7 +3998,7 @@ FX_BOOL CPDF_DataAvail::CheckTrailer(IFX_DownloadHints* pHints) {
 
     CPDF_Dictionary* pTrailerDict = pTrailer->GetDict();
     CPDF_Object* pEncrypt = pTrailerDict->GetElement("Encrypt");
-    if (pEncrypt && pEncrypt->GetType() == PDFOBJ_REFERENCE) {
+    if (ToReference(pEncrypt)) {
       m_docStatus = PDF_DATAAVAIL_LOADALLFILE;
       return TRUE;
     }
@@ -4116,21 +4067,23 @@ 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) {
+    CPDF_Reference* pKid = ToReference(pArray->GetElement(i));
+    if (!pKid)
       continue;
-    }
+
     CPDF_PageNode* pNode = new CPDF_PageNode();
     pPageNode->m_childNode.Add(pNode);
-    pNode->m_dwPageNo = ((CPDF_Reference*)pKid)->GetRefObjNum();
+    pNode->m_dwPageNo = pKid->GetRefObjNum();
   }
   pPages->Release();
   return TRUE;
@@ -4151,7 +4104,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();
@@ -4174,21 +4127,21 @@ FX_BOOL CPDF_DataAvail::CheckUnkownPageNode(FX_DWORD dwPageNo,
     }
     switch (pKids->GetType()) {
       case PDFOBJ_REFERENCE: {
-        CPDF_Reference* pKid = (CPDF_Reference*)pKids;
+        CPDF_Reference* pKid = pKids->AsReference();
         CPDF_PageNode* pNode = new CPDF_PageNode();
         pPageNode->m_childNode.Add(pNode);
         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) {
+          CPDF_Reference* pKid = ToReference(pKidsArray->GetElement(i));
+          if (!pKid)
             continue;
-          }
+
           CPDF_PageNode* pNode = new CPDF_PageNode();
           pPageNode->m_childNode.Add(pNode);
-          pNode->m_dwPageNo = ((CPDF_Reference*)pKid)->GetRefObjNum();
+          pNode->m_dwPageNo = pKid->GetRefObjNum();
         }
       } break;
       default:
@@ -4207,7 +4160,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 +4189,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 +4222,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;