| /* | 
 |  *  Copyright 2004 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 <errno.h> | 
 | #include <string.h> | 
 | #include <algorithm> | 
 | #include <string> | 
 |  | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/location.h" | 
 | #include "rtc_base/message_queue.h" | 
 | #include "rtc_base/stream.h" | 
 | #include "rtc_base/thread.h" | 
 |  | 
 | #if defined(WEBRTC_WIN) | 
 | #include <windows.h> | 
 |  | 
 | #define fileno _fileno | 
 | #include "rtc_base/string_utils.h" | 
 | #endif | 
 |  | 
 | namespace rtc { | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // StreamInterface | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | StreamInterface::~StreamInterface() {} | 
 |  | 
 | StreamResult StreamInterface::WriteAll(const void* data, | 
 |                                        size_t data_len, | 
 |                                        size_t* written, | 
 |                                        int* error) { | 
 |   StreamResult result = SR_SUCCESS; | 
 |   size_t total_written = 0, current_written; | 
 |   while (total_written < data_len) { | 
 |     result = Write(static_cast<const char*>(data) + total_written, | 
 |                    data_len - total_written, ¤t_written, error); | 
 |     if (result != SR_SUCCESS) | 
 |       break; | 
 |     total_written += current_written; | 
 |   } | 
 |   if (written) | 
 |     *written = total_written; | 
 |   return result; | 
 | } | 
 |  | 
 | void StreamInterface::PostEvent(Thread* t, int events, int err) { | 
 |   t->Post(RTC_FROM_HERE, this, MSG_POST_EVENT, | 
 |           new StreamEventData(events, err)); | 
 | } | 
 |  | 
 | void StreamInterface::PostEvent(int events, int err) { | 
 |   PostEvent(Thread::Current(), events, err); | 
 | } | 
 |  | 
 | bool StreamInterface::Flush() { | 
 |   return false; | 
 | } | 
 |  | 
 | StreamInterface::StreamInterface() {} | 
 |  | 
 | void StreamInterface::OnMessage(Message* msg) { | 
 |   if (MSG_POST_EVENT == msg->message_id) { | 
 |     StreamEventData* pe = static_cast<StreamEventData*>(msg->pdata); | 
 |     SignalEvent(this, pe->events, pe->error); | 
 |     delete msg->pdata; | 
 |   } | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // StreamAdapterInterface | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | StreamAdapterInterface::StreamAdapterInterface(StreamInterface* stream, | 
 |                                                bool owned) | 
 |     : stream_(stream), owned_(owned) { | 
 |   if (nullptr != stream_) | 
 |     stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent); | 
 | } | 
 |  | 
 | StreamState StreamAdapterInterface::GetState() const { | 
 |   return stream_->GetState(); | 
 | } | 
 | StreamResult StreamAdapterInterface::Read(void* buffer, | 
 |                                           size_t buffer_len, | 
 |                                           size_t* read, | 
 |                                           int* error) { | 
 |   return stream_->Read(buffer, buffer_len, read, error); | 
 | } | 
 | StreamResult StreamAdapterInterface::Write(const void* data, | 
 |                                            size_t data_len, | 
 |                                            size_t* written, | 
 |                                            int* error) { | 
 |   return stream_->Write(data, data_len, written, error); | 
 | } | 
 | void StreamAdapterInterface::Close() { | 
 |   stream_->Close(); | 
 | } | 
 |  | 
 | bool StreamAdapterInterface::Flush() { | 
 |   return stream_->Flush(); | 
 | } | 
 |  | 
 | void StreamAdapterInterface::Attach(StreamInterface* stream, bool owned) { | 
 |   if (nullptr != stream_) | 
 |     stream_->SignalEvent.disconnect(this); | 
 |   if (owned_) | 
 |     delete stream_; | 
 |   stream_ = stream; | 
 |   owned_ = owned; | 
 |   if (nullptr != stream_) | 
 |     stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent); | 
 | } | 
 |  | 
 | StreamInterface* StreamAdapterInterface::Detach() { | 
 |   if (nullptr != stream_) | 
 |     stream_->SignalEvent.disconnect(this); | 
 |   StreamInterface* stream = stream_; | 
 |   stream_ = nullptr; | 
 |   return stream; | 
 | } | 
 |  | 
 | StreamAdapterInterface::~StreamAdapterInterface() { | 
 |   if (owned_) | 
 |     delete stream_; | 
 | } | 
 |  | 
 | void StreamAdapterInterface::OnEvent(StreamInterface* stream, | 
 |                                      int events, | 
 |                                      int err) { | 
 |   SignalEvent(this, events, err); | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // FileStream | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | FileStream::FileStream() : file_(nullptr) {} | 
 |  | 
 | FileStream::~FileStream() { | 
 |   FileStream::Close(); | 
 | } | 
 |  | 
 | bool FileStream::Open(const std::string& filename, | 
 |                       const char* mode, | 
 |                       int* error) { | 
 |   Close(); | 
 | #if defined(WEBRTC_WIN) | 
 |   std::wstring wfilename; | 
 |   if (Utf8ToWindowsFilename(filename, &wfilename)) { | 
 |     file_ = _wfopen(wfilename.c_str(), ToUtf16(mode).c_str()); | 
 |   } else { | 
 |     if (error) { | 
 |       *error = -1; | 
 |       return false; | 
 |     } | 
 |   } | 
 | #else | 
 |   file_ = fopen(filename.c_str(), mode); | 
 | #endif | 
 |   if (!file_ && error) { | 
 |     *error = errno; | 
 |   } | 
 |   return (file_ != nullptr); | 
 | } | 
 |  | 
 | bool FileStream::OpenShare(const std::string& filename, | 
 |                            const char* mode, | 
 |                            int shflag, | 
 |                            int* error) { | 
 |   Close(); | 
 | #if defined(WEBRTC_WIN) | 
 |   std::wstring wfilename; | 
 |   if (Utf8ToWindowsFilename(filename, &wfilename)) { | 
 |     file_ = _wfsopen(wfilename.c_str(), ToUtf16(mode).c_str(), shflag); | 
 |     if (!file_ && error) { | 
 |       *error = errno; | 
 |       return false; | 
 |     } | 
 |     return file_ != nullptr; | 
 |   } else { | 
 |     if (error) { | 
 |       *error = -1; | 
 |     } | 
 |     return false; | 
 |   } | 
 | #else | 
 |   return Open(filename, mode, error); | 
 | #endif | 
 | } | 
 |  | 
 | bool FileStream::DisableBuffering() { | 
 |   if (!file_) | 
 |     return false; | 
 |   return (setvbuf(file_, nullptr, _IONBF, 0) == 0); | 
 | } | 
 |  | 
 | StreamState FileStream::GetState() const { | 
 |   return (file_ == nullptr) ? SS_CLOSED : SS_OPEN; | 
 | } | 
 |  | 
 | StreamResult FileStream::Read(void* buffer, | 
 |                               size_t buffer_len, | 
 |                               size_t* read, | 
 |                               int* error) { | 
 |   if (!file_) | 
 |     return SR_EOS; | 
 |   size_t result = fread(buffer, 1, buffer_len, file_); | 
 |   if ((result == 0) && (buffer_len > 0)) { | 
 |     if (feof(file_)) | 
 |       return SR_EOS; | 
 |     if (error) | 
 |       *error = errno; | 
 |     return SR_ERROR; | 
 |   } | 
 |   if (read) | 
 |     *read = result; | 
 |   return SR_SUCCESS; | 
 | } | 
 |  | 
 | StreamResult FileStream::Write(const void* data, | 
 |                                size_t data_len, | 
 |                                size_t* written, | 
 |                                int* error) { | 
 |   if (!file_) | 
 |     return SR_EOS; | 
 |   size_t result = fwrite(data, 1, data_len, file_); | 
 |   if ((result == 0) && (data_len > 0)) { | 
 |     if (error) | 
 |       *error = errno; | 
 |     return SR_ERROR; | 
 |   } | 
 |   if (written) | 
 |     *written = result; | 
 |   return SR_SUCCESS; | 
 | } | 
 |  | 
 | void FileStream::Close() { | 
 |   if (file_) { | 
 |     DoClose(); | 
 |     file_ = nullptr; | 
 |   } | 
 | } | 
 |  | 
 | bool FileStream::SetPosition(size_t position) { | 
 |   if (!file_) | 
 |     return false; | 
 |   return (fseek(file_, static_cast<int>(position), SEEK_SET) == 0); | 
 | } | 
 |  | 
 | bool FileStream::Flush() { | 
 |   if (file_) { | 
 |     return (0 == fflush(file_)); | 
 |   } | 
 |   // try to flush empty file? | 
 |   RTC_NOTREACHED(); | 
 |   return false; | 
 | } | 
 |  | 
 | void FileStream::DoClose() { | 
 |   fclose(file_); | 
 | } | 
 |  | 
 | }  // namespace rtc |