1 //
2 // memory_stream.cpp
3 //
4 // Copyright © 2024 Apple Inc. All rights reserved.
5 //
6 // Please refer to the license found in the LICENSE file in the root directory of the source tree.
7
8 #include "memory_stream.hpp"
9
10 #include <limits>
11
12 namespace inmemoryfs {
13
MemoryStreamBuf(const std::shared_ptr<MemoryBuffer> & buffer)14 MemoryStreamBuf::MemoryStreamBuf(const std::shared_ptr<MemoryBuffer>& buffer) noexcept : buffer_(buffer) {
15 auto start = static_cast<char*>(buffer->data());
16 auto end = start + buffer->size();
17 setg(start, start, end);
18 setp(start, end);
19 }
20
iseekoff(std::streambuf::off_type offset,std::ios_base::seekdir dir)21 std::streambuf::pos_type MemoryStreamBuf::iseekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir) {
22 std::streambuf::off_type next = -1;
23 const std::ptrdiff_t size = std::ptrdiff_t(egptr() - eback());
24 switch (dir) {
25 case std::ios_base::beg: {
26 next = offset;
27 break;
28 }
29 case std::ios_base::cur: {
30 next = std::streambuf::off_type(std::ptrdiff_t(gptr() - eback())) + offset;
31 break;
32 }
33 case std::ios_base::end: {
34 next = std::streambuf::off_type(size) + offset;
35 break;
36 }
37 default:
38 break;
39 }
40
41 if (next < 0 || next >= std::streambuf::off_type(size)) {
42 return std::streambuf::pos_type(std::streambuf::off_type(-1));
43 }
44
45 setg(eback(), eback() + next, egptr());
46 return gptr() - eback();
47 }
48
oseekoff(std::streambuf::off_type offset,std::ios_base::seekdir dir)49 std::streambuf::pos_type MemoryStreamBuf::oseekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir) {
50 std::streambuf::off_type next = -1;
51 const std::ptrdiff_t size = std::ptrdiff_t(epptr() - pbase());
52 switch (dir) {
53 case std::ios_base::beg: {
54 next = offset;
55 break;
56 }
57 case std::ios_base::cur: {
58 next = std::streambuf::off_type(std::ptrdiff_t(pptr() - pbase())) + offset;
59 break;
60 }
61 case std::ios_base::end: {
62 next = std::streambuf::off_type(size) + offset;
63 break;
64 }
65 default: {
66 break;
67 }
68 }
69
70 if (next < 0 || next > std::streambuf::off_type(size)) {
71 return std::streambuf::pos_type(std::streambuf::off_type(-1));
72 }
73
74 setp(pbase(), epptr());
75 pbump(static_cast<int>(next));
76 return pptr() - pbase();
77 }
78
79 std::streambuf::pos_type
seekoff(std::streambuf::off_type offset,std::ios_base::seekdir dir,std::ios_base::openmode which)80 MemoryStreamBuf::seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir, std::ios_base::openmode which) {
81 if (which & std::ios_base::out) {
82 return oseekoff(offset, dir);
83 } else if (which & std::ios_base::in) {
84 return iseekoff(offset, dir);
85 } else {
86 return std::streambuf::pos_type(std::streambuf::off_type(-1));
87 }
88 }
89
seekpos(std::streambuf::pos_type pos,std::ios_base::openmode which)90 std::streambuf::pos_type MemoryStreamBuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode which) {
91 return seekoff(pos - std::streambuf::pos_type(std::streambuf::off_type(0)), std::ios::beg, which);
92 }
93
showmanyc()94 std::streamsize MemoryStreamBuf::showmanyc() {
95 std::ptrdiff_t n = egptr() - gptr();
96 std::streamsize max = std::numeric_limits<std::streamsize>::max();
97 return (n <= max ? std::streamsize(n) : max);
98 }
99
pbackfail(std::streambuf::int_type ch)100 std::streambuf::int_type MemoryStreamBuf::pbackfail(std::streambuf::int_type ch) {
101 if (eback() == gptr() || (ch != traits_type::eof() && ch != gptr()[-1])) {
102 return traits_type::eof();
103 }
104 gbump(-1);
105 return ch;
106 }
107
underflow()108 std::streambuf::int_type MemoryStreamBuf::underflow() {
109 if (gptr() == egptr()) {
110 return traits_type::eof();
111 }
112 return traits_type::to_int_type(*gptr());
113 }
114
uflow()115 std::streambuf::int_type MemoryStreamBuf::uflow() {
116 if (gptr() == egptr()) {
117 return traits_type::eof();
118 }
119 const std::streambuf::char_type ch = *gptr();
120 gbump(1);
121 return traits_type::to_int_type(ch);
122 }
123
overflow(std::streambuf::int_type ch)124 std::streambuf::int_type MemoryStreamBuf::overflow(std::streambuf::int_type ch) {
125 if (ch == traits_type::eof()) {
126 return ch;
127 }
128 const std::streambuf::char_type c = traits_type::to_char_type(ch);
129 xsputn(&c, 1);
130 return ch;
131 }
132
xsgetn(char * s,std::streamsize n)133 std::streamsize MemoryStreamBuf::xsgetn(char* s, std::streamsize n) {
134 const ptrdiff_t remaining = egptr() - gptr();
135 n = std::min(n, remaining);
136 if (n <= 0) {
137 return std::streamsize(0);
138 }
139 auto current = epptr();
140 for (std::streamsize i = 0; i < n; i++) {
141 *(s + i) = *(current + i);
142 }
143 setg(eback(), current + n, egptr());
144 return n;
145 }
146
xsputn(const char * s,std::streamsize n)147 std::streamsize MemoryStreamBuf::xsputn(const char* s, std::streamsize n) {
148 const ptrdiff_t remaining = epptr() - pptr();
149 n = std::min(n, remaining);
150 if (n <= 0) {
151 return std::streamsize(0);
152 }
153 auto current = pptr();
154 for (std::streamsize i = 0; i < n; i++) {
155 *(current + i) = *(s + i);
156 }
157
158 pbump(static_cast<int>(n));
159 return n;
160 }
161
MemoryIStream(const std::shared_ptr<MemoryBuffer> & buffer)162 MemoryIStream::MemoryIStream(const std::shared_ptr<MemoryBuffer>& buffer) noexcept
163 : std::istream(nullptr), streambuf(buffer) {
164 rdbuf(&streambuf);
165 }
166
MemoryOStream(const std::shared_ptr<MemoryBuffer> & buffer)167 MemoryOStream::MemoryOStream(const std::shared_ptr<MemoryBuffer>& buffer) noexcept
168 : std::ostream(nullptr), streambuf(buffer) {
169 rdbuf(&streambuf);
170 }
171
172 } // namespace inmemoryfs
173