/** * @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 #include #include 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; }