| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Os/File.cpp | ||
| 3 | // \brief common function implementation for Os::File | ||
| 4 | // ====================================================================== | ||
| 5 | #include <Fw/Types/Assert.hpp> | ||
| 6 | #include <Fw/Types/StringUtils.hpp> | ||
| 7 | #include <Os/File.hpp> | ||
| 8 | #include <algorithm> | ||
| 9 | #include <config/FppConstantsAc.hpp> | ||
| 10 | |||
| 11 | namespace Os { | ||
| 12 | |||
| 13 |
6/6✓ Branch 14 taken 46511 times.
✓ Branch 20 taken 23813632 times.
✓ Branch 21 taken 46511 times.
✓ Branch 27 taken 744176 times.
✓ Branch 28 taken 46511 times.
✓ Branch 34 taken 46511 times.
|
24604319 | File::File() : m_crc_buffer(), m_handle_storage(), m_delegate(*FileInterface::getDelegate(m_handle_storage)) { |
| 14 | 46511 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 15 | 46511 | } | |
| 16 | |||
| 17 | 186758 | File::~File() { | |
| 18 | 93378 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 19 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 46689 times.
✓ Branch 5 taken 9261 times.
✓ Branch 6 taken 37428 times.
|
93378 | if (this->m_mode != OPEN_NO_MODE) { |
| 20 | 18522 | this->close(); | |
| 21 | } | ||
| 22 | 93378 | m_delegate.~FileInterface(); | |
| 23 | 93380 | } | |
| 24 | |||
| 25 | 261 | File::File(const File& other) | |
| 26 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 261 times.
|
261 | : m_mode(other.m_mode), |
| 27 | 261 | m_hash(other.m_hash), | |
| 28 |
2/2✓ Branch 4 taken 133632 times.
✓ Branch 5 taken 261 times.
|
133893 | m_crc_buffer(), |
| 29 |
2/2✓ Branch 4 taken 4176 times.
✓ Branch 5 taken 261 times.
|
4437 | m_handle_storage(), |
| 30 |
1/1✓ Branch 14 taken 261 times.
|
522 | m_delegate(*FileInterface::getDelegate(m_handle_storage, &other.m_delegate)) { |
| 31 | 261 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 32 | 261 | } | |
| 33 | |||
| 34 | 95 | File& File::operator=(const File& other) { | |
| 35 |
1/2✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
|
95 | if (this != &other) { |
| 36 | // The delegate below is constructed over the storage of the existing one. Any file this | ||
| 37 | // object currently holds must be closed first or its handle is orphaned permanently. | ||
| 38 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 95 times.
✓ Branch 5 taken 79 times.
✓ Branch 6 taken 16 times.
|
95 | if (this->m_mode != OPEN_NO_MODE) { |
| 39 | 79 | this->close(); | |
| 40 | } | ||
| 41 | 95 | this->m_delegate.~FileInterface(); | |
| 42 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 95 times.
|
95 | this->m_mode = other.m_mode; |
| 43 | 95 | this->m_hash = other.m_hash; | |
| 44 | 95 | (void)FileInterface::getDelegate(m_handle_storage, &other.m_delegate); | |
| 45 | 95 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 46 | } | ||
| 47 | 95 | return *this; | |
| 48 | } | ||
| 49 | |||
| 50 | 29133 | File::Status File::open(const CHAR* filepath, File::Mode requested_mode) { | |
| 51 | 29133 | return this->open(filepath, requested_mode, OverwriteType::NO_OVERWRITE); | |
| 52 | } | ||
| 53 | |||
| 54 | 32708 | File::Status File::open(const CHAR* filepath, File::Mode requested_mode, File::OverwriteType overwrite) { | |
| 55 | 32708 | FW_ASSERT(nullptr != filepath); | |
| 56 | 32708 | return this->open(filepath, static_cast<FwSizeType>(FileNameStringSize + 1), requested_mode, overwrite); | |
| 57 | } | ||
| 58 | |||
| 59 | ✗ | File::Status File::open(const CHAR* filepath, FwSizeType length, File::Mode requested_mode) { | |
| 60 | ✗ | return this->open(filepath, length, requested_mode, OverwriteType::NO_OVERWRITE); | |
| 61 | } | ||
| 62 | |||
| 63 | 32737 | File::Status File::open(const CHAR* filepath, | |
| 64 | FwSizeType length, | ||
| 65 | File::Mode requested_mode, | ||
| 66 | File::OverwriteType overwrite) { | ||
| 67 | 32737 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 68 | 32737 | FW_ASSERT(nullptr != filepath); | |
| 69 | 32737 | const FwSizeType string_len = static_cast<FwSizeType>(Fw::StringUtils::string_length(filepath, length)); | |
| 70 | 32737 | FW_ASSERT(string_len < length, static_cast<FwAssertArgType>(string_len), static_cast<FwAssertArgType>(length)); | |
| 71 | 32737 | FW_ASSERT(File::Mode::OPEN_NO_MODE < requested_mode && File::Mode::MAX_OPEN_MODE > requested_mode); | |
| 72 | 32737 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 73 | 32737 | FW_ASSERT((0 <= overwrite) && (overwrite < OverwriteType::MAX_OVERWRITE_TYPE)); | |
| 74 | // Check for already opened file | ||
| 75 |
2/2✓ Branch 4 taken 72 times.
✓ Branch 5 taken 32665 times.
|
32737 | if (this->isOpen()) { |
| 76 | 72 | return File::Status::INVALID_MODE; | |
| 77 | } | ||
| 78 | 32665 | File::Status status = this->m_delegate.open(filepath, requested_mode, overwrite); | |
| 79 |
2/2✓ Branch 0 taken 23410 times.
✓ Branch 1 taken 9255 times.
|
32665 | if (status == File::Status::OP_OK) { |
| 80 | 23410 | this->m_mode = requested_mode; | |
| 81 | // Reset any open CRC calculations | ||
| 82 | 23410 | this->m_hash.init(); | |
| 83 | } | ||
| 84 | |||
| 85 | 32665 | return status; | |
| 86 | } | ||
| 87 | |||
| 88 | ✗ | File::Status File::open(const Fw::ConstStringBase& path, File::Mode requested_mode) { | |
| 89 | ✗ | return this->open(path.toChar(), static_cast<FwSizeType>(path.getCapacity()), requested_mode, | |
| 90 | ✗ | OverwriteType::NO_OVERWRITE); | |
| 91 | } | ||
| 92 | |||
| 93 | 14 | File::Status File::open(const Fw::ConstStringBase& path, File::Mode requested_mode, File::OverwriteType overwrite) { | |
| 94 | 14 | return this->open(path.toChar(), static_cast<FwSizeType>(path.getCapacity()), requested_mode, overwrite); | |
| 95 | } | ||
| 96 | |||
| 97 | 23665 | void File::close() { | |
| 98 | 23665 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 99 | 23665 | FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE); | |
| 100 | 23665 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 101 | 23665 | this->m_delegate.close(); | |
| 102 | 23665 | this->m_mode = Mode::OPEN_NO_MODE; | |
| 103 | 23665 | } | |
| 104 | |||
| 105 | 48254 | bool File::isOpen() const { | |
| 106 | 48254 | FW_ASSERT(&this->m_delegate == reinterpret_cast<const FileInterface*>(&this->m_handle_storage[0])); | |
| 107 | 48254 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 108 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 48254 times.
|
48254 | return this->m_mode != Mode::OPEN_NO_MODE; |
| 109 | } | ||
| 110 | |||
| 111 | 10990 | File::Status File::size(FwSizeType& size_result) { | |
| 112 | 10990 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 113 | 10990 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 114 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 10990 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10990 times.
|
10990 | if (OPEN_NO_MODE == this->m_mode) { |
| 115 | ✗ | return File::Status::NOT_OPENED; | |
| 116 | } | ||
| 117 | 10990 | return this->m_delegate.size(size_result); | |
| 118 | } | ||
| 119 | |||
| 120 | 5013 | File::Status File::position(FwSizeType& position_result) { | |
| 121 | 5013 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 122 | 5013 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 123 | // Check that the file is open before attempting operation | ||
| 124 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 5013 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 5004 times.
|
5013 | if (OPEN_NO_MODE == this->m_mode) { |
| 125 | 9 | return File::Status::NOT_OPENED; | |
| 126 | } | ||
| 127 | 5004 | return this->m_delegate.position(position_result); | |
| 128 | } | ||
| 129 | |||
| 130 | 74 | File::Status File::preallocate(FwSizeType offset, FwSizeType length) { | |
| 131 | 74 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 132 | 74 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 133 | // Check that the file is open before attempting operation | ||
| 134 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 74 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 55 times.
|
74 | if (OPEN_NO_MODE == this->m_mode) { |
| 135 | 19 | return File::Status::NOT_OPENED; | |
| 136 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 55 times.
|
55 | } else if (OPEN_READ == this->m_mode) { |
| 137 | ✗ | return File::Status::INVALID_MODE; | |
| 138 | } | ||
| 139 | 55 | return this->m_delegate.preallocate(offset, length); | |
| 140 | } | ||
| 141 | |||
| 142 | 275 | File::Status File::seek(FwSignedSizeType offset, File::SeekType seekType) { | |
| 143 | 275 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 144 | 275 | FW_ASSERT((0 <= seekType) && (seekType < SeekType::MAX_SEEK_TYPE)); | |
| 145 | // Cannot do a seek with a negative offset in absolute mode | ||
| 146 | 275 | FW_ASSERT((seekType == File::SeekType::RELATIVE) || (offset >= 0)); | |
| 147 | 275 | FW_ASSERT((0 <= this->m_mode) && (this->m_mode < Mode::MAX_OPEN_MODE)); | |
| 148 | // Check that the file is open before attempting operation | ||
| 149 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 275 times.
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 258 times.
|
275 | if (OPEN_NO_MODE == this->m_mode) { |
| 150 | 17 | return File::Status::NOT_OPENED; | |
| 151 | } | ||
| 152 | 258 | return this->m_delegate.seek(offset, seekType); | |
| 153 | } | ||
| 154 | |||
| 155 | 42 | File::Status File::seek_absolute(FwSizeType offset) { | |
| 156 | 42 | Os::File::Status status = File::Status::OTHER_ERROR; | |
| 157 | // If the offset can be represented by a signed value, then we can perform a single seek | ||
| 158 |
1/2✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
|
42 | if (static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()) >= offset) { |
| 159 | // Check that the bounding above is correct | ||
| 160 | 42 | FW_ASSERT(static_cast<FwSignedSizeType>(offset) >= 0); | |
| 161 | 42 | status = this->seek(static_cast<FwSignedSizeType>(offset), File::SeekType::ABSOLUTE); | |
| 162 | } | ||
| 163 | // Otherwise, a full seek to any value represented by FwSizeType can be performed | ||
| 164 | // by at most 3 seeks of a FwSignedSizeType. Two half seeks (rounded down) that are | ||
| 165 | // strictly bounded by std::numeric_limits<FwSignedSizeType>::max() and one seek of | ||
| 166 | // a possibile "odd" byte to ensure odds offsets do not introduce an off-by-one-error. | ||
| 167 | // Thus we perform 3 seeks to guarantee that we can reach any position. | ||
| 168 | else { | ||
| 169 | ✗ | FwSignedSizeType half_offset = static_cast<FwSignedSizeType>(offset >> 1); | |
| 170 | ✗ | bool is_odd = (offset % 2) == 1; | |
| 171 | ✗ | status = this->seek(half_offset, File::SeekType::ABSOLUTE); | |
| 172 | ✗ | if (status == File::Status::OP_OK) { | |
| 173 | ✗ | status = this->seek(half_offset, File::SeekType::RELATIVE); | |
| 174 | } | ||
| 175 | ✗ | if (status == File::Status::OP_OK) { | |
| 176 | ✗ | status = this->seek((is_odd) ? 1 : 0, File::SeekType::RELATIVE); | |
| 177 | } | ||
| 178 | } | ||
| 179 | 42 | return status; | |
| 180 | } | ||
| 181 | |||
| 182 | 88 | File::Status File::flush() { | |
| 183 | 88 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 184 | 88 | FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE); | |
| 185 | // Check that the file is open before attempting operation | ||
| 186 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 73 times.
|
88 | if (OPEN_NO_MODE == this->m_mode) { |
| 187 | 15 | return File::Status::NOT_OPENED; | |
| 188 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 71 times.
|
73 | } else if (OPEN_READ == this->m_mode) { |
| 189 | 2 | return File::Status::INVALID_MODE; | |
| 190 | } | ||
| 191 | 71 | return this->m_delegate.flush(); | |
| 192 | } | ||
| 193 | |||
| 194 | 8990 | File::Status File::read(U8* buffer, FwSizeType& size) { | |
| 195 | 8990 | return this->read(buffer, size, WaitType::WAIT); | |
| 196 | } | ||
| 197 | |||
| 198 | 254397 | File::Status File::read(U8* buffer, FwSizeType& size, File::WaitType wait) { | |
| 199 | 254397 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 200 | 254397 | FW_ASSERT(buffer != nullptr); | |
| 201 | 254397 | FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE); | |
| 202 | // Check that the file is open before attempting operation | ||
| 203 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 254397 times.
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 254380 times.
|
254397 | if (OPEN_NO_MODE == this->m_mode) { |
| 204 | 17 | size = 0; | |
| 205 | 17 | return File::Status::NOT_OPENED; | |
| 206 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 254380 times.
✓ Branch 5 taken 78 times.
✓ Branch 6 taken 254302 times.
|
254380 | } else if (OPEN_READ != this->m_mode) { |
| 207 | 78 | size = 0; | |
| 208 | 78 | return File::Status::INVALID_MODE; | |
| 209 | } | ||
| 210 | 254302 | return this->m_delegate.read(buffer, size, wait); | |
| 211 | } | ||
| 212 | |||
| 213 | 7933 | File::Status File::write(const U8* buffer, FwSizeType& size) { | |
| 214 | 7933 | return this->write(buffer, size, WaitType::WAIT); | |
| 215 | } | ||
| 216 | |||
| 217 | 8892 | File::Status File::write(const U8* buffer, FwSizeType& size, File::WaitType wait) { | |
| 218 | 8892 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 219 | 8892 | FW_ASSERT(buffer != nullptr); | |
| 220 | 8892 | FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE); | |
| 221 | // Check that the file is open before attempting operation | ||
| 222 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 8892 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 8865 times.
|
8892 | if (OPEN_NO_MODE == this->m_mode) { |
| 223 | 27 | size = 0; | |
| 224 | 27 | return File::Status::NOT_OPENED; | |
| 225 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 8865 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 8862 times.
|
8865 | } else if (OPEN_READ == this->m_mode) { |
| 226 | 3 | size = 0; | |
| 227 | 3 | return File::Status::INVALID_MODE; | |
| 228 | } | ||
| 229 | 8862 | return this->m_delegate.write(buffer, size, wait); | |
| 230 | } | ||
| 231 | |||
| 232 | 2 | FileHandle* File::getHandle() { | |
| 233 | 2 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 234 | 2 | return this->m_delegate.getHandle(); | |
| 235 | } | ||
| 236 | |||
| 237 | 125 | File::Status File::calculateCrc(U32& crc) { | |
| 238 | 125 | File::Status status = File::Status::OP_OK; | |
| 239 | 125 | FwSizeType size = FW_FILE_CHUNK_SIZE; | |
| 240 | 125 | crc = 0; | |
| 241 |
1/2✓ Branch 1 taken 130 times.
✗ Branch 2 not taken.
|
130 | for (FwSizeType i = 0; i < std::numeric_limits<FwSizeType>::max(); i++) { |
| 242 |
1/1✓ Branch 4 taken 130 times.
|
130 | status = this->incrementalCrc(size); |
| 243 | // Break on eof or error | ||
| 244 |
4/4✓ Branch 0 taken 104 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 99 times.
|
130 | if ((size != FW_FILE_CHUNK_SIZE) || (status != File::OP_OK)) { |
| 245 | break; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | // When successful, finalize the CRC | ||
| 249 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 101 times.
|
125 | if (status == File::OP_OK) { |
| 250 |
1/1✓ Branch 4 taken 24 times.
|
24 | status = this->finalizeCrc(crc); |
| 251 | } | ||
| 252 | 125 | return status; | |
| 253 | } | ||
| 254 | |||
| 255 | 227 | File::Status File::incrementalCrc(FwSizeType& size) { | |
| 256 | 227 | File::Status status = File::Status::OP_OK; | |
| 257 | 227 | FW_ASSERT(size <= FW_FILE_CHUNK_SIZE, FwAssertArgType(size)); | |
| 258 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 227 times.
✓ Branch 5 taken 38 times.
✓ Branch 6 taken 189 times.
|
227 | if (OPEN_NO_MODE == this->m_mode) { |
| 259 | 38 | status = File::Status::NOT_OPENED; | |
| 260 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 189 times.
✓ Branch 5 taken 155 times.
✓ Branch 6 taken 34 times.
|
189 | } else if (OPEN_READ != this->m_mode) { |
| 261 | 155 | status = File::Status::INVALID_MODE; | |
| 262 | } else { | ||
| 263 | // Read data without waiting for additional data to be available | ||
| 264 | 34 | status = this->read(this->m_crc_buffer, size, File::WaitType::NO_WAIT); | |
| 265 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
|
34 | if (OP_OK == status) { |
| 266 | 32 | FW_ASSERT(size <= FW_FILE_CHUNK_SIZE, FwAssertArgType(size)); | |
| 267 | 32 | this->m_hash.update(this->m_crc_buffer, size); | |
| 268 | } | ||
| 269 | } | ||
| 270 | 227 | return status; | |
| 271 | } | ||
| 272 | |||
| 273 | 94 | File::Status File::finalizeCrc(U32& crc) { | |
| 274 | 94 | File::Status status = File::Status::OP_OK; | |
| 275 | 94 | this->m_hash.finalize(crc); | |
| 276 | // Historically, the CRC calculation in File omitted the final 1's complement step. Utils::Hash performs that step | ||
| 277 | // and as such, we must undo it before returning the value to ensure backwards compatibility. | ||
| 278 | 94 | crc = ~crc; | |
| 279 | 94 | this->m_hash.init(); | |
| 280 | 94 | return status; | |
| 281 | } | ||
| 282 | |||
| 283 | 42 | File::Status File::readline(U8* buffer, FwSizeType& size, File::WaitType wait) { | |
| 284 | 42 | const FwSizeType requested_size = size; | |
| 285 | 42 | FW_ASSERT(&this->m_delegate == reinterpret_cast<FileInterface*>(&this->m_handle_storage[0])); | |
| 286 | 42 | FW_ASSERT(buffer != nullptr); | |
| 287 | 42 | FW_ASSERT(this->m_mode < Mode::MAX_OPEN_MODE); | |
| 288 | // Check that the file is open before attempting operation | ||
| 289 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
|
42 | if (OPEN_NO_MODE == this->m_mode) { |
| 290 | ✗ | size = 0; | |
| 291 | ✗ | return File::Status::NOT_OPENED; | |
| 292 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
|
42 | } else if (OPEN_READ != this->m_mode) { |
| 293 | ✗ | size = 0; | |
| 294 | ✗ | return File::Status::INVALID_MODE; | |
| 295 | } | ||
| 296 | 42 | FwSizeType original_location = 0; | |
| 297 |
1/1✓ Branch 4 taken 42 times.
|
42 | File::Status status = this->position(original_location); |
| 298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (status != Os::File::Status::OP_OK) { |
| 299 | ✗ | size = 0; | |
| 300 | ✗ | (void)this->seek_absolute(original_location); | |
| 301 | ✗ | return status; | |
| 302 | } | ||
| 303 | 42 | FwSizeType read = 0; | |
| 304 | // Loop reading chunk by chunk | ||
| 305 |
1/2✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
|
42 | for (FwSizeType i = 0; i < size; i += read) { |
| 306 | // read in chunks to avoid large buffer allocations | ||
| 307 | 42 | FwSizeType current_chunk_size = std::min(size - i, static_cast<FwSizeType>(FW_FILE_CHUNK_SIZE)); | |
| 308 | 42 | read = current_chunk_size; | |
| 309 |
1/1✓ Branch 5 taken 42 times.
|
42 | status = this->read(buffer + i, read, wait); |
| 310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (status != File::Status::OP_OK) { |
| 311 | // Contract: on error, seek back to the original location | ||
| 312 | ✗ | size = 0; | |
| 313 | ✗ | (void)this->seek_absolute(original_location); | |
| 314 | ✗ | return status; | |
| 315 | } | ||
| 316 | // EOF break out now | ||
| 317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (read == 0) { |
| 318 | ✗ | size = i; | |
| 319 | ✗ | return Os::File::Status::OP_OK; | |
| 320 | } | ||
| 321 | // Loop from i to i + current_chunk_size looking for `\n` | ||
| 322 | 42 | const FwSizeType chunk_end = i + read; | |
| 323 |
1/2✓ Branch 0 taken 1757 times.
✗ Branch 1 not taken.
|
1757 | for (FwSizeType j = i; j < chunk_end; j++) { |
| 324 | // Newline seek back to after it, return the size read | ||
| 325 |
2/2✓ Branch 2 taken 42 times.
✓ Branch 3 taken 1715 times.
|
1757 | if (buffer[j] == '\n') { |
| 326 | 42 | size = j + 1; | |
| 327 | // Ensure that the computation worked and there is not overflow | ||
| 328 | 42 | FW_ASSERT(size <= requested_size); | |
| 329 | 42 | FW_ASSERT(std::numeric_limits<FwSizeType>::max() - size >= original_location); | |
| 330 |
1/1✓ Branch 4 taken 42 times.
|
42 | (void)this->seek_absolute(original_location + j + 1); |
| 331 | 42 | return Os::File::Status::OP_OK; | |
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | // Failed to find newline within data available | ||
| 336 | // Contract: on error, seek back to the original location | ||
| 337 | ✗ | size = 0; | |
| 338 | ✗ | (void)this->seek_absolute(original_location); | |
| 339 | ✗ | return Os::File::Status::OTHER_ERROR; | |
| 340 | } | ||
| 341 | } // namespace Os | ||
| 342 |