| Index: core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp
 | 
| diff --git a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp b/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp
 | 
| deleted file mode 100644
 | 
| index 32a75f98da9549d13827dfe534486ab646b86109..0000000000000000000000000000000000000000
 | 
| --- a/core/fpdfapi/fpdf_parser/cpdf_syntax_parser.cpp
 | 
| +++ /dev/null
 | 
| @@ -1,997 +0,0 @@
 | 
| -// Copyright 2016 PDFium Authors. All rights reserved.
 | 
| -// Use of this source code is governed by a BSD-style license that can be
 | 
| -// found in the LICENSE file.
 | 
| -
 | 
| -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 | 
| -
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_syntax_parser.h"
 | 
| -
 | 
| -#include <vector>
 | 
| -
 | 
| -#include "core/fpdfapi/cpdf_modulemgr.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_array.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_crypto_handler.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_name.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_null.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_number.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_reference.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_stream.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/cpdf_string.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/fpdf_parser_decode.h"
 | 
| -#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h"
 | 
| -#include "core/fxcrt/fx_ext.h"
 | 
| -#include "third_party/base/numerics/safe_math.h"
 | 
| -
 | 
| -namespace {
 | 
| -
 | 
| -struct SearchTagRecord {
 | 
| -  CFX_ByteStringC m_bsTag;
 | 
| -  FX_STRSIZE m_Offset;
 | 
| -};
 | 
| -
 | 
| -}  // namespace
 | 
| -
 | 
| -// static
 | 
| -int CPDF_SyntaxParser::s_CurrentRecursionDepth = 0;
 | 
| -
 | 
| -CPDF_SyntaxParser::CPDF_SyntaxParser()
 | 
| -    : CPDF_SyntaxParser(CFX_WeakPtr<CFX_ByteStringPool>()) {}
 | 
| -
 | 
| -CPDF_SyntaxParser::CPDF_SyntaxParser(
 | 
| -    const CFX_WeakPtr<CFX_ByteStringPool>& pPool)
 | 
| -    : m_MetadataObjnum(0),
 | 
| -      m_pFileAccess(nullptr),
 | 
| -      m_pFileBuf(nullptr),
 | 
| -      m_BufSize(CPDF_ModuleMgr::kFileBufSize),
 | 
| -      m_pPool(pPool) {}
 | 
| -
 | 
| -CPDF_SyntaxParser::~CPDF_SyntaxParser() {
 | 
| -  FX_Free(m_pFileBuf);
 | 
| -}
 | 
| -
 | 
| -FX_BOOL CPDF_SyntaxParser::GetCharAt(FX_FILESIZE pos, uint8_t& ch) {
 | 
| -  CFX_AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
 | 
| -  m_Pos = pos;
 | 
| -  return GetNextChar(ch);
 | 
| -}
 | 
| -
 | 
| -FX_BOOL CPDF_SyntaxParser::GetNextChar(uint8_t& ch) {
 | 
| -  FX_FILESIZE pos = m_Pos + m_HeaderOffset;
 | 
| -  if (pos >= m_FileLen)
 | 
| -    return FALSE;
 | 
| -
 | 
| -  if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
 | 
| -    FX_FILESIZE read_pos = pos;
 | 
| -    uint32_t read_size = m_BufSize;
 | 
| -    if ((FX_FILESIZE)read_size > m_FileLen)
 | 
| -      read_size = (uint32_t)m_FileLen;
 | 
| -
 | 
| -    if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
 | 
| -      if (m_FileLen < (FX_FILESIZE)read_size) {
 | 
| -        read_pos = 0;
 | 
| -        read_size = (uint32_t)m_FileLen;
 | 
| -      } else {
 | 
| -        read_pos = m_FileLen - read_size;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size))
 | 
| -      return FALSE;
 | 
| -
 | 
| -    m_BufOffset = read_pos;
 | 
| -  }
 | 
| -  ch = m_pFileBuf[pos - m_BufOffset];
 | 
