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/file_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 #ifdef _MSC_VER
20*103e46e4SHarish Mahendrakar #define FSEEK_(stream, offset, whence) _fseeki64(stream, offset, whence)
21*103e46e4SHarish Mahendrakar #elif defined(_WIN32)
22*103e46e4SHarish Mahendrakar #define FSEEK_(stream, offset, whence) \
23*103e46e4SHarish Mahendrakar fseeko64(stream, static_cast<off_t>(offset), whence)
24*103e46e4SHarish Mahendrakar #elif _POSIX_C_SOURCE >= 200112L
25*103e46e4SHarish Mahendrakar #define FSEEK_(stream, offset, whence) \
26*103e46e4SHarish Mahendrakar fseeko(stream, static_cast<off_t>(offset), whence)
27*103e46e4SHarish Mahendrakar #else
28*103e46e4SHarish Mahendrakar #define FSEEK_(stream, offset, whence) \
29*103e46e4SHarish Mahendrakar std::fseek(stream, static_cast<long>(offset), whence)
30*103e46e4SHarish Mahendrakar #endif
31*103e46e4SHarish Mahendrakar
32*103e46e4SHarish Mahendrakar namespace webm {
33*103e46e4SHarish Mahendrakar
FileReader(FILE * file)34*103e46e4SHarish Mahendrakar FileReader::FileReader(FILE* file) : file_(file) { assert(file); }
35*103e46e4SHarish Mahendrakar
FileReader(FileReader && other)36*103e46e4SHarish Mahendrakar FileReader::FileReader(FileReader&& other)
37*103e46e4SHarish Mahendrakar : file_(std::move(other.file_)), position_(other.position_) {
38*103e46e4SHarish Mahendrakar other.position_ = 0;
39*103e46e4SHarish Mahendrakar }
40*103e46e4SHarish Mahendrakar
operator =(FileReader && other)41*103e46e4SHarish Mahendrakar FileReader& FileReader::operator=(FileReader&& other) {
42*103e46e4SHarish Mahendrakar if (this != &other) {
43*103e46e4SHarish Mahendrakar file_ = std::move(other.file_);
44*103e46e4SHarish Mahendrakar position_ = other.position_;
45*103e46e4SHarish Mahendrakar other.position_ = 0;
46*103e46e4SHarish Mahendrakar }
47*103e46e4SHarish Mahendrakar return *this;
48*103e46e4SHarish Mahendrakar }
49*103e46e4SHarish Mahendrakar
Read(std::size_t num_to_read,std::uint8_t * buffer,std::uint64_t * num_actually_read)50*103e46e4SHarish Mahendrakar Status FileReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
51*103e46e4SHarish Mahendrakar std::uint64_t* num_actually_read) {
52*103e46e4SHarish Mahendrakar assert(num_to_read > 0);
53*103e46e4SHarish Mahendrakar assert(buffer != nullptr);
54*103e46e4SHarish Mahendrakar assert(num_actually_read != nullptr);
55*103e46e4SHarish Mahendrakar
56*103e46e4SHarish Mahendrakar if (file_ == nullptr) {
57*103e46e4SHarish Mahendrakar *num_actually_read = 0;
58*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
59*103e46e4SHarish Mahendrakar }
60*103e46e4SHarish Mahendrakar
61*103e46e4SHarish Mahendrakar std::size_t actual =
62*103e46e4SHarish Mahendrakar std::fread(static_cast<void*>(buffer), 1, num_to_read, file_.get());
63*103e46e4SHarish Mahendrakar *num_actually_read = static_cast<std::uint64_t>(actual);
64*103e46e4SHarish Mahendrakar position_ += *num_actually_read;
65*103e46e4SHarish Mahendrakar
66*103e46e4SHarish Mahendrakar if (actual == 0) {
67*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
68*103e46e4SHarish Mahendrakar }
69*103e46e4SHarish Mahendrakar
70*103e46e4SHarish Mahendrakar if (actual == num_to_read) {
71*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
72*103e46e4SHarish Mahendrakar } else {
73*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
74*103e46e4SHarish Mahendrakar }
75*103e46e4SHarish Mahendrakar }
76*103e46e4SHarish Mahendrakar
Skip(std::uint64_t num_to_skip,std::uint64_t * num_actually_skipped)77*103e46e4SHarish Mahendrakar Status FileReader::Skip(std::uint64_t num_to_skip,
78*103e46e4SHarish Mahendrakar std::uint64_t* num_actually_skipped) {
79*103e46e4SHarish Mahendrakar assert(num_to_skip > 0);
80*103e46e4SHarish Mahendrakar assert(num_actually_skipped != nullptr);
81*103e46e4SHarish Mahendrakar
82*103e46e4SHarish Mahendrakar *num_actually_skipped = 0;
83*103e46e4SHarish Mahendrakar
84*103e46e4SHarish Mahendrakar if (file_ == nullptr) {
85*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
86*103e46e4SHarish Mahendrakar }
87*103e46e4SHarish Mahendrakar
88*103e46e4SHarish Mahendrakar // Try seeking forward first.
89*103e46e4SHarish Mahendrakar long seek_offset = std::numeric_limits<long>::max(); // NOLINT
90*103e46e4SHarish Mahendrakar if (num_to_skip < static_cast<unsigned long>(seek_offset)) { // NOLINT
91*103e46e4SHarish Mahendrakar seek_offset = static_cast<long>(num_to_skip); // NOLINT
92*103e46e4SHarish Mahendrakar }
93*103e46e4SHarish Mahendrakar if (!FSEEK_(file_.get(), seek_offset, SEEK_CUR)) {
94*103e46e4SHarish Mahendrakar *num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
95*103e46e4SHarish Mahendrakar position_ += static_cast<std::uint64_t>(seek_offset);
96*103e46e4SHarish Mahendrakar if (static_cast<unsigned long>(seek_offset) == num_to_skip) { // NOLINT
97*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
98*103e46e4SHarish Mahendrakar } else {
99*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
100*103e46e4SHarish Mahendrakar }
101*103e46e4SHarish Mahendrakar }
102*103e46e4SHarish Mahendrakar std::clearerr(file_.get());
103*103e46e4SHarish Mahendrakar
104*103e46e4SHarish Mahendrakar // Seeking doesn't work on things like pipes, so if seeking failed then fall
105*103e46e4SHarish Mahendrakar // back to reading the data into a junk buffer.
106*103e46e4SHarish Mahendrakar std::size_t actual = 0;
107*103e46e4SHarish Mahendrakar do {
108*103e46e4SHarish Mahendrakar std::uint8_t junk[1024];
109*103e46e4SHarish Mahendrakar std::size_t num_to_read = sizeof(junk);
110*103e46e4SHarish Mahendrakar if (num_to_skip < num_to_read) {
111*103e46e4SHarish Mahendrakar num_to_read = static_cast<std::size_t>(num_to_skip);
112*103e46e4SHarish Mahendrakar }
113*103e46e4SHarish Mahendrakar
114*103e46e4SHarish Mahendrakar std::size_t actual =
115*103e46e4SHarish Mahendrakar std::fread(static_cast<void*>(junk), 1, num_to_read, file_.get());
116*103e46e4SHarish Mahendrakar *num_actually_skipped += static_cast<std::uint64_t>(actual);
117*103e46e4SHarish Mahendrakar position_ += static_cast<std::uint64_t>(actual);
118*103e46e4SHarish Mahendrakar num_to_skip -= static_cast<std::uint64_t>(actual);
119*103e46e4SHarish Mahendrakar } while (actual > 0 && num_to_skip > 0);
120*103e46e4SHarish Mahendrakar
121*103e46e4SHarish Mahendrakar if (*num_actually_skipped == 0) {
122*103e46e4SHarish Mahendrakar return Status(Status::kEndOfFile);
123*103e46e4SHarish Mahendrakar }
124*103e46e4SHarish Mahendrakar
125*103e46e4SHarish Mahendrakar if (num_to_skip == 0) {
126*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
127*103e46e4SHarish Mahendrakar } else {
128*103e46e4SHarish Mahendrakar return Status(Status::kOkPartial);
129*103e46e4SHarish Mahendrakar }
130*103e46e4SHarish Mahendrakar }
131*103e46e4SHarish Mahendrakar
Seek(std::uint64_t seek_position)132*103e46e4SHarish Mahendrakar Status FileReader::Seek(std::uint64_t seek_position) {
133*103e46e4SHarish Mahendrakar if (FSEEK_(file_.get(), seek_position, SEEK_SET)) {
134*103e46e4SHarish Mahendrakar return Status(Status::kSeekFailed);
135*103e46e4SHarish Mahendrakar }
136*103e46e4SHarish Mahendrakar position_ = seek_position;
137*103e46e4SHarish Mahendrakar return Status(Status::kOkCompleted);
138*103e46e4SHarish Mahendrakar }
139*103e46e4SHarish Mahendrakar
Position() const140*103e46e4SHarish Mahendrakar std::uint64_t FileReader::Position() const { return position_; }
141*103e46e4SHarish Mahendrakar
142*103e46e4SHarish Mahendrakar } // namespace webm
143