#include #include #include #include namespace frostbite2D { Asset &Asset::get() { static Asset instance; return instance; } fs::path Asset::toPath(const std::string &path) const { #ifdef _WIN32 return fs::u8path(path); #else return fs::path(path); #endif } std::string Asset::fromPath(const fs::path &path) const { #ifdef _WIN32 return path.u8string(); #else return path.string(); #endif } std::string Asset::resolveFullPath(const std::string &path) const { if (path.empty()) { return path; } fs::path p = toPath(path); if (p.is_absolute()) { return path; } if (!workingDirectory_.empty()) { return fromPath(toPath(workingDirectory_) / p); } return path; } bool Asset::readTextFile(const std::string &path, std::string &outContent) { std::string fullPath = resolveFullPath(path); if (!exists(fullPath)) { return false; } std::ifstream file(toPath(fullPath), std::ios::in | std::ios::binary); if (!file.is_open()) { return false; } std::ostringstream ss; ss << file.rdbuf(); outContent = ss.str(); file.close(); return true; } bool Asset::writeTextFile(const std::string &path, const std::string &content, bool append) { std::string fullPath = resolveFullPath(path); auto mode = std::ios::out; if (append) { mode |= std::ios::app; } std::ofstream file(toPath(fullPath), mode); if (!file.is_open()) { return false; } file << content; file.close(); return true; } bool Asset::readBinaryFile(const std::string &path, std::vector &outData) { std::string fullPath = resolveFullPath(path); if (!exists(fullPath)) { return false; } std::ifstream file(toPath(fullPath), std::ios::in | std::ios::binary); if (!file.is_open()) { return false; } file.seekg(0, std::ios::end); auto size = file.tellg(); file.seekg(0, std::ios::beg); outData.resize(static_cast(size)); file.read(reinterpret_cast(outData.data()), size); file.close(); return true; } bool Asset::writeBinaryFile(const std::string &path, const std::vector &data, bool append) { std::string fullPath = resolveFullPath(path); auto mode = std::ios::out | std::ios::binary; if (append) { mode |= std::ios::app; } std::ofstream file(toPath(fullPath), mode); if (!file.is_open()) { return false; } file.write(reinterpret_cast(data.data()), data.size()); file.close(); return true; } bool Asset::exists(const std::string &path) const { std::error_code ec; return fs::exists(toPath(resolveFullPath(path)), ec); } bool Asset::isDirectory(const std::string &path) const { std::error_code ec; return fs::is_directory(toPath(resolveFullPath(path)), ec); } bool Asset::isRegularFile(const std::string &path) const { std::error_code ec; return fs::is_regular_file(toPath(resolveFullPath(path)), ec); } bool Asset::createDirectory(const std::string &path) { std::error_code ec; return fs::create_directory(toPath(resolveFullPath(path)), ec); } bool Asset::createDirectories(const std::string &path) { std::error_code ec; return fs::create_directories(toPath(resolveFullPath(path)), ec); } bool Asset::removeFile(const std::string &path) { std::error_code ec; return fs::remove(toPath(resolveFullPath(path)), ec); } bool Asset::removeDirectory(const std::string &path) { std::error_code ec; return fs::remove_all(toPath(resolveFullPath(path)), ec) > 0; } bool Asset::copyFile(const std::string &from, const std::string &to, bool overwrite) { std::error_code ec; auto options = overwrite ? fs::copy_options::overwrite_existing : fs::copy_options::none; return fs::copy_file(toPath(resolveFullPath(from)), toPath(resolveFullPath(to)), options, ec); } bool Asset::moveFile(const std::string &from, const std::string &to) { std::error_code ec; fs::rename(toPath(resolveFullPath(from)), toPath(resolveFullPath(to)), ec); return !ec; } bool Asset::rename(const std::string &oldPath, const std::string &newPath) { std::error_code ec; fs::rename(toPath(resolveFullPath(oldPath)), toPath(resolveFullPath(newPath)), ec); return !ec; } std::vector Asset::listFiles(const std::string &directoryPath, bool recursive) { std::vector files; fs::path fullPath = toPath(resolveFullPath(directoryPath)); std::error_code ec; if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { return files; } try { if (recursive) { for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { if (entry.is_regular_file()) { files.push_back(fromPath(entry.path())); } } } else { for (const auto &entry : fs::directory_iterator(fullPath, ec)) { if (entry.is_regular_file()) { files.push_back(fromPath(entry.path())); } } } } catch (...) { } return files; } std::vector Asset::listDirectories(const std::string &directoryPath, bool recursive) { std::vector directories; fs::path fullPath = toPath(resolveFullPath(directoryPath)); std::error_code ec; if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { return directories; } try { if (recursive) { for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { if (entry.is_directory()) { directories.push_back(fromPath(entry.path())); } } } else { for (const auto &entry : fs::directory_iterator(fullPath, ec)) { if (entry.is_directory()) { directories.push_back(fromPath(entry.path())); } } } } catch (...) { } return directories; } std::vector Asset::listAll(const std::string &directoryPath, bool recursive) { std::vector items; fs::path fullPath = toPath(resolveFullPath(directoryPath)); std::error_code ec; if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { return items; } try { if (recursive) { for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { items.push_back(fromPath(entry.path())); } } else { for (const auto &entry : fs::directory_iterator(fullPath, ec)) { items.push_back(fromPath(entry.path())); } } } catch (...) { } return items; } std::vector Asset::listFilesWithExtension(const std::string &directoryPath, const std::string &extension, bool recursive) { std::vector files; fs::path fullPath = toPath(resolveFullPath(directoryPath)); fs::path ext = toPath(extension); std::error_code ec; if (!fs::exists(fullPath, ec) || !fs::is_directory(fullPath, ec)) { return files; } try { if (recursive) { for (const auto &entry : fs::recursive_directory_iterator(fullPath, ec)) { if (entry.is_regular_file() && entry.path().extension() == ext) { files.push_back(fromPath(entry.path())); } } } else { for (const auto &entry : fs::directory_iterator(fullPath, ec)) { if (entry.is_regular_file() && entry.path().extension() == ext) { files.push_back(fromPath(entry.path())); } } } } catch (...) { } return files; } FileInfo Asset::getFileInfo(const std::string &path) { FileInfo info; std::string fullPath = resolveFullPath(path); info.fullPath = fullPath; if (!exists(fullPath)) { info.exists = false; return info; } info.exists = true; info.isDirectory = isDirectory(fullPath); info.isRegularFile = isRegularFile(fullPath); fs::path p = toPath(fullPath); info.name = fromPath(p.filename()); info.extension = fromPath(p.extension()); if (info.isRegularFile) { std::error_code ec; info.size = fs::file_size(p, ec); if (ec) { info.size = 0; } } return info; } std::string Asset::getFileName(const std::string &path) const { return fromPath(toPath(path).filename()); } std::string Asset::getFileNameWithoutExtension(const std::string &path) const { return fromPath(toPath(path).stem()); } std::string Asset::getExtension(const std::string &path) const { return fromPath(toPath(path).extension()); } std::string Asset::getParentPath(const std::string &path) const { return fromPath(toPath(path).parent_path()); } std::string Asset::getAbsolutePath(const std::string &path) const { std::error_code ec; return fromPath(fs::absolute(toPath(resolveFullPath(path)), ec)); } std::string Asset::getCanonicalPath(const std::string &path) const { std::error_code ec; return fromPath(fs::canonical(toPath(resolveFullPath(path)), ec)); } std::string Asset::getCurrentPath() const { std::error_code ec; return fromPath(fs::current_path(ec)); } bool Asset::setCurrentPath(const std::string &path) { std::error_code ec; fs::current_path(toPath(path), ec); return !ec; } std::string Asset::combinePath(const std::string &left, const std::string &right) const { return fromPath(toPath(left) / toPath(right)); } std::string Asset::normalizePath(const std::string &path) const { std::error_code ec; auto p = fs::absolute(toPath(resolveFullPath(path)), ec); if (ec) { return path; } return fromPath(p.make_preferred()); } uint64 Asset::getFileSize(const std::string &path) const { std::error_code ec; auto size = fs::file_size(toPath(resolveFullPath(path)), ec); if (ec) { return 0; } return size; } bool Asset::isEmpty(const std::string &path) const { std::error_code ec; return fs::is_empty(toPath(resolveFullPath(path)), ec); } std::optional Asset::readFileToString(const std::string &path) { std::string content; if (readTextFile(path, content)) { return content; } return std::nullopt; } std::optional> Asset::readFileToBytes(const std::string &path) { std::vector data; if (readBinaryFile(path, data)) { return data; } return std::nullopt; } void Asset::setWorkingDirectory(const std::string &path) { workingDirectory_ = path; } const std::string &Asset::getWorkingDirectory() const { return workingDirectory_; } std::string Asset::resolvePath(const std::string &relativePath) const { return resolveFullPath(relativePath); } void Asset::setAssetRoot(const std::string &root) { assetRoot_ = root; } const std::string &Asset::getAssetRoot() const { return assetRoot_; } std::string Asset::resolveAssetPath(const std::string &relativePath) const { if (assetRoot_.empty()) { return resolveFullPath(relativePath); } return resolveFullPath(combinePath(assetRoot_, relativePath)); } } // namespace frostbite2D