diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index da699ea..84ecece 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,18 +10,20 @@ LuaEngine Windows: script: - mkdir -p build - cd build - - qmake CONFIG+=WITH_LUAENGINERUN ../luaengine.pro + - qmake CONFIG+=WITH_LUAENGINECOM CONFIG+=WITH_LUAENGINERUN ../luaengine.pro - make -j4 - cp -Rf src/luaenginecore/release/LuaEngine.dll ../ - cp -Rf src/luaenginegui/release/LuaEngineGui.dll ../ - cp -Rf src/luaengineio/release/LuaEngineIO.dll ../ - cp -Rf src/luaengineos/release/LuaEngineOS.dll ../ - cp -Rf src/luaengine/release/LuaEngine.exe ../ + - cp -Rf src/luaenginec/release/luaenginec.exe ../ - cd .. artifacts: paths: - "LuaEngine.dll" - "LuaEngine.exe" + - "luaenginec.exe" - "LuaEngineGui.dll" - "LuaEngineIO.dll" - "LuaEngineOS.dll" @@ -34,13 +36,13 @@ LuaEngineApp: script: - mkdir -p build - cd build - - qmake-static CONFIG+=WITH_LUAENGINEAPP ../luaengine.pro + - qmake-static CONFIG+=WITH_LUAENGINEAPP DEFINES+=LUAENGINE_FOOTER_SCRIPT ../luaengine.pro - make -j4 - - cp -Rf src/luaengineapp/release/LuaEngineApp.exe ../ + - cp -Rf src/luaengineapp/release/LuaEngineApp.exe ../windows.le - cd .. artifacts: paths: - - "LuaEngineApp.exe" + - "windows.le" LuaEngine Setup: stage: deploy diff --git a/src/luaengine/main.cpp b/src/luaengine/main.cpp index 56745b3..cc3bd67 100644 --- a/src/luaengine/main.cpp +++ b/src/luaengine/main.cpp @@ -21,7 +21,6 @@ #include #include #include -#include int main(int argc, char *argv[]) { diff --git a/src/luaengineapp/luaengineapp.pro b/src/luaengineapp/luaengineapp.pro index ebdf88e..42cf37f 100644 --- a/src/luaengineapp/luaengineapp.pro +++ b/src/luaengineapp/luaengineapp.pro @@ -36,11 +36,12 @@ INCLUDEPATH += \ SOURCES += \ main.cpp -win32: HEADERS += \ - resource.h - OTHER_FILES += \ app.lua \ app.rc -win32: RC_FILE = app.rc + +!defined(LUAENGINE_FOOTER_SCRIPT) { + win32: HEADERS += resource.h + win32: RC_FILE = app.rc +} diff --git a/src/luaengineapp/main.cpp b/src/luaengineapp/main.cpp index 9074f5c..60a87cf 100644 --- a/src/luaengineapp/main.cpp +++ b/src/luaengineapp/main.cpp @@ -19,6 +19,7 @@ #include "LuaEngineIO.h" #include "LuaEngineOS.h" #include +#include #include #include #ifdef Q_OS_WIN @@ -30,7 +31,6 @@ int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); QApplication a(argc, argv); - #ifdef Q_OS_WIN #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) if (QSysInfo::windowsVersion() >= 0x0080) @@ -42,14 +42,37 @@ int main(int argc, char *argv[]) QByteArray luaScript; #ifdef Q_OS_WIN +#ifdef LUAENGINE_FOOTER_SCRIPT { - HMODULE handle = GetModuleHandleW(NULL); - HRSRC resource = FindResourceW(handle, MAKEINTRESOURCE(IDR_SCRIPT1), L"SCRIPT"); - HGLOBAL resourceData = LoadResource(handle, resource); - DWORD size = SizeofResource(handle, resource); - const char *data = static_cast(LockResource(resourceData)); - luaScript = QByteArray(data, size); + QFile executable(a.arguments().at(0)); + if (executable.open(QIODevice::ReadOnly)) { + qint64 executableSize = executable.size(); + executable.seek(executableSize - 6); + QByteArray footer = executable.read(6); + if (footer.right(2) == QByteArray("\xb4\x00", 2)) { + bool sizeOk; + qint64 scriptSize = footer.left(4).toHex().toLongLong(&sizeOk, 16); + if (sizeOk) { + executable.seek(executableSize - scriptSize - 6); + luaScript = executable.read(scriptSize); + } + } + else { + QMessageBox::information(NULL, "Lua Engine", "Lua Engine Script footer not found!"); + } + } } +#else + { + HMODULE handle = GetModuleHandleW(NULL); + HRSRC resource = FindResourceW(handle, MAKEINTRESOURCE(IDR_SCRIPT1), L"SCRIPT"); + HGLOBAL resourceData = LoadResource(handle, resource); + DWORD size = SizeofResource(handle, resource); + const char *data = static_cast(LockResource(resourceData)); + luaScript = QByteArray(data, size); + } + } +#endif #endif LuaEngineGui luaEngineGui; @@ -63,7 +86,7 @@ int main(int argc, char *argv[]) } if (luaEngineGui.executeLuaFunction("main", arguments, true)) { - QVariant variant = luaEngineGui.returnVariant(); + const QVariant variant = luaEngineGui.returnVariant(); if (variant.type() == QVariant::Int || variant.type() == QVariant::LongLong) { return variant.toInt(); } diff --git a/src/luaenginec/luaenginec.pro b/src/luaenginec/luaenginec.pro new file mode 100644 index 0000000..a43d05b --- /dev/null +++ b/src/luaenginec/luaenginec.pro @@ -0,0 +1,34 @@ +#/***************************************************************************** +#* luaEngine Lua Engine for Qt +#* Copyright (C) 2019 Syping +#* +#* Licensed under the Apache License, Version 2.0 (the "License"); +#* you may not use this file except in compliance with the License. +#* You may obtain a copy of the License at +#* +#* http://www.apache.org/licenses/LICENSE-2.0 +#* +#* Unless required by applicable law or agreed to in writing, software +#* distributed under the License is distributed on an "AS IS" BASIS, +#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#* See the License for the specific language governing permissions and +#* limitations under the License. +#*****************************************************************************/ + +QT += core +QT -= gui widgets +TARGET = luaenginec +CONFIG += c++11 + +static: DEFINES += LUAENGINE_STATIC + +CONFIG(debug, debug|release): win32: LIBS += -L$$OUT_PWD/../luaenginecore/debug -lLuaEngine +CONFIG(release, debug|release): win32: LIBS += -L$$OUT_PWD/../luaenginecore/release -lLuaEngine +unix: LIBS += -L$$OUT_PWD/../luaenginecore -lLuaEngine + +INCLUDEPATH += \ + ../luaenginecore/lua \ + ../luaenginecore/luaengine \ + +SOURCES += \ + main.cpp diff --git a/src/luaenginec/main.cpp b/src/luaenginec/main.cpp new file mode 100644 index 0000000..fabd1b9 --- /dev/null +++ b/src/luaenginec/main.cpp @@ -0,0 +1,100 @@ +/***************************************************************************** +* luaEngine Lua Engine for Qt +* Copyright (C) 2018-2019 Syping +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*****************************************************************************/ + +#include "LuaEngine.h" +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + a.setApplicationName("luaenginec"); + a.setApplicationVersion("0.1"); + + QCommandLineParser parser; + + QCommandLineOption pLuaEngineOption(QStringList() << "le" << "luaengine", "Location of portable Lua Engine executor.", "luaengine"); + parser.addOption(pLuaEngineOption); + + parser.addPositionalArgument("source", "Source file to build."); + parser.addPositionalArgument("output", "Output file."); + + parser.addHelpOption(); + parser.addVersionOption(); + + parser.process(a); + + const QStringList args = parser.positionalArguments(); + + QFile luaScript(args.at(0)); + + LuaEngine luaEngine; + if (!luaEngine.loadLuaScript(&luaScript)) { + QTextStream(stderr) << "Failed to load \"" << args.at(0) << "\"." << endl; + return 1; + } + + QSaveFile outputFile(args.at(1)); + if (!outputFile.open(QIODevice::WriteOnly)) { + QTextStream(stderr) << "Failed to open \"" << args.at(1) << "\"." << endl; + return 1; + } + + QString pLuaEngine = parser.value(pLuaEngineOption); + if (!pLuaEngine.isEmpty()) { + QFile portableLuaEngine(pLuaEngine); + if (!portableLuaEngine.open(QIODevice::ReadOnly)) { + outputFile.cancelWriting(); + outputFile.commit(); + QTextStream(stderr) << "Failed to open \"" << pLuaEngine << "\"." << endl; + return 1; + } + outputFile.write(portableLuaEngine.readAll()); + } + + const QByteArray luaDump = luaEngine.dumpLuaScript(); + int dumpSize = luaDump.size(); + outputFile.write(luaDump); + + if (!pLuaEngine.isEmpty()) { + QByteArray lengthArray = QByteArray::number(dumpSize, 16); + if (lengthArray.size() > 8) { + outputFile.cancelWriting(); + outputFile.commit(); + QTextStream(stderr) << "Lua Engine script is too large." << endl; + return 1; + } + else { + while (lengthArray.size() != 8) { + lengthArray.insert(0, "0"); + } + } + outputFile.write(QByteArray::fromHex(lengthArray)); + outputFile.write("\xb4\x00", 2); + } + + if (!outputFile.commit()) { + QTextStream(stderr) << "Failed to write \"" << args.at(1) << "\"." << endl; + return 1; + } + + return 0; +} diff --git a/src/luaenginecore/luaengine/LuaEngine.cpp b/src/luaenginecore/luaengine/LuaEngine.cpp index e7638f3..23070ce 100644 --- a/src/luaenginecore/luaengine/LuaEngine.cpp +++ b/src/luaenginecore/luaengine/LuaEngine.cpp @@ -20,7 +20,6 @@ #include #include #include -#include LuaEngine::LuaEngine(QObject *parent, bool loadBaseLibraries) : QObject(parent) { @@ -53,6 +52,13 @@ void LuaEngine::loadBaseLibraries() luaL_openlibs(L); } +int LuaEngine::luaEngineWriter_p(lua_State *L_p, const void *buffer, size_t size, void *array) +{ + Q_UNUSED(L_p) + ((QByteArray*)array)->append(QByteArray(static_cast(buffer), (int)size)); + return 0; +} + int LuaEngine::luaEngineVersion_p(lua_State *L_p) { pushVariant(L_p, "0.1"); @@ -83,10 +89,44 @@ int LuaEngine::luaEnginePlatform_p(lua_State *L_p) return 1; } -bool LuaEngine::executeLuaScript(const QByteArray &data) +QByteArray LuaEngine::dumpLuaScript() +{ + QByteArray array; + lua_lock(L); + lua_dump(L, luaEngineWriter_p, (void*)&array, 1); + lua_unlock(L); + return array; +} + +bool LuaEngine::loadLuaScript(const QByteArray &data) { int result = luaL_loadbuffer(L, data.data(), data.size(), "script"); - if (result == 0) + return (result == 0) ? true : false; +} + +bool LuaEngine::loadLuaScript(QIODevice *device, bool closeDevice) +{ + QByteArray data; + if (!device->isOpen()) { + if (device->open(QIODevice::ReadOnly)) { + data = device->readAll(); + if (closeDevice) + device->close(); + return loadLuaScript(data); + } + } + else { + data = device->readAll(); + if (closeDevice) + device->close(); + return loadLuaScript(data); + } + return false; +} + +bool LuaEngine::executeLuaScript(const QByteArray &data) +{ + if (loadLuaScript(data)) return (lua_pcall(L, 0, LUA_MULTRET, 0) == 0) ? true : false; return false; } diff --git a/src/luaenginecore/luaengine/LuaEngine.h b/src/luaenginecore/luaengine/LuaEngine.h index 8d1bc42..51bf964 100644 --- a/src/luaenginecore/luaengine/LuaEngine.h +++ b/src/luaenginecore/luaengine/LuaEngine.h @@ -29,6 +29,7 @@ extern "C" { #include "../lua/lua.h" #include "../lua/lualib.h" #include "../lua/lauxlib.h" +#include "../lua/llimits.h" } class LUAENGINESHARED_EXPORT LuaEngine : public QObject @@ -39,6 +40,9 @@ public: ~LuaEngine(); lua_State* luaState(); void loadBaseLibraries(); + QByteArray dumpLuaScript(); + bool loadLuaScript(const QByteArray &data); + bool loadLuaScript(QIODevice *device, bool closeDevice = true); bool executeLuaScript(const QByteArray &data); bool executeLuaScript(QIODevice *device, bool closeDevice = true); bool executeLuaFunction(const char *name, bool requireReturn = false); @@ -74,6 +78,7 @@ public: private: lua_State *L; + static int luaEngineWriter_p(lua_State *L_p, const void *buffer, size_t size, void *array); static int luaEngineVersion_p(lua_State *L_p); static int luaEnginePlatform_p(lua_State *L_p); static int luaObjectDelete_p(lua_State *L_p); diff --git a/src/src.pro b/src/src.pro index 29d94f9..8c0775a 100644 --- a/src/src.pro +++ b/src/src.pro @@ -25,3 +25,4 @@ SUBDIRS += luaenginecore \ CONFIG(WITH_LUAENGINEAPP): SUBDIRS += luaengineapp CONFIG(WITH_LUAENGINERUN): SUBDIRS += luaengine +CONFIG(WITH_LUAENGINECOM): SUBDIRS += luaenginec