• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CFX_MemoryStream(bool bConsecutive)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 
CFX_MemoryStream(uint8_t * pBuffer,size_t nSize,bool bTakeOver)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 
~CFX_MemoryStream()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 
GetSize()44 FX_FILESIZE CFX_MemoryStream::GetSize() {
45   return static_cast<FX_FILESIZE>(m_nCurSize);
46 }
47 
IsEOF()48 bool CFX_MemoryStream::IsEOF() {
49   return m_nCurPos >= static_cast<size_t>(GetSize());
50 }
51 
GetPosition()52 FX_FILESIZE CFX_MemoryStream::GetPosition() {
53   return static_cast<FX_FILESIZE>(m_nCurPos);
54 }
55 
Flush()56 bool CFX_MemoryStream::Flush() {
57   return true;
58 }
59 
ReadBlock(void * buffer,FX_FILESIZE offset,size_t size)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 
ReadBlock(void * buffer,size_t size)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 
WriteBlock(const void * buffer,FX_FILESIZE offset,size_t size)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 
EstimateSize(size_t nInitSize,size_t nGrowSize)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 
AttachBuffer(uint8_t * pBuffer,size_t nSize)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 
DetachBuffer()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 
ExpandBlocks(size_t size)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