// Copyright (c) 2016 The WebM 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 "webm/istream_reader.h" #include #include #include #include #include #include #include "webm/status.h" namespace webm { IstreamReader::IstreamReader(IstreamReader&& other) : istream_(std::move(other.istream_)), position_(other.position_) { other.position_ = 0; } IstreamReader& IstreamReader::operator=(IstreamReader&& other) { if (this != &other) { istream_ = std::move(other.istream_); position_ = other.position_; other.position_ = 0; } return *this; } Status IstreamReader::Read(std::size_t num_to_read, std::uint8_t* buffer, std::uint64_t* num_actually_read) { assert(num_to_read > 0); assert(buffer != nullptr); assert(num_actually_read != nullptr); if (istream_ == nullptr) { *num_actually_read = 0; return Status(Status::kEndOfFile); } using unsigned_streamsize = std::make_unsigned::type; constexpr std::streamsize streamsize_max = std::numeric_limits::max(); std::streamsize limited_num_to_read; if (num_to_read > static_cast(streamsize_max)) { limited_num_to_read = streamsize_max; } else { limited_num_to_read = static_cast(num_to_read); } istream_->read(reinterpret_cast(buffer), limited_num_to_read); std::streamsize actual = istream_->gcount(); *num_actually_read = static_cast(actual); position_ += *num_actually_read; if (actual == 0) { return Status(Status::kEndOfFile); } if (static_cast(actual) == num_to_read) { return Status(Status::kOkCompleted); } else { return Status(Status::kOkPartial); } } Status IstreamReader::Skip(std::uint64_t num_to_skip, std::uint64_t* num_actually_skipped) { assert(num_to_skip > 0); assert(num_actually_skipped != nullptr); *num_actually_skipped = 0; if (istream_ == nullptr || !istream_->good()) { return Status(Status::kEndOfFile); } // Try seeking forward first. using unsigned_streamsize = std::make_unsigned::type; constexpr std::streamsize streamsize_max = std::numeric_limits::max(); std::streamsize seek_offset; if (num_to_skip > static_cast(streamsize_max)) { seek_offset = streamsize_max; } else { seek_offset = static_cast(num_to_skip); } if (istream_->seekg(seek_offset, std::ios_base::cur)) { *num_actually_skipped = static_cast(seek_offset); position_ += static_cast(seek_offset); if (static_cast(seek_offset) == num_to_skip) { return Status(Status::kOkCompleted); } else { return Status(Status::kOkPartial); } } istream_->clear(); // Seeking doesn't work on things like pipes, so if seeking failed then fall // back to reading the data into a junk buffer. std::size_t actual = 0; do { char junk[1024]; std::streamsize num_to_read = static_cast(sizeof(junk)); if (num_to_skip < static_cast(num_to_read)) { num_to_read = static_cast(num_to_skip); } istream_->read(junk, num_to_read); std::streamsize actual = istream_->gcount(); *num_actually_skipped += static_cast(actual); position_ += static_cast(actual); num_to_skip -= static_cast(actual); } while (actual > 0 && num_to_skip > 0); if (*num_actually_skipped == 0) { return Status(Status::kEndOfFile); } if (num_to_skip == 0) { return Status(Status::kOkCompleted); } else { return Status(Status::kOkPartial); } } std::uint64_t IstreamReader::Position() const { return position_; } } // namespace webm