| -  m_Pos++;
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -FX_BOOL CPDF_SyntaxParser::GetCharAtBackward(FX_FILESIZE pos, uint8_t& ch) {
 | 
| -  pos += m_HeaderOffset;
 | 
| -  if (pos >= m_FileLen)
 | 
| -    return FALSE;
 | 
| -
 | 
| -  if (m_BufOffset >= pos || (FX_FILESIZE)(m_BufOffset + m_BufSize) <= pos) {
 | 
| -    FX_FILESIZE read_pos;
 | 
| -    if (pos < (FX_FILESIZE)m_BufSize)
 | 
| -      read_pos = 0;
 | 
| -    else
 | 
| -      read_pos = pos - m_BufSize + 1;
 | 
| -
 | 
| -    uint32_t read_size = m_BufSize;
 | 
| -    if ((FX_FILESIZE)(read_pos + read_size) > m_FileLen) {
 | 
| -      if (m_FileLen < (FX_FILESIZE)read_size) {
 | 
| -        read_pos = 0;
 | 
| -        read_size = (uint32_t)m_FileLen;
 | 
| -      } else {
 | 
| -        read_pos = m_FileLen - read_size;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    if (!m_pFileAccess->ReadBlock(m_pFileBuf, read_pos, read_size))
 | 
| -      return FALSE;
 | 
| -
 | 
| -    m_BufOffset = read_pos;
 | 
| -  }
 | 
| -  ch = m_pFileBuf[pos - m_BufOffset];
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -FX_BOOL CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, uint32_t size) {
 | 
| -  if (!m_pFileAccess->ReadBlock(pBuf, m_Pos + m_HeaderOffset, size))
 | 
| -    return FALSE;
 | 
| -  m_Pos += size;
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -void CPDF_SyntaxParser::GetNextWordInternal(bool* bIsNumber) {
 | 
| -  m_WordSize = 0;
 | 
| -  if (bIsNumber)
 | 
| -    *bIsNumber = true;
 | 
| -
 | 
| -  uint8_t ch;
 | 
| -  if (!GetNextChar(ch))
 | 
| -    return;
 | 
| -
 | 
| -  while (1) {
 | 
| -    while (PDFCharIsWhitespace(ch)) {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -    }
 | 
| -
 | 
| -    if (ch != '%')
 | 
| -      break;
 | 
| -
 | 
| -    while (1) {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -      if (PDFCharIsLineEnding(ch))
 | 
| -        break;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (PDFCharIsDelimiter(ch)) {
 | 
| -    if (bIsNumber)
 | 
| -      *bIsNumber = false;
 | 
| -
 | 
| -    m_WordBuffer[m_WordSize++] = ch;
 | 
| -    if (ch == '/') {
 | 
| -      while (1) {
 | 
| -        if (!GetNextChar(ch))
 | 
| -          return;
 | 
| -
 | 
| -        if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) {
 | 
| -          m_Pos--;
 | 
| -          return;
 | 
| -        }
 | 
| -
 | 
| -        if (m_WordSize < sizeof(m_WordBuffer) - 1)
 | 
| -          m_WordBuffer[m_WordSize++] = ch;
 | 
| -      }
 | 
| -    } else if (ch == '<') {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -
 | 
| -      if (ch == '<')
 | 
| -        m_WordBuffer[m_WordSize++] = ch;
 | 
| -      else
 | 
| -        m_Pos--;
 | 
| -    } else if (ch == '>') {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -
 | 
| -      if (ch == '>')
 | 
| -        m_WordBuffer[m_WordSize++] = ch;
 | 
| -      else
 | 
| -        m_Pos--;
 | 
| -    }
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  while (1) {
 | 
| -    if (m_WordSize < sizeof(m_WordBuffer) - 1)
 | 
| -      m_WordBuffer[m_WordSize++] = ch;
 | 
| -
 | 
| -    if (!PDFCharIsNumeric(ch)) {
 | 
| -      if (bIsNumber)
 | 
| -        *bIsNumber = false;
 | 
| -    }
 | 
| -
 | 
| -    if (!GetNextChar(ch))
 | 
| -      return;
 | 
| -
 | 
| -    if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
 | 
| -      m_Pos--;
 | 
| -      break;
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -CFX_ByteString CPDF_SyntaxParser::ReadString() {
 | 
| -  uint8_t ch;
 | 
| -  if (!GetNextChar(ch))
 | 
| -    return CFX_ByteString();
 | 
| -
 | 
| -  CFX_ByteTextBuf buf;
 | 
| -  int32_t parlevel = 0;
 | 
| -  int32_t status = 0;
 | 
| -  int32_t iEscCode = 0;
 | 
| -  while (1) {
 | 
| -    switch (status) {
 | 
| -      case 0:
 | 
| -        if (ch == ')') {
 | 
| -          if (parlevel == 0) {
 | 
| -            return buf.MakeString();
 | 
| -          }
 | 
| -          parlevel--;
 | 
| -          buf.AppendChar(')');
 | 
| -        } else if (ch == '(') {
 | 
| -          parlevel++;
 | 
| -          buf.AppendChar('(');
 | 
| -        } else if (ch == '\\') {
 | 
| -          status = 1;
 | 
| -        } else {
 | 
| -          buf.AppendChar(ch);
 | 
| -        }
 | 
| -        break;
 | 
| -      case 1:
 | 
| -        if (ch >= '0' && ch <= '7') {
 | 
| -          iEscCode = FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
 | 
| -          status = 2;
 | 
| -          break;
 | 
| -        }
 | 
| -
 | 
| -        if (ch == 'n') {
 | 
| -          buf.AppendChar('\n');
 | 
| -        } else if (ch == 'r') {
 | 
| -          buf.AppendChar('\r');
 | 
| -        } else if (ch == 't') {
 | 
| -          buf.AppendChar('\t');
 | 
| -        } else if (ch == 'b') {
 | 
| -          buf.AppendChar('\b');
 | 
| -        } else if (ch == 'f') {
 | 
| -          buf.AppendChar('\f');
 | 
| -        } else if (ch == '\r') {
 | 
| -          status = 4;
 | 
| -          break;
 | 
| -        } else if (ch != '\n') {
 | 
| -          buf.AppendChar(ch);
 | 
| -        }
 | 
| -        status = 0;
 | 
| -        break;
 | 
| -      case 2:
 | 
| -        if (ch >= '0' && ch <= '7') {
 | 
| -          iEscCode =
 | 
| -              iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
 | 
| -          status = 3;
 | 
| -        } else {
 | 
| -          buf.AppendChar(iEscCode);
 | 
| -          status = 0;
 | 
| -          continue;
 | 
| -        }
 | 
| -        break;
 | 
| -      case 3:
 | 
| -        if (ch >= '0' && ch <= '7') {
 | 
| -          iEscCode =
 | 
| -              iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
 | 
| -          buf.AppendChar(iEscCode);
 | 
| -          status = 0;
 | 
| -        } else {
 | 
| -          buf.AppendChar(iEscCode);
 | 
| -          status = 0;
 | 
| -          continue;
 | 
| -        }
 | 
| -        break;
 | 
| -      case 4:
 | 
| -        status = 0;
 | 
| -        if (ch != '\n')
 | 
| -          continue;
 | 
| -        break;
 | 
| -    }
 | 
| -
 | 
| -    if (!GetNextChar(ch))
 | 
| -      break;
 | 
| -  }
 | 
| -
 | 
| -  GetNextChar(ch);
 | 
| -  return buf.MakeString();
 | 
| -}
 | 
| -
 | 
| -CFX_ByteString CPDF_SyntaxParser::ReadHexString() {
 | 
| -  uint8_t ch;
 | 
| -  if (!GetNextChar(ch))
 | 
| -    return CFX_ByteString();
 | 
| -
 | 
| -  CFX_ByteTextBuf buf;
 | 
| -  bool bFirst = true;
 | 
| -  uint8_t code = 0;
 | 
| -  while (1) {
 | 
| -    if (ch == '>')
 | 
| -      break;
 | 
| -
 | 
| -    if (std::isxdigit(ch)) {
 | 
| -      int val = FXSYS_toHexDigit(ch);
 | 
| -      if (bFirst) {
 | 
| -        code = val * 16;
 | 
| -      } else {
 | 
| -        code += val;
 | 
| -        buf.AppendByte(code);
 | 
| -      }
 | 
| -      bFirst = !bFirst;
 | 
| -    }
 | 
| -
 | 
| -    if (!GetNextChar(ch))
 | 
| -      break;
 | 
| -  }
 | 
| -  if (!bFirst)
 | 
| -    buf.AppendByte(code);
 | 
| -
 | 
| -  return buf.MakeString();
 | 
| -}
 | 
| -
 | 
| -void CPDF_SyntaxParser::ToNextLine() {
 | 
| -  uint8_t ch;
 | 
| -  while (GetNextChar(ch)) {
 | 
| -    if (ch == '\n')
 | 
| -      break;
 | 
| -
 | 
| -    if (ch == '\r') {
 | 
| -      GetNextChar(ch);
 | 
| -      if (ch != '\n')
 | 
| -        --m_Pos;
 | 
| -      break;
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void CPDF_SyntaxParser::ToNextWord() {
 | 
| -  uint8_t ch;
 | 
| -  if (!GetNextChar(ch))
 | 
| -    return;
 | 
| -
 | 
| -  while (1) {
 | 
| -    while (PDFCharIsWhitespace(ch)) {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -    }
 | 
| -
 | 
| -    if (ch != '%')
 | 
| -      break;
 | 
| -
 | 
| -    while (1) {
 | 
| -      if (!GetNextChar(ch))
 | 
| -        return;
 | 
| -      if (PDFCharIsLineEnding(ch))
 | 
| -        break;
 | 
| -    }
 | 
| -  }
 | 
| -  m_Pos--;
 | 
| -}
 | 
| -
 | 
| -CFX_ByteString CPDF_SyntaxParser::GetNextWord(bool* bIsNumber) {
 | 
| -  GetNextWordInternal(bIsNumber);
 | 
| -  return CFX_ByteString((const FX_CHAR*)m_WordBuffer, m_WordSize);
 | 
| -}
 | 
| -
 | 
| -CFX_ByteString CPDF_SyntaxParser::GetKeyword() {
 | 
| -  return GetNextWord(nullptr);
 | 
| -}
 | 
| -
 | 
| -CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjectHolder* pObjList,
 | 
| -                                          uint32_t objnum,
 | 
| -                                          uint32_t gennum,
 | 
| -                                          FX_BOOL bDecrypt) {
 | 
| -  CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
 | 
| -  if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth)
 | 
| -    return nullptr;
 | 
| -
 | 
| -  FX_FILESIZE SavedObjPos = m_Pos;
 | 
| -  bool bIsNumber;
 | 
| -  CFX_ByteString word = GetNextWord(&bIsNumber);
 | 
| -  if (word.GetLength() == 0)
 | 
| -    return nullptr;
 | 
| -
 | 
| -  if (bIsNumber) {
 | 
| -    FX_FILESIZE SavedPos = m_Pos;
 | 
| -    CFX_ByteString nextword = GetNextWord(&bIsNumber);
 | 
| -    if (bIsNumber) {
 | 
| -      CFX_ByteString nextword2 = GetNextWord(nullptr);
 | 
| -      if (nextword2 == "R")
 | 
| -        return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str()));
 | 
| -    }
 | 
| -    m_Pos = SavedPos;
 | 
| -    return new CPDF_Number(word.AsStringC());
 | 
| -  }
 | 
| -
 | 
| -  if (word == "true" || word == "false")
 | 
| -    return new CPDF_Boolean(word == "true");
 | 
| -
 | 
| -  if (word == "null")
 | 
| -    return new CPDF_Null;
 | 
| -
 | 
| -  if (word == "(") {
 | 
| -    CFX_ByteString str = ReadString();
 | 
| -    if (m_pCryptoHandler && bDecrypt)
 | 
| -      m_pCryptoHandler->Decrypt(objnum, gennum, str);
 | 
| -    return new CPDF_String(MaybeIntern(str), FALSE);
 | 
| -  }
 | 
| -
 | 
| -  if (word == "<") {
 | 
| -    CFX_ByteString str = ReadHexString();
 | 
| -    if (m_pCryptoHandler && bDecrypt)
 | 
| -      m_pCryptoHandler->Decrypt(objnum, gennum, str);
 | 
| -    return new CPDF_String(MaybeIntern(str), TRUE);
 | 
| -  }
 | 
| -
 | 
| -  if (word == "[") {
 | 
| -    CPDF_Array* pArray = new CPDF_Array;
 | 
| -    while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true))
 | 
| -      pArray->Add(pObj);
 | 
| -
 | 
| -    return pArray;
 | 
| -  }
 | 
| -
 | 
| -  if (word[0] == '/') {
 | 
| -    return new CPDF_Name(MaybeIntern(
 | 
| -        PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))));
 | 
| -  }
 | 
| -
 | 
| -  if (word == "<<") {
 | 
| -    int32_t nKeys = 0;
 | 
| -    FX_FILESIZE dwSignValuePos = 0;
 | 
| -
 | 
| -    std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
 | 
| -        new CPDF_Dictionary(m_pPool));
 | 
| -    while (1) {
 | 
| -      CFX_ByteString key = GetNextWord(nullptr);
 | 
| -      if (key.IsEmpty())
 | 
| -        return nullptr;
 | 
| -
 | 
| -      FX_FILESIZE SavedPos = m_Pos - key.GetLength();
 | 
| -      if (key == ">>")
 | 
| -        break;
 | 
| -
 | 
| -      if (key == "endobj") {
 | 
| -        m_Pos = SavedPos;
 | 
| -        break;
 | 
| -      }
 | 
| -
 | 
| -      if (key[0] != '/')
 | 
| -        continue;
 | 
| -
 | 
| -      ++nKeys;
 | 
| -      key = PDF_NameDecode(key);
 | 
| -      if (key.IsEmpty())
 | 
| -        continue;
 | 
| -
 | 
| -      if (key == "/Contents")
 | 
| -        dwSignValuePos = m_Pos;
 | 
| -
 | 
| -      CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true);
 | 
| -      if (!pObj)
 | 
| -        continue;
 | 
| -
 | 
| -      CFX_ByteString keyNoSlash(key.raw_str() + 1, key.GetLength() - 1);
 | 
| -      pDict->SetFor(keyNoSlash, pObj);
 | 
| -    }
 | 
| -
 | 
| -    // Only when this is a signature dictionary and has contents, we reset the
 | 
| -    // contents to the un-decrypted form.
 | 
| -    if (pDict->IsSignatureDict() && dwSignValuePos) {
 | 
| -      CFX_AutoRestorer<FX_FILESIZE> save_pos(&m_Pos);
 | 
| -      m_Pos = dwSignValuePos;
 | 
| -      pDict->SetFor("Contents", GetObject(pObjList, objnum, gennum, false));
 | 
| -    }
 | 
| -
 | 
| -    FX_FILESIZE SavedPos = m_Pos;
 | 
| -    CFX_ByteString nextword = GetNextWord(nullptr);
 | 
| -    if (nextword != "stream") {
 | 
| -      m_Pos = SavedPos;
 | 
| -      return pDict.release();
 | 
| -    }
 | 
| -    return ReadStream(pDict.release(), objnum, gennum);
 | 
| -  }
 | 
| -
 | 
| -  if (word == ">>")
 | 
| -    m_Pos = SavedObjPos;
 | 
| -
 | 
| -  return nullptr;
 | 
| -}
 | 
