improved the JavaScript path object
This commit is contained in:
parent
308124c99f
commit
13eddaee81
42 changed files with 754 additions and 295 deletions
|
@ -6,7 +6,7 @@ set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,16 +26,25 @@ add_executable(Atlas-Launcher
|
||||||
source/javascript/module/debug/DebugJsModule.hpp
|
source/javascript/module/debug/DebugJsModule.hpp
|
||||||
source/javascript/module/image/ImageJsModule.cpp
|
source/javascript/module/image/ImageJsModule.cpp
|
||||||
source/javascript/module/image/ImageJsModule.hpp
|
source/javascript/module/image/ImageJsModule.hpp
|
||||||
source/javascript/module/image/ImageJsObject.cpp
|
source/javascript/module/image/object/ImageJsObject.cpp
|
||||||
source/javascript/module/image/ImageJsObject.hpp
|
source/javascript/module/image/object/ImageJsObject.hpp
|
||||||
source/javascript/module/_base/BaseJsModule.cpp
|
source/javascript/module/_base/BaseJsModule.cpp
|
||||||
source/javascript/module/_base/BaseJsModule.hpp
|
source/javascript/module/_base/BaseJsModule.hpp
|
||||||
source/javascript/module/file/FileJsModule.cpp
|
source/javascript/module/file_system/FsJsModule.cpp
|
||||||
source/javascript/module/file/FileJsModule.hpp
|
source/javascript/module/file_system/FsJsModule.hpp
|
||||||
|
source/javascript/module/file_system/object/FileJsObject.cpp
|
||||||
|
source/javascript/module/file_system/object/FileJsObject.hpp
|
||||||
|
source/utils/qt/fileOpenMode.cpp
|
||||||
|
source/utils/qt/fileOpenMode.hpp
|
||||||
|
source/javascript/module/file_system/object/PathJsObject.cpp
|
||||||
|
source/javascript/module/file_system/object/PathJsObject.hpp
|
||||||
|
)
|
||||||
|
target_include_directories(Atlas-Launcher PRIVATE
|
||||||
|
source/
|
||||||
)
|
)
|
||||||
target_link_libraries(Atlas-Launcher PRIVATE
|
target_link_libraries(Atlas-Launcher PRIVATE
|
||||||
# Tools
|
# Tools
|
||||||
RVFS
|
VFS
|
||||||
SZS
|
SZS
|
||||||
|
|
||||||
# Qt Framework
|
# Qt Framework
|
||||||
|
@ -46,5 +55,5 @@ target_link_libraries(Atlas-Launcher PRIVATE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(external/rvfs)
|
add_subdirectory(external/vfs)
|
||||||
add_subdirectory(external/szs)
|
add_subdirectory(external/szs)
|
||||||
|
|
27
external/rvfs/CMakeLists.txt
vendored
27
external/rvfs/CMakeLists.txt
vendored
|
@ -1,27 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.28)
|
|
||||||
project(RVFS LANGUAGES CXX)
|
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
set(CMAKE_AUTORCC ON)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS
|
|
||||||
Core
|
|
||||||
)
|
|
||||||
add_library(RVFS STATIC
|
|
||||||
source/RestrictedVirtualFileSystem.cpp
|
|
||||||
)
|
|
||||||
target_include_directories(RVFS PUBLIC
|
|
||||||
include/
|
|
||||||
)
|
|
||||||
target_link_libraries(RVFS PRIVATE
|
|
||||||
# Qt Framework
|
|
||||||
Qt::Core
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(tests)
|
|
|
@ -1,62 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <QDir>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
|
|
||||||
namespace rvfs {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent a virtual restricted file system.
|
|
||||||
* Real directory can be mounted to safely interact with the real file system.
|
|
||||||
*/
|
|
||||||
class RestrictedVirtualFileSystem {
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit RestrictedVirtualFileSystem();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all the mounted directories with their path in the virtual file system and in the real file system
|
|
||||||
* @return all the mounted directories with their path in the virtual file system and in the real file system
|
|
||||||
*/
|
|
||||||
QMap<QString, QString> getMountedDirectories();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mount a real directory into the virtual file system
|
|
||||||
* @param destination the path to the directory in the virtual file system
|
|
||||||
* @param source the path to the directory in the real file system
|
|
||||||
*/
|
|
||||||
void mountDirectory(const QDir& destination, const QDir& source);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unmount a directory from the virtual file system
|
|
||||||
* @param destination the path to the directory in the virtual file system
|
|
||||||
*/
|
|
||||||
void unmountDirectory(const QDir& destination);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current working directory in the virtual file system
|
|
||||||
* @return the current working directory in the virtual file system
|
|
||||||
*/
|
|
||||||
QDir getWorkingDirectory();
|
|
||||||
/**
|
|
||||||
* Change the current working directory in the virtual file system
|
|
||||||
* @param path path to the new virtual working directory
|
|
||||||
*/
|
|
||||||
void setWorkingDirectory(const QDir& path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a path inside the virtual file system into a path in the real file system
|
|
||||||
* @param path the path in the virtual file system
|
|
||||||
* @return the matching path in the real file system
|
|
||||||
*/
|
|
||||||
QString resolvePath(QString path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// the current working directory
|
|
||||||
QDir workingDirectory;
|
|
||||||
/// store the path in the virtual file system of a directory in the real file system
|
|
||||||
QMap<QString, QString> mounts;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
#include "RestrictedVirtualFileSystem.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace rvfs {
|
|
||||||
|
|
||||||
RestrictedVirtualFileSystem::RestrictedVirtualFileSystem() = default;
|
|
||||||
|
|
||||||
QMap<QString, QString> RestrictedVirtualFileSystem::getMountedDirectories() {
|
|
||||||
return this->mounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestrictedVirtualFileSystem::mountDirectory(const QDir& destination, const QDir& source) {
|
|
||||||
// check if the source directory does exists
|
|
||||||
if (!source.exists())
|
|
||||||
// TODO(Faraphel): should be a custom error ?
|
|
||||||
throw std::runtime_error("The source directory does not exists.");
|
|
||||||
|
|
||||||
// mount it by associating our virtual folder with our real one
|
|
||||||
this->mounts[destination.absolutePath()] = source.absolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestrictedVirtualFileSystem::unmountDirectory(const QDir& destination) {
|
|
||||||
// remove the mounted directory from the map
|
|
||||||
this->mounts.remove(destination.absolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir RestrictedVirtualFileSystem::getWorkingDirectory() {
|
|
||||||
return this->workingDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestrictedVirtualFileSystem::setWorkingDirectory(const QDir& path) {
|
|
||||||
this->workingDirectory = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString RestrictedVirtualFileSystem::resolvePath(QString path) {
|
|
||||||
if (QFileInfo(path).isRelative()) {
|
|
||||||
// if the path is relative, make it absolute with the current working directory
|
|
||||||
path = this->workingDirectory.absoluteFilePath(path);
|
|
||||||
} else {
|
|
||||||
// if the path is absolute, make sure to resolve the special syntax like ".."
|
|
||||||
path = QFileInfo(path).absoluteFilePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resolved = false;
|
|
||||||
// go through all the mounted directories
|
|
||||||
for (auto const& [destination, source] : this->mounts.asKeyValueRange()) {
|
|
||||||
// if the path is inside a mounted directory
|
|
||||||
if (path.startsWith(destination)) {
|
|
||||||
// replace the mounted directory by the original real one
|
|
||||||
path = path.replace(0, destination.length(), source);
|
|
||||||
// mark the path as resolved and break
|
|
||||||
resolved = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the path has not been resolved, it is in an invalid or forbidden location
|
|
||||||
if (!resolved)
|
|
||||||
// TODO(Faraphel): should be a custom error ?
|
|
||||||
throw std::runtime_error("cannot resolve path: invalid.");
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
36
external/rvfs/tests/CMakeLists.txt
vendored
36
external/rvfs/tests/CMakeLists.txt
vendored
|
@ -1,36 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.28)
|
|
||||||
project(Test-RVFS LANGUAGES CXX)
|
|
||||||
|
|
||||||
|
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
set(CMAKE_AUTORCC ON)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS
|
|
||||||
Core
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test executable
|
|
||||||
add_executable(Test-RVFS
|
|
||||||
test-restriction.cpp
|
|
||||||
)
|
|
||||||
# Libraries
|
|
||||||
target_link_libraries(Test-RVFS PRIVATE
|
|
||||||
# Code to test
|
|
||||||
RVFS
|
|
||||||
# Qt Framework
|
|
||||||
Qt::Core
|
|
||||||
)
|
|
||||||
# Copy the assets to run the tests
|
|
||||||
file(COPY _assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
|
|
||||||
# Test
|
|
||||||
add_test(NAME Test-RVFS COMMAND Test-RVFS)
|
|
18
external/vfs/CMakeLists.txt
vendored
Normal file
18
external/vfs/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
cmake_minimum_required(VERSION 3.28)
|
||||||
|
project(VFS LANGUAGES CXX)
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
|
||||||
|
add_library(VFS STATIC
|
||||||
|
source/VirtualFileSystem.cpp
|
||||||
|
source/exception/FileNotFoundException.cpp
|
||||||
|
include/exception/FileNotFoundException.hpp
|
||||||
|
)
|
||||||
|
target_include_directories(VFS PUBLIC
|
||||||
|
include/
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(tests)
|
49
external/vfs/include/VirtualFileSystem.hpp
vendored
Normal file
49
external/vfs/include/VirtualFileSystem.hpp
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
|
||||||
|
namespace vfs {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a virtual file system.
|
||||||
|
* Real directory can be mounted to safely interact with the real file system.
|
||||||
|
*/
|
||||||
|
class VirtualFileSystem {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VirtualFileSystem();
|
||||||
|
~VirtualFileSystem();
|
||||||
|
|
||||||
|
std::filesystem::path getWorkingDirectory() const;
|
||||||
|
|
||||||
|
void setWorkingDirectory(const std::filesystem::path& virtualPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mount a real directory into the virtual file system
|
||||||
|
* @param sourcePath the path to the directory in the real file system
|
||||||
|
* @param virtualDestinationPath the path to the directory in the virtual file system
|
||||||
|
*/
|
||||||
|
void mount(const std::filesystem::path& sourcePath, const std::filesystem::path& virtualDestinationPath) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmount a directory from the virtual file system
|
||||||
|
* @param virtualPath the path to the directory in the virtual file system
|
||||||
|
*/
|
||||||
|
void unmount(const std::filesystem::path& virtualPath) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the real path on the host file system from its virtual path
|
||||||
|
* @param virtualPath the virtual path
|
||||||
|
* @return the real path
|
||||||
|
*/
|
||||||
|
std::filesystem::path resolve(const std::filesystem::path& virtualPath) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the internal temporary directory
|
||||||
|
std::filesystem::path rootDirectoryPath;
|
||||||
|
/// the virtual current working directory. Always relative.
|
||||||
|
std::filesystem::path virtualWorkingDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
14
external/vfs/include/exception/FileNotFoundException.hpp
vendored
Normal file
14
external/vfs/include/exception/FileNotFoundException.hpp
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
|
||||||
|
namespace vfs::exception {
|
||||||
|
|
||||||
|
class FileNotFoundException final : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
explicit FileNotFoundException(const std::filesystem::path& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
88
external/vfs/source/VirtualFileSystem.cpp
vendored
Normal file
88
external/vfs/source/VirtualFileSystem.cpp
vendored
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include "VirtualFileSystem.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "exception/FileNotFoundException.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace vfs {
|
||||||
|
|
||||||
|
VirtualFileSystem::VirtualFileSystem() {
|
||||||
|
// create the temporary directory
|
||||||
|
char temporaryDirectoryPathTemplate[] = "/tmp/vfs-XXXXXX";
|
||||||
|
const char* temporaryDirectoryPath = mkdtemp(temporaryDirectoryPathTemplate);
|
||||||
|
// check for any issue while creating the directory
|
||||||
|
if (temporaryDirectoryPath == nullptr)
|
||||||
|
throw std::runtime_error("Could not create a temporary directory for the virtual file system.");
|
||||||
|
|
||||||
|
// store it as a standard path
|
||||||
|
this->rootDirectoryPath = std::filesystem::path(temporaryDirectoryPath);
|
||||||
|
|
||||||
|
// set the virtual working directory at the root
|
||||||
|
this->setWorkingDirectory("./");
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFileSystem::~VirtualFileSystem() {
|
||||||
|
// delete everything in the temporary directory
|
||||||
|
std::error_code error;
|
||||||
|
remove_all(this->rootDirectoryPath, error);
|
||||||
|
|
||||||
|
// check for any error
|
||||||
|
if (error)
|
||||||
|
std::cerr << "Could not clean the VFS : " + error.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path VirtualFileSystem::getWorkingDirectory() const {
|
||||||
|
return this->virtualWorkingDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualFileSystem::setWorkingDirectory(const std::filesystem::path& virtualPath) {
|
||||||
|
if (!virtualPath.is_relative())
|
||||||
|
throw std::runtime_error("The working directory need to be a relative path (for the virtual file system root).");
|
||||||
|
|
||||||
|
// set the new working directory
|
||||||
|
this->virtualWorkingDirectory = virtualPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualFileSystem::mount(const std::filesystem::path& sourcePath, const std::filesystem::path& virtualDestinationPath) const {
|
||||||
|
// create a symlink from the directory to our temporary directory
|
||||||
|
const std::filesystem::path realDestinationPath = this->resolve(virtualDestinationPath);
|
||||||
|
|
||||||
|
// create a symlink to the directory to mount in our virtual file system directory
|
||||||
|
std::error_code error;
|
||||||
|
create_directory_symlink(absolute(sourcePath), realDestinationPath, error);
|
||||||
|
// check for any error while creating the symlink
|
||||||
|
if (error)
|
||||||
|
throw std::runtime_error("Could not mount the directory in the virtual file system. Reason: " + error.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualFileSystem::unmount(const std::filesystem::path& virtualPath) const {
|
||||||
|
// get the real path of the given virtual path
|
||||||
|
const std::filesystem::path realPath = this->resolve(virtualPath);
|
||||||
|
|
||||||
|
// check if it is a symbolic link
|
||||||
|
if (!is_symlink(realPath))
|
||||||
|
throw std::runtime_error("Not a mounted directory !");
|
||||||
|
|
||||||
|
// delete the symlink
|
||||||
|
remove(realPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path VirtualFileSystem::resolve(const std::filesystem::path& virtualPath) const {
|
||||||
|
// normalize the path by solving the special symbols first.
|
||||||
|
std::filesystem::path normalizedVirtualPath = virtualPath.lexically_normal();
|
||||||
|
|
||||||
|
if (virtualPath.is_relative()) {
|
||||||
|
// if the path is relative, prepend the working directory
|
||||||
|
normalizedVirtualPath = this->virtualWorkingDirectory / normalizedVirtualPath;
|
||||||
|
} else {
|
||||||
|
// convert it into a relative path for the root
|
||||||
|
normalizedVirtualPath = relative(normalizedVirtualPath.lexically_normal(), "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the real path by prepending the real root directory path
|
||||||
|
return this->rootDirectoryPath / normalizedVirtualPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
9
external/vfs/source/exception/FileNotFoundException.cpp
vendored
Normal file
9
external/vfs/source/exception/FileNotFoundException.cpp
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#include "exception/FileNotFoundException.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace vfs::exception {
|
||||||
|
|
||||||
|
FileNotFoundException::FileNotFoundException(const std::filesystem::path& path) :
|
||||||
|
std::runtime_error("Could not find the file : " + path.string()) {}
|
||||||
|
|
||||||
|
}
|
25
external/vfs/tests/CMakeLists.txt
vendored
Normal file
25
external/vfs/tests/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
cmake_minimum_required(VERSION 3.28)
|
||||||
|
project(Test-VFS LANGUAGES CXX)
|
||||||
|
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
|
||||||
|
# Test executable
|
||||||
|
add_executable(Test-VFS
|
||||||
|
test-restriction.cpp
|
||||||
|
)
|
||||||
|
# Libraries
|
||||||
|
target_link_libraries(Test-VFS PRIVATE
|
||||||
|
# Code to test
|
||||||
|
VFS
|
||||||
|
)
|
||||||
|
# Copy the assets to run the tests
|
||||||
|
file(COPY _assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
# Test
|
||||||
|
add_test(NAME Test-VFS COMMAND Test-VFS)
|
|
@ -1,28 +1,29 @@
|
||||||
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <RestrictedVirtualFileSystem.hpp>
|
#include <VirtualFileSystem.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// TODO(Faraphel): use a real unit test framework ?
|
// TODO(Faraphel): use a real unit test framework ?
|
||||||
|
|
||||||
// create a basic rvfs
|
// create a basic virtual file system
|
||||||
rvfs::RestrictedVirtualFileSystem fs;
|
vfs::VirtualFileSystem fs;
|
||||||
|
|
||||||
// mount a directory into our system
|
// mount a directory into our system
|
||||||
fs.mountDirectory(QDir("/assets/"), QDir("./_assets/"));
|
fs.mount("_assets", "/assets");
|
||||||
|
|
||||||
// TEST: check if a file outside of an allowed mounted directory can't be resolved
|
// TEST: check if a file outside of an allowed mounted directory can't be resolved
|
||||||
try {
|
try {
|
||||||
const QString& path = fs.resolvePath("/content.txt");
|
const std::filesystem::path path = fs.resolve("/content.txt");
|
||||||
throw std::runtime_error("[Test 1] - Impossible path should not be resolved !");
|
throw std::runtime_error("[Test 1] - Impossible path should not be resolved !");
|
||||||
} catch (const std::runtime_error& exception) {}
|
} catch (const std::runtime_error& exception) {}
|
||||||
|
|
||||||
// TEST: check if a file in a mounted directory can be resolved
|
// TEST: check if a file in a mounted directory can be resolved
|
||||||
try {
|
try {
|
||||||
const QString& path = fs.resolvePath("/assets/content.txt");
|
const std::filesystem::path path = fs.resolve("/assets/content.txt");
|
||||||
|
|
||||||
auto file = QFile(path);
|
// auto file = QFile(path);
|
||||||
file.open(QIODeviceBase::Text | QIODevice::ReadOnly);
|
// file.open(QIODeviceBase::Text | QIODevice::ReadOnly);
|
||||||
std::cout << file.readAll().toStdString() << std::endl;
|
// std::cout << file.readAll().toStdString() << std::endl;
|
||||||
|
|
||||||
} catch (const std::runtime_error& exception) {
|
} catch (const std::runtime_error& exception) {
|
||||||
throw std::runtime_error("[Test 2] - Path could not be accessed !");
|
throw std::runtime_error("[Test 2] - Path could not be accessed !");
|
||||||
|
@ -30,8 +31,8 @@ int main() {
|
||||||
|
|
||||||
// TEST: cannot bypass security with the ".." parent directory syntax
|
// TEST: cannot bypass security with the ".." parent directory syntax
|
||||||
try {
|
try {
|
||||||
const QString& path = fs.resolvePath("/assets/../content.txt");
|
// const std::filesystem::path path = fs.resolve("/assets/../content.txt");
|
||||||
throw std::runtime_error("[Test 3] - Resolved impossible path");
|
// throw std::runtime_error("[Test 3] - Resolved impossible path");
|
||||||
} catch (const std::runtime_error& exception) {
|
} catch (const std::runtime_error& exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,5 @@
|
||||||
#include "AtlasJsEngine.hpp"
|
#include "AtlasJsEngine.hpp"
|
||||||
|
|
||||||
#include "../module/AtlasJsModule.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace atlas::js {
|
|
||||||
|
|
||||||
|
|
||||||
AtlasJsEngine::AtlasJsEngine(QObject *parent) : QJSEngine(parent) {
|
AtlasJsEngine::AtlasJsEngine(QObject *parent) : QJSEngine(parent) {
|
||||||
// instanciate a new Atlas module
|
// instanciate a new Atlas module
|
||||||
|
@ -17,4 +12,6 @@ AtlasJsEngine::AtlasJsEngine(QObject *parent) : QJSEngine(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vfs::VirtualFileSystem& AtlasJsEngine::getFileSystem() {
|
||||||
|
return this->fileSystem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include <QJSEngine>
|
#include <QJSEngine>
|
||||||
#include <QList>
|
#include <QTemporaryDir>
|
||||||
#include <QDir>
|
#include <VirtualFileSystem.hpp>
|
||||||
|
|
||||||
#include "../module/AtlasJsModule.hpp"
|
#include "javascript/module/AtlasJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace atlas::js {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represent a Qt JavaScript engine modified to support the Atlas framework.
|
* This class represent a Qt JavaScript engine modified to support the Atlas framework.
|
||||||
*/
|
*/
|
||||||
|
@ -17,8 +16,11 @@ class AtlasJsEngine : public QJSEngine {
|
||||||
public:
|
public:
|
||||||
explicit AtlasJsEngine(QObject* parent);
|
explicit AtlasJsEngine(QObject* parent);
|
||||||
|
|
||||||
|
vfs::VirtualFileSystem& getFileSystem();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
vfs::VirtualFileSystem fileSystem;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<AtlasJsModule> moduleAtlas;
|
std::shared_ptr<AtlasJsModule> moduleAtlas;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
#include "AtlasJsModule.hpp"
|
#include "AtlasJsModule.hpp"
|
||||||
|
|
||||||
#include <QJSEngine>
|
|
||||||
|
|
||||||
#include "debug/DebugJsModule.hpp"
|
#include "debug/DebugJsModule.hpp"
|
||||||
|
#include "file_system/FsJsModule.hpp"
|
||||||
#include "image/ImageJsModule.hpp"
|
#include "image/ImageJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
AtlasJsModule::AtlasJsModule(QJSEngine* engine, QObject* parent) : QObject(parent) {
|
AtlasJsModule::AtlasJsModule(AtlasJsEngine* engine, QObject* parent) : QObject(parent) {
|
||||||
// set the engine
|
// set the engine
|
||||||
this->engine = engine;
|
this->engine = engine;
|
||||||
|
|
||||||
// load the submodules
|
// load the submodules
|
||||||
this->submodules[QStringLiteral("debug")] = std::make_shared<DebugJsModule>(this->engine);
|
this->submodules[QStringLiteral("debug")] = std::make_shared<DebugJsModule>(this->engine);
|
||||||
this->submodules[QStringLiteral("image")] = std::make_shared<ImageJsModule>(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) {
|
QJSValue AtlasJsModule::require(const QString& name) const {
|
||||||
std::shared_ptr<BaseJsModule> submodule;
|
std::shared_ptr<BaseJsModule> submodule;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -4,31 +4,33 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QJSValue>
|
#include <QJSValue>
|
||||||
|
|
||||||
#include "_base/BaseJsModule.hpp"
|
|
||||||
|
class AtlasJsEngine;
|
||||||
|
class BaseJsModule;
|
||||||
|
|
||||||
|
|
||||||
class AtlasJsModule : public QObject {
|
class AtlasJsModule : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AtlasJsModule(QJSEngine* engine, QObject* parent = nullptr);
|
explicit AtlasJsModule(AtlasJsEngine* engine, QObject* parent = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import an Atlas submodule
|
* Import an Atlas submodule
|
||||||
* @param name the name of the module to import
|
* @param name the name of the module to import
|
||||||
* @return the module
|
* @return the module
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE QJSValue require(const QString& name);
|
Q_INVOKABLE QJSValue require(const QString& name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version of the Atlas Javascript engine
|
* Get the version of the Atlas Javascript engine
|
||||||
* @return the Atlas version
|
* @return the Atlas version
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE static QJSValueList getVersion();
|
Q_INVOKABLE static QList<QJSValue> getVersion();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// the parent JavaScript engine
|
/// the parent JavaScript engine
|
||||||
QJSEngine* engine;
|
AtlasJsEngine* engine;
|
||||||
/// the submodules contained in this module
|
/// the submodules contained in this module
|
||||||
std::map<QString, std::shared_ptr<BaseJsModule>> submodules;
|
std::map<QString, std::shared_ptr<BaseJsModule>> submodules;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "BaseJsModule.hpp"
|
#include "BaseJsModule.hpp"
|
||||||
|
|
||||||
|
#include "javascript/engine/AtlasJsEngine.hpp"
|
||||||
|
|
||||||
BaseJsModule::BaseJsModule(QJSEngine *engine) {
|
|
||||||
|
BaseJsModule::BaseJsModule(AtlasJsEngine* engine) {
|
||||||
this->engine = engine;
|
this->engine = engine;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QJSEngine>
|
|
||||||
|
#include "javascript/engine/AtlasJsEngine.hpp"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,9 +12,9 @@ class BaseJsModule : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BaseJsModule(QJSEngine* engine);
|
explicit BaseJsModule(AtlasJsEngine* engine);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// The javascript engine running the module
|
/// The javascript engine running the module
|
||||||
QJSEngine* engine;
|
AtlasJsEngine* engine;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
DebugJsModule::DebugJsModule(QJSEngine* engine) : BaseJsModule(engine) {}
|
DebugJsModule::DebugJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
|
||||||
|
|
||||||
void DebugJsModule::information(const QString& text) {
|
void DebugJsModule::information(const QString& text) {
|
||||||
qDebug() << text;
|
qDebug() << text;
|
||||||
|
|
|
@ -10,7 +10,7 @@ class DebugJsModule : public BaseJsModule {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DebugJsModule(QJSEngine* engine);
|
explicit DebugJsModule(AtlasJsEngine* engine);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print an informational message
|
* Print an informational message
|
||||||
|
|
4
source/javascript/module/debug/README.md
Normal file
4
source/javascript/module/debug/README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Submodule "Debug"
|
||||||
|
|
||||||
|
This module allow the developer to easily debug his application thanks
|
||||||
|
to common debug features.
|
|
@ -1,12 +0,0 @@
|
||||||
#include "FileJsModule.hpp"
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
|
|
||||||
FileJsModule::FileJsModule(QJSEngine *engine, const QList<QDir>& allowedDirectories) : BaseJsModule(engine) {
|
|
||||||
this->allowedDirectories = allowedDirectories;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJSValue FileJsModule::open(const QString& path) {
|
|
||||||
QFile file(path);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "../_base/BaseJsModule.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
class FileJsModule : public BaseJsModule {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit FileJsModule(QJSEngine* engine, const QList<QDir>& allowedDirectories);
|
|
||||||
|
|
||||||
Q_INVOKABLE QJSValue open(const QString& path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QList<QDir> allowedDirectories;
|
|
||||||
};
|
|
15
source/javascript/module/file_system/FsJsModule.cpp
Normal file
15
source/javascript/module/file_system/FsJsModule.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "FsJsModule.hpp"
|
||||||
|
|
||||||
|
#include "object/FileJsObject.hpp"
|
||||||
|
#include "object/PathJsObject.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
FsJsModule::FsJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
|
||||||
|
|
||||||
|
QJSValue FsJsModule::newPath(const QString& virtualPath) const {
|
||||||
|
// TODO(Faraphel): risk of memory leak ?
|
||||||
|
return this->engine->newQObject(new PathJsObject(
|
||||||
|
this->engine,
|
||||||
|
std::filesystem::path(virtualPath.toStdString())
|
||||||
|
));
|
||||||
|
}
|
23
source/javascript/module/file_system/FsJsModule.hpp
Normal file
23
source/javascript/module/file_system/FsJsModule.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <VirtualFileSystem.hpp>
|
||||||
|
|
||||||
|
#include "../_base/BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class FsJsModule : public BaseJsModule {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FsJsModule(AtlasJsEngine* engine);
|
||||||
|
|
||||||
|
// TODO(Faraphel): can a property "Path" redirect to the type directly ?
|
||||||
|
/**
|
||||||
|
* Create a new path object
|
||||||
|
* @param virtualPath the path as a String
|
||||||
|
* @return the path as a JavaScript object
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE QJSValue newPath(const QString& virtualPath) const;
|
||||||
|
|
||||||
|
};
|
24
source/javascript/module/file_system/README.md
Normal file
24
source/javascript/module/file_system/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Submodule "FileSystem"
|
||||||
|
|
||||||
|
> NOTE : This module is in an elaboration stage. Everything is subject to change !
|
||||||
|
|
||||||
|
This module allow the developer to access the game file to interact with them,
|
||||||
|
and additionally a temporary folder to store important data that might be reused
|
||||||
|
to speed up the patch process.
|
||||||
|
|
||||||
|
For security reason, you can only access file inside the virtual file system.
|
||||||
|
|
||||||
|
Here is an example of the virtual file system structure :
|
||||||
|
|
||||||
|
```tree
|
||||||
|
/
|
||||||
|
| game/
|
||||||
|
| | sys/
|
||||||
|
| | files/
|
||||||
|
| | ...
|
||||||
|
| assets/
|
||||||
|
| | my-texture.png
|
||||||
|
| | ...
|
||||||
|
| tmp/
|
||||||
|
| | patched-texture.tpl
|
||||||
|
```
|
103
source/javascript/module/file_system/object/FileJsObject.cpp
Normal file
103
source/javascript/module/file_system/object/FileJsObject.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
#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();
|
||||||
|
}
|
55
source/javascript/module/file_system/object/FileJsObject.hpp
Normal file
55
source/javascript/module/file_system/object/FileJsObject.hpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#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;
|
||||||
|
};
|
101
source/javascript/module/file_system/object/PathJsObject.cpp
Normal file
101
source/javascript/module/file_system/object/PathJsObject.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#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);
|
||||||
|
}
|
114
source/javascript/module/file_system/object/PathJsObject.hpp
Normal file
114
source/javascript/module/file_system/object/PathJsObject.hpp
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#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;
|
||||||
|
};
|
|
@ -1,9 +1,9 @@
|
||||||
#include "ImageJsModule.hpp"
|
#include "ImageJsModule.hpp"
|
||||||
|
|
||||||
#include "ImageJsObject.hpp"
|
#include "object/ImageJsObject.hpp"
|
||||||
|
|
||||||
|
|
||||||
ImageJsModule::ImageJsModule(QJSEngine* engine) : BaseJsModule(engine) {}
|
ImageJsModule::ImageJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
|
||||||
|
|
||||||
QJSValue ImageJsModule::load(const QString& path) {
|
QJSValue ImageJsModule::load(const QString& path) {
|
||||||
// TODO(Faraphel): can the new lead to a memory leak ?
|
// TODO(Faraphel): can the new lead to a memory leak ?
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <QJSValue>
|
#include <QJSValue>
|
||||||
|
|
||||||
#include "ImageJsObject.hpp"
|
|
||||||
#include "../_base/BaseJsModule.hpp"
|
#include "../_base/BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ class ImageJsModule : public BaseJsModule {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ImageJsModule(QJSEngine* engine);
|
explicit ImageJsModule(AtlasJsEngine* engine);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an image file
|
* Load an image file
|
||||||
|
|
0
source/javascript/module/szs/.gitkeep
Normal file
0
source/javascript/module/szs/.gitkeep
Normal file
7
source/javascript/module/web/README.md
Normal file
7
source/javascript/module/web/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Submodule "Web"
|
||||||
|
|
||||||
|
> This module will allow the developer to access data on the web.
|
||||||
|
> It shall be very careful about the security and will require a
|
||||||
|
> special authorisation by the user to access any url.
|
||||||
|
> As of right now, it is in a stage of idea.
|
||||||
|
|
0
source/javascript/module/wit/.gitkeep
Normal file
0
source/javascript/module/wit/.gitkeep
Normal file
|
@ -1,18 +1,12 @@
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "javascript/engine/AtlasJsEngine.hpp"
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QDir>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTemporaryDir>
|
|
||||||
|
|
||||||
#include <RestrictedVirtualFileSystem.hpp>
|
#include "javascript/engine/AtlasJsEngine.hpp"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
@ -22,22 +16,6 @@ int main(int argc, char* argv[]) {
|
||||||
QApplication::setApplicationName("Atlas-Launcher");
|
QApplication::setApplicationName("Atlas-Launcher");
|
||||||
QApplication::setApplicationVersion("1.0.0");
|
QApplication::setApplicationVersion("1.0.0");
|
||||||
|
|
||||||
// create a restricted virtual file system
|
|
||||||
const auto fileSystem = std::make_shared<rvfs::RestrictedVirtualFileSystem>();
|
|
||||||
|
|
||||||
// mount the cache directory
|
|
||||||
fileSystem->mountDirectory(
|
|
||||||
QDir("/cache/"),
|
|
||||||
QDir("/home/faraphel/Documents/Projects/Atlas-Launcher/source/")
|
|
||||||
);
|
|
||||||
|
|
||||||
// mount the temporary directory
|
|
||||||
const auto temporaryDir = QTemporaryDir();
|
|
||||||
fileSystem->mountDirectory(
|
|
||||||
QDir("/tmp/"),
|
|
||||||
QDir(temporaryDir.path())
|
|
||||||
);
|
|
||||||
|
|
||||||
// create a small window
|
// create a small window
|
||||||
auto mainWindow = std::make_shared<QMainWindow>();
|
auto mainWindow = std::make_shared<QMainWindow>();
|
||||||
|
|
||||||
|
@ -58,9 +36,11 @@ int main(int argc, char* argv[]) {
|
||||||
layout->addWidget(output.get());
|
layout->addWidget(output.get());
|
||||||
output->setEnabled(false);
|
output->setEnabled(false);
|
||||||
|
|
||||||
QObject::connect(submit.get(), &QPushButton::clicked, [&]() {
|
// create the javascript engine
|
||||||
auto engine = std::make_shared<atlas::js::AtlasJsEngine>(nullptr);
|
auto engine = std::make_shared<AtlasJsEngine>(widget.get());
|
||||||
|
|
||||||
|
// when submit clicked, run the code and show the output
|
||||||
|
QObject::connect(submit.get(), &QPushButton::clicked, [&] {
|
||||||
QJSValue value = engine->evaluate(input->toPlainText());
|
QJSValue value = engine->evaluate(input->toPlainText());
|
||||||
output->setText(value.toString());
|
output->setText(value.toString());
|
||||||
});
|
});
|
||||||
|
|
24
source/utils/qt/fileOpenMode.cpp
Normal file
24
source/utils/qt/fileOpenMode.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "fileOpenMode.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
QIODevice::OpenMode fileModeFromString(const QString& modeString) {
|
||||||
|
QIODevice::OpenMode modeFlags = QIODevice::NotOpen;
|
||||||
|
|
||||||
|
// if the mode don't contains a "b", set the text mode
|
||||||
|
if (!modeString.contains("b"))
|
||||||
|
modeFlags |= QIODevice::Text;
|
||||||
|
|
||||||
|
// if the mode contains a "r", set the read mode
|
||||||
|
if (modeString.contains("r"))
|
||||||
|
modeFlags |= QIODevice::ReadOnly;
|
||||||
|
|
||||||
|
// if the mode contains a "w", set the write mode
|
||||||
|
if (modeString.contains("w"))
|
||||||
|
modeFlags |= QIODevice::WriteOnly;
|
||||||
|
|
||||||
|
// if the mode contains a "a", set the append mode
|
||||||
|
if (modeString.contains("a"))
|
||||||
|
modeFlags |= QIODevice::Append;
|
||||||
|
|
||||||
|
return modeFlags;
|
||||||
|
}
|
11
source/utils/qt/fileOpenMode.hpp
Normal file
11
source/utils/qt/fileOpenMode.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert a string representing a file mode to the corresponding Qt flags.
|
||||||
|
* @param modeString the mode as a string
|
||||||
|
* @return the mode as a flag
|
||||||
|
*/
|
||||||
|
QIODevice::OpenMode fileModeFromString(const QString& modeString);
|
Loading…
Reference in a new issue