base for the Atlas JavaScript engine : implemented the Engine, a virtual filesytem and prepared the library system.
This commit is contained in:
parent
719d815b2d
commit
308124c99f
28 changed files with 655 additions and 197 deletions
199
.gitignore
vendored
199
.gitignore
vendored
|
@ -1,196 +1,7 @@
|
||||||
# ---> Python
|
# IDE
|
||||||
# Byte-compiled / optimized / DLL files
|
.idea/
|
||||||
__pycache__/
|
.venv/
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
# CMake
|
||||||
*.so
|
cmake-*/
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# poetry
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
||||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
||||||
# commonly ignored for libraries.
|
|
||||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
||||||
#poetry.lock
|
|
||||||
|
|
||||||
# pdm
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
||||||
#pdm.lock
|
|
||||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
||||||
# in version control.
|
|
||||||
# https://pdm.fming.dev/#use-with-ide
|
|
||||||
.pdm.toml
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|
||||||
# PyCharm
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
#.idea/
|
|
||||||
|
|
||||||
# ---> C++
|
|
||||||
# Prerequisites
|
|
||||||
*.d
|
|
||||||
|
|
||||||
# Compiled Object files
|
|
||||||
*.slo
|
|
||||||
*.lo
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
*.dll
|
|
||||||
|
|
||||||
# Fortran module files
|
|
||||||
*.mod
|
|
||||||
*.smod
|
|
||||||
|
|
||||||
# Compiled Static libraries
|
|
||||||
*.lai
|
|
||||||
*.la
|
|
||||||
*.a
|
|
||||||
*.lib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
|
|
||||||
|
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,9 +1,9 @@
|
||||||
[submodule ".mods/Atlas"]
|
[submodule ".mods/Atlas"]
|
||||||
path = .mods/Atlas
|
path = .mods/Atlas
|
||||||
url = https://git.faraphel.fr/Atlas/Atlas-Mod
|
url = https://git.faraphel.fr/Atlas/Atlas-Mod
|
||||||
[submodule "library-szs"]
|
[submodule "external/szs"]
|
||||||
path = external/szs
|
path = external/szs
|
||||||
url = https://git.faraphel.fr/Atlas/library-szs
|
url = https://git.faraphel.fr/Atlas/library-szs
|
||||||
[submodule "library-wit"]
|
[submodule "external/wit"]
|
||||||
path = external/szs
|
path = external/wit
|
||||||
url = https://git.faraphel.fr/Atlas/library-wit
|
url = https://git.faraphel.fr/Atlas/library-wit
|
||||||
|
|
1
.mods/Atlas
Submodule
1
.mods/Atlas
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 997d361d05a2f022d027118f6d1cb5c9642586a5
|
50
CMakeLists.txt
Normal file
50
CMakeLists.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
cmake_minimum_required(VERSION 3.28)
|
||||||
|
project(Atlas-Launcher 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
|
||||||
|
Gui
|
||||||
|
Widgets
|
||||||
|
Qml
|
||||||
|
)
|
||||||
|
add_executable(Atlas-Launcher
|
||||||
|
source/main.cpp
|
||||||
|
source/javascript/module/AtlasJsModule.cpp
|
||||||
|
source/javascript/module/AtlasJsModule.hpp
|
||||||
|
source/javascript/engine/AtlasJsEngine.cpp
|
||||||
|
source/javascript/engine/AtlasJsEngine.hpp
|
||||||
|
source/javascript/module/debug/DebugJsModule.cpp
|
||||||
|
source/javascript/module/debug/DebugJsModule.hpp
|
||||||
|
source/javascript/module/image/ImageJsModule.cpp
|
||||||
|
source/javascript/module/image/ImageJsModule.hpp
|
||||||
|
source/javascript/module/image/ImageJsObject.cpp
|
||||||
|
source/javascript/module/image/ImageJsObject.hpp
|
||||||
|
source/javascript/module/_base/BaseJsModule.cpp
|
||||||
|
source/javascript/module/_base/BaseJsModule.hpp
|
||||||
|
source/javascript/module/file/FileJsModule.cpp
|
||||||
|
source/javascript/module/file/FileJsModule.hpp
|
||||||
|
)
|
||||||
|
target_link_libraries(Atlas-Launcher PRIVATE
|
||||||
|
# Tools
|
||||||
|
RVFS
|
||||||
|
SZS
|
||||||
|
|
||||||
|
# Qt Framework
|
||||||
|
Qt::Core
|
||||||
|
Qt::Gui
|
||||||
|
Qt::Widgets
|
||||||
|
Qt::Qml
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
add_subdirectory(external/rvfs)
|
||||||
|
add_subdirectory(external/szs)
|
27
external/rvfs/CMakeLists.txt
vendored
Normal file
27
external/rvfs/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
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)
|
10
external/rvfs/README.md
vendored
Normal file
10
external/rvfs/README.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Restricted Virtual File System
|
||||||
|
This is a micro-library used to create a virtual file system to restrict access
|
||||||
|
to the host file system while still being able to mount directories that can be accessed.
|
||||||
|
|
||||||
|
As of right now, this is an incredibly simple implementation of this system that
|
||||||
|
work by mapping virtual directory path to a corresponding real directory path, replacing
|
||||||
|
them while resolving the path and reject all others paths that have not been mounted
|
||||||
|
to avoid access to other files.
|
||||||
|
|
||||||
|
It does not emulate a real file system nor allow control over permissions of the files.
|
62
external/rvfs/include/RestrictedVirtualFileSystem.hpp
vendored
Normal file
62
external/rvfs/include/RestrictedVirtualFileSystem.hpp
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
65
external/rvfs/source/RestrictedVirtualFileSystem.cpp
vendored
Normal file
65
external/rvfs/source/RestrictedVirtualFileSystem.cpp
vendored
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#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
Normal file
36
external/rvfs/tests/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
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)
|
1
external/rvfs/tests/_assets/content.txt
vendored
Normal file
1
external/rvfs/tests/_assets/content.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
This is a simple text file.
|
37
external/rvfs/tests/test-restriction.cpp
vendored
Normal file
37
external/rvfs/tests/test-restriction.cpp
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <RestrictedVirtualFileSystem.hpp>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// TODO(Faraphel): use a real unit test framework ?
|
||||||
|
|
||||||
|
// create a basic rvfs
|
||||||
|
rvfs::RestrictedVirtualFileSystem fs;
|
||||||
|
|
||||||
|
// mount a directory into our system
|
||||||
|
fs.mountDirectory(QDir("/assets/"), QDir("./_assets/"));
|
||||||
|
|
||||||
|
// TEST: check if a file outside of an allowed mounted directory can't be resolved
|
||||||
|
try {
|
||||||
|
const QString& path = fs.resolvePath("/content.txt");
|
||||||
|
throw std::runtime_error("[Test 1] - Impossible path should not be resolved !");
|
||||||
|
} catch (const std::runtime_error& exception) {}
|
||||||
|
|
||||||
|
// TEST: check if a file in a mounted directory can be resolved
|
||||||
|
try {
|
||||||
|
const QString& path = fs.resolvePath("/assets/content.txt");
|
||||||
|
|
||||||
|
auto file = QFile(path);
|
||||||
|
file.open(QIODeviceBase::Text | QIODevice::ReadOnly);
|
||||||
|
std::cout << file.readAll().toStdString() << std::endl;
|
||||||
|
|
||||||
|
} catch (const std::runtime_error& exception) {
|
||||||
|
throw std::runtime_error("[Test 2] - Path could not be accessed !");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST: cannot bypass security with the ".." parent directory syntax
|
||||||
|
try {
|
||||||
|
const QString& path = fs.resolvePath("/assets/../content.txt");
|
||||||
|
throw std::runtime_error("[Test 3] - Resolved impossible path");
|
||||||
|
} catch (const std::runtime_error& exception) {
|
||||||
|
}
|
||||||
|
}
|
1
external/szs
vendored
Submodule
1
external/szs
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 3b292fbcad336ebb2d9137a379c8a9cdaf945162
|
1
external/wit
vendored
Submodule
1
external/wit
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 80328498a1f2446a67a1df55900edb63e6e93bb0
|
20
source/javascript/engine/AtlasJsEngine.cpp
Normal file
20
source/javascript/engine/AtlasJsEngine.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "AtlasJsEngine.hpp"
|
||||||
|
|
||||||
|
#include "../module/AtlasJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace atlas::js {
|
||||||
|
|
||||||
|
|
||||||
|
AtlasJsEngine::AtlasJsEngine(QObject *parent) : QJSEngine(parent) {
|
||||||
|
// instanciate a new Atlas module
|
||||||
|
this->moduleAtlas = std::make_unique<AtlasJsModule>(this);
|
||||||
|
|
||||||
|
// convert it into a javascript object
|
||||||
|
const QJSValue jsModuleAtlas = this->newQObject(this->moduleAtlas.get());
|
||||||
|
// make it accessible as "atlas" in the javascript code
|
||||||
|
this->globalObject().setProperty("atlas", jsModuleAtlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
24
source/javascript/engine/AtlasJsEngine.hpp
Normal file
24
source/javascript/engine/AtlasJsEngine.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QJSEngine>
|
||||||
|
#include <QList>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include "../module/AtlasJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace atlas::js {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represent a Qt JavaScript engine modified to support the Atlas framework.
|
||||||
|
*/
|
||||||
|
class AtlasJsEngine : public QJSEngine {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AtlasJsEngine(QObject* parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<AtlasJsModule> moduleAtlas;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
47
source/javascript/module/AtlasJsModule.cpp
Normal file
47
source/javascript/module/AtlasJsModule.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "AtlasJsModule.hpp"
|
||||||
|
|
||||||
|
#include <QJSEngine>
|
||||||
|
|
||||||
|
#include "debug/DebugJsModule.hpp"
|
||||||
|
#include "image/ImageJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
AtlasJsModule::AtlasJsModule(QJSEngine* 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("image")] = std::make_shared<ImageJsModule>(this->engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJSValue AtlasJsModule::require(const QString& name) {
|
||||||
|
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;
|
||||||
|
}
|
34
source/javascript/module/AtlasJsModule.hpp
Normal file
34
source/javascript/module/AtlasJsModule.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QJSValue>
|
||||||
|
|
||||||
|
#include "_base/BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class AtlasJsModule : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AtlasJsModule(QJSEngine* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version of the Atlas Javascript engine
|
||||||
|
* @return the Atlas version
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE static QJSValueList getVersion();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the parent JavaScript engine
|
||||||
|
QJSEngine* engine;
|
||||||
|
/// the submodules contained in this module
|
||||||
|
std::map<QString, std::shared_ptr<BaseJsModule>> submodules;
|
||||||
|
};
|
6
source/javascript/module/_base/BaseJsModule.cpp
Normal file
6
source/javascript/module/_base/BaseJsModule.cpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
BaseJsModule::BaseJsModule(QJSEngine *engine) {
|
||||||
|
this->engine = engine;
|
||||||
|
}
|
19
source/javascript/module/_base/BaseJsModule.hpp
Normal file
19
source/javascript/module/_base/BaseJsModule.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QJSEngine>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for an Atlas JavaScript submodule
|
||||||
|
*/
|
||||||
|
class BaseJsModule : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseJsModule(QJSEngine* engine);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// The javascript engine running the module
|
||||||
|
QJSEngine* engine;
|
||||||
|
};
|
10
source/javascript/module/debug/DebugJsModule.cpp
Normal file
10
source/javascript/module/debug/DebugJsModule.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include "DebugJsModule.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
|
DebugJsModule::DebugJsModule(QJSEngine* engine) : BaseJsModule(engine) {}
|
||||||
|
|
||||||
|
void DebugJsModule::information(const QString& text) {
|
||||||
|
qDebug() << text;
|
||||||
|
}
|
19
source/javascript/module/debug/DebugJsModule.hpp
Normal file
19
source/javascript/module/debug/DebugJsModule.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../_base/BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module implements useful feature to help with debugging
|
||||||
|
*/
|
||||||
|
class DebugJsModule : public BaseJsModule {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DebugJsModule(QJSEngine* engine);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an informational message
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE static void information(const QString& text);
|
||||||
|
};
|
12
source/javascript/module/file/FileJsModule.cpp
Normal file
12
source/javascript/module/file/FileJsModule.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#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);
|
||||||
|
}
|
18
source/javascript/module/file/FileJsModule.hpp
Normal file
18
source/javascript/module/file/FileJsModule.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#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;
|
||||||
|
};
|
11
source/javascript/module/image/ImageJsModule.cpp
Normal file
11
source/javascript/module/image/ImageJsModule.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "ImageJsModule.hpp"
|
||||||
|
|
||||||
|
#include "ImageJsObject.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
ImageJsModule::ImageJsModule(QJSEngine* engine) : BaseJsModule(engine) {}
|
||||||
|
|
||||||
|
QJSValue ImageJsModule::load(const QString& path) {
|
||||||
|
// TODO(Faraphel): can the new lead to a memory leak ?
|
||||||
|
return this->engine->newQObject(new ImageJsObject(path));
|
||||||
|
}
|
23
source/javascript/module/image/ImageJsModule.hpp
Normal file
23
source/javascript/module/image/ImageJsModule.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QJSValue>
|
||||||
|
|
||||||
|
#include "ImageJsObject.hpp"
|
||||||
|
#include "../_base/BaseJsModule.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A module to manipulate image file
|
||||||
|
*/
|
||||||
|
class ImageJsModule : public BaseJsModule {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImageJsModule(QJSEngine* engine);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an image file
|
||||||
|
* @param
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE QJSValue load(const QString& path);
|
||||||
|
};
|
20
source/javascript/module/image/ImageJsObject.cpp
Normal file
20
source/javascript/module/image/ImageJsObject.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "ImageJsObject.hpp"
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
|
||||||
|
ImageJsObject::ImageJsObject(const QString& path) {
|
||||||
|
this->_internal = std::make_unique<QImage>(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ImageJsObject::getWidth() {
|
||||||
|
return this->_internal->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ImageJsObject::getHeight() {
|
||||||
|
return this->_internal->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ImageJsObject::getSize() {
|
||||||
|
return this->_internal->size();
|
||||||
|
}
|
22
source/javascript/module/image/ImageJsObject.hpp
Normal file
22
source/javascript/module/image/ImageJsObject.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
|
||||||
|
class ImageJsObject : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImageJsObject(const QString& path);
|
||||||
|
|
||||||
|
Q_INVOKABLE std::size_t getWidth();
|
||||||
|
Q_INVOKABLE std::size_t getHeight();
|
||||||
|
Q_INVOKABLE QSize getSize();
|
||||||
|
|
||||||
|
// TODO(Faraphel): implement copy / paste, fill, shapes, mirror, resize, expand, shrink, crop, map...
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<QImage> _internal;
|
||||||
|
};
|
||||||
|
|
71
source/main.cpp
Normal file
71
source/main.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "javascript/engine/AtlasJsEngine.hpp"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
|
#include <RestrictedVirtualFileSystem.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
// application informations
|
||||||
|
QApplication application(argc, argv);
|
||||||
|
QApplication::setOrganizationDomain("faraphel.fr");
|
||||||
|
QApplication::setApplicationName("Atlas-Launcher");
|
||||||
|
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
|
||||||
|
auto mainWindow = std::make_shared<QMainWindow>();
|
||||||
|
|
||||||
|
auto widget = std::make_shared<QWidget>();
|
||||||
|
mainWindow->setCentralWidget(widget.get());
|
||||||
|
|
||||||
|
auto layout = std::make_shared<QVBoxLayout>();
|
||||||
|
widget->setLayout(layout.get());
|
||||||
|
|
||||||
|
auto input = std::make_shared<QTextEdit>();
|
||||||
|
layout->addWidget(input.get());
|
||||||
|
|
||||||
|
auto submit = std::make_shared<QPushButton>();
|
||||||
|
layout->addWidget(submit.get());
|
||||||
|
submit->setText("Run");
|
||||||
|
|
||||||
|
auto output = std::make_shared<QTextEdit>();
|
||||||
|
layout->addWidget(output.get());
|
||||||
|
output->setEnabled(false);
|
||||||
|
|
||||||
|
QObject::connect(submit.get(), &QPushButton::clicked, [&]() {
|
||||||
|
auto engine = std::make_shared<atlas::js::AtlasJsEngine>(nullptr);
|
||||||
|
|
||||||
|
QJSValue value = engine->evaluate(input->toPlainText());
|
||||||
|
output->setText(value.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow->show();
|
||||||
|
|
||||||
|
return QApplication::exec();
|
||||||
|
}
|
Loading…
Reference in a new issue