// 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/parser/cpdf_stream.h"

#include <utility>
#include <vector>

#include "constants/stream_dict_common.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_encryptor.h"
#include "core/fpdfapi/parser/cpdf_flateencoder.h"
#include "core/fpdfapi/parser/cpdf_number.h"
#include "core/fpdfapi/parser/cpdf_stream_acc.h"
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
#include "core/fxcrt/fx_stream.h"
#include "third_party/base/numerics/safe_conversions.h"
#include "third_party/base/stl_util.h"

namespace {

bool IsMetaDataStreamDictionary(const CPDF_Dictionary* dict) {
  return dict && dict->GetNameFor("Type") == "Metadata" &&
         dict->GetNameFor("Subtype") == "XML";
}

}  // namespace

CPDF_Stream::CPDF_Stream() = default;

CPDF_Stream::CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
                         uint32_t size,
                         RetainPtr<CPDF_Dictionary> pDict)
    : m_pDict(std::move(pDict)) {
  TakeData(std::move(pData), size);
}

CPDF_Stream::~CPDF_Stream() {
  m_ObjNum = kInvalidObjNum;
  if (m_pDict && m_pDict->GetObjNum() == kInvalidObjNum)
    m_pDict.Leak();  // lowercase release, release ownership.
}

CPDF_Object::Type CPDF_Stream::GetType() const {
  return kStream;
}

CPDF_Dictionary* CPDF_Stream::GetDict() {
  return m_pDict.Get();
}

const CPDF_Dictionary* CPDF_Stream::GetDict() const {
  return m_pDict.Get();
}

bool CPDF_Stream::IsStream() const {
  return true;
}

CPDF_Stream* CPDF_Stream::AsStream() {
  return this;
}

const CPDF_Stream* CPDF_Stream::AsStream() const {
  return this;
}

void CPDF_Stream::InitStream(pdfium::span<const uint8_t> pData,
                             RetainPtr<CPDF_Dictionary> pDict) {
  m_pDict = std::move(pDict);
  SetData(pData);
}

void CPDF_Stream::InitStreamFromFile(
    const RetainPtr<IFX_SeekableReadStream>& pFile,
    RetainPtr<CPDF_Dictionary> pDict) {
  m_bMemoryBased = false;
  m_pDataBuf.reset();
  m_pFile = pFile;
  m_dwSize = pdfium::base::checked_cast<uint32_t>(pFile->GetSize());
  m_pDict = std::move(pDict);
  m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize));
}

RetainPtr<CPDF_Object> CPDF_Stream::Clone() const {
  return CloneObjectNonCyclic(false);
}

RetainPtr<CPDF_Object> CPDF_Stream::CloneNonCyclic(
    bool bDirect,
    std::set<const CPDF_Object*>* pVisited) const {
  pVisited->insert(this);
  auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this);
  pAcc->LoadAllDataRaw();

  uint32_t streamSize = pAcc->GetSize();
  const CPDF_Dictionary* pDict = GetDict();
  RetainPtr<CPDF_Dictionary> pNewDict;
  if (pDict && !pdfium::Contains(*pVisited, pDict)) {
    pNewDict =
        ToDictionary(static_cast<const CPDF_Object*>(pDict)->CloneNonCyclic(
            bDirect, pVisited));
  }
  return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(), streamSize,
                                         std::move(pNewDict));
}

void CPDF_Stream::SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData) {
  SetData(pData);
  m_pDict->RemoveFor("Filter");
  m_pDict->RemoveFor(pdfium::stream::kDecodeParms);
}

void CPDF_Stream::SetDataFromStringstreamAndRemoveFilter(
    std::ostringstream* stream) {
  if (stream->tellp() <= 0) {
    SetDataAndRemoveFilter({});
    return;
  }

  SetDataAndRemoveFilter(
      {reinterpret_cast<const uint8_t*>(stream->str().c_str()),
       static_cast<size_t>(stream->tellp())});
}

void CPDF_Stream::SetData(pdfium::span<const uint8_t> pData) {
  std::unique_ptr<uint8_t, FxFreeDeleter> data_copy;
  if (!pData.empty()) {
    data_copy.reset(FX_AllocUninit(uint8_t, pData.size()));
    memcpy(data_copy.get(), pData.data(), pData.size());
  }
  TakeData(std::move(data_copy), pData.size());
}

void CPDF_Stream::TakeData(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
                           uint32_t size) {
  m_bMemoryBased = true;
  m_pFile = nullptr;
  m_pDataBuf = std::move(pData);
  m_dwSize = size;
  if (!m_pDict)
    m_pDict = pdfium::MakeRetain<CPDF_Dictionary>();
  m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(size));
}

void CPDF_Stream::SetDataFromStringstream(std::ostringstream* stream) {
  if (stream->tellp() <= 0) {
    SetData({});
    return;
  }
  SetData({reinterpret_cast<const uint8_t*>(stream->str().c_str()),
           static_cast<size_t>(stream->tellp())});
}

bool CPDF_Stream::ReadRawData(FX_FILESIZE offset,
                              uint8_t* buf,
                              uint32_t size) const {
  if (!m_bMemoryBased && m_pFile)
    return m_pFile->ReadBlockAtOffset(buf, offset, size);

  if (m_pDataBuf)
    memcpy(buf, m_pDataBuf.get() + offset, size);

  return true;
}

bool CPDF_Stream::HasFilter() const {
  return m_pDict && m_pDict->KeyExist("Filter");
}

WideString CPDF_Stream::GetUnicodeText() const {
  auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this);
  pAcc->LoadAllDataFiltered();
  return PDF_DecodeText(pAcc->GetSpan());
}

bool CPDF_Stream::WriteTo(IFX_ArchiveStream* archive,
                          const CPDF_Encryptor* encryptor) const {
  const bool is_metadata = IsMetaDataStreamDictionary(GetDict());
  CPDF_FlateEncoder encoder(this, !is_metadata);

  std::vector<uint8_t, FxAllocAllocator<uint8_t>> encrypted_data;
  pdfium::span<const uint8_t> data = encoder.GetSpan();

  if (encryptor && !is_metadata) {
    encrypted_data = encryptor->Encrypt(data);
    data = encrypted_data;
  }

  size_t size = data.size();
  if (static_cast<size_t>(encoder.GetDict()->GetIntegerFor("Length")) != size) {
    encoder.CloneDict();
    encoder.GetClonedDict()->SetNewFor<CPDF_Number>("Length",
                                                    static_cast<int>(size));
  }

  if (!encoder.GetDict()->WriteTo(archive, encryptor))
    return false;

  if (!archive->WriteString("stream\r\n"))
    return false;

  if (size && !archive->WriteBlock(data.data(), size))
    return false;

  if (!archive->WriteString("\r\nendstream"))
    return false;

  return true;
}
