blob: 8073d375dad189f3ae035c367c0d3d9bb06b3b58 [file] [log] [blame]
// 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.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fxcrt/cfx_memorystream.h"
#include <algorithm>
#include "core/fxcrt/fx_safe_types.h"
namespace {
constexpr size_t kBlockSize = 64 * 1024;
} // namespace
CFX_MemoryStream::CFX_MemoryStream(bool bConsecutive)
: m_nTotalSize(0),
m_nCurSize(0),
m_bConsecutive(bConsecutive),
m_bTakeOver(true) {}
CFX_MemoryStream::CFX_MemoryStream(uint8_t* pBuffer,
size_t nSize,
bool bTakeOver)
: m_nTotalSize(nSize),
m_nCurSize(nSize),
m_bConsecutive(true),
m_bTakeOver(bTakeOver) {
m_Blocks.push_back(pBuffer);
}
CFX_MemoryStream::~CFX_MemoryStream() {
if (m_bTakeOver) {
for (uint8_t* pBlock : m_Blocks)
FX_Free(pBlock);
}
}
FX_FILESIZE CFX_MemoryStream::GetSize() {
return static_cast<FX_FILESIZE>(m_nCurSize);
}
bool CFX_MemoryStream::IsEOF() {
return m_nCurPos >= static_cast<size_t>(GetSize());
}
FX_FILESIZE CFX_MemoryStream::GetPosition() {
return static_cast<FX_FILESIZE>(m_nCurPos);
}
bool CFX_MemoryStream::Flush() {
return true;
}
bool CFX_MemoryStream::ReadBlock(void* buffer,
FX_FILESIZE offset,
size_t size) {
if (!buffer || !size || offset < 0)
return false;
FX_SAFE_SIZE_T newPos = size;
newPos += offset;
if (!newPos.IsValid() || newPos.ValueOrDefault(0) == 0 ||
newPos.ValueOrDie() > m_nCurSize) {
return false;
}
m_nCurPos = newPos.ValueOrDie();
if (m_bConsecutive) {
memcpy(buffer, m_Blocks[0] + static_cast<size_t>(offset), size);
return true;
}
size_t nStartBlock = static_cast<size_t>(offset) / kBlockSize;
offset -= static_cast<FX_FILESIZE>(nStartBlock * kBlockSize);
while (size) {
size_t nRead = std::min(size, kBlockSize - static_cast<size_t>(offset));
memcpy(buffer, m_Blocks[nStartBlock] + offset, nRead);
buffer = static_cast<uint8_t*>(buffer) + nRead;
size -= nRead;
++nStartBlock;
offset = 0;
}
return true;
}
size_t CFX_MemoryStream::ReadBlock(void* buffer, size_t size) {
if (m_nCurPos >= m_nCurSize)
return 0;
size_t nRead = std::min(size, m_nCurSize - m_nCurPos);
if (!ReadBlock(buffer, static_cast<int32_t>(m_nCurPos), nRead))
return 0;
return nRead;
}
bool CFX_MemoryStream::WriteBlock(const void* buffer,
FX_FILESIZE offset,
size_t size) {
if (!buffer || !size)
return false;
if (m_bConsecutive) {
FX_SAFE_SIZE_T newPos = size;
newPos += offset;
if (!newPos.IsValid())
return false;
m_nCurPos = newPos.ValueOrDie();
if (m_nCurPos > m_nTotalSize) {
m_nTotalSize = (m_nCurPos + kBlockSize - 1) / kBlockSize * kBlockSize;
if (m_Blocks.empty())
m_Blocks.push_back(FX_Alloc(uint8_t, m_nTotalSize));
else
m_Blocks[0] = FX_Realloc(uint8_t, m_Blocks[0], m_nTotalSize);
}
memcpy(m_Blocks[0] + offset, buffer, size);
m_nCurSize = std::max(m_nCurSize, m_nCurPos);
return true;
}
FX_SAFE_SIZE_T newPos = size;
newPos += offset;
if (!newPos.IsValid())
return false;
if (!ExpandBlocks(newPos.ValueOrDie()))
return false;
m_nCurPos = newPos.ValueOrDie();
size_t nStartBlock = static_cast<size_t>(offset) / kBlockSize;
offset -= static_cast<FX_FILESIZE>(nStartBlock * kBlockSize);
while (size) {
size_t nWrite = std::min(size, kBlockSize - static_cast<size_t>(offset));
memcpy(m_Blocks[nStartBlock] + offset, buffer, nWrite);
buffer = static_cast<const uint8_t*>(buffer) + nWrite;
size -= nWrite;
++nStartBlock;
offset = 0;
}
return true;
}
bool CFX_MemoryStream::Seek(size_t pos) {
if (pos > m_nCurSize)
return false;
m_nCurPos = pos;
return true;
}
bool CFX_MemoryStream::ExpandBlocks(size_t size) {
m_nCurSize = std::max(m_nCurSize, size);
if (size <= m_nTotalSize)
return true;
size = (size - m_nTotalSize + kBlockSize - 1) / kBlockSize;
size_t iCount = m_Blocks.size();
m_Blocks.resize(iCount + size);
while (size--) {
m_Blocks[iCount++] = FX_Alloc(uint8_t, kBlockSize);
m_nTotalSize += kBlockSize;
}
return true;
}