1 // Copyright 2021 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/std_file_stream.h"
16
17 #include "pw_assert/check.h"
18
19 namespace pw::stream {
20 namespace {
21
WhenceToSeekDir(Stream::Whence whence)22 std::ios::seekdir WhenceToSeekDir(Stream::Whence whence) {
23 switch (whence) {
24 case Stream::Whence::kBeginning:
25 return std::ios::beg;
26 case Stream::Whence::kCurrent:
27 return std::ios::cur;
28 case Stream::Whence::kEnd:
29 return std::ios::end;
30 }
31 PW_CRASH("Unknown value for enum Stream::Whence");
32 }
33
34 } // namespace
35
DoRead(ByteSpan dest)36 StatusWithSize StdFileReader::DoRead(ByteSpan dest) {
37 stream_.peek(); // Peek to set EOF if at the end of the file.
38 if (stream_.eof()) {
39 return StatusWithSize::OutOfRange();
40 }
41
42 stream_.read(reinterpret_cast<char*>(dest.data()), dest.size());
43 if (stream_.bad()) {
44 return StatusWithSize::Unknown();
45 }
46
47 return StatusWithSize(stream_.gcount());
48 }
49
DoSeek(ptrdiff_t offset,Whence origin)50 Status StdFileReader::DoSeek(ptrdiff_t offset, Whence origin) {
51 // Explicitly clear EOF bit if needed.
52 if (stream_.eof()) {
53 stream_.clear();
54 }
55 if (!stream_.seekg(offset, WhenceToSeekDir(origin))) {
56 return Status::Unknown();
57 }
58 return OkStatus();
59 }
60
DoTell()61 size_t StdFileReader::DoTell() {
62 auto pos = static_cast<int>(stream_.tellg());
63 return pos < 0 ? kUnknownPosition : pos;
64 }
65
ConservativeLimit(LimitType limit) const66 size_t StdFileReader::ConservativeLimit(LimitType limit) const {
67 if (limit == LimitType::kWrite) {
68 return 0;
69 }
70
71 // Attempt to determine the number of bytes left in the file by seeking
72 // to the end and checking where we end up.
73 if (stream_.eof()) {
74 return 0;
75 }
76 auto stream = const_cast<std::ifstream*>(&this->stream_);
77 auto start = stream->tellg();
78 if (start == -1) {
79 return 0;
80 }
81 stream->seekg(0, std::ios::end);
82 auto end = stream->tellg();
83 if (end == -1) {
84 return 0;
85 }
86 stream->seekg(start, std::ios::beg);
87 return end - start;
88 }
89
DoWrite(ConstByteSpan data)90 Status StdFileWriter::DoWrite(ConstByteSpan data) {
91 if (stream_.eof()) {
92 return Status::OutOfRange();
93 }
94
95 if (stream_.write(reinterpret_cast<const char*>(data.data()), data.size())) {
96 return OkStatus();
97 }
98
99 return Status::Unknown();
100 }
101
DoSeek(ptrdiff_t offset,Whence origin)102 Status StdFileWriter::DoSeek(ptrdiff_t offset, Whence origin) {
103 if (!stream_.seekp(offset, WhenceToSeekDir(origin))) {
104 return Status::Unknown();
105 }
106 return OkStatus();
107 }
108
DoTell()109 size_t StdFileWriter::DoTell() {
110 auto pos = static_cast<int>(stream_.tellp());
111 return pos < 0 ? kUnknownPosition : pos;
112 }
113
114 } // namespace pw::stream
115