| -
 | 
| -CPDF_Object* CPDF_SyntaxParser::GetObjectForStrict(
 | 
| -    CPDF_IndirectObjectHolder* pObjList,
 | 
| -    uint32_t objnum,
 | 
| -    uint32_t gennum) {
 | 
| -  CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
 | 
| -  if (++s_CurrentRecursionDepth > kParserMaxRecursionDepth)
 | 
| -    return nullptr;
 | 
| -
 | 
| -  FX_FILESIZE SavedObjPos = m_Pos;
 | 
| -  bool bIsNumber;
 | 
| -  CFX_ByteString word = GetNextWord(&bIsNumber);
 | 
| -  if (word.GetLength() == 0)
 | 
| -    return nullptr;
 | 
| -
 | 
| -  if (bIsNumber) {
 | 
| -    FX_FILESIZE SavedPos = m_Pos;
 | 
| -    CFX_ByteString nextword = GetNextWord(&bIsNumber);
 | 
| -    if (bIsNumber) {
 | 
| -      CFX_ByteString nextword2 = GetNextWord(nullptr);
 | 
| -      if (nextword2 == "R")
 | 
| -        return new CPDF_Reference(pObjList, FXSYS_atoui(word.c_str()));
 | 
| -    }
 | 
| -    m_Pos = SavedPos;
 | 
| -    return new CPDF_Number(word.AsStringC());
 | 
| -  }
 | 
| -
 | 
| -  if (word == "true" || word == "false")
 | 
| -    return new CPDF_Boolean(word == "true");
 | 
| -
 | 
| -  if (word == "null")
 | 
| -    return new CPDF_Null;
 | 
| -
 | 
| -  if (word == "(") {
 | 
| -    CFX_ByteString str = ReadString();
 | 
| -    if (m_pCryptoHandler)
 | 
| -      m_pCryptoHandler->Decrypt(objnum, gennum, str);
 | 
| -    return new CPDF_String(MaybeIntern(str), FALSE);
 | 
| -  }
 | 
| -
 | 
| -  if (word == "<") {
 | 
| -    CFX_ByteString str = ReadHexString();
 | 
| -    if (m_pCryptoHandler)
 | 
| -      m_pCryptoHandler->Decrypt(objnum, gennum, str);
 | 
| -    return new CPDF_String(MaybeIntern(str), TRUE);
 | 
| -  }
 | 
| -
 | 
| -  if (word == "[") {
 | 
| -    std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>> pArray(
 | 
| -        new CPDF_Array);
 | 
| -    while (CPDF_Object* pObj = GetObject(pObjList, objnum, gennum, true))
 | 
| -      pArray->Add(pObj);
 | 
| -
 | 
| -    return m_WordBuffer[0] == ']' ? pArray.release() : nullptr;
 | 
| -  }
 | 
| -
 | 
| -  if (word[0] == '/') {
 | 
| -    return new CPDF_Name(MaybeIntern(
 | 
| -        PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))));
 | 
