1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_stream/interval_reader.h"
16
17 #include "pw_assert/check.h"
18
19 namespace pw::stream {
20
DoRead(ByteSpan destination)21 StatusWithSize IntervalReader::DoRead(ByteSpan destination) {
22 if (!source_reader_) {
23 return StatusWithSize(Status::FailedPrecondition(), 0);
24 }
25
26 if (!status_.ok()) {
27 return StatusWithSize(status_, 0);
28 }
29
30 if (current_ == end_) {
31 return StatusWithSize::OutOfRange();
32 }
33
34 // Seek the source reader to the `current_` offset of this IntervalReader
35 // before reading.
36 Status status = source_reader_->Seek(current_, Whence::kBeginning);
37 if (!status.ok()) {
38 return StatusWithSize(status, 0);
39 }
40
41 size_t to_read = std::min(destination.size(), end_ - current_);
42 Result<ByteSpan> res = source_reader_->Read(destination.first(to_read));
43 if (!res.ok()) {
44 return StatusWithSize(res.status(), 0);
45 }
46
47 current_ += res.value().size();
48 return StatusWithSize(res.value().size());
49 }
50
DoSeek(ptrdiff_t offset,Whence origin)51 Status IntervalReader::DoSeek(ptrdiff_t offset, Whence origin) {
52 ptrdiff_t absolute_position = std::numeric_limits<ptrdiff_t>::min();
53
54 // Convert from the position within the interval to the position within the
55 // source reader stream.
56 switch (origin) {
57 case Whence::kBeginning:
58 absolute_position = offset + start_;
59 break;
60
61 case Whence::kCurrent:
62 absolute_position = current_ + offset;
63 break;
64
65 case Whence::kEnd:
66 absolute_position = end_ + offset;
67 break;
68 }
69
70 if (absolute_position < 0) {
71 return Status::InvalidArgument();
72 }
73
74 if (static_cast<size_t>(absolute_position) < start_ ||
75 static_cast<size_t>(absolute_position) > end_) {
76 return Status::InvalidArgument();
77 }
78
79 current_ = absolute_position;
80 return OkStatus();
81 }
82
83 } // namespace pw::stream
84