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