| -  }
 | 
| -
 | 
| -  if (word == "<<") {
 | 
| -    std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> pDict(
 | 
| -        new CPDF_Dictionary(m_pPool));
 | 
| -    while (1) {
 | 
| -      FX_FILESIZE SavedPos = m_Pos;
 | 
| -      CFX_ByteString key = GetNextWord(nullptr);
 | 
| -      if (key.IsEmpty())
 | 
| -        return nullptr;
 | 
| -
 | 
| -      if (key == ">>")
 | 
| -        break;
 | 
| -
 | 
| -      if (key == "endobj") {
 | 
| -        m_Pos = SavedPos;
 | 
| -        break;
 | 
| -      }
 | 
| -
 | 
| -      if (key[0] != '/')
 | 
| -        continue;
 | 
| -
 | 
| -      key = PDF_NameDecode(key);
 | 
| -      std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
 | 
| -          GetObject(pObjList, objnum, gennum, true));
 | 
| -      if (!obj) {
 | 
| -        uint8_t ch;
 | 
| -        while (GetNextChar(ch) && ch != 0x0A && ch != 0x0D) {
 | 
| -          continue;
 | 
| -        }
 | 
| -        return nullptr;
 | 
| -      }
 | 
| -
 | 
| -      if (key.GetLength() > 1) {
 | 
| -        pDict->SetFor(CFX_ByteString(key.c_str() + 1, key.GetLength() - 1),
 | 
| -                      obj.release());
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    FX_FILESIZE SavedPos = m_Pos;
 | 
| -    CFX_ByteString nextword = GetNextWord(nullptr);
 | 
| -    if (nextword != "stream") {
 | 
| -      m_Pos = SavedPos;
 | 
| -      return pDict.release();
 | 
| -    }
 | 
| -
 | 
| -    return ReadStream(pDict.release(), objnum, gennum);
 | 
| -  }
 | 
| -
 | 
| -  if (word == ">>")
 | 
| -    m_Pos = SavedObjPos;
 | 
| -
 | 
| -  return nullptr;
 | 
| -}
 | 
