134 lines
4.1 KiB
C++
134 lines
4.1 KiB
C++
// 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 <cassert>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <limits>
|
|
#include <memory>
|
|
|
|
#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<std::streamsize>::type;
|
|
constexpr std::streamsize streamsize_max =
|
|
std::numeric_limits<std::streamsize>::max();
|
|
std::streamsize limited_num_to_read;
|
|
if (num_to_read > static_cast<unsigned_streamsize>(streamsize_max)) {
|
|
limited_num_to_read = streamsize_max;
|
|
} else {
|
|
limited_num_to_read = static_cast<std::streamsize>(num_to_read);
|
|
}
|
|
|
|
istream_->read(reinterpret_cast<char*>(buffer), limited_num_to_read);
|
|
std::streamsize actual = istream_->gcount();
|
|
*num_actually_read = static_cast<std::uint64_t>(actual);
|
|
position_ += *num_actually_read;
|
|
|
|
if (actual == 0) {
|
|
return Status(Status::kEndOfFile);
|
|
}
|
|
|
|
if (static_cast<std::size_t>(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<std::streamsize>::type;
|
|
constexpr std::streamsize streamsize_max =
|
|
std::numeric_limits<std::streamsize>::max();
|
|
std::streamsize seek_offset;
|
|
if (num_to_skip > static_cast<unsigned_streamsize>(streamsize_max)) {
|
|
seek_offset = streamsize_max;
|
|
} else {
|
|
seek_offset = static_cast<std::streamsize>(num_to_skip);
|
|
}
|
|
if (istream_->seekg(seek_offset, std::ios_base::cur)) {
|
|
*num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
|
|
position_ += static_cast<std::uint64_t>(seek_offset);
|
|
if (static_cast<std::uint64_t>(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<std::streamsize>(sizeof(junk));
|
|
if (num_to_skip < static_cast<std::uint64_t>(num_to_read)) {
|
|
num_to_read = static_cast<std::streamsize>(num_to_skip);
|
|
}
|
|
|
|
istream_->read(junk, num_to_read);
|
|
std::streamsize actual = istream_->gcount();
|
|
*num_actually_skipped += static_cast<std::uint64_t>(actual);
|
|
position_ += static_cast<std::uint64_t>(actual);
|
|
num_to_skip -= static_cast<std::uint64_t>(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
|