1 // Copyright 2015 The Chromium OS 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 #include <brillo/streams/memory_stream.h>
6 
7 #include <limits>
8 
9 #include <base/bind.h>
10 #include <brillo/message_loops/message_loop.h>
11 #include <brillo/streams/stream_errors.h>
12 #include <brillo/streams/stream_utils.h>
13 
14 namespace brillo {
15 
MemoryStream(std::unique_ptr<data_container::DataContainerInterface> container,size_t stream_position)16 MemoryStream::MemoryStream(
17     std::unique_ptr<data_container::DataContainerInterface> container,
18     size_t stream_position)
19     : container_{std::move(container)}, stream_position_{stream_position} {}
20 
OpenRef(const void * buffer,size_t size,ErrorPtr * error)21 StreamPtr MemoryStream::OpenRef(const void* buffer,
22                                 size_t size,
23                                 ErrorPtr* error) {
24   std::unique_ptr<data_container::ReadOnlyBuffer> container{
25       new data_container::ReadOnlyBuffer{buffer, size}};
26   return CreateEx(std::move(container), 0, error);
27 }
28 
OpenCopyOf(const void * buffer,size_t size,ErrorPtr * error)29 StreamPtr MemoryStream::OpenCopyOf(const void* buffer,
30                                    size_t size,
31                                    ErrorPtr* error) {
32   std::unique_ptr<data_container::ReadOnlyVectorCopy<uint8_t>> container{
33       new data_container::ReadOnlyVectorCopy<uint8_t>{
34           reinterpret_cast<const uint8_t*>(buffer), size}};
35   return CreateEx(std::move(container), 0, error);
36 }
37 
OpenRef(const std::string & buffer,ErrorPtr * error)38 StreamPtr MemoryStream::OpenRef(const std::string& buffer, ErrorPtr* error) {
39   std::unique_ptr<data_container::ReadOnlyStringRef> container{
40       new data_container::ReadOnlyStringRef{buffer}};
41   return CreateEx(std::move(container), 0, error);
42 }
43 
OpenCopyOf(std::string buffer,ErrorPtr * error)44 StreamPtr MemoryStream::OpenCopyOf(std::string buffer, ErrorPtr* error) {
45   std::unique_ptr<data_container::ReadOnlyStringCopy> container{
46       new data_container::ReadOnlyStringCopy{std::move(buffer)}};
47   return CreateEx(std::move(container), 0, error);
48 }
49 
OpenRef(const char * buffer,ErrorPtr * error)50 StreamPtr MemoryStream::OpenRef(const char* buffer, ErrorPtr* error) {
51   return OpenRef(buffer, std::strlen(buffer), error);
52 }
53 
OpenCopyOf(const char * buffer,ErrorPtr * error)54 StreamPtr MemoryStream::OpenCopyOf(const char* buffer, ErrorPtr* error) {
55   return OpenCopyOf(buffer, std::strlen(buffer), error);
56 }
57 
Create(size_t reserve_size,ErrorPtr * error)58 StreamPtr MemoryStream::Create(size_t reserve_size, ErrorPtr* error) {
59   std::unique_ptr<data_container::ByteBuffer> container{
60       new data_container::ByteBuffer{reserve_size}};
61   return CreateEx(std::move(container), 0, error);
62 }
63 
CreateRef(std::string * buffer,ErrorPtr * error)64 StreamPtr MemoryStream::CreateRef(std::string* buffer, ErrorPtr* error) {
65   std::unique_ptr<data_container::StringPtr> container{
66       new data_container::StringPtr{buffer}};
67   return CreateEx(std::move(container), 0, error);
68 }
69 
CreateRefForAppend(std::string * buffer,ErrorPtr * error)70 StreamPtr MemoryStream::CreateRefForAppend(std::string* buffer,
71                                            ErrorPtr* error) {
72   std::unique_ptr<data_container::StringPtr> container{
73       new data_container::StringPtr{buffer}};
74   return CreateEx(std::move(container), buffer->size(), error);
75 }
76 
CreateEx(std::unique_ptr<data_container::DataContainerInterface> container,size_t stream_position,ErrorPtr * error)77 StreamPtr MemoryStream::CreateEx(
78     std::unique_ptr<data_container::DataContainerInterface> container,
79     size_t stream_position,
80     ErrorPtr* error) {
81   ignore_result(error);  // Unused.
82   return StreamPtr{new MemoryStream(std::move(container), stream_position)};
83 }
84 
IsOpen() const85 bool MemoryStream::IsOpen() const { return container_ != nullptr; }
CanRead() const86 bool MemoryStream::CanRead() const { return IsOpen(); }
87 
CanWrite() const88 bool MemoryStream::CanWrite() const {
89   return IsOpen() && !container_->IsReadOnly();
90 }
91 
CanSeek() const92 bool MemoryStream::CanSeek() const { return IsOpen(); }
CanGetSize() const93 bool MemoryStream::CanGetSize() const { return IsOpen(); }
94 
GetSize() const95 uint64_t MemoryStream::GetSize() const {
96   return IsOpen() ? container_->GetSize() : 0;
97 }
98 
SetSizeBlocking(uint64_t size,ErrorPtr * error)99 bool MemoryStream::SetSizeBlocking(uint64_t size, ErrorPtr* error) {
100   if (!CheckContainer(error))
101     return false;
102   return container_->Resize(size, error);
103 }
104 
GetRemainingSize() const105 uint64_t MemoryStream::GetRemainingSize() const {
106   uint64_t pos = GetPosition();
107   uint64_t size = GetSize();
108   return (pos < size) ? size - pos : 0;
109 }
110 
GetPosition() const111 uint64_t MemoryStream::GetPosition() const {
112   return IsOpen() ? stream_position_ : 0;
113 }
114 
Seek(int64_t offset,Whence whence,uint64_t * new_position,ErrorPtr * error)115 bool MemoryStream::Seek(int64_t offset,
116                         Whence whence,
117                         uint64_t* new_position,
118                         ErrorPtr* error) {
119   uint64_t pos = 0;
120   if (!CheckContainer(error) ||
121       !stream_utils::CalculateStreamPosition(FROM_HERE, offset, whence,
122                                              stream_position_, GetSize(), &pos,
123                                              error)) {
124     return false;
125   }
126   if (pos > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) {
127     // This can only be the case on 32 bit systems.
128     brillo::Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
129                          errors::stream::kInvalidParameter,
130                          "Stream pointer position is outside allowed limits");
131     return false;
132   }
133 
134   stream_position_ = static_cast<size_t>(pos);
135   if (new_position)
136     *new_position = stream_position_;
137   return true;
138 }
139 
ReadNonBlocking(void * buffer,size_t size_to_read,size_t * size_read,bool * end_of_stream,ErrorPtr * error)140 bool MemoryStream::ReadNonBlocking(void* buffer,
141                                    size_t size_to_read,
142                                    size_t* size_read,
143                                    bool* end_of_stream,
144                                    ErrorPtr* error) {
145   if (!CheckContainer(error))
146     return false;
147   size_t read = 0;
148   if (!container_->Read(buffer, size_to_read, stream_position_, &read, error))
149     return false;
150   stream_position_ += read;
151   *size_read = read;
152   if (end_of_stream)
153     *end_of_stream = (read == 0) && (size_to_read != 0);
154   return true;
155 }
156 
WriteNonBlocking(const void * buffer,size_t size_to_write,size_t * size_written,ErrorPtr * error)157 bool MemoryStream::WriteNonBlocking(const void* buffer,
158                                     size_t size_to_write,
159                                     size_t* size_written,
160                                     ErrorPtr* error) {
161   if (!CheckContainer(error))
162     return false;
163   if (!container_->Write(buffer, size_to_write, stream_position_, size_written,
164                          error)) {
165     return false;
166   }
167   stream_position_ += *size_written;
168   return true;
169 }
170 
FlushBlocking(ErrorPtr * error)171 bool MemoryStream::FlushBlocking(ErrorPtr* error) {
172   return CheckContainer(error);
173 }
174 
CloseBlocking(ErrorPtr * error)175 bool MemoryStream::CloseBlocking(ErrorPtr* error) {
176   ignore_result(error);  // Unused.
177   container_.reset();
178   return true;
179 }
180 
CheckContainer(ErrorPtr * error) const181 bool MemoryStream::CheckContainer(ErrorPtr* error) const {
182   return container_ || stream_utils::ErrorStreamClosed(FROM_HERE, error);
183 }
184 
WaitForData(AccessMode mode,const base::Callback<void (AccessMode)> & callback,ErrorPtr *)185 bool MemoryStream::WaitForData(AccessMode mode,
186                                const base::Callback<void(AccessMode)>& callback,
187                                ErrorPtr* /* error */) {
188   MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, mode));
189   return true;
190 }
191 
WaitForDataBlocking(AccessMode in_mode,base::TimeDelta,AccessMode * out_mode,ErrorPtr *)192 bool MemoryStream::WaitForDataBlocking(AccessMode in_mode,
193                                        base::TimeDelta /* timeout */,
194                                        AccessMode* out_mode,
195                                        ErrorPtr* /* error */) {
196   if (out_mode)
197     *out_mode = in_mode;
198   return true;
199 }
200 
201 }  // namespace brillo
202