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
14namespace brillo {
15
16MemoryStream::MemoryStream(
17    std::unique_ptr<data_container::DataContainerInterface> container,
18    size_t stream_position)
19    : container_{std::move(container)}, stream_position_{stream_position} {}
20
21StreamPtr 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
29StreamPtr 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
38StreamPtr 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
44StreamPtr 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
50StreamPtr MemoryStream::OpenRef(const char* buffer, ErrorPtr* error) {
51  return OpenRef(buffer, std::strlen(buffer), error);
52}
53
54StreamPtr MemoryStream::OpenCopyOf(const char* buffer, ErrorPtr* error) {
55  return OpenCopyOf(buffer, std::strlen(buffer), error);
56}
57
58StreamPtr 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
64StreamPtr 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
70StreamPtr 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
77StreamPtr 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
85bool MemoryStream::IsOpen() const { return container_ != nullptr; }
86bool MemoryStream::CanRead() const { return IsOpen(); }
87
88bool MemoryStream::CanWrite() const {
89  return IsOpen() && !container_->IsReadOnly();
90}
91
92bool MemoryStream::CanSeek() const { return IsOpen(); }
93bool MemoryStream::CanGetSize() const { return IsOpen(); }
94
95uint64_t MemoryStream::GetSize() const {
96  return IsOpen() ? container_->GetSize() : 0;
97}
98
99bool MemoryStream::SetSizeBlocking(uint64_t size, ErrorPtr* error) {
100  if (!CheckContainer(error))
101    return false;
102  return container_->Resize(size, error);
103}
104
105uint64_t MemoryStream::GetRemainingSize() const {
106  uint64_t pos = GetPosition();
107  uint64_t size = GetSize();
108  return (pos < size) ? size - pos : 0;
109}
110
111uint64_t MemoryStream::GetPosition() const {
112  return IsOpen() ? stream_position_ : 0;
113}
114
115bool 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
140bool 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
157bool 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
171bool MemoryStream::FlushBlocking(ErrorPtr* error) {
172  return CheckContainer(error);
173}
174
175bool MemoryStream::CloseBlocking(ErrorPtr* error) {
176  ignore_result(error);  // Unused.
177  container_.reset();
178  return true;
179}
180
181bool MemoryStream::CheckContainer(ErrorPtr* error) const {
182  return container_ || stream_utils::ErrorStreamClosed(FROM_HERE, error);
183}
184
185bool 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
192bool 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