blob: 520d1dd202e59cb29ff92f40dba293b2a28fefb0 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#if defined(WEBRTC_POSIX)
12#include <sys/file.h>
13#endif // WEBRTC_POSIX
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <errno.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000017
18#include <algorithm>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019#include <string>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000020
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021#include "webrtc/base/basictypes.h"
nissec80e7412017-01-11 05:56:46 -080022#include "webrtc/base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023#include "webrtc/base/logging.h"
24#include "webrtc/base/messagequeue.h"
25#include "webrtc/base/stream.h"
26#include "webrtc/base/stringencode.h"
27#include "webrtc/base/stringutils.h"
28#include "webrtc/base/thread.h"
29#include "webrtc/base/timeutils.h"
30
31#if defined(WEBRTC_WIN)
32#include "webrtc/base/win32.h"
33#define fileno _fileno
34#endif
35
36namespace rtc {
37
38///////////////////////////////////////////////////////////////////////////////
39// StreamInterface
40///////////////////////////////////////////////////////////////////////////////
41StreamInterface::~StreamInterface() {
42}
43
44StreamResult StreamInterface::WriteAll(const void* data, size_t data_len,
45 size_t* written, int* error) {
46 StreamResult result = SR_SUCCESS;
47 size_t total_written = 0, current_written;
48 while (total_written < data_len) {
49 result = Write(static_cast<const char*>(data) + total_written,
50 data_len - total_written, &current_written, error);
51 if (result != SR_SUCCESS)
52 break;
53 total_written += current_written;
54 }
55 if (written)
56 *written = total_written;
57 return result;
58}
59
60StreamResult StreamInterface::ReadAll(void* buffer, size_t buffer_len,
61 size_t* read, int* error) {
62 StreamResult result = SR_SUCCESS;
63 size_t total_read = 0, current_read;
64 while (total_read < buffer_len) {
65 result = Read(static_cast<char*>(buffer) + total_read,
66 buffer_len - total_read, &current_read, error);
67 if (result != SR_SUCCESS)
68 break;
69 total_read += current_read;
70 }
71 if (read)
72 *read = total_read;
73 return result;
74}
75
76StreamResult StreamInterface::ReadLine(std::string* line) {
77 line->clear();
78 StreamResult result = SR_SUCCESS;
79 while (true) {
80 char ch;
deadbeef37f5ecf2017-02-27 14:06:41 -080081 result = Read(&ch, sizeof(ch), nullptr, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082 if (result != SR_SUCCESS) {
83 break;
84 }
85 if (ch == '\n') {
86 break;
87 }
88 line->push_back(ch);
89 }
90 if (!line->empty()) { // give back the line we've collected so far with
91 result = SR_SUCCESS; // a success code. Otherwise return the last code
92 }
93 return result;
94}
95
96void StreamInterface::PostEvent(Thread* t, int events, int err) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070097 t->Post(RTC_FROM_HERE, this, MSG_POST_EVENT,
98 new StreamEventData(events, err));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099}
100
101void StreamInterface::PostEvent(int events, int err) {
102 PostEvent(Thread::Current(), events, err);
103}
104
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000105const void* StreamInterface::GetReadData(size_t* data_len) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800106 return nullptr;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000107}
108
109void* StreamInterface::GetWriteBuffer(size_t* buf_len) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800110 return nullptr;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000111}
112
113bool StreamInterface::SetPosition(size_t position) {
114 return false;
115}
116
117bool StreamInterface::GetPosition(size_t* position) const {
118 return false;
119}
120
121bool StreamInterface::GetSize(size_t* size) const {
122 return false;
123}
124
125bool StreamInterface::GetAvailable(size_t* size) const {
126 return false;
127}
128
129bool StreamInterface::GetWriteRemaining(size_t* size) const {
130 return false;
131}
132
133bool StreamInterface::Flush() {
134 return false;
135}
136
137bool StreamInterface::ReserveSize(size_t size) {
138 return true;
139}
140
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141StreamInterface::StreamInterface() {
142}
143
144void StreamInterface::OnMessage(Message* msg) {
145 if (MSG_POST_EVENT == msg->message_id) {
146 StreamEventData* pe = static_cast<StreamEventData*>(msg->pdata);
147 SignalEvent(this, pe->events, pe->error);
148 delete msg->pdata;
149 }
150}
151
152///////////////////////////////////////////////////////////////////////////////
153// StreamAdapterInterface
154///////////////////////////////////////////////////////////////////////////////
155
156StreamAdapterInterface::StreamAdapterInterface(StreamInterface* stream,
157 bool owned)
158 : stream_(stream), owned_(owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800159 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
161}
162
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000163StreamState StreamAdapterInterface::GetState() const {
164 return stream_->GetState();
165}
166StreamResult StreamAdapterInterface::Read(void* buffer,
167 size_t buffer_len,
168 size_t* read,
169 int* error) {
170 return stream_->Read(buffer, buffer_len, read, error);
171}
172StreamResult StreamAdapterInterface::Write(const void* data,
173 size_t data_len,
174 size_t* written,
175 int* error) {
176 return stream_->Write(data, data_len, written, error);
177}
178void StreamAdapterInterface::Close() {
179 stream_->Close();
180}
181
182bool StreamAdapterInterface::SetPosition(size_t position) {
183 return stream_->SetPosition(position);
184}
185
186bool StreamAdapterInterface::GetPosition(size_t* position) const {
187 return stream_->GetPosition(position);
188}
189
190bool StreamAdapterInterface::GetSize(size_t* size) const {
191 return stream_->GetSize(size);
192}
193
194bool StreamAdapterInterface::GetAvailable(size_t* size) const {
195 return stream_->GetAvailable(size);
196}
197
198bool StreamAdapterInterface::GetWriteRemaining(size_t* size) const {
199 return stream_->GetWriteRemaining(size);
200}
201
202bool StreamAdapterInterface::ReserveSize(size_t size) {
203 return stream_->ReserveSize(size);
204}
205
206bool StreamAdapterInterface::Flush() {
207 return stream_->Flush();
208}
209
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210void StreamAdapterInterface::Attach(StreamInterface* stream, bool owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800211 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212 stream_->SignalEvent.disconnect(this);
213 if (owned_)
214 delete stream_;
215 stream_ = stream;
216 owned_ = owned;
deadbeef37f5ecf2017-02-27 14:06:41 -0800217 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000218 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
219}
220
221StreamInterface* StreamAdapterInterface::Detach() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800222 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 stream_->SignalEvent.disconnect(this);
224 StreamInterface* stream = stream_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800225 stream_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226 return stream;
227}
228
229StreamAdapterInterface::~StreamAdapterInterface() {
230 if (owned_)
231 delete stream_;
232}
233
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000234void StreamAdapterInterface::OnEvent(StreamInterface* stream,
235 int events,
236 int err) {
237 SignalEvent(this, events, err);
238}
239
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000241// NullStream
242///////////////////////////////////////////////////////////////////////////////
243
244NullStream::NullStream() {
245}
246
247NullStream::~NullStream() {
248}
249
250StreamState NullStream::GetState() const {
251 return SS_OPEN;
252}
253
254StreamResult NullStream::Read(void* buffer, size_t buffer_len,
255 size_t* read, int* error) {
256 if (error) *error = -1;
257 return SR_ERROR;
258}
259
260StreamResult NullStream::Write(const void* data, size_t data_len,
261 size_t* written, int* error) {
262 if (written) *written = data_len;
263 return SR_SUCCESS;
264}
265
266void NullStream::Close() {
267}
268
269///////////////////////////////////////////////////////////////////////////////
270// FileStream
271///////////////////////////////////////////////////////////////////////////////
272
deadbeef37f5ecf2017-02-27 14:06:41 -0800273FileStream::FileStream() : file_(nullptr) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274
275FileStream::~FileStream() {
276 FileStream::Close();
277}
278
279bool FileStream::Open(const std::string& filename, const char* mode,
280 int* error) {
281 Close();
282#if defined(WEBRTC_WIN)
283 std::wstring wfilename;
284 if (Utf8ToWindowsFilename(filename, &wfilename)) {
285 file_ = _wfopen(wfilename.c_str(), ToUtf16(mode).c_str());
286 } else {
287 if (error) {
288 *error = -1;
289 return false;
290 }
291 }
292#else
293 file_ = fopen(filename.c_str(), mode);
294#endif
295 if (!file_ && error) {
296 *error = errno;
297 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800298 return (file_ != nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299}
300
301bool FileStream::OpenShare(const std::string& filename, const char* mode,
302 int shflag, int* error) {
303 Close();
304#if defined(WEBRTC_WIN)
305 std::wstring wfilename;
306 if (Utf8ToWindowsFilename(filename, &wfilename)) {
307 file_ = _wfsopen(wfilename.c_str(), ToUtf16(mode).c_str(), shflag);
308 if (!file_ && error) {
309 *error = errno;
310 return false;
311 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800312 return file_ != nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000313 } else {
314 if (error) {
315 *error = -1;
316 }
317 return false;
318 }
319#else
320 return Open(filename, mode, error);
321#endif
322}
323
324bool FileStream::DisableBuffering() {
325 if (!file_)
326 return false;
deadbeef37f5ecf2017-02-27 14:06:41 -0800327 return (setvbuf(file_, nullptr, _IONBF, 0) == 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000328}
329
330StreamState FileStream::GetState() const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800331 return (file_ == nullptr) ? SS_CLOSED : SS_OPEN;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332}
333
334StreamResult FileStream::Read(void* buffer, size_t buffer_len,
335 size_t* read, int* error) {
336 if (!file_)
337 return SR_EOS;
338 size_t result = fread(buffer, 1, buffer_len, file_);
339 if ((result == 0) && (buffer_len > 0)) {
340 if (feof(file_))
341 return SR_EOS;
342 if (error)
343 *error = errno;
344 return SR_ERROR;
345 }
346 if (read)
347 *read = result;
348 return SR_SUCCESS;
349}
350
351StreamResult FileStream::Write(const void* data, size_t data_len,
352 size_t* written, int* error) {
353 if (!file_)
354 return SR_EOS;
355 size_t result = fwrite(data, 1, data_len, file_);
356 if ((result == 0) && (data_len > 0)) {
357 if (error)
358 *error = errno;
359 return SR_ERROR;
360 }
361 if (written)
362 *written = result;
363 return SR_SUCCESS;
364}
365
366void FileStream::Close() {
367 if (file_) {
368 DoClose();
deadbeef37f5ecf2017-02-27 14:06:41 -0800369 file_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000370 }
371}
372
373bool FileStream::SetPosition(size_t position) {
374 if (!file_)
375 return false;
376 return (fseek(file_, static_cast<int>(position), SEEK_SET) == 0);
377}
378
379bool FileStream::GetPosition(size_t* position) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800380 RTC_DCHECK(nullptr != position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000381 if (!file_)
382 return false;
383 long result = ftell(file_);
384 if (result < 0)
385 return false;
386 if (position)
387 *position = result;
388 return true;
389}
390
391bool FileStream::GetSize(size_t* size) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800392 RTC_DCHECK(nullptr != size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000393 if (!file_)
394 return false;
395 struct stat file_stats;
396 if (fstat(fileno(file_), &file_stats) != 0)
397 return false;
398 if (size)
399 *size = file_stats.st_size;
400 return true;
401}
402
403bool FileStream::GetAvailable(size_t* size) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800404 RTC_DCHECK(nullptr != size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000405 if (!GetSize(size))
406 return false;
407 long result = ftell(file_);
408 if (result < 0)
409 return false;
410 if (size)
411 *size -= result;
412 return true;
413}
414
415bool FileStream::ReserveSize(size_t size) {
416 // TODO: extend the file to the proper length
417 return true;
418}
419
420bool FileStream::GetSize(const std::string& filename, size_t* size) {
421 struct stat file_stats;
422 if (stat(filename.c_str(), &file_stats) != 0)
423 return false;
424 *size = file_stats.st_size;
425 return true;
426}
427
428bool FileStream::Flush() {
429 if (file_) {
430 return (0 == fflush(file_));
431 }
432 // try to flush empty file?
nissec80e7412017-01-11 05:56:46 -0800433 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000434 return false;
435}
436
437#if defined(WEBRTC_POSIX) && !defined(__native_client__)
438
439bool FileStream::TryLock() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800440 if (file_ == nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000441 // Stream not open.
nissec80e7412017-01-11 05:56:46 -0800442 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000443 return false;
444 }
445
446 return flock(fileno(file_), LOCK_EX|LOCK_NB) == 0;
447}
448
449bool FileStream::Unlock() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800450 if (file_ == nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000451 // Stream not open.
nissec80e7412017-01-11 05:56:46 -0800452 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000453 return false;
454 }
455
456 return flock(fileno(file_), LOCK_UN) == 0;
457}
458
459#endif
460
461void FileStream::DoClose() {
462 fclose(file_);
463}
464
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000465///////////////////////////////////////////////////////////////////////////////
466// MemoryStream
467///////////////////////////////////////////////////////////////////////////////
468
469MemoryStreamBase::MemoryStreamBase()
deadbeef37f5ecf2017-02-27 14:06:41 -0800470 : buffer_(nullptr), buffer_length_(0), data_length_(0), seek_position_(0) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000471
472StreamState MemoryStreamBase::GetState() const {
473 return SS_OPEN;
474}
475
476StreamResult MemoryStreamBase::Read(void* buffer, size_t bytes,
477 size_t* bytes_read, int* error) {
478 if (seek_position_ >= data_length_) {
479 return SR_EOS;
480 }
481 size_t available = data_length_ - seek_position_;
482 if (bytes > available) {
483 // Read partial buffer
484 bytes = available;
485 }
486 memcpy(buffer, &buffer_[seek_position_], bytes);
487 seek_position_ += bytes;
488 if (bytes_read) {
489 *bytes_read = bytes;
490 }
491 return SR_SUCCESS;
492}
493
494StreamResult MemoryStreamBase::Write(const void* buffer, size_t bytes,
495 size_t* bytes_written, int* error) {
496 size_t available = buffer_length_ - seek_position_;
497 if (0 == available) {
498 // Increase buffer size to the larger of:
499 // a) new position rounded up to next 256 bytes
500 // b) double the previous length
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000501 size_t new_buffer_length =
502 std::max(((seek_position_ + bytes) | 0xFF) + 1, buffer_length_ * 2);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000503 StreamResult result = DoReserve(new_buffer_length, error);
504 if (SR_SUCCESS != result) {
505 return result;
506 }
nisseede5da42017-01-12 05:15:36 -0800507 RTC_DCHECK(buffer_length_ >= new_buffer_length);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000508 available = buffer_length_ - seek_position_;
509 }
510
511 if (bytes > available) {
512 bytes = available;
513 }
514 memcpy(&buffer_[seek_position_], buffer, bytes);
515 seek_position_ += bytes;
516 if (data_length_ < seek_position_) {
517 data_length_ = seek_position_;
518 }
519 if (bytes_written) {
520 *bytes_written = bytes;
521 }
522 return SR_SUCCESS;
523}
524
525void MemoryStreamBase::Close() {
526 // nothing to do
527}
528
529bool MemoryStreamBase::SetPosition(size_t position) {
530 if (position > data_length_)
531 return false;
532 seek_position_ = position;
533 return true;
534}
535
536bool MemoryStreamBase::GetPosition(size_t* position) const {
537 if (position)
538 *position = seek_position_;
539 return true;
540}
541
542bool MemoryStreamBase::GetSize(size_t* size) const {
543 if (size)
544 *size = data_length_;
545 return true;
546}
547
548bool MemoryStreamBase::GetAvailable(size_t* size) const {
549 if (size)
550 *size = data_length_ - seek_position_;
551 return true;
552}
553
554bool MemoryStreamBase::ReserveSize(size_t size) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800555 return (SR_SUCCESS == DoReserve(size, nullptr));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000556}
557
558StreamResult MemoryStreamBase::DoReserve(size_t size, int* error) {
559 return (buffer_length_ >= size) ? SR_SUCCESS : SR_EOS;
560}
561
562///////////////////////////////////////////////////////////////////////////////
563
deadbeef37f5ecf2017-02-27 14:06:41 -0800564MemoryStream::MemoryStream() : buffer_alloc_(nullptr) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000565
deadbeef37f5ecf2017-02-27 14:06:41 -0800566MemoryStream::MemoryStream(const char* data) : buffer_alloc_(nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000567 SetData(data, strlen(data));
568}
569
570MemoryStream::MemoryStream(const void* data, size_t length)
deadbeef37f5ecf2017-02-27 14:06:41 -0800571 : buffer_alloc_(nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000572 SetData(data, length);
573}
574
575MemoryStream::~MemoryStream() {
576 delete [] buffer_alloc_;
577}
578
579void MemoryStream::SetData(const void* data, size_t length) {
580 data_length_ = buffer_length_ = length;
581 delete [] buffer_alloc_;
582 buffer_alloc_ = new char[buffer_length_ + kAlignment];
583 buffer_ = reinterpret_cast<char*>(ALIGNP(buffer_alloc_, kAlignment));
584 memcpy(buffer_, data, data_length_);
585 seek_position_ = 0;
586}
587
588StreamResult MemoryStream::DoReserve(size_t size, int* error) {
589 if (buffer_length_ >= size)
590 return SR_SUCCESS;
591
592 if (char* new_buffer_alloc = new char[size + kAlignment]) {
593 char* new_buffer = reinterpret_cast<char*>(
594 ALIGNP(new_buffer_alloc, kAlignment));
595 memcpy(new_buffer, buffer_, data_length_);
596 delete [] buffer_alloc_;
597 buffer_alloc_ = new_buffer_alloc;
598 buffer_ = new_buffer;
599 buffer_length_ = size;
600 return SR_SUCCESS;
601 }
602
603 if (error) {
604 *error = ENOMEM;
605 }
606 return SR_ERROR;
607}
608
609///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000610// FifoBuffer
611///////////////////////////////////////////////////////////////////////////////
612
613FifoBuffer::FifoBuffer(size_t size)
614 : state_(SS_OPEN), buffer_(new char[size]), buffer_length_(size),
615 data_length_(0), read_position_(0), owner_(Thread::Current()) {
616 // all events are done on the owner_ thread
617}
618
619FifoBuffer::FifoBuffer(size_t size, Thread* owner)
620 : state_(SS_OPEN), buffer_(new char[size]), buffer_length_(size),
621 data_length_(0), read_position_(0), owner_(owner) {
622 // all events are done on the owner_ thread
623}
624
625FifoBuffer::~FifoBuffer() {
626}
627
628bool FifoBuffer::GetBuffered(size_t* size) const {
629 CritScope cs(&crit_);
630 *size = data_length_;
631 return true;
632}
633
634bool FifoBuffer::SetCapacity(size_t size) {
635 CritScope cs(&crit_);
636 if (data_length_ > size) {
637 return false;
638 }
639
640 if (size != buffer_length_) {
641 char* buffer = new char[size];
642 const size_t copy = data_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000643 const size_t tail_copy = std::min(copy, buffer_length_ - read_position_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000644 memcpy(buffer, &buffer_[read_position_], tail_copy);
645 memcpy(buffer + tail_copy, &buffer_[0], copy - tail_copy);
646 buffer_.reset(buffer);
647 read_position_ = 0;
648 buffer_length_ = size;
649 }
650 return true;
651}
652
653StreamResult FifoBuffer::ReadOffset(void* buffer, size_t bytes,
654 size_t offset, size_t* bytes_read) {
655 CritScope cs(&crit_);
656 return ReadOffsetLocked(buffer, bytes, offset, bytes_read);
657}
658
659StreamResult FifoBuffer::WriteOffset(const void* buffer, size_t bytes,
660 size_t offset, size_t* bytes_written) {
661 CritScope cs(&crit_);
662 return WriteOffsetLocked(buffer, bytes, offset, bytes_written);
663}
664
665StreamState FifoBuffer::GetState() const {
jbauch097d5492016-02-09 02:30:34 -0800666 CritScope cs(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000667 return state_;
668}
669
670StreamResult FifoBuffer::Read(void* buffer, size_t bytes,
671 size_t* bytes_read, int* error) {
672 CritScope cs(&crit_);
673 const bool was_writable = data_length_ < buffer_length_;
674 size_t copy = 0;
675 StreamResult result = ReadOffsetLocked(buffer, bytes, 0, &copy);
676
677 if (result == SR_SUCCESS) {
678 // If read was successful then adjust the read position and number of
679 // bytes buffered.
680 read_position_ = (read_position_ + copy) % buffer_length_;
681 data_length_ -= copy;
682 if (bytes_read) {
683 *bytes_read = copy;
684 }
685
686 // if we were full before, and now we're not, post an event
687 if (!was_writable && copy > 0) {
688 PostEvent(owner_, SE_WRITE, 0);
689 }
690 }
691 return result;
692}
693
694StreamResult FifoBuffer::Write(const void* buffer, size_t bytes,
695 size_t* bytes_written, int* error) {
696 CritScope cs(&crit_);
697
698 const bool was_readable = (data_length_ > 0);
699 size_t copy = 0;
700 StreamResult result = WriteOffsetLocked(buffer, bytes, 0, &copy);
701
702 if (result == SR_SUCCESS) {
703 // If write was successful then adjust the number of readable bytes.
704 data_length_ += copy;
705 if (bytes_written) {
706 *bytes_written = copy;
707 }
708
709 // if we didn't have any data to read before, and now we do, post an event
710 if (!was_readable && copy > 0) {
711 PostEvent(owner_, SE_READ, 0);
712 }
713 }
714 return result;
715}
716
717void FifoBuffer::Close() {
718 CritScope cs(&crit_);
719 state_ = SS_CLOSED;
720}
721
722const void* FifoBuffer::GetReadData(size_t* size) {
723 CritScope cs(&crit_);
724 *size = (read_position_ + data_length_ <= buffer_length_) ?
725 data_length_ : buffer_length_ - read_position_;
726 return &buffer_[read_position_];
727}
728
729void FifoBuffer::ConsumeReadData(size_t size) {
730 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800731 RTC_DCHECK(size <= data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000732 const bool was_writable = data_length_ < buffer_length_;
733 read_position_ = (read_position_ + size) % buffer_length_;
734 data_length_ -= size;
735 if (!was_writable && size > 0) {
736 PostEvent(owner_, SE_WRITE, 0);
737 }
738}
739
740void* FifoBuffer::GetWriteBuffer(size_t* size) {
741 CritScope cs(&crit_);
742 if (state_ == SS_CLOSED) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800743 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000744 }
745
746 // if empty, reset the write position to the beginning, so we can get
747 // the biggest possible block
748 if (data_length_ == 0) {
749 read_position_ = 0;
750 }
751
752 const size_t write_position = (read_position_ + data_length_)
753 % buffer_length_;
754 *size = (write_position > read_position_ || data_length_ == 0) ?
755 buffer_length_ - write_position : read_position_ - write_position;
756 return &buffer_[write_position];
757}
758
759void FifoBuffer::ConsumeWriteBuffer(size_t size) {
760 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800761 RTC_DCHECK(size <= buffer_length_ - data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000762 const bool was_readable = (data_length_ > 0);
763 data_length_ += size;
764 if (!was_readable && size > 0) {
765 PostEvent(owner_, SE_READ, 0);
766 }
767}
768
769bool FifoBuffer::GetWriteRemaining(size_t* size) const {
770 CritScope cs(&crit_);
771 *size = buffer_length_ - data_length_;
772 return true;
773}
774
775StreamResult FifoBuffer::ReadOffsetLocked(void* buffer,
776 size_t bytes,
777 size_t offset,
778 size_t* bytes_read) {
779 if (offset >= data_length_) {
780 return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
781 }
782
783 const size_t available = data_length_ - offset;
784 const size_t read_position = (read_position_ + offset) % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000785 const size_t copy = std::min(bytes, available);
786 const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000787 char* const p = static_cast<char*>(buffer);
788 memcpy(p, &buffer_[read_position], tail_copy);
789 memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
790
791 if (bytes_read) {
792 *bytes_read = copy;
793 }
794 return SR_SUCCESS;
795}
796
797StreamResult FifoBuffer::WriteOffsetLocked(const void* buffer,
798 size_t bytes,
799 size_t offset,
800 size_t* bytes_written) {
801 if (state_ == SS_CLOSED) {
802 return SR_EOS;
803 }
804
805 if (data_length_ + offset >= buffer_length_) {
806 return SR_BLOCK;
807 }
808
809 const size_t available = buffer_length_ - data_length_ - offset;
810 const size_t write_position = (read_position_ + data_length_ + offset)
811 % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000812 const size_t copy = std::min(bytes, available);
813 const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000814 const char* const p = static_cast<const char*>(buffer);
815 memcpy(&buffer_[write_position], p, tail_copy);
816 memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
817
818 if (bytes_written) {
819 *bytes_written = copy;
820 }
821 return SR_SUCCESS;
822}
823
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000824///////////////////////////////////////////////////////////////////////////////
825// StringStream - Reads/Writes to an external std::string
826///////////////////////////////////////////////////////////////////////////////
827
Tommi00aac5a2015-05-25 11:25:59 +0200828StringStream::StringStream(std::string* str)
829 : str_(*str), read_pos_(0), read_only_(false) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000830}
831
832StringStream::StringStream(const std::string& str)
833 : str_(const_cast<std::string&>(str)), read_pos_(0), read_only_(true) {
834}
835
836StreamState StringStream::GetState() const {
837 return SS_OPEN;
838}
839
840StreamResult StringStream::Read(void* buffer, size_t buffer_len,
841 size_t* read, int* error) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000842 size_t available = std::min(buffer_len, str_.size() - read_pos_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000843 if (!available)
844 return SR_EOS;
845 memcpy(buffer, str_.data() + read_pos_, available);
846 read_pos_ += available;
847 if (read)
848 *read = available;
849 return SR_SUCCESS;
850}
851
852StreamResult StringStream::Write(const void* data, size_t data_len,
853 size_t* written, int* error) {
854 if (read_only_) {
855 if (error) {
856 *error = -1;
857 }
858 return SR_ERROR;
859 }
860 str_.append(static_cast<const char*>(data),
861 static_cast<const char*>(data) + data_len);
862 if (written)
863 *written = data_len;
864 return SR_SUCCESS;
865}
866
867void StringStream::Close() {
868}
869
870bool StringStream::SetPosition(size_t position) {
871 if (position > str_.size())
872 return false;
873 read_pos_ = position;
874 return true;
875}
876
877bool StringStream::GetPosition(size_t* position) const {
878 if (position)
879 *position = read_pos_;
880 return true;
881}
882
883bool StringStream::GetSize(size_t* size) const {
884 if (size)
885 *size = str_.size();
886 return true;
887}
888
889bool StringStream::GetAvailable(size_t* size) const {
890 if (size)
891 *size = str_.size() - read_pos_;
892 return true;
893}
894
895bool StringStream::ReserveSize(size_t size) {
896 if (read_only_)
897 return false;
898 str_.reserve(size);
899 return true;
900}
901
902///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000903
904StreamResult Flow(StreamInterface* source,
deadbeef37f5ecf2017-02-27 14:06:41 -0800905 char* buffer,
906 size_t buffer_len,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000907 StreamInterface* sink,
deadbeef37f5ecf2017-02-27 14:06:41 -0800908 size_t* data_len /* = nullptr */) {
nisseede5da42017-01-12 05:15:36 -0800909 RTC_DCHECK(buffer_len > 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000910
911 StreamResult result;
912 size_t count, read_pos, write_pos;
913 if (data_len) {
914 read_pos = *data_len;
915 } else {
916 read_pos = 0;
917 }
918
919 bool end_of_stream = false;
920 do {
921 // Read until buffer is full, end of stream, or error
922 while (!end_of_stream && (read_pos < buffer_len)) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800923 result = source->Read(buffer + read_pos, buffer_len - read_pos, &count,
924 nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000925 if (result == SR_EOS) {
926 end_of_stream = true;
927 } else if (result != SR_SUCCESS) {
928 if (data_len) {
929 *data_len = read_pos;
930 }
931 return result;
932 } else {
933 read_pos += count;
934 }
935 }
936
937 // Write until buffer is empty, or error (including end of stream)
938 write_pos = 0;
939 while (write_pos < read_pos) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800940 result = sink->Write(buffer + write_pos, read_pos - write_pos, &count,
941 nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000942 if (result != SR_SUCCESS) {
943 if (data_len) {
944 *data_len = read_pos - write_pos;
945 if (write_pos > 0) {
946 memmove(buffer, buffer + write_pos, *data_len);
947 }
948 }
949 return result;
950 }
951 write_pos += count;
952 }
953
954 read_pos = 0;
955 } while (!end_of_stream);
956
957 if (data_len) {
958 *data_len = 0;
959 }
960 return SR_SUCCESS;
961}
962
963///////////////////////////////////////////////////////////////////////////////
964
965} // namespace rtc