Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2017 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxcrt/cfx_memorystream.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fxcrt/fx_safe_types.h"
     12 
     13 namespace {
     14 
     15 const int32_t kBlockSize = 64 * 1024;
     16 
     17 }  // namespace
     18 
     19 CFX_MemoryStream::CFX_MemoryStream(bool bConsecutive)
     20     : m_nTotalSize(0),
     21       m_nCurSize(0),
     22       m_nCurPos(0),
     23       m_nGrowSize(kBlockSize),
     24       m_dwFlags(Type::kTakeOver | (bConsecutive ? Type::kConsecutive : 0)) {}
     25 
     26 CFX_MemoryStream::CFX_MemoryStream(uint8_t* pBuffer,
     27                                    size_t nSize,
     28                                    bool bTakeOver)
     29     : m_nTotalSize(nSize),
     30       m_nCurSize(nSize),
     31       m_nCurPos(0),
     32       m_nGrowSize(kBlockSize),
     33       m_dwFlags(Type::kConsecutive | (bTakeOver ? Type::kTakeOver : 0)) {
     34   m_Blocks.push_back(pBuffer);
     35 }
     36 
     37 CFX_MemoryStream::~CFX_MemoryStream() {
     38   if (m_dwFlags & Type::kTakeOver) {
     39     for (uint8_t* pBlock : m_Blocks)
     40       FX_Free(pBlock);
     41   }
     42 }
     43 
     44 FX_FILESIZE CFX_MemoryStream::GetSize() {
     45   return static_cast<FX_FILESIZE>(m_nCurSize);
     46 }
     47 
     48 bool CFX_MemoryStream::IsEOF() {
     49   return m_nCurPos >= static_cast<size_t>(GetSize());
     50 }
     51 
     52 FX_FILESIZE CFX_MemoryStream::GetPosition() {
     53   return static_cast<FX_FILESIZE>(m_nCurPos);
     54 }
     55 
     56 bool CFX_MemoryStream::Flush() {
     57   return true;
     58 }
     59 
     60 bool CFX_MemoryStream::ReadBlock(void* buffer,
     61                                  FX_FILESIZE offset,
     62                                  size_t size) {
     63   if (!buffer || !size || offset < 0)
     64     return false;
     65 
     66   FX_SAFE_SIZE_T newPos = size;
     67   newPos += offset;
     68   if (!newPos.IsValid() || newPos.ValueOrDefault(0) == 0 ||
     69       newPos.ValueOrDie() > m_nCurSize) {
     70     return false;
     71   }
     72 
     73   m_nCurPos = newPos.ValueOrDie();
     74   if (m_dwFlags & Type::kConsecutive) {
     75     memcpy(buffer, m_Blocks[0] + static_cast<size_t>(offset), size);
     76     return true;
     77   }
     78 
     79   size_t nStartBlock = static_cast<size_t>(offset) / m_nGrowSize;
     80   offset -= static_cast<FX_FILESIZE>(nStartBlock * m_nGrowSize);
     81   while (size) {
     82     size_t nRead = std::min(size, m_nGrowSize - static_cast<size_t>(offset));
     83     memcpy(buffer, m_Blocks[nStartBlock] + offset, nRead);
     84     buffer = static_cast<uint8_t*>(buffer) + nRead;
     85     size -= nRead;
     86     ++nStartBlock;
     87     offset = 0;
     88   }
     89   return true;
     90 }
     91 
     92 size_t CFX_MemoryStream::ReadBlock(void* buffer, size_t size) {
     93   if (m_nCurPos >= m_nCurSize)
     94     return 0;
     95 
     96   size_t nRead = std::min(size, m_nCurSize - m_nCurPos);
     97   if (!ReadBlock(buffer, static_cast<int32_t>(m_nCurPos), nRead))
     98     return 0;
     99 
    100   return nRead;
    101 }
    102 
    103 bool CFX_MemoryStream::WriteBlock(const void* buffer,
    104                                   FX_FILESIZE offset,
    105                                   size_t size) {
    106   if (!buffer || !size)
    107     return false;
    108 
    109   if (m_dwFlags & Type::kConsecutive) {
    110     FX_SAFE_SIZE_T newPos = size;
    111     newPos += offset;
    112     if (!newPos.IsValid())
    113       return false;
    114 
    115     m_nCurPos = newPos.ValueOrDie();
    116     if (m_nCurPos > m_nTotalSize) {
    117       m_nTotalSize = (m_nCurPos + m_nGrowSize - 1) / m_nGrowSize * m_nGrowSize;
    118       if (m_Blocks.empty())
    119         m_Blocks.push_back(FX_Alloc(uint8_t, m_nTotalSize));
    120       else
    121         m_Blocks[0] = FX_Realloc(uint8_t, m_Blocks[0], m_nTotalSize);
    122     }
    123 
    124     memcpy(m_Blocks[0] + offset, buffer, size);
    125     m_nCurSize = std::max(m_nCurSize, m_nCurPos);
    126 
    127     return true;
    128   }
    129 
    130   FX_SAFE_SIZE_T newPos = size;
    131   newPos += offset;
    132   if (!newPos.IsValid())
    133     return false;
    134   if (!ExpandBlocks(newPos.ValueOrDie()))
    135     return false;
    136 
    137   m_nCurPos = newPos.ValueOrDie();
    138   size_t nStartBlock = static_cast<size_t>(offset) / m_nGrowSize;
    139   offset -= static_cast<FX_FILESIZE>(nStartBlock * m_nGrowSize);
    140   while (size) {
    141     size_t nWrite = std::min(size, m_nGrowSize - static_cast<size_t>(offset));
    142     memcpy(m_Blocks[nStartBlock] + offset, buffer, nWrite);
    143     buffer = static_cast<const uint8_t*>(buffer) + nWrite;
    144     size -= nWrite;
    145     ++nStartBlock;
    146     offset = 0;
    147   }
    148   return true;
    149 }
    150 
    151 void CFX_MemoryStream::EstimateSize(size_t nInitSize, size_t nGrowSize) {
    152   if (m_dwFlags & Type::kConsecutive) {
    153     if (m_Blocks.empty()) {
    154       m_Blocks.push_back(
    155           FX_Alloc(uint8_t, std::max(nInitSize, static_cast<size_t>(4096))));
    156     }
    157     m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096));
    158   } else if (m_Blocks.empty()) {
    159     m_nGrowSize = std::max(nGrowSize, static_cast<size_t>(4096));
    160   }
    161 }
    162 
    163 void CFX_MemoryStream::AttachBuffer(uint8_t* pBuffer, size_t nSize) {
    164   if (!(m_dwFlags & Type::kConsecutive))
    165     return;
    166 
    167   m_Blocks.clear();
    168   m_Blocks.push_back(pBuffer);
    169   m_nTotalSize = nSize;
    170   m_nCurSize = nSize;
    171   m_nCurPos = 0;
    172   m_dwFlags = Type::kConsecutive;
    173 }
    174 
    175 void CFX_MemoryStream::DetachBuffer() {
    176   if (!(m_dwFlags & Type::kConsecutive))
    177     return;
    178 
    179   m_Blocks.clear();
    180   m_nTotalSize = 0;
    181   m_nCurSize = 0;
    182   m_nCurPos = 0;
    183   m_dwFlags = Type::kTakeOver;
    184 }
    185 
    186 bool CFX_MemoryStream::ExpandBlocks(size_t size) {
    187   m_nCurSize = std::max(m_nCurSize, size);
    188   if (size <= m_nTotalSize)
    189     return true;
    190 
    191   size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;
    192   size_t iCount = m_Blocks.size();
    193   m_Blocks.resize(iCount + size);
    194   while (size--) {
    195     m_Blocks[iCount++] = FX_Alloc(uint8_t, m_nGrowSize);
    196     m_nTotalSize += m_nGrowSize;
    197   }
    198   return true;
    199 }
    200