Shaka Packager SDK
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 
21 namespace shaka {
22 namespace {
23 
24 // A helper filesystem object. This holds the data for the memory files.
25 class 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 
115 MemoryFile::MemoryFile(const std::string& file_name, const std::string& mode)
116  : File(file_name), mode_(mode), file_(NULL), position_(0) {}
117 
118 MemoryFile::~MemoryFile() {}
119 
120 bool MemoryFile::Close() {
121  if (!FileSystem::Instance()->Close(file_name()))
122  return false;
123  delete this;
124  return true;
125 }
126 
127 int64_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 
139 int64_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 
157 void MemoryFile::CloseForWriting() {}
158 
159 int64_t MemoryFile::Size() {
160  DCHECK(file_);
161  return file_->size();
162 }
163 
164 bool MemoryFile::Flush() {
165  return true;
166 }
167 
168 bool 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 
176 bool MemoryFile::Tell(uint64_t* position) {
177  *position = position_;
178  return true;
179 }
180 
181 bool 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 
190 void MemoryFile::DeleteAll() {
191  FileSystem::Instance()->DeleteAll();
192 }
193 
194 void 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.
Definition: crypto_flags.cc:66