Files
2024-05-18 23:53:26 +08:00

150 lines
4.8 KiB
C++

/**
* @file kPlugin.cpp
*
* @internal
* Copyright (C) 2014-2021 by LMI Technologies Inc.
* Licensed under the MIT License.
* Redistributed files must retain the above copyright notice.
*/
#include <kApi/Utils/kPlugin.h>
#include <kApi/Utils/kDynamicLib.h>
#include <kApi/Io/kPath.h>
kBeginClassEx(k, kPlugin)
kAddPrivateVMethod(kPlugin, kObject, VRelease)
kEndClassEx()
kFx(kStatus) kPlugin_Construct(kPlugin* plugin, const kChar* path, kAlloc allocator)
{
return kPlugin_ConstructEx(plugin, path, 0, kNULL, 0, kNULL, allocator);
}
kFx(kStatus) kPlugin_ConstructEx(kPlugin* plugin, const kChar* path, kVersion requiredPlatformVersion, kVersion* platformVersion,
kVersion requiredAssemblyVersion, kVersion* assemblyVersion, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kStatus status;
kCheck(kAlloc_GetObject(alloc, kTypeOf(kPlugin), plugin));
if (!kSuccess(status = xkPlugin_Init(*plugin, kTypeOf(kPlugin), path, requiredPlatformVersion, platformVersion, requiredAssemblyVersion, assemblyVersion, alloc)))
{
kAlloc_FreeRef(alloc, plugin);
}
return status;
}
kFx(kStatus) xkPlugin_CheckVersion(kPlugin plugin, const kChar* path, const kChar* kind, kVersion required, const kChar* versionFxName, kVersion* actual)
{
kObjR(kPlugin, plugin);
xkPluginVersionFx versionFx = kNULL;
kVersion parsed = 0;
kSize i;
if ((required != k32U_MIN) && (required != k32U_MAX))
{
if (!kSuccess(kDynamicLib_FindFunction(obj->library, versionFxName, (kFunction*)&versionFx)))
{
kLogf("kPlugin: Could not find %s version function in dynamic library (%s).", kind, path);
return kERROR_FORMAT;
}
if (!kSuccess(kVersion_Parse(&parsed, versionFx())))
{
kLogf("kPlugin: Could not parse %s version in dynamic library (%s).", kind, path);
return kERROR_VERSION;
}
for (i = 0; i < 4; ++i) //major, minor, release, build
{
k32u requiredDigit = (required >> 8*i) & 0xFF;
k32u parsedDigit = (parsed >> 8*i) & 0xFF;
if (requiredDigit != k8U_MAX)
{
if (requiredDigit != parsedDigit)
{
kText32 requiredStr;
kText32 parsedStr;
kCheck(kVersion_Format(required, requiredStr, sizeof(requiredStr)));
kCheck(kVersion_Format(parsed, parsedStr, sizeof(parsedStr)));
kLogf("kPlugin: %s version mismatch (required=%s, actual=%s) in dynamic library (%s).", kind, requiredStr, parsedStr, path);
return kERROR_VERSION;
}
}
}
}
if (!kIsNull(actual))
{
*actual = parsed;
}
return kOK;
}
kFx(kStatus) xkPlugin_Init(kPlugin plugin, kType type, const kChar* path, kVersion requiredPlatformVersion, kVersion* platformVersion,
kVersion requiredAssemblyVersion, kVersion* assemblyVersion, kAlloc allocator)
{
kObjR(kPlugin, plugin);
xkPluginConstructFx constructFx = kNULL;
kStatus exception = kOK;
kStatus opStatus = kOK;
if (!kIsNull(platformVersion)) *platformVersion = 0;
if (!kIsNull(assemblyVersion)) *assemblyVersion = 0;
kCheck(kObject_Init(plugin, type, allocator));
obj->library = kNULL;
obj->assembly = kNULL;
obj->handle = kNULL;
kTry
{
if (!kSuccess(opStatus = kDynamicLib_Construct(&obj->library, path, allocator)))
{
kLogf("kPlugin: Load failed (%s) for dynamic library (%s).", kStatus_Name(opStatus), path);
kThrow(opStatus);
}
kTest(xkPlugin_CheckVersion(plugin, path, "Platform", requiredPlatformVersion, xkPLUGIN_PLATFORM_VERSION_FX, platformVersion));
kTest(xkPlugin_CheckVersion(plugin, path, "Assembly", requiredAssemblyVersion, xkPLUGIN_ASSEMBLY_VERSION_FX, assemblyVersion));
if (!kSuccess(kDynamicLib_FindFunction(obj->library, xkPLUGIN_CONSTRUCT_FX, (kFunction*)&constructFx)))
{
kLogf("kPlugin: Assembly constructor could not be located in dynamic library (%s).", path);
kThrow(kERROR_FORMAT);
}
if (!kSuccess(opStatus = constructFx(&obj->assembly)))
{
kLogf("kPlugin: Assembly construction failed (code=%s) for plugin (%s).", kStatus_Name(opStatus), path);
kThrow(kERROR_CONFLICT);
}
}
kCatch(&exception)
{
xkPlugin_VRelease(plugin);
kEndCatch(exception);
}
return kOK;
}
kFx(kStatus) xkPlugin_VRelease(kPlugin plugin)
{
kObj(kPlugin, plugin);
kCheck(kObject_Destroy(obj->assembly));
kCheck(kObject_Destroy(obj->library));
kCheck(kObject_VRelease(plugin));
return kOK;
}