Symphony Of Empires
io.cpp
Go to the documentation of this file.
1 // Eng3D - General purpouse game engine
2 // Copyright (C) 2021, Eng3D contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // io.cpp
20 //
21 // Abstract:
22 // Generalized "IO" functions for more abstract access to the OS resources
23 // along with a custom "std::filesystem" implementation to aid and
24 // implement custom paths.
25 // ----------------------------------------------------------------------------
26 
27 #include <filesystem>
28 #include "eng3d/io.hpp"
29 #include "eng3d/state.hpp"
30 #include "eng3d/utils.hpp"
31 #include "eng3d/log.hpp"
32 
39  return abs_path;
40 }
41 
42 //
43 // Asset::File
44 //
46  this->fp = std::fopen(abs_path.c_str(), "rb");
47  if(fp == nullptr)
48  CXX_THROW(std::runtime_error, Eng3D::translate_format("Can't open file %s", path.c_str()));
49 }
50 
52  std::fclose(this->fp);
53  this->fp = nullptr;
54 }
55 
56 void Eng3D::IO::Asset::File::read(void* buf, size_t n) {
57  std::fread(buf, 1, n, this->fp);
58 }
59 
60 void Eng3D::IO::Asset::File::write(const void* buf, size_t n) {
61  std::fwrite(buf, 1, n, this->fp);
62 }
63 
64 void Eng3D::IO::Asset::File::seek(SeekType type, int offset) {
65  if(type == SeekType::CURRENT) {
66  std::fseek(this->fp, offset, SEEK_CUR);
67  } else if(type == SeekType::START) {
68  std::fseek(this->fp, offset, SEEK_SET);
69  } else if(type == SeekType::END) {
70  std::fseek(this->fp, offset, SEEK_END);
71  }
72 }
73 
75  FILE* cfp = const_cast<FILE*>(this->fp);
76  fpos_t pos;
77  std::fgetpos(cfp, &pos); // Save
78  std::fseek(cfp, 0, SEEK_END); // Go to the end
79  long size = ::ftell(cfp); // Get size
80  std::fsetpos(cfp, &pos); // Reset
81  return static_cast<size_t>(size);
82 }
83 
84 //
85 // Package manager
86 //
87 void Eng3D::IO::PackageManager::recursive_filesystem_walk(Eng3D::IO::Package& package, const std::string& root, const std::string& current) {
88  // Register paths into our virtual filesystem
89  for(const auto& entry : std::filesystem::recursive_directory_iterator(current)) {
90  if(entry.is_directory()) continue;
91  auto asset = std::make_shared<Eng3D::IO::Asset::File>();
92  asset->path = entry.path().lexically_relative(root).string();
93  asset->abs_path = entry.path().string();
94 #ifdef E3D_TARGET_WINDOWS
95  std::replace(asset->path.begin(), asset->path.end(), '\\', '/');
96  std::replace(asset->abs_path.begin(), asset->abs_path.end(), '\\', '/');
97 #endif
98  package.assets.push_back(asset);
99  }
100 }
101 
102 static inline std::string get_full_path() {
103 #ifndef E3D_TARGET_SWITCH
104 # ifdef NO_COPY_MODS
105  return "../mods/";
106 # else
107  return "./mods/";
108 # endif
109 #else
110  return "romfs:/";
111 #endif
112 }
113 
114 //
115 // PackageManager
116 //
117 Eng3D::IO::PackageManager::PackageManager(Eng3D::State& _s, const std::vector<std::string>& pkg_paths)
118  : s{ _s }
119 {
120  if(pkg_paths.empty()) {
121  const std::string asset_path = get_full_path();
122  // All folders inside mods/
123  for(const auto& entry : std::filesystem::directory_iterator(asset_path)) {
124  if(!entry.is_directory()) continue;
125  Eng3D::IO::Package package{};
126  package.name = entry.path().lexically_relative(asset_path).string(); // Relative (for nicer names)
127  package.abs_path = entry.path().string(); // Absolute
128  recursive_filesystem_walk(package, entry.path().string(), entry.path().string());
129  this->packages.push_back(package);
130  }
131  } else {
132  // Manually specified paths (can be outside mods/)
133  for(const auto& entry : pkg_paths) {
134  Eng3D::IO::Package package{};
135  package.name = entry;
136  package.abs_path = entry;
137  recursive_filesystem_walk(package, entry, entry);
138  this->packages.push_back(package);
139  }
140  }
141 }
142 
146 std::shared_ptr<Eng3D::IO::Asset::Base> Eng3D::IO::PackageManager::get_unique(const Eng3D::IO::Path& path) {
147  std::vector<std::shared_ptr<Eng3D::IO::Asset::Base>> list = this->get_multiple(path);
148  if(list.empty())
149  return std::shared_ptr<Eng3D::IO::Asset::Base>(nullptr);
150  return list.at(0);
151 }
152 
157 std::vector<std::shared_ptr<Eng3D::IO::Asset::Base>> Eng3D::IO::PackageManager::get_multiple(const Eng3D::IO::Path& path) {
158  std::vector<std::shared_ptr<Eng3D::IO::Asset::Base>> list;
159  for(const auto& package : this->packages)
160  for(const auto& asset : package.assets)
161  if(asset->path == path.str)
162  list.push_back(asset);
163  return list;
164 }
165 
169 std::vector<std::shared_ptr<Eng3D::IO::Asset::Base>> Eng3D::IO::PackageManager::get_multiple_prefix(const Eng3D::IO::Path& prefix) {
170  std::vector<std::shared_ptr<Eng3D::IO::Asset::Base>> list;
171  for(const auto& package : this->packages)
172  for(const auto& asset : package.assets)
173  if(asset->path.substr(0, prefix.str.length()) == prefix.str)
174  list.push_back(asset);
175  return list;
176 }
177 
181 std::vector<std::string> Eng3D::IO::PackageManager::get_paths(void) const {
182  std::vector<std::string> paths;
183  for(const auto& package : this->packages)
184  paths.push_back(package.abs_path);
185  return paths;
186 }
std::vector< std::shared_ptr< Eng3D::IO::Asset::Base > > get_multiple(const Eng3D::IO::Path &path)
Obtains multiple assets iff they share a common path (useful for concating files that might clash,...
Definition: io.cpp:157
void recursive_filesystem_walk(Eng3D::IO::Package &package, const std::string &root, const std::string &current)
Definition: io.cpp:87
std::vector< Package > packages
Definition: io.hpp:144
std::vector< std::shared_ptr< Eng3D::IO::Asset::Base > > get_multiple_prefix(const Eng3D::IO::Path &path)
Obtains all assets starting with a given prefix.
Definition: io.cpp:169
std::vector< std::string > get_paths(void) const
Obtain all the paths that are currently under the management of a package, that is return the absolut...
Definition: io.cpp:181
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Definition: io.cpp:146
SeekType
Definition: io.hpp:70
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
std::string abs_path
Definition: io.hpp:87
std::string get_abs_path() const
Get the abs path object in a safe manner, such as that the access does not occur on null pointers....
Definition: io.cpp:38
virtual void write(const void *buf, size_t n)
Definition: io.cpp:60
virtual void seek(Eng3D::IO::SeekType type, int offset)
Definition: io.cpp:64
virtual void read(void *buf, size_t n)
Definition: io.cpp:56
virtual void open()
Definition: io.cpp:45
virtual size_t get_size(void) const
Definition: io.cpp:74
virtual void close()
Definition: io.cpp:51
A package containing a set of assets.
Definition: io.hpp:124
std::string name
Definition: io.hpp:125
std::vector< std::shared_ptr< Eng3D::IO::Asset::Base > > assets
Definition: io.hpp:127
The path class abstracts away most of the burden from handling system-dependant filesystem paths.
Definition: io.hpp:44
std::string str
Definition: io.hpp:59
#define CXX_THROW(class,...)
Definition: utils.hpp:98