| -
 | 
| -unsigned int CPDF_SyntaxParser::ReadEOLMarkers(FX_FILESIZE pos) {
 | 
| -  unsigned char byte1 = 0;
 | 
| -  unsigned char byte2 = 0;
 | 
| -
 | 
| -  GetCharAt(pos, byte1);
 | 
| -  GetCharAt(pos + 1, byte2);
 | 
| -
 | 
| -  if (byte1 == '\r' && byte2 == '\n')
 | 
| -    return 2;
 | 
| -
 | 
| -  if (byte1 == '\r' || byte1 == '\n')
 | 
| -    return 1;
 | 
| -
 | 
| -  return 0;
 | 
| -}
 | 
| -
 | 
| -CPDF_Stream* CPDF_SyntaxParser::ReadStream(CPDF_Dictionary* pDict,
 | 
| -                                           uint32_t objnum,
 | 
| -                                           uint32_t gennum) {
 | 
| -  CPDF_Object* pLenObj = pDict->GetObjectFor("Length");
 | 
| -  FX_FILESIZE len = -1;
 | 
| -  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;
 | 
| -
 | 
| -  const CFX_ByteStringC kEndStreamStr("endstream");
 | 
| -  const CFX_ByteStringC kEndObjStr("endobj");
 | 
| -
 | 
| -  CPDF_CryptoHandler* pCryptoHandler =
 | 
| -      objnum == (uint32_t)m_MetadataObjnum ? nullptr : m_pCryptoHandler.get();
 | 
| -  if (!pCryptoHandler) {
 | 
| -    FX_BOOL bSearchForKeyword = TRUE;
 | 
| -    if (len >= 0) {
 | 
| -      pdfium::base::CheckedNumeric<FX_FILESIZE> pos = m_Pos;
 | 
| -      pos += len;
 | 
| -      if (pos.IsValid() && pos.ValueOrDie() < m_FileLen)
 | 
| -        m_Pos = pos.ValueOrDie();
 | 
| -
 | 
| -      m_Pos += ReadEOLMarkers(m_Pos);
 | 
| -      FXSYS_memset(m_WordBuffer, 0, kEndStreamStr.GetLength() + 1);
 | 
| -      GetNextWordInternal(nullptr);
 | 
| -      // Earlier version of PDF specification doesn't require EOL marker before
 | 
| -      // 'endstream' keyword. If keyword 'endstream' follows the bytes in
 | 
| -      // specified length, it signals the end of stream.
 | 
| -      if (FXSYS_memcmp(m_WordBuffer, kEndStreamStr.raw_str(),
 | 
| -                       kEndStreamStr.GetLength()) == 0) {
 | 
| -        bSearchForKeyword = FALSE;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    if (bSearchForKeyword) {
 | 
| -      // If len is not available, len needs to be calculated
 | 
| -      // by searching the keywords "endstream" or "endobj".
 | 
| -      m_Pos = streamStartPos;
 | 
| -      FX_FILESIZE endStreamOffset = 0;
 | 
| -      while (endStreamOffset >= 0) {
 | 
| -        endStreamOffset = FindTag(kEndStreamStr, 0);
 | 
| -
 | 
| -        // Can't find "endstream".
 | 
| -        if (endStreamOffset < 0)
 | 
| -          break;
 | 
| -
 | 
| -        // Stop searching when "endstream" is found.
 | 
| -        if (IsWholeWord(m_Pos - kEndStreamStr.GetLength(), m_FileLen,
 | 
| -                        kEndStreamStr, TRUE)) {
 | 
| -          endStreamOffset = m_Pos - streamStartPos - kEndStreamStr.GetLength();
 | 
| -          break;
 | 
| -        }
 | 
| -      }
 | 
| -
 | 
| -      m_Pos = streamStartPos;
 | 
| -      FX_FILESIZE endObjOffset = 0;
 | 
| -      while (endObjOffset >= 0) {
 | 
| -        endObjOffset = FindTag(kEndObjStr, 0);
 | 
| -
 | 
| -        // Can't find "endobj".
 | 
| -        if (endObjOffset < 0)
 | 
| -          break;
 | 
| -
 | 
| -        // Stop searching when "endobj" is found.
 | 
| -        if (IsWholeWord(m_Pos - kEndObjStr.GetLength(), m_FileLen, kEndObjStr,
 | 
| -                        TRUE)) {
 | 
| -          endObjOffset = m_Pos - streamStartPos - kEndObjStr.GetLength();
 | 
| -          break;
 | 
| -        }
 | 
| -      }
 | 
| -
 | 
| -      // Can't find "endstream" or "endobj".
 | 
| -      if (endStreamOffset < 0 && endObjOffset < 0) {
 | 
| -        pDict->Release();
 | 
| -        return nullptr;
 | 
| -      }
 | 
| -
 | 
| -      if (endStreamOffset < 0 && endObjOffset >= 0) {
 | 
| -        // Correct the position of end stream.
 | 
| -        endStreamOffset = endObjOffset;
 | 
| -      } else if (endStreamOffset >= 0 && endObjOffset < 0) {
 | 
| -        // Correct the position of end obj.
 | 
| -        endObjOffset = endStreamOffset;
 | 
| -      } else if (endStreamOffset > endObjOffset) {
 | 
| -        endStreamOffset = endObjOffset;
 | 
| -      }
 | 
| -
 | 
| -      len = endStreamOffset;
 | 
| -      int numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 2);
 | 
| -      if (numMarkers == 2) {
 | 
| -        len -= 2;
 | 
| -      } else {
 | 
| -        numMarkers = ReadEOLMarkers(streamStartPos + endStreamOffset - 1);
 | 
| -        if (numMarkers == 1) {
 | 
| -          len -= 1;
 | 
| -        }
 | 
| -      }
 | 
| -
 | 
| -      if (len < 0) {
 | 
| -        pDict->Release();
 | 
| -        return nullptr;
 | 
| -      }
 | 
| -      pDict->SetIntegerFor("Length", len);
 | 
| -    }
 | 
| -    m_Pos = streamStartPos;
 | 
| -  }
 | 
| -
 | 
| -  if (len < 0) {
 | 
| -    pDict->Release();
 | 
| -    return nullptr;
 | 
| -  }
 | 
| -
 | 
| -  uint8_t* pData = nullptr;
 | 
| -  if (len > 0) {
 | 
| -    pData = FX_Alloc(uint8_t, len);
 | 
| -    ReadBlock(pData, len);
 | 
| -    if (pCryptoHandler) {
 | 
| -      CFX_BinaryBuf dest_buf;
 | 
| -      dest_buf.EstimateSize(pCryptoHandler->DecryptGetSize(len));
 | 
| -
 | 
| -      void* context = pCryptoHandler->DecryptStart(objnum, gennum);
 | 
| -      pCryptoHandler->DecryptStream(context, pData, len, dest_buf);
 | 
| -      pCryptoHandler->DecryptFinish(context, dest_buf);
 | 
| -
 | 
| -      FX_Free(pData);
 | 
| -      pData = dest_buf.GetBuffer();
 | 
| -      len = dest_buf.GetSize();
 | 
| -      dest_buf.DetachBuffer();
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  CPDF_Stream* pStream = new CPDF_Stream(pData, len, pDict);
 | 
| -  streamStartPos = m_Pos;
 | 
| -  FXSYS_memset(m_WordBuffer, 0, kEndObjStr.GetLength() + 1);
 | 
| -
 | 
| -  GetNextWordInternal(nullptr);
 | 
| -
 | 
| -  int numMarkers = ReadEOLMarkers(m_Pos);
 | 
| -  if (m_WordSize == static_cast<unsigned int>(kEndObjStr.GetLength()) &&
 | 
| -      numMarkers != 0 &&
 | 
| -      FXSYS_memcmp(m_WordBuffer, kEndObjStr.raw_str(),
 | 
| -                   kEndObjStr.GetLength()) == 0) {
 | 
| -    m_Pos = streamStartPos;
 | 
| -  }
 | 
| -  return pStream;
 | 
| -}
 | 
| -
 | 
| -void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess,
 | 
| -                                   uint32_t HeaderOffset) {
 | 
| -  FX_Free(m_pFileBuf);
 | 
| -
 | 
| -  m_pFileBuf = FX_Alloc(uint8_t, m_BufSize);
 | 
| -  m_HeaderOffset = HeaderOffset;
 | 
| -  m_FileLen = pFileAccess->GetSize();
 | 
| -  m_Pos = 0;
 | 
| -  m_pFileAccess = pFileAccess;
 | 
| -  m_BufOffset = 0;
 | 
| -  pFileAccess->ReadBlock(
 | 
| -      m_pFileBuf, 0,
 | 
| -      (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize));
 | 
| -}
 | 
| -
 | 
| -uint32_t CPDF_SyntaxParser::GetDirectNum() {
 | 
| -  bool bIsNumber;
 | 
| -  GetNextWordInternal(&bIsNumber);
 | 
| -  if (!bIsNumber)
 | 
| -    return 0;
 | 
| -
 | 
| -  m_WordBuffer[m_WordSize] = 0;
 | 
| -  return FXSYS_atoui(reinterpret_cast<const FX_CHAR*>(m_WordBuffer));
 | 
| -}
 | 
| -
 | 
| -bool CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos,
 | 
| -                                    FX_FILESIZE limit,
 | 
| -                                    const CFX_ByteStringC& tag,
 | 
| -                                    FX_BOOL checkKeyword) {
 | 
| -  const uint32_t taglen = tag.GetLength();
 | 
| -
 | 
| -  bool bCheckLeft = !PDFCharIsDelimiter(tag[0]) && !PDFCharIsWhitespace(tag[0]);
 | 
| -  bool bCheckRight = !PDFCharIsDelimiter(tag[taglen - 1]) &&
 | 
| -                     !PDFCharIsWhitespace(tag[taglen - 1]);
 | 
| -
 | 
| -  uint8_t ch;
 | 
| -  if (bCheckRight && startpos + (int32_t)taglen <= limit &&
 | 
| -      GetCharAt(startpos + (int32_t)taglen, ch)) {
 | 
| -    if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) ||
 | 
| -        (checkKeyword && PDFCharIsDelimiter(ch))) {
 | 
| -      return false;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (bCheckLeft && startpos > 0 && GetCharAt(startpos - 1, ch)) {
 | 
| -    if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) ||
 | 
| -        (checkKeyword && PDFCharIsDelimiter(ch))) {
 | 
| -      return false;
 | 
| -    }
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -// TODO(dsinclair): Split into a SearchWordForward and SearchWordBackwards
 | 
| -// and drop the bool.
 | 
| -FX_BOOL CPDF_SyntaxParser::SearchWord(const CFX_ByteStringC& tag,
 | 
| -                                      FX_BOOL bWholeWord,
 | 
| -                                      FX_BOOL bForward,
 | 
| -                                      FX_FILESIZE limit) {
 | 
| -  int32_t taglen = tag.GetLength();
 | 
| -  if (taglen == 0)
 | 
| -    return FALSE;
 | 
| -
 | 
| -  FX_FILESIZE pos = m_Pos;
 | 
| -  int32_t offset = 0;
 | 
| -  if (!bForward)
 | 
| -    offset = taglen - 1;
 | 
| -
 | 
| -  const uint8_t* tag_data = tag.raw_str();
 | 
| -  uint8_t byte;
 | 
| -  while (1) {
 | 
| -    if (bForward) {
 | 
| -      if (limit && pos >= m_Pos + limit)
 | 
| -        return FALSE;
 | 
| -
 | 
| -      if (!GetCharAt(pos, byte))
 | 
| -        return FALSE;
 | 
| -
 | 
| -    } else {
 | 
| -      if (limit && pos <= m_Pos - limit)
 | 
| -        return FALSE;
 | 
| -
 | 
| -      if (!GetCharAtBackward(pos, byte))
 | 
| -        return FALSE;
 | 
| -    }
 | 
| -
 | 
| -    if (byte == tag_data[offset]) {
 | 
| -      if (bForward) {
 | 
| -        offset++;
 | 
| -        if (offset < taglen) {
 | 
| -          pos++;
 | 
| -          continue;
 | 
| -        }
 | 
| -      } else {
 | 
| -        offset--;
 | 
| -        if (offset >= 0) {
 | 
| -          pos--;
 | 
| -          continue;
 | 
| -        }
 | 
| -      }
 | 
| -
 | 
| -      FX_FILESIZE startpos = bForward ? pos - taglen + 1 : pos;
 | 
| -      if (!bWholeWord || IsWholeWord(startpos, limit, tag, FALSE)) {
 | 
| -        m_Pos = startpos;
 | 
| -        return TRUE;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    if (bForward) {
 | 
| -      offset = byte == tag_data[0] ? 1 : 0;
 | 
| -      pos++;
 | 
| -    } else {
 | 
| -      offset = byte == tag_data[taglen - 1] ? taglen - 2 : taglen - 1;
 | 
| -      pos--;
 | 
| -    }
 | 
| -
 | 
| -    if (pos < 0)
 | 
| -      return FALSE;
 | 
| -  }
 | 
| -
 | 
| -  return FALSE;
 | 
| -}
 | 
| -
 | 
| -int32_t CPDF_SyntaxParser::SearchMultiWord(const CFX_ByteStringC& tags,
 | 
| -                                           FX_BOOL bWholeWord,
 | 
| -                                           FX_FILESIZE limit) {
 | 
| -  int32_t ntags = 1;
 | 
| -  for (int i = 0; i < tags.GetLength(); ++i) {
 | 
| -    if (tags[i] == 0)
 | 
| -      ++ntags;
 | 
| -  }
 | 
| -
 | 
| -  // Ensure that the input byte string happens to be nul-terminated. This
 | 
| -  // need not be the case, but the loop below uses this guarantee to put
 | 
| -  // the last pattern into the vector.
 | 
| -  ASSERT(tags[tags.GetLength()] == 0);
 | 
| -  std::vector<SearchTagRecord> patterns(ntags);
 | 
| -  uint32_t start = 0;
 | 
| -  uint32_t itag = 0;
 | 
| -  uint32_t max_len = 0;
 | 
| -  for (int i = 0; i <= tags.GetLength(); ++i) {
 | 
| -    if (tags[i] == 0) {
 | 
| -      uint32_t len = i - start;
 | 
| -      max_len = std::max(len, max_len);
 | 
| -      patterns[itag].m_bsTag = tags.Mid(start, len);
 | 
| -      patterns[itag].m_Offset = 0;
 | 
| -      start = i + 1;
 | 
| -      ++itag;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  const FX_FILESIZE pos_limit = m_Pos + limit;
 | 
| -  for (FX_FILESIZE pos = m_Pos; !limit || pos < pos_limit; ++pos) {
 | 
| -    uint8_t byte;
 | 
| -    if (!GetCharAt(pos, byte))
 | 
| -      break;
 | 
| -
 | 
| -    for (int i = 0; i < ntags; ++i) {
 | 
| -      SearchTagRecord& pat = patterns[i];
 | 
| -      if (pat.m_bsTag[pat.m_Offset] != byte) {
 | 
| -        pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0;
 | 
| -        continue;
 | 
| -      }
 | 
| -
 | 
| -      ++pat.m_Offset;
 | 
| -      if (pat.m_Offset != pat.m_bsTag.GetLength())
 | 
| -        continue;
 | 
| -
 | 
| -      if (!bWholeWord || IsWholeWord(pos - pat.m_bsTag.GetLength(), limit,
 | 
| -                                     pat.m_bsTag, FALSE)) {
 | 
| -        return i;
 | 
| -      }
 | 
| -
 | 
| -      pat.m_Offset = (pat.m_bsTag[0] == byte) ? 1 : 0;
 | 
| -    }
 | 
| -  }
 | 
| -  return -1;
 | 
| -}
 | 
| -
 | 
| -FX_FILESIZE CPDF_SyntaxParser::FindTag(const CFX_ByteStringC& tag,
 | 
| -                                       FX_FILESIZE limit) {
 | 
| -  int32_t taglen = tag.GetLength();
 | 
| -  int32_t match = 0;
 | 
| -  limit += m_Pos;
 | 
| -  FX_FILESIZE startpos = m_Pos;
 | 
| -
 | 
| -  while (1) {
 | 
| -    uint8_t ch;
 | 
| -    if (!GetNextChar(ch))
 | 
| -      return -1;
 | 
| -
 | 
| -    if (ch == tag[match]) {
 | 
| -      match++;
 | 
| -      if (match == taglen)
 | 
| -        return m_Pos - startpos - taglen;
 | 
| -    } else {
 | 
| -      match = ch == tag[0] ? 1 : 0;
 | 
| -    }
 | 
| -
 | 
| -    if (limit && m_Pos == limit)
 | 
| -      return -1;
 | 
| -  }
 | 
| -  return -1;
 | 
| -}
 | 
| -
 | 
| -void CPDF_SyntaxParser::SetEncrypt(
 | 
| -    std::unique_ptr<CPDF_CryptoHandler> pCryptoHandler) {
 | 
| -  m_pCryptoHandler = std::move(pCryptoHandler);
 | 
| -}
 | 
| -
 | 
| -CFX_ByteString CPDF_SyntaxParser::MaybeIntern(const CFX_ByteString& str) {
 | 
| -  return m_pPool ? m_pPool->Intern(str) : str;
 | 
| -}
 | 
| 
 |