Shaka Packager SDK
Loading...
Searching...
No Matches
memory_file.cc
1// Copyright 2015 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/file/memory_file.h>
8
9#include <algorithm>
10#include <cstring> // for memcpy
11#include <map>
12#include <memory>
13#include <set>
14
15#include <absl/log/check.h>
16#include <absl/log/log.h>
17#include <absl/synchronization/mutex.h>
18
19#include <packager/macros/logging.h>
20
21namespace shaka {
22namespace {
23
24// A helper filesystem object. This holds the data for the memory files.
25class FileSystem {
26 public:
27 ~FileSystem() {}
28
29 static FileSystem* Instance() {
30 static FileSystem instance;
31 return &instance;
32 }
33
34 void Delete(const std::string& file_name) {
35 absl::MutexLock auto_lock(&mutex_);
36
37 if (open_files_.find(file_name) != open_files_.end()) {
38 LOG(ERROR) << "File '" << file_name
39 << "' is still open. Deleting an open MemoryFile is not "
40 "allowed. Exit without deleting the file.";
41 return;
42 }
43
44 files_.erase(file_name);
45 }
46
47 void DeleteAll() {
48 absl::MutexLock auto_lock(&mutex_);
49 if (!open_files_.empty()) {
50 LOG(ERROR) << "There are still files open. Deleting an open MemoryFile "
51 "is not allowed. Exit without deleting the file.";
52 return;
53 }
54 files_.clear();
55 }
56
57 std::vector<uint8_t>* Open(const std::string& file_name,
58 const std::string& mode) {
59 absl::MutexLock auto_lock(&mutex_);
60
61 if (open_files_.find(file_name) != open_files_.end()) {
62 NOTIMPLEMENTED() << "File '" << file_name
63 << "' is already open. MemoryFile does not support "
64 "opening the same file before it is closed.";
65 return nullptr;
66 }
67
68 auto iter = files_.find(file_name);
69 if (mode == "r") {
70 if (iter == files_.end())
71 return nullptr;
72 } else if (mode == "w") {
73 if (iter != files_.end())
74 iter->second.clear();
75 } else {
76 NOTIMPLEMENTED() << "File mode '" << mode
77 << "' not supported by MemoryFile";
78 return nullptr;
79 }
80
81 open_files_[file_name] = mode;
82 return &files_[file_name];
83 }
84
85 bool Close(const std::string& file_name) {
86 absl::MutexLock auto_lock(&mutex_);
87
88 auto iter = open_files_.find(file_name);
89 if (iter == open_files_.end()) {
90 LOG(ERROR) << "Cannot close file '" << file_name
91 << "' which is not open.";
92 return false;
93 }
94
95 open_files_.erase(iter);
96 return true;
97 }
98
99 private:
100 FileSystem(const FileSystem&) = delete;
101 FileSystem& operator=(const FileSystem&) = delete;
102
103 FileSystem() = default;
104
105 // Filename to file data map.
106 std::map<std::string, std::vector<uint8_t>> files_ ABSL_GUARDED_BY(mutex_);
107 // Filename to file open modes map.
108 std::map<std::string, std::string> open_files_ ABSL_GUARDED_BY(mutex_);
109
110 absl::Mutex mutex_;
111};
112
113} // namespace
114
115MemoryFile::MemoryFile(const std::string& file_name, const std::string& mode)
116 : File(file_name), mode_(mode), file_(NULL), position_(0) {}
117
118MemoryFile::~MemoryFile() {}
119
120bool MemoryFile::Close() {
121 if (!FileSystem::Instance()->Close(file_name()))
122 return false;
123 delete this;
124 return true;
125}
126
127int64_t MemoryFile::Read(void* buffer, uint64_t length) {
128 const uint64_t size = Size();
129 DCHECK_LE(position_, size);
130 if (position_ >= size)
131 return 0;
132
133 const uint64_t bytes_to_read = std::min(length, size - position_);
134 memcpy(buffer, &(*file_)[position_], bytes_to_read);
135 position_ += bytes_to_read;
136 return bytes_to_read;
137}
138
139int64_t MemoryFile::Write(const void* buffer, uint64_t length) {
140 // If length is zero, we won't resize the buffer and it is possible for
141 // |position| to equal the length of the buffer. This will cause a segfault
142 // when indexing into the buffer for the memcpy.
143 if (length == 0) {
144 return 0;
145 }
146
147 const uint64_t size = Size();
148 if (size < position_ + length) {
149 file_->resize(position_ + length);
150 }
151
152 memcpy(&(*file_)[position_], buffer, length);
153 position_ += length;
154 return length;
155}
156
157void MemoryFile::CloseForWriting() {}
158
159int64_t MemoryFile::Size() {
160 DCHECK(file_);
161 return file_->size();
162}
163
164bool MemoryFile::Flush() {
165 return true;
166}
167
168bool MemoryFile::Seek(uint64_t position) {
169 if (Size() < static_cast<int64_t>(position))
170 return false;
171
172 position_ = position;
173 return true;
174}
175
176bool MemoryFile::Tell(uint64_t* position) {
177 *position = position_;
178 return true;
179}
180
181bool MemoryFile::Open() {
182 file_ = FileSystem::Instance()->Open(file_name(), mode_);
183 if (!file_)
184 return false;
185
186 position_ = 0;
187 return true;
188}
189
190void MemoryFile::DeleteAll() {
191 FileSystem::Instance()->DeleteAll();
192}
193
194void MemoryFile::Delete(const std::string& file_name) {
195 FileSystem::Instance()->Delete(file_name);
196}
197
198} // namespace shaka
All the methods that are virtual are virtual for mocking.