1 // Copyright 2017 The PDFium Authors
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 #include <utility>
11
12 #include "core/fxcrt/fx_safe_types.h"
13 #include "core/fxcrt/span_util.h"
14
15 CFX_MemoryStream::CFX_MemoryStream() = default;
16
17 CFX_MemoryStream::~CFX_MemoryStream() = default;
18
GetSize()19 FX_FILESIZE CFX_MemoryStream::GetSize() {
20 return static_cast<FX_FILESIZE>(m_nCurSize);
21 }
22
IsEOF()23 bool CFX_MemoryStream::IsEOF() {
24 return m_nCurPos >= static_cast<size_t>(GetSize());
25 }
26
GetPosition()27 FX_FILESIZE CFX_MemoryStream::GetPosition() {
28 return static_cast<FX_FILESIZE>(m_nCurPos);
29 }
30
Flush()31 bool CFX_MemoryStream::Flush() {
32 return true;
33 }
34
GetSpan() const35 pdfium::span<const uint8_t> CFX_MemoryStream::GetSpan() const {
36 return pdfium::make_span(m_data).first(m_nCurSize);
37 }
38
ReadBlockAtOffset(pdfium::span<uint8_t> buffer,FX_FILESIZE offset)39 bool CFX_MemoryStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
40 FX_FILESIZE offset) {
41 if (buffer.empty() || offset < 0)
42 return false;
43
44 FX_SAFE_SIZE_T new_pos = buffer.size();
45 new_pos += offset;
46 if (!new_pos.IsValid() || new_pos.ValueOrDefault(0) == 0 ||
47 new_pos.ValueOrDie() > m_nCurSize) {
48 return false;
49 }
50
51 m_nCurPos = new_pos.ValueOrDie();
52 // Safe to cast `offset` because it was used to calculate `new_pos` above, and
53 // `new_pos` is valid.
54 fxcrt::spancpy(buffer,
55 GetSpan().subspan(static_cast<size_t>(offset), buffer.size()));
56 return true;
57 }
58
ReadBlock(pdfium::span<uint8_t> buffer)59 size_t CFX_MemoryStream::ReadBlock(pdfium::span<uint8_t> buffer) {
60 if (m_nCurPos >= m_nCurSize)
61 return 0;
62
63 size_t nRead = std::min(buffer.size(), m_nCurSize - m_nCurPos);
64 if (!ReadBlockAtOffset(buffer.first(nRead), static_cast<int32_t>(m_nCurPos)))
65 return 0;
66
67 return nRead;
68 }
69
WriteBlockAtOffset(pdfium::span<const uint8_t> buffer,FX_FILESIZE offset)70 bool CFX_MemoryStream::WriteBlockAtOffset(pdfium::span<const uint8_t> buffer,
71 FX_FILESIZE offset) {
72 if (offset < 0)
73 return false;
74
75 if (buffer.empty())
76 return true;
77
78 FX_SAFE_SIZE_T safe_new_pos = buffer.size();
79 safe_new_pos += offset;
80 if (!safe_new_pos.IsValid())
81 return false;
82
83 size_t new_pos = safe_new_pos.ValueOrDie();
84 if (new_pos > m_data.size()) {
85 static constexpr size_t kBlockSize = 64 * 1024;
86 FX_SAFE_SIZE_T new_size = new_pos;
87 new_size *= 2;
88 new_size += (kBlockSize - 1);
89 new_size /= kBlockSize;
90 new_size *= kBlockSize;
91 if (!new_size.IsValid())
92 return false;
93
94 m_data.resize(new_size.ValueOrDie());
95 }
96 m_nCurPos = new_pos;
97
98 // Safe to cast `offset` because it was used to calculate `safe_new_pos`
99 // above, and `safe_new_pos` is valid.
100 fxcrt::spancpy(pdfium::make_span(m_data).subspan(static_cast<size_t>(offset)),
101 buffer);
102 m_nCurSize = std::max(m_nCurSize, m_nCurPos);
103
104 return true;
105 }
106