implemented all the Path and File methods
This commit is contained in:
parent
64c247ba6f
commit
03a9833d21
19 changed files with 431 additions and 503 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
#include "BaseJsModule.hpp"
|
|
||||||
|
|
||||||
#include "javascript/engine/AtlasJsEngine.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
BaseJsModule::BaseJsModule(AtlasJsEngine* engine) {
|
|
||||||
this->engine = engine;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
65
source/script/module/filesystem/File.cpp
Normal file
65
source/script/module/filesystem/File.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
67
source/script/module/filesystem/File.hpp
Normal file
67
source/script/module/filesystem/File.hpp
Normal 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;
|
||||||
|
};
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
|
20
source/utils/file/openMode.cpp
Normal file
20
source/utils/file/openMode.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
source/utils/file/openMode.hpp
Normal file
11
source/utils/file/openMode.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ios>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace atlas::utils::file {
|
||||||
|
|
||||||
|
std::ios_base::openmode getOpenMode(const std::string& mode);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue