diff options
| author | saturneric <[email protected]> | 2026-09-19 14:23:07 +0200 |
|---|---|---|
| committer | saturneric <[email protected]> | 2026-09-19 14:23:07 +0200 |
| commit | 92f4cb0cecfa9887d3ab7395c9a88de7ec69266d (patch) | |
| tree | e4e4c200e613855b006a7770e8ae3235fd2f4344 | |
| parent | fix(modules): correct module lifecycle setup (diff) | |
| download | modules-92f4cb0cecfa9887d3ab7395c9a88de7ec69266d.tar.gz modules-92f4cb0cecfa9887d3ab7395c9a88de7ec69266d.zip | |
refactor(module): relocate module author headers
- remove duplicated module author headers from the top-level include path
- rely on gf_module_runtime to expose the runtime-owned interfaces
- keep only SDK headers in the global include directories
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | include/GFModule.h | 65 | ||||
| -rw-r--r-- | include/GFModuleBootstrap.h | 133 | ||||
| -rw-r--r-- | include/GFModuleCommonUtils.hpp | 37 | ||||
| -rw-r--r-- | include/GFModuleConvert.h | 216 | ||||
| -rw-r--r-- | include/GFModuleDefine.h | 35 | ||||
| -rw-r--r-- | include/GFModuleEvent.h | 236 | ||||
| -rw-r--r-- | include/GFModuleExport.h | 69 | ||||
| -rw-r--r-- | include/GFModuleI18n.h | 102 | ||||
| -rw-r--r-- | include/GFModuleLog.h | 77 | ||||
| -rw-r--r-- | include/GFModuleMemory.h | 215 |
11 files changed, 3 insertions, 1186 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e6d13a4..863b04c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,10 @@ set(SDK_LIB_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") message(STATUS "GpgFrontend Modules SDK Headers Path: ${SDK_INCLUDE_PATH} ") message(STATUS "GpgFrontend Modules SDK Library Path: ${SDK_LIB_PATH} ") +# The module author surface now lives with the runtime that implements it +# (src/module_runtime/include), and gf_add_module() puts it on the path by +# linking gf_module_runtime. Only the SDK headers are still needed here. include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include ${SDK_INCLUDE_PATH} ) diff --git a/include/GFModule.h b/include/GFModule.h deleted file mode 100644 index 740ed81..0000000 --- a/include/GFModule.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -/** - * @file GFModule.h - * @brief The one header a module includes. - * - * Everything a module needs, grouped by what it is for. Include this; the - * individual headers are there for when you want to see what is in each area, - * not because you have to pick. - * - * | Header | What lives there | - * | ----------------- | ------------------------------------------------ | - * | GFModuleLog.h | `LOG_*`, `FLOG_*`, `MLog*` | - * | GFModuleEvent.h | `LISTEN`, `CB_*`, handlers, event conversion | - * | GFModuleI18n.h | translation context and `.qm` reader | - * | GFModuleMemory.h | who frees what: `DUP`/`UDUP`, SDK allocation | - * | GFModuleConvert.h | QString/QMap <-> C, `FormatString` | - * - * Deliberately NOT here: `GFModuleBootstrap.h`, and through it the generated - * `GFModuleIdentity.h`. Exactly one translation unit per module bootstraps, so - * only that one includes it. Everything else -- including the sources a - * module's own gtest target compiles without the SDK -- then builds without - * needing anything generated. - * - * A module declares itself in `module.json` beside its `CMakeLists.txt`, and - * `gf_add_module()` turns that one file into the generated identity, the - * translation wiring and the signed package. Nothing about a module's identity - * is written twice. - */ - -#include "GFModuleConvert.h" -#include "GFModuleEvent.h" -#include "GFModuleExport.h" -#include "GFModuleI18n.h" -#include "GFModuleLog.h" -#include "GFModuleMemory.h" -#include "GFSDKBuildInfo.h" diff --git a/include/GFModuleBootstrap.h b/include/GFModuleBootstrap.h deleted file mode 100644 index c1a2642..0000000 --- a/include/GFModuleBootstrap.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKModuleApi.h> - -#include "GFModuleExport.h" -#include "GFModuleIdentity.h" -#include "GFSDKBuildInfo.h" - -/** - * @file GFModuleBootstrap.h - * @brief Define a module through the single bootstrap symbol. - * - * Replaces GF_MODULE_API_DECLARE + GF_MODULE_API_DEFINE, which between them - * required a module to export ten separate symbols. Here a module exports - * exactly one, and describes itself through a versioned table. - * - * WHAT A MODULE GAINS. The host hands `activate` a GFHostApi table instead of - * the module linking ~130 global SDK symbols. That is what makes it possible - * for the host to withhold a capability (hand over a table with the gpg group - * null), and what lets a test supply its own table instead of compiling a - * parallel set of stub symbols that drift from the real SDK. - * - * USAGE, once per module, with no arguments at all: - * - * GF_MODULE_BOOTSTRAP() - * - * Identity comes from the generated GFModuleIdentity.h, which is built from - * the module's own module.json. - * - * The host api pointer is stashed in GFHost() for the module's own code to - * reach without threading it through every function. It is valid from the - * moment activate() is called until the module is unloaded. - */ - -/// The host table this module was activated with. Null before activation. -inline const GFHostApi*& GFHostApiSlot() { - static const GFHostApi* host = nullptr; - return host; -} - -/// Convenience accessor for module code. -inline auto GFHost() -> const GFHostApi* { return GFHostApiSlot(); } - -/** - * @brief Define this module's bootstrap symbol, lifecycle table and identity. - * - * Takes no arguments. Everything it needs comes from `GFModuleIdentity.h`, - * which `gf_add_module()` generates from the module's `module.json` -- so the - * identifier and version the host cross-checks against the signed manifest - * cannot disagree with it, because there is only one copy. - * - * It replaces `GF_MODULE_BOOTSTRAP_V2(id, name, ver, desc, author)`, whose - * five arguments were the C++ half of the same five values the CMake call - * repeated. Three of them -- name, description, author -- fed only - * `GFGetModuleMetaData()`, which had no callers at all: the host reads that - * metadata from the verified package manifest instead. So they are simply - * gone, rather than moved. - * - * The module still writes its lifecycle functions under their classic names -- - * GFRegisterModule, GFActiveModule, GFExecuteModule, GFDeactivateModule, - * GFUnregisterModule -- and this adapts them onto the table. - * - * Note the ORDER inside activate: the host's table has no separate register - * step, so whatever the module did in GFRegisterModule -- typically - * registering its translator -- has to run here, before GFActiveModule starts - * subscribing to events. - */ -#define GF_MODULE_BOOTSTRAP() \ - /* Identity strings are BORROWED statics, not fresh allocations. */ \ - /* They used to be DUP(...)ed on every call because the SDK entry points */ \ - /* they were passed to freed their arguments. Now that arguments are */ \ - /* borrowed, allocating here would simply leak -- and GFGetModuleID() is */ \ - /* called on the order of seventy times across the modules. */ \ - auto GFGetModuleID() -> const char* { return GF_MODULE_ID; } \ - using MEvent = QMap<QString, QString>; \ - using EventHandler = std::function<int(const MEvent&)>; \ - namespace { \ - static QMap<QString, EventHandler> gModuleEventHandlers; \ - static QMap<QString, EventHandler>& _gr_module_event_handlers = \ - gModuleEventHandlers; \ - } \ - DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL \ - static int GFBootstrapActivate(const GFHostApi* host, void*) { \ - GFHostApiSlot() = host; \ - const int rc = GFRegisterModule(); \ - if (rc != 0) return rc; \ - return GFActiveModule(); \ - } \ - static void GFBootstrapUnregister() { (void)GFUnregisterModule(); } \ - extern "C" GF_MODULE_EXPORT const GFModuleApi* GFModuleGetApi( \ - uint32_t host_abi) { \ - /* Decline a host outside the range this module was built for, rather */ \ - /* than loading and failing on the first mismatched call. */ \ - if (host_abi < GF_SDK_ABI_MIN_SUPPORTED || \ - host_abi > GF_SDK_ABI_VERSION) { \ - return nullptr; \ - } \ - /* Static: the host borrows this table and never frees it. */ \ - static const GFModuleApi kApi = { \ - sizeof(GFModuleApi), GF_SDK_ABI_VERSION, GF_MODULE_ID, \ - GF_MODULE_VERSION, &GFBootstrapActivate, &GFExecuteModule, \ - &GFDeactivateModule, &GFBootstrapUnregister, \ - }; \ - return &kApi; \ - } diff --git a/include/GFModuleCommonUtils.hpp b/include/GFModuleCommonUtils.hpp deleted file mode 100644 index ca224fa..0000000 --- a/include/GFModuleCommonUtils.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -// DEPRECATED. This header's contents were split by concern into GFModule.h and -// the five headers it pulls in. It remains for one cycle so that a module can -// be ported without being rewritten in the same commit. -// -// Include "GFModule.h" instead. - -#include "GFModule.h" diff --git a/include/GFModuleConvert.h b/include/GFModuleConvert.h deleted file mode 100644 index f803e93..0000000 --- a/include/GFModuleConvert.h +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKBasic.h> -#include <GFSDKModule.h> -#include <GFSDKUI.h> -#include <GFSDKUIModel.h> - -#include <QMap> -#include <QString> -#include <QStringList> -#include <QVariant> -#include <cstring> -#include <string> -#include <type_traits> - -#include "GFModuleMemory.h" - -/** - * @file GFModuleConvert.h - * @brief Moving values across the C boundary, and formatting strings. - * - * Everything here converts between what a module works in (QString, QMap, - * QList) and what the SDK speaks (char*, null-terminated arrays, linked - * lists). The ownership rules that apply are in GFModuleMemory.h and are not - * repeated: as a rule of thumb, a `Convert...ToMap` consumes what it is given - * and a `ConvertMapTo...` produces something the callee will own. - */ - -// ---------------------------------------------------------------- formatting - -inline auto FormatStringHelper(const QString& format, const std::string& arg) - -> QString { - return format.arg(QString::fromStdString(arg)); -} - -template <typename T> -auto FormatStringHelper(const QString& format, T arg) -> QString { - return format.arg(arg); -} - -template <typename... Args> -auto FormatStringHelper(const QString& format, const std::string& arg, - Args... args) -> QString { - return FormatStringHelper(format.arg(QString::fromStdString(arg)), args...); -} - -template <typename T, typename... Args> -auto FormatStringHelper(const QString& format, T arg, Args... args) -> QString { - return FormatStringHelper(format.arg(arg), args...); -} - -inline auto FormatStringHelper(const QString& format) -> QString { - return format; -} - -template <typename T> -inline auto FormatStringHelper(const T& format) -> - typename std::enable_if<std::is_same<T, std::string>::value, - QString>::type { - return FormatStringHelper(QString::fromStdString(format)); -} - -/// Qt-style `%1`/`%2` substitution. NOTE: `%1`, not printf's `%s`. -template <typename... Args> -auto FormatString(const QString& format, Args... args) -> QString { - return FormatStringHelper(format, args...); -} - -// ------------------------------------------------------------------ metadata - -inline auto QMapToMetaDataArray(const QMap<QString, QString>& map) - -> MetaData** { - auto** meta_data_array = - static_cast<MetaData**>(GFAllocateMemory(sizeof(MetaData*) * map.size())); - - int index = 0; - for (auto it = map.begin(); it != map.end(); ++it) { - meta_data_array[index] = - static_cast<MetaData*>(GFAllocateMemory(sizeof(MetaData))); - - QByteArray const key = it.key().toUtf8(); - QByteArray const value = it.value().toUtf8(); - - meta_data_array[index]->key = GFModuleStrDup(key); - meta_data_array[index]->value = GFModuleStrDup(value); - - ++index; - } - - return meta_data_array; -} - -// -------------------------------------------------------------- arrays, lists - -inline auto CharArrayToQStringList(char** pl_components, int size) - -> QStringList { - QStringList list; - for (int i = 0; i < size; ++i) { - list.append(UDUP(pl_components[i])); - } - GFFreeMemory(static_cast<void*>(pl_components)); - return list; -} - -inline auto QStringListToCharArray(const QStringList& list) -> char** { - char** char_array = - static_cast<char**>(GFAllocateMemory(list.size() * sizeof(char*))); - - int index = 0; - for (const QString& item : list) { - QByteArray value = item.toUtf8(); - char_array[index] = static_cast<char*>(GFAllocateMemory(value.size() + 1)); - std::strcpy(char_array[index], value.constData()); - index++; - } - - return char_array; -} - -template <typename T> -inline auto ArrayToQList(T** pl_components, int size) -> QList<T> { - if (pl_components == nullptr || size <= 0) { - return QList<T>(); - } - - QList<T> list; - for (int i = 0; i < size; ++i) { - list.append(*pl_components[i]); - GFFreeMemory(pl_components[i]); - } - GFFreeMemory(pl_components); - return list; -} - -template <typename T> -inline auto QListToArray(const QList<T>& list) -> T** { - T** array = static_cast<T**>(GFAllocateMemory(list.size() * sizeof(T*))); - int index = 0; - for (const T& item : list) { - auto mem = static_cast<T*>(GFAllocateMemory(sizeof(T))); - array[index] = new (mem) T(item); - index++; - } - - return array; -} - -// ------------------------------------------------------------------- QVariant - -inline auto ConvertQVariantToVoidPtr(const QVariant& variant) -> void* { - void* mem = GFAllocateMemory(sizeof(QVariant)); - auto* variant_ptr = new (mem) QVariant(variant); - return static_cast<void*>(variant_ptr); -} - -inline auto ConvertVoidPtrToQVariant(void* ptr) -> QVariant { - if (ptr == nullptr) return {}; - - auto* variant_ptr = static_cast<QVariant*>(ptr); - QVariant variant = *variant_ptr; - - GFFreeMemory(variant_ptr); - return variant; -} - -// --------------------------------------------------------------- gui objects - -template <typename T> -auto GFUIGetGUIObjectAs(const QString& handle) -> T* { - auto* obj = - static_cast<QObject*>(GFUIGetGUIObject(handle.toUtf8().constData())); - if (!obj) { - return nullptr; - } - return qobject_cast<T*>(obj); -} - -#define Q_VARIANT_Q_OBJECT_FACTORY_DECLARE(name) \ - auto name(void* data_raw_ptr) -> void*; - -#define Q_VARIANT_Q_OBJECT_FACTORY_DEFINE(name, func) \ - auto name(void* data_raw_ptr) -> void* { \ - auto data = ConvertVoidPtrToQVariant(data_raw_ptr); \ - return func(data); \ - } - -#define GUI_OBJECT(factory, data) \ - GFUICreateGUIObject(factory, ConvertQVariantToVoidPtr(data)) diff --git a/include/GFModuleDefine.h b/include/GFModuleDefine.h deleted file mode 100644 index 0392960..0000000 --- a/include/GFModuleDefine.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -// DEPRECATED. Its two includes are what GFModule.h does properly. -// -// Include "GFModule.h" instead. - -#include "GFModule.h" diff --git a/include/GFModuleEvent.h b/include/GFModuleEvent.h deleted file mode 100644 index 1ac6614..0000000 --- a/include/GFModuleEvent.h +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKBasic.h> -#include <GFSDKModule.h> - -#include <QMap> -#include <QString> -#include <functional> - -#include "GFModuleConvert.h" -#include "GFModuleMemory.h" - -/** - * @file GFModuleEvent.h - * @brief Subscribing to events, handling them, and answering them. - * - * A module says what it wants to hear with LISTEN(), declares a handler per - * event with REGISTER_EVENT_HANDLER(), and answers with CB_SUCC() or CB_ERR(). - * The dispatch table in between is generated by - * DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL, which the bootstrap - * macro expands for you -- a module does not normally write it out. - * - * Every one of these expands GFGetModuleID(), which is why that accessor is - * the one piece of generated identity that still exists. - */ - -/** - * @brief This module's identifier. - * - * Declared here because this header's macros are what call it. It is *defined* - * by GF_MODULE_BOOTSTRAP() in exactly one translation unit per module, from - * the identifier in module.json -- so a second copy cannot exist to disagree - * with the signed manifest the host checks it against. - */ -auto GFGetModuleID() -> const char*; - -/** - * @brief The lifecycle functions every module defines. - * - * Written out rather than produced by a macro. `GF_MODULE_API_DECLARE` used to - * expand to eleven of these, six of which described entry points the host - * stopped resolving when the bootstrap table replaced them -- so the - * declarations outlived the functions and nothing noticed, because a - * declaration nobody defines costs nothing until somebody calls it. - * - * GF_MODULE_BOOTSTRAP() adapts these onto the table the host actually uses. - */ -extern "C" { -auto GFRegisterModule() -> int; -auto GFActiveModule() -> int; -auto GFExecuteModule(GFModuleEvent*) -> int; -auto GFDeactivateModule() -> int; -auto GFUnregisterModule() -> int; -} - -/// Subscribe to an event by id. -/// -/// No DUP: SDK arguments are borrowed, so pre-allocating here would leak. -#define LISTEN(event) GFModuleListenEvent(GFGetModuleID(), (event)) - -// ------------------------------------------------------------- conversions - -inline auto ConvertEventParamsToMap(GFModuleEventParam* params) - -> QMap<QString, QString> { - QMap<QString, QString> param_map; - GFModuleEventParam* current = params; - GFModuleEventParam* last; - - while (current != nullptr) { - const auto name = UDUP(current->name); - const auto value = USECDUP(current->value); - - if (!name.isEmpty()) param_map[name] = value; - - last = current; - current = current->next; - GFFreeMemory(last); - } - - return param_map; -} - -inline auto ConvertMapToParams(const QMap<QString, QString>& param_map) - -> GFModuleEventParam* { - GFModuleEventParam* head = nullptr; - GFModuleEventParam* prev = nullptr; -#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) - for (const auto& [key, value] : param_map.asKeyValueRange()) { - auto* param = static_cast<GFModuleEventParam*>( - GFAllocateMemory(sizeof(GFModuleEventParam))); - - param->name = DUP(key.toUtf8()); - param->value = SECDUP(value.toUtf8()); - param->next = nullptr; - - if (prev == nullptr) { - head = param; - } else { - prev->next = param; - } - prev = param; - } -#else - for (auto it = param_map.keyValueBegin(); it != param_map.keyValueEnd(); - ++it) { - auto* param = static_cast<GFModuleEventParam*>( - GFAllocateMemory(sizeof(GFModuleEventParam))); - - param->name = DUP(it->first.toUtf8()); - param->value = SECDUP(it->second.toUtf8()); - param->next = nullptr; - - if (prev == nullptr) { - head = param; - } else { - prev->next = param; - } - prev = param; - } -#endif - - return head; -} - -inline auto ConvertEventToMap(GFModuleEvent* event) -> QMap<QString, QString> { - QMap<QString, QString> event_map; - - event_map["event_id"] = UDUP(event->id); - event_map["trigger_id"] = UDUP(event->trigger_id); - event_map.insert(ConvertEventParamsToMap(event->params)); - - GFFreeMemory(event); - - return event_map; -} - -inline auto ConvertMapToEvent(QMap<QString, QString> event_map) - -> GFModuleEvent* { - auto* event = - static_cast<GFModuleEvent*>(GFAllocateMemory(sizeof(GFModuleEvent))); - - event->id = DUP(event_map["event_id"].toUtf8()); - event->trigger_id = DUP(event_map["trigger_id"].toUtf8()); - event->params = nullptr; - - return event; -} - -// ---------------------------------------------------------------- answering - -inline void CB(const QMap<QString, QString>& event, const char* module, - const QMap<QString, QString>& params) { - GFModuleTriggerModuleEventCallback(ConvertMapToEvent(event), module, - ConvertMapToParams(params)); -} - -#undef CB_SUCC -/// Answer an event with success, and return from the handler. -#define CB_SUCC(event) \ - { \ - CB(event, GFGetModuleID(), {{"ret", "0"}}); \ - return 0; \ - } - -#undef CB_ERR -/// Answer an event with a failure, and return that code from the handler. -#define CB_ERR(event, ret, err) \ - { \ - CB(event, GFGetModuleID(), \ - {{"ret", QString::number(ret)}, {"err", QString(err)}}); \ - return ret; \ - } - -#undef CB_ERR_NO_RET -/// The same, without returning -- for a handler with cleanup still to do. -#define CB_ERR_NO_RET(event, ret, err) \ - { \ - CB(event, GFGetModuleID(), \ - {{"ret", QString::number(ret)}, {"err", QString(err)}}); \ - } - -// ----------------------------------------------------------------- dispatch - -#define EXECUTE_MODULE() \ - auto GFExecuteModule(GFModuleEvent* p_event) -> int { \ - auto event = ConvertEventToMap(p_event); - -#define END_EXECUTE_MODULE() } - -#define DEFINE_EXECUTE_API_USING_STANDARD_EVEN_HANDLE_MODEL \ - EXECUTE_MODULE() { \ - auto event_id = event["event_id"]; \ - auto it = _gr_module_event_handlers.find(event_id); \ - if (it != _gr_module_event_handlers.end()) { \ - return it.value()(event); \ - } \ - CB_ERR(event, -1, QString("unsupported event id: %1").arg(event_id)); \ - } \ - END_EXECUTE_MODULE() - -/// Register a handler for one event id, at static-initialisation time. -#define REGISTER_EVENT_HANDLER(event_id, handler) \ - namespace { \ - auto _gv_register_event_handler_by_id_##event_id = []() -> const bool { \ - _gr_module_event_handlers[#event_id] = handler; \ - return true; \ - }(); \ - } diff --git a/include/GFModuleExport.h b/include/GFModuleExport.h deleted file mode 100644 index fe61b89..0000000 --- a/include/GFModuleExport.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (C) 2021-2026 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef GF_MODULE_EXPORT_H -#define GF_MODULE_EXPORT_H - -#ifdef GF_MODULE_STATIC_DEFINE -#define GF_MODULE_EXPORT -#define GF_MODULE_NO_EXPORT -#else -#ifndef GF_MODULE_EXPORT -#ifdef GF_MODULE_EXPORTS -/* We are building this library */ -#define GF_MODULE_EXPORT __attribute__((visibility("default"))) -#else -/* We are using this library */ -#define GF_MODULE_EXPORT __attribute__((visibility("default"))) -#endif -#endif - -#ifndef GF_MODULE_NO_EXPORT -#define GF_MODULE_NO_EXPORT __attribute__((visibility("hidden"))) -#endif -#endif - -#ifndef GF_MODULE_DEPRECATED -#define GF_MODULE_DEPRECATED __attribute__((__deprecated__)) -#endif - -#ifndef GF_MODULE_DEPRECATED_EXPORT -#define GF_MODULE_DEPRECATED_EXPORT GF_MODULE_EXPORT GF_MODULE_DEPRECATED -#endif - -#ifndef GF_MODULE_DEPRECATED_NO_EXPORT -#define GF_MODULE_DEPRECATED_NO_EXPORT GF_MODULE_NO_EXPORT GF_MODULE_DEPRECATED -#endif - -#if 0 /* DEFINE_NO_DEPRECATED */ -#ifndef GF_MODULE_NO_DEPRECATED -#define GF_MODULE_NO_DEPRECATED -#endif -#endif - -#endif /* GF_MODULE_EXPORT_H */ diff --git a/include/GFModuleI18n.h b/include/GFModuleI18n.h deleted file mode 100644 index 613f12c..0000000 --- a/include/GFModuleI18n.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKBasic.h> - -#include <QCoreApplication> -#include <QFile> -#include <QIODevice> -#include <QString> - -#include "GFModuleLog.h" -#include "GFModuleMemory.h" - -/** - * @file GFModuleI18n.h - * @brief Translating a module's own strings. - * - * A module compiles its `.qm` files into itself as Qt resources, and hands - * them to the host on request. Two lines set that up: - * - * DEFINE_TRANSLATIONS_STRUCTURE() // once, at file scope - * REGISTER_TRANS_READER() // once, during activation - * - * The context name is no longer passed in. It comes from - * `GF_MODULE_TRANSLATION_CONTEXT`, generated from `module.json` and supplied by - * `GFModuleIdentity.h` -- which this header does not include, because a macro - * is expanded where it is used: the one translation unit that bootstraps has - * that definition, and no other source needs it. It comes from one place - * because it used to be written out three times -- here, in - * `gpgfrontend_collect_ts_files` and in the `.ts` filenames -- and nothing - * checked that the three agreed. A context that disagrees with its `.ts` files - * does not fail to build; it silently produces a module that is never - * translated. - */ - -#define GF_CONCATENATE_DETAIL(x, y) x##y -#define GF_CONCATENATE(x, y) GF_CONCATENATE_DETAIL(x, y) -#define GF_STRINGIFY(x) #x -#define GF_TOSTRING(x) GF_STRINGIFY(x) - -/// Mark a string for translation in the module's own context. -#define GC_TR(text) QT_TRANSLATE_NOOP("GTrC", text) - -#define GTRC_TR(name, src) GF_CONCATENATE(GTrC_, name)::tr(src) -#define GTRC_AS_STRING(name) GF_TOSTRING(GTrC_##name) - -/** - * @brief Define the module's translation context and its `.qm` reader. - * - * Expands at file scope, once per module. The reader is what - * REGISTER_TRANS_READER() hands to the host. - */ -#define DEFINE_TRANSLATIONS_STRUCTURE() \ - class GTrC { \ - Q_DECLARE_TR_FUNCTIONS(GTrC) \ - }; \ - auto TranslatorDataReader(const char* p_l, char** p_d) -> int { \ - auto locale = QString::fromUtf8(p_l == nullptr ? "" : p_l); \ - QFile f(QString(":/i18n/%2.%1.qm") \ - .arg(locale) \ - .arg(GF_MODULE_TRANSLATION_CONTEXT)); \ - if (f.exists() && f.open(QIODevice::ReadOnly)) { \ - auto b = f.readAll(); \ - *p_d = AllocBufferAndCopy(b); \ - return b.size(); \ - } \ - FLOG_WARN("%3 loading, locale: %1, not found", locale, f.fileName(), \ - QString::fromUtf8(GFGetModuleID())); \ - *p_d = nullptr; \ - return 0; \ - } - -/// Tell the host where to get this module's translations. -#define REGISTER_TRANS_READER() \ - GFAppRegisterTranslatorReader(GFGetModuleID(), TranslatorDataReader) diff --git a/include/GFModuleLog.h b/include/GFModuleLog.h deleted file mode 100644 index 0024ca9..0000000 --- a/include/GFModuleLog.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKLog.h> - -#include <QString> - -#include "GFModuleConvert.h" - -/** - * @file GFModuleLog.h - * @brief Logging from inside a module. - * - * Two families, differing only in whether they take arguments: - * - * LOG_INFO("started"); - * FLOG_INFO("started with %1 accounts", count); - * - * The placeholders are Qt's `%1`, `%2`, ... and **not** printf's `%s`/`%d`. - * Passing a printf format produces a message with the format string in it - * rather than the value, which is the most common mistake made here. - * - * ## The levels are real levels - * - * They were not. `LOG_INFO`, `LOG_WARN` and `LOG_ERROR` all expanded to - * `MLogDebug`, so 58 call sites across the modules -- 46 of them `LOG_ERROR` - * -- were emitted at debug level and never appeared at any higher one. Every - * module author who logged an error and saw nothing was looking at this. The - * `FLOG_*` forms were always correct, which is exactly why it went unnoticed: - * the two families sat beside each other and only one of them worked. - */ - -inline void MLogDebug(const QString& s) { GFModuleLogDebug(s.toUtf8()); } -inline void MLogInfo(const QString& s) { GFModuleLogInfo(s.toUtf8()); } -inline void MLogWarn(const QString& s) { GFModuleLogWarn(s.toUtf8()); } -inline void MLogError(const QString& s) { GFModuleLogError(s.toUtf8()); } - -#define LOG_DEBUG(format) MLogDebug(FormatString(QString(format))) -#define LOG_INFO(format) MLogInfo(FormatString(QString(format))) -#define LOG_WARN(format) MLogWarn(FormatString(QString(format))) -#define LOG_ERROR(format) MLogError(FormatString(QString(format))) - -#define FLOG_DEBUG(format, ...) \ - MLogDebug(FormatString(QString(format), __VA_ARGS__)) -#define FLOG_INFO(format, ...) \ - MLogInfo(FormatString(QString(format), __VA_ARGS__)) -#define FLOG_WARN(format, ...) \ - MLogWarn(FormatString(QString(format), __VA_ARGS__)) -#define FLOG_ERROR(format, ...) \ - MLogError(FormatString(QString(format), __VA_ARGS__)) diff --git a/include/GFModuleMemory.h b/include/GFModuleMemory.h deleted file mode 100644 index dce58cb..0000000 --- a/include/GFModuleMemory.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric <[email protected]> - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric <[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include <GFSDKBasic.h> - -#include <QByteArray> -#include <QSharedPointer> -#include <QString> -#include <cstring> -#include <memory> -#include <new> - -/** - * @file GFModuleMemory.h - * @brief Who frees what, and the helpers that make it obvious. - * - * ## The rule, in one place - * - * **SDK arguments are borrowed.** Pass a pointer straight through -- - * `s.toUtf8().constData()` for a QString -- and keep owning it. Do *not* - * pre-allocate one to hand over: nothing on the other side will free it. That - * is what the old `DUP()`/`QDUP()` at call sites was for, and why doing it now - * simply leaks. - * - * The one exception is a struct rather than an argument: the few aggregates a - * module builds and hands over whole -- `GFModuleEvent`, `GFModuleEventParam`, - * `GFModuleMetaData`, `GFCommandExecuteContext` -- still transfer, so their - * `char*` members are still allocated with GFModuleStrDup. - * - * **SDK return values are owned.** Reclaim them, which is what the `U...` - * family below is for. - */ - -/// Allocate a copy of @p v that a transferring struct will own. -#define DUP(v) GFModuleStrDup(v) - -/// The same, from the wiping allocator, for a value that is a secret. -#define SECDUP(v) GFModuleSecStrDup(v) - -/// Take ownership of an SDK string and return it as a QString. -#define UDUP(v) UnStrDup(v) - -/// The same, releasing it back to the wiping allocator. -#define USECDUP(v) UnSecStrDup(v) - -/// Take ownership of a sized SDK buffer and return its exact octets. -#define UDUPN(v, n) UnBytesDup(v, n) - -/// Takes ownership of a sized SDK buffer and returns its octets verbatim. -/// -/// The QString forms below decode UTF-8 and stop at the first NUL, which is -/// right for identifiers and error strings and wrong for message data: a MIME -/// entity may be 8bit or binary, and a signature covers exact octets. Anything -/// that crosses the crypto boundary must use this and the matching @c *N SDK -/// entry points instead. -inline auto UnBytesDup(const char* s, size_t size) -> QByteArray { - if (s == nullptr) return {}; - QByteArray bytes(s, static_cast<qsizetype>(size)); - GFFreeMemory(static_cast<void*>(const_cast<char*>(s))); - return bytes; -} - -inline auto UnStrDup(const char* s) -> QString { - auto q_s = QString::fromUtf8(s == nullptr ? "" : s); - if (s != nullptr) GFFreeMemory(static_cast<void*>(const_cast<char*>(s))); - return q_s; -} - -inline auto UnSecStrDup(const char* s) -> QString { - auto q_s = QString::fromUtf8(s == nullptr ? "" : s); - if (s != nullptr) GFSecFreeMemory(static_cast<void*>(const_cast<char*>(s))); - return q_s; -} - -inline auto QStrDup(const QString& str) -> char* { return DUP(str.toUtf8()); } - -inline auto QSecStrDup(const QString& str) -> char* { - return SECDUP(str.toUtf8()); -} - -/// Copies @p b into an SDK buffer, NUL-terminated one past the end. -/// -/// The terminator is not optional politeness: the buffer is handed to the -/// host, and a caller that treats it as a C string would otherwise read past -/// the allocation. @p b .size() stays authoritative for the byte count. -inline auto AllocBufferAndCopy(const QByteArray& b) -> char* { - auto* p = static_cast<char*>(GFAllocateMemory(sizeof(char) * (b.size() + 1))); - if (p == nullptr) return nullptr; - memcpy(p, b.constData(), b.size()); - p[b.size()] = '\0'; - return p; -} - -template <typename T> -class PointerConverter { - public: - explicit PointerConverter(void* ptr) : ptr_(ptr) {} - - auto AsType() const -> T* { return static_cast<T*>(ptr_); } - - private: - void* ptr_; -}; - -/** - * @brief Construct a T in SDK-allocated memory, freed through the SDK. - * - * NAMING. These four used to be called `Secure...`, which said the wrong - * thing: they allocate from the ORDINARY SDK arena (GFAllocateMemory), not the - * wiping one (GFSecAllocateMemory). The old names had a comment saying so, - * which is the weakest possible place to put it -- a name is read every time - * and a comment once. For anything that must actually be erased, use the - * secure entry points explicitly or a GFBuf handle. - */ -template <typename T, typename... Args> -auto SdkCreateSharedObject(Args&&... args) -> std::shared_ptr<T> { - void* mem = GFAllocateMemory(sizeof(T)); - if (!mem) throw std::bad_alloc(); - - try { - T* obj = new (mem) T(std::forward<Args>(args)...); - return std::shared_ptr<T>(obj, [](T* ptr) { - ptr->~T(); - GFFreeMemory(ptr); - }); - } catch (...) { - GFFreeMemory(mem); - throw; - } -} - -template <typename T, typename... Args> -auto SdkCreateQSharedObject(Args&&... args) -> QSharedPointer<T> { - void* mem = GFAllocateMemory(sizeof(T)); - if (!mem) throw std::bad_alloc(); - - try { - T* obj = new (mem) T(std::forward<Args>(args)...); - return QSharedPointer<T>(obj, [](T* ptr) { - ptr->~T(); - GFFreeMemory(ptr); - }); - } catch (...) { - GFFreeMemory(mem); - throw; - } -} - -/// Allocate @p size bytes from the ordinary SDK arena, typed. -template <typename T> -auto SdkMallocAsType(std::size_t size) -> T* { - return PointerConverter<T>(GFAllocateMemory(size)).AsType(); -} - -/// Resize an SDK allocation, typed. -template <typename T> -auto SdkReallocAsType(T* ptr, std::size_t size) -> T* { - return PointerConverter<T>(GFReallocateMemory(ptr, size)).AsType(); -} - -// Deprecated spellings, kept for one cycle so a module can be ported without -// being rewritten. They allocate from the ordinary arena, exactly as the new -// names say and the old ones did not. -template <typename T, typename... Args> -[[deprecated( - "renamed to SdkCreateSharedObject: it is not a secure allocation")]] -auto SecureCreateSharedObject(Args&&... args) -> std::shared_ptr<T> { - return SdkCreateSharedObject<T>(std::forward<Args>(args)...); -} - -template <typename T, typename... Args> -[[deprecated( - "renamed to SdkCreateQSharedObject: it is not a secure allocation")]] -auto SecureCreateQSharedObject(Args&&... args) -> QSharedPointer<T> { - return SdkCreateQSharedObject<T>(std::forward<Args>(args)...); -} - -template <typename T> -[[deprecated("renamed to SdkMallocAsType: it is not a secure allocation")]] -auto SecureMallocAsType(std::size_t size) -> T* { - return SdkMallocAsType<T>(size); -} - -template <typename T> -[[deprecated("renamed to SdkReallocAsType: it is not a secure allocation")]] -auto SecureReallocAsType(T* ptr, std::size_t size) -> T* { - return SdkReallocAsType<T>(ptr, size); -} |
