implemented all the Path and File methods

This commit is contained in:
faraphel 2024-08-23 17:04:03 +02:00
parent 64c247ba6f
commit 03a9833d21
19 changed files with 431 additions and 503 deletions

View file

@ -33,6 +33,10 @@ add_executable(Atlas-Launcher
source/script/module/filesystem/_load.hpp source/script/module/filesystem/_load.hpp
source/script/module/filesystem/Path.cpp source/script/module/filesystem/Path.cpp
source/script/module/filesystem/Path.hpp source/script/module/filesystem/Path.hpp
source/script/module/filesystem/File.cpp
source/script/module/filesystem/File.hpp
source/utils/file/openMode.cpp
source/utils/file/openMode.hpp
) )
target_include_directories(Atlas-Launcher PRIVATE target_include_directories(Atlas-Launcher PRIVATE
# AngelScript # AngelScript

View file

@ -1,49 +0,0 @@
#include "AtlasJsModule.hpp"
#include "debug/DebugJsModule.hpp"
#include "file_system/FsJsModule.hpp"
#include "image/ImageJsModule.hpp"
AtlasJsModule::AtlasJsModule(AtlasJsEngine* engine, QObject* parent) : QObject(parent) {
// set the engine
this->engine = engine;
// load the submodules
this->submodules[QStringLiteral("debug")] = std::make_shared<DebugJsModule>(this->engine);
this->submodules[QStringLiteral("fs")] = std::make_shared<FsJsModule>(this->engine);
// this->submodules[QStringLiteral("image")] = std::make_shared<ImageJsModule>(this->engine);
// TODO(Faraphel): check if the filesystem is correctly restricted
}
QJSValue AtlasJsModule::require(const QString& name) const {
std::shared_ptr<BaseJsModule> submodule;
try {
// get the submodule from its name
submodule = this->submodules.at(name);
} catch (const std::out_of_range&) {
// if not found, throw a Javascript error and return null
this->engine->throwError(
QJSValue::ReferenceError,
QStringLiteral("the module \"") + name + QStringLiteral("\" does not exist.")
);
return QJSValue(QJSPrimitiveNull());
}
// return the module as a new javascript object
return this->engine->newQObject(submodule.get());
}
QJSValueList AtlasJsModule::getVersion() {
// TODO(Faraphel): should be stored somewhere else.
// TODO(Faraphel): The type should implement an easy comparison system, if possible
QJSValueList version;
version.append(1);
version.append(0);
version.append(0);
return version;
}

View file

@ -1,36 +0,0 @@
#pragma once
#include <QObject>
#include <QJSValue>
class AtlasJsEngine;
class BaseJsModule;
class AtlasJsModule : public QObject {
Q_OBJECT
public:
explicit AtlasJsModule(AtlasJsEngine* engine, QObject* parent = nullptr);
/**
* Import an Atlas submodule
* @param name the name of the module to import
* @return the module
*/
Q_INVOKABLE QJSValue require(const QString& name) const;
/**
* Get the version of the Atlas Javascript engine
* @return the Atlas version
*/
Q_INVOKABLE static QList<QJSValue> getVersion();
private:
/// the parent JavaScript engine
AtlasJsEngine* engine;
/// the submodules contained in this module
std::map<QString, std::shared_ptr<BaseJsModule>> submodules;
};

View file

@ -1,8 +0,0 @@
#include "BaseJsModule.hpp"
#include "javascript/engine/AtlasJsEngine.hpp"
BaseJsModule::BaseJsModule(AtlasJsEngine* engine) {
this->engine = engine;
}

View file

@ -1,20 +0,0 @@
#pragma once
#include <QObject>
#include "javascript/engine/AtlasJsEngine.hpp"
/**
* Base class for an Atlas JavaScript submodule
*/
class BaseJsModule : public QObject {
Q_OBJECT
public:
explicit BaseJsModule(AtlasJsEngine* engine);
protected:
/// The javascript engine running the module
AtlasJsEngine* engine;
};

View file

@ -1,103 +0,0 @@
#include "FileJsObject.hpp"
#include <QJSValue>
#include <QTextStream>
#include "exception/FileNotFoundException.hpp"
#include "javascript/engine/AtlasJsEngine.hpp"
#include "utils/qt/fileOpenMode.hpp"
FileJsObject::FileJsObject(AtlasJsEngine* engine, const std::filesystem::path& virtualPath) {
// save the engine
this->engine = engine;
// create the internal QFile
std::filesystem::path realPath;
try {
realPath = this->engine->getFileSystem().resolve(virtualPath);
} catch (const vfs::exception::FileNotFoundException& exception) {
this->engine->throwError(QJSValue::ErrorType::URIError, "Invalid path.");
return;
}
// allocate the internal file
this->_internal = std::make_unique<QFile>(realPath);
}
void FileJsObject::open(const QString& mode) {
// get the mode flags from its string representation
this->mode = fileModeFromString(mode);
// open the file with the corresponding mode
if (!this->_internal->open(this->mode)) {
this->engine->throwError(QJSValue::URIError, "Cannot open the file.");
return;
}
// if we are in text mode, prepare the QTextStream wrapper
if (this->mode.testFlag(QIODevice::Text))
this->textStream = std::make_unique<QTextStream>(this->_internal.get());
}
QJSValue FileJsObject::read(const std::size_t size) const {
// check if we can read the file
if (!this->mode.testFlag(QIODevice::ReadOnly)) {
this->engine->throwError(QJSValue::ErrorType::TypeError, "The file is not open in read mode.");
return QJSValue(QJSPrimitiveNull());
}
// if we are in text mode, read from the text stream
if (this->mode.testFlag(QIODevice::Text))
return this->textStream->read(static_cast<qint64>(size));
// if we are in binary mode, read from the binary stream
const auto data = this->_internal->read(static_cast<qint64>(size));
return this->engine->toScriptValue(data);
}
std::size_t FileJsObject::write(const QJSValue& data) const {
// check if we can write into the file
if (!this->mode.testFlag(QIODevice::WriteOnly)) {
this->engine->throwError(QJSValue::ErrorType::TypeError, "The file is not open in write mode.");
return 0;
}
const QString dataString = data.toString();
// if we are in text mode, write text data
if (this->mode.testFlag(QIODevice::Text)) {
*this->textStream << dataString;
return dataString.size();
}
const QByteArray dataByte = dataString.toUtf8();
// if we are in binary mode, insert the raw binary data
return this->_internal->write(dataByte);
}
std::size_t FileJsObject::tell() const {
// if we are in text mode, return the position of the text stream
if (this->mode.testFlag(QIODevice::Text))
return this->textStream->pos();
// if we are in binary mode, return the position of the raw binary stream
return this->_internal->pos();
}
void FileJsObject::seek(const std::size_t position) const {
// if we are in text mode, set the position of the text stream
if (this->mode.testFlag(QIODevice::Text)) {
this->textStream->seek(static_cast<qint64>(position));
return;
}
// if we are in binary mode, set the position of the raw binary stream
this->_internal->seek(static_cast<qint64>(position));
}
void FileJsObject::close() const {
// if still opened, close the file
if (this->_internal->isOpen())
this->_internal->close();
}

View file

@ -1,55 +0,0 @@
#pragma once
#include <cstdlib>
#include <QFile>
#include <QJSValue>
#include <QObject>
#include <QTextStream>
#include "javascript/engine/AtlasJsEngine.hpp"
/**
* Represent a JavaScript file.
* This is a wrapper around `QFile`
*/
class FileJsObject : public QObject {
Q_OBJECT
public:
explicit FileJsObject(AtlasJsEngine* engine, const std::filesystem::path& virtualPath);
/**
* Open the file to access its content.
* @param mode the opening mode of the file, using "r", "w", "+", etc...
*/
Q_INVOKABLE void open(const QString& mode = QStringLiteral("r"));
/**
* Read the content of the file.
* @param size the size of the content to read.
* @return the content of the file
*/
Q_INVOKABLE QJSValue read(size_t size = std::numeric_limits<std::size_t>::max()) const;
/**
* Write data into the file
* @param data the data to write into the file
* @return the size of the data written
*/
Q_INVOKABLE std::size_t write(const QJSValue& data) const;
Q_INVOKABLE std::size_t tell() const;
Q_INVOKABLE void seek(std::size_t position) const;
/**
* Close the file.
*/
Q_INVOKABLE void close() const;
private:
AtlasJsEngine* engine;
std::unique_ptr<QFile> _internal;
QIODevice::OpenMode mode;
std::unique_ptr<QTextStream> textStream;
};

View file

@ -1,101 +0,0 @@
#include "PathJsObject.hpp"
#include <QDir>
#include <QList>
#include "FileJsObject.hpp"
#include "exception/FileNotFoundException.hpp"
PathJsObject::PathJsObject(AtlasJsEngine* engine, const std::filesystem::path& virtualPath) {
this->engine = engine;
this->virtualPath = virtualPath;
}
QJSValue PathJsObject::getParent() const {
// return the parent directory
return this->engine->newQObject(new PathJsObject(
this->engine,
this->virtualPath.parent_path()
));
}
QList<QJSValue> PathJsObject::getChildrens() const {
// check if the path is iterable
if (!this->isDirectory()) {
this->engine->throwError(QJSValue::ErrorType::TypeError, "Only directories can have children.");
return {};
}
// get the corresponding real directory path
const std::filesystem::path realPath = this->getRealPath();
// prepare the list of children paths
auto childsPath = QList<QJSValue>();
// iterate through the childrens of the directory
for (const auto& childRealEntry : std::filesystem::directory_iterator(realPath)) {
// get the corresponding path object
const auto& childRealPath = childRealEntry.path();
// get the virtual path
std::filesystem::path childVirtualPath = this->virtualPath / childRealPath.filename();
// add it to the list of childrens
const auto pathJs = this->engine->newQObject(new PathJsObject(
this->engine,
childVirtualPath
));
childsPath.append(pathJs);
}
return childsPath;
}
bool PathJsObject::isFile() const {
return is_regular_file(this->getRealPath());
}
bool PathJsObject::isDirectory() const {
return is_directory(this->getRealPath());
}
Q_INVOKABLE QJSValue PathJsObject::open(const QString& mode, const QString& encoding) {
// create a new file object
auto* file = new FileJsObject(
this->engine,
this->virtualPath
);
// open it with the given mode
file->open(mode);
// convert it into a QJSValue
auto fileJs = this->engine->newQObject(file);
return fileJs;
// TODO(Faraphel): handle encoding
}
QString PathJsObject::getPath() const {
return QString::fromStdString(this->virtualPath.string());
}
QString PathJsObject::getDirname() const {
return QString::fromStdString(this->virtualPath.parent_path().string());
}
QString PathJsObject::getFilename() const {
return QString::fromStdString(this->virtualPath.filename());
}
QString PathJsObject::getBasename() const {
return QString::fromStdString(this->virtualPath.stem());
}
QString PathJsObject::getSuffix() const {
return QString::fromStdString(this->virtualPath.extension());
}
std::filesystem::path PathJsObject::getRealPath() const {
return this->engine->getFileSystem().resolve(this->virtualPath);
}

View file

@ -1,114 +0,0 @@
#pragma once
#include <QObject>
#include <QString>
#include <QList>
#include <QDir>
#include <QSharedPointer>
#include "javascript/module/file_system/object/FileJsObject.hpp"
#include "javascript/engine/AtlasJsEngine.hpp"
/**
* Represent a file system Path as a JavaScript object
* Similar to the pathlib library in Python
*/
class PathJsObject : public QObject {
Q_OBJECT
public:
explicit PathJsObject(AtlasJsEngine* engine, const std::filesystem::path& virtualPath);
// browse
/**
* Get the parent directory
* @return the parent directory
*/
Q_INVOKABLE QJSValue getParent() const;
/**
* Get the child paths
* @return the child paths
*/
Q_INVOKABLE QList<QJSValue> getChildrens(bool recursive = false, QString pattern = "*") const;
// type
Q_INVOKABLE bool exists();
/**
* is the current path leading to a file
* @return is the current path leading to a file
*/
Q_INVOKABLE bool isFile() const;
/**
* is the current path leading to a directory
* @return is the current path leading to a directory
*/
Q_INVOKABLE bool isDirectory() const;
// operation
/**
* open the path as a file
* @return the opened file
*/
Q_INVOKABLE QJSValue open(const QString& mode, const QString& encoding = QStringLiteral("utf-8"));
Q_INVOKABLE void mkdir(bool parents);
Q_INVOKABLE void remove(bool recursive);
// component
/**
* get the full path to the file
* @return the full path to the file
*/
Q_INVOKABLE QString getPath() const;
/**
* get the name of the directory containing the file
* @return the name of the directory containing the file
*/
Q_INVOKABLE QString getDirname() const;
/**
* get the name of the file
* @return the name of the file
*/
Q_INVOKABLE QString getFilename() const;
/**
* get the name of the file without the suffix
* @return the name of the file without the suffix
*/
Q_INVOKABLE QString getBasename() const;
/**
* get the extension of the file
* @return the extension of the file
*/
Q_INVOKABLE QString getSuffix() const;
/**
* get the extensions of the file
* @return the extensions of the file
*/
Q_INVOKABLE QList<QString> getSuffixes() const;
/**
* get the segments of the path
* @return the segments of the path
*/
Q_INVOKABLE QList<QString> getSegments() const;
private:
/// the JavaScript engine
AtlasJsEngine* engine;
/// the virtual path
std::filesystem::path virtualPath;
/**
* Get the real path on the host file system of the path
* @return the real path on the host file system
* @throw rvfs::exception::FileNotFoundException if the path does not match with anything on the real file system
*/
std::filesystem::path getRealPath() const;
};

View file

@ -8,6 +8,7 @@
#include "script/engine/Engine.hpp" #include "script/engine/Engine.hpp"
#include "script/module/debug/_load.hpp" #include "script/module/debug/_load.hpp"
#include "script/module/filesystem/_load.hpp"
int main_AngelScript(int argc, char* argv[]) { int main_AngelScript(int argc, char* argv[]) {
@ -19,6 +20,7 @@ int main_AngelScript(int argc, char* argv[]) {
// functions // functions
atlas::script::module::debug::load(atlasEngine.get()); atlas::script::module::debug::load(atlasEngine.get());
atlas::script::module::filesystem::load(atlasEngine.get());
// script // script
CScriptBuilder builder; CScriptBuilder builder;
@ -27,12 +29,7 @@ int main_AngelScript(int argc, char* argv[]) {
if (error < 0) if (error < 0)
throw std::runtime_error("Could not start a new module."); throw std::runtime_error("Could not start a new module.");
error = builder.AddSectionFromMemory("script", R"( error = builder.AddSectionFromFile(".mods/Atlas/scripts/hello.as");
void main() {
array<int> data(256);
atlas::debug::log("main", "hello world !");
}
)");
if (error < 0) if (error < 0)
throw std::runtime_error("Could not add a section to the module."); throw std::runtime_error("Could not add a section to the module.");
@ -88,5 +85,5 @@ int main_vfspp(int argc, char* argv[]) {
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
main_vfspp(argc, argv); main_AngelScript(argc, argv);
} }

View file

@ -38,6 +38,9 @@ Engine::Engine() {
RegisterScriptWeakRef(this->asEngine); RegisterScriptWeakRef(this->asEngine);
RegisterExceptionRoutines(this->asEngine); RegisterExceptionRoutines(this->asEngine);
RegisterScriptMath(this->asEngine); RegisterScriptMath(this->asEngine);
// Virtual file system
this->fileSystem = std::make_unique<vfs::VirtualFileSystem>();
} }
void Engine::asCallback(const asSMessageInfo *message, void *args) { void Engine::asCallback(const asSMessageInfo *message, void *args) {
@ -79,4 +82,8 @@ asIScriptEngine* Engine::getAsEngine() const {
return this->asEngine; return this->asEngine;
} }
std::shared_ptr<vfs::VirtualFileSystem> Engine::getFileSystem() const {
return this->fileSystem;
}
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <angelscript.h> #include <angelscript.h>
#include <VirtualFileSystem.hpp>
namespace atlas::script::engine { namespace atlas::script::engine {
@ -27,8 +28,15 @@ public:
*/ */
[[nodiscard]] asIScriptEngine* getAsEngine() const; [[nodiscard]] asIScriptEngine* getAsEngine() const;
/**
* get the file system
* @return the file system
*/
[[nodiscard]] std::shared_ptr<vfs::VirtualFileSystem> getFileSystem() const;
private: private:
asIScriptEngine* asEngine; asIScriptEngine* asEngine;
std::shared_ptr<vfs::VirtualFileSystem> fileSystem;
}; };
} }

View file

@ -0,0 +1,65 @@
#include "File.hpp"
#include "utils/file/openMode.hpp"
File::File(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath) {
this->engine = engine;
this->virtualPath = virtualPath;
}
void File::open(const std::string& mode) {
// allocate the internal file
this->stream = std::fstream(this->getRealPath(), atlas::utils::file::getOpenMode(mode));
}
std::vector<std::uint8_t> File::read(const std::size_t size) {
// create a buffer
std::vector<std::uint8_t> buffer(size);
// read into the buffer
this->stream.read(
reinterpret_cast<std::fstream::char_type*>(buffer.data()),
static_cast<std::streamsize>(size)
);
// set the write cursor to the read cursor (synchronise)
this->stream.seekp(this->stream.tellg());
return buffer;
}
void File::write(const std::vector<std::uint8_t>& buffer) {
// read onto the buffer
this->stream.write(
reinterpret_cast<const std::fstream::char_type*>(buffer.data()),
static_cast<std::streamsize>(buffer.size())
);
// set the read cursor to the write cursor (synchronise)
this->stream.seekg(this->stream.tellp());
}
std::size_t File::tell() {
// return the stream cursor position.
// The read and write cursors are always synchronised.
return this->stream.tellp();
}
void File::seek(const std::size_t position) {
// set the new stream cursor position.
// synchronise the two cursors.
this->stream.seekg(static_cast<std::streamoff>(position));
this->stream.seekp(this->stream.tellg());
}
void File::close() {
// close the stream
this->stream.close();
}
std::filesystem::path File::getRealPath() const {
// get the real path from the internal virtual path
return this->engine->getFileSystem()->resolve(this->virtualPath);
}

View file

@ -0,0 +1,67 @@
#pragma once
#include <string>
#include <filesystem>
#include <vector>
#include <fstream>
#include "script/engine/Engine.hpp"
/**
* Represent a JavaScript file.
* This is a wrapper around `QFile`
*/
class File {
public:
explicit File(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath);
/**
* Open the file to access its content.
* @param mode the opening mode of the file, using "r", "w", "+", etc...
*/
void open(const std::string& mode = "r");
/**
* Read the content of the file.
* @param size the size of the content to read.
* @return the content of the file
*/
std::vector<std::uint8_t> read(size_t size = std::numeric_limits<std::size_t>::max());
/**
* Write data into the file
* @param buffer the data to write into the file
* @return the size of the data written
*/
void write(const std::vector<std::uint8_t>& buffer);
/**
* Get the current cursor position
* @return the current cursor position
*/
std::size_t tell();
/**
* Set the cursor position
* @param position the new cursor position
*/
void seek(std::size_t position);
/**
* Close the file.
*/
void close();
private:
/**
* Get the corresponding real file path
* @return the real file path
*/
std::filesystem::path getRealPath() const;
std::filesystem::path virtualPath;
/// the Atlas engine
const atlas::script::engine::Engine* engine;
/// the internal file streamer
std::fstream stream;
};

View file

@ -1,8 +1,131 @@
#include "Path.hpp" #include "Path.hpp"
namespace atlas::script::module::filesystem { #include <regex>
Path::Path(const engine::Engine* atlasEngine, const std::string &path) { #include "exception/FileNotFoundException.hpp"
Path::Path(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath) {
this->engine = engine;
this->virtualPath = virtualPath;
} }
Path Path::getParent() const {
// return the parent directory
return Path(
this->engine,
this->virtualPath.parent_path()
);
}
std::vector<std::shared_ptr<Path>> Path::getChildrens(const bool recursive, const std::string& pattern) const {
// TODO(Faraphel): implement recursive and pattern
// check if the path is iterable
if (!this->isDirectory())
throw std::runtime_error("Can only iterate directories.");
// get the corresponding real directory path
const std::filesystem::path realPath = this->getRealPath();
// prepare the list of children paths
auto childsPath = std::vector<std::shared_ptr<Path>>();
// iterate through the childrens of the directory
for (const auto& childRealEntry : std::filesystem::directory_iterator(realPath)) {
// get the corresponding path object
const auto& childRealPath = childRealEntry.path();
// get the virtual path
std::filesystem::path childVirtualPath = this->virtualPath / childRealPath.filename();
// add it to the list of childrens
auto path = std::make_shared<Path>(
this->engine,
childVirtualPath
);
childsPath.push_back(path);
}
return childsPath;
}
bool Path::exists() const {
return std::filesystem::exists(this->getRealPath());
}
bool Path::isFile() const {
return is_regular_file(this->getRealPath());
}
bool Path::isDirectory() const {
return is_directory(this->getRealPath());
}
std::shared_ptr<File> Path::open(const std::string& mode, const std::string& encoding) {
// create a new file object
auto file = std::make_shared<File>(
this->engine,
this->virtualPath
);
// open it with the given mode
file->open(mode);
return file;
// TODO(Faraphel): handle encoding. Wrapper text reader like in C ? readText / writeText ? overloading with std::string ?
}
bool Path::mkdir(const bool parents) const {
return create_directory(this->getRealPath());
}
void Path::remove(const bool recursive) const {
if (recursive)
remove_all(this->getRealPath());
else
std::filesystem::remove(this->getRealPath());
}
std::string Path::getPath() const {
return this->virtualPath.string();
}
std::string Path::getDirname() const {
return this->virtualPath.parent_path().string();
}
std::string Path::getFilename() const {
return this->virtualPath.filename();
}
std::string Path::getBasename() const {
return this->virtualPath.stem();
}
std::string Path::getSuffix() const {
return this->virtualPath.extension();
}
std::vector<std::string> Path::getSuffixes() const {
const std::string filename = this->virtualPath;
auto delimiter = std::regex(".");
// split the string at every occurence of the "." character
auto parts = std::vector<std::string>(
std::sregex_token_iterator(filename.begin(), filename.end(), delimiter, -1),
std::sregex_token_iterator()
);
// remove the first string (the basename)
parts.erase(parts.begin());
return parts;
}
std::vector<std::string> Path::getComponents() const {
return {this->virtualPath.begin(), this->virtualPath.end()};
}
std::filesystem::path Path::getRealPath() const {
return this->engine->getFileSystem()->resolve(this->virtualPath);
} }

View file

@ -1,17 +1,114 @@
#pragma once #pragma once
#include <string>
#include <filesystem>
#include <vector>
#include "File.hpp"
#include "script/engine/Engine.hpp" #include "script/engine/Engine.hpp"
namespace atlas::script::module::filesystem {
/** /**
* Represent a path in the virtual file system * Represent a virtual file system path
* Similar to the pathlib library in Python
*/ */
class Path { class Path {
public:
explicit Path(const engine::Engine* atlasEngine, const std::string& path);
};
} public:
explicit Path(const atlas::script::engine::Engine* engine, const std::filesystem::path& virtualPath);
// browse
/**
* Get the parent directory
* @return the parent directory
*/
[[nodiscard]] Path getParent() const;
/**
* Get the child paths
* @return the child paths
*/
[[nodiscard]] std::vector<std::shared_ptr<Path>> getChildrens(bool recursive = false, const std::string& pattern = "*") const;
// type
/**
* Check if the path correspond to a file system entry
* @return does the path exists
*/
[[nodiscard]] bool exists() const;
/**
* is the current path leading to a file
* @return is the current path leading to a file
*/
[[nodiscard]] bool isFile() const;
/**
* is the current path leading to a directory
* @return is the current path leading to a directory
*/
[[nodiscard]] bool isDirectory() const;
// operation
/**
* open the path as a file
* @return the opened file
*/
std::shared_ptr<File> open(const std::string& mode, const std::string& encoding = "utf-8");
[[nodiscard]] bool mkdir(bool parents) const;
void remove(bool recursive) const;
// component
/**
* get the full path to the file
* @return the full path to the file
*/
[[nodiscard]] std::string getPath() const;
/**
* get the name of the directory containing the file
* @return the name of the directory containing the file
*/
[[nodiscard]] std::string getDirname() const;
/**
* get the name of the file
* @return the name of the file
*/
[[nodiscard]] std::string getFilename() const;
/**
* get the name of the file without the suffix
* @return the name of the file without the suffix
*/
[[nodiscard]] std::string getBasename() const;
/**
* get the extension of the file
* @return the extension of the file
*/
[[nodiscard]] std::string getSuffix() const;
/**
* get the extensions of the file
* @return the extensions of the file
*/
[[nodiscard]] std::vector<std::string> getSuffixes() const;
/**
* get the components of the path
* @return the components of the path
*/
[[nodiscard]] std::vector<std::string> getComponents() const;
private:
/// the JavaScript engine
const atlas::script::engine::Engine* engine;
/// the virtual path
std::filesystem::path virtualPath;
/**
* Get the real path on the host file system of the path
* @return the real path on the host file system
* @throw rvfs::exception::FileNotFoundException if the path does not match with anything on the real file system
*/
[[nodiscard]] std::filesystem::path getRealPath() const;
};

View file

@ -2,11 +2,18 @@
#include <stdexcept> #include <stdexcept>
#include "Path.hpp"
namespace atlas::script::module::filesystem { namespace atlas::script::module::filesystem {
Path* pathFactory(const engine::Engine* atlasEngine, const std::string& virtualPath) {
return new Path(atlasEngine, virtualPath);
};
void load(const engine::Engine* atlasEngine) { void load(const engine::Engine* atlasEngine) {
asIScriptEngine* asEngine = atlasEngine->getAsEngine(); asIScriptEngine* asEngine = atlasEngine->getAsEngine();
auto fileSystem = atlasEngine->getFileSystem();
int error; int error;
// start namespace // start namespace
@ -14,6 +21,14 @@ void load(const engine::Engine* atlasEngine) {
if (error < 0) if (error < 0)
throw std::runtime_error("Could not enter the \"atlas::filesystem\" namespace."); throw std::runtime_error("Could not enter the \"atlas::filesystem\" namespace.");
// TODO(Faraphel): register the Path and File types
error = asEngine->RegisterGlobalProperty("int Path::FileSystem", fileSystem.get());
// error = asEngine->RegisterObjectType("Path", 0, asOBJ_REF);
// error = asEngine->RegisterObjectBehaviour("Path", asBEHAVE_FACTORY, "Path@ f(const string& in)", asFUNCTION(pathFactory), asCALL_CDECL);
// error = asEngine->RegisterObjectMethod("Path", "Path@ getParent() const", asMETHOD(Path, getParent), asCALL_THISCALL);
// error = asEngine->RegisterObjectMethod("Path", "bool exists() const", asMETHOD(Path, exists), asCALL_THISCALL);
// end namespace // end namespace
error = asEngine->SetDefaultNamespace(""); error = asEngine->SetDefaultNamespace("");
if (error < 0) if (error < 0)

View file

@ -0,0 +1,20 @@
#include "openMode.hpp"
namespace atlas::utils::file {
std::ios_base::openmode getOpenMode(const std::string& mode) {
// initialise an empty flags
auto flags = static_cast<std::ios_base::openmode>(0);
// set the flags
if (mode.find('r') != std::string::npos) flags |= std::ios::in;
if (mode.find('w') != std::string::npos) flags |= std::ios::out;
if (mode.find('a') != std::string::npos) flags |= std::ios::app;
if (mode.find('b') != std::string::npos) flags |= std::ios::binary;
return flags;
}
}

View file

@ -0,0 +1,11 @@
#pragma once
#include <ios>
#include <string>
namespace atlas::utils::file {
std::ios_base::openmode getOpenMode(const std::string& mode);
}