// Copyright 2017 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.

#include "core/fpdfapi/parser/cpdf_cross_ref_avail.h"

#include <algorithm>
#include <vector>

#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fpdfapi/parser/cpdf_read_validator.h"
#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_syntax_parser.h"
#include "core/fpdfapi/parser/fpdf_parser_utility.h"

namespace {

constexpr char kCrossRefKeyword[] = "xref";
constexpr char kTrailerKeyword[] = "trailer";
constexpr char kPrevCrossRefFieldKey[] = "Prev";
constexpr char kTypeFieldKey[] = "Type";
constexpr char kPrevCrossRefStreamOffsetFieldKey[] = "XRefStm";
constexpr char kXRefKeyword[] = "XRef";
constexpr char kEncryptKey[] = "Encrypt";

}  // namespace

CPDF_CrossRefAvail::CPDF_CrossRefAvail(CPDF_SyntaxParser* parser,
                                       FX_FILESIZE last_crossref_offset)
    : parser_(parser), last_crossref_offset_(last_crossref_offset) {
  ASSERT(parser_);
  AddCrossRefForCheck(last_crossref_offset);
}

CPDF_CrossRefAvail::~CPDF_CrossRefAvail() {}

CPDF_DataAvail::DocAvailStatus CPDF_CrossRefAvail::CheckAvail() {
  if (current_status_ == CPDF_DataAvail::DataAvailable)
    return CPDF_DataAvail::DataAvailable;

  const CPDF_ReadValidator::Session read_session(GetValidator().Get());
  while (true) {
    bool check_result = false;
    switch (current_state_) {
      case State::kCrossRefCheck:
        check_result = CheckCrossRef();
        break;
      case State::kCrossRefV4ItemCheck:
        check_result = CheckCrossRefV4Item();
        break;
      case State::kCrossRefV4TrailerCheck:
        check_result = CheckCrossRefV4Trailer();
        break;
      case State::kDone:
        break;
      default: {
        current_status_ = CPDF_DataAvail::DataError;
        NOTREACHED();
        break;
      }
    }
    if (!check_result)
      break;

    ASSERT(!GetValidator()->has_read_problems());
  }
  return current_status_;
}

bool CPDF_CrossRefAvail::CheckReadProblems() {
  if (GetValidator()->read_error()) {
    current_status_ = CPDF_DataAvail::DataError;
    return true;
  }
  return GetValidator()->has_unavailable_data();
}

bool CPDF_CrossRefAvail::CheckCrossRef() {
  if (cross_refs_for_check_.empty()) {
    // All cross refs were checked.
    current_state_ = State::kDone;
    current_status_ = CPDF_DataAvail::DataAvailable;
    return true;
  }
  parser_->SetPos(cross_refs_for_check_.front());

  const ByteString first_word = parser_->PeekNextWord(nullptr);
  if (CheckReadProblems())
    return false;

  const bool result = (first_word == kCrossRefKeyword) ? CheckCrossRefV4()
                                                       : CheckCrossRefStream();

  if (result)
    cross_refs_for_check_.pop();

  return result;
}

bool CPDF_CrossRefAvail::CheckCrossRefV4() {
  const ByteString keyword = parser_->GetKeyword();
  if (CheckReadProblems())
    return false;

  if (keyword != kCrossRefKeyword) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  current_state_ = State::kCrossRefV4ItemCheck;
  current_offset_ = parser_->GetPos();
  return true;
}

bool CPDF_CrossRefAvail::CheckCrossRefV4Item() {
  parser_->SetPos(current_offset_);
  const ByteString keyword = parser_->GetKeyword();
  if (CheckReadProblems())
    return false;

  if (keyword.IsEmpty()) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  if (keyword == kTrailerKeyword)
    current_state_ = State::kCrossRefV4TrailerCheck;

  // Go to next item.
  current_offset_ = parser_->GetPos();
  return true;
}

bool CPDF_CrossRefAvail::CheckCrossRefV4Trailer() {
  parser_->SetPos(current_offset_);

  std::unique_ptr<CPDF_Dictionary> trailer =
      ToDictionary(parser_->GetObjectBody(nullptr));
  if (CheckReadProblems())
    return false;

  if (!trailer) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  if (ToReference(trailer->GetObjectFor(kEncryptKey))) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  const int32_t xrefpos =
      GetDirectInteger(trailer.get(), kPrevCrossRefFieldKey);
  if (xrefpos &&
      pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos))
    AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos));

  const int32_t stream_xref_offset =
      GetDirectInteger(trailer.get(), kPrevCrossRefStreamOffsetFieldKey);
  if (stream_xref_offset &&
      pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(
          stream_xref_offset))
    AddCrossRefForCheck(static_cast<FX_FILESIZE>(stream_xref_offset));

  // Goto check next crossref
  current_state_ = State::kCrossRefCheck;
  return true;
}

bool CPDF_CrossRefAvail::CheckCrossRefStream() {
  auto cross_ref =
      parser_->GetIndirectObject(nullptr, CPDF_SyntaxParser::ParseType::kLoose);
  if (CheckReadProblems())
    return false;

  const CPDF_Dictionary* trailer =
      cross_ref && cross_ref->IsStream() ? cross_ref->GetDict() : nullptr;
  if (!trailer) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  if (ToReference(trailer->GetObjectFor(kEncryptKey))) {
    current_status_ = CPDF_DataAvail::DataError;
    return false;
  }

  CPDF_Name* type_name = ToName(trailer->GetObjectFor(kTypeFieldKey));
  if (type_name && type_name->GetString() == kXRefKeyword) {
    const int32_t xrefpos = trailer->GetIntegerFor(kPrevCrossRefFieldKey);
    if (xrefpos &&
        pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos))
      AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos));
  }
  // Goto check next crossref
  current_state_ = State::kCrossRefCheck;
  return true;
}

void CPDF_CrossRefAvail::AddCrossRefForCheck(FX_FILESIZE crossref_offset) {
  if (registered_crossrefs_.count(crossref_offset))
    return;

  cross_refs_for_check_.push(crossref_offset);
  registered_crossrefs_.insert(crossref_offset);
}

fxcrt::RetainPtr<CPDF_ReadValidator> CPDF_CrossRefAvail::GetValidator() {
  return parser_->GetValidator();
}
