|  | /* | 
|  | *  Copyright 2018 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "rtc_base/memory_stream.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cerrno> | 
|  | #include <cstdint> | 
|  | #include <cstring> | 
|  |  | 
|  | #include "api/array_view.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/stream.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | StreamState MemoryStream::GetState() const { | 
|  | return SS_OPEN; | 
|  | } | 
|  |  | 
|  | StreamResult MemoryStream::Read(ArrayView<uint8_t> buffer, | 
|  | size_t& bytes_read, | 
|  | int& error) { | 
|  | if (seek_position_ >= data_length_) { | 
|  | return SR_EOS; | 
|  | } | 
|  | size_t available = data_length_ - seek_position_; | 
|  | size_t bytes; | 
|  | if (buffer.size() > available) { | 
|  | // Read partial buffer | 
|  | bytes = available; | 
|  | } else { | 
|  | bytes = buffer.size(); | 
|  | } | 
|  | memcpy(buffer.data(), &buffer_[seek_position_], bytes); | 
|  | seek_position_ += bytes; | 
|  | bytes_read = bytes; | 
|  | return SR_SUCCESS; | 
|  | } | 
|  |  | 
|  | StreamResult MemoryStream::Write(ArrayView<const uint8_t> buffer, | 
|  | size_t& bytes_written, | 
|  | int& error) { | 
|  | size_t available = buffer_length_ - seek_position_; | 
|  | if (0 == available) { | 
|  | // Increase buffer size to the larger of: | 
|  | // a) new position rounded up to next 256 bytes | 
|  | // b) double the previous length | 
|  | size_t new_buffer_length = std::max( | 
|  | ((seek_position_ + buffer.size()) | 0xFF) + 1, buffer_length_ * 2); | 
|  | StreamResult result = DoReserve(new_buffer_length, &error); | 
|  | if (SR_SUCCESS != result) { | 
|  | return result; | 
|  | } | 
|  | RTC_DCHECK(buffer_length_ >= new_buffer_length); | 
|  | available = buffer_length_ - seek_position_; | 
|  | } | 
|  |  | 
|  | size_t bytes = buffer.size(); | 
|  | if (bytes > available) { | 
|  | bytes = available; | 
|  | } | 
|  | memcpy(&buffer_[seek_position_], buffer.data(), bytes); | 
|  | seek_position_ += bytes; | 
|  | if (data_length_ < seek_position_) { | 
|  | data_length_ = seek_position_; | 
|  | } | 
|  | bytes_written = bytes; | 
|  | return SR_SUCCESS; | 
|  | } | 
|  |  | 
|  | void MemoryStream::Close() { | 
|  | // nothing to do | 
|  | } | 
|  |  | 
|  | bool MemoryStream::SetPosition(size_t position) { | 
|  | if (position > data_length_) | 
|  | return false; | 
|  | seek_position_ = position; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool MemoryStream::GetPosition(size_t* position) const { | 
|  | if (position) | 
|  | *position = seek_position_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void MemoryStream::Rewind() { | 
|  | seek_position_ = 0; | 
|  | } | 
|  |  | 
|  | bool MemoryStream::GetSize(size_t* size) const { | 
|  | if (size) | 
|  | *size = data_length_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool MemoryStream::ReserveSize(size_t size) { | 
|  | return (SR_SUCCESS == DoReserve(size, nullptr)); | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | MemoryStream::MemoryStream() {} | 
|  |  | 
|  | MemoryStream::~MemoryStream() { | 
|  | delete[] buffer_; | 
|  | } | 
|  |  | 
|  | void MemoryStream::SetData(const void* data, size_t length) { | 
|  | data_length_ = buffer_length_ = length; | 
|  | delete[] buffer_; | 
|  | buffer_ = new char[buffer_length_]; | 
|  | memcpy(buffer_, data, data_length_); | 
|  | seek_position_ = 0; | 
|  | } | 
|  |  | 
|  | StreamResult MemoryStream::DoReserve(size_t size, int* error) { | 
|  | if (buffer_length_ >= size) | 
|  | return SR_SUCCESS; | 
|  |  | 
|  | if (char* new_buffer = new char[size]) { | 
|  | if (buffer_ != nullptr && data_length_ > 0) { | 
|  | memcpy(new_buffer, buffer_, data_length_); | 
|  | } | 
|  | delete[] buffer_; | 
|  | buffer_ = new_buffer; | 
|  | buffer_length_ = size; | 
|  | return SR_SUCCESS; | 
|  | } | 
|  |  | 
|  | if (error) { | 
|  | *error = ENOMEM; | 
|  | } | 
|  | return SR_ERROR; | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |