1*103e46e4SHarish Mahendrakar // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include "webm/istream_reader.h"
9*103e46e4SHarish Mahendrakar
10*103e46e4SHarish Mahendrakar #include <cassert>
11*103e46e4SHarish Mahendrakar #include <cstdint>
12*103e46e4SHarish Mahendrakar #include <cstdio>
13*103e46e4SHarish Mahendrakar #include <cstdlib>
14*103e46e4SHarish Mahendrakar #include <limits>
15*103e46e4SHarish Mahendrakar #include <memory>
16*103e46e4SHarish Mahendrakar
17*103e46e4SHarish Mahendrakar #include "webm/status.h"
18*103e46e4SHarish Mahendrakar
19*103e46e4SHarish Mahendrakar namespace webm {
20*103e46e4SHarish Mahendrakar
IstreamReader(IstreamReader && other)21*103e46e4SHarish Mahendrakar IstreamReader::IstreamReader(IstreamReader&& other)
22*103e46e4SHarish Mahendrakar : istream_(std::move(other.istream_)), position_(other.position_) {
23*103e46e4SHarish Mahendrakar other.position_ = 0;
24*103e46e4SHarish Mahendrakar }
25*103e46e4SHarish Mahendrakar
operator =(IstreamReader && other)26*103e46e4SHarish Mahendrakar IstreamReader& IstreamReader::operator=(IstreamReader&& other) {
27*103e46e4SHarish Mahendrakar if (this != &other) {
28*103e46e4SHarish Mahendrakar istream_ = std::move(other.istream_);
29*103e46e4SHarish Mahendrakar position_ = other.position_;
30*103e46e4SHarish Mahendrakar other.position_ = 0;
31*103e46e4SHarish Mahendrakar }
32*103e46e4SHarish Mahendrakar return *this;
33*103e46e4SHarish Mahendrakar }
34*103e46e4SHarish Mahendrakar
Read(std::size_t num_to_read,std::uint8_t * buffer,std::uint64_t * num_actually_read)35*103e46e4SHarish Mahendrakar Status IstreamReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
36*103e46e4SHarish Mahendrakar std::uint64_t* num_actually_read) {
37*103e46e4SHarish Mahendrakar assert(num_to_read > 0);
38*103e46e4SHarish Mahendrakar assert(buffer != nullptr);
39*103e46e4SHarish Mahendrakar assert(num_actually_read != nullptr);
40*103e46e4SHarish Mahendrakar
41*103e46e4SHarish Mahendrakar if (istream_ == nullptr) {
42*103e46e4SHarish Mahendrakar *num_actually_read = 0;
43*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
44*103e46e4SHarish Mahendrakar }
45*103e46e4SHarish Mahendrakar
46*103e46e4SHarish Mahendrakar using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
47*103e46e4SHarish Mahendrakar constexpr std::streamsize streamsize_max =
48*103e46e4SHarish Mahendrakar std::numeric_limits<std::streamsize>::max();
49*103e46e4SHarish Mahendrakar std::streamsize limited_num_to_read;
50*103e46e4SHarish Mahendrakar if (num_to_read > static_cast<unsigned_streamsize>(streamsize_max)) {
51*103e46e4SHarish Mahendrakar limited_num_to_read = streamsize_max;
52*103e46e4SHarish Mahendrakar } else {
53*103e46e4SHarish Mahendrakar limited_num_to_read = static_cast<std::streamsize>(num_to_read);
54*103e46e4SHarish Mahendrakar }
55*103e46e4SHarish Mahendrakar
56*103e46e4SHarish Mahendrakar istream_->read(reinterpret_cast<char*>(buffer), limited_num_to_read);
57*103e46e4SHarish Mahendrakar std::streamsize actual = istream_->gcount();
58*103e46e4SHarish Mahendrakar *num_actually_read = static_cast<std::uint64_t>(actual);
59*103e46e4SHarish Mahendrakar position_ += *num_actually_read;
60*103e46e4SHarish Mahendrakar
61*103e46e4SHarish Mahendrakar if (actual == 0) {
62*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
63*103e46e4SHarish Mahendrakar }
64*103e46e4SHarish Mahendrakar
65*103e46e4SHarish Mahendrakar if (static_cast<std::size_t>(actual) == num_to_read) {
66*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
67*103e46e4SHarish Mahendrakar } else {
68*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
69*103e46e4SHarish Mahendrakar }
70*103e46e4SHarish Mahendrakar }
71*103e46e4SHarish Mahendrakar
Skip(std::uint64_t num_to_skip,std::uint64_t * num_actually_skipped)72*103e46e4SHarish Mahendrakar Status IstreamReader::Skip(std::uint64_t num_to_skip,
73*103e46e4SHarish Mahendrakar std::uint64_t* num_actually_skipped) {
74*103e46e4SHarish Mahendrakar assert(num_to_skip > 0);
75*103e46e4SHarish Mahendrakar assert(num_actually_skipped != nullptr);
76*103e46e4SHarish Mahendrakar
77*103e46e4SHarish Mahendrakar *num_actually_skipped = 0;
78*103e46e4SHarish Mahendrakar if (istream_ == nullptr || !istream_->good()) {
79*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
80*103e46e4SHarish Mahendrakar }
81*103e46e4SHarish Mahendrakar
82*103e46e4SHarish Mahendrakar // Try seeking forward first.
83*103e46e4SHarish Mahendrakar using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
84*103e46e4SHarish Mahendrakar constexpr std::streamsize streamsize_max =
85*103e46e4SHarish Mahendrakar std::numeric_limits<std::streamsize>::max();
86*103e46e4SHarish Mahendrakar std::streamsize seek_offset;
87*103e46e4SHarish Mahendrakar if (num_to_skip > static_cast<unsigned_streamsize>(streamsize_max)) {
88*103e46e4SHarish Mahendrakar seek_offset = streamsize_max;
89*103e46e4SHarish Mahendrakar } else {
90*103e46e4SHarish Mahendrakar seek_offset = static_cast<std::streamsize>(num_to_skip);
91*103e46e4SHarish Mahendrakar }
92*103e46e4SHarish Mahendrakar if (istream_->seekg(seek_offset, std::ios_base::cur)) {
93*103e46e4SHarish Mahendrakar *num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
94*103e46e4SHarish Mahendrakar position_ += static_cast<std::uint64_t>(seek_offset);
95*103e46e4SHarish Mahendrakar if (static_cast<std::uint64_t>(seek_offset) == num_to_skip) {
96*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
97*103e46e4SHarish Mahendrakar } else {
98*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
99*103e46e4SHarish Mahendrakar }
100*103e46e4SHarish Mahendrakar }
101*103e46e4SHarish Mahendrakar istream_->clear();
102*103e46e4SHarish Mahendrakar
103*103e46e4SHarish Mahendrakar // Seeking doesn't work on things like pipes, so if seeking failed then fall
104*103e46e4SHarish Mahendrakar // back to reading the data into a junk buffer.
105*103e46e4SHarish Mahendrakar std::size_t actual = 0;
106*103e46e4SHarish Mahendrakar do {
107*103e46e4SHarish Mahendrakar char junk[1024];
108*103e46e4SHarish Mahendrakar std::streamsize num_to_read = static_cast<std::streamsize>(sizeof(junk));
109*103e46e4SHarish Mahendrakar if (num_to_skip < static_cast<std::uint64_t>(num_to_read)) {
110*103e46e4SHarish Mahendrakar num_to_read = static_cast<std::streamsize>(num_to_skip);
111*103e46e4SHarish Mahendrakar }
112*103e46e4SHarish Mahendrakar
113*103e46e4SHarish Mahendrakar istream_->read(junk, num_to_read);
114*103e46e4SHarish Mahendrakar std::streamsize actual = istream_->gcount();
115*103e46e4SHarish Mahendrakar *num_actually_skipped += static_cast<std::uint64_t>(actual);
116*103e46e4SHarish Mahendrakar position_ += static_cast<std::uint64_t>(actual);
117*103e46e4SHarish Mahendrakar num_to_skip -= static_cast<std::uint64_t>(actual);
118*103e46e4SHarish Mahendrakar } while (actual > 0 && num_to_skip > 0);
119*103e46e4SHarish Mahendrakar
120*103e46e4SHarish Mahendrakar if (*num_actually_skipped == 0) {
121*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
122*103e46e4SHarish Mahendrakar }
123*103e46e4SHarish Mahendrakar
124*103e46e4SHarish Mahendrakar if (num_to_skip == 0) {
125*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
126*103e46e4SHarish Mahendrakar } else {
127*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
128*103e46e4SHarish Mahendrakar }
129*103e46e4SHarish Mahendrakar }
130*103e46e4SHarish Mahendrakar
Position() const131*103e46e4SHarish Mahendrakar std::uint64_t IstreamReader::Position() const { return position_; }
132*103e46e4SHarish Mahendrakar
133*103e46e4SHarish Mahendrakar } // namespace webm
134