xref: /aosp_15_r20/external/libwebm/webm_parser/src/file_reader.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS.  All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 #include "webm/file_reader.h"
9 
10 #include <cassert>
11 #include <cstdint>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <limits>
15 #include <memory>
16 
17 #include "webm/status.h"
18 
19 #ifdef _MSC_VER
20 #define FSEEK_(stream, offset, whence) _fseeki64(stream, offset, whence)
21 #elif defined(_WIN32)
22 #define FSEEK_(stream, offset, whence) \
23   fseeko64(stream, static_cast<off_t>(offset), whence)
24 #elif _POSIX_C_SOURCE >= 200112L
25 #define FSEEK_(stream, offset, whence) \
26   fseeko(stream, static_cast<off_t>(offset), whence)
27 #else
28 #define FSEEK_(stream, offset, whence) \
29   std::fseek(stream, static_cast<long>(offset), whence)
30 #endif
31 
32 namespace webm {
33 
FileReader(FILE * file)34 FileReader::FileReader(FILE* file) : file_(file) { assert(file); }
35 
FileReader(FileReader && other)36 FileReader::FileReader(FileReader&& other)
37     : file_(std::move(other.file_)), position_(other.position_) {
38   other.position_ = 0;
39 }
40 
operator =(FileReader && other)41 FileReader& FileReader::operator=(FileReader&& other) {
42   if (this != &other) {
43     file_ = std::move(other.file_);
44     position_ = other.position_;
45     other.position_ = 0;
46   }
47   return *this;
48 }
49 
Read(std::size_t num_to_read,std::uint8_t * buffer,std::uint64_t * num_actually_read)50 Status FileReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
51                         std::uint64_t* num_actually_read) {
52   assert(num_to_read > 0);
53   assert(buffer != nullptr);
54   assert(num_actually_read != nullptr);
55 
56   if (file_ == nullptr) {
57     *num_actually_read = 0;
58     return Status(Status::kEndOfFile);
59   }
60 
61   std::size_t actual =
62       std::fread(static_cast<void*>(buffer), 1, num_to_read, file_.get());
63   *num_actually_read = static_cast<std::uint64_t>(actual);
64   position_ += *num_actually_read;
65 
66   if (actual == 0) {
67     return Status(Status::kEndOfFile);
68   }
69 
70   if (actual == num_to_read) {
71     return Status(Status::kOkCompleted);
72   } else {
73     return Status(Status::kOkPartial);
74   }
75 }
76 
Skip(std::uint64_t num_to_skip,std::uint64_t * num_actually_skipped)77 Status FileReader::Skip(std::uint64_t num_to_skip,
78                         std::uint64_t* num_actually_skipped) {
79   assert(num_to_skip > 0);
80   assert(num_actually_skipped != nullptr);
81 
82   *num_actually_skipped = 0;
83 
84   if (file_ == nullptr) {
85     return Status(Status::kEndOfFile);
86   }
87 
88   // Try seeking forward first.
89   long seek_offset = std::numeric_limits<long>::max();  // NOLINT
90   if (num_to_skip < static_cast<unsigned long>(seek_offset)) {  // NOLINT
91     seek_offset = static_cast<long>(num_to_skip);  // NOLINT
92   }
93   if (!FSEEK_(file_.get(), seek_offset, SEEK_CUR)) {
94     *num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
95     position_ += static_cast<std::uint64_t>(seek_offset);
96     if (static_cast<unsigned long>(seek_offset) == num_to_skip) {  // NOLINT
97       return Status(Status::kOkCompleted);
98     } else {
99       return Status(Status::kOkPartial);
100     }
101   }
102   std::clearerr(file_.get());
103 
104   // Seeking doesn't work on things like pipes, so if seeking failed then fall
105   // back to reading the data into a junk buffer.
106   std::size_t actual = 0;
107   do {
108     std::uint8_t junk[1024];
109     std::size_t num_to_read = sizeof(junk);
110     if (num_to_skip < num_to_read) {
111       num_to_read = static_cast<std::size_t>(num_to_skip);
112     }
113 
114     std::size_t actual =
115         std::fread(static_cast<void*>(junk), 1, num_to_read, file_.get());
116     *num_actually_skipped += static_cast<std::uint64_t>(actual);
117     position_ += static_cast<std::uint64_t>(actual);
118     num_to_skip -= static_cast<std::uint64_t>(actual);
119   } while (actual > 0 && num_to_skip > 0);
120 
121   if (*num_actually_skipped == 0) {
122     return Status(Status::kEndOfFile);
123   }
124 
125   if (num_to_skip == 0) {
126     return Status(Status::kOkCompleted);
127   } else {
128     return Status(Status::kOkPartial);
129   }
130 }
131 
Seek(std::uint64_t seek_position)132 Status FileReader::Seek(std::uint64_t seek_position) {
133   if (FSEEK_(file_.get(), seek_position, SEEK_SET)) {
134     return Status(Status::kSeekFailed);
135   }
136   position_ = seek_position;
137   return Status(Status::kOkCompleted);
138 }
139 
Position() const140 std::uint64_t FileReader::Position() const { return position_; }
141 
142 }  // namespace webm
143