Refactor project structure
This commit is contained in:
106
core/ANSLibsLoader/ANSLibsLoader.cpp
Normal file
106
core/ANSLibsLoader/ANSLibsLoader.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// ============================================================================
|
||||
// ANSLibsLoader.cpp — Master orchestrator for all dynamic library loading
|
||||
//
|
||||
// Coordinates sub-loaders in the correct dependency order:
|
||||
// 1. DLL search path injection (shared directory)
|
||||
// 2. OpenCV (CvLoader) — pre-loads opencv_world + companions
|
||||
// 3. OpenVINO (OvLoader) — pre-loads TBB + openvino.dll
|
||||
// 4. NVIDIA stack (NvDynLoader) — TRT, cuDNN, CUDA
|
||||
// 5. ONNX Runtime (EPLoader) — with execution provider selection
|
||||
//
|
||||
// Shutdown releases everything in reverse order.
|
||||
// ============================================================================
|
||||
|
||||
#include "ANSLibsLoader.h"
|
||||
#include "DynLibUtils.h"
|
||||
#include "CvLoader.h"
|
||||
#include "OvLoader.h"
|
||||
#include "NvDynLoader.h"
|
||||
#include "EPLoader.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
namespace ANSCENTER {
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Static member definitions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
bool ANSLibsLoader::s_initialized = false;
|
||||
|
||||
static std::mutex g_masterMutex;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Initialize
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
void ANSLibsLoader::Initialize(const std::string& shared_dir, EngineType preferred)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_masterMutex);
|
||||
if (s_initialized) return;
|
||||
|
||||
std::cout << "==========================================================\n"
|
||||
<< "ANSLibsLoader: Initializing all dynamic libraries...\n"
|
||||
<< " Shared dir : " << shared_dir << "\n"
|
||||
<< " Engine pref : " << static_cast<int>(preferred) << "\n"
|
||||
<< "==========================================================" << std::endl;
|
||||
|
||||
// ── STEP 1: Inject shared dir into search path ───────────────────────────
|
||||
// This must happen before any DLL loading so all libraries in the shared
|
||||
// directory are discoverable.
|
||||
DynLib::InjectDllSearchPath(shared_dir);
|
||||
|
||||
// ── STEP 2: Pre-load OpenCV ──────────────────────────────────────────────
|
||||
// Must happen before consuming DLLs (ANSODEngine etc.) are loaded, because
|
||||
// those are import-linked against opencv_world and need the DLL available.
|
||||
CvLoader::Initialize(shared_dir);
|
||||
|
||||
// ── STEP 3: Pre-load OpenVINO + TBB ──────────────────────────────────────
|
||||
// OpenVINO is used directly (ov::Core) by many projects (ANSODEngine,
|
||||
// ANSLPR, ANSFR, etc.). Pre-loading ensures the DLLs from the shared
|
||||
// directory are resolved before any import-linked consumer is loaded.
|
||||
OvLoader::Initialize(shared_dir);
|
||||
|
||||
// ── STEP 4: Load NVIDIA stack ────────────────────────────────────────────
|
||||
// Only attempt if the preferred engine is NVIDIA or AUTO_DETECT.
|
||||
if (preferred == EngineType::NVIDIA_GPU ||
|
||||
preferred == EngineType::AUTO_DETECT)
|
||||
{
|
||||
NvDynLoader::Initialize();
|
||||
}
|
||||
|
||||
// ── STEP 5: Load ONNX Runtime + select execution provider ────────────────
|
||||
EPLoader::Initialize(shared_dir, preferred);
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
std::cout << "==========================================================\n"
|
||||
<< "ANSLibsLoader: Initialization complete.\n"
|
||||
<< "==========================================================" << std::endl;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Shutdown
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
void ANSLibsLoader::Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_masterMutex);
|
||||
|
||||
// Shut down in reverse initialization order.
|
||||
// Each sub-loader is idempotent and safe to call even if not initialized.
|
||||
EPLoader::Shutdown();
|
||||
NvDynLoader::Shutdown();
|
||||
OvLoader::Shutdown();
|
||||
CvLoader::Shutdown();
|
||||
|
||||
s_initialized = false;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// IsInitialized
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
bool ANSLibsLoader::IsInitialized()
|
||||
{
|
||||
return s_initialized;
|
||||
}
|
||||
|
||||
} // namespace ANSCENTER
|
||||
28
core/ANSLibsLoader/ANSLibsLoader.def
Normal file
28
core/ANSLibsLoader/ANSLibsLoader.def
Normal file
@@ -0,0 +1,28 @@
|
||||
; ============================================================================
|
||||
; ANSLibsLoader.def — Module definition file
|
||||
;
|
||||
; Exports the extern "C" TRT / ONNX-parser factory stubs so consuming
|
||||
; projects can link ANSLibsLoader.lib instead of nvinfer_XX.lib /
|
||||
; nvonnxparser_XX.lib.
|
||||
;
|
||||
; WHY A .DEF FILE?
|
||||
; ----------------
|
||||
; NvInfer.h declares these functions with TENSORRTAPI, and our stub
|
||||
; definitions in NvDynLoader.cpp must match that declaration exactly.
|
||||
; Any mismatch in __declspec attributes or noexcept causes C2375.
|
||||
; By using a .def file the linker exports the symbols without requiring
|
||||
; __declspec(dllexport) in the source code at all.
|
||||
; ============================================================================
|
||||
|
||||
LIBRARY ANSLibsLoader
|
||||
|
||||
EXPORTS
|
||||
; TensorRT factory stubs (called by NvInfer.h inline wrappers)
|
||||
createInferBuilder_INTERNAL
|
||||
createInferRuntime_INTERNAL
|
||||
createInferRefitter_INTERNAL
|
||||
|
||||
; ONNX parser factory stubs (called by NvOnnxParser.h inline wrappers)
|
||||
createNvOnnxParser_INTERNAL
|
||||
createNvOnnxParserRefitter_INTERNAL
|
||||
getNvOnnxParserVersion
|
||||
38
core/ANSLibsLoader/CMakeLists.txt
Normal file
38
core/ANSLibsLoader/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
# ANSLibsLoader — DLL that dynamically loads all ANS modules
|
||||
add_library(ANSLibsLoader SHARED
|
||||
ANSLibsLoader.cpp
|
||||
CvLoader.cpp
|
||||
DynLibUtils.cpp
|
||||
EPLoader.cpp
|
||||
NvDynLoader.cpp
|
||||
OvLoader.cpp
|
||||
dllmain.cpp
|
||||
pch.cpp
|
||||
pch.h
|
||||
framework.h
|
||||
include/ANSLibsLoader.h
|
||||
include/CvLoader.h
|
||||
include/DynLibUtils.h
|
||||
include/EPLoader.h
|
||||
include/NvDynLoader.h
|
||||
include/OvLoader.h
|
||||
)
|
||||
|
||||
target_include_directories(ANSLibsLoader PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(ANSLibsLoader
|
||||
PRIVATE ANSLicensingSystem
|
||||
PRIVATE labview
|
||||
PRIVATE spdlog_dep
|
||||
PRIVATE opencv
|
||||
PRIVATE onnxruntime
|
||||
PRIVATE tensorrt
|
||||
PRIVATE openvino
|
||||
PRIVATE CUDA::cudart_static
|
||||
)
|
||||
|
||||
target_compile_definitions(ANSLibsLoader PRIVATE UNICODE _UNICODE ANSLIBSLOADER_EXPORTS NOMINMAX)
|
||||
target_precompile_headers(ANSLibsLoader PRIVATE pch.h)
|
||||
211
core/ANSLibsLoader/CvLoader.cpp
Normal file
211
core/ANSLibsLoader/CvLoader.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// ============================================================================
|
||||
// CvLoader.cpp — OpenCV DLL discovery and pre-loading
|
||||
// ============================================================================
|
||||
|
||||
#include "CvLoader.h"
|
||||
#include "DynLibUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
using namespace ANSCENTER::DynLib;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Static member definitions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
std::mutex CvLoader::s_mutex;
|
||||
bool CvLoader::s_initialized = false;
|
||||
CvInfo CvLoader::s_info;
|
||||
LibHandle CvLoader::s_hCvWorld = nullptr;
|
||||
LibHandle CvLoader::s_hCvImgHash = nullptr;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Helper — extract version string from version code (e.g. 4130 → "4.13.0")
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
static std::string VersionFromCode(int code)
|
||||
{
|
||||
// OpenCV version encoding: XYZZ where X=major, Y=minor, ZZ=patch
|
||||
// 4130 → major=4, minor=13, patch=0
|
||||
// 4100 → major=4, minor=10, patch=0
|
||||
// 490 → major=4, minor=9, patch=0
|
||||
int major = code / 1000;
|
||||
int minor = (code / 10) % 100;
|
||||
int patch = code % 10;
|
||||
return std::to_string(major) + "." +
|
||||
std::to_string(minor) + "." +
|
||||
std::to_string(patch);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Helper — extract version code from DLL filename
|
||||
// "opencv_world4130.dll" → 4130
|
||||
// "opencv_world4100.dll" → 4100
|
||||
// "libopencv_world.so.413"→ 413 (Linux)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
static int ExtractVersionCode(const std::string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Windows: opencv_world<XYZZ>.dll — digits between "opencv_world" and ".dll"
|
||||
const std::string marker = "opencv_world";
|
||||
size_t pos = path.find(marker);
|
||||
if (pos == std::string::npos) return 0;
|
||||
pos += marker.size();
|
||||
size_t dot = path.find('.', pos);
|
||||
if (dot == std::string::npos) return 0;
|
||||
try { return std::stoi(path.substr(pos, dot - pos)); }
|
||||
catch (...) { return 0; }
|
||||
#else
|
||||
// Linux: libopencv_world.so.<digits>
|
||||
size_t dot = path.find_last_of('.');
|
||||
if (dot == std::string::npos || dot + 1 >= path.size()) return 0;
|
||||
try { return std::stoi(path.substr(dot + 1)); }
|
||||
catch (...) { return 0; }
|
||||
#endif
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Candidate lists — search ANSCENTER shared dir first, then system PATH
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
std::vector<std::string> CvLoader::CvWorldCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
// Versioned candidates, newest first (covers OpenCV 4.5 through 4.20+)
|
||||
// Version codes: 4200, 4190, 4180, ..., 4130, ..., 4100, ..., 450
|
||||
static const int versions[] = {
|
||||
4200, 4190, 4180, 4170, 4160, 4150, 4140, 4130, 4120, 4110, 4100,
|
||||
490, 480, 470, 460, 450
|
||||
};
|
||||
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
for (int ver : versions) {
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir,
|
||||
"opencv_world" + std::to_string(ver) + ".dll"));
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir,
|
||||
"libopencv_world.so." + std::to_string(ver)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
for (int ver : versions) {
|
||||
#ifdef _WIN32
|
||||
v.push_back("opencv_world" + std::to_string(ver) + ".dll");
|
||||
#else
|
||||
v.push_back("libopencv_world.so." + std::to_string(ver));
|
||||
#endif
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> CvLoader::CvImgHashCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
static const int versions[] = {
|
||||
4200, 4190, 4180, 4170, 4160, 4150, 4140, 4130, 4120, 4110, 4100,
|
||||
490, 480, 470, 460, 450
|
||||
};
|
||||
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
for (int ver : versions) {
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir,
|
||||
"opencv_img_hash" + std::to_string(ver) + ".dll"));
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir,
|
||||
"libopencv_img_hash.so." + std::to_string(ver)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
for (int ver : versions) {
|
||||
#ifdef _WIN32
|
||||
v.push_back("opencv_img_hash" + std::to_string(ver) + ".dll");
|
||||
#else
|
||||
v.push_back("libopencv_img_hash.so." + std::to_string(ver));
|
||||
#endif
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Initialize
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
const CvInfo& CvLoader::Initialize(const std::string& shared_dir, bool verbose)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
if (s_initialized) return s_info;
|
||||
|
||||
// Clean up any partially-loaded handles from a previous failed attempt
|
||||
if (s_hCvWorld) { FreeLib(s_hCvWorld); s_hCvWorld = nullptr; }
|
||||
if (s_hCvImgHash) { FreeLib(s_hCvImgHash); s_hCvImgHash = nullptr; }
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "==================================================" << std::endl;
|
||||
std::cout << "[CvLoader] Discovering OpenCV libraries..." << std::endl;
|
||||
std::cout << " Shared dir : " << shared_dir << std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 1: Inject shared dir into search path ───────────────────────────
|
||||
// This ensures dependent DLLs (e.g. opencv_videoio_ffmpeg) can also be
|
||||
// found when they are co-located with opencv_world in the shared dir.
|
||||
InjectDllSearchPath(shared_dir);
|
||||
|
||||
// ── STEP 2: Pre-load opencv_world ────────────────────────────────────────
|
||||
std::string worldPath;
|
||||
s_hCvWorld = FindAndLoad(CvWorldCandidates(shared_dir), worldPath, verbose);
|
||||
if (s_hCvWorld) {
|
||||
s_info.dllPath = worldPath;
|
||||
s_info.versionCode = ExtractVersionCode(worldPath);
|
||||
s_info.version = VersionFromCode(s_info.versionCode);
|
||||
s_info.loaded = true;
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "[CvLoader] OpenCV version = " << s_info.version
|
||||
<< " (code " << s_info.versionCode << ")" << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << "[CvLoader] WARNING: No opencv_world DLL found in "
|
||||
<< shared_dir << " or system PATH." << std::endl;
|
||||
std::cout << "[CvLoader] OpenCV will rely on import-lib resolution at load time."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 3: Pre-load companion modules ───────────────────────────────────
|
||||
// These are optional — missing is a warning, not a failure.
|
||||
std::string imgHashPath;
|
||||
s_hCvImgHash = FindAndLoad(CvImgHashCandidates(shared_dir), imgHashPath, verbose);
|
||||
if (!s_hCvImgHash && verbose) {
|
||||
std::cout << "[CvLoader] opencv_img_hash not found (optional)." << std::endl;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "[CvLoader] "
|
||||
<< (s_info.loaded ? "initialised successfully." : "WARNING — opencv_world not pre-loaded.")
|
||||
<< std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
return s_info;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Shutdown
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
void CvLoader::Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
|
||||
// Release in reverse order
|
||||
if (s_hCvImgHash) { FreeLib(s_hCvImgHash); s_hCvImgHash = nullptr; }
|
||||
if (s_hCvWorld) { FreeLib(s_hCvWorld); s_hCvWorld = nullptr; }
|
||||
|
||||
s_info = CvInfo{};
|
||||
s_initialized = false;
|
||||
}
|
||||
125
core/ANSLibsLoader/DynLibUtils.cpp
Normal file
125
core/ANSLibsLoader/DynLibUtils.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// ============================================================================
|
||||
// DynLibUtils.cpp — Shared dynamic library loading utilities
|
||||
// ============================================================================
|
||||
|
||||
#include "DynLibUtils.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace DynLib {
|
||||
|
||||
// ── FileExists ───────────────────────────────────────────────────────────
|
||||
bool FileExists(const std::string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD attr = GetFileAttributesA(path.c_str());
|
||||
return (attr != INVALID_FILE_ATTRIBUTES) &&
|
||||
!(attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
struct stat st {};
|
||||
return (::stat(path.c_str(), &st) == 0) && S_ISREG(st.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── JoinPath ─────────────────────────────────────────────────────────────
|
||||
std::string JoinPath(const std::string& base, const std::string& component)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char sep = '\\';
|
||||
#else
|
||||
const char sep = '/';
|
||||
#endif
|
||||
if (base.empty()) return component;
|
||||
if (base.back() == sep || base.back() == '/')
|
||||
return base + component;
|
||||
return base + sep + component;
|
||||
}
|
||||
|
||||
// ── InjectDllSearchPath ──────────────────────────────────────────────────
|
||||
void InjectDllSearchPath(const std::string& dir)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly)
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, nullptr, 0);
|
||||
std::wstring wdir(static_cast<size_t>(wlen > 0 ? wlen - 1 : 0), L'\0');
|
||||
if (wlen > 0)
|
||||
MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, wdir.data(), wlen);
|
||||
DLL_DIRECTORY_COOKIE cookie = AddDllDirectory(wdir.c_str());
|
||||
if (!cookie)
|
||||
std::cerr << "[DynLib] WARNING: AddDllDirectory failed for: "
|
||||
<< dir << " (error " << GetLastError() << ")" << std::endl;
|
||||
|
||||
char existing_path[32767] = {};
|
||||
GetEnvironmentVariableA("PATH", existing_path, sizeof(existing_path));
|
||||
std::string new_path = dir + ";" + existing_path;
|
||||
if (!SetEnvironmentVariableA("PATH", new_path.c_str()))
|
||||
std::cerr << "[DynLib] WARNING: SetEnvironmentVariable PATH failed."
|
||||
<< std::endl;
|
||||
#else
|
||||
const char* existing = getenv("LD_LIBRARY_PATH");
|
||||
std::string new_path = dir +
|
||||
(existing ? (":" + std::string(existing)) : "");
|
||||
setenv("LD_LIBRARY_PATH", new_path.c_str(), 1);
|
||||
#endif
|
||||
std::cout << "[DynLib] DLL search path injected: " << dir << std::endl;
|
||||
}
|
||||
|
||||
// ── LoadLib ──────────────────────────────────────────────────────────────
|
||||
LibHandle LoadLib(const std::string& path, bool globalLoad)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
(void)globalLoad;
|
||||
return LoadLibraryExA(path.c_str(), nullptr,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
#else
|
||||
return globalLoad
|
||||
? ::dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL)
|
||||
: ::dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── FreeLib ──────────────────────────────────────────────────────────────
|
||||
void FreeLib(LibHandle h)
|
||||
{
|
||||
if (!h) return;
|
||||
#ifdef _WIN32
|
||||
::FreeLibrary(h);
|
||||
#else
|
||||
::dlclose(h);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── GetSymbol ────────────────────────────────────────────────────────────
|
||||
void* GetSymbol(LibHandle h, const char* sym)
|
||||
{
|
||||
if (!h) return nullptr;
|
||||
#ifdef _WIN32
|
||||
return reinterpret_cast<void*>(::GetProcAddress(h, sym));
|
||||
#else
|
||||
return ::dlsym(h, sym);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ── FindAndLoad ──────────────────────────────────────────────────────────
|
||||
LibHandle FindAndLoad(const std::vector<std::string>& candidates,
|
||||
std::string& loadedPath,
|
||||
bool verbose,
|
||||
bool globalLoad)
|
||||
{
|
||||
for (const auto& name : candidates) {
|
||||
LibHandle h = LoadLib(name, globalLoad);
|
||||
if (h) {
|
||||
loadedPath = name;
|
||||
if (verbose)
|
||||
std::cout << "[DynLib] Loaded: " << name << std::endl;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
return LIB_INVALID;
|
||||
}
|
||||
|
||||
} // namespace DynLib
|
||||
} // namespace ANSCENTER
|
||||
492
core/ANSLibsLoader/EPLoader.cpp
Normal file
492
core/ANSLibsLoader/EPLoader.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
// EPLoader.cpp
|
||||
// Dynamic ONNX Runtime EP loader.
|
||||
// Loads onnxruntime.dll at runtime — no onnxruntime.lib linkage required.
|
||||
//
|
||||
// Moved from ONNXEngine/ to ANSLibsLoader/.
|
||||
// Compile this file in EXACTLY ONE project (ANSLibsLoader.dll).
|
||||
// That project MUST define ANSLIBSLOADER_EXPORTS in its Preprocessor Definitions.
|
||||
//
|
||||
// Windows: LoadLibraryExW + AddDllDirectory + GetProcAddress
|
||||
// Linux: dlopen (RTLD_NOW | RTLD_GLOBAL) + dlsym
|
||||
|
||||
#include "EPLoader.h"
|
||||
#include "DynLibUtils.h"
|
||||
|
||||
// ORT C++ headers — included ONLY in this translation unit.
|
||||
// ORT_API_MANUAL_INIT must be defined project-wide (Preprocessor Definitions)
|
||||
// in every project that includes ORT headers, so all translation units see
|
||||
// Ort::Global<void>::api_ as an extern rather than a default-constructed object.
|
||||
#include <onnxruntime_cxx_api.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace ANSCENTER {
|
||||
|
||||
// ── Static member definitions ────────────────────────────────────────────
|
||||
#ifdef ANSLIBSLOADER_EXPORTS
|
||||
std::mutex EPLoader::s_mutex;
|
||||
bool EPLoader::s_initialized = false;
|
||||
EPInfo EPLoader::s_info;
|
||||
# ifdef _WIN32
|
||||
std::string EPLoader::s_temp_ort_path;
|
||||
std::string EPLoader::s_temp_dir;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// ── File-scope state ─────────────────────────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
static HMODULE s_ort_module = nullptr;
|
||||
#else
|
||||
static void* s_ort_module = nullptr;
|
||||
#endif
|
||||
static const OrtApi* s_ort_api = nullptr;
|
||||
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// File-scope helpers (anonymous namespace — not exported)
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
namespace {
|
||||
|
||||
// ── GetOrtApi ────────────────────────────────────────────────────────
|
||||
const OrtApi* GetOrtApi()
|
||||
{
|
||||
if (!s_ort_module)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] ORT DLL not loaded — call EPLoader::Current() first.");
|
||||
|
||||
if (s_ort_api)
|
||||
return s_ort_api;
|
||||
|
||||
#ifdef _WIN32
|
||||
using Fn = const OrtApiBase* (ORT_API_CALL*)();
|
||||
auto fn = reinterpret_cast<Fn>(
|
||||
GetProcAddress(s_ort_module, "OrtGetApiBase"));
|
||||
#else
|
||||
using Fn = const OrtApiBase* (ORT_API_CALL*)();
|
||||
auto fn = reinterpret_cast<Fn>(
|
||||
dlsym(s_ort_module, "OrtGetApiBase"));
|
||||
#endif
|
||||
if (!fn)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] OrtGetApiBase symbol not found in loaded ORT DLL.");
|
||||
|
||||
const OrtApiBase* base = fn();
|
||||
if (!base)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] OrtGetApiBase() returned null.");
|
||||
|
||||
int dllMaxApi = ORT_API_VERSION;
|
||||
{
|
||||
const char* verStr = base->GetVersionString();
|
||||
int major = 0, minor = 0;
|
||||
if (verStr && sscanf(verStr, "%d.%d", &major, &minor) == 2)
|
||||
dllMaxApi = minor;
|
||||
}
|
||||
int targetApi = std::min(ORT_API_VERSION, dllMaxApi);
|
||||
|
||||
const OrtApi* api = base->GetApi(targetApi);
|
||||
if (!api)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] No compatible ORT API version found in loaded DLL.");
|
||||
|
||||
s_ort_api = api;
|
||||
return s_ort_api;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// EPLoader public / private methods
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
const char* OrtDllName()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return "onnxruntime.dll";
|
||||
#elif defined(__APPLE__)
|
||||
return "libonnxruntime.dylib";
|
||||
#else
|
||||
return "libonnxruntime.so";
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* EPLoader::SubdirName(EngineType type)
|
||||
{
|
||||
switch (type) {
|
||||
case EngineType::NVIDIA_GPU: return "cuda";
|
||||
case EngineType::AMD_GPU: return "directml";
|
||||
case EngineType::OPENVINO_GPU: return "openvino";
|
||||
case EngineType::CPU: return "cpu";
|
||||
default: return "cpu";
|
||||
}
|
||||
}
|
||||
|
||||
const char* EPLoader::EngineTypeName(EngineType type)
|
||||
{
|
||||
switch (type) {
|
||||
case EngineType::NVIDIA_GPU: return "NVIDIA_GPU";
|
||||
case EngineType::AMD_GPU: return "AMD_GPU";
|
||||
case EngineType::OPENVINO_GPU: return "OPENVINO_GPU";
|
||||
case EngineType::CPU: return "CPU";
|
||||
case EngineType::AUTO_DETECT: return "AUTO_DETECT";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
std::string EPLoader::ResolveEPDir(const std::string& shared_dir,
|
||||
EngineType type)
|
||||
{
|
||||
std::string ep_base = DynLib::JoinPath(shared_dir, "ep");
|
||||
std::string subdir = DynLib::JoinPath(ep_base, SubdirName(type));
|
||||
std::string dll_probe = DynLib::JoinPath(subdir, OrtDllName());
|
||||
|
||||
if (DynLib::FileExists(dll_probe)) {
|
||||
std::cout << "[EPLoader] EP subdir found: " << subdir << std::endl;
|
||||
return subdir;
|
||||
}
|
||||
|
||||
std::string flat_probe = DynLib::JoinPath(shared_dir, OrtDllName());
|
||||
if (DynLib::FileExists(flat_probe)) {
|
||||
std::cout << "[EPLoader] EP subdir not found — "
|
||||
"using flat Shared/ (backward compat): "
|
||||
<< shared_dir << std::endl;
|
||||
return shared_dir;
|
||||
}
|
||||
|
||||
std::cerr << "[EPLoader] WARNING: " << OrtDllName() << " not found in:\n"
|
||||
<< " " << subdir << "\n"
|
||||
<< " " << shared_dir << "\n"
|
||||
<< " LoadOrtDll will fail with a clear error."
|
||||
<< std::endl;
|
||||
return subdir;
|
||||
}
|
||||
|
||||
EngineType EPLoader::AutoDetect()
|
||||
{
|
||||
std::cout << "[EPLoader] Auto-detecting hardware..." << std::endl;
|
||||
ANSLicenseHelper helper;
|
||||
EngineType detected = helper.CheckHardwareInformation();
|
||||
std::cout << "[EPLoader] Detected: " << EngineTypeName(detected) << std::endl;
|
||||
return detected;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const EPInfo& EPLoader::Initialize(const std::string& shared_dir,
|
||||
EngineType preferred)
|
||||
{
|
||||
if (s_initialized) return s_info;
|
||||
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
if (s_initialized) return s_info;
|
||||
|
||||
std::cout << "[EPLoader] Initializing..." << std::endl;
|
||||
std::cout << "[EPLoader] Shared dir : " << shared_dir << std::endl;
|
||||
std::cout << "[EPLoader] Preferred EP : " << EngineTypeName(preferred) << std::endl;
|
||||
|
||||
EngineType type = (preferred == EngineType::AUTO_DETECT)
|
||||
? AutoDetect() : preferred;
|
||||
|
||||
std::string ep_dir = ResolveEPDir(shared_dir, type);
|
||||
|
||||
// When the EP lives in a subdirectory (e.g. ep/openvino/), provider
|
||||
// DLLs may depend on runtime libraries that live in the parent
|
||||
// shared_dir (e.g. openvino.dll). Inject shared_dir into the DLL
|
||||
// search path so Windows can resolve those dependencies.
|
||||
if (ep_dir != shared_dir)
|
||||
DynLib::InjectDllSearchPath(shared_dir);
|
||||
|
||||
LoadOrtDll(ep_dir);
|
||||
|
||||
s_info.type = type;
|
||||
s_info.libraryDir = ep_dir;
|
||||
s_info.fromSubdir = (ep_dir != shared_dir);
|
||||
s_initialized = true;
|
||||
|
||||
std::cout << "[EPLoader] Ready. EP=" << EngineTypeName(type)
|
||||
<< " dir=" << ep_dir << std::endl;
|
||||
return s_info;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const EPInfo& EPLoader::Current()
|
||||
{
|
||||
if (!s_initialized)
|
||||
return Initialize(DEFAULT_SHARED_DIR, EngineType::AUTO_DETECT);
|
||||
return s_info;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
bool EPLoader::IsInitialized()
|
||||
{
|
||||
return s_initialized;
|
||||
}
|
||||
|
||||
void* EPLoader::GetOrtApiRaw()
|
||||
{
|
||||
Current();
|
||||
const OrtApi* api = GetOrtApi();
|
||||
if (!api)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] GetOrtApiRaw: OrtApi not available.");
|
||||
return static_cast<void*>(const_cast<OrtApi*>(api));
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
// ── MakeTempDir ──────────────────────────────────────────────────────────
|
||||
static std::string MakeTempDir()
|
||||
{
|
||||
char tmp[MAX_PATH] = {};
|
||||
GetTempPathA(MAX_PATH, tmp);
|
||||
std::string dir = std::string(tmp)
|
||||
+ "anscenter_ort_"
|
||||
+ std::to_string(GetCurrentProcessId());
|
||||
CreateDirectoryA(dir.c_str(), nullptr);
|
||||
return dir;
|
||||
}
|
||||
|
||||
// ── CopyDirToTemp ─────────────────────────────────────────────────────────
|
||||
static void CopyDirToTemp(const std::string& ep_dir,
|
||||
const std::string& temp_dir)
|
||||
{
|
||||
std::string pattern = ep_dir + "\\*.dll";
|
||||
WIN32_FIND_DATAA fd{};
|
||||
HANDLE hFind = FindFirstFileA(pattern.c_str(), &fd);
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
std::cerr << "[EPLoader] WARNING: No DLLs found in ep_dir: "
|
||||
<< ep_dir << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int copied = 0, skipped = 0;
|
||||
do {
|
||||
std::string src = ep_dir + "\\" + fd.cFileName;
|
||||
std::string dst = temp_dir + "\\" + fd.cFileName;
|
||||
|
||||
if (CopyFileA(src.c_str(), dst.c_str(), /*bFailIfExists=*/FALSE)) {
|
||||
++copied;
|
||||
std::cout << "[EPLoader] copied: " << fd.cFileName << std::endl;
|
||||
}
|
||||
else {
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
|
||||
std::cerr << "[EPLoader] WARNING: could not copy "
|
||||
<< fd.cFileName
|
||||
<< " (err=" << err << ") — skipping." << std::endl;
|
||||
}
|
||||
++skipped;
|
||||
}
|
||||
} while (FindNextFileA(hFind, &fd));
|
||||
|
||||
FindClose(hFind);
|
||||
std::cout << "[EPLoader] Staged " << copied << " DLL(s) to temp dir"
|
||||
<< (skipped ? " (" + std::to_string(skipped) + " already present)" : "")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// ── DeleteTempDir ─────────────────────────────────────────────────────────
|
||||
static void DeleteTempDir(const std::string& dir)
|
||||
{
|
||||
if (dir.empty()) return;
|
||||
|
||||
std::string pattern = dir + "\\*";
|
||||
WIN32_FIND_DATAA fd{};
|
||||
HANDLE hFind = FindFirstFileA(pattern.c_str(), &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(fd.cFileName, ".") == 0 ||
|
||||
strcmp(fd.cFileName, "..") == 0) continue;
|
||||
std::string f = dir + "\\" + fd.cFileName;
|
||||
DeleteFileA(f.c_str());
|
||||
} while (FindNextFileA(hFind, &fd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
RemoveDirectoryA(dir.c_str());
|
||||
std::cout << "[EPLoader] Temp staging dir deleted: " << dir << std::endl;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
// ── LoadOrtDll ───────────────────────────────────────────────────────────
|
||||
void EPLoader::LoadOrtDll(const std::string& ep_dir)
|
||||
{
|
||||
if (s_ort_module) {
|
||||
std::cout << "[EPLoader] ORT DLL already loaded — skipping." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject ep_dir into the DLL search path so cudart64_*.dll and other
|
||||
// CUDA runtime DLLs that are NOT copied to temp are still found.
|
||||
DynLib::InjectDllSearchPath(ep_dir);
|
||||
|
||||
std::string src_path = DynLib::JoinPath(ep_dir, OrtDllName());
|
||||
std::cout << "[EPLoader] ORT source : " << src_path << std::endl;
|
||||
|
||||
#ifdef _WIN32
|
||||
// ── Windows: stage ALL ep_dir DLLs into a process-unique temp folder ────
|
||||
std::string temp_dir = MakeTempDir();
|
||||
std::cout << "[EPLoader] Staging dir : " << temp_dir << std::endl;
|
||||
|
||||
CopyDirToTemp(ep_dir, temp_dir);
|
||||
|
||||
std::string ort_alias = temp_dir + "\\anscenter_ort_"
|
||||
+ std::to_string(GetCurrentProcessId()) + ".dll";
|
||||
std::string ort_in_temp = temp_dir + "\\" + OrtDllName();
|
||||
|
||||
if (!CopyFileA(ort_in_temp.c_str(), ort_alias.c_str(), /*bFailIfExists=*/FALSE)) {
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] Failed to create ORT alias in temp dir.\n"
|
||||
" src : " + ort_in_temp + "\n"
|
||||
" dst : " + ort_alias + "\n"
|
||||
" err : " + std::to_string(err));
|
||||
}
|
||||
}
|
||||
std::cout << "[EPLoader] ORT alias : " << ort_alias << std::endl;
|
||||
|
||||
DynLib::InjectDllSearchPath(temp_dir);
|
||||
|
||||
HMODULE hExisting = GetModuleHandleA("onnxruntime.dll");
|
||||
if (hExisting) {
|
||||
char existingPath[MAX_PATH] = {};
|
||||
GetModuleFileNameA(hExisting, existingPath, MAX_PATH);
|
||||
std::string existingStr(existingPath);
|
||||
std::transform(existingStr.begin(), existingStr.end(),
|
||||
existingStr.begin(), ::tolower);
|
||||
if (existingStr.find("system32") != std::string::npos ||
|
||||
existingStr.find("syswow64") != std::string::npos) {
|
||||
std::cerr << "[EPLoader] WARNING: System ORT is resident ("
|
||||
<< existingPath << ") - our alias overrides it." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly)
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, ort_alias.c_str(), -1, nullptr, 0);
|
||||
std::wstring walias(static_cast<size_t>(wlen > 0 ? wlen - 1 : 0), L'\0');
|
||||
if (wlen > 0)
|
||||
MultiByteToWideChar(CP_UTF8, 0, ort_alias.c_str(), -1, walias.data(), wlen);
|
||||
s_ort_module = LoadLibraryExW(
|
||||
walias.c_str(),
|
||||
nullptr,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
|
||||
if (!s_ort_module) {
|
||||
DWORD err = GetLastError();
|
||||
DeleteTempDir(temp_dir);
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] LoadLibraryExW failed: " + ort_alias +
|
||||
"\n Windows error code: " + std::to_string(err) +
|
||||
"\n Ensure all CUDA runtime DLLs (cudart64_*.dll etc.)"
|
||||
"\n exist in: " + ep_dir);
|
||||
}
|
||||
|
||||
s_temp_ort_path = ort_alias;
|
||||
s_temp_dir = temp_dir;
|
||||
|
||||
#else
|
||||
// ── Linux / macOS ─────────────────────────────────────────────────────
|
||||
s_ort_module = dlopen(src_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!s_ort_module) {
|
||||
throw std::runtime_error(
|
||||
std::string("[EPLoader] dlopen failed: ") + src_path +
|
||||
"\n " + dlerror());
|
||||
}
|
||||
#endif
|
||||
|
||||
// ── Bootstrap ORT C++ API ─────────────────────────────────────────────
|
||||
using OrtGetApiBase_fn = const OrtApiBase* (ORT_API_CALL*)();
|
||||
#ifdef _WIN32
|
||||
auto fn = reinterpret_cast<OrtGetApiBase_fn>(
|
||||
GetProcAddress(s_ort_module, "OrtGetApiBase"));
|
||||
#else
|
||||
auto fn = reinterpret_cast<OrtGetApiBase_fn>(
|
||||
dlsym(s_ort_module, "OrtGetApiBase"));
|
||||
#endif
|
||||
if (!fn)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] OrtGetApiBase not exported — is this a genuine onnxruntime build?\n"
|
||||
" path: " + src_path);
|
||||
|
||||
const OrtApiBase* base = fn();
|
||||
if (!base)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] OrtGetApiBase() returned null from: " + src_path);
|
||||
|
||||
// ── Version negotiation ───────────────────────────────────────────────
|
||||
int dllMaxApi = ORT_API_VERSION;
|
||||
{
|
||||
const char* verStr = base->GetVersionString();
|
||||
int major = 0, minor = 0;
|
||||
if (verStr && sscanf(verStr, "%d.%d", &major, &minor) == 2)
|
||||
dllMaxApi = minor;
|
||||
}
|
||||
int targetApi = std::min(ORT_API_VERSION, dllMaxApi);
|
||||
|
||||
if (targetApi < ORT_API_VERSION) {
|
||||
std::cerr << "[EPLoader] WARNING: ORT DLL version "
|
||||
<< base->GetVersionString()
|
||||
<< " supports up to API " << dllMaxApi
|
||||
<< " but headers expect API " << ORT_API_VERSION << ".\n"
|
||||
<< " Using API " << targetApi
|
||||
<< ". Consider upgrading onnxruntime.dll in ep/ to match SDK headers."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
const OrtApi* api = base->GetApi(targetApi);
|
||||
if (!api)
|
||||
throw std::runtime_error(
|
||||
"[EPLoader] GetApi(" + std::to_string(targetApi) +
|
||||
") returned null — the DLL may be corrupt.");
|
||||
|
||||
s_ort_api = api;
|
||||
Ort::Global<void>::api_ = api;
|
||||
|
||||
std::cout << "[EPLoader] ORT loaded successfully." << std::endl;
|
||||
std::cout << "[EPLoader] ORT DLL version : " << base->GetVersionString() << std::endl;
|
||||
std::cout << "[EPLoader] ORT header API : " << ORT_API_VERSION << std::endl;
|
||||
std::cout << "[EPLoader] ORT active API : " << targetApi << std::endl;
|
||||
}
|
||||
|
||||
// ── Shutdown ──────────────────────────────────────────────────────────────
|
||||
void EPLoader::Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
|
||||
if (s_ort_module) {
|
||||
std::cout << "[EPLoader] Unloading ORT DLL..." << std::endl;
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(s_ort_module);
|
||||
if (!s_temp_dir.empty()) {
|
||||
DeleteTempDir(s_temp_dir);
|
||||
s_temp_dir.clear();
|
||||
}
|
||||
s_temp_ort_path.clear();
|
||||
#else
|
||||
dlclose(s_ort_module);
|
||||
#endif
|
||||
s_ort_module = nullptr;
|
||||
}
|
||||
|
||||
s_ort_api = nullptr;
|
||||
s_initialized = false;
|
||||
s_info = EPInfo{};
|
||||
std::cout << "[EPLoader] Shutdown complete." << std::endl;
|
||||
}
|
||||
|
||||
} // namespace ANSCENTER
|
||||
646
core/ANSLibsLoader/NvDynLoader.cpp
Normal file
646
core/ANSLibsLoader/NvDynLoader.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
// ============================================================================
|
||||
// NvDynLoader.cpp
|
||||
//
|
||||
// Moved from TensorRTAPI/ to ANSLibsLoader/ for centralized library management.
|
||||
// Now compiled into ANSLibsLoader.dll — all extern "C" stubs are exported via
|
||||
// ANSLIBS_API so consuming projects can link ANSLibsLoader.lib instead of
|
||||
// nvinfer_XX.lib / nvonnxparser_XX.lib.
|
||||
//
|
||||
// Two responsibilities:
|
||||
//
|
||||
// 1. Provide extern "C" stub DEFINITIONS for every symbol that TRT / ONNX
|
||||
// parser inline wrappers reference. This satisfies the linker without
|
||||
// linking nvinfer_XX.lib / nvonnxparser_XX.lib. Each stub forwards the
|
||||
// call through a function pointer that Initialize() populates at runtime.
|
||||
//
|
||||
// 2. Implement NvDynLoader::Initialize() which searches for installed NVIDIA
|
||||
// DLLs (trying multiple major versions, newest first) and binds all
|
||||
// required function pointers.
|
||||
// ============================================================================
|
||||
|
||||
#include "NvDynLoader.h"
|
||||
#include "DynLibUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
using namespace ANSCENTER::DynLib;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Static member definitions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
bool NvDynLoader::s_initialized = false;
|
||||
int NvDynLoader::s_trtMajor = 0;
|
||||
std::string NvDynLoader::s_trtPath;
|
||||
std::string NvDynLoader::s_onnxPath;
|
||||
std::string NvDynLoader::s_cudaPath;
|
||||
std::string NvDynLoader::s_cudnnPath;
|
||||
LibHandle NvDynLoader::s_hTrt = nullptr;
|
||||
LibHandle NvDynLoader::s_hOnnx = nullptr;
|
||||
LibHandle NvDynLoader::s_hCuda = nullptr;
|
||||
LibHandle NvDynLoader::s_hCudnn = nullptr;
|
||||
|
||||
NvDynLoader::PfnBuilder* NvDynLoader::pfn_createInferBuilder_INTERNAL = nullptr;
|
||||
NvDynLoader::PfnRuntime* NvDynLoader::pfn_createInferRuntime_INTERNAL = nullptr;
|
||||
NvDynLoader::PfnRefitter* NvDynLoader::pfn_createInferRefitter_INTERNAL = nullptr;
|
||||
NvDynLoader::PfnParser* NvDynLoader::pfn_createNvOnnxParser_INTERNAL = nullptr;
|
||||
NvDynLoader::PfnParserRefitter* NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL = nullptr;
|
||||
NvDynLoader::PfnGetParserVersion* NvDynLoader::pfn_getNvOnnxParserVersion = nullptr;
|
||||
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
cudaError_t (*NvDynLoader::pfn_cudaGetDeviceCount) (int*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaSetDevice) (int) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaGetDeviceProperties) (cudaDeviceProp*, int) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaDeviceSetLimit) (cudaLimit, size_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaDeviceSynchronize) () = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaDeviceGetStreamPriorityRange)(int*, int*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaMalloc) (void**, size_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaFree) (void*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaMemset) (void*, int, size_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaMemGetInfo) (size_t*, size_t*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaMemcpy) (void*, const void*, size_t, cudaMemcpyKind) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaMemcpyAsync) (void*, const void*, size_t, cudaMemcpyKind, cudaStream_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaStreamCreate) (cudaStream_t*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaStreamCreateWithPriority) (cudaStream_t*, unsigned int, int) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaStreamDestroy) (cudaStream_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaStreamSynchronize) (cudaStream_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaStreamWaitEvent) (cudaStream_t, cudaEvent_t, unsigned int) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaEventCreate) (cudaEvent_t*) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaEventCreateWithFlags) (cudaEvent_t*, unsigned int) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaEventRecord) (cudaEvent_t, cudaStream_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaEventDestroy) (cudaEvent_t) = nullptr;
|
||||
const char* (*NvDynLoader::pfn_cudaGetErrorString) (cudaError_t) = nullptr;
|
||||
cudaError_t (*NvDynLoader::pfn_cudaGetLastError) () = nullptr;
|
||||
#endif // NV_DYNAMIC_CUDA
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// extern "C" stubs (exported from ANSLibsLoader.dll via .def file)
|
||||
//
|
||||
// These provide the linker symbols that TRT / ONNX-parser inline wrappers
|
||||
// reference. TENSORRTAPI / NVONNXPARSER_API are overridden to empty in
|
||||
// NvDynLoader.h, so the NvInfer.h / NvOnnxParser.h declarations are plain
|
||||
// extern "C" (no __declspec attribute). Our definitions below are also
|
||||
// plain extern "C" — no __declspec attribute — so the linkage matches.
|
||||
//
|
||||
// The symbols are exported from the DLL via ANSLibsLoader.def, NOT via
|
||||
// __declspec(dllexport). This avoids the C2375 "different linkage" error
|
||||
// that occurs when NvInfer.h and our definitions carry different attributes.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
extern "C" {
|
||||
|
||||
void* createInferBuilder_INTERNAL(void* logger, int32_t version) noexcept
|
||||
{
|
||||
assert(NvDynLoader::pfn_createInferBuilder_INTERNAL &&
|
||||
"NvDynLoader::Initialize() has not been called before the first TRT use.");
|
||||
return NvDynLoader::pfn_createInferBuilder_INTERNAL(logger, version);
|
||||
}
|
||||
|
||||
void* createInferRuntime_INTERNAL(void* logger, int32_t version) noexcept
|
||||
{
|
||||
assert(NvDynLoader::pfn_createInferRuntime_INTERNAL &&
|
||||
"NvDynLoader::Initialize() has not been called before the first TRT use.");
|
||||
return NvDynLoader::pfn_createInferRuntime_INTERNAL(logger, version);
|
||||
}
|
||||
|
||||
// createInferRefitter_INTERNAL — only needed if engine refitting is used;
|
||||
// guarded so a missing symbol is a no-op rather than an assert failure.
|
||||
void* createInferRefitter_INTERNAL(void* engine, void* logger, int32_t version) noexcept
|
||||
{
|
||||
if (!NvDynLoader::pfn_createInferRefitter_INTERNAL) return nullptr;
|
||||
return NvDynLoader::pfn_createInferRefitter_INTERNAL(engine, logger, version);
|
||||
}
|
||||
|
||||
void* createNvOnnxParser_INTERNAL(void* network, void* logger, int32_t version) noexcept
|
||||
{
|
||||
assert(NvDynLoader::pfn_createNvOnnxParser_INTERNAL &&
|
||||
"NvDynLoader::Initialize() has not been called before the first ONNX-parser use.");
|
||||
return NvDynLoader::pfn_createNvOnnxParser_INTERNAL(network, logger, version);
|
||||
}
|
||||
|
||||
// createNvOnnxParserRefitter_INTERNAL — TRT 10+ symbol; absent on TRT 8/9.
|
||||
// Guarded rather than asserted so older TRT versions continue to work.
|
||||
void* createNvOnnxParserRefitter_INTERNAL(void* refitter, void* logger, int32_t version) noexcept
|
||||
{
|
||||
if (!NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL) return nullptr;
|
||||
return NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL(refitter, logger, version);
|
||||
}
|
||||
|
||||
// getNvOnnxParserVersion — optional version query; returns 0 if not available.
|
||||
int getNvOnnxParserVersion() noexcept
|
||||
{
|
||||
if (!NvDynLoader::pfn_getNvOnnxParserVersion) return 0;
|
||||
return NvDynLoader::pfn_getNvOnnxParserVersion();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// CUDA stubs (only when NV_DYNAMIC_CUDA is defined)
|
||||
// Removes the cudart_static.lib dependency; CUDA RT is loaded dynamically.
|
||||
//
|
||||
// WHY extern "C":
|
||||
// cuda_runtime.h wraps every public API in `extern "C"` when compiled as C++,
|
||||
// giving each function C linkage (no name mangling). Our stub DEFINITIONS
|
||||
// must use the same linkage — otherwise the linker sees a C-linkage declaration
|
||||
// (from the header) paired with a C++-mangled definition (from our .cpp), which
|
||||
// is an unresolved-symbol error on both MSVC and GCC/Clang.
|
||||
//
|
||||
// WHY cudaDeviceSynchronize / cudaGetLastError are NOT in the macro list:
|
||||
// CUDA_STUB_N macros require at least one parameter. These two functions take
|
||||
// zero arguments; they are defined manually in the block below. Do NOT add
|
||||
// them back to the macro invocation list — it would create duplicate definitions.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
|
||||
extern "C" { // ← must match the extern "C" in cuda_runtime.h
|
||||
|
||||
#define CUDA_STUB_1(ret, name, t0, a0) \
|
||||
ret name(t0 a0) { \
|
||||
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0); }
|
||||
|
||||
#define CUDA_STUB_2(ret, name, t0,a0, t1,a1) \
|
||||
ret name(t0 a0, t1 a1) { \
|
||||
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1); }
|
||||
|
||||
#define CUDA_STUB_3(ret, name, t0,a0, t1,a1, t2,a2) \
|
||||
ret name(t0 a0, t1 a1, t2 a2) { \
|
||||
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2); }
|
||||
|
||||
#define CUDA_STUB_4(ret, name, t0,a0, t1,a1, t2,a2, t3,a3) \
|
||||
ret name(t0 a0, t1 a1, t2 a2, t3 a3) { \
|
||||
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2,a3); }
|
||||
|
||||
#define CUDA_STUB_5(ret, name, t0,a0, t1,a1, t2,a2, t3,a3, t4,a4) \
|
||||
ret name(t0 a0, t1 a1, t2 a2, t3 a3, t4 a4) { \
|
||||
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2,a3,a4); }
|
||||
|
||||
CUDA_STUB_1(cudaError_t, cudaGetDeviceCount, int*, count)
|
||||
CUDA_STUB_1(cudaError_t, cudaSetDevice, int, dev)
|
||||
CUDA_STUB_2(cudaError_t, cudaGetDeviceProperties, cudaDeviceProp*, prop, int, dev)
|
||||
CUDA_STUB_2(cudaError_t, cudaDeviceSetLimit, cudaLimit, limit, size_t, value)
|
||||
CUDA_STUB_2(cudaError_t, cudaDeviceGetStreamPriorityRange, int*, leastPriority, int*, greatestPriority)
|
||||
CUDA_STUB_2(cudaError_t, cudaMalloc, void**, devPtr, size_t, size)
|
||||
CUDA_STUB_1(cudaError_t, cudaFree, void*, devPtr)
|
||||
CUDA_STUB_3(cudaError_t, cudaMemset, void*, devPtr, int, value, size_t, count)
|
||||
CUDA_STUB_2(cudaError_t, cudaMemGetInfo, size_t*, free, size_t*, total)
|
||||
CUDA_STUB_4(cudaError_t, cudaMemcpy, void*, dst, const void*, src, size_t, count, cudaMemcpyKind, kind)
|
||||
CUDA_STUB_5(cudaError_t, cudaMemcpyAsync, void*, dst, const void*, src, size_t, count, cudaMemcpyKind, kind, cudaStream_t, stream)
|
||||
CUDA_STUB_1(cudaError_t, cudaStreamCreate, cudaStream_t*, stream)
|
||||
CUDA_STUB_3(cudaError_t, cudaStreamCreateWithPriority, cudaStream_t*, stream, unsigned int, flags, int, priority)
|
||||
CUDA_STUB_1(cudaError_t, cudaStreamDestroy, cudaStream_t, stream)
|
||||
CUDA_STUB_1(cudaError_t, cudaStreamSynchronize, cudaStream_t, stream)
|
||||
CUDA_STUB_3(cudaError_t, cudaStreamWaitEvent, cudaStream_t, stream, cudaEvent_t, event, unsigned int, flags)
|
||||
CUDA_STUB_1(cudaError_t, cudaEventCreate, cudaEvent_t*, event)
|
||||
CUDA_STUB_2(cudaError_t, cudaEventCreateWithFlags, cudaEvent_t*, event, unsigned int, flags)
|
||||
CUDA_STUB_2(cudaError_t, cudaEventRecord, cudaEvent_t, event, cudaStream_t, stream)
|
||||
CUDA_STUB_1(cudaError_t, cudaEventDestroy, cudaEvent_t, event)
|
||||
CUDA_STUB_1(const char*, cudaGetErrorString, cudaError_t, error)
|
||||
|
||||
// 0-argument stubs — defined manually; NOT in the macro list above:
|
||||
cudaError_t cudaDeviceSynchronize() {
|
||||
assert(NvDynLoader::pfn_cudaDeviceSynchronize);
|
||||
return NvDynLoader::pfn_cudaDeviceSynchronize();
|
||||
}
|
||||
cudaError_t cudaGetLastError() {
|
||||
assert(NvDynLoader::pfn_cudaGetLastError);
|
||||
return NvDynLoader::pfn_cudaGetLastError();
|
||||
}
|
||||
|
||||
#undef CUDA_STUB_1
|
||||
#undef CUDA_STUB_2
|
||||
#undef CUDA_STUB_3
|
||||
#undef CUDA_STUB_4
|
||||
#undef CUDA_STUB_5
|
||||
|
||||
} // extern "C"
|
||||
#endif // NV_DYNAMIC_CUDA
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Helper — shared directory path with trailing separator
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
static std::string SharedDirWithSep()
|
||||
{
|
||||
std::string dir = DEFAULT_SHARED_DIR;
|
||||
#ifdef _WIN32
|
||||
if (!dir.empty() && dir.back() != '\\') dir += '\\';
|
||||
#else
|
||||
if (!dir.empty() && dir.back() != '/') dir += '/';
|
||||
#endif
|
||||
return dir;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// DLL candidate lists
|
||||
// Priority 1 — ANSCENTER shared directory (full absolute path, newest first)
|
||||
// Priority 2 — System PATH / LD_LIBRARY_PATH fallback (bare name, newest first)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
std::vector<std::string> NvDynLoader::TrtCandidates()
|
||||
{
|
||||
const std::string ansDir = SharedDirWithSep();
|
||||
std::vector<std::string> v;
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
for (int major = 20; major >= 8; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back(ansDir + "nvinfer_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back(ansDir + "libnvinfer.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
for (int major = 20; major >= 8; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back("nvinfer_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back("libnvinfer.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> NvDynLoader::OnnxCandidates()
|
||||
{
|
||||
const std::string ansDir = SharedDirWithSep();
|
||||
std::vector<std::string> v;
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
for (int major = 20; major >= 8; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back(ansDir + "nvonnxparser_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back(ansDir + "libnvonnxparser.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
for (int major = 20; major >= 8; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back("nvonnxparser_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back("libnvonnxparser.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> NvDynLoader::CudnnCandidates()
|
||||
{
|
||||
const std::string ansDir = SharedDirWithSep();
|
||||
std::vector<std::string> v;
|
||||
// ── cuDNN DLL/SO naming conventions ───────────────────────────────────────
|
||||
// Windows: cudnn64_<major>.dll (e.g. cudnn64_8.dll, cudnn64_9.dll)
|
||||
// Linux: libcudnn.so.<major> (e.g. libcudnn.so.8, libcudnn.so.9)
|
||||
//
|
||||
// Note: cuDNN 9 on Windows ships as multiple split DLLs
|
||||
// (cudnn_ops.dll, cudnn_cnn.dll, etc.) but cudnn64_9.dll remains the
|
||||
// main entry-point / compatibility shim. The split DLLs are resolved
|
||||
// automatically once the ANSCENTER directory is added to the search path
|
||||
// via LOAD_WITH_ALTERED_SEARCH_PATH (Windows) or RTLD_GLOBAL (Linux).
|
||||
//
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
for (int major = 12; major >= 7; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back(ansDir + "cudnn64_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back(ansDir + "libcudnn.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
for (int major = 12; major >= 7; --major) {
|
||||
#ifdef _WIN32
|
||||
v.push_back("cudnn64_" + std::to_string(major) + ".dll");
|
||||
#else
|
||||
v.push_back("libcudnn.so." + std::to_string(major));
|
||||
#endif
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
std::vector<std::string> NvDynLoader::CudaRtCandidates()
|
||||
{
|
||||
const std::string ansDir = SharedDirWithSep();
|
||||
std::vector<std::string> v;
|
||||
// ── CUDA runtime DLL/SO naming conventions ────────────────────────────────
|
||||
//
|
||||
// Windows — NVIDIA changed naming at CUDA 12:
|
||||
// CUDA 11.x : cudart64_110.dll … cudart64_118.dll (major + minor digit)
|
||||
// CUDA 12+ : cudart64_12.dll, cudart64_13.dll … (major-only)
|
||||
//
|
||||
// Linux — major-only symlink is the stable name on all versions:
|
||||
// libcudart.so.11, libcudart.so.12, libcudart.so.13 …
|
||||
// (major.minor symlinks also tried as fallback for CUDA 11.x)
|
||||
//
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
for (int major = 15; major >= 12; --major) // CUDA 12+ : major-only
|
||||
v.push_back(ansDir + "cudart64_" + std::to_string(major) + ".dll");
|
||||
for (int minor = 9; minor >= 0; --minor) // CUDA 11.x: major+minor
|
||||
v.push_back(ansDir + "cudart64_11" + std::to_string(minor) + ".dll");
|
||||
v.push_back(ansDir + "cudart64.dll"); // non-versioned alias
|
||||
#else
|
||||
for (int major = 15; major >= 11; --major) // all versions: major-only
|
||||
v.push_back(ansDir + "libcudart.so." + std::to_string(major));
|
||||
for (int minor = 9; minor >= 0; --minor) // CUDA 11.x: major.minor fallback
|
||||
v.push_back(ansDir + "libcudart.so.11." + std::to_string(minor));
|
||||
#endif
|
||||
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
#ifdef _WIN32
|
||||
for (int major = 15; major >= 12; --major)
|
||||
v.push_back("cudart64_" + std::to_string(major) + ".dll");
|
||||
for (int minor = 9; minor >= 0; --minor)
|
||||
v.push_back("cudart64_11" + std::to_string(minor) + ".dll");
|
||||
v.push_back("cudart64.dll");
|
||||
#else
|
||||
for (int major = 15; major >= 11; --major)
|
||||
v.push_back("libcudart.so." + std::to_string(major));
|
||||
for (int minor = 9; minor >= 0; --minor)
|
||||
v.push_back("libcudart.so.11." + std::to_string(minor));
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Initialize
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
static std::mutex g_initMutex;
|
||||
|
||||
bool NvDynLoader::Initialize(bool verbose)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_initMutex);
|
||||
if (s_initialized) return true;
|
||||
|
||||
const std::string ansDir = SharedDirWithSep();
|
||||
|
||||
// If a previous Initialize() call partially loaded some libraries before
|
||||
// failing (s_initialized stays false but handles may be non-null), release
|
||||
// them now so we can retry cleanly without leaking handles.
|
||||
if (s_hOnnx) { FreeLib(s_hOnnx); s_hOnnx = nullptr; }
|
||||
if (s_hTrt) { FreeLib(s_hTrt); s_hTrt = nullptr; }
|
||||
if (s_hCudnn) { FreeLib(s_hCudnn); s_hCudnn = nullptr; }
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
if (s_hCuda) { FreeLib(s_hCuda); s_hCuda = nullptr; }
|
||||
#endif
|
||||
|
||||
bool ok = true;
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "==================================================" << std::endl;
|
||||
std::cout << "NvDynLoader: discovering NVIDIA libraries..." << std::endl;
|
||||
std::cout << " Shared dir : " << ansDir << std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 1: CUDA Runtime (NV_DYNAMIC_CUDA only) ───────────────────────────
|
||||
// Loaded first so cuDNN and TRT find CUDA symbols already resident in the
|
||||
// process image when they are opened.
|
||||
// Linux: globalLoad=true (RTLD_GLOBAL) makes cudart symbols process-wide.
|
||||
// Windows: LoadLibraryExA is always process-global; globalLoad is a no-op.
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
s_hCuda = FindAndLoad(CudaRtCandidates(), s_cudaPath, verbose, /*globalLoad=*/true);
|
||||
if (!s_hCuda) {
|
||||
std::cout << "NvDynLoader ERROR: No CUDA runtime DLL found. "
|
||||
"Searched " << ansDir << " and system PATH." << std::endl;
|
||||
ok = false;
|
||||
} else {
|
||||
bool b = true;
|
||||
b &= Bind(s_hCuda, "cudaGetDeviceCount", pfn_cudaGetDeviceCount);
|
||||
b &= Bind(s_hCuda, "cudaSetDevice", pfn_cudaSetDevice);
|
||||
// cudaGetDeviceProperties: CUDA 12 renamed the export to '_v2'; CUDA 11
|
||||
// uses the plain name. Try the CUDA 12+ symbol first, fall back to
|
||||
// the CUDA 11 name. IMPORTANT: do NOT `b &=` the first attempt before
|
||||
// the fallback — that would set b=false on CUDA 11 even though the
|
||||
// plain-name fallback succeeds, causing a spurious init failure.
|
||||
Bind(s_hCuda, "cudaGetDeviceProperties_v2", pfn_cudaGetDeviceProperties); // CUDA 12+
|
||||
if (!pfn_cudaGetDeviceProperties)
|
||||
Bind(s_hCuda, "cudaGetDeviceProperties", pfn_cudaGetDeviceProperties); // CUDA 11
|
||||
b &= (pfn_cudaGetDeviceProperties != nullptr);
|
||||
b &= Bind(s_hCuda, "cudaDeviceSetLimit", pfn_cudaDeviceSetLimit);
|
||||
b &= Bind(s_hCuda, "cudaDeviceSynchronize", pfn_cudaDeviceSynchronize);
|
||||
b &= Bind(s_hCuda, "cudaDeviceGetStreamPriorityRange", pfn_cudaDeviceGetStreamPriorityRange);
|
||||
b &= Bind(s_hCuda, "cudaMalloc", pfn_cudaMalloc);
|
||||
b &= Bind(s_hCuda, "cudaFree", pfn_cudaFree);
|
||||
b &= Bind(s_hCuda, "cudaMemset", pfn_cudaMemset);
|
||||
b &= Bind(s_hCuda, "cudaMemGetInfo", pfn_cudaMemGetInfo);
|
||||
b &= Bind(s_hCuda, "cudaMemcpy", pfn_cudaMemcpy);
|
||||
b &= Bind(s_hCuda, "cudaMemcpyAsync", pfn_cudaMemcpyAsync);
|
||||
b &= Bind(s_hCuda, "cudaStreamCreate", pfn_cudaStreamCreate);
|
||||
b &= Bind(s_hCuda, "cudaStreamCreateWithPriority", pfn_cudaStreamCreateWithPriority);
|
||||
b &= Bind(s_hCuda, "cudaStreamDestroy", pfn_cudaStreamDestroy);
|
||||
b &= Bind(s_hCuda, "cudaStreamSynchronize", pfn_cudaStreamSynchronize);
|
||||
b &= Bind(s_hCuda, "cudaStreamWaitEvent", pfn_cudaStreamWaitEvent);
|
||||
b &= Bind(s_hCuda, "cudaEventCreate", pfn_cudaEventCreate);
|
||||
b &= Bind(s_hCuda, "cudaEventCreateWithFlags", pfn_cudaEventCreateWithFlags);
|
||||
b &= Bind(s_hCuda, "cudaEventRecord", pfn_cudaEventRecord);
|
||||
b &= Bind(s_hCuda, "cudaEventDestroy", pfn_cudaEventDestroy);
|
||||
b &= Bind(s_hCuda, "cudaGetErrorString", pfn_cudaGetErrorString);
|
||||
b &= Bind(s_hCuda, "cudaGetLastError", pfn_cudaGetLastError);
|
||||
if (!b) {
|
||||
std::cout << "NvDynLoader ERROR: One or more CUDA entry points not found in "
|
||||
<< s_cudaPath << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
#endif // NV_DYNAMIC_CUDA
|
||||
|
||||
// ── STEP 2: cuDNN pre-load ────────────────────────────────────────────────
|
||||
// Must be loaded BEFORE TRT so the OS can resolve TRT's cuDNN dependency:
|
||||
//
|
||||
// Windows – LoadLibraryExA + LOAD_WITH_ALTERED_SEARCH_PATH causes Windows
|
||||
// to use the DLL's own directory when resolving its transitive
|
||||
// dependencies. Pre-loading cuDNN from ANSCENTER dir also puts
|
||||
// it in the process DLL table so TRT's import loader finds it.
|
||||
//
|
||||
// Linux – RTLD_GLOBAL exports cuDNN symbols process-wide so TRT's
|
||||
// DT_NEEDED resolution succeeds without LD_LIBRARY_PATH changes.
|
||||
// cuDNN 9 also ships split DLLs (libcudnn_ops.so.9, etc.); those
|
||||
// are found automatically once libcudnn.so.9 is globally loaded.
|
||||
//
|
||||
// Not finding cuDNN is a WARNING, not a fatal error — TRT may still locate
|
||||
// it via LD_LIBRARY_PATH / system PATH at load time.
|
||||
s_hCudnn = FindAndLoad(CudnnCandidates(), s_cudnnPath, verbose, /*globalLoad=*/true);
|
||||
if (!s_hCudnn && verbose) {
|
||||
std::cout << "NvDynLoader: WARNING — cuDNN not found in " << ansDir
|
||||
<< "; TRT will search system PATH / LD_LIBRARY_PATH." << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 3: TensorRT core ─────────────────────────────────────────────────
|
||||
s_hTrt = FindAndLoad(TrtCandidates(), s_trtPath, verbose);
|
||||
if (!s_hTrt) {
|
||||
std::cout << "NvDynLoader ERROR: No TensorRT DLL found. "
|
||||
"Searched " << ansDir << " and system PATH." << std::endl;
|
||||
ok = false;
|
||||
} else {
|
||||
// Extract major version from the loaded library path.
|
||||
// Windows : "C:\...\nvinfer_10.dll" → digits between last '_' and last '.'
|
||||
// Linux : ".../libnvinfer.so.10" → digits after last '.'
|
||||
#ifdef _WIN32
|
||||
{
|
||||
const size_t under = s_trtPath.find_last_of('_');
|
||||
const size_t dot = s_trtPath.find_last_of('.');
|
||||
if (under != std::string::npos && dot != std::string::npos && dot > under) {
|
||||
try { s_trtMajor = std::stoi(s_trtPath.substr(under + 1, dot - under - 1)); }
|
||||
catch (...) { /* non-numeric — leave s_trtMajor at 0 */ }
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
const size_t dot = s_trtPath.find_last_of('.');
|
||||
if (dot != std::string::npos && dot + 1 < s_trtPath.size()) {
|
||||
try { s_trtMajor = std::stoi(s_trtPath.substr(dot + 1)); }
|
||||
catch (...) { /* non-numeric — leave s_trtMajor at 0 */ }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool b = true;
|
||||
b &= Bind(s_hTrt, "createInferBuilder_INTERNAL", pfn_createInferBuilder_INTERNAL);
|
||||
b &= Bind(s_hTrt, "createInferRuntime_INTERNAL", pfn_createInferRuntime_INTERNAL);
|
||||
Bind(s_hTrt, "createInferRefitter_INTERNAL", pfn_createInferRefitter_INTERNAL); // optional
|
||||
if (!b) {
|
||||
std::cout << "NvDynLoader ERROR: Required TRT entry points not found in "
|
||||
<< s_trtPath << std::endl;
|
||||
ok = false;
|
||||
} else if (verbose) {
|
||||
std::cout << "NvDynLoader: TRT major version = " << s_trtMajor << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ── STEP 4: ONNX parser ───────────────────────────────────────────────────
|
||||
s_hOnnx = FindAndLoad(OnnxCandidates(), s_onnxPath, verbose);
|
||||
if (!s_hOnnx) {
|
||||
std::cout << "NvDynLoader ERROR: No nvonnxparser DLL found. "
|
||||
"Searched " << ansDir << " and system PATH." << std::endl;
|
||||
ok = false;
|
||||
} else {
|
||||
if (!Bind(s_hOnnx, "createNvOnnxParser_INTERNAL", pfn_createNvOnnxParser_INTERNAL)) {
|
||||
std::cout << "NvDynLoader ERROR: createNvOnnxParser_INTERNAL not found in "
|
||||
<< s_onnxPath << std::endl;
|
||||
ok = false;
|
||||
} else {
|
||||
// TRT 10+ optional symbols — absent on TRT 8/9; missing is not an error.
|
||||
Bind(s_hOnnx, "createNvOnnxParserRefitter_INTERNAL", pfn_createNvOnnxParserRefitter_INTERNAL);
|
||||
Bind(s_hOnnx, "getNvOnnxParserVersion", pfn_getNvOnnxParserVersion);
|
||||
|
||||
// Cross-check: TRT and ONNX-parser must share the same major version.
|
||||
// Mismatched majors (e.g. nvinfer_10 + nvonnxparser_11) compile fine
|
||||
// but crash at runtime when the ONNX parser tries to populate a TRT
|
||||
// network object built by a different major version.
|
||||
int onnxMajor = 0;
|
||||
#ifdef _WIN32
|
||||
{
|
||||
const size_t under = s_onnxPath.find_last_of('_');
|
||||
const size_t dot = s_onnxPath.find_last_of('.');
|
||||
if (under != std::string::npos && dot != std::string::npos && dot > under)
|
||||
try { onnxMajor = std::stoi(s_onnxPath.substr(under + 1, dot - under - 1)); }
|
||||
catch (...) {}
|
||||
}
|
||||
#else
|
||||
{
|
||||
const size_t dot = s_onnxPath.find_last_of('.');
|
||||
if (dot != std::string::npos && dot + 1 < s_onnxPath.size())
|
||||
try { onnxMajor = std::stoi(s_onnxPath.substr(dot + 1)); }
|
||||
catch (...) {}
|
||||
}
|
||||
#endif
|
||||
if (onnxMajor > 0 && s_trtMajor > 0 && onnxMajor != s_trtMajor) {
|
||||
std::cout << "NvDynLoader ERROR: TRT major version (" << s_trtMajor
|
||||
<< ") != ONNX-parser major version (" << onnxMajor << ").\n"
|
||||
<< " TRT : " << s_trtPath << "\n"
|
||||
<< " ONNX : " << s_onnxPath << "\n"
|
||||
<< " Replace both DLLs with matching versions in "
|
||||
<< ansDir << std::endl;
|
||||
ok = false;
|
||||
} else if (verbose && onnxMajor > 0) {
|
||||
std::cout << "NvDynLoader: ONNX-parser major version = " << onnxMajor << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_initialized = ok;
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "NvDynLoader: "
|
||||
<< (ok ? "initialised successfully." : "FAILED — check errors above.")
|
||||
<< std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Shutdown
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
void NvDynLoader::Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_initMutex);
|
||||
|
||||
// NOTE: No early-return guard on s_initialized here.
|
||||
//
|
||||
// Shutdown() must always release whatever handles are currently open,
|
||||
// including handles left behind by a *partially*-successful Initialize()
|
||||
// call (where s_initialized == false but some DLLs were already opened).
|
||||
// Every FreeLib call is guarded by if(h), so this function is safe to call
|
||||
// on a fully- or partially-initialised instance, and also safe to call
|
||||
// multiple times (idempotent).
|
||||
|
||||
// ── Null all entry-point pointers first ───────────────────────────────────
|
||||
// Prevents stubs from jumping into freed library memory in the window
|
||||
// between Shutdown() and a subsequent Initialize() call.
|
||||
pfn_createInferBuilder_INTERNAL = nullptr;
|
||||
pfn_createInferRuntime_INTERNAL = nullptr;
|
||||
pfn_createInferRefitter_INTERNAL = nullptr;
|
||||
pfn_createNvOnnxParser_INTERNAL = nullptr;
|
||||
pfn_createNvOnnxParserRefitter_INTERNAL = nullptr;
|
||||
pfn_getNvOnnxParserVersion = nullptr;
|
||||
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
// Null every CUDA function pointer so the assert() in each stub fires
|
||||
// immediately if a CUDA call is made after Shutdown() without a new
|
||||
// Initialize(), rather than silently calling into freed DLL memory.
|
||||
pfn_cudaGetDeviceCount = nullptr;
|
||||
pfn_cudaSetDevice = nullptr;
|
||||
pfn_cudaGetDeviceProperties = nullptr;
|
||||
pfn_cudaDeviceSetLimit = nullptr;
|
||||
pfn_cudaDeviceSynchronize = nullptr;
|
||||
pfn_cudaDeviceGetStreamPriorityRange = nullptr;
|
||||
pfn_cudaMalloc = nullptr;
|
||||
pfn_cudaFree = nullptr;
|
||||
pfn_cudaMemset = nullptr;
|
||||
pfn_cudaMemGetInfo = nullptr;
|
||||
pfn_cudaMemcpy = nullptr;
|
||||
pfn_cudaMemcpyAsync = nullptr;
|
||||
pfn_cudaStreamCreate = nullptr;
|
||||
pfn_cudaStreamCreateWithPriority = nullptr;
|
||||
pfn_cudaStreamDestroy = nullptr;
|
||||
pfn_cudaStreamSynchronize = nullptr;
|
||||
pfn_cudaStreamWaitEvent = nullptr;
|
||||
pfn_cudaEventCreate = nullptr;
|
||||
pfn_cudaEventCreateWithFlags = nullptr;
|
||||
pfn_cudaEventRecord = nullptr;
|
||||
pfn_cudaEventDestroy = nullptr;
|
||||
pfn_cudaGetErrorString = nullptr;
|
||||
pfn_cudaGetLastError = nullptr;
|
||||
#endif // NV_DYNAMIC_CUDA
|
||||
|
||||
// ── Release handles in reverse load order ─────────────────────────────────
|
||||
// ONNX parser → depends on TRT
|
||||
// TRT → depends on cuDNN + CUDA RT
|
||||
// cuDNN → depends on CUDA RT
|
||||
// CUDA RT → base dependency
|
||||
if (s_hOnnx) { FreeLib(s_hOnnx); s_hOnnx = nullptr; }
|
||||
if (s_hTrt) { FreeLib(s_hTrt); s_hTrt = nullptr; }
|
||||
if (s_hCudnn) { FreeLib(s_hCudnn); s_hCudnn = nullptr; }
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
if (s_hCuda) { FreeLib(s_hCuda); s_hCuda = nullptr; }
|
||||
#endif
|
||||
|
||||
// ── Reset version / path state ────────────────────────────────────────────
|
||||
// A subsequent Initialize() call will re-discover fresh paths and versions.
|
||||
s_trtMajor = 0;
|
||||
s_trtPath.clear();
|
||||
s_onnxPath.clear();
|
||||
s_cudaPath.clear();
|
||||
s_cudnnPath.clear();
|
||||
s_initialized = false;
|
||||
}
|
||||
252
core/ANSLibsLoader/OvLoader.cpp
Normal file
252
core/ANSLibsLoader/OvLoader.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
// ============================================================================
|
||||
// OvLoader.cpp — OpenVINO DLL discovery and pre-loading
|
||||
//
|
||||
// Loading order (dependency chain):
|
||||
// 1. Intel TBB (tbb12.dll / tbbmalloc.dll) — required by openvino.dll
|
||||
// 2. openvino.dll — core runtime
|
||||
// 3. openvino_c.dll — C API (optional, version query)
|
||||
//
|
||||
// Plugins (openvino_intel_cpu_plugin, openvino_intel_gpu_plugin, etc.) and
|
||||
// frontends (openvino_ir_frontend, openvino_onnx_frontend, etc.) are loaded
|
||||
// on-demand by OpenVINO's internal plugin system. They are discovered
|
||||
// automatically because the shared directory is injected into the DLL
|
||||
// search path by ANSLibsLoader before OvLoader::Initialize() runs.
|
||||
// ============================================================================
|
||||
|
||||
#include "OvLoader.h"
|
||||
#include "DynLibUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
using namespace ANSCENTER::DynLib;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Static member definitions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
std::mutex OvLoader::s_mutex;
|
||||
bool OvLoader::s_initialized = false;
|
||||
OvInfo OvLoader::s_info;
|
||||
LibHandle OvLoader::s_hTbb = nullptr;
|
||||
LibHandle OvLoader::s_hTbbMalloc = nullptr;
|
||||
LibHandle OvLoader::s_hOvCore = nullptr;
|
||||
LibHandle OvLoader::s_hOvC = nullptr;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Candidate lists — search ANSCENTER shared dir first, then system PATH
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
std::vector<std::string> OvLoader::TbbCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir, "tbb12.dll"));
|
||||
v.push_back(JoinPath(shared_dir, "tbb.dll"));
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir, "libtbb.so.12"));
|
||||
v.push_back(JoinPath(shared_dir, "libtbb.so.2"));
|
||||
v.push_back(JoinPath(shared_dir, "libtbb.so"));
|
||||
#endif
|
||||
|
||||
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
|
||||
#ifdef _WIN32
|
||||
v.push_back("tbb12.dll");
|
||||
v.push_back("tbb.dll");
|
||||
#else
|
||||
v.push_back("libtbb.so.12");
|
||||
v.push_back("libtbb.so.2");
|
||||
v.push_back("libtbb.so");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> OvLoader::TbbMallocCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir, "tbbmalloc.dll"));
|
||||
v.push_back("tbbmalloc.dll");
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir, "libtbbmalloc.so.2"));
|
||||
v.push_back(JoinPath(shared_dir, "libtbbmalloc.so"));
|
||||
v.push_back("libtbbmalloc.so.2");
|
||||
v.push_back("libtbbmalloc.so");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> OvLoader::OvCoreCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir, "openvino.dll"));
|
||||
v.push_back("openvino.dll");
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir, "libopenvino.so"));
|
||||
v.push_back("libopenvino.so");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<std::string> OvLoader::OvCApiCandidates(const std::string& shared_dir)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
#ifdef _WIN32
|
||||
v.push_back(JoinPath(shared_dir, "openvino_c.dll"));
|
||||
v.push_back("openvino_c.dll");
|
||||
#else
|
||||
v.push_back(JoinPath(shared_dir, "libopenvino_c.so"));
|
||||
v.push_back("libopenvino_c.so");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Version extraction via OpenVINO C API
|
||||
//
|
||||
// The C API exports ov_get_openvino_version() which fills an ov_version_t
|
||||
// struct with a buildNumber string (e.g. "2024.6.0-17404-4c0f47d2335").
|
||||
// We replicate the struct layout locally to avoid including OpenVINO headers.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
std::string OvLoader::TryGetVersion(LibHandle hOvC)
|
||||
{
|
||||
if (!hOvC) return {};
|
||||
|
||||
// Replicate the ov_version_t layout from openvino/c/ov_common.h
|
||||
struct ov_version_local {
|
||||
const char* buildNumber;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
using fn_get_version = int (*)(ov_version_local*);
|
||||
using fn_free_version = void (*)(ov_version_local*);
|
||||
|
||||
fn_get_version pfnGet = nullptr;
|
||||
fn_free_version pfnFree = nullptr;
|
||||
|
||||
Bind(hOvC, "ov_get_openvino_version", pfnGet);
|
||||
Bind(hOvC, "ov_version_free", pfnFree);
|
||||
|
||||
if (!pfnGet) return {};
|
||||
|
||||
ov_version_local ver = {};
|
||||
if (pfnGet(&ver) == 0 && ver.buildNumber) {
|
||||
std::string result = ver.buildNumber;
|
||||
if (pfnFree) pfnFree(&ver);
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Initialize
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
const OvInfo& OvLoader::Initialize(const std::string& shared_dir, bool verbose)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
if (s_initialized) return s_info;
|
||||
|
||||
// Clean up any partially-loaded handles from a previous failed attempt
|
||||
if (s_hOvC) { FreeLib(s_hOvC); s_hOvC = nullptr; }
|
||||
if (s_hOvCore) { FreeLib(s_hOvCore); s_hOvCore = nullptr; }
|
||||
if (s_hTbbMalloc) { FreeLib(s_hTbbMalloc); s_hTbbMalloc = nullptr; }
|
||||
if (s_hTbb) { FreeLib(s_hTbb); s_hTbb = nullptr; }
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "==================================================" << std::endl;
|
||||
std::cout << "[OvLoader] Discovering OpenVINO libraries..." << std::endl;
|
||||
std::cout << " Shared dir : " << shared_dir << std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 1: Inject shared dir into search path ───────────────────────────
|
||||
// Ensures plugins/frontends are discoverable by OpenVINO's internal loader.
|
||||
InjectDllSearchPath(shared_dir);
|
||||
|
||||
// ── STEP 2: Pre-load Intel TBB (dependency of openvino.dll) ──────────────
|
||||
std::string tbbPath;
|
||||
s_hTbb = FindAndLoad(TbbCandidates(shared_dir), tbbPath, verbose);
|
||||
if (s_hTbb) {
|
||||
if (verbose)
|
||||
std::cout << "[OvLoader] TBB loaded: " << tbbPath << std::endl;
|
||||
} else if (verbose) {
|
||||
std::cout << "[OvLoader] WARNING: TBB not found "
|
||||
<< "(openvino.dll may fail to load)." << std::endl;
|
||||
}
|
||||
|
||||
std::string tbbMallocPath;
|
||||
s_hTbbMalloc = FindAndLoad(TbbMallocCandidates(shared_dir),
|
||||
tbbMallocPath, verbose);
|
||||
if (!s_hTbbMalloc && verbose) {
|
||||
std::cout << "[OvLoader] tbbmalloc not found (optional)." << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 3: Pre-load openvino.dll (core runtime) ─────────────────────────
|
||||
std::string corePath;
|
||||
s_hOvCore = FindAndLoad(OvCoreCandidates(shared_dir), corePath, verbose);
|
||||
if (s_hOvCore) {
|
||||
s_info.dllPath = corePath;
|
||||
s_info.loaded = true;
|
||||
|
||||
if (verbose)
|
||||
std::cout << "[OvLoader] OpenVINO core loaded: " << corePath
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "[OvLoader] WARNING: openvino.dll not found in "
|
||||
<< shared_dir << " or system PATH." << std::endl;
|
||||
std::cout << "[OvLoader] OpenVINO will rely on import-lib resolution "
|
||||
<< "at load time." << std::endl;
|
||||
}
|
||||
|
||||
// ── STEP 4: Pre-load openvino_c.dll + query version ──────────────────────
|
||||
std::string cApiPath;
|
||||
s_hOvC = FindAndLoad(OvCApiCandidates(shared_dir), cApiPath, verbose);
|
||||
if (s_hOvC) {
|
||||
s_info.version = TryGetVersion(s_hOvC);
|
||||
if (!s_info.version.empty() && verbose) {
|
||||
std::cout << "[OvLoader] OpenVINO version = " << s_info.version
|
||||
<< std::endl;
|
||||
}
|
||||
} else if (verbose) {
|
||||
std::cout << "[OvLoader] openvino_c.dll not found "
|
||||
<< "(version detection skipped)." << std::endl;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "[OvLoader] "
|
||||
<< (s_info.loaded
|
||||
? "initialised successfully."
|
||||
: "WARNING — openvino.dll not pre-loaded.")
|
||||
<< std::endl;
|
||||
std::cout << "==================================================" << std::endl;
|
||||
}
|
||||
return s_info;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Shutdown
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
void OvLoader::Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_mutex);
|
||||
|
||||
// Release in reverse load order
|
||||
if (s_hOvC) { FreeLib(s_hOvC); s_hOvC = nullptr; }
|
||||
if (s_hOvCore) { FreeLib(s_hOvCore); s_hOvCore = nullptr; }
|
||||
if (s_hTbbMalloc) { FreeLib(s_hTbbMalloc); s_hTbbMalloc = nullptr; }
|
||||
if (s_hTbb) { FreeLib(s_hTbb); s_hTbb = nullptr; }
|
||||
|
||||
s_info = OvInfo{};
|
||||
s_initialized = false;
|
||||
}
|
||||
23
core/ANSLibsLoader/dllmain.cpp
Normal file
23
core/ANSLibsLoader/dllmain.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#define NOMINMAX // Prevent windows.h from defining min/max macros
|
||||
#include <windows.h>
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
5
core/ANSLibsLoader/framework.h
Normal file
5
core/ANSLibsLoader/framework.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
89
core/ANSLibsLoader/include/ANSLibsLoader.h
Normal file
89
core/ANSLibsLoader/include/ANSLibsLoader.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#ifndef ANSLIBSLOADER_H
|
||||
#define ANSLIBSLOADER_H
|
||||
|
||||
// ============================================================================
|
||||
// ANSLibsLoader — Centralized dynamic library loader for ANSCENTER
|
||||
//
|
||||
// Consolidates all runtime DLL loading:
|
||||
// - ONNX Runtime (via EPLoader)
|
||||
// - TensorRT / cuDNN / CUDA (via NvDynLoader)
|
||||
// - OpenCV (via CvLoader)
|
||||
// - OpenVINO + TBB (via OvLoader)
|
||||
//
|
||||
// USAGE
|
||||
// -----
|
||||
// // At application startup:
|
||||
// ANSCENTER::ANSLibsLoader::Initialize();
|
||||
//
|
||||
// // At application exit (after all engine objects are destroyed):
|
||||
// ANSCENTER::ANSLibsLoader::Shutdown();
|
||||
//
|
||||
// EXPORT MACRO
|
||||
// ------------
|
||||
// ANSLIBS_API replaces both ANSCORE_API and ENGINE_API for loader classes.
|
||||
// Define ANSLIBSLOADER_EXPORTS when building ANSLibsLoader.dll.
|
||||
// All other projects importing from ANSLibsLoader get __declspec(dllimport).
|
||||
// ============================================================================
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef ANSLIBSLOADER_EXPORTS
|
||||
# define ANSLIBS_API __declspec(dllexport)
|
||||
# else
|
||||
# define ANSLIBS_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define ANSLIBS_API
|
||||
#endif
|
||||
|
||||
#include "ANSLicense.h" // for ANSCENTER::EngineType enum
|
||||
#include <string>
|
||||
|
||||
namespace ANSCENTER {
|
||||
|
||||
class ANSLIBS_API ANSLibsLoader
|
||||
{
|
||||
public:
|
||||
// ── Platform defaults ────────────────────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"C:\\ProgramData\\ANSCENTER\\Shared";
|
||||
#else
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"/opt/anscenter/shared";
|
||||
#endif
|
||||
|
||||
// ── Master initialization ────────────────────────────────────────────
|
||||
/// Calls all sub-loaders in the correct order:
|
||||
/// 1. Injects shared_dir into DLL search path
|
||||
/// 2. CvLoader — pre-loads OpenCV
|
||||
/// 3. OvLoader — pre-loads OpenVINO + TBB
|
||||
/// 4. NvDynLoader — loads TRT / cuDNN / CUDA (if NVIDIA)
|
||||
/// 5. EPLoader — loads ONNX Runtime with selected EP
|
||||
///
|
||||
/// Thread-safe. Subsequent calls are no-ops.
|
||||
static void Initialize(
|
||||
const std::string& shared_dir = DEFAULT_SHARED_DIR,
|
||||
EngineType preferred = EngineType::AUTO_DETECT);
|
||||
|
||||
// ── Master shutdown ──────────────────────────────────────────────────
|
||||
/// Shuts down all sub-loaders in reverse order.
|
||||
/// Must be called AFTER all engine/session objects are destroyed.
|
||||
/// Safe to call multiple times.
|
||||
static void Shutdown();
|
||||
|
||||
// ── Status ───────────────────────────────────────────────────────────
|
||||
[[nodiscard]] static bool IsInitialized();
|
||||
|
||||
// ── Non-copyable / non-movable ───────────────────────────────────────
|
||||
ANSLibsLoader() = delete;
|
||||
ANSLibsLoader(const ANSLibsLoader&) = delete;
|
||||
ANSLibsLoader& operator=(const ANSLibsLoader&) = delete;
|
||||
|
||||
private:
|
||||
static bool s_initialized;
|
||||
};
|
||||
|
||||
} // namespace ANSCENTER
|
||||
|
||||
#endif // ANSLIBSLOADER_H
|
||||
62
core/ANSLibsLoader/include/CvLoader.h
Normal file
62
core/ANSLibsLoader/include/CvLoader.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
// ============================================================================
|
||||
// CvLoader -- Runtime discovery and pre-loading of OpenCV DLLs
|
||||
//
|
||||
// OpenCV is normally import-linked (opencv_world4130.lib), but the DLLs
|
||||
// must be discoverable at process load time. CvLoader ensures the correct
|
||||
// DLL is found by:
|
||||
// 1. Searching the ANSCENTER shared directory for versioned candidates
|
||||
// 2. Injecting the directory into the DLL search path
|
||||
// 3. Pre-loading the DLL so dependent modules resolve it correctly
|
||||
//
|
||||
// Companion modules (opencv_img_hash, opencv_videoio_ffmpeg) are also
|
||||
// pre-loaded when found alongside the main opencv_world DLL.
|
||||
// ============================================================================
|
||||
|
||||
#include "ANSLibsLoader.h" // ANSLIBS_API
|
||||
#include "DynLibUtils.h" // LibHandle
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
// ============================================================================
|
||||
struct ANSLIBS_API CvInfo
|
||||
{
|
||||
std::string dllPath; // Full path to loaded opencv_world DLL
|
||||
std::string version; // e.g. "4.13.0"
|
||||
int versionCode = 0;// e.g. 4130
|
||||
bool loaded = false;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
class ANSLIBS_API CvLoader
|
||||
{
|
||||
public:
|
||||
/// Discover and pre-load OpenCV DLLs.
|
||||
/// Safe to call multiple times -- subsequent calls are no-ops.
|
||||
/// @param shared_dir Directory to search first (default: ANSCENTER shared).
|
||||
/// @param verbose Print discovery results to stdout.
|
||||
/// @returns Reference to the discovery result.
|
||||
[[nodiscard]] static const CvInfo& Initialize(
|
||||
const std::string& shared_dir = ANSCENTER::DynLib::DEFAULT_SHARED_DIR,
|
||||
bool verbose = true);
|
||||
|
||||
/// Release pre-loaded library handles.
|
||||
static void Shutdown();
|
||||
|
||||
/// Query current state.
|
||||
[[nodiscard]] static const CvInfo& Current() noexcept { return s_info; }
|
||||
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
|
||||
|
||||
private:
|
||||
/// Build candidate DLL names, newest first.
|
||||
static std::vector<std::string> CvWorldCandidates(const std::string& shared_dir);
|
||||
static std::vector<std::string> CvImgHashCandidates(const std::string& shared_dir);
|
||||
|
||||
static std::mutex s_mutex;
|
||||
static bool s_initialized;
|
||||
static CvInfo s_info;
|
||||
static LibHandle s_hCvWorld;
|
||||
static LibHandle s_hCvImgHash;
|
||||
};
|
||||
95
core/ANSLibsLoader/include/DynLibUtils.h
Normal file
95
core/ANSLibsLoader/include/DynLibUtils.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#ifndef DYNLIBUTILS_H
|
||||
#define DYNLIBUTILS_H
|
||||
|
||||
// ============================================================================
|
||||
// DynLibUtils — Shared dynamic library loading utilities
|
||||
//
|
||||
// Common infrastructure used by EPLoader, NvDynLoader, CvLoader, OvLoader, etc.
|
||||
// Consolidates duplicate utility functions that were previously in each loader.
|
||||
// ============================================================================
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
using LibHandle = HMODULE;
|
||||
# define LIB_INVALID nullptr
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
using LibHandle = void*;
|
||||
# define LIB_INVALID nullptr
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace DynLib {
|
||||
|
||||
// ── Platform defaults ────────────────────────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"C:\\ProgramData\\ANSCENTER\\Shared";
|
||||
#else
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"/opt/anscenter/shared";
|
||||
#endif
|
||||
|
||||
// ── File / path helpers ──────────────────────────────────────────────────
|
||||
|
||||
/// Returns true if @p path is a regular file.
|
||||
[[nodiscard]] bool FileExists(const std::string& path);
|
||||
|
||||
/// Joins base + component with the platform separator.
|
||||
[[nodiscard]] std::string JoinPath(const std::string& base,
|
||||
const std::string& component);
|
||||
|
||||
// ── DLL search-path injection ────────────────────────────────────────────
|
||||
|
||||
/// Adds @p dir to the DLL search path.
|
||||
/// - Windows: AddDllDirectory() + prepend to %PATH%
|
||||
/// - Linux: prepend to $LD_LIBRARY_PATH
|
||||
void InjectDllSearchPath(const std::string& dir);
|
||||
|
||||
// ── Library loading ──────────────────────────────────────────────────────
|
||||
|
||||
/// Iterates @p candidates, returns the first successfully loaded library.
|
||||
/// @param loadedPath On success, receives the path/name that was loaded.
|
||||
/// @param verbose Print discovery results to stdout.
|
||||
/// @param globalLoad Linux only: use RTLD_GLOBAL (ignored on Windows).
|
||||
[[nodiscard]] LibHandle FindAndLoad(const std::vector<std::string>& candidates,
|
||||
std::string& loadedPath,
|
||||
bool verbose = true,
|
||||
bool globalLoad = false);
|
||||
|
||||
/// Load a single library by path.
|
||||
/// @param globalLoad Linux only: use RTLD_GLOBAL.
|
||||
[[nodiscard]] LibHandle LoadLib(const std::string& path, bool globalLoad = false);
|
||||
|
||||
/// Free a loaded library handle.
|
||||
void FreeLib(LibHandle h);
|
||||
|
||||
/// Get a symbol address from a loaded library.
|
||||
[[nodiscard]] void* GetSymbol(LibHandle h, const char* sym);
|
||||
|
||||
// ── Type-safe symbol binding ─────────────────────────────────────────────
|
||||
|
||||
/// Bind a function pointer from a loaded library handle.
|
||||
/// @returns true if the symbol was found and bound.
|
||||
template<typename Fn>
|
||||
[[nodiscard]] bool Bind(LibHandle h, const char* sym, Fn*& pfn)
|
||||
{
|
||||
pfn = reinterpret_cast<Fn*>(GetSymbol(h, sym));
|
||||
return pfn != nullptr;
|
||||
}
|
||||
|
||||
} // namespace DynLib
|
||||
} // namespace ANSCENTER
|
||||
|
||||
#endif // DYNLIBUTILS_H
|
||||
116
core/ANSLibsLoader/include/EPLoader.h
Normal file
116
core/ANSLibsLoader/include/EPLoader.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
#ifndef EPLOADER_H
|
||||
#define EPLOADER_H
|
||||
|
||||
// ============================================================================
|
||||
// EPLoader — Dynamic ONNX Runtime loader
|
||||
//
|
||||
// Moved from ONNXEngine/ to ANSLibsLoader/ for centralized library management.
|
||||
// Now exported via ANSLIBS_API from ANSLibsLoader.dll.
|
||||
// ============================================================================
|
||||
|
||||
#include "ANSLibsLoader.h" // ANSLIBS_API, EngineType
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
namespace ANSCENTER {
|
||||
|
||||
struct EPInfo {
|
||||
EngineType type = EngineType::CPU;
|
||||
std::string name; // "CUDA", "OpenVINO", "DirectML", "CPU"
|
||||
std::string ortProviderName; // exact ORT provider string
|
||||
std::string libraryDir; // resolved absolute path to EP DLLs
|
||||
bool fromSubdir = false; // true = ep/<name>/, false = flat Shared/
|
||||
};
|
||||
|
||||
class ANSLIBS_API EPLoader
|
||||
{
|
||||
public:
|
||||
|
||||
// ── Platform defaults ────────────────────────────────────────────────
|
||||
#ifdef _WIN32
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"C:\\ProgramData\\ANSCENTER\\Shared";
|
||||
#else
|
||||
static constexpr const char* DEFAULT_SHARED_DIR =
|
||||
"/opt/anscenter/shared";
|
||||
#endif
|
||||
|
||||
// ── Initialize ───────────────────────────────────────────────────────
|
||||
/// Call once at application startup (optional — Current() lazy-inits).
|
||||
///
|
||||
/// @param shared_dir Root deployment directory.
|
||||
/// Expected subdirectory layout:
|
||||
/// <shared_dir>/ep/cuda/onnxruntime.dll
|
||||
/// <shared_dir>/ep/directml/onnxruntime.dll
|
||||
/// <shared_dir>/ep/openvino/onnxruntime.dll
|
||||
/// <shared_dir>/ep/cpu/onnxruntime.dll
|
||||
/// Falls back to <shared_dir>/onnxruntime.dll if
|
||||
/// subdirectories are absent (backward compat).
|
||||
///
|
||||
/// @param preferred Force a specific EP.
|
||||
/// Pass EngineType::AUTO_DETECT to let AutoDetect()
|
||||
/// query ANSLicenseHelper (default).
|
||||
///
|
||||
/// @return Const reference to the populated EPInfo.
|
||||
/// Valid for the lifetime of the process.
|
||||
///
|
||||
/// @throws std::runtime_error if onnxruntime.dll cannot be loaded or
|
||||
/// OrtGetApiBase is not found in the DLL.
|
||||
[[nodiscard]] static const EPInfo& Initialize(
|
||||
const std::string& shared_dir = DEFAULT_SHARED_DIR,
|
||||
EngineType preferred = EngineType::AUTO_DETECT);
|
||||
|
||||
// ── Current ──────────────────────────────────────────────────────────
|
||||
/// Returns the active EPInfo. Calls Initialize() with default arguments
|
||||
/// on the first invocation (lazy auto-init). Thread-safe.
|
||||
[[nodiscard]] static const EPInfo& Current();
|
||||
|
||||
// ── AutoDetect ───────────────────────────────────────────────────────
|
||||
/// Delegates to ANSLicenseHelper::CheckHardwareInformation().
|
||||
/// Priority: NVIDIA > AMD > Intel (OpenVINO) > CPU.
|
||||
[[nodiscard]] static EngineType AutoDetect();
|
||||
|
||||
// ── IsInitialized ────────────────────────────────────────────────────
|
||||
[[nodiscard]] static bool IsInitialized();
|
||||
|
||||
// ── EngineTypeName ───────────────────────────────────────────────────
|
||||
[[nodiscard]] static const char* EngineTypeName(EngineType type);
|
||||
|
||||
// ── SubdirName ───────────────────────────────────────────────────────
|
||||
/// Returns the ep/ subdirectory name for a given EngineType.
|
||||
/// e.g. EngineType::NVIDIA_GPU → "cuda"
|
||||
[[nodiscard]] static const char* SubdirName(EngineType type);
|
||||
[[nodiscard]] static void* GetOrtApiRaw();
|
||||
|
||||
// ── Shutdown ─────────────────────────────────────────────────────────
|
||||
/// Releases the onnxruntime.dll handle.
|
||||
/// Call at application exit AFTER all Ort::Session objects are destroyed.
|
||||
/// Safe to call multiple times.
|
||||
static void Shutdown();
|
||||
|
||||
// ── Non-copyable / non-movable ───────────────────────────────────────
|
||||
EPLoader() = delete;
|
||||
EPLoader(const EPLoader&) = delete;
|
||||
EPLoader& operator=(const EPLoader&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
static std::string ResolveEPDir(const std::string& shared_dir,
|
||||
EngineType type);
|
||||
static void LoadOrtDll(const std::string& ep_dir);
|
||||
|
||||
// ── State ────────────────────────────────────────────────────────────
|
||||
// Defined in EPLoader.cpp only when ANSLIBSLOADER_EXPORTS is set.
|
||||
static std::mutex s_mutex;
|
||||
static bool s_initialized;
|
||||
static EPInfo s_info;
|
||||
#ifdef _WIN32
|
||||
static std::string s_temp_ort_path;
|
||||
static std::string s_temp_dir;
|
||||
#endif
|
||||
};
|
||||
} // namespace ANSCENTER
|
||||
|
||||
#endif // EPLOADER_H
|
||||
142
core/ANSLibsLoader/include/NvDynLoader.h
Normal file
142
core/ANSLibsLoader/include/NvDynLoader.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
// ============================================================================
|
||||
// NvDynLoader -- Runtime discovery and loading of NVIDIA TensorRT / CUDA DLLs
|
||||
//
|
||||
// Moved from TensorRTAPI/ to ANSLibsLoader/ for centralized library management.
|
||||
// Now exported via ANSLIBS_API from ANSLibsLoader.dll.
|
||||
//
|
||||
// PROBLEM SOLVED
|
||||
// --------------
|
||||
// Linking against nvinfer_10.lib / nvonnxparser_10.lib hard-codes the major
|
||||
// version into the binary's import table. Upgrading TRT 10 -> 11 then forces
|
||||
// every project to update its .lib references and relink.
|
||||
//
|
||||
// SOLUTION
|
||||
// --------
|
||||
// NvDynLoader provides the three extern "C" symbols that TRT / ONNX-parser
|
||||
// inline wrappers call (createInferBuilder_INTERNAL, etc.) as thin stubs
|
||||
// compiled directly into ANSLibsLoader.dll. At runtime the stubs call through
|
||||
// function pointers into whichever DLL version is actually installed.
|
||||
//
|
||||
// All C++ vtable dispatch (IBuilder, IRuntime, IParser methods) continues to
|
||||
// work correctly because the objects are created by -- and owned by the vtable
|
||||
// of -- the DLL that was dynamically loaded.
|
||||
//
|
||||
// REQUIRED PROJECT CHANGES
|
||||
// ------------------------
|
||||
// Consuming projects:
|
||||
// REMOVE: nvinfer_10.lib / nvonnxparser_10.lib from linker input
|
||||
// ADD: ANSLibsLoader.lib
|
||||
// KEEP: cudart_static.lib (or use NV_DYNAMIC_CUDA for dynamic CUDA RT)
|
||||
// ============================================================================
|
||||
|
||||
#include "ANSLibsLoader.h" // ANSLIBS_API
|
||||
#include "DynLibUtils.h" // LibHandle
|
||||
|
||||
// -- TRT / ONNX-parser API decoration override --------------------------------
|
||||
// Must appear BEFORE including NvInfer.h / NvOnnxParser.h.
|
||||
// By default these macros expand to __declspec(dllimport), which would conflict
|
||||
// with our extern "C" stub definitions in NvDynLoader.cpp. Setting them to
|
||||
// empty makes all TRT inline-wrapper calls direct, so the linker resolves them
|
||||
// against our stubs rather than against nvinfer_XX.lib.
|
||||
//
|
||||
// The stubs are exported from ANSLibsLoader.dll via the .def file
|
||||
// (ANSLibsLoader.def), NOT via __declspec(dllexport), to avoid C2375
|
||||
// linkage conflicts between the NvInfer.h declarations and our definitions.
|
||||
#ifndef TENSORRTAPI
|
||||
# define TENSORRTAPI
|
||||
#endif
|
||||
#ifndef NVONNXPARSER_API
|
||||
# define NVONNXPARSER_API
|
||||
#endif
|
||||
|
||||
#include <cuda_runtime.h> // CUDA types (cudaStream_t, cudaDeviceProp, ...)
|
||||
#include <NvInfer.h> // TRT types (IBuilder, IRuntime, ...)
|
||||
#include <NvOnnxParser.h> // nvonnxparser types
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// ============================================================================
|
||||
class ANSLIBS_API NvDynLoader
|
||||
{
|
||||
public:
|
||||
// -- Lifecycle -------------------------------------------------------------
|
||||
/// Discover and load NVIDIA DLLs at runtime.
|
||||
/// Safe to call multiple times -- subsequent calls are no-ops.
|
||||
/// @param verbose Print discovery results to stdout.
|
||||
/// @returns false if a critical library (TRT or CUDA) could not be loaded.
|
||||
[[nodiscard]] static bool Initialize(bool verbose = true);
|
||||
|
||||
/// Release all loaded library handles. Call at application exit.
|
||||
static void Shutdown();
|
||||
|
||||
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
|
||||
|
||||
// -- Informational ---------------------------------------------------------
|
||||
[[nodiscard]] static const std::string& TrtDllPath() noexcept { return s_trtPath; }
|
||||
[[nodiscard]] static const std::string& OnnxDllPath() noexcept { return s_onnxPath; }
|
||||
[[nodiscard]] static const std::string& CudaDllPath() noexcept { return s_cudaPath; }
|
||||
[[nodiscard]] static const std::string& CudnnDllPath()noexcept { return s_cudnnPath; }
|
||||
[[nodiscard]] static int TrtMajor() noexcept { return s_trtMajor; }
|
||||
|
||||
// -- TRT factory pointers ---------------------------------------------------
|
||||
using PfnBuilder = void*(void* logger, int32_t version) noexcept;
|
||||
using PfnRuntime = void*(void* logger, int32_t version) noexcept;
|
||||
using PfnRefitter = void*(void* engine, void* logger, int32_t version) noexcept;
|
||||
using PfnParser = void*(void* network, void* logger, int32_t version) noexcept;
|
||||
using PfnParserRefitter = void*(void* refitter, void* logger, int32_t version) noexcept;
|
||||
using PfnGetParserVersion = int() noexcept;
|
||||
|
||||
static PfnBuilder* pfn_createInferBuilder_INTERNAL;
|
||||
static PfnRuntime* pfn_createInferRuntime_INTERNAL;
|
||||
static PfnRefitter* pfn_createInferRefitter_INTERNAL;
|
||||
static PfnParser* pfn_createNvOnnxParser_INTERNAL;
|
||||
static PfnParserRefitter* pfn_createNvOnnxParserRefitter_INTERNAL;
|
||||
static PfnGetParserVersion* pfn_getNvOnnxParserVersion;
|
||||
|
||||
// -- CUDA function pointers (populated only with NV_DYNAMIC_CUDA) -----------
|
||||
#ifdef NV_DYNAMIC_CUDA
|
||||
static cudaError_t (*pfn_cudaGetDeviceCount) (int*);
|
||||
static cudaError_t (*pfn_cudaSetDevice) (int);
|
||||
static cudaError_t (*pfn_cudaGetDeviceProperties) (cudaDeviceProp*, int);
|
||||
static cudaError_t (*pfn_cudaDeviceSetLimit) (cudaLimit, size_t);
|
||||
static cudaError_t (*pfn_cudaDeviceSynchronize) ();
|
||||
static cudaError_t (*pfn_cudaDeviceGetStreamPriorityRange)(int*, int*);
|
||||
static cudaError_t (*pfn_cudaMalloc) (void**, size_t);
|
||||
static cudaError_t (*pfn_cudaFree) (void*);
|
||||
static cudaError_t (*pfn_cudaMemset) (void*, int, size_t);
|
||||
static cudaError_t (*pfn_cudaMemGetInfo) (size_t*, size_t*);
|
||||
static cudaError_t (*pfn_cudaMemcpy) (void*, const void*, size_t, cudaMemcpyKind);
|
||||
static cudaError_t (*pfn_cudaMemcpyAsync) (void*, const void*, size_t, cudaMemcpyKind, cudaStream_t);
|
||||
static cudaError_t (*pfn_cudaStreamCreate) (cudaStream_t*);
|
||||
static cudaError_t (*pfn_cudaStreamCreateWithPriority) (cudaStream_t*, unsigned int, int);
|
||||
static cudaError_t (*pfn_cudaStreamDestroy) (cudaStream_t);
|
||||
static cudaError_t (*pfn_cudaStreamSynchronize) (cudaStream_t);
|
||||
static cudaError_t (*pfn_cudaStreamWaitEvent) (cudaStream_t, cudaEvent_t, unsigned int);
|
||||
static cudaError_t (*pfn_cudaEventCreate) (cudaEvent_t*);
|
||||
static cudaError_t (*pfn_cudaEventCreateWithFlags) (cudaEvent_t*, unsigned int);
|
||||
static cudaError_t (*pfn_cudaEventRecord) (cudaEvent_t, cudaStream_t);
|
||||
static cudaError_t (*pfn_cudaEventDestroy) (cudaEvent_t);
|
||||
static const char* (*pfn_cudaGetErrorString) (cudaError_t);
|
||||
static cudaError_t (*pfn_cudaGetLastError) ();
|
||||
#endif // NV_DYNAMIC_CUDA
|
||||
|
||||
private:
|
||||
static bool s_initialized;
|
||||
static int s_trtMajor;
|
||||
static std::string s_trtPath;
|
||||
static std::string s_onnxPath;
|
||||
static std::string s_cudaPath;
|
||||
static std::string s_cudnnPath;
|
||||
static LibHandle s_hTrt;
|
||||
static LibHandle s_hOnnx;
|
||||
static LibHandle s_hCuda;
|
||||
static LibHandle s_hCudnn;
|
||||
|
||||
// Candidate DLL / SO name lists.
|
||||
static std::vector<std::string> TrtCandidates();
|
||||
static std::vector<std::string> OnnxCandidates();
|
||||
static std::vector<std::string> CudnnCandidates();
|
||||
static std::vector<std::string> CudaRtCandidates();
|
||||
};
|
||||
69
core/ANSLibsLoader/include/OvLoader.h
Normal file
69
core/ANSLibsLoader/include/OvLoader.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
// ============================================================================
|
||||
// OvLoader -- Runtime discovery and pre-loading of OpenVINO DLLs
|
||||
//
|
||||
// OpenVINO is normally import-linked (openvino.lib), but the DLLs
|
||||
// must be discoverable at process load time. OvLoader ensures the correct
|
||||
// DLLs are found by:
|
||||
// 1. Pre-loading Intel TBB (dependency of openvino.dll)
|
||||
// 2. Pre-loading openvino.dll from the ANSCENTER shared directory
|
||||
// 3. Optionally querying the OpenVINO version via the C API
|
||||
//
|
||||
// Plugins (CPU, GPU, NPU) and frontends (IR, ONNX, etc.) are discovered
|
||||
// automatically by OpenVINO's internal plugin loader from the same directory
|
||||
// once the shared directory has been injected into the DLL search path.
|
||||
// ============================================================================
|
||||
|
||||
#include "ANSLibsLoader.h" // ANSLIBS_API
|
||||
#include "DynLibUtils.h" // LibHandle
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
// ============================================================================
|
||||
struct ANSLIBS_API OvInfo
|
||||
{
|
||||
std::string dllPath; // Full path to loaded openvino.dll
|
||||
std::string version; // e.g. "2024.6.0" (build number from C API)
|
||||
bool loaded = false;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
class ANSLIBS_API OvLoader
|
||||
{
|
||||
public:
|
||||
/// Discover and pre-load OpenVINO + TBB DLLs.
|
||||
/// Safe to call multiple times -- subsequent calls are no-ops.
|
||||
/// @param shared_dir Directory to search first (default: ANSCENTER shared).
|
||||
/// @param verbose Print discovery results to stdout.
|
||||
/// @returns Reference to the discovery result.
|
||||
[[nodiscard]] static const OvInfo& Initialize(
|
||||
const std::string& shared_dir = ANSCENTER::DynLib::DEFAULT_SHARED_DIR,
|
||||
bool verbose = true);
|
||||
|
||||
/// Release pre-loaded library handles.
|
||||
static void Shutdown();
|
||||
|
||||
/// Query current state.
|
||||
[[nodiscard]] static const OvInfo& Current() noexcept { return s_info; }
|
||||
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
|
||||
|
||||
private:
|
||||
/// Build candidate DLL names for each component.
|
||||
static std::vector<std::string> TbbCandidates(const std::string& shared_dir);
|
||||
static std::vector<std::string> TbbMallocCandidates(const std::string& shared_dir);
|
||||
static std::vector<std::string> OvCoreCandidates(const std::string& shared_dir);
|
||||
static std::vector<std::string> OvCApiCandidates(const std::string& shared_dir);
|
||||
|
||||
/// Try to extract version string via the ov_get_openvino_version C API.
|
||||
static std::string TryGetVersion(LibHandle hOvC);
|
||||
|
||||
static std::mutex s_mutex;
|
||||
static bool s_initialized;
|
||||
static OvInfo s_info;
|
||||
static LibHandle s_hTbb;
|
||||
static LibHandle s_hTbbMalloc;
|
||||
static LibHandle s_hOvCore;
|
||||
static LibHandle s_hOvC;
|
||||
};
|
||||
5
core/ANSLibsLoader/pch.cpp
Normal file
5
core/ANSLibsLoader/pch.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
13
core/ANSLibsLoader/pch.h
Normal file
13
core/ANSLibsLoader/pch.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
#endif //PCH_H
|
||||
2952
core/ANSLicensingSystem/ANSLicense.cpp
Normal file
2952
core/ANSLicensingSystem/ANSLicense.cpp
Normal file
File diff suppressed because it is too large
Load Diff
395
core/ANSLicensingSystem/ANSLicense.h
Normal file
395
core/ANSLicensingSystem/ANSLicense.h
Normal file
@@ -0,0 +1,395 @@
|
||||
#ifndef ANSLICENSE_H
|
||||
#define ANSLICENSE_H
|
||||
|
||||
#ifdef ANSLICENSE_EXPORTS
|
||||
#define ANSLICENSE_API __declspec(dllexport)
|
||||
#else
|
||||
#define ANSLICENSE_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include "anslicensing.h"
|
||||
#include "LabVIEWHeader/extcode.h"
|
||||
#include <mutex>
|
||||
#ifdef _UNICODE
|
||||
#define _T(s) L##s
|
||||
#define _tprintf wprintf
|
||||
#define _tcscmp wcscmp
|
||||
#define _tfopen fopen
|
||||
#else
|
||||
#define _T(s) (s)
|
||||
#define _TL(s) L##s
|
||||
#define _tprintf printf
|
||||
#define _tcscmp strcmp
|
||||
#define _tfopen fopen
|
||||
#endif
|
||||
|
||||
enum LicenseKeyStatus {
|
||||
SUCCESS = 0,
|
||||
INVALID_LICENSE_KEY = 1,
|
||||
INVALID_HARDWARE_ID = 2,
|
||||
LICENSE_EXPIRED = 3,
|
||||
INVALID_ACTIVATION_KEY = 4,
|
||||
PAYMENT_REQUIRED = 5,
|
||||
INVALID_PRODUCT = 6,
|
||||
UNKNOWN = 7
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int32 cnt; /* number of bytes that follow */
|
||||
double value[1]; /* value of double */
|
||||
} LDbl, * LDblPtr, ** LDblHandle;
|
||||
|
||||
namespace ANSCENTER
|
||||
{
|
||||
|
||||
// Precision used for GPU inference
|
||||
|
||||
enum OCRType {
|
||||
SINGLETEXT = 0,
|
||||
STRUCTURE = 1
|
||||
};
|
||||
|
||||
enum OCRLanguage {
|
||||
ENGLISH = 0,
|
||||
CHINESE = 1,
|
||||
FRENCH = 2,
|
||||
GERMANY = 3,
|
||||
JAPANESE= 4,
|
||||
KOREAN = 5,
|
||||
CUSTOM =6
|
||||
};
|
||||
// Precision used for GPU inference
|
||||
enum class Precision {
|
||||
// Full precision floating point value
|
||||
FP32,
|
||||
// Half prevision floating point value
|
||||
FP16,
|
||||
// Int8 quantization.
|
||||
// Has reduced dynamic range, may result in slight loss in accuracy.
|
||||
// If INT8 is selected, must provide path to calibration dataset directory.
|
||||
INT8,
|
||||
};
|
||||
|
||||
// Options for the network
|
||||
struct Options {
|
||||
// Precision to use for GPU inference.
|
||||
Precision precision = Precision::FP16;
|
||||
// If INT8 precision is selected, must provide path to calibration dataset
|
||||
// directory.
|
||||
std::string calibrationDataDirectoryPath;
|
||||
// The batch size to be used when computing calibration data for INT8
|
||||
// inference. Should be set to as large a batch number as your GPU will
|
||||
// support.
|
||||
int32_t calibrationBatchSize = 128;
|
||||
// The batch size which should be optimized for.
|
||||
int32_t optBatchSize = 1;
|
||||
// Maximum allowable batch size
|
||||
int32_t maxBatchSize = 16;
|
||||
// GPU device index
|
||||
int deviceIndex = 0;
|
||||
// Directory where the engine file should be saved
|
||||
std::string engineFileDir = ".";
|
||||
|
||||
// Maximum allowed input width
|
||||
int32_t maxInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
// Minimum allowed input width
|
||||
int32_t minInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
// Optimal input width
|
||||
int32_t optInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
|
||||
// Maximum allowed input height
|
||||
int32_t maxInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
// Minimum allowed input height
|
||||
int32_t minInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
// Optimal input height
|
||||
int32_t optInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
|
||||
// GPU clock lock frequency in MHz.
|
||||
// -1 = auto (default) — query max supported clock and lock at ~80%
|
||||
// 0 = disabled — let the driver manage clocks dynamically
|
||||
// >0 = lock at this specific MHz value (e.g. 2400)
|
||||
// Prevents GPU power throttling that causes TensorRT timing instability
|
||||
// on laptop GPUs. Requires elevated privileges; fails gracefully if not.
|
||||
int32_t gpuClockLockMHz = -1;
|
||||
};
|
||||
|
||||
enum PrecisionType {
|
||||
INT8 = 0,
|
||||
FP16 = 1,
|
||||
FP32 = 2,
|
||||
};
|
||||
enum EngineType {
|
||||
CPU = 0,
|
||||
NVIDIA_GPU = 1,
|
||||
OPENVINO_GPU = 2,
|
||||
AMD_GPU = 3,
|
||||
AUTO_DETECT = 99 // default: hardware auto-detection
|
||||
};
|
||||
enum DetectionType {
|
||||
CLASSIFICATION = 0,
|
||||
DETECTION = 1,
|
||||
SEGMENTATION = 2,
|
||||
FACEDETECTOR = 3,
|
||||
FACERECOGNIZER = 4,
|
||||
LICENSEPLATE = 5,
|
||||
TEXTSCENSE = 6,
|
||||
KEYPOINT=7,
|
||||
OBB = 8 // Oriented Bounding Box
|
||||
};
|
||||
enum ModelType {
|
||||
TENSORFLOW = 0,
|
||||
YOLOV4 = 1,
|
||||
YOLOV5 = 2,
|
||||
YOLOV8 = 3,
|
||||
TENSORRT = 4,
|
||||
OPENVINO = 5,
|
||||
FACEDETECT = 6,
|
||||
FACERECOGNIZE = 7,
|
||||
ALPR = 8,
|
||||
OCR = 9,
|
||||
ANOMALIB = 10,
|
||||
POSE=11,
|
||||
SAM=12,
|
||||
ODHUBMODEL = 13,
|
||||
YOLOV10RTOD = 14, // TensorRT Object Detection for Yolov10
|
||||
YOLOV10OVOD = 15, // OpenVINO Object Detection for Yolov10
|
||||
CUSTOMDETECTOR = 16, // Custom Detector
|
||||
YOLOV12 = 17, // YoloV12 standard for yolov12
|
||||
CUSTOMPY = 18, // Custom Python script model
|
||||
MOTIONDETECTOR = 19, // Motion Detector,
|
||||
ONNXCL =20,
|
||||
ONNXPOSE=21,
|
||||
RTPOSE=22,
|
||||
ONNXSEG = 23,
|
||||
RTSEG = 24,
|
||||
ONNXOBB = 25,
|
||||
RTOBB = 26,
|
||||
MOVIENET=27,
|
||||
ONNXSAM3=28,
|
||||
RTSAM3 = 29,
|
||||
ONNXYOLO = 30,
|
||||
RTYOLO = 31
|
||||
};
|
||||
enum TrackerType {
|
||||
BYTETRACK = 0,
|
||||
UCMC = 1,
|
||||
OCSORT = 2
|
||||
};
|
||||
enum ANSPRODUCTS {
|
||||
ANNHUB = 1000,
|
||||
DLHUB = 1001,
|
||||
ODHUB = 1002,
|
||||
ANSVIS = 1003,
|
||||
ANS_FACERECOGNIZE = 1004,
|
||||
ANS_OCR = 1005,
|
||||
ANS_ALPR =1006,
|
||||
ANS_CV = 1007,
|
||||
ANS_TS = 1008
|
||||
};
|
||||
enum ANSLICENSESTATUS {
|
||||
ACTIVE = 0,
|
||||
EXPIRED = 1,
|
||||
TRIAL=2,
|
||||
UNLICENSE = 3
|
||||
};
|
||||
struct ModelConfig {
|
||||
DetectionType detectionType;
|
||||
ModelType modelType;
|
||||
PrecisionType precisionType;
|
||||
int inpWidth;
|
||||
int inpHeight;
|
||||
float modelConfThreshold;
|
||||
float modelMNSThreshold;
|
||||
float detectionScoreThreshold;
|
||||
int numKPS; // Number of pose keypoint
|
||||
float kpsThreshold;
|
||||
bool autoGPUDetection;
|
||||
float unknownPersonThreshold;
|
||||
int gpuOptBatchSize = 1; // The batch size which should be optimized for.
|
||||
int gpuMaxBatchSize = 1; // Maximum allowable batch size
|
||||
int gpuDeviceIndex = 0; // GPU device index
|
||||
|
||||
// Maximum allowed input width
|
||||
int32_t maxInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
// Minimum allowed input width
|
||||
int32_t minInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
// Optimal input width
|
||||
int32_t optInputWidth = -1; // Default to -1 --> expecting fixed input size
|
||||
|
||||
// Maximum allowed input height
|
||||
int32_t maxInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
// Minimum allowed input height
|
||||
int32_t minInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
// Optimal input height
|
||||
int32_t optInputHeight = -1; // Default to -1 --> expecting fixed input size
|
||||
};
|
||||
|
||||
struct ANSLicenseInfo {
|
||||
std::string productName;
|
||||
std::string licenseKey;
|
||||
std::string activationKey;
|
||||
std::string hardwareId;
|
||||
ANSLICENSESTATUS licenseStatus;
|
||||
int remainingDays;
|
||||
int enableFeature;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ANSLICENSE_API SPDLogger
|
||||
{// Singleton design pattern
|
||||
protected:
|
||||
SPDLogger(const std::string& loggerFileName, bool consoleLoggerEnable = false)
|
||||
: _loggerFileName(loggerFileName), _consoleLoggerEnable(consoleLoggerEnable) {
|
||||
Init();
|
||||
}
|
||||
void Init();
|
||||
void ConfigureLogger();
|
||||
std::string _loggerFileName{};
|
||||
bool _consoleLoggerEnable{true};
|
||||
// Deleting copy constructor and assignment operator to ensure singleton
|
||||
SPDLogger(const SPDLogger&) = delete;
|
||||
SPDLogger& operator=(const SPDLogger&) = delete;
|
||||
|
||||
public:
|
||||
bool Release();
|
||||
~SPDLogger();
|
||||
// Static method to get the singleton instance
|
||||
static SPDLogger& GetInstance(const std::string& loggerFileName, bool consoleLoggerEnable = false) {
|
||||
static SPDLogger instance(loggerFileName, consoleLoggerEnable);
|
||||
return instance;
|
||||
}
|
||||
void Disable();
|
||||
void Enable();
|
||||
void LogTrace(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
void LogDebug(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
void LogInfo(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
void LogWarn(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
void LogError(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
void LogFatal(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
|
||||
};
|
||||
|
||||
class ANSLICENSE_API ANSLSHelper {
|
||||
private:
|
||||
LicenseTemplate* _licenseTemplate = nullptr;
|
||||
License* _license = nullptr;
|
||||
std::wstring _licenseFilePath = _T("");
|
||||
std::wstring _licenseServiceURL = _T("");
|
||||
std::wstring _sdkLicenseKey = _T("");
|
||||
std::wstring _privateKey = _T("");
|
||||
std::wstring _publicKey = _T("");
|
||||
|
||||
SPDLogger& _logger = SPDLogger::GetInstance("License");
|
||||
std::string LoadLicenseContent();
|
||||
void Setup5x5LicenseTemplate();// This is simple case
|
||||
std::wstring GetProductId(std::string licenseKey);
|
||||
|
||||
public:
|
||||
ANSLSHelper();
|
||||
ANSLSHelper(std::string licenseServiceURL);
|
||||
ANSLSHelper(std::string privateKey, std::string licenseServiceURL);
|
||||
ANSLSHelper(std::string privateKey, std::string publicKey, std::string licenseServiceURL);
|
||||
~ANSLSHelper();
|
||||
|
||||
void SetupLicenseTemplate();
|
||||
|
||||
[[nodiscard]] bool MatchCurrentHardwareId(std::string hwid);
|
||||
[[nodiscard]] bool DectectClockmanipulation(int year, int month, int date);
|
||||
|
||||
[[nodiscard]] std::string GetLicenseData(std::string licenseKey);
|
||||
[[nodiscard]] int ActivateLicense(std::string licenseKey, std::string registrationName, std::string& activationKey); // Always activate the license (need internet connection)
|
||||
[[nodiscard]] int ActivateLicenseWithCustomHWID(std::string licenseKey, std::string registrationName, std::string hardwareId, std::string& activationKey); // Always activate the license (need internet connection)
|
||||
|
||||
[[nodiscard]] bool LoadLicenseTemplate(std::string templateFilePath);
|
||||
[[nodiscard]] std::string SaveLicenseTemplate(std::string templateFilePath, bool savePrivateKey);
|
||||
|
||||
// These are the common methods to be used
|
||||
void SetLicenseServiceURL(std::string licenseServiceURL);
|
||||
[[nodiscard]] std::string GetCurrentHardwareId();
|
||||
void LoadLicense(std::string licenseKey);
|
||||
[[nodiscard]] std::string SaveLicense();
|
||||
[[nodiscard]] std::string GenerateKey(int productId, std::string registrationName, int productFeature, bool trialLicense);
|
||||
[[nodiscard]] std::string GenerateKey(int productId, std::string registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate);
|
||||
[[nodiscard]] bool IsLicenseKeyValid(std::string licenseKey, std::string registrationName); // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
|
||||
[[nodiscard]] bool CheckLicenseKey(std::string licenseKey, std::string registrationName, int productId, int& enabledFeatures); // Check if the license key is valid
|
||||
[[nodiscard]] int ValidateLicense(std::string licenseKey, std::string registrationName, std::string& activationKey);
|
||||
[[nodiscard]] int ValidateLicenseWithCustomHWID(std::string licenseKey, std::string registrationName, std::string customHWID, std::string& activationKey);
|
||||
|
||||
[[nodiscard]] int GenerateOfflineActivationData(std::string licenseKey, std::string registrationName, std::string& offlineActivationData);
|
||||
[[nodiscard]] int InstallOfflineLicense(std::string licenseKey, std::string registrationName, std::string activationKey);
|
||||
|
||||
// Utilities
|
||||
[[nodiscard]] static int ExtractModelZipFile(std::string modelZipFile, std::string password, std::string modelName, std::string& extractedOutputFolder);
|
||||
[[nodiscard]] static bool ZipFolerWithPassword(std::string folderPath, std::string zipFilePath, std::string password);
|
||||
[[nodiscard]] static int PrepareEdgeModel(std::string modelZipFile, std::string zipFilePassword, std::string edgePassword, std::string modelName, std::string edgeSerialNumber, std::string& configFilePathName, std::string& labelMapPathName, std::string& outputModelFolder);
|
||||
[[nodiscard]] static std::string GetSystemHardwareInformation();
|
||||
[[nodiscard]] static bool ReleaseLogger();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ANSLICENSE_API ANSLicenseHelper {
|
||||
private:
|
||||
[[nodiscard]] static bool deleteRecursively(const std::string& pathStr, bool safeMode);
|
||||
[[nodiscard]] static bool isPathSafe(const std::string& pathStr);
|
||||
public:
|
||||
[[nodiscard]] static bool LicenseVerification(std::string licenseKey, int productId, std::string registrationName);
|
||||
[[nodiscard]] static EngineType CheckHardwareInformation();
|
||||
[[nodiscard]] static std::string ListLicenses();
|
||||
[[nodiscard]] static int ActivateTrialLicense(std::string productName);
|
||||
[[nodiscard]] static int DeactivateLicense(std::string productName);
|
||||
[[nodiscard]] static int ActivateLicense(std::string productName, std::string licenseKey);
|
||||
[[nodiscard]] static int ActivateLicenseWithCustomHWID(std::string productName, std::string licenseKey, std::string hwid, std::string& activationKey);
|
||||
[[nodiscard]] static std::string DecodeValidationData(const char* validationData);
|
||||
[[nodiscard]] static std::string GenerateActivationDataFile(std::string activationKey,std::string licenseKey, std::string hardwareId, std::string validationData);
|
||||
[[nodiscard]] static std::string DecodeBase64(std::string base64String);
|
||||
[[nodiscard]] static bool RemoveTrialLicenseKeys(std::string registrationName);
|
||||
[[nodiscard]] static bool DeleleteRecursively(const std::string& pathStr) {
|
||||
return deleteRecursively(pathStr, true);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
extern "C" __declspec(dllexport) int CreateANSLSHandle(ANSCENTER::ANSLSHelper * *Handle, const char* privateKey, const char* publicKey, const char* licenseServiceURL);
|
||||
extern "C" __declspec(dllexport) int Release(ANSCENTER::ANSLSHelper * *Handle);
|
||||
extern "C" __declspec(dllexport) void SetLicenseServiceURL(ANSCENTER::ANSLSHelper * *Handle, const char* licenseServiceURL);
|
||||
extern "C" __declspec(dllexport) int GetLicenseData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, LStrHandle licenseData);
|
||||
extern "C" __declspec(dllexport) int LoadLicenseTemplate(ANSCENTER::ANSLSHelper * *Handle, const char* templateFilePath);
|
||||
extern "C" __declspec(dllexport) int GetCurrentHardwareId(ANSCENTER::ANSLSHelper * *Handle, LStrHandle currentHwID);
|
||||
extern "C" __declspec(dllexport) int GenerateKey(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int trialLicense, LStrHandle generatedKey);
|
||||
extern "C" __declspec(dllexport) int GenerateKeyWithExpiredDate(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate, LStrHandle generatedKey);
|
||||
extern "C" __declspec(dllexport) int CheckLicenseKey(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, int productId);// , LStrHandle strEnableFeature); // Check if the license key is valid
|
||||
extern "C" __declspec(dllexport) int ValidateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* existingActivationKey, LStrHandle activationKey);
|
||||
extern "C" __declspec(dllexport) int ActivateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle activationKey); // Always activate the license (need internet connection)
|
||||
extern "C" __declspec(dllexport) int ActivateLicenseWithCustomHWID(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* hardwareId, LStrHandle activationKey); // Always activate the license (need internet connection)
|
||||
extern "C" __declspec(dllexport) int IsLicenseKeyValid(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName); // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
|
||||
extern "C" __declspec(dllexport) int GenerateOfflineActivationData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle offlineActivationData);
|
||||
extern "C" __declspec(dllexport) int InstallOfflineLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* activationKey);
|
||||
|
||||
|
||||
// Utilities
|
||||
extern "C" __declspec(dllexport) int ExtractModelZipFile(const char* modelZipFile, const char* password, const char* modelName, LStrHandle extractedOutputFolder);
|
||||
extern "C" __declspec(dllexport) int ZipFolderToZipFile(const char* modelFolderSource,const char* modelZipFileDes, const char* password);
|
||||
extern "C" __declspec(dllexport) int PrepareEdgeModel(const char* modelZipFile, const char* zipFilePassword, const char* edgePassword, const char* modelName, const char* edgeSerialNumber, LStrHandle pathArray);
|
||||
extern "C" __declspec(dllexport) int GetSystemHardwareInformation(LStrHandle systemHardwareInformation);
|
||||
extern "C" __declspec(dllexport) int ReleaseLoggers();
|
||||
extern "C" __declspec(dllexport) int ListANSLicenses(std::string &listLicense);
|
||||
extern "C" __declspec(dllexport) int ListANSLicenses_LV(LStrHandle ansProductLicenses);
|
||||
extern "C" __declspec(dllexport) int ActivateTrialLicense(const char* productName);
|
||||
extern "C" __declspec(dllexport) int DeactivateLicense(const char* productName);
|
||||
extern "C" __declspec(dllexport) int ActivateProductLicense(const char* productName, const char* licenseKey);
|
||||
extern "C" __declspec(dllexport) int ActivateProductLicenseWithCustomHWID(const char* productName, const char* licenseKey, const char* hwid, LStrHandle lvActivationKey);
|
||||
extern "C" __declspec(dllexport) int GetRegistrationName(const char* validationData, LStrHandle registrationName);
|
||||
extern "C" __declspec(dllexport) int GenerateActivationKeyData(const char* activationKey, const char* licenseKey, const char* hardwareId, const char* validationData, LStrHandle activationData);
|
||||
extern "C" __declspec(dllexport) int ANSLicenseVerification(const char* licenseKey, int productId, const char* registrationName);
|
||||
extern "C" __declspec(dllexport) int ANSModelConversion(const char* zipModelFile, const char* zipModelPassword);
|
||||
extern "C" __declspec(dllexport) int DeletePathRecursively(const char* pathTobeDeleted);
|
||||
|
||||
#endif
|
||||
67
core/ANSLicensingSystem/CMakeLists.txt
Normal file
67
core/ANSLicensingSystem/CMakeLists.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
# ANSLicensingSystem — DLL for license validation (also used by LabVIEW)
|
||||
add_library(ANSLicensingSystem SHARED
|
||||
ANSLicense.cpp
|
||||
ANSLicense.h
|
||||
Utility.cpp
|
||||
Utility.h
|
||||
pch.cpp
|
||||
pch.h
|
||||
framework.h
|
||||
dllmain.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ANSLicensingSystem PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SHARED_INCLUDE_DIR}
|
||||
# These are needed by consumers because ANSLicense.h / Utility.h include them
|
||||
${RESEARCH_DIR} # for LabVIEWHeader/extcode.h
|
||||
${ANSLIBS_DIR}/ZLIB/include # for zlib.h (Utility.h includes it)
|
||||
${VCPKG_INCLUDE_DIR} # for zip.h (Utility.h includes it)
|
||||
)
|
||||
|
||||
target_include_directories(ANSLicensingSystem PRIVATE
|
||||
${ANLS_ROOT}/ANSLIB/anszip
|
||||
${RESEARCH_DIR}/ANS-HWiNFO/include
|
||||
${RESEARCH_DIR}/spdlog-1.12.0/include
|
||||
)
|
||||
|
||||
target_link_libraries(ANSLicensingSystem
|
||||
PRIVATE anslicensing
|
||||
PRIVATE labview
|
||||
PRIVATE opencv
|
||||
PRIVATE zlib_dep
|
||||
PRIVATE spdlog_dep
|
||||
PRIVATE boost
|
||||
)
|
||||
|
||||
target_link_directories(ANSLicensingSystem PRIVATE
|
||||
${RESEARCH_DIR}/ANS-HWiNFO/lib
|
||||
${RESEARCH_DIR}/boost_lib
|
||||
${VCPKG_LIB_DIR}
|
||||
${ANLS_ROOT}/ANSLIB/anszip/x64/Release
|
||||
)
|
||||
|
||||
# BASE64 class — not exported from anslicensing.dll, compile directly
|
||||
target_include_directories(ANSLicensingSystem PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/core/anslicensing
|
||||
)
|
||||
target_sources(ANSLicensingSystem PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/core/anslicensing/base64.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(ANSLicensingSystem PRIVATE
|
||||
HWiNFO.lib OpenCL.lib OpenCLExt.lib
|
||||
bz2.lib zip.lib
|
||||
libboost_log-vc143-mt-x64-1_82.lib
|
||||
shlwapi.lib winhttp.lib
|
||||
${WIN_COMMON_LIBS}
|
||||
)
|
||||
|
||||
target_compile_definitions(ANSLicensingSystem PRIVATE
|
||||
ANSLICENSE_EXPORTS
|
||||
ANSLICENSINGSYSTEM_EXPORTS
|
||||
UNICODE _UNICODE
|
||||
_USRDLL
|
||||
)
|
||||
|
||||
target_precompile_headers(ANSLicensingSystem PRIVATE pch.h)
|
||||
895
core/ANSLicensingSystem/Utility.cpp
Normal file
895
core/ANSLicensingSystem/Utility.cpp
Normal file
@@ -0,0 +1,895 @@
|
||||
#include "Utility.h"
|
||||
#include <ctime>
|
||||
|
||||
template <typename T>
|
||||
T get_data(const boost::property_tree::ptree& pt, const std::string& key)
|
||||
{
|
||||
T ret;
|
||||
if (boost::optional<T> data = pt.get_optional<T>(key))
|
||||
{
|
||||
ret = data.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return T();
|
||||
//throw std::runtime_error("Could not read the data from ptree: [key: " + key + "]");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Convert file path to only the filename
|
||||
std::string path_to_filename(std::string path) {
|
||||
return path.substr(path.find_last_of("/\\") + 1);
|
||||
}
|
||||
std::string GetMainFolderDir() {
|
||||
std::string loggerDir = "C:\\ProgramData\\ANSCENTER";
|
||||
if (!FolderExist(loggerDir)) {
|
||||
CreateDirectory(loggerDir);
|
||||
}
|
||||
return loggerDir;
|
||||
}
|
||||
|
||||
std::string GetLoggerDir()
|
||||
{
|
||||
std::string mainFolderDir = GetMainFolderDir();
|
||||
#ifdef _WIN32
|
||||
const char pathSeparator = '\\'; // Windows uses backslash
|
||||
#else
|
||||
const char pathSeparator = '/'; // Unix-like systems use forward slash
|
||||
#endif
|
||||
std::string loggerDir = mainFolderDir+ pathSeparator+"Logs";
|
||||
if (!FolderExist(loggerDir)) {
|
||||
CreateDirectory(loggerDir);
|
||||
}
|
||||
return loggerDir;
|
||||
}
|
||||
std::string GetLicenseDir()
|
||||
{
|
||||
std::string mainFolderDir = GetMainFolderDir();
|
||||
#ifdef _WIN32
|
||||
const char pathSeparator = '\\'; // Windows uses backslash
|
||||
#else
|
||||
const char pathSeparator = '/'; // Unix-like systems use forward slash
|
||||
#endif
|
||||
std::string loggerDir = mainFolderDir + pathSeparator + "Licenses";
|
||||
if (!FolderExist(loggerDir)) {
|
||||
CreateDirectory(loggerDir);
|
||||
}
|
||||
return loggerDir;
|
||||
}
|
||||
std::wstring String2WString(const std::string input)
|
||||
{
|
||||
auto w = fs::path(input).wstring();
|
||||
return w;
|
||||
}
|
||||
std::string WString2String(const std::wstring input)
|
||||
{
|
||||
auto s = fs::path(input).string();
|
||||
return s;
|
||||
}
|
||||
std::string Dash2Underscore(std::string text)
|
||||
{
|
||||
std::replace(text.begin(), text.end(), '-', '_');
|
||||
return text;
|
||||
}
|
||||
std::string Underscore2Dash(std::string text) {
|
||||
std::replace(text.begin(), text.end(), '_', '-');
|
||||
return text;
|
||||
}
|
||||
std::string Space2Underscore(std::string text) {
|
||||
std::replace(text.begin(), text.end(), ' ', '_');
|
||||
return text;
|
||||
}
|
||||
|
||||
bool FileExist(const std::string& filePath) {
|
||||
return fs::exists(filePath) && fs::is_regular_file(filePath);
|
||||
}
|
||||
bool FolderExist(const std::string& folderPath) {
|
||||
return fs::is_directory(folderPath);
|
||||
}
|
||||
bool CreateDirectory(const std::string& folderPath) {
|
||||
try {
|
||||
fs::create_directory(folderPath);
|
||||
return true;
|
||||
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Creating directory: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool RenameFile(const std::string& oldFilePath, const std::string& newFilePath) {
|
||||
try {
|
||||
fs::rename(oldFilePath, newFilePath);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error renaming file: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool CopyFile(const std::string& sourceFilePath, const std::string& destinationFilePath) {
|
||||
try {
|
||||
fs::copy_file(sourceFilePath, destinationFilePath, fs::copy_options::overwrite_existing);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error copying file: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void CopyFiles(const std::string& sourceFolder, const std::string& destinationFolder)
|
||||
{
|
||||
for (const auto& entry : std::filesystem::directory_iterator(sourceFolder))
|
||||
{
|
||||
if (entry.is_regular_file())
|
||||
{
|
||||
std::filesystem::copy(entry.path(), destinationFolder / entry.path().filename());
|
||||
}
|
||||
}
|
||||
}
|
||||
bool DeleteFile(const std::string& filePath) {
|
||||
try {
|
||||
fs::remove(filePath);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error deleting file: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::string FindFilePathInFileList(const std::vector<std::string>& vec, const std::string& substring)
|
||||
{
|
||||
auto it = std::find_if(vec.begin(), vec.end(), [&substring](const std::string& str) {
|
||||
return str.find(substring) != std::string::npos;
|
||||
});
|
||||
|
||||
return (it != vec.end()) ? *it : "";
|
||||
}
|
||||
bool DeleteLicenseFile(const std::string& filePath) {
|
||||
try {
|
||||
fs::remove(filePath);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error deleting file: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void ToLowerCase(std::string& str) {
|
||||
for (auto& c : str)
|
||||
{
|
||||
c = tolower(c);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toLower(const std::string& str) {
|
||||
std::string result = str;
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string GetFileExtension(const std::string& filePath) {
|
||||
fs::path path(filePath);
|
||||
std::string extensionFile= path.extension().string();
|
||||
ToLowerCase(extensionFile);
|
||||
return extensionFile;
|
||||
}
|
||||
std::vector<std::string> ListFilesInFolder(const std::string& folderPath) {
|
||||
std::vector<std::string> filePaths;
|
||||
try {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(folderPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string filePath = entry.path().string();
|
||||
std::string fileName = GetFileNameWithoutExtension(filePath);
|
||||
std::string _licenseKey, _activationKey, _validationData;
|
||||
if (ReadLicenseKeyFile(filePath, _licenseKey, _activationKey, _validationData)) {
|
||||
filePaths.push_back(entry.path().string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error listing files in folder: " << ex.what() << std::endl;
|
||||
}
|
||||
|
||||
return filePaths;
|
||||
}
|
||||
void DeleteFilesInFolderExcept(const std::string& folderPath, const std::vector<std::string>& filesToKeep) {
|
||||
try {
|
||||
for (const auto& entry : fs::directory_iterator(folderPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string fileName = entry.path().filename().string();
|
||||
if (std::find(filesToKeep.begin(), filesToKeep.end(), fileName) == filesToKeep.end()) {
|
||||
// File is not in the list of files to keep; delete it.
|
||||
fs::remove(entry.path());
|
||||
std::cout << "Deleted: " << entry.path() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error deleting files in folder: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
bool DeleteFolder(const std::string& folderPath) {
|
||||
try {
|
||||
fs::remove_all(folderPath);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error deleting folder: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::string GetFileNameWithoutExtension(const std::string& filePath) {
|
||||
fs::path path(filePath);
|
||||
return path.stem().string();
|
||||
}
|
||||
std::string ReadFileContent(std::string filePath) {
|
||||
std::ifstream ifs(filePath);
|
||||
return std::string((std::istreambuf_iterator<char>(ifs)),
|
||||
(std::istreambuf_iterator<char>()));
|
||||
}
|
||||
std::string ReadFileAsBinary(const std::string& filename) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return ""; // Return an empty string to indicate failure
|
||||
}
|
||||
|
||||
// Read the file content into a stringstream
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
|
||||
// Convert the stringstream to a string
|
||||
return buffer.str();
|
||||
}
|
||||
int ReadAllBytes(std::string filePath, std::vector<char>& allDataBytes) {
|
||||
// Open the file in binary mode
|
||||
std::ifstream file(filePath, std::ios::binary);
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
file.seekg(0, std::ios::end);
|
||||
std::streampos fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Create a vector to store the file data
|
||||
std::vector<char> fileData(fileSize);
|
||||
|
||||
// Read the file into the vector
|
||||
if (!file.read(fileData.data(), fileSize)) {
|
||||
std::cerr << "Failed to read file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
allDataBytes = fileData;
|
||||
|
||||
return 0;
|
||||
}
|
||||
// Functionto get parent folder path (C:\ParentFolder\FileName) -> C:\ParentFolder
|
||||
std::string GetParentFolder(const std::string& filePath) {
|
||||
size_t lastSlashPos = filePath.find_last_of("/\\"); // Handle both '/' and '\'
|
||||
if (lastSlashPos != std::string::npos) {
|
||||
return filePath.substr(0, lastSlashPos);
|
||||
}
|
||||
return ""; // Return an empty string if there is no folder
|
||||
}
|
||||
// Function to extract the folder name from a file path or file name
|
||||
std::string ExtractFolderName(const std::string& directoryPath) {
|
||||
std::filesystem::path path(directoryPath);
|
||||
return path.stem().string();
|
||||
}
|
||||
// Function to create a file path from a folder name and a file name
|
||||
std::string CreateFilePath(const std::string& folderName, const std::string& fileName) {
|
||||
#ifdef _WIN32
|
||||
const char pathSeparator = '\\'; // Windows uses backslash
|
||||
#else
|
||||
const char pathSeparator = '/'; // Unix-like systems use forward slash
|
||||
#endif
|
||||
std::string folder = folderName;
|
||||
if (!folder.empty() && folder.back() != pathSeparator) {
|
||||
folder += pathSeparator;
|
||||
}
|
||||
return folder + fileName;
|
||||
}
|
||||
|
||||
std::filesystem::path GetSafeTempDirectory() {
|
||||
std::filesystem::path systemTemp = std::filesystem::temp_directory_path();
|
||||
std::filesystem::path fallbackTemp = "C:\\ProgramData\\Jh7O7nUe7vS\\";
|
||||
|
||||
// Ensure fallback directory exists
|
||||
if (!std::filesystem::exists(fallbackTemp)) {
|
||||
try {
|
||||
std::filesystem::create_directories(fallbackTemp);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Failed to create fallback temp directory: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert systemTemp to lowercase string for checking
|
||||
std::string systemTempStr = toLower(systemTemp.string());
|
||||
|
||||
// Check if systemTemp does not exist or contains "c:\windows"
|
||||
if (!std::filesystem::exists(systemTemp) ||
|
||||
systemTempStr.find("windows") != std::string::npos) {
|
||||
return fallbackTemp;
|
||||
}
|
||||
|
||||
return systemTemp;
|
||||
}
|
||||
std::string GenerateOutputFolder(std::string modelFilePath, std::string modelName, bool edgeDeviceModel) {
|
||||
// Get the path to the Temp folder
|
||||
std::filesystem::path tempFolderPath = GetSafeTempDirectory();
|
||||
std::string outputFolder = "";
|
||||
outputFolder.clear();
|
||||
if (std::filesystem::exists(tempFolderPath)) {
|
||||
std::string strTempPath = tempFolderPath.string();
|
||||
#ifdef _WIN32
|
||||
const char pathSeparator = '\\'; // Windows uses backslash
|
||||
#else
|
||||
const char pathSeparator = '/'; // Unix-like systems use forward slash
|
||||
#endif
|
||||
std::string baseFolder = strTempPath + "Models";
|
||||
if(!FolderExist(baseFolder)) {
|
||||
CreateDirectory(baseFolder);
|
||||
}
|
||||
std::string EdgeModelsFolder = baseFolder + pathSeparator + "EdgeModels";
|
||||
if (!FolderExist(EdgeModelsFolder)) {
|
||||
CreateDirectory(EdgeModelsFolder);
|
||||
}
|
||||
std::string EngineModelsFolder = baseFolder + pathSeparator + "EngineModels";
|
||||
if (!FolderExist(EngineModelsFolder)) {
|
||||
CreateDirectory(EngineModelsFolder);
|
||||
}
|
||||
if(edgeDeviceModel)
|
||||
outputFolder = EdgeModelsFolder + pathSeparator + modelName;
|
||||
else
|
||||
outputFolder = EngineModelsFolder + pathSeparator + modelName;
|
||||
return outputFolder;
|
||||
}
|
||||
else {
|
||||
return outputFolder;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtractPasswordProtectedZip(const std::string& zipFileName,
|
||||
const std::string& password,
|
||||
const std::string& modelName,
|
||||
std::string& outputFolder,
|
||||
bool edgeDeviceModel) {
|
||||
outputFolder = GenerateOutputFolder(zipFileName, modelName, edgeDeviceModel);
|
||||
return ExtractProtectedZipFile(zipFileName, password, modelName, outputFolder);
|
||||
}
|
||||
|
||||
|
||||
bool AddFileToZip(zip* archive, const char* filePath, const char* zipPath, const char* password) {
|
||||
struct zip_source* source = zip_source_file(archive, filePath, 0, 0);
|
||||
if (!source) {
|
||||
std::cerr << "Failed to add file '" << filePath << "' to ZIP archive." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zip_file_add(archive, zipPath, source, ZIP_FL_OVERWRITE) == -1) {
|
||||
std::cerr << "Failed to add file '" << filePath << "' to ZIP archive." << std::endl;
|
||||
zip_source_free(source);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the index of the added file
|
||||
zip_int64_t fileIndex = zip_name_locate(archive, zipPath, 0);
|
||||
if (fileIndex < 0) {
|
||||
std::cerr << "Failed to locate file '" << zipPath << "' in ZIP archive." << std::endl;
|
||||
zip_source_free(source);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set encryption for the added file
|
||||
if (zip_file_set_encryption(archive, fileIndex, ZIP_EM_AES_256, password) == -1) {
|
||||
std::cerr << "Failed to set encryption for file '" << zipPath << "' in ZIP archive." << std::endl;
|
||||
zip_source_free(source);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddFolderContentsToZip(zip* archive, const char* folderPath, const char* zipPath, const char* password) {
|
||||
try {
|
||||
fs::path dir(folderPath);
|
||||
|
||||
if (!fs::exists(dir) || !fs::is_directory(dir)) {
|
||||
std::cerr << "Failed to open directory '" << folderPath << "'." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const fs::directory_entry& entry : fs::directory_iterator(dir)) {
|
||||
std::string entryName = entry.path().filename().string();
|
||||
std::string entryPath = (zipPath && zipPath[0] != '\0') ? std::string(zipPath) + "/" + entryName : entryName;
|
||||
std::string filePath = folderPath + std::string("/") + entryName;
|
||||
|
||||
if (fs::is_directory(entry.status())) {
|
||||
if (entryName != "." && entryName != "..") {
|
||||
if (!AddFolderContentsToZip(archive, filePath.c_str(), entryPath.c_str(), password)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!AddFileToZip(archive, filePath.c_str(), entryPath.c_str(), password)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipFolderWithPassword(const char* folderPath, const char* zipFilePath, const char* password) {
|
||||
zip* zipArchive;
|
||||
zip_flags_t flags = ZIP_CREATE | ZIP_TRUNCATE;
|
||||
//std::cout << "Open Zip File: " << zipFilePath << std::endl;
|
||||
zipArchive = zip_open(zipFilePath, flags, nullptr);
|
||||
if (!zipArchive) {
|
||||
std::cerr << "Failed to create ZIP archive." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set a password for the ZIP file
|
||||
if (zip_set_default_password(zipArchive, password) == -1) {
|
||||
std::cerr << "Failed to set the password for the ZIP file." << std::endl;
|
||||
zip_close(zipArchive);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add folder contents to the ZIP archive
|
||||
if (!AddFolderContentsToZip(zipArchive, folderPath, "", password)) {
|
||||
zip_close(zipArchive);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the ZIP archive to the file
|
||||
if (zip_close(zipArchive) == -1) {
|
||||
std::cerr << "Failed to save the ZIP archive to the file." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector) {
|
||||
std::string result;
|
||||
for (size_t i = 0; i < inputVector.size(); ++i) {
|
||||
result += inputVector[i];
|
||||
if (i < inputVector.size() - 1) {
|
||||
result += ",";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::string VectorToSeparatedString(const std::vector<std::string>& inputVector) {
|
||||
std::string result;
|
||||
for (size_t i = 0; i < inputVector.size(); ++i) {
|
||||
result += inputVector[i];
|
||||
if (i < inputVector.size() - 1) {
|
||||
result += ";";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::vector<std::string> Split(const std::string str, const std::string regex_str) {
|
||||
std::regex regexz(regex_str);
|
||||
return { std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
|
||||
std::sregex_token_iterator() };
|
||||
}
|
||||
|
||||
std::vector<std::string> GetTrialLicenseKeyFiles(std::string registrationName) {
|
||||
std::vector < std::string> trialLicenseKeyFiles;
|
||||
std::string trialLicenseKeyFileName = registrationName + "_Trial.lic";
|
||||
if (CreateDirectory("C:\\ProgramData\\Apple")) {
|
||||
std::string trialLicenseKeyFile1 = CreateFilePath("C:\\ProgramData\\Apple", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile1);
|
||||
}
|
||||
if (CreateDirectory("C:\\ProgramData\\Licenses")) {
|
||||
std::string trialLicenseKeyFile2 = CreateFilePath("C:\\ProgramData\\Licenses", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile2);
|
||||
}
|
||||
if (CreateDirectory("C:\\ProgramData\\McAfee")) {
|
||||
std::string trialLicenseKeyFile3 = CreateFilePath("C:\\ProgramData\\McAfee", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile3);
|
||||
}
|
||||
if (CreateDirectory("C:\\ProgramData\\NVIDIA")) {
|
||||
std::string trialLicenseKeyFile4 = CreateFilePath("C:\\ProgramData\\NVIDIA", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile4);
|
||||
}
|
||||
if (CreateDirectory("C:\\ProgramData\\National Instruments")) {
|
||||
std::string trialLicenseKeyFile5 = CreateFilePath("C:\\ProgramData\\National Instruments", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile5);
|
||||
}
|
||||
if (CreateDirectory("C:\\ProgramData\\Microsoft")) {
|
||||
std::string trialLicenseKeyFile6 = CreateFilePath("C:\\ProgramData\\Microsoft", trialLicenseKeyFileName);
|
||||
trialLicenseKeyFiles.push_back(trialLicenseKeyFile6);
|
||||
}
|
||||
return trialLicenseKeyFiles;
|
||||
}
|
||||
bool ReadLicenseKeyFile(std::string licenseKeyFilePath, std::string& licenseKey, std::string& activationKey, std::string& validationData) {
|
||||
try {
|
||||
if (!FileExist(licenseKeyFilePath))return false;
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json(licenseKeyFilePath, pt);
|
||||
|
||||
auto itLicenseKey = pt.get_child("license_key");
|
||||
licenseKey = itLicenseKey.get_value<std::string>();
|
||||
|
||||
auto itActivationKey = pt.get_child("activation_key");
|
||||
activationKey = itActivationKey.get_value<std::string>();
|
||||
|
||||
auto itRegistrationName = pt.get_child("license_key_validation_data");
|
||||
validationData = itRegistrationName.get_value<std::string>();
|
||||
|
||||
if ((licenseKey.empty()) ||
|
||||
(activationKey.empty()) ||
|
||||
(validationData.empty())) return false;
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::cout<<"Read License key"<< e.what()<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
std::string GetTrialLicenseKey(std::string registrationName) {
|
||||
std::string trialLicenseKey;
|
||||
std::vector<std::string> trialLicenseKeys;
|
||||
trialLicenseKeys.clear();
|
||||
|
||||
// Get all licenseKeys from vavious places
|
||||
std::vector < std::string> trialLicenseKeyFiles =GetTrialLicenseKeyFiles(registrationName);
|
||||
size_t trialSize = trialLicenseKeyFiles.size();
|
||||
for (size_t i = 0; i < trialSize; i++) {
|
||||
std::string trialLicenseFile = trialLicenseKeyFiles[i];
|
||||
if (FileExist(trialLicenseFile)) {
|
||||
std::string trialLicenseKey = ReadFileContent(trialLicenseFile);
|
||||
trialLicenseKeys.push_back(trialLicenseKey);
|
||||
}
|
||||
}
|
||||
sort(trialLicenseKeys.begin(), trialLicenseKeys.end());
|
||||
trialLicenseKeys.erase(unique(trialLicenseKeys.begin(), trialLicenseKeys.end()), trialLicenseKeys.end());
|
||||
|
||||
size_t lSize = trialLicenseKeys.size();
|
||||
if (lSize == 1) trialLicenseKey = trialLicenseKeys[0];
|
||||
return trialLicenseKey;
|
||||
}
|
||||
|
||||
bool UpdateTrialLicenseKey(std::string trialLicenseKey, std::string registrationName) {
|
||||
try {
|
||||
std::vector < std::string> trialLicenseKeyFiles = GetTrialLicenseKeyFiles(registrationName);
|
||||
size_t trialSize = trialLicenseKeyFiles.size();
|
||||
for (size_t i = 0; i < trialSize; i++) {
|
||||
try {
|
||||
std::string trialLicenseFile = trialLicenseKeyFiles[i];
|
||||
std::ofstream(trialLicenseFile) << trialLicenseKey;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RemoveTrialLicenseKey(std::string registrationName) {
|
||||
try {
|
||||
std::vector < std::string> trialLicenseKeyFiles = GetTrialLicenseKeyFiles(registrationName);
|
||||
size_t trialSize = trialLicenseKeyFiles.size();
|
||||
for (size_t i = 0; i < trialSize; i++) {
|
||||
try {
|
||||
DeleteFile(trialLicenseKeyFiles[i]);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int GetExpirationDate(std::string licenseData, int &productId) {
|
||||
if (licenseData.empty()) return -1;
|
||||
int remainDate = -1;
|
||||
std::stringstream ss;
|
||||
ss << licenseData;
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json(ss, pt);
|
||||
auto rootNode = pt.get_child("licenseData");
|
||||
auto childNode = rootNode.get_child("remaining_days");
|
||||
remainDate = childNode.get_value<int>();
|
||||
|
||||
childNode = rootNode.get_child("valid_product_id");
|
||||
productId = childNode.get_value<int>();
|
||||
|
||||
return remainDate;
|
||||
}
|
||||
|
||||
|
||||
std::string GetStringCurrentDateTime() {
|
||||
// Get the current time
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::tm now = {}; // Initialize to all zeros
|
||||
localtime_s(&now, &t);
|
||||
// Convert the time to a string
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(&now, "%Y%m%d%H%M%S");
|
||||
std::string currentDateTime = ss.str();
|
||||
return currentDateTime;
|
||||
}
|
||||
|
||||
std::string GetDateTimeString(const std::string& format) {
|
||||
// Get the current time
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::tm now = {}; // Initialize to all zeros
|
||||
localtime_s(&now, &t);
|
||||
// Convert the time to a string
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(&now, format.c_str());
|
||||
std::string currentDateTime = ss.str();
|
||||
return currentDateTime;
|
||||
}
|
||||
|
||||
// For traing engine
|
||||
//bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder)
|
||||
//{
|
||||
// int error;
|
||||
// if (!FileExist(zipFileName))return false;
|
||||
// zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
|
||||
// if (!archive) {
|
||||
// std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
// try {
|
||||
// if (!password.empty()) {
|
||||
// if (zip_set_default_password(archive, password.c_str()) == -1) {
|
||||
// std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// int numEntries = (int)zip_get_num_entries(archive, 0);
|
||||
// for (int i = 0; i < numEntries; i++) {
|
||||
// zip_file_t* file = zip_fopen_index(archive, i, 0);
|
||||
// if (!file) {
|
||||
// std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// // Check if the folder exists
|
||||
// if (!std::filesystem::exists(outputFolder)) {
|
||||
// // Folder does not exist, so create it
|
||||
// try {
|
||||
// std::filesystem::create_directories(outputFolder);
|
||||
// }
|
||||
// catch (const std::exception& ex) {
|
||||
// std::cerr << "Error opening file in ZIP: " << ex.what() << std::endl;
|
||||
// zip_close(archive);
|
||||
// zip_fclose(file);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// try {// otherwise extract to the output folder
|
||||
// const char* filename = zip_get_name(archive, i, 0);
|
||||
// std::string outputPath = CreateFilePath(outputFolder, filename);
|
||||
//
|
||||
// // Check if filename ends with '/' indicating it's a directory
|
||||
// if (outputPath.back() == '/') {// Create the directory and its parents as needed
|
||||
// fs::create_directories(outputPath);
|
||||
// }
|
||||
// else {// Proceed to extract the file
|
||||
// std::ofstream output(outputPath, std::ios::binary);
|
||||
// if (!output.is_open()) {
|
||||
// zip_fclose(file);
|
||||
// }
|
||||
// else {
|
||||
// const size_t buffer_size = 4096;
|
||||
// unsigned char buffer[buffer_size];
|
||||
// zip_int64_t bytesRead;
|
||||
// while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
|
||||
// output.write(reinterpret_cast<char*>(buffer), bytesRead);
|
||||
// }
|
||||
// zip_fclose(file);
|
||||
// output.close();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (const std::exception& ex) {
|
||||
// std::cerr << "Error creating output file: " << ex.what() << std::endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (...) {
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// zip_close(archive);
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder) {
|
||||
// int error;
|
||||
// if (!FileExist(zipFileName)) return false;
|
||||
//
|
||||
// zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
|
||||
// if (!archive) {
|
||||
// std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// if (!password.empty()) {
|
||||
// if (zip_set_default_password(archive, password.c_str()) == -1) {
|
||||
// std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int numEntries = static_cast<int>(zip_get_num_entries(archive, 0));
|
||||
// for (int i = 0; i < numEntries; i++) {
|
||||
// zip_file_t* file = zip_fopen_index(archive, i, 0);
|
||||
// if (!file) {
|
||||
// std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // Check and create the output folder if necessary
|
||||
// if (!std::filesystem::exists(outputFolder)) {
|
||||
// try {
|
||||
// std::filesystem::create_directories(outputFolder);
|
||||
// }
|
||||
// catch (const std::exception& ex) {
|
||||
// std::cerr << "Error creating output directory: " << ex.what() << std::endl;
|
||||
// zip_fclose(file);
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// const char* filename = zip_get_name(archive, i, 0);
|
||||
// std::string outputPath = CreateFilePath(outputFolder, filename);
|
||||
//
|
||||
// // Check if the path is a directory and create it if necessary
|
||||
// if (outputPath.back() == '/') {
|
||||
// std::filesystem::create_directories(outputPath);
|
||||
// }
|
||||
// else {
|
||||
// std::ofstream output(outputPath, std::ios::binary);
|
||||
// if (!output.is_open()) {
|
||||
// std::cerr << "Error creating output file: " << outputPath << std::endl;
|
||||
// zip_fclose(file);
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// const size_t buffer_size = 4096;
|
||||
// unsigned char buffer[buffer_size];
|
||||
// zip_int64_t bytesRead;
|
||||
// while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
|
||||
// output.write(reinterpret_cast<char*>(buffer), bytesRead);
|
||||
// }
|
||||
//
|
||||
// output.close();
|
||||
// }
|
||||
//
|
||||
// zip_fclose(file);
|
||||
// }
|
||||
// catch (const std::exception& ex) {
|
||||
// std::cerr << "Error creating output file: " << ex.what() << std::endl;
|
||||
// zip_fclose(file);
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (...) {
|
||||
// zip_close(archive);
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// zip_close(archive);
|
||||
// return true;
|
||||
//}
|
||||
bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder)
|
||||
{
|
||||
int error;
|
||||
if (!FileExist(zipFileName))return false;
|
||||
zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
|
||||
if (!archive) {
|
||||
std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (!password.empty()) {
|
||||
if (zip_set_default_password(archive, password.c_str()) == -1) {
|
||||
std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
|
||||
zip_close(archive);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int numEntries = (int)zip_get_num_entries(archive, 0);
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
zip_file_t* file = zip_fopen_index(archive, i, 0);
|
||||
if (!file) {
|
||||
std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
|
||||
zip_close(archive);
|
||||
return false;
|
||||
}
|
||||
// Check if the folder exists
|
||||
if (!std::filesystem::exists(outputFolder)) {
|
||||
// Folder does not exist, so create it
|
||||
try {
|
||||
std::filesystem::create_directories(outputFolder);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error opening file in ZIP: " << ex.what() << std::endl;
|
||||
zip_close(archive);
|
||||
zip_fclose(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {// otherwise extract to the output folder
|
||||
const char* filename = zip_get_name(archive, i, 0);
|
||||
std::string outputPath = CreateFilePath(outputFolder, filename);
|
||||
|
||||
// Check if filename ends with '/' indicating it's a directory
|
||||
if (outputPath.back() == '/') {// Create the directory and its parents as needed
|
||||
fs::create_directories(outputPath);
|
||||
}
|
||||
else {// Proceed to extract the file
|
||||
std::ofstream output(outputPath, std::ios::binary);
|
||||
if (!output.is_open()) {
|
||||
zip_fclose(file);
|
||||
}
|
||||
else {
|
||||
const size_t buffer_size = 4096;
|
||||
unsigned char buffer[buffer_size];
|
||||
zip_int64_t bytesRead;
|
||||
while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
|
||||
output.write(reinterpret_cast<char*>(buffer), bytesRead);
|
||||
}
|
||||
zip_fclose(file);
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::cerr << "Error creating output file: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
zip_close(archive);
|
||||
return false;
|
||||
}
|
||||
zip_close(archive);
|
||||
return true;
|
||||
}
|
||||
|
||||
92
core/ANSLicensingSystem/Utility.h
Normal file
92
core/ANSLicensingSystem/Utility.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#ifndef UTILITY_H
|
||||
#define UTILITY_H
|
||||
#include "ANSLicense.h"
|
||||
#include <boost/date_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include "boost/property_tree/ptree.hpp"
|
||||
#include "boost/property_tree/json_parser.hpp"
|
||||
#include "boost/foreach.hpp"
|
||||
|
||||
#include <zlib.h>
|
||||
#include <zip.h>
|
||||
#include <filesystem>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <stdio.h>
|
||||
|
||||
//namespace logging = boost::log;
|
||||
//namespace attrs = boost::log::attributes;
|
||||
//namespace expr = boost::log::expressions;
|
||||
//namespace src = boost::log::sources;
|
||||
//namespace keywords = boost::log::keywords;
|
||||
//namespace sinks = boost::log::sinks;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) ((a) > (b) ? (b) : (a))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
#endif
|
||||
#define DETECT_BUFFER_SIZE 0x9000
|
||||
|
||||
|
||||
ANSLICENSE_API std::string path_to_filename(std::string path);
|
||||
ANSLICENSE_API std::string GetMainFolderDir();
|
||||
ANSLICENSE_API std::string GetLoggerDir();
|
||||
ANSLICENSE_API std::string GetLicenseDir();
|
||||
// Convert file path to only the filename
|
||||
ANSLICENSE_API std::wstring String2WString(const std::string input);
|
||||
ANSLICENSE_API std::string WString2String(const std::wstring input);
|
||||
ANSLICENSE_API std::string Dash2Underscore(std::string text);
|
||||
ANSLICENSE_API std::string Underscore2Dash(std::string text);
|
||||
ANSLICENSE_API std::string Space2Underscore(std::string text);
|
||||
|
||||
[[nodiscard]] ANSLICENSE_API bool FileExist(const std::string& filePath);
|
||||
[[nodiscard]] ANSLICENSE_API bool FolderExist(const std::string& folderPath);
|
||||
[[nodiscard]] ANSLICENSE_API bool CreateDirectory(const std::string& folderPath);
|
||||
|
||||
[[nodiscard]] ANSLICENSE_API bool RenameFile(const std::string& oldFilePath, const std::string& newFilePath);
|
||||
[[nodiscard]] ANSLICENSE_API bool CopyFile(const std::string& sourceFilePath, const std::string& destinationFilePath);
|
||||
ANSLICENSE_API void CopyFiles(const std::string& sourceFolder, const std::string& destinationFolder);
|
||||
[[nodiscard]] ANSLICENSE_API bool DeleteFile(const std::string& filePath);
|
||||
[[nodiscard]] ANSLICENSE_API bool DeleteLicenseFile(const std::string& filePath);
|
||||
[[nodiscard]] ANSLICENSE_API std::vector<std::string> ListFilesInFolder(const std::string& folderPath);
|
||||
ANSLICENSE_API void DeleteFilesInFolderExcept(const std::string& folderPath, const std::vector<std::string>& filesToKeep);
|
||||
[[nodiscard]] ANSLICENSE_API bool DeleteFolder(const std::string& folderPath);
|
||||
ANSLICENSE_API void ToLowerCase(std::string& str);
|
||||
ANSLICENSE_API std::string toLower(const std::string& str);
|
||||
ANSLICENSE_API std::string GetFileExtension(const std::string& filePath);
|
||||
ANSLICENSE_API std::string GetFileNameWithoutExtension(const std::string& filePath);
|
||||
ANSLICENSE_API std::string FindFilePathInFileList(const std::vector<std::string>& fileList, const std::string& fileName);
|
||||
ANSLICENSE_API std::string ReadFileContent(std::string filePath);
|
||||
ANSLICENSE_API std::string ReadFileAsBinary(const std::string& filename);
|
||||
ANSLICENSE_API int ReadAllBytes(std::string filePath, std::vector<char>& allDataBytes);
|
||||
ANSLICENSE_API std::string ExtractFolderName(const std::string& filePath); // Function to extract the folder name from a file path or file name
|
||||
ANSLICENSE_API std::string GetParentFolder(const std::string& directoryPath);// Function to extract the folder name from a file path or file name
|
||||
ANSLICENSE_API std::string CreateFilePath(const std::string& folderName, const std::string& fileName);// Function to create a file path from a folder name and a file name
|
||||
ANSLICENSE_API std::filesystem::path GetSafeTempDirectory();
|
||||
ANSLICENSE_API std::string GenerateOutputFolder(std::string modelFilePath, std::string modelName, bool edgeDeviceModel=true);
|
||||
ANSLICENSE_API bool ExtractPasswordProtectedZip(const std::string& zipFileName, const std::string& password, const std::string& modelName, std::string& outputFolder, bool edgeDeviceModel = true);
|
||||
ANSLICENSE_API bool AddFileToZip(zip* archive, const char* filePath, const char* zipPath, const char* password);
|
||||
ANSLICENSE_API bool AddFolderContentsToZip(zip* archive, const char* folderPath, const char* zipPath, const char* password);
|
||||
ANSLICENSE_API bool ZipFolderWithPassword(const char* folderPath, const char* zipFilePath, const char* password);
|
||||
ANSLICENSE_API std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector);
|
||||
ANSLICENSE_API std::string VectorToSeparatedString(const std::vector<std::string>& inputVector);
|
||||
ANSLICENSE_API std::vector<std::string> Split(const std::string str, const std::string regex_str);
|
||||
ANSLICENSE_API bool ReadLicenseKeyFile(std::string licenseKeyFilePath, std::string& licenseKey, std::string& activationKey, std::string& validationData);
|
||||
ANSLICENSE_API std::vector<std::string> GetTrialLicenseKeyFiles(std::string registrationName);
|
||||
ANSLICENSE_API std::string GetTrialLicenseKey(std::string registrationName);
|
||||
ANSLICENSE_API bool UpdateTrialLicenseKey(std::string trialLicenseKey, std::string registrationName);
|
||||
ANSLICENSE_API int GetExpirationDate(std::string licenseData, int& productId);
|
||||
ANSLICENSE_API bool RemoveTrialLicenseKey(std::string registrationName);
|
||||
ANSLICENSE_API std::string GetStringCurrentDateTime(); // Return current datetime in string format
|
||||
ANSLICENSE_API std::string GetDateTimeString(const std::string& format);
|
||||
// For training engine
|
||||
//bool ExtractPasswordProtectedZipForTrainingEgnine(const std::string& zipFileName, const std::string& password, const std::string& modelName, std::string& outputFolder, bool edgeDeviceModel = true);
|
||||
ANSLICENSE_API bool ExtractProtectedZipFile(const std::string& zipFileName,const std::string& password,const std::string& modelName,const std::string outputFolder);
|
||||
#endif
|
||||
554
core/ANSLicensingSystem/dllmain.cpp
Normal file
554
core/ANSLicensingSystem/dllmain.cpp
Normal file
@@ -0,0 +1,554 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
#include "ANSLicense.h"
|
||||
#include "Utility.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int CreateANSLSHandle(ANSCENTER::ANSLSHelper * *Handle, const char* privateKey, const char* publicKey, const char* licenseServiceURL) {
|
||||
try {
|
||||
if (!Handle || !privateKey || !publicKey || !licenseServiceURL) return 0;
|
||||
std::string st_privateKey = privateKey;
|
||||
std::string st_publicKey = publicKey;
|
||||
std::string st_licenseServiceURL = licenseServiceURL;
|
||||
(*Handle) = new ANSCENTER::ANSLSHelper(st_privateKey, st_publicKey, st_licenseServiceURL);
|
||||
if (*Handle == nullptr) return 0;
|
||||
else return 1;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int Release(ANSCENTER::ANSLSHelper * *Handle) {
|
||||
try {
|
||||
if (!Handle || !(*Handle)) return 1; // already released
|
||||
delete* Handle;
|
||||
*Handle = nullptr;
|
||||
return 1;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) void SetLicenseServiceURL(ANSCENTER::ANSLSHelper * *Handle, const char* licenseServiceURL) {
|
||||
if (!Handle || !(*Handle) || !licenseServiceURL) return;
|
||||
(*Handle)->SetLicenseServiceURL(licenseServiceURL);
|
||||
}
|
||||
extern "C" __declspec(dllexport) int GetLicenseData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, LStrHandle licenseData) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey) return 0;
|
||||
std::string st = (*Handle)->GetLicenseData(licenseKey);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(licenseData, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*licenseData)->cnt = size;
|
||||
memcpy((*licenseData)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int LoadLicenseTemplate(ANSCENTER::ANSLSHelper * *Handle, const char* templateFilePath) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !templateFilePath) return 0;
|
||||
bool result = (*Handle)->LoadLicenseTemplate(templateFilePath);
|
||||
if (result == true) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int GetCurrentHardwareId(ANSCENTER::ANSLSHelper * *Handle, LStrHandle currentHwID) {
|
||||
try {
|
||||
if (!Handle || !(*Handle)) return 0;
|
||||
std::string st = (*Handle)->GetCurrentHardwareId();
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(currentHwID, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*currentHwID)->cnt = size;
|
||||
memcpy((*currentHwID)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int GenerateKey(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int trialLicense, LStrHandle generatedKey) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !registrationName) return 0;
|
||||
bool enableTrialLicense = false;
|
||||
if (trialLicense > 0)enableTrialLicense = true;
|
||||
std::string st = (*Handle)->GenerateKey(productId, registrationName, productFeature, enableTrialLicense);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(generatedKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*generatedKey)->cnt = size;
|
||||
memcpy((*generatedKey)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int GenerateKeyWithExpiredDate(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate, LStrHandle generatedKey) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !registrationName) return 0;
|
||||
std::string st = (*Handle)->GenerateKey(productId, registrationName, productFeature, expiredYear, expiredMonth, expiredDate);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(generatedKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*generatedKey)->cnt = size;
|
||||
memcpy((*generatedKey)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int CheckLicenseKey(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, int productId){ //, LStrHandle strEnableFeature) { // Check if the license key is valid
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return -1;
|
||||
int enFeatures = 0;
|
||||
bool result = (*Handle)->CheckLicenseKey(licenseKey, registrationName, productId, enFeatures);
|
||||
if (result) return enFeatures;
|
||||
else return -1;
|
||||
}
|
||||
catch (...) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int ValidateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* existingActivationKey,LStrHandle activationKey) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !existingActivationKey) return UNKNOWN;
|
||||
std::string st = existingActivationKey;
|
||||
int result = (*Handle)->ValidateLicense(licenseKey, registrationName, st);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*activationKey)->cnt = size;
|
||||
memcpy((*activationKey)->str, st.c_str(), size);
|
||||
return result;
|
||||
}
|
||||
else return UNKNOWN;
|
||||
}
|
||||
else return INVALID_LICENSE_KEY;
|
||||
}
|
||||
catch (...) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
extern "C" __declspec(dllexport) int ActivateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle activationKey) { // Always activate the license (need internet connection)
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return UNKNOWN;
|
||||
std::string st = "";
|
||||
int result = (*Handle)->ActivateLicense(licenseKey, registrationName, st);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*activationKey)->cnt = size;
|
||||
memcpy((*activationKey)->str, st.c_str(), size);
|
||||
return result;
|
||||
}
|
||||
else return UNKNOWN;
|
||||
}
|
||||
else return INVALID_LICENSE_KEY;
|
||||
}
|
||||
catch (...) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ActivateLicenseWithCustomHWID(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* hardwareId, LStrHandle activationKey) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !hardwareId) return UNKNOWN;
|
||||
std::string st;
|
||||
int result = (*Handle)->ActivateLicenseWithCustomHWID(licenseKey, registrationName, hardwareId, st);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*activationKey)->cnt = size;
|
||||
memcpy((*activationKey)->str, st.c_str(), size);
|
||||
return result;
|
||||
}
|
||||
else return UNKNOWN;
|
||||
}
|
||||
else return INVALID_LICENSE_KEY;
|
||||
}
|
||||
catch (...) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}// Always activate the license (need internet connection)
|
||||
|
||||
extern "C" __declspec(dllexport) int IsLicenseKeyValid(ANSCENTER::ANSLSHelper **Handle, const char* licenseKey, const char * registrationName) { // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return 0;
|
||||
bool result = (*Handle)->IsLicenseKeyValid(licenseKey, registrationName);
|
||||
if (result) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) int GenerateOfflineActivationData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle offlineActivationData) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return 0;
|
||||
std::string st = "";
|
||||
int result = (*Handle)->GenerateOfflineActivationData(licenseKey, registrationName, st);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(offlineActivationData, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*offlineActivationData)->cnt = size;
|
||||
memcpy((*offlineActivationData)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int InstallOfflineLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* activationKey) {
|
||||
try {
|
||||
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !activationKey) return 0;
|
||||
return (*Handle)->InstallOfflineLicense(licenseKey, registrationName, activationKey);
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Utilities
|
||||
extern "C" __declspec(dllexport) int ExtractModelZipFile(const char* modelZipFile, const char* password, const char* modelName, LStrHandle extractedOutputFolder) {
|
||||
try {
|
||||
std::string st = "";
|
||||
int result = ANSCENTER::ANSLSHelper::ExtractModelZipFile(modelZipFile, password, modelName, st);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(extractedOutputFolder, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*extractedOutputFolder)->cnt = size;
|
||||
memcpy((*extractedOutputFolder)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ZipFolderToZipFile(const char* modelFolderSource, const char* modelZipFileDes, const char* password) {
|
||||
try {
|
||||
std::string stPass = password;
|
||||
if (stPass.empty()) password = "Sh7O7nUe7vJ/417W0gWX+dSdfcP9hUqtf/fEqJGqxYL3PedvHubJag==";
|
||||
bool result = ANSCENTER::ANSLSHelper::ZipFolerWithPassword(modelFolderSource, modelZipFileDes, password);
|
||||
if (result == true) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int PrepareEdgeModel(const char* modelZipFile, const char* zipFilePassword, const char* edgePassword, const char* modelName, const char* edgeSerialNumber,LStrHandle pathArray) {
|
||||
try {
|
||||
std::string st_configFilePathName = "";
|
||||
std::string st_labelMapPathName = "";
|
||||
std::string st_zipFilePathName = "";
|
||||
int result = ANSCENTER::ANSLSHelper::PrepareEdgeModel(modelZipFile, zipFilePassword, edgePassword, modelName, edgeSerialNumber, st_configFilePathName, st_labelMapPathName, st_zipFilePathName);
|
||||
std::string st = st_configFilePathName + ";" + st_labelMapPathName + ";" + st_zipFilePathName;
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(pathArray, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*pathArray)->cnt = size;
|
||||
memcpy((*pathArray)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int GetSystemHardwareInformation(LStrHandle systemHardwareInformation) {
|
||||
try {
|
||||
std::string st = ANSCENTER::ANSLSHelper::GetSystemHardwareInformation();
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(systemHardwareInformation, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*systemHardwareInformation)->cnt = size;
|
||||
memcpy((*systemHardwareInformation)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ReleaseLoggers() {
|
||||
try {
|
||||
bool result = ANSCENTER::ANSLSHelper::ReleaseLogger();
|
||||
if (result) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ListANSLicenses(std::string & listLicense) {
|
||||
try {
|
||||
listLicense = ANSCENTER::ANSLicenseHelper::ListLicenses();
|
||||
if (!listLicense.empty()) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) int ListANSLicenses_LV(LStrHandle ansProductLicenses) {
|
||||
try {
|
||||
std::string st = ANSCENTER::ANSLicenseHelper::ListLicenses();
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(ansProductLicenses, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*ansProductLicenses)->cnt = size;
|
||||
memcpy((*ansProductLicenses)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int ActivateTrialLicense(const char* productName) {
|
||||
return ANSCENTER::ANSLicenseHelper::ActivateTrialLicense(productName);
|
||||
}
|
||||
extern "C" __declspec(dllexport) int DeactivateLicense(const char* productName) {
|
||||
return ANSCENTER::ANSLicenseHelper::DeactivateLicense(productName);
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ActivateProductLicense(const char* productName, const char* licenseKey) {
|
||||
return ANSCENTER::ANSLicenseHelper::ActivateLicense(productName,licenseKey);
|
||||
}
|
||||
extern "C" __declspec(dllexport) int ActivateProductLicenseWithCustomHWID(const char* productName, const char* licenseKey, const char* hwid, LStrHandle lvActivationKey) {
|
||||
try {
|
||||
std::string st;
|
||||
int result = ANSCENTER::ANSLicenseHelper::ActivateLicenseWithCustomHWID(productName, licenseKey, hwid, st);
|
||||
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(lvActivationKey, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*lvActivationKey)->cnt = size;
|
||||
memcpy((*lvActivationKey)->str, st.c_str(), size);
|
||||
return result;
|
||||
}
|
||||
else return LicenseKeyStatus::UNKNOWN;
|
||||
}
|
||||
else return LicenseKeyStatus::INVALID_LICENSE_KEY;
|
||||
}
|
||||
catch (...) {
|
||||
return LicenseKeyStatus::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int GetRegistrationName(const char* validationData, LStrHandle registrationName) {
|
||||
try {
|
||||
std::string st = ANSCENTER::ANSLicenseHelper::DecodeValidationData(validationData);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(registrationName, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*registrationName)->cnt = size;
|
||||
memcpy((*registrationName)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) int GenerateActivationKeyData(const char* activationKey, const char* licenseKey, const char* hardwareId, const char* validationData, LStrHandle activationData) {
|
||||
try {
|
||||
std::string st = ANSCENTER::ANSLicenseHelper::GenerateActivationDataFile(activationKey, licenseKey, hardwareId, validationData);
|
||||
int size = (int)st.length();
|
||||
if (size > 0) {
|
||||
MgErr error;
|
||||
error = DSSetHandleSize(activationData, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error == noErr)
|
||||
{
|
||||
(*activationData)->cnt = size;
|
||||
memcpy((*activationData)->str, st.c_str(), size);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int ANSLicenseVerification(const char* licenseKey, int productId, const char* registrationName) {
|
||||
try{
|
||||
bool result = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, productId, registrationName);
|
||||
if (result)return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) int ANSModelConversion(const char* zipModelFile, const char* zipModelPassword) {
|
||||
try {
|
||||
//1. Uzip the model file to a temp location
|
||||
std::string parentFolder = GetParentFolder(zipModelFile);
|
||||
if (parentFolder.empty()) {
|
||||
return -1; // or handle error appropriately
|
||||
}
|
||||
std::string modelName = GetFileNameWithoutExtension(zipModelFile) + "_converted";
|
||||
const std::string outputFolder = GenerateOutputFolder(zipModelFile, modelName, true);
|
||||
if (!FolderExist(outputFolder)) fs::create_directory(outputFolder);
|
||||
bool extractedResult = ExtractProtectedZipFile(zipModelFile, zipModelPassword, modelName, outputFolder);
|
||||
if (!extractedResult) return 0;
|
||||
//2. Zip the model file to a temp location
|
||||
std::string newModelZipFile = CreateFilePath(parentFolder, modelName + ".zip");
|
||||
std::string newModelZipPassword = "Sh7O7nUe7vJ/417W0gWX+dSdfcP9hUqtf/fEqJGqxYL3PedvHubJag==";
|
||||
//3. Read names of classes from the label map file
|
||||
std::string labelMapFile = CreateFilePath(outputFolder, "classes.names");
|
||||
if (labelMapFile.empty()) return 0;
|
||||
std::vector<std::string> classesNames = Split(ReadFileContent(labelMapFile), "\n");
|
||||
// 4. Create Categories folder
|
||||
std::string categoriesFolder = outputFolder + "\\Categories";
|
||||
if (FolderExist(categoriesFolder))DeleteFolder(categoriesFolder);
|
||||
fs::create_directory(categoriesFolder);
|
||||
for (size_t i = 0; i < classesNames.size(); ++i) {
|
||||
std::ofstream outFile(categoriesFolder + "/" + classesNames[i] + "." + std::to_string(i + 1));
|
||||
outFile.close();
|
||||
}
|
||||
bool zipResult = ZipFolderWithPassword(outputFolder.c_str(), newModelZipFile.c_str(), newModelZipPassword.c_str());
|
||||
if (zipResult) {
|
||||
DeleteFolder(outputFolder);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
extern "C" __declspec(dllexport) int DeletePathRecursively(const char* pathTobeDeleted) {
|
||||
try {
|
||||
bool result = ANSCENTER::ANSLicenseHelper::DeleleteRecursively(pathTobeDeleted);
|
||||
if (result) return 1;
|
||||
else return 0;
|
||||
}
|
||||
catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
7
core/ANSLicensingSystem/framework.h
Normal file
7
core/ANSLicensingSystem/framework.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define NOMINMAX // Prevent windows.h from defining min/max macros
|
||||
// which break std::min / std::max (C2589)
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
5
core/ANSLicensingSystem/pch.cpp
Normal file
5
core/ANSLicensingSystem/pch.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
13
core/ANSLicensingSystem/pch.h
Normal file
13
core/ANSLicensingSystem/pch.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
#endif //PCH_H
|
||||
17
core/anslicensing/CMakeLists.txt
Normal file
17
core/anslicensing/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
# anslicensing — Licensing SDK (shared library, built from source)
|
||||
file(GLOB ANSLICENSING_SOURCES "*.cpp" "*.c")
|
||||
file(GLOB ANSLICENSING_HEADERS "*.h")
|
||||
|
||||
add_library(anslicensing SHARED ${ANSLICENSING_SOURCES} ${ANSLICENSING_HEADERS})
|
||||
|
||||
target_include_directories(anslicensing PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SHARED_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(anslicensing PRIVATE ANSLICENSING_EXPORTS LICENSING_EXPORTS _USRDLL)
|
||||
if(WIN32)
|
||||
target_link_libraries(anslicensing PRIVATE ${WIN_COMMON_LIBS} winhttp)
|
||||
else()
|
||||
target_link_libraries(anslicensing PRIVATE ${UNIX_COMMON_LIBS} curl ssl crypto)
|
||||
endif()
|
||||
395
core/anslicensing/base32.cpp
Normal file
395
core/anslicensing/base32.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "base32.h"
|
||||
|
||||
|
||||
const char BASE32::alphabet[] = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
const char BASE32::values[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, /* - 40 -> 47 */
|
||||
|
||||
-1,-1,24,25,26,27,28,29,30,31, /* 0123456789 - 48 -> 57 */
|
||||
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */
|
||||
3, 4, 5, 6, 7,-1, 8, 9,10,11, /* DEFGHIJKLM - 68 -> 77 */
|
||||
12,-1,13,14,15,16,17,18,19,20, /* NOPQRSTUVW - 78 -> 87 */
|
||||
21,22,23, /* XYZ - 88 -> 90 */
|
||||
|
||||
-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, /* abcd - 91 -> 100 */
|
||||
4, 5, 6, 7,-1, 8, 9,10,11,12, /* efghijklmn - 101 -> 110 */
|
||||
-1,13,14,15,16,17,18,19,20,21, /* opqrstuvwx - 111 -> 120 */
|
||||
22,23,-1,-1,-1,-1,-1,-1,-1,-1, /* yz - 121 -> 130 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */
|
||||
-1,-1,-1,-1,-1, /* - 251 -> 255 */
|
||||
};
|
||||
|
||||
BASE32::BASE32()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BASE32::~BASE32()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string BASE32::encode(unsigned char * buf, int len, bool padding)
|
||||
{
|
||||
int pad;
|
||||
int enclen = encode_pad_length(len, &pad);
|
||||
string encbuf;
|
||||
|
||||
if (!padding)
|
||||
pad = 0;
|
||||
|
||||
encbuf.resize(enclen + pad + 1); /* Allow for trailing NUL */
|
||||
|
||||
encode_exactly(buf, len, encbuf.data(), enclen);
|
||||
|
||||
if (pad)
|
||||
memset(encbuf.data() + enclen, '=', pad);
|
||||
|
||||
encbuf[enclen + pad] = '\0';
|
||||
|
||||
return encbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* encode_exactly
|
||||
*
|
||||
* Encode `len' bytes from `buf' into `enclen' bytes starting from `encbuf'.
|
||||
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
|
||||
*/
|
||||
void BASE32::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
unsigned char const *ip = buf + len; /* Input pointer, one byte off end */
|
||||
char *op = encbuf + enclen; /* Output pointer, one byte off end */
|
||||
|
||||
assert(buf);
|
||||
assert(encbuf);
|
||||
assert(len > 0);
|
||||
assert(enclen >= len * 8 / 5);
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 5 bytes of input
|
||||
* are split into groups of 5 bits, each group being encoded as a
|
||||
* single base32 digit.
|
||||
*
|
||||
* input byte 0 1 2 3 4
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* |01234012|34012340|12340123|40123401|23401234|
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* <---><----><---><----><----><---><----><--->
|
||||
* output digit 0 1 2 3 4 5 6 7
|
||||
*
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start encoding from the end. The encoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch (len % 5) {
|
||||
case 0:
|
||||
do {
|
||||
assert(op - encbuf >= 8);
|
||||
i = (unsigned char) *--ip; /* Input #4 */
|
||||
*--op = alphabet[i & 0x1f]; /* Ouput #7 */
|
||||
i >>= 5; /* upper <234>, input #4 */
|
||||
/* FALLTHROUGH */
|
||||
case 4:
|
||||
i |= ((unsigned char) *--ip) << 3; /* had 3 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #6 */
|
||||
i >>= 5; /* upper <401234>, input #3 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #5 */
|
||||
i >>= 5; /* upper <4>, input #3 */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
i |= ((unsigned char) *--ip) << 1; /* had 1 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #4 */
|
||||
i >>= 5; /* upper <1234>, input #2 */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #3 */
|
||||
i >>= 5; /* upper <3401234>, input #1 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #2 */
|
||||
i >>= 5; /* upper <34>, input #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #1 */
|
||||
i >>= 5; /* upper <01234>, input #0 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #0 */
|
||||
i >>= 5; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= encbuf);
|
||||
} while (op > encbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* encode_pad_length
|
||||
*
|
||||
* Compute the number of base32 digits and amount of padding necessary
|
||||
* to encode `len' bytes.
|
||||
*
|
||||
* Returns the number of base32 digits necessary.
|
||||
* Furthermore, if `pad' is a non-NULL pointer, it is filled with the amount
|
||||
* of padding chars that would be necessary.
|
||||
*/
|
||||
int BASE32::encode_pad_length(int len, int *pad)
|
||||
{
|
||||
int ndigits; /* Base32 digits necessary */
|
||||
int npad = 0; /* Final padding chars necessary */
|
||||
int qcount; /* Amount of full quintets */
|
||||
int remainder; /* Amount of input bytes in final quintet */
|
||||
|
||||
assert(len > 0);
|
||||
|
||||
qcount = len / 5;
|
||||
remainder = len - (qcount * 5);
|
||||
|
||||
assert(remainder >= 0);
|
||||
|
||||
switch (remainder) {
|
||||
case 0: npad = 0; break;
|
||||
case 1: npad = 6; break;
|
||||
case 2: npad = 4; break;
|
||||
case 3: npad = 3; break;
|
||||
case 4: npad = 1; break;
|
||||
default: assert(0); /* Not possible */
|
||||
}
|
||||
|
||||
ndigits = qcount * 8; /* Each full quintet encoded on 8 bytes */
|
||||
if (npad != 0)
|
||||
ndigits += (8 - npad);
|
||||
|
||||
if (pad)
|
||||
*pad = npad;
|
||||
|
||||
return ndigits;
|
||||
}
|
||||
|
||||
vector<unsigned char> BASE32::decode( const char * buf, int len, int * outlen )
|
||||
{
|
||||
int declen;
|
||||
vector<unsigned char> decbuf;
|
||||
int decoded;
|
||||
|
||||
if (len == 0 || (len & 0x7)) /* Empty, or padding bytes missing */
|
||||
{
|
||||
decbuf.clear();
|
||||
return decbuf;
|
||||
}
|
||||
|
||||
declen = (len >> 3) * 5;
|
||||
decbuf.resize(declen);
|
||||
|
||||
decoded = decode_into(buf, len, decbuf.data(), declen);
|
||||
|
||||
if (decoded == 0)
|
||||
decbuf.clear();
|
||||
|
||||
if (outlen != NULL)
|
||||
*outlen = decoded;
|
||||
|
||||
return decbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_into
|
||||
*
|
||||
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf',
|
||||
* faking the necessary amount of padding if necessary.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
*
|
||||
* Returns the amount of bytes decoded (without trailing padding) if successful,
|
||||
* 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE32::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
|
||||
{
|
||||
int padding = 0;
|
||||
|
||||
if (len & 0x7)
|
||||
padding = 8 - (len & 0x7);
|
||||
|
||||
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_alphabet
|
||||
*
|
||||
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf'.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
* Uses the specified decoding alphabet.
|
||||
*
|
||||
* `padding', when non-zero, is the amount of padding that is missing from
|
||||
* the input buffer and which we must assume.
|
||||
*
|
||||
* Return decoded bytes if successful, 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE32::decode_alphabet(const char valmap[],
|
||||
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
char const *ip = buf + len; /* Input pointer, one byte off end */
|
||||
int dlen = (len >> 3) * 5; /* Exact decoded length */
|
||||
unsigned char *op; /* Output pointer, one byte off end */
|
||||
int bytes; /* bytes decoded without padding */
|
||||
char v;
|
||||
|
||||
assert(padding >= 0);
|
||||
assert(buf);
|
||||
assert(decbuf);
|
||||
assert(len > 0);
|
||||
assert((len & 0x7) == 0); /* `len' is a multiple of 8 bytes */
|
||||
//assert(declen >= dlen);
|
||||
|
||||
/*
|
||||
* If the last byte of input is '=', there is padding and we need to
|
||||
* zero the tail of the decoding buffer.
|
||||
*
|
||||
* Likewise, when `padding' is non-zero, act as if the '=' were there.
|
||||
*/
|
||||
|
||||
if (buf[len-1] == '=' || padding > 0) {
|
||||
int pad = 0;
|
||||
int n = 0; /* Amount of bytes to zero */
|
||||
int s = 0; /* Amount of bytes to zero */
|
||||
|
||||
/*
|
||||
* Remove and count trailing input padding bytes.
|
||||
*/
|
||||
|
||||
if (padding == 0) {
|
||||
while (*--ip == '=')
|
||||
pad++;
|
||||
ip++; /* Points one byte after real non-padding input */
|
||||
} else {
|
||||
pad = padding;
|
||||
ip -= padding;
|
||||
}
|
||||
|
||||
switch (pad) {
|
||||
case 1: n = 1; s = 0; break;
|
||||
case 3: n = 2; s = 1; break;
|
||||
case 4: n = 3; s = 2; break;
|
||||
case 6: n = 4; s = 3; break;
|
||||
default:
|
||||
return 0; /* Cannot be valid base32 */
|
||||
}
|
||||
|
||||
memset(decbuf + (dlen - n), 0, n);
|
||||
op = decbuf + (dlen - s);
|
||||
bytes = dlen - n;
|
||||
} else {
|
||||
op = decbuf + dlen;
|
||||
bytes = dlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 8 bytes of input,
|
||||
* each consisting of only 5 bits of information forming a base32 digit,
|
||||
* are concatenated back into 5 bytes of binary information.
|
||||
*
|
||||
* input digit 0 1 2 3 4 5 6 7
|
||||
* <---><----><---><----><----><---><----><--->
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* |01234012|34012340|12340123|40123401|23401234|
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* output byte 0 1 2 3 4
|
||||
*
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start decoding from the end. The decoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch ((ip - buf) % 8) {
|
||||
case 0:
|
||||
do {
|
||||
i = valmap[(unsigned char) *--ip]; /* Input #7 */
|
||||
if (i < 0)
|
||||
return 0;
|
||||
/* FALLTHROUGH */
|
||||
case 7:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #6 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 5; /* had 5 bits */
|
||||
*--op = i & 0xff; /* Output #4 */
|
||||
i >>= 8; /* lower <01> of output #3 */
|
||||
/* FALLTHROUGH */
|
||||
case 6:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #5 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 2; /* had 2 bits */
|
||||
/* FALLTHROUGH */
|
||||
case 5:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #4 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 7; /* had 7 bits */
|
||||
*--op = i & 0xff; /* Output #3 */
|
||||
i >>= 8; /* lower <0123> of output #2 */
|
||||
/* FALLTHROUGH */
|
||||
case 4:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #3 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 4; /* had 4 bits */
|
||||
*--op = i & 0xff; /* Output #2 */
|
||||
i >>= 8; /* lower <0> of output #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #2 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 1; /* had 1 bit */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #1 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 6; /* had 6 bits */
|
||||
*--op = i & 0xff; /* Output #1 */
|
||||
i >>= 8; /* lower <012> of output #0 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #0 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 3; /* had 3 bits */
|
||||
*--op = i & 0xff; /* Output #0 */
|
||||
i >>= 8; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= decbuf);
|
||||
} while (op > decbuf);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
26
core/anslicensing/base32.h
Normal file
26
core/anslicensing/base32.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BASE32 {
|
||||
public:
|
||||
BASE32();
|
||||
~BASE32();
|
||||
|
||||
string encode(unsigned char * input, int len, bool padding = false);
|
||||
vector<unsigned char> decode(const char * input, int len, int * outlen);
|
||||
|
||||
int encode_pad_length(int len, int *pad);
|
||||
|
||||
private:
|
||||
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
|
||||
|
||||
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
|
||||
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
|
||||
|
||||
static const char values[];
|
||||
static const char alphabet[];
|
||||
};
|
||||
378
core/anslicensing/base64.cpp
Normal file
378
core/anslicensing/base64.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* The Base 64 Alphabet
|
||||
*
|
||||
* Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
* 0 A 17 R 34 i 51 z
|
||||
* 1 B 18 S 35 j 52 0
|
||||
* 2 C 19 T 36 k 53 1
|
||||
* 3 D 20 U 37 l 54 2
|
||||
* 4 E 21 V 38 m 55 3
|
||||
* 5 F 22 W 39 n 56 4
|
||||
* 6 G 23 X 40 o 57 5
|
||||
* 7 H 24 Y 41 p 58 6
|
||||
* 8 I 25 Z 42 q 59 7
|
||||
* 9 J 26 a 43 r 60 8
|
||||
* 10 K 27 b 44 s 61 9
|
||||
* 11 L 28 c 45 t 62 +
|
||||
* 12 M 29 d 46 u 63 /
|
||||
* 13 N 30 e 47 v
|
||||
* 14 O 31 f 48 w (pad) =
|
||||
* 15 P 32 g 49 x
|
||||
* 16 Q 33 h 50 y
|
||||
*/
|
||||
|
||||
const char BASE64::alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
const char BASE64::values[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */
|
||||
|
||||
-1,-1,-1,62,-1,-1,-1,63, /* ()*+'-./ - 40 -> 47 */
|
||||
52,53,54,55,56,57,58,59,60,61, /* 0123456789 - 48 -> 57 */
|
||||
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */
|
||||
3, 4, 5, 6, 7, 8, 9,10,11,12, /* DEFGHIJKLM - 68 -> 77 */
|
||||
13,14,15,16,17,18,19,20,21,22, /* NOPQRSTUVW - 78 -> 87 */
|
||||
23,24,25,-1,-1,-1,-1,-1,-1,26, /* XYZ[\]^_`a - 88 -> 97 */
|
||||
27,28,29,30,31,32,33,34,35,36, /* bcdefghijk - 98 -> 107 */
|
||||
37,38,39,40,41,42,43,44,45,46, /* lmnopqrstu - 108 -> 117 */
|
||||
47,48,49,50,51, /* vwxyz - 118 -> 122 */
|
||||
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, /* - 123 -> 130 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */
|
||||
-1,-1,-1,-1,-1, /* - 251 -> 255 */
|
||||
};
|
||||
|
||||
BASE64::BASE64()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BASE64::~BASE64()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string BASE64::encode(unsigned char * buf, int len, bool padding)
|
||||
{
|
||||
int pad;
|
||||
int enclen = encode_pad_length(len, &pad);
|
||||
string encbuf;
|
||||
|
||||
if (!padding)
|
||||
pad = 0;
|
||||
|
||||
encbuf.resize(enclen + pad); /* Allow for trailing NUL */
|
||||
|
||||
encode_exactly(buf, len, encbuf.data(), enclen);
|
||||
|
||||
if (pad)
|
||||
memset(encbuf.data() + enclen, '=', pad);
|
||||
|
||||
return encbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* encode_exactly
|
||||
*
|
||||
* Encode `len' bytes from `buf' unsignedo `enclen' bytes starting from `encbuf'.
|
||||
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
|
||||
*/
|
||||
void BASE64::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
unsigned char const *ip = buf + len; /* Input pounsigneder, one byte off end */
|
||||
char *op = encbuf + enclen; /* Output pounsigneder, one byte off end */
|
||||
|
||||
assert(buf);
|
||||
assert(encbuf);
|
||||
assert(len > 0);
|
||||
assert(enclen >= len * 4 / 3);
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 3 bytes of input
|
||||
* are split unsignedo groups of 6 bits, each group being encoded as a
|
||||
* single base64 digit.
|
||||
*
|
||||
* input byte 0 1 2
|
||||
* +--------+--------+--------+
|
||||
* |01234501|23450123|45012345|
|
||||
* +--------+--------+--------+
|
||||
* <----><-----><-----><---->
|
||||
* output digit 0 1 2 3
|
||||
*
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start encoding from the end. The encoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch (len % 3) {
|
||||
case 0:
|
||||
do {
|
||||
assert(op - encbuf >= 4);
|
||||
i = (unsigned char) *--ip; /* Input #2 */
|
||||
*--op = alphabet[i & 0x3f]; /* Ouput #3 */
|
||||
i >>= 6; /* upper <45>, input #2 */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
|
||||
*--op = alphabet[i & 0x3f]; /* Output #2 */
|
||||
i >>= 6; /* upper <2345>, input #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
|
||||
*--op = alphabet[i & 0x3f]; /* Output #1 */
|
||||
i >>= 6; /* upper <012345>, input #0 */
|
||||
*--op = alphabet[i & 0x3f]; /* Output #0 */
|
||||
i >>= 6; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= encbuf);
|
||||
} while (op > encbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* encode_pad_length
|
||||
*
|
||||
* Compute the number of base64 digits and amount of padding necessary
|
||||
* to encode `len' bytes.
|
||||
*
|
||||
* Returns the number of base64 digits necessary.
|
||||
* Furthermore, if `pad' is a non-NULL pounsigneder, it is filled with the amount
|
||||
* of padding chars that would be necessary.
|
||||
*/
|
||||
int BASE64::encode_pad_length(int len, int *pad)
|
||||
{
|
||||
int ndigits; /* Base64 digits necessary */
|
||||
int npad = 0; /* Final padding chars necessary */
|
||||
int tcount; /* Amount of full triplets */
|
||||
int remainder; /* Amount of input bytes in final triplet */
|
||||
|
||||
assert(len > 0);
|
||||
|
||||
tcount = len / 3;
|
||||
remainder = len - (tcount * 3);
|
||||
|
||||
assert((unsigned) remainder >= 0);
|
||||
|
||||
switch (remainder) {
|
||||
case 0: npad = 0; break;
|
||||
case 1: npad = 2; break;
|
||||
case 2: npad = 1; break;
|
||||
default: assert(0); /* Not possible */
|
||||
}
|
||||
|
||||
ndigits = tcount * 4; /* Each full triplet encoded on 4 bytes */
|
||||
if (npad != 0)
|
||||
ndigits += (4 - npad);
|
||||
|
||||
if (pad)
|
||||
*pad = npad;
|
||||
|
||||
return ndigits;
|
||||
}
|
||||
|
||||
/**
|
||||
* base64_decode
|
||||
*
|
||||
* Decode `len' bytes starting at `buf' unsignedo new allocated buffer.
|
||||
*
|
||||
* Returns the new decoded buffer, or NULL if the input was not valid base64
|
||||
* encoding. The caller knows the length of the returned buffer: it's the
|
||||
* size of the input divided by 4 and multiplied by 3. If `outlen' is non-NULL,
|
||||
* it is filled with the amount of bytes decoded unsignedo the buffer (without
|
||||
* trailing padding).
|
||||
*/
|
||||
vector<unsigned char> BASE64::decode(const char * buf, int len, int * outlen)
|
||||
{
|
||||
int declen;
|
||||
vector<unsigned char> decbuf;
|
||||
int decoded;
|
||||
|
||||
if (len == -1)
|
||||
len = strlen(buf);
|
||||
|
||||
// if (len == 0 || (len & 0x3)) /* Empty, or padding bytes missing */
|
||||
// return NULL;
|
||||
|
||||
declen = (len >> 2) * 3;
|
||||
decbuf.resize(declen * sizeof(unsigned char));
|
||||
|
||||
decoded = decode_into(buf, len, decbuf.data(), declen);
|
||||
|
||||
if (decoded == 0)
|
||||
decbuf.clear();
|
||||
|
||||
if (outlen)
|
||||
*outlen = decoded;
|
||||
|
||||
return decbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode_into
|
||||
*
|
||||
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf',
|
||||
* faking the necessary amount of padding if necessary.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
*
|
||||
* Returns the amount of bytes decoded (without trailing padding) if successful,
|
||||
* 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE64::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
|
||||
{
|
||||
int padding = 0;
|
||||
|
||||
if (len & 0x3)
|
||||
padding = 4 - (len & 0x3);
|
||||
|
||||
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_alphabet
|
||||
*
|
||||
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf'.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
* Uses the specified decoding alphabet.
|
||||
*
|
||||
* `padding', when non-zero, is the amount of padding that is missing from
|
||||
* the input buffer and which we must assume.
|
||||
*
|
||||
* Return decoded bytes if successful, 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE64::decode_alphabet(const char valmap[],
|
||||
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
char const *ip = buf + len; /* Input pounsigneder, one byte off end */
|
||||
int dlen = (len >> 2) * 3; /* Exact decoded length */
|
||||
unsigned char *op; /* Output pounsigneder, one byte off end */
|
||||
int bytes; /* Bytes decoded without padding */
|
||||
char v;
|
||||
|
||||
assert(buf);
|
||||
assert(decbuf);
|
||||
assert(len > 0);
|
||||
assert((len & 0x3) == 0); /* `len' is a multiple of 4 bytes */
|
||||
//assert(declen >= dlen);
|
||||
|
||||
/*
|
||||
* If the last byte of input is '=', there is padding and we need to
|
||||
* zero the tail of the decoding buffer.
|
||||
*
|
||||
* Likewise, when `padding' is non-zero, act as if the '=' were there.
|
||||
*/
|
||||
|
||||
if (buf[len-1] == '=' || padding > 0) {
|
||||
int pad = 0;
|
||||
int n = 0; /* Amount of bytes to zero */
|
||||
int s = 0; /* Amount of bytes to zero */
|
||||
|
||||
/*
|
||||
* Remove and count trailing input padding bytes.
|
||||
*/
|
||||
|
||||
if (padding == 0) {
|
||||
while (*--ip == '=')
|
||||
pad++;
|
||||
ip++; /* Pounsigneds one byte after real non-padding input */
|
||||
} else {
|
||||
pad = padding;
|
||||
ip -= padding;
|
||||
}
|
||||
|
||||
switch (pad) {
|
||||
case 1: n = 1; s = 0; break;
|
||||
case 2: n = 2; s = 1; break;
|
||||
default:
|
||||
return 0; /* Cannot be valid base64 */
|
||||
}
|
||||
|
||||
memset(decbuf + (dlen - n), 0, n);
|
||||
op = decbuf + (dlen - s);
|
||||
bytes = dlen - n;
|
||||
} else {
|
||||
op = decbuf + dlen;
|
||||
bytes = dlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 4 bytes of input,
|
||||
* each consisting of only 6 bits of information forming a base64 digit,
|
||||
* are concatenated back unsignedo 3 bytes of binary information.
|
||||
*
|
||||
* input digit 0 1 2 3
|
||||
* <----><-----><-----><---->
|
||||
* +--------+--------+--------+
|
||||
* |01234501|23450123|45012345|
|
||||
* +--------+--------+--------+
|
||||
* output byte 0 1 2
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start decoding from the end. The decoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch ((ip - buf) % 4) {
|
||||
case 0:
|
||||
do {
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #3 */
|
||||
if (v < 0) return 0;
|
||||
i = v;
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #2 */
|
||||
if (v < 0) return 0;
|
||||
i |= v << 6; /* had 6 bits */
|
||||
*--op = i & 0xff; /* Output #2 */
|
||||
i >>= 8; /* lower <0123> of output #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #1 */
|
||||
if (v < 0) return 0;
|
||||
i |= v << 4; /* had 4 bits */
|
||||
*--op = i & 0xff; /* Output #1 */
|
||||
i >>= 8; /* lower <01> of output #0 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #0 */
|
||||
if (v < 0) return 0;
|
||||
i |= v << 2; /* had 2 bits */
|
||||
*--op = i & 0xff; /* Output #0 */
|
||||
i >>= 8; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= decbuf);
|
||||
} while (op > decbuf);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
26
core/anslicensing/base64.h
Normal file
26
core/anslicensing/base64.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BASE64 {
|
||||
public:
|
||||
BASE64();
|
||||
~BASE64();
|
||||
|
||||
string encode(unsigned char * input, int len, bool padding = false);
|
||||
vector<unsigned char> decode(const char * input, int len = -1, int * outlen = nullptr);
|
||||
|
||||
int encode_pad_length(int len, int *pad);
|
||||
|
||||
private:
|
||||
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
|
||||
|
||||
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
|
||||
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
|
||||
|
||||
static const char values[];
|
||||
static const char alphabet[];
|
||||
};
|
||||
1000
core/anslicensing/bigint.cpp
Normal file
1000
core/anslicensing/bigint.cpp
Normal file
File diff suppressed because it is too large
Load Diff
130
core/anslicensing/bigint.h
Normal file
130
core/anslicensing/bigint.h
Normal file
@@ -0,0 +1,130 @@
|
||||
#ifndef __BIGINT_H
|
||||
#define __BIGINT_H
|
||||
|
||||
class bigint;
|
||||
class bigint_value;
|
||||
|
||||
class bigint_unit // Provides storage allocation and index checking
|
||||
{
|
||||
friend class bigint_value;
|
||||
friend class bigint;
|
||||
|
||||
public:
|
||||
bigint_unit();
|
||||
~bigint_unit();
|
||||
|
||||
public:
|
||||
void clear(); // set n to zero
|
||||
unsigned get( unsigned i ) const; // get ith unsigned
|
||||
void set( unsigned i, unsigned x ); // set ith unsigned
|
||||
void reserve( unsigned x ); // storage hint
|
||||
void fast_mul( bigint_unit & x, bigint_unit & y, unsigned n ); // Time critical routine
|
||||
|
||||
private:
|
||||
unsigned n; // used units (read-only)
|
||||
unsigned * a; // array of units
|
||||
unsigned z; // units allocated
|
||||
};
|
||||
|
||||
class bigint_value : public bigint_unit
|
||||
{
|
||||
friend class bigint;
|
||||
|
||||
public:
|
||||
bigint_value();
|
||||
|
||||
public:
|
||||
int is_zero() const;
|
||||
unsigned bit( unsigned i ) const;
|
||||
void setbit( unsigned i );
|
||||
void clearbit( unsigned i );
|
||||
unsigned bits() const;
|
||||
int cf( bigint_value& x ) const;
|
||||
int product( bigint_value &x ) const;
|
||||
void shl();
|
||||
int shr(); // result is carry
|
||||
void shr( unsigned n );
|
||||
void add( bigint_value& x );
|
||||
void _xor( bigint_value& x );
|
||||
void _and( bigint_value& x );
|
||||
void subtract( bigint_value& x );
|
||||
void init( unsigned x );
|
||||
void copy( bigint_value& x );
|
||||
unsigned to_unsigned(); // Unsafe conversion to unsigned
|
||||
void mul( bigint_value& x, bigint_value& y );
|
||||
void divide( bigint_value& x, bigint_value& y, bigint_value& rem );
|
||||
|
||||
private:
|
||||
unsigned share; // share count, used by bigint to delay physical copying
|
||||
};
|
||||
|
||||
class bigint // very long integer - can be used like long
|
||||
{
|
||||
public:
|
||||
// Construction and
|
||||
bigint ( unsigned x = 0 );
|
||||
bigint ( const bigint & x );
|
||||
~bigint();
|
||||
|
||||
public:
|
||||
// Standard arithmetic operators
|
||||
friend bigint operator +( const bigint& x, const bigint& y );
|
||||
friend bigint operator -( const bigint& x, const bigint& y );
|
||||
friend bigint operator *( const bigint& x, const bigint& y );
|
||||
friend bigint operator /( const bigint& x, const bigint& y );
|
||||
friend bigint operator %( const bigint& x, const bigint& y );
|
||||
friend bigint operator ^( const bigint& x, const bigint& y );
|
||||
friend bigint pow2( unsigned n );
|
||||
friend bigint operator &( const bigint& x, const bigint& y );
|
||||
|
||||
friend bigint operator <<( const bigint& x, unsigned n );
|
||||
|
||||
bigint & operator +=( const bigint& x );
|
||||
bigint & operator -=( const bigint& x );
|
||||
bigint & operator >>=( unsigned n );
|
||||
|
||||
// Standard comparison operators
|
||||
friend int operator !=( const bigint& x, const bigint& y );
|
||||
friend int operator ==( const bigint& x, const bigint& y );
|
||||
friend int operator >=( const bigint& x, const bigint& y );
|
||||
friend int operator <=( const bigint& x, const bigint& y );
|
||||
friend int operator > ( const bigint& x, const bigint& y );
|
||||
friend int operator < ( const bigint& x, const bigint& y );
|
||||
|
||||
// Absolute value
|
||||
friend bigint abs( const bigint & x );
|
||||
|
||||
// conversion operations
|
||||
friend unsigned to_unsigned( const bigint &x );
|
||||
bigint & operator =(const bigint& x);
|
||||
|
||||
// Bit operations
|
||||
unsigned bits() const;
|
||||
unsigned bit(unsigned i) const;
|
||||
void setbit(unsigned i);
|
||||
void clearbit(unsigned i);
|
||||
bigint & operator ^=( const bigint& x );
|
||||
bigint & operator &=( const bigint& x );
|
||||
bigint & ror( unsigned n ); // single bit rotate
|
||||
bigint & rol( unsigned n ); // single bit rotate
|
||||
friend int product( const bigint & x, const bigint & y ); // parity of x&y
|
||||
|
||||
void load( const unsigned * a, unsigned n ); // load value, a[0] is lsw
|
||||
void store( unsigned * a, unsigned n ) const; // low level save, a[0] is lsw
|
||||
|
||||
private:
|
||||
bigint_value * value;
|
||||
int negative;
|
||||
int cf( const bigint & x ) const;
|
||||
void docopy();
|
||||
friend class monty;
|
||||
};
|
||||
|
||||
bigint modexp( const bigint & x, const bigint & e, const bigint & m ); // m must be odd
|
||||
bigint gcd( const bigint & X, const bigint & Y ); // greatest common denominator
|
||||
bigint modinv( const bigint & a, const bigint & m ); // modular inverse
|
||||
bigint lucas ( const bigint & P, const bigint & Z, const bigint & k, const bigint & p ); // P^2 - 4Z != 0
|
||||
bigint sqrt( const bigint & g, const bigint & p ); // square root mod p
|
||||
bigint pow2( unsigned n );
|
||||
|
||||
#endif
|
||||
232
core/anslicensing/bitstream.cpp
Normal file
232
core/anslicensing/bitstream.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// Copyright (c) ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#include "bitstream.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BitStream::BitStream(int bitSize)
|
||||
{
|
||||
Create(bitSize);
|
||||
}
|
||||
|
||||
BitStream::BitStream(vector<unsigned char>& buf, int bufBits)
|
||||
{
|
||||
Attach(buf, bufBits);
|
||||
}
|
||||
|
||||
bool BitStream::Create(int bitCount)
|
||||
{
|
||||
m_bufBits = bitCount;
|
||||
m_currentBitIndex = 0;
|
||||
|
||||
if (!bitCount)
|
||||
{
|
||||
m_buf.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
m_buf.resize((bitCount + 7) >> 3);
|
||||
|
||||
Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitStream::Attach(vector<unsigned char>& buf, int bufBits)
|
||||
{
|
||||
m_buf = std::move(buf);
|
||||
m_bufBits = bufBits;
|
||||
m_currentBitIndex = 0;
|
||||
}
|
||||
|
||||
int BitStream::Read(void *bitPtr, int bitCount)
|
||||
{
|
||||
if(bitCount + m_currentBitIndex > m_bufBits)
|
||||
{
|
||||
bitCount = m_bufBits - m_currentBitIndex;
|
||||
}
|
||||
|
||||
if(!bitCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readBitCount = bitCount;
|
||||
unsigned char lastByteMask = (unsigned char)((1 << (readBitCount & 7)) - 1);
|
||||
unsigned char * sourcePtr = m_buf.data() + (m_currentBitIndex >> 3);
|
||||
int byteCount = (bitCount + 7) >> 3;
|
||||
unsigned char * destPtr = (unsigned char *)bitPtr;
|
||||
|
||||
int downShift = m_currentBitIndex & 0x7;
|
||||
int upShift = 8 - downShift;
|
||||
|
||||
if (!downShift)
|
||||
{
|
||||
while(byteCount--)
|
||||
*destPtr++ = *sourcePtr++;
|
||||
|
||||
m_currentBitIndex += bitCount;
|
||||
|
||||
if (lastByteMask > 0)
|
||||
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
|
||||
|
||||
return readBitCount;
|
||||
}
|
||||
|
||||
unsigned char sourceByte = *sourcePtr >> downShift;
|
||||
m_currentBitIndex += bitCount;
|
||||
|
||||
for (; bitCount > 8; bitCount -= 8)
|
||||
{
|
||||
unsigned char nextByte = *++sourcePtr;
|
||||
*destPtr++ = sourceByte | (nextByte << upShift);
|
||||
sourceByte = nextByte >> downShift;
|
||||
}
|
||||
|
||||
if (bitCount)
|
||||
{
|
||||
if (bitCount <= upShift)
|
||||
{
|
||||
*destPtr = sourceByte;
|
||||
return readBitCount;
|
||||
}
|
||||
|
||||
*destPtr = sourceByte | ( (*++sourcePtr) << upShift);
|
||||
}
|
||||
|
||||
if (lastByteMask > 0)
|
||||
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
|
||||
|
||||
return readBitCount;
|
||||
}
|
||||
|
||||
int BitStream::Write(const void * bitPtr, int bitCount)
|
||||
{
|
||||
int maxBits = ((m_bufBits + 7) >> 3) << 3;
|
||||
|
||||
if (bitCount + m_currentBitIndex > maxBits)
|
||||
{
|
||||
bitCount = maxBits - m_currentBitIndex;
|
||||
}
|
||||
|
||||
if(!bitCount)
|
||||
return 0;
|
||||
|
||||
int writeBitCount = bitCount;
|
||||
int upShift = m_currentBitIndex & 0x7;
|
||||
int downShift = 8 - upShift;
|
||||
|
||||
const unsigned char * sourcePtr = (unsigned char *)bitPtr;
|
||||
unsigned char * destPtr = m_buf.data() + (m_currentBitIndex >> 3);
|
||||
|
||||
// if this write is for <= 1 byte, and it will all fit in the
|
||||
// first dest byte, then do some special masking.
|
||||
if (downShift >= bitCount)
|
||||
{
|
||||
unsigned char mask = (unsigned char)(((1 << bitCount) - 1) << upShift);
|
||||
*destPtr = (*destPtr & ~mask) | ((*sourcePtr << upShift) & mask);
|
||||
m_currentBitIndex += bitCount;
|
||||
return writeBitCount;
|
||||
}
|
||||
|
||||
// check for byte aligned writes -- this will be
|
||||
// much faster than the shifting writes.
|
||||
|
||||
if(!upShift)
|
||||
{
|
||||
m_currentBitIndex += bitCount;
|
||||
|
||||
for(; bitCount >= 8; bitCount -= 8)
|
||||
*destPtr++ = *sourcePtr++;
|
||||
|
||||
if(bitCount)
|
||||
{
|
||||
unsigned char mask = (unsigned char)((1 << bitCount) - 1);
|
||||
*destPtr = (*sourcePtr & mask) | (*destPtr & ~mask);
|
||||
}
|
||||
|
||||
return writeBitCount;
|
||||
}
|
||||
|
||||
// the write destination is not byte aligned.
|
||||
unsigned char sourceByte;
|
||||
unsigned char destByte = *destPtr & (0xFF >> downShift);
|
||||
unsigned char lastMask = (unsigned char)(0xFF >> (7 - ((m_currentBitIndex + bitCount - 1) & 0x7)));
|
||||
|
||||
m_currentBitIndex += bitCount;
|
||||
|
||||
for(;bitCount >= 8; bitCount -= 8)
|
||||
{
|
||||
sourceByte = *sourcePtr++;
|
||||
*destPtr++ = destByte | (sourceByte << upShift);
|
||||
destByte = sourceByte >> downShift;
|
||||
}
|
||||
|
||||
if(bitCount == 0)
|
||||
{
|
||||
*destPtr = (*destPtr & ~lastMask) | (destByte & lastMask);
|
||||
return writeBitCount;
|
||||
}
|
||||
|
||||
if(bitCount <= downShift)
|
||||
{
|
||||
*destPtr = (*destPtr & ~lastMask) | ((destByte | (*sourcePtr << upShift)) & lastMask);
|
||||
return writeBitCount;
|
||||
}
|
||||
|
||||
sourceByte = *sourcePtr;
|
||||
|
||||
*destPtr++ = destByte | (sourceByte << upShift);
|
||||
*destPtr = (*destPtr & ~lastMask) | ((sourceByte >> downShift) & lastMask);
|
||||
|
||||
return writeBitCount;
|
||||
}
|
||||
|
||||
void BitStream::ZeroPadToNextByte()
|
||||
{
|
||||
unsigned char zero = 0;
|
||||
|
||||
if(m_currentBitIndex & 0x7)
|
||||
Write(&zero, 8 - (m_currentBitIndex & 0x7));
|
||||
}
|
||||
|
||||
int BitStream::Seek(int offset, bool relative)
|
||||
{
|
||||
unsigned oldIndex = m_currentBitIndex;
|
||||
m_currentBitIndex = (relative) ? m_currentBitIndex + offset : offset;
|
||||
return oldIndex;
|
||||
}
|
||||
|
||||
int BitStream::GetSize()
|
||||
{
|
||||
return m_bufBits;
|
||||
}
|
||||
|
||||
void * BitStream::GetBuffer(int * sizeInBits)
|
||||
{
|
||||
if (sizeInBits != NULL)
|
||||
*sizeInBits = m_bufBits;
|
||||
|
||||
return m_buf.data();
|
||||
}
|
||||
|
||||
void BitStream::ReleaseBuffer(int bitCount)
|
||||
{
|
||||
m_currentBitIndex = bitCount;
|
||||
}
|
||||
|
||||
void BitStream::Clear()
|
||||
{
|
||||
memset(m_buf.data(), 0, m_buf.size());
|
||||
}
|
||||
29
core/anslicensing/bitstream.h
Normal file
29
core/anslicensing/bitstream.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BitStream
|
||||
{
|
||||
public:
|
||||
BitStream(int bitSize = 0);
|
||||
BitStream(vector<unsigned char>& buf, int bitSize);
|
||||
|
||||
|
||||
bool Create(int sizeInBits);
|
||||
void Attach(vector<unsigned char>& buf, int sizeInBits);
|
||||
int Read(void *bitPtr, int countInBits);
|
||||
int Write(const void * bitPtr, int countInBits);
|
||||
int Seek(int offset, bool relative = false);
|
||||
int GetSize();
|
||||
void ZeroPadToNextByte();
|
||||
void * GetBuffer(int * sizeInBits = NULL);
|
||||
void ReleaseBuffer(int bitCount);
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
vector<unsigned char> m_buf;
|
||||
int m_bufBits;
|
||||
int m_currentBitIndex;
|
||||
};
|
||||
125
core/anslicensing/bitstream2.cpp
Normal file
125
core/anslicensing/bitstream2.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bitstream2.h"
|
||||
|
||||
const unsigned char BitStream2::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
|
||||
|
||||
BitStream2::BitStream2() :
|
||||
ownMemory(false),
|
||||
currentBit(0),
|
||||
currentByte(0),
|
||||
buffer(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BitStream2::BitStream2(int bitCount)
|
||||
{
|
||||
currentBit = 0;
|
||||
currentByte = 0;
|
||||
Create(bitCount);
|
||||
}
|
||||
|
||||
BitStream2::~BitStream2()
|
||||
{
|
||||
if (ownMemory)
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void BitStream2::Create(int bitCount)
|
||||
{
|
||||
bufSize = (bitCount + 7) >> 3;
|
||||
buffer = new unsigned char[(bitCount + 7) >> 3];
|
||||
ownMemory = true;
|
||||
memset(buffer, 0, bufSize);
|
||||
}
|
||||
|
||||
void BitStream2::Attach(void * buf, int bitCount)
|
||||
{
|
||||
buffer = (unsigned char *)buf;
|
||||
}
|
||||
|
||||
int BitStream2::Write(const unsigned char * buf, int bitCount)
|
||||
{
|
||||
unsigned char destByte;
|
||||
|
||||
int leftBits = currentBit & 7;
|
||||
int rightBits = 8 - leftBits;
|
||||
|
||||
int i = 0;
|
||||
int count = bitCount;
|
||||
while (count > 0)
|
||||
{
|
||||
destByte = (unsigned char)((buffer[currentByte] & hiMask[leftBits]) | (buf[i] >> leftBits));
|
||||
buffer[currentByte] = destByte;
|
||||
|
||||
count = (count > rightBits) ? count - rightBits : 0;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
currentByte++;
|
||||
buffer[currentByte] = (unsigned char)(buf[i] << rightBits);
|
||||
count = (count > leftBits) ? count - leftBits : 0;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
currentBit += bitCount;
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
int BitStream2::WriteUInt16(unsigned short val)
|
||||
{
|
||||
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
|
||||
return Write(split, 16);
|
||||
}
|
||||
|
||||
int BitStream2::Read(unsigned char * buf, int bitCount)
|
||||
{
|
||||
unsigned char destByte;
|
||||
int rightBits = 8 - (currentBit & 7);
|
||||
int leftBits = 8 - rightBits;
|
||||
|
||||
int count = bitCount;
|
||||
int i = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
buf[i] = (unsigned char)(buffer[currentByte] << leftBits);
|
||||
count = (count > rightBits) ? count - rightBits : 0;
|
||||
if (count > 0)
|
||||
{
|
||||
currentByte++;
|
||||
destByte = buf[i];
|
||||
destByte = (unsigned char)(destByte | (buffer[currentByte] >> rightBits));
|
||||
buf[i] = destByte;
|
||||
|
||||
count = (count > leftBits) ? count - leftBits : 0;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
currentBit += bitCount;
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
int BitStream2::ReadUInt16(unsigned short * val)
|
||||
{
|
||||
unsigned char split[2];
|
||||
|
||||
int result = Read(split, 16);
|
||||
|
||||
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char * BitStream2::GetBuffer()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
24
core/anslicensing/bitstream2.h
Normal file
24
core/anslicensing/bitstream2.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
class BitStream2
|
||||
{
|
||||
public:
|
||||
BitStream2();
|
||||
BitStream2(int bitCount);
|
||||
~BitStream2();
|
||||
|
||||
void Create(int bitCount);
|
||||
void Attach(void * buf, int bitCount);
|
||||
int Write(const unsigned char * buf, int bitCount);
|
||||
int WriteUInt16(unsigned short val);
|
||||
int Read(unsigned char * buf, int bitCount);
|
||||
int ReadUInt16(unsigned short * val);
|
||||
unsigned char * GetBuffer();
|
||||
|
||||
protected:
|
||||
bool ownMemory;
|
||||
unsigned char * buffer;
|
||||
int bufSize;
|
||||
int currentBit, currentByte;
|
||||
static const unsigned char hiMask[];
|
||||
};
|
||||
144
core/anslicensing/bitstream3.cpp
Normal file
144
core/anslicensing/bitstream3.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bitstream3.h"
|
||||
|
||||
const unsigned char BitStream3::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
|
||||
|
||||
BitStream3::BitStream3() :
|
||||
ownMemory(false),
|
||||
currentBit(0),
|
||||
currentByte(0),
|
||||
buffer(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BitStream3::BitStream3(int bitCount)
|
||||
{
|
||||
currentBit = 0;
|
||||
currentByte = 0;
|
||||
Create(bitCount);
|
||||
}
|
||||
|
||||
BitStream3::~BitStream3()
|
||||
{
|
||||
if (ownMemory)
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void BitStream3::Create(int bitCount)
|
||||
{
|
||||
bufSize = (bitCount + 7) >> 3;
|
||||
bitSize = bitCount;
|
||||
buffer = (unsigned char*)malloc((bitCount + 7) >> 3);
|
||||
ownMemory = true;
|
||||
memset(buffer, 0, bufSize);
|
||||
}
|
||||
|
||||
void BitStream3::Attach(void * buf, int bitCount)
|
||||
{
|
||||
buffer = (unsigned char *)buf;
|
||||
bitSize = bitCount;
|
||||
currentBit = 0;
|
||||
currentByte = 0;
|
||||
}
|
||||
|
||||
int BitStream3::Write(const unsigned char * buf, int bitCount)
|
||||
{
|
||||
int i = 0, gap = 8 - (currentBit & 7);
|
||||
|
||||
if (bitCount >= gap)
|
||||
{
|
||||
if ((gap & 7) != 0)
|
||||
{
|
||||
buffer[currentByte] = (unsigned char)((buffer[currentByte] << gap) | (buf[0] >> (bitCount < 8 ? bitCount - gap : 8 - gap)));
|
||||
currentBit += gap; bitCount -= gap; currentByte++;
|
||||
|
||||
for (; bitCount >= 8; i++, currentByte++, currentBit += 8, bitCount -= 8)
|
||||
buffer[currentByte] = (unsigned char)((buf[i] << gap) | (buf[i + 1] >> (8 - gap)));
|
||||
}
|
||||
else
|
||||
for (; bitCount >= 8; currentByte++, i++, currentBit += 8, bitCount -= 8)
|
||||
buffer[currentByte] = buf[i];
|
||||
}
|
||||
|
||||
if (bitCount > 0)
|
||||
{
|
||||
buffer[currentByte] = (unsigned char)((buffer[currentByte] << bitCount) | (buf[i] & ((1 << bitCount) - 1)));
|
||||
currentBit += bitCount;
|
||||
}
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
int BitStream3::WriteUInt16(unsigned short val)
|
||||
{
|
||||
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
|
||||
return Write(split, 16);
|
||||
}
|
||||
|
||||
int BitStream3::Read(unsigned char * readBuf, int bitCount)
|
||||
{
|
||||
int i = 0, gap = currentBit & 7;
|
||||
|
||||
if ((gap & 7) != 0)
|
||||
{
|
||||
for (; bitCount >= 8 + 8 - gap; bitCount -= 8, currentByte++, currentBit += 8, i++)
|
||||
readBuf[i] = (unsigned char)((buffer[currentByte] << gap) | (buffer[currentByte + 1] >> (8 - gap)));
|
||||
|
||||
// byte align
|
||||
if (bitCount > 0)
|
||||
{
|
||||
if (bitCount < 8 - gap)
|
||||
{
|
||||
readBuf[i] = (unsigned char)((buffer[currentByte] >> (8 - gap - bitCount)) & ((1 << bitCount) - 1));
|
||||
currentBit += bitCount;
|
||||
bitCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
readBuf[i] = (unsigned char)(buffer[currentByte] & ((1 << (8 - gap)) - 1));
|
||||
|
||||
bitCount -= (8 - gap);
|
||||
currentBit += (8 - gap);
|
||||
currentByte++;
|
||||
|
||||
readBuf[i] <<= (bitCount < gap ? bitCount : gap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
for (; bitCount >= 8; bitCount -= 8, currentByte++, currentBit += 8, i++)
|
||||
readBuf[i] = buffer[currentByte];
|
||||
|
||||
// already aligned
|
||||
if (bitCount > 0)
|
||||
{
|
||||
if (currentBit + 8 <= bitSize) // not last byte
|
||||
readBuf[i] |= (unsigned char)((buffer[currentByte] >> (8 - bitCount)) & ((1 << bitCount) - 1));
|
||||
else // last byte
|
||||
readBuf[i] = (unsigned char)((buffer[currentByte] >> ((bitSize & 7) - bitCount)) & ((1 << bitCount) - 1));
|
||||
|
||||
currentBit += bitCount;
|
||||
}
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
int BitStream3::ReadUInt16(unsigned short * val)
|
||||
{
|
||||
unsigned char split[2];
|
||||
|
||||
int result = Read(split, 16);
|
||||
|
||||
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char * BitStream3::GetBuffer()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
24
core/anslicensing/bitstream3.h
Normal file
24
core/anslicensing/bitstream3.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
class BitStream3
|
||||
{
|
||||
public:
|
||||
BitStream3();
|
||||
BitStream3(int bitCount);
|
||||
~BitStream3();
|
||||
|
||||
void Create(int bitCount);
|
||||
void Attach(void * buf, int bitCount);
|
||||
int Write(const unsigned char * buf, int bitCount);
|
||||
int WriteUInt16(unsigned short val);
|
||||
int Read(unsigned char * buf, int bitCount);
|
||||
int ReadUInt16(unsigned short * val);
|
||||
unsigned char * GetBuffer();
|
||||
|
||||
protected:
|
||||
bool ownMemory;
|
||||
unsigned char * buffer;
|
||||
int bufSize, bitSize;
|
||||
int currentBit, currentByte;
|
||||
static const unsigned char hiMask[];
|
||||
};
|
||||
4
core/anslicensing/bitstruct.cpp
Normal file
4
core/anslicensing/bitstruct.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "precomp.h"
|
||||
#include "bitstruct.h"
|
||||
|
||||
|
||||
378
core/anslicensing/bitstruct.h
Normal file
378
core/anslicensing/bitstruct.h
Normal file
@@ -0,0 +1,378 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "uniconv.h"
|
||||
#include "except.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BitStruct {
|
||||
|
||||
public:
|
||||
enum FIELD_TYPE
|
||||
{
|
||||
RAW,
|
||||
INTEGER,
|
||||
STRING,
|
||||
DATE14,
|
||||
DATE13,
|
||||
DATE16,
|
||||
};
|
||||
|
||||
private:
|
||||
class Field {
|
||||
public:
|
||||
Field():
|
||||
m_fieldType(FIELD_TYPE::INTEGER),
|
||||
m_offset(0),
|
||||
m_size(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Field(FIELD_TYPE fieldType, int offset, int size)
|
||||
{
|
||||
m_fieldType = fieldType;
|
||||
m_offset = offset;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
public:
|
||||
FIELD_TYPE m_fieldType;
|
||||
int m_offset;
|
||||
int m_size;
|
||||
};
|
||||
|
||||
typedef std::map<string, Field> FieldMap;
|
||||
|
||||
public:
|
||||
BitStruct(int bitSize = 0) :
|
||||
m_bits(bitSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BitStruct(vector<unsigned char>& buf, int bitSize):
|
||||
m_bits(buf, bitSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Create(int bitSize = 0)
|
||||
{
|
||||
m_bits.Create(bitSize);
|
||||
}
|
||||
|
||||
void Attach(vector<unsigned char>& buf, int bitSize)
|
||||
{
|
||||
m_bits.Attach(buf, bitSize);
|
||||
}
|
||||
|
||||
void AddField(const char * fieldName, FIELD_TYPE fieldType, int fieldBitSize, int offset = -1 )
|
||||
{
|
||||
if (offset == -1)
|
||||
offset = currentFieldOffset;
|
||||
|
||||
m_fieldMap.insert(FieldMap::value_type(fieldName, Field(fieldType, offset, fieldBitSize)));
|
||||
|
||||
currentFieldOffset = offset + fieldBitSize;
|
||||
}
|
||||
|
||||
bool GetField(const char * fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * fieldOffset) const
|
||||
{
|
||||
FieldMap::const_iterator iter = m_fieldMap.find(fieldName);
|
||||
|
||||
if (iter == m_fieldMap.end())
|
||||
return false;
|
||||
|
||||
*fieldType = iter->second.m_fieldType;
|
||||
*fieldSize = iter->second.m_size;
|
||||
*fieldOffset = iter->second.m_offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnumFields(void **enumHandle, const char **fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * offset)
|
||||
{
|
||||
FieldMap::iterator * pIter;
|
||||
static string name;
|
||||
|
||||
if (*enumHandle == NULL)
|
||||
{
|
||||
pIter = new FieldMap::iterator(m_fieldMap.begin());
|
||||
if (!pIter)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
pIter = (FieldMap::iterator *)(*enumHandle);
|
||||
|
||||
if (*pIter == m_fieldMap.end())
|
||||
{
|
||||
delete pIter;
|
||||
return false;
|
||||
}
|
||||
|
||||
name = (*pIter)->first;
|
||||
*fieldName = name.c_str();
|
||||
|
||||
*fieldType = (*pIter)->second.m_fieldType;
|
||||
*fieldSize = (*pIter)->second.m_size;
|
||||
*offset = (*pIter)->second.m_offset;
|
||||
|
||||
pIter->operator ++(); // *Iter++ does not work. Think why :)
|
||||
|
||||
*enumHandle = pIter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Set(const char * fieldName, const void * buf, unsigned len)
|
||||
{
|
||||
int offset = 0, size = m_bits.GetSize();
|
||||
|
||||
if (fieldName)
|
||||
{
|
||||
FieldMap::iterator iter;
|
||||
iter = m_fieldMap.find(fieldName);
|
||||
if (iter == m_fieldMap.end())
|
||||
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
|
||||
|
||||
offset = iter->second.m_offset;
|
||||
size = iter->second.m_size;
|
||||
}
|
||||
|
||||
m_bits.Seek(offset);
|
||||
|
||||
int bitlen = len << 3;
|
||||
|
||||
if (bitlen >= size)
|
||||
m_bits.Write(buf, size);
|
||||
else
|
||||
{
|
||||
int bits = size - bitlen;
|
||||
unsigned char * zeroes = (unsigned char *)_alloca((bits + 7) >> 3);
|
||||
memset(zeroes, 0, (bits + 7) >> 3);
|
||||
m_bits.Write(buf, bitlen);
|
||||
m_bits.Write(zeroes, bits);
|
||||
}
|
||||
}
|
||||
|
||||
void Set(const char * fieldName, const char * data)
|
||||
{
|
||||
Set(fieldName, data, (unsigned)strlen(data));
|
||||
}
|
||||
|
||||
void Set(const char * fieldName, int data)
|
||||
{
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
Set(fieldName, &data, sizeof(data));
|
||||
#else
|
||||
unsigned char buf[sizeof(int)] = { 0, 0, 0, 0 };
|
||||
|
||||
buf[0] = (unsigned char)(data & 0xFF);
|
||||
buf[1] = (unsigned char)((data >> 8) & 0xFF);
|
||||
buf[2] = (unsigned char)((data >> 16) & 0xFF);
|
||||
buf[3] = (unsigned char)((data >> 24) & 0xFF);
|
||||
|
||||
Set(fieldName, buf, sizeof(data));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Set(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
FieldMap::iterator iter;
|
||||
iter = m_fieldMap.find(fieldName);
|
||||
if (iter == m_fieldMap.end() )
|
||||
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
|
||||
|
||||
int date;
|
||||
|
||||
switch (iter->second.m_fieldType)
|
||||
{
|
||||
case FIELD_TYPE_DATE13:
|
||||
date = PackDate13(year, month, day);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_DATE14:
|
||||
date = PackDate14(year, month, day);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_DATE16:
|
||||
date = PackDate16(year, month, day);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "A data value is being set to a non-date field");
|
||||
}
|
||||
|
||||
Set(fieldName, date);
|
||||
}
|
||||
|
||||
void Get(const char * dataField, void * buf, int * len)
|
||||
{
|
||||
if (dataField)
|
||||
{
|
||||
FieldMap::const_iterator iter;
|
||||
|
||||
iter = m_fieldMap.find(dataField);
|
||||
if ( iter == m_fieldMap.end() )
|
||||
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
|
||||
|
||||
if ( *len < ( iter->second.m_size + 7 ) >> 3 )
|
||||
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
|
||||
|
||||
m_bits.Seek(iter->second.m_offset);
|
||||
m_bits.Read(buf, iter->second.m_size);
|
||||
|
||||
*len = (iter->second.m_size + 7) >> 3;
|
||||
} else
|
||||
{
|
||||
int validationDataLen = (m_bits.GetSize() + 7) >> 3;
|
||||
|
||||
if (*len < validationDataLen)
|
||||
{
|
||||
*len = validationDataLen;
|
||||
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
memcpy(buf, m_bits.GetBuffer(), validationDataLen);
|
||||
*len = validationDataLen;
|
||||
}
|
||||
}
|
||||
|
||||
int GetInt(const char * dataField)
|
||||
{
|
||||
FieldMap::const_iterator iter;
|
||||
|
||||
iter = m_fieldMap.find(dataField);
|
||||
if ( iter == m_fieldMap.end() )
|
||||
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
|
||||
|
||||
unsigned char buf[sizeof(int)] = {0, 0, 0, 0};
|
||||
|
||||
if ( sizeof(buf) < ( iter->second.m_size + 7 ) >> 3 )
|
||||
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
|
||||
|
||||
m_bits.Seek(iter->second.m_offset);
|
||||
m_bits.Read(buf, iter->second.m_size);
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
return *(int *)buf;
|
||||
#else
|
||||
return ((int)buf[3] << 24) | ((int)buf[2] << 16) | ((int)buf[1] << 8) | (int)buf[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetDate(const char * dataField, int * year, int * month, int * day)
|
||||
{
|
||||
FieldMap::const_iterator iter;
|
||||
|
||||
iter = m_fieldMap.find(dataField);
|
||||
if ( iter == m_fieldMap.end() )
|
||||
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
|
||||
|
||||
unsigned short packedDate = (unsigned short)GetInt(dataField);
|
||||
|
||||
switch (iter->second.m_fieldType)
|
||||
{
|
||||
case FIELD_TYPE_DATE13:
|
||||
UnpackDate13(packedDate, year, month, day);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_DATE14:
|
||||
UnpackDate14(packedDate, year, month, day);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_DATE16:
|
||||
UnpackDate16(packedDate, year, month, day);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "An attempt was made to query a date from a non-date field");
|
||||
}
|
||||
}
|
||||
|
||||
void * GetBuffer(int * sizeInBits = NULL)
|
||||
{
|
||||
return m_bits.GetBuffer(sizeInBits);
|
||||
}
|
||||
|
||||
BitStream& GetBitStream()
|
||||
{
|
||||
return m_bits;
|
||||
}
|
||||
|
||||
int GetCurrentFieldOffset()
|
||||
{
|
||||
return currentFieldOffset;
|
||||
}
|
||||
|
||||
void ResetFieldOffset()
|
||||
{
|
||||
currentFieldOffset = 0;
|
||||
}
|
||||
|
||||
int GetSize()
|
||||
{
|
||||
return m_bits.GetSize();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned short PackDate13(int year, int month, int day)
|
||||
{
|
||||
if (year < 2012 || year > 2027)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 13-bit date. Allowed values are 2012-2027");
|
||||
|
||||
return (unsigned short)(((month - 1) << 9) | ((day - 1) << 4) | (year - 2012));
|
||||
}
|
||||
|
||||
void UnpackDate13(unsigned short packedDate, int * year, int * month, int * day)
|
||||
{
|
||||
*year = 2012 + (packedDate & 0x0F);
|
||||
*month = 1 + (packedDate >> 9);
|
||||
*day = 1 + ((packedDate >> 4) & 0x1F);
|
||||
}
|
||||
|
||||
unsigned short PackDate14(int year, int month, int day)
|
||||
{
|
||||
if (year < 2010 || year > 2041)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 14-bit date. Allowed values are 2010-2041");
|
||||
|
||||
return (unsigned short)(((month - 1) << 10) | ((day - 1) << 5) | (year - 2010));
|
||||
}
|
||||
|
||||
void UnpackDate14(unsigned short packedDate, int * year, int * month, int * day)
|
||||
{
|
||||
*year = 2010 + (packedDate & 0x1F);
|
||||
*month = 1 + (packedDate >> 10);
|
||||
*day = 1 + ((packedDate >> 5) & 0x1F);
|
||||
}
|
||||
|
||||
unsigned short PackDate16(int year, int month, int day)
|
||||
{
|
||||
if (year < 2000 || year > 2127)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 16-bit date. Allowed values are 2010-2127");
|
||||
|
||||
return (unsigned short)(((year - 2000) << 9) | (month << 5) | day);
|
||||
}
|
||||
|
||||
void UnpackDate16(unsigned short packedDate, int * year, int * month, int * day)
|
||||
{
|
||||
*year = 2000 + (packedDate >> 9);
|
||||
*month = (packedDate & 0x01FF) >> 5;
|
||||
*day = packedDate & 0x001F;
|
||||
}
|
||||
|
||||
FieldMap m_fieldMap;
|
||||
BitStream m_bits;
|
||||
int currentFieldOffset;
|
||||
};
|
||||
2
core/anslicensing/certificate.cpp
Normal file
2
core/anslicensing/certificate.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "precomp.h"
|
||||
#include "certificate.h"
|
||||
451
core/anslicensing/certificate.h
Normal file
451
core/anslicensing/certificate.h
Normal file
@@ -0,0 +1,451 @@
|
||||
#ifndef __CERTIFICATE_H
|
||||
#define __CERTIFICATE_H
|
||||
|
||||
#include "ecc.h"
|
||||
#include "bitstruct.h"
|
||||
#include "except.h"
|
||||
#include "base64.h"
|
||||
#include "sdkregistration.h"
|
||||
#include "download.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
using namespace ECC;
|
||||
|
||||
class Certificate
|
||||
{
|
||||
public:
|
||||
Certificate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Certificate(const char * base64Certificate)
|
||||
{
|
||||
|
||||
BASE64 base64;
|
||||
int len;
|
||||
|
||||
auto buf = base64.decode(base64Certificate, strlen(base64Certificate), &len);
|
||||
|
||||
if (buf.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 encoding for certificate");
|
||||
|
||||
Attach(buf, len);
|
||||
}
|
||||
|
||||
Certificate(vector<unsigned char>& buf, int len)
|
||||
{
|
||||
Attach(buf, len);
|
||||
}
|
||||
|
||||
void* GetBuffer(int * len)
|
||||
{
|
||||
int size;
|
||||
void * buf = m_certBits.GetBuffer(&size);
|
||||
size = (size + 7) >> 3;
|
||||
*len = size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char * ToString()
|
||||
{
|
||||
|
||||
BASE64 base64;
|
||||
int len;
|
||||
static string base64cert;
|
||||
unsigned char * buf = (unsigned char *)m_certBits.GetBuffer(&len);
|
||||
len = (len + 7) >> 3;
|
||||
|
||||
auto base64Buf = base64.encode(buf, len, true);
|
||||
|
||||
if (base64Buf.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
|
||||
|
||||
base64cert = base64Buf.c_str();
|
||||
|
||||
return base64cert.c_str();
|
||||
}
|
||||
|
||||
/*
|
||||
static Certificate * Generate(int signatureSize, time_t expirationDate = 0)
|
||||
{
|
||||
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, NULL, expirationDate);
|
||||
}
|
||||
|
||||
static Certificate * Generate(int signatureSize, Certificate * signingCertificate, time_t expirationDate = 0)
|
||||
{
|
||||
return Generate(signatureSize, NULL, NULL, signingCertificate, NULL, expirationDate);
|
||||
}
|
||||
|
||||
static Certificate * Generate(int signatureSize, const char * certificateAuthorityUrl, time_t expirationDate = 0)
|
||||
{
|
||||
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, certificateAuthorityUrl, expirationDate);
|
||||
}
|
||||
*/
|
||||
|
||||
static bool VerifySignature(Certificate * cert, Certificate * validationCert)
|
||||
{
|
||||
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
|
||||
|
||||
if (validationCert == NULL || cert->m_certBits.GetInt("IsSelfSigned") != 0)
|
||||
cert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
|
||||
else
|
||||
validationCert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
|
||||
|
||||
Key key(rawPublicKey, rawPublicKeyLen);
|
||||
|
||||
Verifier verifier;
|
||||
|
||||
verifier.SetPublicKey(&key);
|
||||
|
||||
unsigned char * certBuffer = (unsigned char *)cert->m_certBits.GetBuffer();
|
||||
|
||||
int signedPartLen = 4 + cert->m_certBits.GetInt("PublicKeyLen"),
|
||||
signatureOffset = 2 + signedPartLen,
|
||||
signatureBitLen = cert->m_certBits.GetInt("SignatureSizeBits");
|
||||
|
||||
if (!verifier.Verify(certBuffer, signedPartLen, certBuffer + signatureOffset, (signatureBitLen + 7) >> 3, signatureBitLen))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetPublicKey(void * buf, int * len)
|
||||
{
|
||||
m_certBits.Get("PublicKey", buf, len);
|
||||
}
|
||||
|
||||
static Certificate * Generate(int signatureSize, const char * base64PrivateKey, const char * base64PublicKey, const char * base64SigningPrivateKey, const char * base64SigningCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||||
{
|
||||
Key * privateKey = NULL,
|
||||
* publicKey = NULL,
|
||||
* privateSigningKey;
|
||||
|
||||
Certificate * signingCertificate = NULL;
|
||||
Certificate * result;
|
||||
|
||||
try {
|
||||
if (base64PublicKey != NULL)
|
||||
publicKey = new Key(base64PublicKey);
|
||||
|
||||
if (base64PrivateKey != NULL)
|
||||
privateKey = new Key(base64PrivateKey);
|
||||
|
||||
if (base64SigningPrivateKey != NULL)
|
||||
privateSigningKey = new Key(base64SigningPrivateKey);
|
||||
|
||||
if (base64SigningCertificate != NULL)
|
||||
signingCertificate = new Certificate(base64SigningCertificate);
|
||||
|
||||
result = Generate(signatureSize, privateKey, publicKey, privateSigningKey, signingCertificate, certificateAuthorityUrl, expirationDate);
|
||||
} catch (...)
|
||||
{
|
||||
if (privateKey) delete privateKey;
|
||||
if (publicKey) delete publicKey;
|
||||
if (privateSigningKey) delete privateSigningKey;
|
||||
if (signingCertificate) delete signingCertificate;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (privateKey) delete privateKey;
|
||||
if (publicKey) delete publicKey;
|
||||
if (privateSigningKey) delete privateSigningKey;
|
||||
if (signingCertificate) delete signingCertificate;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static Certificate * Generate(int signatureSize, Key * privateKey, Key * publicKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||||
{
|
||||
|
||||
|
||||
if (publicKey == NULL)
|
||||
{
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "public key must be provided for the certificate");
|
||||
}
|
||||
|
||||
Key * signingKey = NULL;
|
||||
bool selfSigned;
|
||||
|
||||
if (signingPrivateKey == NULL && certificateAuthorityUrl == NULL)
|
||||
{
|
||||
selfSigned = true;
|
||||
signingKey = privateKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
selfSigned = false;
|
||||
if (signingPrivateKey != NULL)
|
||||
signingKey = signingPrivateKey;
|
||||
// else use certificate authority url for signing
|
||||
}
|
||||
|
||||
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
|
||||
publicKey->Store(rawPublicKey, &rawPublicKeyLen);
|
||||
|
||||
// unsigned char rawPrivateKey[256]; int rawPrivateKeyLen = 256;
|
||||
// signingKey->Store(rawPrivateKey, &rawPrivateKeyLen);
|
||||
|
||||
int certBitsLen = 4 * 8 + rawPublicKeyLen * 8;
|
||||
|
||||
BitStruct certBits(certBitsLen);
|
||||
|
||||
certBits.ResetFieldOffset();
|
||||
|
||||
certBits.AddField("Version", BitStruct::INTEGER, 4);
|
||||
certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
|
||||
certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
|
||||
certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
|
||||
certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
|
||||
certBits.AddField("PublicKey", BitStruct::RAW, rawPublicKeyLen * 8);
|
||||
|
||||
certBits.Set("Version", 0);
|
||||
certBits.Set("IsSelfSigned", (selfSigned) ? 1 : 0);
|
||||
certBits.Set("ReservedFlags", 0);
|
||||
|
||||
expirationDate = time(NULL);
|
||||
|
||||
struct tm * t = gmtime(&expirationDate);
|
||||
|
||||
certBits.Set("ExpirationDate", t->tm_year + 1900, t->tm_mon, t->tm_mday);
|
||||
certBits.Set("PublicKeyLen", rawPublicKeyLen);
|
||||
certBits.Set("PublicKey", rawPublicKey, rawPublicKeyLen);
|
||||
|
||||
unsigned char certSignature[256];
|
||||
int sigSizeBytes = 256;
|
||||
int sigSizeBits;
|
||||
|
||||
if (signingKey != NULL)
|
||||
{
|
||||
Signer signer;
|
||||
signer.SetPrivateKey(signingKey);
|
||||
signer.Sign(certBits.GetBuffer(), (certBitsLen + 7) >> 3, certSignature, &sigSizeBytes, &sigSizeBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
if (!certificateAuthorityUrl)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "no means for certificate signing were provided");
|
||||
|
||||
string certificateAuthorityRequest(certificateAuthorityUrl);
|
||||
certificateAuthorityRequest.append("?csr=");
|
||||
BASE64 base64;
|
||||
int len = 4096;
|
||||
char buffer[4096];
|
||||
|
||||
auto base64csr = base64.encode((unsigned char *)certBits.GetBuffer(), (certBits.GetSize() + 7) >> 3, true);
|
||||
string escapedBase64csr(base64csr.c_str());
|
||||
|
||||
StrReplace(escapedBase64csr, "+", "%2B");
|
||||
StrReplace(escapedBase64csr, "/", "%2F");
|
||||
StrReplace(escapedBase64csr, "=", "%3D");
|
||||
|
||||
certificateAuthorityRequest.append(escapedBase64csr);
|
||||
|
||||
const char * sdkLicenseKey = SDKRegistrationImpl::GetLicenseKey();
|
||||
|
||||
if (sdkLicenseKey && strlen(sdkLicenseKey) > 0)
|
||||
{
|
||||
certificateAuthorityRequest.append("&sdklicensekey=");
|
||||
certificateAuthorityRequest.append(sdkLicenseKey);
|
||||
}
|
||||
|
||||
UrlDownloadToString(certificateAuthorityRequest.c_str(), buffer, &len);
|
||||
|
||||
auto rawBuffer = base64.decode(buffer, len, &len);
|
||||
|
||||
if (rawBuffer.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 string");
|
||||
|
||||
auto certBuffer = rawBuffer;
|
||||
|
||||
unique_ptr<Certificate> issuedCert = std::make_unique<Certificate>(certBuffer, len);
|
||||
|
||||
sigSizeBits = issuedCert->m_certBits.GetInt("SignatureSizeBits");
|
||||
sigSizeBytes = (sigSizeBits + 7) >> 3;
|
||||
issuedCert->m_certBits.Get("Signature", certSignature, &sigSizeBytes);
|
||||
|
||||
memcpy(certBits.GetBuffer(), rawBuffer.data(), 4 + rawPublicKeyLen);
|
||||
#else
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signing private key not provided");
|
||||
#endif
|
||||
}
|
||||
|
||||
int certBufLen = ((certBitsLen + 7) >> 3) // header + public key
|
||||
+ 2 // signature size in bits
|
||||
+ ((sigSizeBits + 7) >> 3); // signature
|
||||
|
||||
vector<unsigned char> certBuf;
|
||||
certBuf.resize(certBufLen);
|
||||
|
||||
memcpy(certBuf.data(), certBits.GetBuffer(), (certBitsLen + 7) >> 3);
|
||||
|
||||
certBits.Attach(certBuf, certBufLen * 8);
|
||||
|
||||
certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
|
||||
certBits.AddField("Signature", BitStruct::RAW, ((sigSizeBits + 7) >> 3) << 3);
|
||||
|
||||
certBits.Set("SignatureSizeBits", sigSizeBits);
|
||||
certBits.Set("Signature", certSignature, (sigSizeBits + 7) >> 3);
|
||||
|
||||
Certificate * cert = new Certificate();
|
||||
|
||||
cert->m_certBits = std::move(certBits);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
static const char * Sign(const char * csr, const char * privateKey, const char * signingPrivateKey, const char * signingCertificate, const char * certificateAuthorityUrl, int expYear, int expMonth, int expDay)
|
||||
{
|
||||
Certificate * _csr = new Certificate(csr);
|
||||
Key * _privateKey = (privateKey) ? new Key(privateKey) : NULL;
|
||||
Key * _signingPrivateKey = (signingPrivateKey) ? new Key(signingPrivateKey) : NULL;
|
||||
Certificate * _signingCertificate = (signingCertificate) ? new Certificate(signingCertificate) : NULL;
|
||||
struct tm _expTm;
|
||||
time_t _expTime = 0;
|
||||
|
||||
if (expYear >= 1900 && expMonth >= 1 && expMonth <= 12 && expDay >= 1 && expDay <= 31)
|
||||
{
|
||||
memset(&_expTm, 0, sizeof(_expTm));
|
||||
|
||||
_expTm.tm_year = expYear - 1900;
|
||||
_expTm.tm_mon = expMonth - 1;
|
||||
_expTm.tm_mday = expDay;
|
||||
|
||||
_expTime = mktime(&_expTm);
|
||||
}
|
||||
else
|
||||
if (expYear != 0 || expMonth != 0 || expDay != 0)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "Invalid certificate expiration date");
|
||||
|
||||
Certificate * _signedCert = Sign(_csr, _privateKey, _signingPrivateKey, _signingCertificate, certificateAuthorityUrl, 0);
|
||||
|
||||
if (_csr) delete _csr;
|
||||
if (_privateKey) delete _privateKey;
|
||||
if (_signingPrivateKey) delete _signingPrivateKey;
|
||||
if (_signingCertificate) delete _signingCertificate;
|
||||
|
||||
const char * signedCert = _signedCert->ToString();
|
||||
|
||||
delete _signedCert;
|
||||
|
||||
return signedCert;
|
||||
}
|
||||
|
||||
static Certificate * Sign(Certificate * csr, Key * privateKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||||
{
|
||||
unsigned char buf[1024];
|
||||
int len = 1024;
|
||||
Key * publicKey;
|
||||
|
||||
csr->GetPublicKey(buf, &len);
|
||||
publicKey = new Key(buf, len);
|
||||
|
||||
Certificate * cert = Certificate::Generate(0, privateKey, publicKey, signingPrivateKey, signingCertificate, certificateAuthorityUrl, expirationDate);
|
||||
|
||||
delete publicKey;
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
private:
|
||||
void Attach(vector<unsigned char>& buf, int len)
|
||||
{
|
||||
m_certBits.Attach(buf, len << 3);
|
||||
|
||||
m_certBits.ResetFieldOffset();
|
||||
|
||||
m_certBits.AddField("Version", BitStruct::INTEGER, 4);
|
||||
m_certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
|
||||
m_certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
|
||||
m_certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
|
||||
m_certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
|
||||
m_certBits.AddField("PublicKey", BitStruct::RAW, m_certBits.GetInt("PublicKeyLen") * 8);
|
||||
|
||||
int signedPartLen = (m_certBits.GetCurrentFieldOffset() + 7) >> 3;
|
||||
|
||||
if (len <= signedPartLen)
|
||||
return;
|
||||
|
||||
m_certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
|
||||
|
||||
int signatureBitLen = m_certBits.GetInt("SignatureSizeBits");
|
||||
int signatureLen = (signatureBitLen + 7) >> 3;
|
||||
|
||||
int signatureOffset = m_certBits.GetCurrentFieldOffset() >> 3;
|
||||
|
||||
m_certBits.AddField("Signature", BitStruct::RAW, signatureLen << 3);
|
||||
}
|
||||
|
||||
static ECC::KEY_TYPE GetKeyType(int sigSize)
|
||||
{
|
||||
if (sigSize < 76 || sigSize > 322)
|
||||
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
|
||||
|
||||
ECC::KEY_TYPE keyType;
|
||||
int keySize;
|
||||
|
||||
if (sigSize <= 108)
|
||||
{
|
||||
keyType = ECC::ECC_54;
|
||||
keySize = 54;
|
||||
} else
|
||||
if (sigSize <= 146)
|
||||
{
|
||||
keyType = ECC::ECC_73;
|
||||
keySize = 73;
|
||||
} else
|
||||
if (sigSize <= 158)
|
||||
{
|
||||
keyType = ECC::ECC_79;
|
||||
keySize = 79;
|
||||
} else
|
||||
if (sigSize <= 182)
|
||||
{
|
||||
keyType = ECC::ECC_91;
|
||||
keySize = 91;
|
||||
} else
|
||||
if (sigSize <= 200)
|
||||
{
|
||||
keyType = ECC::ECC_100;
|
||||
keySize = 100;
|
||||
} else
|
||||
if (sigSize <= 240)
|
||||
{
|
||||
keyType = ECC::ECC_120;
|
||||
keySize = 120;
|
||||
} else
|
||||
if (sigSize <= 262)
|
||||
{
|
||||
keyType = ECC::ECC_131;
|
||||
keySize = 131;
|
||||
} else
|
||||
if (sigSize <= 282)
|
||||
{
|
||||
keyType = ECC::ECC_141;
|
||||
keySize = 141;
|
||||
} else
|
||||
{
|
||||
keyType = ECC::ECC_161;
|
||||
keySize = 161;
|
||||
}
|
||||
|
||||
return keyType;
|
||||
}
|
||||
|
||||
static void StrReplace(string& str, const string& oldStr, const string& newStr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(oldStr, pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
}
|
||||
|
||||
BitStruct m_certBits;
|
||||
};
|
||||
|
||||
#endif
|
||||
69
core/anslicensing/crc32.cpp
Normal file
69
core/anslicensing/crc32.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
const unsigned int Crc32::crcTable[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
|
||||
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
|
||||
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
|
||||
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
|
||||
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
|
||||
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
|
||||
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
|
||||
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
|
||||
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
|
||||
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
|
||||
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
|
||||
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
|
||||
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
|
||||
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
|
||||
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
|
||||
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
|
||||
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
|
||||
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
|
||||
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
|
||||
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
|
||||
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
|
||||
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
|
||||
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
|
||||
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
|
||||
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
|
||||
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
|
||||
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
|
||||
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
|
||||
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
|
||||
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
|
||||
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
|
||||
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
|
||||
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
|
||||
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
|
||||
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
|
||||
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
|
||||
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
|
||||
0x2D02EF8D
|
||||
};
|
||||
|
||||
unsigned int Crc32::Compute(const unsigned char * buffer, int count)
|
||||
{
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
|
||||
while (count--)
|
||||
crc = (crc >> 8) ^ crcTable[(crc ^ *buffer++) & 0xFF];
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
10
core/anslicensing/crc32.h
Normal file
10
core/anslicensing/crc32.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class Crc32
|
||||
{
|
||||
public:
|
||||
static unsigned int Compute(const unsigned char * buffer, int count);
|
||||
|
||||
private:
|
||||
static const unsigned int crcTable[256];
|
||||
};
|
||||
2616
core/anslicensing/cwrap.cpp
Normal file
2616
core/anslicensing/cwrap.cpp
Normal file
File diff suppressed because it is too large
Load Diff
211
core/anslicensing/download.cpp
Normal file
211
core/anslicensing/download.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "download.h"
|
||||
#include "uniconv.h"
|
||||
#include "except.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winhttp.h>
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
class CurlWriteBuffer
|
||||
{
|
||||
public:
|
||||
CurlWriteBuffer(void * buffer, size_t size)
|
||||
{
|
||||
this->buffer = (char *)buffer;
|
||||
this->size = size;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
int Append(void * buffer, size_t size)
|
||||
{
|
||||
if (this->offset + size > this->size)
|
||||
size = this->size - offset;
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
memcpy(this->buffer + offset, buffer, size);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
Callback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
return ((CurlWriteBuffer *)userp)->Append(contents, size * nmemb);
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
size_t size;
|
||||
char * buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void UrlDownloadToString(const char * url, char * buffer, int * len)
|
||||
{
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
#ifdef _WIN32
|
||||
HRESULT result = ERROR_SUCCESS;
|
||||
|
||||
URL_COMPONENTS urlComponents;
|
||||
|
||||
do {
|
||||
ZeroMemory(&urlComponents, sizeof(urlComponents));
|
||||
urlComponents.dwStructSize = sizeof(urlComponents);
|
||||
|
||||
urlComponents.dwHostNameLength = (DWORD)-1;
|
||||
urlComponents.dwUrlPathLength = (DWORD)-1;
|
||||
|
||||
auto urlw = s2w(url);
|
||||
|
||||
if (!WinHttpCrackUrl(urlw.c_str(), urlw.size(), 0L, &urlComponents))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
|
||||
if (!internet_ptr)
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
|
||||
if (connection_ptr == NULL)
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
wstring objectPath(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
|
||||
|
||||
DWORD requestFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
|
||||
if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
|
||||
requestFlags |= WINHTTP_FLAG_SECURE;
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> request_ptr(WinHttpOpenRequest(connection_ptr.get(), L"GET", objectPath.c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
|
||||
if (!request_ptr)
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0, 0L, NULL))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD status;
|
||||
DWORD statusSize = sizeof(DWORD);
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize, WINHTTP_NO_HEADER_INDEX))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != HTTP_STATUS_OK)
|
||||
{
|
||||
WCHAR buffer[1024];
|
||||
DWORD bufferSize = 1024;
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &bufferSize, WINHTTP_NO_HEADER_INDEX))
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
result = ERROR_WINHTTP_INVALID_URL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != HTTP_STATUS_OK)
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD offset = 0, count;
|
||||
char lbuf[0x100];
|
||||
|
||||
do {
|
||||
if (WinHttpReadData(request_ptr.get(), lbuf, 0x100, &count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
*len = offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset + count > *len)
|
||||
{
|
||||
result = ERROR_INSUFFICIENT_BUFFER;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer + offset, lbuf, count);
|
||||
offset += count;
|
||||
} else
|
||||
{
|
||||
result = GetLastError();
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
} while (false);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
throw new LicensingException(result, "networking error while downloading url contents");
|
||||
#else
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
if ((curl = curl_easy_init()) == NULL)
|
||||
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
|
||||
CurlWriteBuffer curlBuffer(buffer, *len);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteBuffer::Callback);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curlBuffer);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
curl_easy_cleanup(curl);
|
||||
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
|
||||
}
|
||||
|
||||
*len = curlBuffer.offset;
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
#endif
|
||||
#else // !LICENSING_NO_NETWORKING
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "networking support not built in");
|
||||
#endif
|
||||
}
|
||||
6
core/anslicensing/download.h
Normal file
6
core/anslicensing/download.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __DOWNLOAD_H
|
||||
#define __DOWNLOAD_H
|
||||
|
||||
void UrlDownloadToString(const char * url, char * buffer, int * len);
|
||||
|
||||
#endif
|
||||
1473
core/anslicensing/ec2m.cpp
Normal file
1473
core/anslicensing/ec2m.cpp
Normal file
File diff suppressed because it is too large
Load Diff
256
core/anslicensing/ec2m.h
Normal file
256
core/anslicensing/ec2m.h
Normal file
@@ -0,0 +1,256 @@
|
||||
// elliptic curves over GF(2^(L*K))
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAXL 16
|
||||
#define MAXK 193
|
||||
|
||||
class field;
|
||||
class field_element;
|
||||
class curve;
|
||||
class full_curve_parameter;
|
||||
|
||||
class small_field
|
||||
{
|
||||
friend class field;
|
||||
#if MAXL > 16 // assumes that unsigned short is at least 16 bits
|
||||
typedef unsigned lunit;
|
||||
#else
|
||||
#if MAXL > 8
|
||||
typedef unsigned short lunit;
|
||||
#else
|
||||
typedef unsigned char lunit;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// construction
|
||||
public:
|
||||
small_field( unsigned L, unsigned root );
|
||||
~small_field();
|
||||
|
||||
// methods
|
||||
public:
|
||||
unsigned * curve_order();
|
||||
|
||||
// properties
|
||||
public:
|
||||
lunit * const alog; // index range is [0..(BASE-2)]
|
||||
lunit * const log; // index range is [1..(BASE-1)], but log[0] is set to (BASE-1)
|
||||
const unsigned L, BASE, BASE_M1;
|
||||
};
|
||||
|
||||
// elements are polynomials with coefficients in small_field
|
||||
class field : public small_field
|
||||
{
|
||||
friend class curve;
|
||||
friend class field_element;
|
||||
friend class full_curve_parameter;
|
||||
|
||||
// construction
|
||||
public:
|
||||
field( class full_curve_parameter & a );
|
||||
virtual unsigned rand( unsigned base );
|
||||
|
||||
// methods
|
||||
private:
|
||||
typedef unsigned poly[ 2 * MAXK ];
|
||||
|
||||
static void add( const poly a, const poly b, poly c );
|
||||
static void copy ( const poly a, poly b );
|
||||
static int equal( const poly a, const poly b );
|
||||
void div( poly a, unsigned b );
|
||||
void set_random( poly a );
|
||||
int set_K( unsigned K, unsigned T );
|
||||
void reduce( poly a );
|
||||
void mul( const poly a, const poly b, poly c );
|
||||
void square( const poly a, poly b );
|
||||
void inverse( const poly a, poly b );
|
||||
int trace( const poly a );
|
||||
int slow_trace( const poly a );
|
||||
void quad_solve( const poly a, poly b );
|
||||
void sqrt( const poly a, poly b );
|
||||
void addmul( poly a, unsigned alpha, unsigned j, const poly b );
|
||||
|
||||
friend field_element sqrt( const field_element x );
|
||||
void unpack( const bigint & x, poly a );
|
||||
bigint pack( const poly a );
|
||||
|
||||
// properties
|
||||
private:
|
||||
const unsigned M, K, T;
|
||||
unsigned prng;
|
||||
poly nzt; // element with non-zero trace
|
||||
poly tm; // trace mask ( trace(x) is number of bits in x & tm )
|
||||
};
|
||||
|
||||
class field_element
|
||||
{
|
||||
friend class field;
|
||||
friend class curve;
|
||||
friend class point;
|
||||
friend field_element sqrt( const field_element x );
|
||||
|
||||
// construction
|
||||
public:
|
||||
field_element( const field_element & x );
|
||||
field_element( field * F );
|
||||
field_element();
|
||||
|
||||
// methods
|
||||
public:
|
||||
int operator == ( const field_element & x ) const;
|
||||
int operator == ( unsigned x ) const;
|
||||
field_element operator + ( const field_element & x ) const;
|
||||
field_element operator * ( const field_element & x ) const;
|
||||
field_element operator / ( const field_element & x ) const;
|
||||
field_element & operator = ( const field_element & x );
|
||||
|
||||
// properties
|
||||
private:
|
||||
field * f;
|
||||
field::poly v;
|
||||
};
|
||||
|
||||
class point
|
||||
{
|
||||
friend class curve;
|
||||
friend class ec_crypt;
|
||||
friend point operator * ( const bigint & k, const point & P );
|
||||
|
||||
// construction
|
||||
public:
|
||||
point();
|
||||
point( const point & P );
|
||||
point( curve * C );
|
||||
|
||||
// methods
|
||||
public:
|
||||
point & operator = ( const point & P );
|
||||
point operator + ( const point & P ) const;
|
||||
point operator - ( const point & P ) const;
|
||||
|
||||
// properties
|
||||
private:
|
||||
curve * c;
|
||||
field_element x, y;
|
||||
};
|
||||
|
||||
struct curve_parameter
|
||||
{
|
||||
unsigned L;
|
||||
unsigned K;
|
||||
unsigned T;
|
||||
unsigned root;
|
||||
unsigned b;
|
||||
unsigned nso;
|
||||
unsigned ntf;
|
||||
};
|
||||
|
||||
class full_curve_parameter : public curve_parameter
|
||||
{
|
||||
// construction
|
||||
public:
|
||||
full_curve_parameter( const curve_parameter & bp );
|
||||
|
||||
// properties
|
||||
public:
|
||||
bigint tm, p0, P0;
|
||||
};
|
||||
|
||||
class curve : public field
|
||||
{
|
||||
friend class curve_factory;
|
||||
friend class point;
|
||||
friend point operator * ( const bigint & k, const point & P );
|
||||
|
||||
// construction
|
||||
public:
|
||||
curve( full_curve_parameter & a );
|
||||
|
||||
// methods
|
||||
public:
|
||||
point random_point();
|
||||
static bigint pack( const point & P );
|
||||
point unpack( const bigint & X );
|
||||
static bigint to_vlong( const point & P );
|
||||
|
||||
// methods
|
||||
private:
|
||||
void add( const point & P, const point & Q, point & R );
|
||||
void sub( const point & P, const point & Q, point & R );
|
||||
void mul( const point & P, const bigint & x, point & Q );
|
||||
int calc_y( point & R, unsigned ybit=0 );
|
||||
static int MOV( unsigned B, const bigint & q, const bigint & r );
|
||||
static bigint small_lucas( bigint P, bigint Z, unsigned ik );
|
||||
static unsigned ybit( const field_element & x );
|
||||
static field_element sq( const field_element & x );
|
||||
|
||||
// properties
|
||||
public:
|
||||
point PP; // point with prime order
|
||||
bigint p; // prime order of P
|
||||
|
||||
// properties
|
||||
private:
|
||||
field_element b;
|
||||
};
|
||||
|
||||
class curve_factory // Used for calculating curve_parameter but in practice
|
||||
// use pre-calculated table ncdata.hpp or equivalent
|
||||
{
|
||||
// construction
|
||||
public:
|
||||
curve_factory( unsigned L ); // can take a long time
|
||||
~curve_factory();
|
||||
|
||||
// methods
|
||||
public:
|
||||
int find( unsigned K, curve_parameter & result );
|
||||
|
||||
// properties
|
||||
private:
|
||||
unsigned L;
|
||||
unsigned root;
|
||||
unsigned so_min;
|
||||
unsigned so_max;
|
||||
unsigned *so_set;
|
||||
bigint comp;
|
||||
};
|
||||
|
||||
struct bigint_pair
|
||||
{
|
||||
bigint r;
|
||||
bigint s;
|
||||
};
|
||||
|
||||
class ECC_BASE : private curve
|
||||
{
|
||||
// construction
|
||||
public:
|
||||
ECC_BASE( full_curve_parameter & a );
|
||||
~ECC_BASE();
|
||||
|
||||
// methods
|
||||
public:
|
||||
virtual unsigned rand( unsigned base );
|
||||
|
||||
bigint create_private_key();
|
||||
bigint create_public_key( const bigint & private_key );
|
||||
|
||||
bigint encrypt( const bigint & public_key, bigint & message );
|
||||
bigint decrypt( const bigint & private_key, const bigint & message );
|
||||
|
||||
bigint_pair schnorr_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
|
||||
bool schnorr_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
|
||||
|
||||
bigint_pair dsa_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &));
|
||||
bool dsa_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &));
|
||||
|
||||
// properties
|
||||
public:
|
||||
const unsigned bits; // number of bits in prime order
|
||||
#ifdef WIN32
|
||||
HCRYPTPROV m_cryptProv;
|
||||
#endif
|
||||
};
|
||||
|
||||
596
core/anslicensing/ecc.cpp
Normal file
596
core/anslicensing/ecc.cpp
Normal file
@@ -0,0 +1,596 @@
|
||||
//
|
||||
// Copyright (c) 2014 ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
#include "ecc.h"
|
||||
#include "bigint.h"
|
||||
#include "ec2m.h"
|
||||
#include "sha1.h"
|
||||
#include "except.h"
|
||||
#include "base64.h"
|
||||
#include "uniconv.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
namespace ECC {
|
||||
|
||||
#if 0
|
||||
void biPrint( bigint & data )
|
||||
{
|
||||
int n;
|
||||
unsigned * u;
|
||||
|
||||
n = ( data.bits() + 31 ) / 32;
|
||||
|
||||
u = new unsigned[ n ];
|
||||
|
||||
data.store( u, n );
|
||||
|
||||
printf( "%d ", data.bits() );
|
||||
|
||||
for ( int i = n - 1; i >= 0; i-- )
|
||||
{
|
||||
printf( "%08X ", u[i] );
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
delete [] u;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const curve_parameter eccCurveTable[ 10 ] = { { 9, 7, 1, 17, 43, 48, 1},
|
||||
{ 12, 7, 1, 83, 2049, 10, 1 },
|
||||
{ 13, 7, 1, 27, 124, 52, 1},
|
||||
{ 15, 7, 1, 3, 977, 110, 1},
|
||||
{ 16, 7, 1, 45, 2902, 6, 1},
|
||||
{ 10, 11, 2, 9, 139, 34, 1},
|
||||
{ 12, 11, 2, 83, 2083, 66, 1},
|
||||
{ 13, 11, 2, 27, 773, 48, 1},
|
||||
{ 14, 11, 2, 43, 146, 40, 1},
|
||||
{ 10, 17, 3, 9, 48, 28, 1} };
|
||||
|
||||
static void UintArrayToByteArray(unsigned * srcArray, int bitCount, unsigned char * dstArray)
|
||||
{
|
||||
int dstLength = ((int)bitCount + 7) >> 3;
|
||||
int srcLength = (dstLength + 3) >> 2;
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned currentUint;
|
||||
|
||||
if (dstLength > 3)
|
||||
{
|
||||
while (i < dstLength - 3)
|
||||
{
|
||||
currentUint = (j < srcLength) ? srcArray[j] : 0;
|
||||
|
||||
dstArray[i + 3] = (unsigned char)(currentUint >> 24);
|
||||
dstArray[i + 2] = (unsigned char)((currentUint >> 16) & 0xFF);
|
||||
dstArray[i + 1] = (unsigned char)((currentUint >> 8) & 0xFF);
|
||||
dstArray[i] = (unsigned char)(currentUint & 0xFF);
|
||||
i += 4;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
currentUint = (j < srcLength) ? srcArray[j] : 0;
|
||||
if (i < dstLength) dstArray[i] = (unsigned char)(currentUint & 0xFF); i++;
|
||||
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 8) & 0xFF); i++;
|
||||
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
static void ByteArrayToUintArray(unsigned char * srcArray, int srcLength, unsigned * dstArray)
|
||||
{
|
||||
int roundedLen = (srcLength + sizeof(unsigned) - 1) / sizeof(unsigned);
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < roundedLen - 1)
|
||||
{
|
||||
dstArray[i] = (unsigned)(((unsigned)srcArray[j + 3] << 24) | ((unsigned)srcArray[j + 2] << 16) | ((unsigned)srcArray[j + 1] << 8) | (unsigned)srcArray[j]);
|
||||
i += 1;
|
||||
j += 4;
|
||||
}
|
||||
|
||||
dstArray[roundedLen - 1] = 0;
|
||||
|
||||
if (j < srcLength) dstArray[roundedLen - 1] = (unsigned)(srcArray[j]); j++;
|
||||
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 8); j++;
|
||||
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 16); j++;
|
||||
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 24);
|
||||
}
|
||||
|
||||
class KeyImpl {
|
||||
friend class Key;
|
||||
friend class SignerImpl;
|
||||
friend class VerifierImpl;
|
||||
|
||||
friend void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
|
||||
|
||||
private:
|
||||
KeyImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KeyImpl(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
|
||||
{
|
||||
Load(keyBuf, bufLen, keyType);
|
||||
}
|
||||
|
||||
KeyImpl(const char * base64Key, KEY_TYPE keyType = ECC)
|
||||
{
|
||||
|
||||
BASE64 base64;
|
||||
|
||||
int len;
|
||||
|
||||
auto buf = base64.decode(base64Key, strlen(base64Key), &len);
|
||||
|
||||
if (buf.empty())
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "invalid base64 key");
|
||||
|
||||
Load(buf.data(), len, keyType);
|
||||
}
|
||||
|
||||
void Load(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
|
||||
{
|
||||
if (keyType == ECC)
|
||||
{
|
||||
unsigned char * keyBytes = (unsigned char *)keyBuf;
|
||||
|
||||
if ((keyBytes[0] >> 5) != 0)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "unsupported key version");
|
||||
|
||||
if (keyBytes[1] + 2 != bufLen)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "invalid key size");
|
||||
|
||||
isPrivate = ((keyBytes[0] & 0x10) != 0);
|
||||
SetKeyType((KEY_TYPE)(keyBytes[0] & 0x0F));
|
||||
|
||||
int roundedLen = sizeof(unsigned) * ((bufLen - 2 + sizeof(unsigned) - 1) / sizeof(unsigned));
|
||||
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
|
||||
if (!buf) return;
|
||||
|
||||
ByteArrayToUintArray(keyBytes + 2, bufLen - 2, buf);
|
||||
|
||||
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
|
||||
|
||||
free(buf);
|
||||
} else
|
||||
{
|
||||
SetKeyType(keyType);
|
||||
|
||||
int roundedLen = sizeof(unsigned) * ((bufLen + sizeof(unsigned) - 1) / sizeof(unsigned));
|
||||
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
|
||||
if (!buf) return;
|
||||
|
||||
ByteArrayToUintArray((unsigned char *)keyBuf, bufLen, buf);
|
||||
|
||||
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
|
||||
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
bool Store(void * buf, int * bufLen)
|
||||
{
|
||||
unsigned char * keyBytes = (unsigned char *)buf;
|
||||
|
||||
int numBits = m_key.bits();
|
||||
|
||||
int numBytes = (numBits + 7) >> 3;
|
||||
|
||||
if (*bufLen < 2 + numBytes)
|
||||
return false;
|
||||
|
||||
keyBytes[0] &= 0x1F; // set first 3 bits to 0 - version 1
|
||||
if (isPrivate) keyBytes[0] |= 0x10; else keyBytes[0] &= 0xEF; // the 4th bit is 1 if it's a private key
|
||||
keyBytes[0] = (keyBytes[0] & 0xF0) | (((unsigned char)m_keyType) & 0x0F); // the next 4 bits from 1st byte are the key type
|
||||
keyBytes[1] = numBytes; // the second byte specifies the key size
|
||||
|
||||
int numUints = (numBytes + sizeof(unsigned) - 1) / sizeof(unsigned);
|
||||
unsigned * temp = (unsigned int *)_alloca(numUints * sizeof(unsigned));
|
||||
m_key.store(temp, numUints);
|
||||
|
||||
UintArrayToByteArray(temp, numBits, keyBytes + 2);
|
||||
|
||||
*bufLen = numBytes + 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetKeyType(KEY_TYPE keyType)
|
||||
{
|
||||
m_keyType = keyType;
|
||||
switch (keyType)
|
||||
{
|
||||
case ECC_54: m_keySize = 54;break;
|
||||
case ECC_73: m_keySize = 73;break;
|
||||
case ECC_79: m_keySize = 79;break;
|
||||
case ECC_91: m_keySize = 91;break;
|
||||
case ECC_97: m_keySize = 97;break;
|
||||
case ECC_100: m_keySize = 100;break;
|
||||
case ECC_120: m_keySize = 120;break;
|
||||
case ECC_131: m_keySize = 131;break;
|
||||
case ECC_141: m_keySize = 141;break;
|
||||
case ECC_161: m_keySize = 161;break;
|
||||
}
|
||||
}
|
||||
|
||||
KEY_TYPE GetKeyType()
|
||||
{
|
||||
return m_keyType;
|
||||
}
|
||||
|
||||
KEY_TYPE m_keyType;
|
||||
int m_keySize;
|
||||
bigint m_key;
|
||||
bool isPrivate;
|
||||
};
|
||||
|
||||
class SignerImpl {
|
||||
public:
|
||||
SignerImpl()
|
||||
{
|
||||
m_hashBits = 0; // thus select ECDSA as the signing algorithm
|
||||
}
|
||||
|
||||
~SignerImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static bigint Hash(const bigint & x, const bigint & p)
|
||||
{
|
||||
unsigned int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
|
||||
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
|
||||
unsigned int h[ 5 ];
|
||||
|
||||
x.store(a, n);
|
||||
|
||||
SHA1 sha;
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
|
||||
#else
|
||||
int nb = (x.bits() + 7) >> 3;
|
||||
unsigned char * buf = (unsigned char *)_alloca(nb);
|
||||
UintArrayToByteArray(a, x.bits(), buf);
|
||||
sha.Update(buf, nb);
|
||||
#endif
|
||||
|
||||
sha.Final();
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.GetHash((unsigned char *)h);
|
||||
#else
|
||||
unsigned char bh[20];
|
||||
sha.GetHash(bh);
|
||||
ByteArrayToUintArray(bh, 20, h);
|
||||
#endif
|
||||
|
||||
bigint r;
|
||||
r.load( h, 5 );
|
||||
|
||||
return r % p;
|
||||
}
|
||||
|
||||
void SetHashSize(int hashBits)
|
||||
{
|
||||
m_hashBits = hashBits;
|
||||
}
|
||||
|
||||
void SetPrivateKey(const KeyImpl & privKey)
|
||||
{
|
||||
m_privateKey = privKey;
|
||||
}
|
||||
|
||||
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
|
||||
{
|
||||
full_curve_parameter param(eccCurveTable[ m_privateKey.m_keyType ]);
|
||||
ECC_BASE ecc(param);
|
||||
bigint message;
|
||||
bigint temp;
|
||||
bigint_pair signature;
|
||||
|
||||
*sigLenBits = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? m_hashBits + m_privateKey.m_keySize : m_privateKey.m_keySize << 1;
|
||||
*sigLen = (*sigLenBits + 7) >> 3;
|
||||
|
||||
unsigned * buf = (unsigned *)_alloca(msgLen + *sigLen + sizeof(unsigned) - 1);
|
||||
|
||||
// take care of endianess here, do not do just a memcpy()
|
||||
memcpy(buf, msg, msgLen);
|
||||
memset((char *)buf + msgLen, 0, sizeof(unsigned) - 1);
|
||||
|
||||
unsigned msgHash[5];
|
||||
|
||||
SHA1 sha;
|
||||
sha.Update((unsigned char *)msg, msgLen);
|
||||
sha.Final();
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.GetHash((unsigned char *)msgHash);
|
||||
#else
|
||||
unsigned char msgHashBuf[20];
|
||||
sha.GetHash(msgHashBuf);
|
||||
ByteArrayToUintArray(msgHashBuf, 20, msgHash);
|
||||
#endif
|
||||
|
||||
message.load(msgHash, 5);
|
||||
|
||||
signature = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? ecc.schnorr_sign(message, m_privateKey.m_key, Hash, m_hashBits) : ecc.dsa_sign(message, m_privateKey.m_key, Hash);
|
||||
|
||||
temp = (signature.r << m_privateKey.m_keySize); temp += signature.s;
|
||||
|
||||
unsigned int n = (unsigned)((*sigLen + sizeof(unsigned) - 1) / sizeof(unsigned));
|
||||
|
||||
temp.store(buf, n);
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
// take care of endianess here
|
||||
memcpy(sigBuf, buf, *sigLen);
|
||||
#else
|
||||
UintArrayToByteArray(buf, *sigLenBits, (unsigned char *)sigBuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
KeyImpl m_privateKey;
|
||||
int m_hashBits;
|
||||
};
|
||||
|
||||
class VerifierImpl {
|
||||
public:
|
||||
VerifierImpl()
|
||||
{
|
||||
m_hashBits = 0;
|
||||
}
|
||||
|
||||
~VerifierImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static bigint Hash(const bigint & x, const bigint & p)
|
||||
{
|
||||
int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
|
||||
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
|
||||
unsigned int h[ 5 ];
|
||||
|
||||
x.store(a, n);
|
||||
|
||||
SHA1 sha;
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
|
||||
#else
|
||||
int nb = (x.bits() + 7) >> 3;
|
||||
unsigned char * buf = (unsigned char *)_alloca(nb);
|
||||
UintArrayToByteArray(a, x.bits(), buf);
|
||||
sha.Update(buf, nb);
|
||||
#endif
|
||||
|
||||
sha.Final();
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.GetHash((unsigned char *)h);
|
||||
#else
|
||||
unsigned char bh[20];
|
||||
sha.GetHash(bh);
|
||||
ByteArrayToUintArray(bh, 20, h);
|
||||
#endif
|
||||
|
||||
bigint r;
|
||||
r.load( h, 5 );
|
||||
|
||||
return r % p;
|
||||
}
|
||||
|
||||
void SetHashSize(int hashBits)
|
||||
{
|
||||
m_hashBits = hashBits;
|
||||
}
|
||||
|
||||
void SetPublicKey(const KeyImpl & pubKey)
|
||||
{
|
||||
m_publicKey = pubKey;
|
||||
}
|
||||
|
||||
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
|
||||
{
|
||||
full_curve_parameter param(eccCurveTable[ m_publicKey.m_keyType ]);
|
||||
ECC_BASE ecc(param);
|
||||
bigint message;
|
||||
bigint_pair signature;
|
||||
|
||||
int msgBufLen = (msgLen + sizeof(unsigned) - 1) / sizeof(unsigned);
|
||||
int sigBufLen = (sigLen + sizeof(unsigned) - 1) / sizeof(unsigned);
|
||||
|
||||
unsigned * msgBuf = (unsigned *)_alloca(msgBufLen * sizeof(unsigned));
|
||||
unsigned * sigBuf = (unsigned *)_alloca(sigBufLen * sizeof(unsigned));
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
memset(msgBuf, 0, msgBufLen * sizeof(unsigned));
|
||||
memcpy(msgBuf, msg, msgLen);
|
||||
memset(sigBuf, 0, sigBufLen * sizeof(unsigned));
|
||||
memcpy(sigBuf, sig, sigLen);
|
||||
#else
|
||||
ByteArrayToUintArray((unsigned char *)msg, msgLen, msgBuf);
|
||||
ByteArrayToUintArray((unsigned char *)sig, sigLen, sigBuf);
|
||||
#endif
|
||||
|
||||
unsigned int msgHash[5];
|
||||
|
||||
SHA1 sha;
|
||||
sha.Update((unsigned char *)msg, msgLen);
|
||||
sha.Final();
|
||||
|
||||
#ifndef LICENSING_BIG_ENDIAN
|
||||
sha.GetHash((unsigned char *)msgHash);
|
||||
#else
|
||||
unsigned char byteHash[20];
|
||||
|
||||
sha.GetHash(byteHash);
|
||||
|
||||
ByteArrayToUintArray(byteHash, 20, msgHash);
|
||||
#endif
|
||||
message.load(msgHash, 5);
|
||||
|
||||
signature.r.load(sigBuf, sigBufLen);
|
||||
|
||||
signature.r >>= m_publicKey.m_keySize; signature.r &= (pow2((unsigned)(sigLenBits - m_publicKey.m_keySize)) - 1);
|
||||
|
||||
signature.s.load(sigBuf, sigBufLen);
|
||||
|
||||
signature.s &= (pow2(m_publicKey.m_keySize) - 1);
|
||||
|
||||
return (m_hashBits && m_hashBits < m_publicKey.m_keySize) ? ecc.schnorr_verify(message, signature, m_publicKey.m_key, Hash, m_hashBits) : ecc.dsa_verify(message, signature, m_publicKey.m_key, Hash);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_hashBits;
|
||||
KeyImpl m_publicKey;
|
||||
};
|
||||
|
||||
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey)
|
||||
{
|
||||
full_curve_parameter param(eccCurveTable[ keyType ]);
|
||||
ECC_BASE ecc(param);
|
||||
Key * privateKey = new Key(),
|
||||
* publicKey = new Key();
|
||||
|
||||
privateKey->m_Impl.m_key = ecc.create_private_key();
|
||||
privateKey->m_Impl.SetKeyType(keyType);
|
||||
privateKey->m_Impl.isPrivate = true;
|
||||
|
||||
publicKey->m_Impl.m_key = ecc.create_public_key(privateKey->m_Impl.m_key);
|
||||
publicKey->m_Impl.SetKeyType(keyType);
|
||||
|
||||
*privKey = privateKey;
|
||||
*pubKey = publicKey;
|
||||
}
|
||||
|
||||
Key::Key():
|
||||
m_Impl( *new KeyImpl() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Key::Key(const void * keyBuf, int bufLen, KEY_TYPE keyType):
|
||||
m_Impl( *new KeyImpl(keyBuf, bufLen, keyType) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Key::Key(const char * base64Key, KEY_TYPE keyType):
|
||||
m_Impl( *new KeyImpl(base64Key, keyType))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Key::~Key()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
void Key::Load(const void * keyData, int keyLen, KEY_TYPE keyType)
|
||||
{
|
||||
m_Impl.Load(keyData, keyLen, keyType);
|
||||
}
|
||||
|
||||
bool Key::Store(void * buf, int * bufLen) const
|
||||
{
|
||||
return m_Impl.Store(buf, bufLen);
|
||||
}
|
||||
|
||||
const char * Key::ToString()
|
||||
{
|
||||
|
||||
static string base64key;
|
||||
|
||||
int len = 2 + ((m_Impl.m_key.bits() + 7) >> 3);
|
||||
unsigned char * buf = (unsigned char *)_alloca(len);
|
||||
Store(buf, &len);
|
||||
|
||||
BASE64 base64;
|
||||
|
||||
auto base64Buf = base64.encode(buf, len, true);
|
||||
if (base64Buf.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
|
||||
|
||||
base64key = base64Buf.c_str();
|
||||
|
||||
return base64key.c_str();
|
||||
}
|
||||
|
||||
KEY_TYPE Key::GetKeyType()
|
||||
{
|
||||
return m_Impl.GetKeyType();
|
||||
}
|
||||
|
||||
const Key & Key::operator = (const Key & key)
|
||||
{
|
||||
m_Impl = key.m_Impl;
|
||||
return (const Key &)(*this);
|
||||
}
|
||||
|
||||
Signer::Signer():
|
||||
m_Impl(*new SignerImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Signer::~Signer()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
void Signer::SetHashSize(int hashBits)
|
||||
{
|
||||
m_Impl.SetHashSize(hashBits);
|
||||
}
|
||||
|
||||
void Signer::SetPrivateKey(const Key * privKey)
|
||||
{
|
||||
m_Impl.SetPrivateKey(privKey->m_Impl);
|
||||
}
|
||||
|
||||
void Signer::Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
|
||||
{
|
||||
m_Impl.Sign(msg, msgLen, sigBuf, sigLen, sigLenBits);
|
||||
}
|
||||
|
||||
Verifier::Verifier():
|
||||
m_Impl( *new VerifierImpl() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Verifier::~Verifier()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
void Verifier::SetHashSize(int hashBits)
|
||||
{
|
||||
m_Impl.SetHashSize(hashBits);
|
||||
}
|
||||
|
||||
void Verifier::SetPublicKey(const Key * pubKey)
|
||||
{
|
||||
m_Impl.SetPublicKey(pubKey->m_Impl);
|
||||
}
|
||||
|
||||
bool Verifier::Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
|
||||
{
|
||||
return m_Impl.Verify(msg, msgLen, sig, sigLen, sigLenBits);
|
||||
}
|
||||
|
||||
}
|
||||
80
core/anslicensing/ecc.h
Normal file
80
core/anslicensing/ecc.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef __ECC_H
|
||||
#define __ECC_H
|
||||
|
||||
namespace ECC {
|
||||
|
||||
enum KEY_TYPE {
|
||||
ECC_54,
|
||||
ECC_73,
|
||||
ECC_79,
|
||||
ECC_91,
|
||||
ECC_97,
|
||||
ECC_100,
|
||||
ECC_120,
|
||||
ECC_131,
|
||||
ECC_141,
|
||||
ECC_161,
|
||||
ECC
|
||||
};
|
||||
|
||||
class KeyImpl;
|
||||
|
||||
class Key {
|
||||
public:
|
||||
Key();
|
||||
Key(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
|
||||
Key(const char * base64Key, KEY_TYPE keyType = ECC);
|
||||
~Key();
|
||||
|
||||
void Load(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
|
||||
bool Store(void * buf, int * bufLen) const;
|
||||
const char * ToString();
|
||||
|
||||
KEY_TYPE GetKeyType();
|
||||
|
||||
const Key & operator = (const Key & key);
|
||||
|
||||
public:
|
||||
KeyImpl & m_Impl;
|
||||
};
|
||||
|
||||
typedef unsigned (*HashFunction)(const void *, int, void *, unsigned *);
|
||||
|
||||
class SignerImpl;
|
||||
|
||||
class Signer
|
||||
{
|
||||
public:
|
||||
Signer();
|
||||
~Signer();
|
||||
|
||||
void SetPrivateKey(const Key * privKey);
|
||||
void SetHashSize(int hashBits);
|
||||
|
||||
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int *sigLenInBits = (int *)0);
|
||||
|
||||
private:
|
||||
SignerImpl & m_Impl;
|
||||
};
|
||||
|
||||
class VerifierImpl;
|
||||
|
||||
class Verifier {
|
||||
public:
|
||||
Verifier();
|
||||
~Verifier();
|
||||
|
||||
void SetPublicKey(const Key * pubKey);
|
||||
void SetHashSize(int hashBits);
|
||||
|
||||
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenInBits = 0);
|
||||
|
||||
private:
|
||||
VerifierImpl & m_Impl;
|
||||
};
|
||||
|
||||
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
3
core/anslicensing/except.cpp
Normal file
3
core/anslicensing/except.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "precomp.h"
|
||||
#include "except.h"
|
||||
|
||||
31
core/anslicensing/except.h
Normal file
31
core/anslicensing/except.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __EXCEPT_H
|
||||
#define __EXCEPT_H
|
||||
|
||||
#include <string>
|
||||
#include "anslicensing.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LicensingException : public ANSCENTER::Licensing::Exception {
|
||||
public:
|
||||
LicensingException( int code, const char * message = NULL)
|
||||
{
|
||||
SetCode(code);
|
||||
if (message)
|
||||
SetMessage(message);
|
||||
}
|
||||
|
||||
virtual ~LicensingException() {}
|
||||
|
||||
virtual int GetCode() { return m_code; }
|
||||
virtual const char * GetExceptionMessage() { return m_message.c_str(); }
|
||||
virtual void Destroy() { delete this; }
|
||||
void SetCode(int code) { m_code = code; }
|
||||
void SetMessage(const char * message) { m_message = message; }
|
||||
|
||||
protected:
|
||||
int m_code;
|
||||
string m_message;
|
||||
};
|
||||
|
||||
#endif
|
||||
207
core/anslicensing/generator.cpp
Normal file
207
core/anslicensing/generator.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright (c) 2014 ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
#include "anslicensing.h"
|
||||
#include "template.h"
|
||||
#include "base32.h"
|
||||
#include "base64.h"
|
||||
#include "sha1.h"
|
||||
#include "except.h"
|
||||
#include "bitstream.h"
|
||||
#include "uniconv.h"
|
||||
#include "generator.h"
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
template<>
|
||||
KeyGeneratorT<char>::KeyGeneratorT():
|
||||
m_Impl( *new KeyGeneratorImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<wchar_t>::KeyGeneratorT():
|
||||
m_Impl( *new KeyGeneratorImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<char>::KeyGeneratorT(const LicenseTemplateT<char> * templ):
|
||||
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<wchar_t>::KeyGeneratorT(const LicenseTemplateT<wchar_t> * templ):
|
||||
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<char>::~KeyGeneratorT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<wchar_t>::~KeyGeneratorT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<char> * KeyGeneratorT<char>::Create()
|
||||
{
|
||||
return new KeyGeneratorT<char>();
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyGeneratorT<wchar_t> * KeyGeneratorT<wchar_t>::Create()
|
||||
{
|
||||
return new KeyGeneratorT<wchar_t>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::Destroy(KeyGeneratorT<char> * obj)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::Destroy(KeyGeneratorT<wchar_t> * obj)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_Impl.KeyGeneratorImpl::SetKeyData(fieldName, buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_Impl.KeyGeneratorImpl::SetKeyData(w2s(fieldName).c_str(), buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int data)
|
||||
{
|
||||
|
||||
m_Impl.SetKeyData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int data)
|
||||
{
|
||||
m_Impl.SetKeyData(w2s(fieldName).c_str(), data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_Impl.SetKeyData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const wchar_t * data)
|
||||
{
|
||||
m_Impl.SetKeyData(w2s(fieldName).c_str(), w2s(data).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_Impl.SetKeyData(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_Impl.SetKeyData(w2s(fieldName).c_str(), year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
|
||||
m_Impl.SetValidationData(fieldName, buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, int data)
|
||||
{
|
||||
m_Impl.SetValidationData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
|
||||
{
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_Impl.SetValidationData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
|
||||
{
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> & templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ.m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> & templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ.m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
const char * KeyGeneratorT<char>::GenerateKey()
|
||||
{
|
||||
return m_Impl.GenerateKey();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t * KeyGeneratorT<wchar_t>::GenerateKey()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GenerateKey());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
};
|
||||
};
|
||||
423
core/anslicensing/generator.h
Normal file
423
core/anslicensing/generator.h
Normal file
@@ -0,0 +1,423 @@
|
||||
#pragma once
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "base32.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
#ifdef _WIN32
|
||||
#include <winhttp.h>
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class KeyGeneratorImpl {
|
||||
public:
|
||||
KeyGeneratorImpl():
|
||||
m_signingServiceStatusCode(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KeyGeneratorImpl(const LicenseTemplateImpl * templ):
|
||||
KeyGeneratorImpl()
|
||||
{
|
||||
SetKeyTemplate(templ);
|
||||
}
|
||||
|
||||
void SetKeyTemplate(const LicenseTemplateImpl * templ)
|
||||
{
|
||||
m_keyTemplate = templ;
|
||||
|
||||
m_keyData.Create(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_keyEncoding);
|
||||
m_keyData.GetBitStream().Clear();
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_dataFields)
|
||||
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
|
||||
if (m_keyTemplate->m_validationDataSize)
|
||||
{
|
||||
m_validationData.Create(m_keyTemplate->m_validationDataSize);
|
||||
m_validationData.GetBitStream().Clear();
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_validationFields)
|
||||
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
}
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_keyData.Set(fieldName, buf, len);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_keyData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, int data)
|
||||
{
|
||||
m_keyData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_keyData.Set(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_validationData.Set(fieldName, buf, len);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, int data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static size_t
|
||||
CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
KeyGeneratorImpl * pthis = (KeyGeneratorImpl *)userp;
|
||||
size_t realsize = size * nmemb;
|
||||
|
||||
if (realsize > 1024 || pthis->m_keyBuffer.length() > 1024)
|
||||
return realsize - 1; // signal error
|
||||
|
||||
if (realsize > 0)
|
||||
pthis->m_keyBuffer.append((char *)contents, realsize);
|
||||
|
||||
return realsize;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char * GenerateKey()
|
||||
{
|
||||
BitStream signedData;
|
||||
BitStream signature;
|
||||
ECC::Signer signer;
|
||||
int sigLen, sigLenBits;
|
||||
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
if (m_keyTemplate->m_signingKey == NULL)
|
||||
{
|
||||
|
||||
|
||||
m_signingServiceStatusCode = -1;
|
||||
|
||||
string activationQuery("Activate.ashx?");
|
||||
|
||||
//if (activationQuery[m_keyTemplate->m_signingServiceUrl.length() - 1] != '/')
|
||||
// activationQuery.append(1, '/');
|
||||
//activationQuery.append("Activate.ashx?");
|
||||
|
||||
unsigned char * buf = (unsigned char *)_alloca(1 + ((m_validationData.GetSize() + 7) >> 3));
|
||||
|
||||
void * enumHandle = NULL;
|
||||
const char * name;
|
||||
BitStruct::FIELD_TYPE type;
|
||||
int size, offset;
|
||||
|
||||
while (m_keyTemplate->EnumValidationFields(&enumHandle, &name, (int*)&type, &size, &offset))
|
||||
{
|
||||
m_validationData.GetBitStream().Seek(offset);
|
||||
m_validationData.GetBitStream().Read(buf, size);
|
||||
|
||||
activationQuery.append(name);
|
||||
activationQuery.append("=");
|
||||
|
||||
if ((int)type == FIELD_TYPE_STRING)
|
||||
{
|
||||
buf[(size + 7) >> 3] = '\0';
|
||||
activationQuery.append((char *)buf);
|
||||
} else
|
||||
{
|
||||
BASE64 base64;
|
||||
|
||||
string base64Value = base64.encode(buf, (size + 7) >> 3, true);
|
||||
|
||||
replace_all(base64Value, "+", "%2B");
|
||||
replace_all(base64Value, "/", "%2F");
|
||||
replace_all(base64Value, "=", "%3D");
|
||||
|
||||
activationQuery.append(base64Value.c_str());
|
||||
}
|
||||
|
||||
activationQuery.append("&");
|
||||
}
|
||||
|
||||
if (m_keyTemplate->m_licensingServiceParameters.length() > 0)
|
||||
{
|
||||
activationQuery.append(m_keyTemplate->m_licensingServiceParameters);
|
||||
activationQuery.append("&");
|
||||
}
|
||||
|
||||
activationQuery.erase(activationQuery.length() - 1, 1);
|
||||
|
||||
m_keyBuffer.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
URL_COMPONENTS urlComponents;
|
||||
|
||||
ZeroMemory(&urlComponents, sizeof(urlComponents));
|
||||
urlComponents.dwStructSize = sizeof(urlComponents);
|
||||
|
||||
urlComponents.dwHostNameLength = (DWORD)-1;
|
||||
urlComponents.dwUrlPathLength = (DWORD)-1;
|
||||
|
||||
auto licensingServiceUrl = s2w(m_keyTemplate->m_licensingServiceUrl);
|
||||
|
||||
if (!WinHttpCrackUrl(licensingServiceUrl.c_str(), m_keyTemplate->m_licensingServiceUrl.length(), 0L, &urlComponents))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (1)"));
|
||||
|
||||
std::wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK 2.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
|
||||
|
||||
if (!internet_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (2)"));
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
|
||||
if (!connection_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (3)"));
|
||||
|
||||
activationQuery.insert(0, w2s(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength));
|
||||
|
||||
DWORD requestFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
|
||||
if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
|
||||
requestFlags |= WINHTTP_FLAG_SECURE;
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> request_ptr(WinHttpOpenRequest(connection_ptr.get(), L"GET", s2w(activationQuery).c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
|
||||
if (!request_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (4)"));
|
||||
|
||||
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0L, 0L, 0L))
|
||||
{
|
||||
DWORD result = GetLastError();
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (5)"));
|
||||
}
|
||||
|
||||
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (6)"));
|
||||
|
||||
DWORD status;
|
||||
DWORD statusSize = sizeof(DWORD);
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize, WINHTTP_NO_HEADER_INDEX))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (7)"));
|
||||
|
||||
m_signingServiceStatusCode = status;
|
||||
|
||||
if (status != HTTP_STATUS_OK && status != HTTP_STATUS_ACCEPTED && status != HTTP_STATUS_CREATED)
|
||||
{
|
||||
WCHAR buffer[1024];
|
||||
DWORD bufferSize = 1024;
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &bufferSize, WINHTTP_NO_HEADER_INDEX))
|
||||
throw new LicensingException(STATUS_NET_ERROR, "networking error (8)");
|
||||
|
||||
throw new LicensingException(STATUS_NET_ERROR, w2s(buffer).c_str());
|
||||
}
|
||||
|
||||
DWORD dataSize, count;
|
||||
char buffer[0x100];
|
||||
|
||||
do {
|
||||
if (!WinHttpQueryDataAvailable(request_ptr.get(), &dataSize))
|
||||
break;
|
||||
|
||||
if (size > 0x100)
|
||||
size = 0x100;
|
||||
|
||||
if (WinHttpReadData(request_ptr.get(), buffer, dataSize, &count))
|
||||
m_keyBuffer.append(buffer, count);
|
||||
|
||||
} while (dataSize > 0);
|
||||
#else
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
if ((curl = curl_easy_init()) == NULL)
|
||||
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
|
||||
|
||||
if (*(m_keyTemplate->m_licensingServiceUrl.rbegin()) != '/')
|
||||
activationQuery.insert(0, "/");
|
||||
|
||||
activationQuery.insert(0, m_keyTemplate->m_licensingServiceUrl);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, activationQuery.c_str());
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
#endif
|
||||
|
||||
m_key = m_keyBuffer.c_str();
|
||||
|
||||
return m_key.c_str();
|
||||
}
|
||||
#else
|
||||
if (m_keyTemplate->m_signingKey == NULL)
|
||||
{
|
||||
throw new LicensingException(STATUS_NET_ERROR, "private key not provided");
|
||||
}
|
||||
#endif
|
||||
|
||||
// signed data is license key data followed by validation data
|
||||
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
|
||||
|
||||
if (m_keyTemplate->m_dataSize)
|
||||
signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize);
|
||||
|
||||
if (m_keyTemplate->m_validationDataSize)
|
||||
signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize);
|
||||
|
||||
signedData.ZeroPadToNextByte();
|
||||
|
||||
// create a bit stream to hold the signature
|
||||
signature.Create(m_keyTemplate->m_signatureSize);
|
||||
|
||||
// sign data
|
||||
|
||||
// we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size
|
||||
if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1))
|
||||
signer.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
|
||||
else
|
||||
signer.SetHashSize(0);
|
||||
|
||||
signer.SetPrivateKey(m_keyTemplate->m_signingKey.get());
|
||||
|
||||
signer.Sign(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3,
|
||||
signature.GetBuffer(), &sigLen, &sigLenBits);
|
||||
|
||||
signature.ReleaseBuffer(sigLenBits);
|
||||
|
||||
// write the signature at the end of key data
|
||||
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
|
||||
m_keyData.GetBitStream().Write(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
|
||||
|
||||
// text-encode the license key
|
||||
EncodeKey();
|
||||
|
||||
// success
|
||||
return m_key.c_str();
|
||||
}
|
||||
|
||||
int GetSigningServiceStatusCode()
|
||||
{
|
||||
return m_signingServiceStatusCode;
|
||||
}
|
||||
|
||||
void EncodeKey()
|
||||
{
|
||||
|
||||
string buf;
|
||||
|
||||
// set all bits to 0 until the next byte boundary
|
||||
//m_rawKey.ZeroPadToNextByte();
|
||||
|
||||
// reverse last byte from the stream,
|
||||
// so that we will not lose significant bits in the padless, truncated BAS32/64 encoding
|
||||
unsigned char * lastBytePtr = (unsigned char *)m_keyData.GetBuffer() + ((m_keyData.GetSize() + 7) >> 3) - 1;
|
||||
*lastBytePtr = (unsigned char)(((*lastBytePtr * 0x0802LU & 0x22110LU) | (*lastBytePtr * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
|
||||
switch (m_keyTemplate->m_keyEncoding)
|
||||
{
|
||||
case ENCODING_BASE32X:
|
||||
{
|
||||
BASE32 base32;
|
||||
buf = base32.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODING_BASE64X:
|
||||
{
|
||||
BASE64 base64;
|
||||
buf = base64.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
|
||||
}
|
||||
|
||||
if (buf.empty())
|
||||
throw new LicensingException(STATUS_OUT_OF_MEMORY);
|
||||
|
||||
m_key = buf.c_str();
|
||||
|
||||
if ((int)m_key.length() > m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup)
|
||||
m_key.resize(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup);
|
||||
|
||||
int i;
|
||||
int insertPos;
|
||||
// separate character groups
|
||||
for (i = 0, insertPos = m_keyTemplate->m_charsPerGroup; i < m_keyTemplate->m_numGroups - 1; i++)
|
||||
{
|
||||
m_key.insert(insertPos, m_keyTemplate->m_groupSeparator);
|
||||
insertPos += (unsigned)( m_keyTemplate->m_groupSeparator.length() + m_keyTemplate->m_charsPerGroup );
|
||||
}
|
||||
|
||||
// add header and footer (if any)
|
||||
if (!m_keyTemplate->m_header.empty())
|
||||
m_key.insert(0, m_keyTemplate->m_header + "\r\n");
|
||||
|
||||
if (!m_keyTemplate->m_footer.empty())
|
||||
m_key.append("\r\n" + m_keyTemplate->m_footer);
|
||||
}
|
||||
|
||||
std::size_t replace_all(std::string& inout, std::string_view what, std::string_view with)
|
||||
{
|
||||
std::size_t count{};
|
||||
|
||||
for (std::string::size_type pos{};
|
||||
inout.npos != (pos = inout.find(what.data(), pos, what.length()));
|
||||
pos += with.length(), ++count) {
|
||||
inout.replace(pos, what.length(), with.data(), with.length());
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(oldStr, pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const LicenseTemplateImpl* m_keyTemplate;
|
||||
|
||||
string m_keyBuffer;
|
||||
string m_key;
|
||||
|
||||
BitStruct m_keyData;
|
||||
BitStruct m_validationData;
|
||||
|
||||
int m_signingServiceStatusCode;
|
||||
};
|
||||
169
core/anslicensing/helper.cpp
Normal file
169
core/anslicensing/helper.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Copyright (c) 2014 ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wmihelper.h"
|
||||
#endif
|
||||
|
||||
#include "anslicensing.h"
|
||||
#include "uniconv.h"
|
||||
#include "except.h"
|
||||
#include "hwid.h"
|
||||
#include "base64.h"
|
||||
|
||||
class KeyHelperImpl {
|
||||
|
||||
friend class KeyHelperT<char>;
|
||||
friend class KeyHelperT<wchar_t>;
|
||||
|
||||
private:
|
||||
static const char * GetCurrentHardwareId()
|
||||
{
|
||||
return HardwareId::GetCurrentHardwareId();
|
||||
}
|
||||
|
||||
static bool MatchCurrentHardwareId(const char * hwid)
|
||||
{
|
||||
return HardwareId::MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
|
||||
static bool DetectClockManipulation(int year, int month, int day)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FILETIME thresholdTime;
|
||||
SYSTEMTIME st;
|
||||
TCHAR path[MAX_PATH];
|
||||
|
||||
ZeroMemory(&st, sizeof(st));
|
||||
|
||||
st.wYear = year;
|
||||
st.wMonth = month;
|
||||
st.wDay = day;
|
||||
st.wHour = 23;
|
||||
st.wMinute = 59;
|
||||
st.wSecond = 59;
|
||||
|
||||
if (!SystemTimeToFileTime(&st, &thresholdTime))
|
||||
return false;
|
||||
|
||||
if (GetTempPath(MAX_PATH, path) > 0)
|
||||
{
|
||||
_tcsncat_s<MAX_PATH>(path, "*.*", _TRUNCATE);
|
||||
|
||||
WIN32_FIND_DATA findData;
|
||||
|
||||
HANDLE findHandle = FindFirstFile(path, &findData);
|
||||
if (findHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
while (FindNextFile(findHandle, &findData))
|
||||
{
|
||||
if (CompareFileTime(&findData.ftLastWriteTime, &thresholdTime) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
FindClose(findHandle);
|
||||
}
|
||||
}
|
||||
|
||||
WmiHelper wmi;
|
||||
list<string> propList;
|
||||
|
||||
char dmtfTime[100];
|
||||
char query[MAX_PATH];
|
||||
|
||||
_snprintf_s(query, MAX_PATH, _TRUNCATE, "SELECT EventIdentifier FROM Win32_NTLogEvent WHERE LogFile='system' AND TimeGenerated > '%04d%02d%02d000000.000000-000'", st.wYear, st.wMonth, st.wDay);
|
||||
|
||||
wmi.GetPropertyList(query, "EventIdentifier", &propList);
|
||||
|
||||
if (propList.size() > 0)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
namespace ANSCENTER
|
||||
{
|
||||
namespace Licensing
|
||||
{
|
||||
|
||||
template<>
|
||||
const char * KeyHelperT<char>::GetCurrentHardwareId()
|
||||
{
|
||||
return KeyHelperImpl::GetCurrentHardwareId();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t * KeyHelperT<wchar_t>::GetCurrentHardwareId()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(KeyHelperImpl::GetCurrentHardwareId());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyHelperT<char>::MatchCurrentHardwareId(const char * hwid)
|
||||
{
|
||||
return KeyHelperImpl::MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyHelperT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
|
||||
{
|
||||
return KeyHelperImpl::MatchCurrentHardwareId(w2s(hwid).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyHelperT<char>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
|
||||
{
|
||||
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyHelperT<wchar_t>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
|
||||
{
|
||||
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
namespace ANSCENTER
|
||||
{
|
||||
namespace Licensing
|
||||
{
|
||||
const char* ANSUtility::WString2String(const wchar_t * inputString) {
|
||||
string result = w2s(inputString);
|
||||
return result.c_str();
|
||||
|
||||
}
|
||||
const wchar_t* ANSUtility::String2WString(const char* inputString) {
|
||||
wstring result = s2w(inputString);
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
const char* ANSUtility::EncodeBase64Utility(unsigned char* buf, int len, bool padding) {
|
||||
BASE64 base64;
|
||||
string result= base64.encode(buf, len,padding);
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
const char* ANSUtility::DecodeBase64Utility(const char* input, int len, int* outlen) {
|
||||
BASE64 base64;
|
||||
vector<unsigned char> result = base64.decode(input, len, nullptr);
|
||||
string str(result.begin(), result.end());
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
562
core/anslicensing/hwid.cpp
Normal file
562
core/anslicensing/hwid.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
//
|
||||
// Copyright (c) 2014 ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "wmihelper.h"
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#ifdef __linux__
|
||||
# include <sys/ioctl.h>
|
||||
# include <netinet/in.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
|
||||
// Match Linux to FreeBSD
|
||||
# define AF_LINK AF_PACKET
|
||||
#else
|
||||
# include <net/if_dl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdio.h>
|
||||
#include <set>
|
||||
|
||||
#include "bitstream2.h"
|
||||
#include "bitstream3.h"
|
||||
#include "base32.h"
|
||||
#include "crc32.h"
|
||||
|
||||
#include "hwid.h"
|
||||
#include "except.h"
|
||||
#include "uniconv.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string HardwareId::hardwareId;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
const sockaddr_in* castToIP4(const sockaddr* addr) {
|
||||
if (addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
else if (addr->sa_family == AF_INET) {
|
||||
// An IPv4 address
|
||||
return reinterpret_cast<const sockaddr_in*>(addr);
|
||||
}
|
||||
else {
|
||||
// Not an IPv4 address
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GetCPUIDPropertyList(std::list<std::string>* propList)
|
||||
{
|
||||
unsigned int level = 1, eax = 0, ebx, ecx, edx = 0;
|
||||
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
__get_cpuid(level, &eax, &ebx, &ecx, &edx);
|
||||
#endif
|
||||
|
||||
char buf[17];
|
||||
sprintf(buf, "%08X%08X", edx, eax);
|
||||
propList->push_back(buf);
|
||||
}
|
||||
|
||||
void GetMACPropertyList(std::list<std::string>* propList, int maxCount)
|
||||
{
|
||||
// Head of the interface address linked list
|
||||
ifaddrs* ifap = NULL;
|
||||
|
||||
int r = getifaddrs(&ifap);
|
||||
|
||||
if (r != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ifaddrs* current = ifap;
|
||||
|
||||
if (current == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (current != NULL && maxCount > 0) {
|
||||
|
||||
const sockaddr_in* interfaceAddress = castToIP4(current->ifa_addr);
|
||||
const sockaddr_in* broadcastAddress = castToIP4(current->ifa_dstaddr);
|
||||
const sockaddr_in* subnetMask = castToIP4(current->ifa_netmask);
|
||||
|
||||
if ((current->ifa_addr != NULL) && (current->ifa_addr->sa_family == AF_LINK)) {
|
||||
#ifdef __linux__
|
||||
struct ifreq ifr;
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strcpy(ifr.ifr_name, current->ifa_name);
|
||||
ioctl(fd, SIOCGIFHWADDR, &ifr);
|
||||
close(fd);
|
||||
|
||||
uint8_t* MAC = reinterpret_cast<uint8_t*>(ifr.ifr_hwaddr.sa_data);
|
||||
|
||||
#else // Posix/FreeBSD/Mac OS
|
||||
|
||||
sockaddr_dl* sdl = (struct sockaddr_dl*)current->ifa_addr;
|
||||
uint8_t* MAC = reinterpret_cast<uint8_t*>(LLADDR(sdl));
|
||||
#endif
|
||||
if (MAC[0] != 0 || MAC[1] != 0 || MAC[2] != 0 || MAC[3] != 0 || MAC[4] != 0 || MAC[5] != 0)
|
||||
{
|
||||
char buf[18];
|
||||
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
|
||||
propList->push_back(buf);
|
||||
maxCount--;
|
||||
}
|
||||
}
|
||||
|
||||
current = current->ifa_next;
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
ifap = NULL;
|
||||
}
|
||||
|
||||
void GetHDDPropertyList(std::list<std::string>* propList, int maxCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned short HardwareId::HashString(const char* str)
|
||||
{
|
||||
unsigned int crc = Crc32::Compute((const unsigned char*)str, strlen(str));
|
||||
|
||||
return (unsigned short)(crc >> 16);
|
||||
}
|
||||
|
||||
unsigned short HardwareId::HashInt(int val)
|
||||
{
|
||||
unsigned char buf[4] = { (unsigned char)(val >> 24), (unsigned char)(val >> 16), (unsigned char)(val >> 8), (unsigned char)(val & 0xFF) };
|
||||
unsigned int crc = Crc32::Compute(buf, 4);
|
||||
|
||||
return (unsigned short)(crc >> 16);
|
||||
}
|
||||
|
||||
// LOCALE-INDEPENDENT trim from start (in place)
|
||||
static inline void ltrim(std::string& s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
|
||||
}));
|
||||
}
|
||||
|
||||
// LOCALE-INDEPENDENT trim from end (in place)
|
||||
static inline void rtrim(std::string& s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
|
||||
}).base(), s.end());
|
||||
}
|
||||
|
||||
// trim from both ends (in place)
|
||||
static inline void trim(std::string& s) {
|
||||
ltrim(s);
|
||||
rtrim(s);
|
||||
}
|
||||
|
||||
// LOCALE-INDEPENDENT uppercase conversion
|
||||
static inline void toUpperInvariant(std::string& s) {
|
||||
for (char& c : s) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c = c - 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize hardware string for consistent hashing
|
||||
static std::string NormalizeHardwareString(const std::string& input) {
|
||||
std::string s = input;
|
||||
|
||||
// Trim all types of whitespace
|
||||
trim(s);
|
||||
|
||||
// Remove all remaining whitespace characters
|
||||
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
|
||||
return c <= 32 || c == 0xA0; // Remove control chars and non-breaking space
|
||||
}), s.end());
|
||||
|
||||
// Locale-independent uppercase for ASCII
|
||||
toUpperInvariant(s);
|
||||
|
||||
// Remove non-ASCII characters (Korean text, etc.)
|
||||
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
|
||||
return c > 127;
|
||||
}), s.end());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const char* HardwareId::GetCurrentHardwareId()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
WmiHelper wmi;
|
||||
#endif
|
||||
|
||||
BitStream3 bits(125);
|
||||
list<string> propList;
|
||||
unsigned char version = 1;
|
||||
unsigned short hash1, hash2, hash3, hash4;
|
||||
unsigned short h0 = HashInt(0);
|
||||
|
||||
bits.Write(&version, 3);
|
||||
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
|
||||
|
||||
hash1 = h0;
|
||||
|
||||
string s;
|
||||
|
||||
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
|
||||
{
|
||||
s = NormalizeHardwareString(*iter);
|
||||
|
||||
if ((s.length() > 1)
|
||||
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
&& (s != "00000000000000000000000000000000"))
|
||||
{
|
||||
hash1 = HashString(s.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
propList.push_back("4294967296");
|
||||
#endif
|
||||
|
||||
bits.WriteUInt16(hash1);
|
||||
|
||||
// CPU IDs - get up to 4 for better resilience
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
|
||||
#else
|
||||
GetCPUIDPropertyList(&propList);
|
||||
#endif
|
||||
|
||||
// Normalize CPU IDs
|
||||
for (auto& cpu : propList) {
|
||||
cpu = NormalizeHardwareString(cpu);
|
||||
}
|
||||
|
||||
hash1 = (propList.size() > 0) ? HashString(propList.front().c_str()) : h0;
|
||||
hash2 = (propList.size() > 1) ? HashString(propList.back().c_str()) : h0;
|
||||
|
||||
bits.WriteUInt16(hash1);
|
||||
bits.WriteUInt16(hash2);
|
||||
|
||||
// MAC Addresses - get MORE adapters and sort for consistency
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
// Try physical PCI adapters first
|
||||
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 6);
|
||||
|
||||
// Fallback to VMBUS for VMs
|
||||
if (propList.size() == 0)
|
||||
{
|
||||
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 6);
|
||||
}
|
||||
#else
|
||||
GetMACPropertyList(&propList, 6);
|
||||
#endif
|
||||
|
||||
// Normalize and sort MAC addresses for consistent ordering
|
||||
for (auto& mac : propList) {
|
||||
mac = NormalizeHardwareString(mac);
|
||||
}
|
||||
propList.sort();
|
||||
|
||||
// Store up to 4 MAC hashes
|
||||
auto macIter = propList.begin();
|
||||
hash1 = (propList.size() > 0 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
|
||||
hash2 = (propList.size() > 1 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
|
||||
hash3 = (propList.size() > 2 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
|
||||
hash4 = (propList.size() > 3 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
|
||||
|
||||
bits.WriteUInt16(hash1);
|
||||
bits.WriteUInt16(hash2);
|
||||
bits.WriteUInt16(hash3);
|
||||
bits.WriteUInt16(hash4);
|
||||
|
||||
// HDD Serial Numbers - get more drives and sort
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 4);
|
||||
#else
|
||||
GetHDDPropertyList(&propList, 4);
|
||||
#endif
|
||||
|
||||
// Normalize and sort HDD serials
|
||||
for (auto& serial : propList) {
|
||||
serial = NormalizeHardwareString(serial);
|
||||
}
|
||||
propList.sort();
|
||||
|
||||
auto hddIter = propList.begin();
|
||||
hash1 = (propList.size() > 0 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
|
||||
hash2 = (propList.size() > 1 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
|
||||
|
||||
bits.WriteUInt16(hash1);
|
||||
bits.WriteUInt16(hash2);
|
||||
|
||||
unsigned char* rawHwid = bits.GetBuffer();
|
||||
|
||||
BASE32 base32;
|
||||
|
||||
auto encHwid = base32.encode(rawHwid, 16);
|
||||
|
||||
hardwareId = encHwid.c_str();
|
||||
|
||||
hardwareId.erase(hardwareId.length() - 1);
|
||||
|
||||
unsigned i;
|
||||
unsigned insertPos;
|
||||
// separate character groups
|
||||
for (i = 0, insertPos = 5; i < 4; i++)
|
||||
{
|
||||
hardwareId.insert(insertPos, "-");
|
||||
insertPos += 6;
|
||||
}
|
||||
|
||||
return hardwareId.c_str();
|
||||
}
|
||||
|
||||
bool HardwareId::MatchCurrentHardwareId(const char* hwid)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WmiHelper wmi;
|
||||
#endif
|
||||
|
||||
unsigned short h0 = HashInt(0);
|
||||
string hardwareId((char*)hwid);
|
||||
|
||||
for (int i = 0, erasePos = 0; i < 4; i++)
|
||||
{
|
||||
erasePos += 5;
|
||||
hardwareId.erase(erasePos, 1);
|
||||
}
|
||||
|
||||
BASE32 base32;
|
||||
int bufLen;
|
||||
|
||||
int padLen;
|
||||
int len = base32.encode_pad_length(((int)hardwareId.length() * 5 + 7) >> 3, &padLen);
|
||||
|
||||
if (len > (int)hardwareId.length())
|
||||
hardwareId.append(len - hardwareId.length(), 'A');
|
||||
|
||||
if (padLen)
|
||||
hardwareId.append(padLen, '=');
|
||||
|
||||
auto buf = base32.decode(hardwareId.c_str(), hardwareId.length(), &bufLen);
|
||||
|
||||
BitStream3 bits;
|
||||
bits.Attach(buf.data(), 125);
|
||||
unsigned char version = 0;
|
||||
|
||||
bits.Read(&version, 3);
|
||||
|
||||
if ((version & 0x7) > 1)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid hardware id version");
|
||||
|
||||
list<string> propList;
|
||||
set<unsigned short> storedHashes; // Store all hashes from license
|
||||
unsigned short hash1, hash2, hash3, hash4;
|
||||
|
||||
// Use a points-based matching system for resilience
|
||||
int matchPoints = 0;
|
||||
const int REQUIRED_POINTS = 2; // Need at least 2 components to match
|
||||
|
||||
// Read UUID hash
|
||||
bits.ReadUInt16(&hash1);
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
// Legacy version 0 support (memory size based)
|
||||
if (hash1 != h0)
|
||||
{
|
||||
unsigned long long memSize = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT Capacity FROM Win32_PhysicalMemory", "Capacity", &propList);
|
||||
#else
|
||||
propList.push_back("4294967296");
|
||||
#endif
|
||||
|
||||
if (propList.size() > 0)
|
||||
{
|
||||
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
|
||||
{
|
||||
memSize += _atoi64(iter->c_str());
|
||||
}
|
||||
|
||||
memSize = memSize / (1024 * 1024);
|
||||
|
||||
if (hash1 != HashInt((int)memSize))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
matchPoints += 2; // UUID/Memory match gives 2 points
|
||||
}
|
||||
else
|
||||
{
|
||||
// Version 1+ - UUID based
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
|
||||
#endif
|
||||
if (propList.size() > 0)
|
||||
{
|
||||
string s = NormalizeHardwareString(propList.front());
|
||||
|
||||
if ((s.length() > 1)
|
||||
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
&& (s != "00000000000000000000000000000000"))
|
||||
{
|
||||
if (hash1 != h0 && hash1 == HashString(s.c_str()))
|
||||
{
|
||||
matchPoints += 2; // UUID match is worth 2 points (most stable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read CPU hashes
|
||||
bits.ReadUInt16(&hash1);
|
||||
bits.ReadUInt16(&hash2);
|
||||
|
||||
storedHashes.clear();
|
||||
if (hash1 != h0) storedHashes.insert(hash1);
|
||||
if (hash2 != h0) storedHashes.insert(hash2);
|
||||
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
|
||||
#else
|
||||
GetCPUIDPropertyList(&propList);
|
||||
#endif
|
||||
|
||||
// Check if ANY current CPU matches stored hashes
|
||||
int cpuMatches = 0;
|
||||
for (auto& cpu : propList) {
|
||||
string s = NormalizeHardwareString(cpu);
|
||||
unsigned short currentHash = HashString(s.c_str());
|
||||
if (storedHashes.find(currentHash) != storedHashes.end()) {
|
||||
cpuMatches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpuMatches > 0) {
|
||||
matchPoints += 1; // CPU match is worth 1 point
|
||||
}
|
||||
|
||||
// Read MAC hashes (now 4 hashes for better resilience)
|
||||
bits.ReadUInt16(&hash1);
|
||||
bits.ReadUInt16(&hash2);
|
||||
bits.ReadUInt16(&hash3);
|
||||
bits.ReadUInt16(&hash4);
|
||||
|
||||
storedHashes.clear();
|
||||
if (hash1 != h0) storedHashes.insert(hash1);
|
||||
if (hash2 != h0) storedHashes.insert(hash2);
|
||||
if (hash3 != h0) storedHashes.insert(hash3);
|
||||
if (hash4 != h0) storedHashes.insert(hash4);
|
||||
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 10);
|
||||
|
||||
if (propList.size() == 0)
|
||||
{
|
||||
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 10);
|
||||
}
|
||||
#else
|
||||
GetMACPropertyList(&propList, 10);
|
||||
#endif
|
||||
|
||||
// Check if ANY current MAC address matches stored hashes
|
||||
int macMatches = 0;
|
||||
for (auto& mac : propList) {
|
||||
string s = NormalizeHardwareString(mac);
|
||||
unsigned short currentHash = HashString(s.c_str());
|
||||
if (storedHashes.find(currentHash) != storedHashes.end()) {
|
||||
macMatches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (macMatches > 0) {
|
||||
matchPoints += 1; // MAC match is worth 1 point
|
||||
}
|
||||
|
||||
// Read HDD hashes
|
||||
bits.ReadUInt16(&hash1);
|
||||
bits.ReadUInt16(&hash2);
|
||||
|
||||
storedHashes.clear();
|
||||
if (hash1 != h0) storedHashes.insert(hash1);
|
||||
if (hash2 != h0) storedHashes.insert(hash2);
|
||||
|
||||
propList.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 10);
|
||||
#else
|
||||
GetHDDPropertyList(&propList, 10);
|
||||
#endif
|
||||
|
||||
// Check if ANY current HDD serial matches stored hashes
|
||||
int hddMatches = 0;
|
||||
for (auto& serial : propList) {
|
||||
string s = NormalizeHardwareString(serial);
|
||||
unsigned short currentHash = HashString(s.c_str());
|
||||
if (storedHashes.find(currentHash) != storedHashes.end()) {
|
||||
hddMatches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hddMatches > 0) {
|
||||
matchPoints += 1; // HDD match is worth 1 point
|
||||
}
|
||||
|
||||
// Validation passes if we have enough matching points
|
||||
// Typical valid scenarios:
|
||||
// - UUID (2) + CPU (1) = 3 points ✓
|
||||
// - UUID (2) + MAC (1) = 3 points ✓
|
||||
// - UUID (2) + HDD (1) = 3 points ✓
|
||||
// - CPU (1) + MAC (1) + HDD (1) = 3 points ✓ (if UUID changed but hardware same)
|
||||
return matchPoints >= REQUIRED_POINTS;
|
||||
}
|
||||
16
core/anslicensing/hwid.h
Normal file
16
core/anslicensing/hwid.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __HARDWARE_ID_H
|
||||
#define __HARDWARE_ID_H
|
||||
|
||||
class HardwareId
|
||||
{
|
||||
public:
|
||||
static const char * GetCurrentHardwareId();
|
||||
static bool MatchCurrentHardwareId(const char * hwid);
|
||||
|
||||
private:
|
||||
static unsigned short HashString(const char * str);
|
||||
static unsigned short HashInt(int val);
|
||||
static string hardwareId;
|
||||
};
|
||||
|
||||
#endif
|
||||
360
core/anslicensing/license.cpp
Normal file
360
core/anslicensing/license.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include "anslicensing.h"
|
||||
#include "license.h"
|
||||
#include "uniconv.h"
|
||||
#include "except.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "picojson.h"
|
||||
#include "base64.h"
|
||||
|
||||
void LicenseImpl::LoadXml(const char * xmlTemplate)
|
||||
{
|
||||
tinyxml2::XMLDocument xml;
|
||||
tinyxml2::XMLElement * rootElement, *element;
|
||||
const char * attr;
|
||||
int version = 1;
|
||||
|
||||
if (xml.Parse(xmlTemplate) != tinyxml2::XML_NO_ERROR)
|
||||
throw new LicensingException(STATUS_INVALID_XML);
|
||||
|
||||
if ((element = rootElement = xml.FirstChildElement()) == NULL)
|
||||
throw new LicensingException(STATUS_INVALID_XML);
|
||||
|
||||
if ((attr = element->Attribute("version")) != NULL)
|
||||
version = atoi(attr);
|
||||
|
||||
if (version > 1)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
|
||||
|
||||
bool isLease = false;
|
||||
|
||||
if ((attr = element->Attribute("isLease")) != NULL)
|
||||
isLease = (_stricmp(attr, "1") == 0 || _stricmp(attr, "true") == 0);
|
||||
|
||||
m_isLease = isLease;
|
||||
|
||||
if ((element = rootElement->FirstChildElement("LicenseKey")) == NULL)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
|
||||
|
||||
m_licenseKey = element->GetText();
|
||||
|
||||
if ((element = rootElement->FirstChildElement("LicenseKeyValidationData")) != NULL)
|
||||
{
|
||||
BASE64 base64;
|
||||
|
||||
m_licenseKeyValidationData = base64.decode(element->GetText(), strlen(element->GetText()), nullptr);
|
||||
|
||||
if (!m_licenseKeyValidationData.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid BASE64 string");
|
||||
}
|
||||
|
||||
if ((element = rootElement->FirstChildElement("ActivationKey")) == NULL)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
|
||||
|
||||
m_activationKey = element->GetText();
|
||||
|
||||
if ((element = rootElement->FirstChildElement("HardwareId")) == NULL)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
|
||||
|
||||
m_hardwareId = element->GetText();
|
||||
}
|
||||
|
||||
#ifndef MAX_XML_BUFFER_SIZE
|
||||
#define MAX_XML_BUFFER_SIZE 4096
|
||||
#endif
|
||||
|
||||
const char * LicenseImpl::SaveXml()
|
||||
{
|
||||
BASE64 base64;
|
||||
char buffer[MAX_XML_BUFFER_SIZE];
|
||||
|
||||
m_xmlLicense.resize(0);
|
||||
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); m_xmlLicense.append(buffer);
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<License version=\"%d\" isLease=\"%d\">\n", m_version, (m_isLease) ? 1 : 0); m_xmlLicense.append(buffer);
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKey>%s</LicenseKey>\n", m_licenseKey.c_str()); m_xmlLicense.append(buffer);
|
||||
|
||||
if (!m_licenseKeyValidationData.empty())
|
||||
{
|
||||
BASE64 base64;
|
||||
|
||||
auto enc = base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true);
|
||||
|
||||
if (!enc.empty())
|
||||
{
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKeyValidationData>"); m_xmlLicense.append(buffer);
|
||||
m_xmlLicense.append(enc);
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</LicenseKeyValidationData>\n"); m_xmlLicense.append(buffer);
|
||||
}
|
||||
else
|
||||
throw new LicensingException(STATUS_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<ActivationKey>%s</ActivationKey>\n", m_activationKey.c_str()); m_xmlLicense.append(buffer);
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<HardwareId>%s</HardwareId>\n", m_hardwareId.c_str()); m_xmlLicense.append(buffer);
|
||||
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</License>"); m_xmlLicense.append(buffer);
|
||||
|
||||
return m_xmlLicense.c_str();
|
||||
}
|
||||
|
||||
void LicenseImpl::LoadJson(const char * jsonLicense)
|
||||
{
|
||||
picojson::value json;
|
||||
|
||||
auto err = picojson::parse(json, jsonLicense);
|
||||
|
||||
if (!err.empty())
|
||||
throw new LicensingException(STATUS_INVALID_PARAM);
|
||||
|
||||
picojson::object license = json.get<picojson::object>();
|
||||
|
||||
auto version = license["version"].get<double>();
|
||||
|
||||
if (version > 1)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
|
||||
|
||||
m_isLease = license.count("is_lease") ? license["is_lease"].get<bool>() : false;
|
||||
|
||||
m_licenseKey = license["license_key"].get<string>();
|
||||
|
||||
if (license.count("license_key_validation_data"))
|
||||
{
|
||||
BASE64 base64;
|
||||
m_licenseKeyValidationData = base64.decode(license["license_key_validation_data"].get<string>().c_str());
|
||||
}
|
||||
|
||||
m_activationKey = license["activation_key"].get<string>();
|
||||
|
||||
m_hardwareId = license["hardware_id"].get<string>();
|
||||
}
|
||||
|
||||
#ifndef MAX_JSON_BUFFER_SIZE
|
||||
#define MAX_JSON_BUFFER_SIZE 4096
|
||||
#endif
|
||||
|
||||
const char * LicenseImpl::SaveJson()
|
||||
{
|
||||
picojson::object license;
|
||||
BASE64 base64;
|
||||
|
||||
license["version"] = picojson::value((double)1);
|
||||
license["is_lease"] = picojson::value(m_isLease);
|
||||
license["license_key"] = picojson::value(m_licenseKey);
|
||||
license["hardware_id"] = picojson::value(m_hardwareId);
|
||||
license["activation_key"] = picojson::value(m_activationKey);
|
||||
|
||||
if (!m_licenseKeyValidationData.empty())
|
||||
license["license_key_validation_data"] = picojson::value(base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true));
|
||||
|
||||
m_jsonLicense = picojson::value(license).serialize(true);
|
||||
|
||||
return m_jsonLicense.c_str();
|
||||
}
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
template<>
|
||||
LicenseT<char>::LicenseT() :
|
||||
m_Impl(*new LicenseImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseT<wchar_t>::LicenseT() :
|
||||
m_Impl(*new LicenseImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseT<char>::~LicenseT()
|
||||
{
|
||||
delete& m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseT<wchar_t>::~LicenseT()
|
||||
{
|
||||
delete& m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<char>::SaveXml()
|
||||
{
|
||||
return m_Impl.SaveXml();
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<wchar_t>::SaveXml()
|
||||
{
|
||||
return m_Impl.SaveXml();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::LoadXml(const char* xml)
|
||||
{
|
||||
m_Impl.LoadXml(xml);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::LoadXml(const char* xml)
|
||||
{
|
||||
m_Impl.LoadXml(xml);
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<char>::SaveJson()
|
||||
{
|
||||
return m_Impl.SaveJson();
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<wchar_t>::SaveJson()
|
||||
{
|
||||
return m_Impl.SaveJson();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::LoadJson(const char* xml)
|
||||
{
|
||||
m_Impl.LoadJson(xml);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::LoadJson(const char* xml)
|
||||
{
|
||||
m_Impl.LoadJson(xml);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::SetLicenseKey(const char* licenseKey)
|
||||
{
|
||||
m_Impl.SetLicenseKey(licenseKey);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::SetLicenseKey(const wchar_t* licenseKey)
|
||||
{
|
||||
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::GetLicenseKeyValidationData(void** buf, int* len)
|
||||
{
|
||||
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::GetLicenseKeyValidationData(void** buf, int* len)
|
||||
{
|
||||
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<char>::GetLicenseKey()
|
||||
{
|
||||
return m_Impl.GetLicenseKey();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t* LicenseT<wchar_t>::GetLicenseKey()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetLicenseKey());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::SetActivationKey(const char* activationKey)
|
||||
{
|
||||
m_Impl.SetActivationKey(activationKey);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::SetActivationKey(const wchar_t* activationKey)
|
||||
{
|
||||
m_Impl.SetActivationKey(w2s(activationKey).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<char>::GetActivationKey()
|
||||
{
|
||||
return m_Impl.GetActivationKey();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t* LicenseT<wchar_t>::GetActivationKey()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetActivationKey());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::SetHardwareId(const char* hardwareId)
|
||||
{
|
||||
m_Impl.SetHardwareId(hardwareId);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::SetHardwareId(const wchar_t* hardwareId)
|
||||
{
|
||||
m_Impl.SetHardwareId(w2s(hardwareId).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
const char* LicenseT<char>::GetHardwareId()
|
||||
{
|
||||
return m_Impl.GetHardwareId();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t* LicenseT<wchar_t>::GetHardwareId()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetHardwareId());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<char>::SetLease(bool isLease)
|
||||
{
|
||||
m_Impl.SetLease(isLease);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseT<wchar_t>::SetLease(bool isLease)
|
||||
{
|
||||
m_Impl.SetLease(isLease);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseT<char>::IsLease()
|
||||
{
|
||||
return m_Impl.IsLease();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseT<wchar_t>::IsLease()
|
||||
{
|
||||
return m_Impl.IsLease();
|
||||
}
|
||||
};
|
||||
}
|
||||
104
core/anslicensing/license.h
Normal file
104
core/anslicensing/license.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "except.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LicenseImpl {
|
||||
|
||||
friend class LicenseValidationResultT<char>;
|
||||
friend class LicenseValidationResultT<wchar_t>;
|
||||
|
||||
public:
|
||||
LicenseImpl():
|
||||
m_isLease(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CopyFrom(const LicenseImpl * src)
|
||||
{
|
||||
m_activationKey = src->m_activationKey;
|
||||
m_hardwareId = src->m_hardwareId;
|
||||
m_isLease = src->m_isLease;
|
||||
m_licenseKey = src->m_licenseKey;
|
||||
m_xmlLicense = src->m_xmlLicense;
|
||||
SetLicenseKeyValidationData(src->m_licenseKeyValidationData.data(), src->m_licenseKeyValidationData.size());
|
||||
}
|
||||
|
||||
void LoadXml(const char * xml);
|
||||
const char * SaveXml();
|
||||
|
||||
void LoadJson(const char * json);
|
||||
const char * SaveJson();
|
||||
|
||||
const char * GetLicenseKey() const
|
||||
{
|
||||
return m_licenseKey.c_str();
|
||||
}
|
||||
|
||||
void SetLicenseKey(const char * licenseKey)
|
||||
{
|
||||
m_licenseKey = licenseKey;
|
||||
}
|
||||
|
||||
void GetLicenseKeyValidationData(const void ** buf, int * len) const
|
||||
{
|
||||
*buf = m_licenseKeyValidationData.data();
|
||||
*len = m_licenseKeyValidationData.size();
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const void* buf, int len)
|
||||
{
|
||||
if (buf && len > 0)
|
||||
{
|
||||
m_licenseKeyValidationData.resize(len);
|
||||
memcpy(m_licenseKeyValidationData.data(), buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_licenseKeyValidationData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const char * GetActivationKey() const
|
||||
{
|
||||
return m_activationKey.c_str();
|
||||
}
|
||||
|
||||
void SetActivationKey(const char * activationKey)
|
||||
{
|
||||
m_activationKey = activationKey;
|
||||
}
|
||||
|
||||
const char * GetHardwareId() const
|
||||
{
|
||||
return m_hardwareId.c_str();
|
||||
}
|
||||
|
||||
void SetHardwareId(const char * hardwareId)
|
||||
{
|
||||
m_hardwareId = hardwareId;
|
||||
}
|
||||
|
||||
bool IsLease() const
|
||||
{
|
||||
return m_isLease;
|
||||
}
|
||||
|
||||
void SetLease(bool isLease)
|
||||
{
|
||||
m_isLease = isLease;
|
||||
}
|
||||
|
||||
private:
|
||||
string m_licenseKey;
|
||||
string m_activationKey;
|
||||
string m_hardwareId;
|
||||
vector<unsigned char> m_licenseKeyValidationData;
|
||||
bool m_isLease;
|
||||
string m_xmlLicense;
|
||||
string m_jsonLicense;
|
||||
static const int m_version = 1;
|
||||
};
|
||||
108
core/anslicensing/licensevalidationargs.cpp
Normal file
108
core/anslicensing/licensevalidationargs.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "precomp.h"
|
||||
#include "anslicensing.h"
|
||||
#include "license.h"
|
||||
#include "uniconv.h"
|
||||
#include "licensevalidationargs.h"
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
|
||||
template<>
|
||||
LicenseValidationArgsT<char>::LicenseValidationArgsT():
|
||||
m_Impl(*new LicenseValidationArgsImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationArgsT<wchar_t>::LicenseValidationArgsT() :
|
||||
m_Impl(*new LicenseValidationArgsImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationArgsT<char>::~LicenseValidationArgsT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationArgsT<wchar_t>::~LicenseValidationArgsT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicenseKey(const char * licenseKey)
|
||||
{
|
||||
m_Impl.SetLicenseKey(licenseKey);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicenseKey(const wchar_t * licenseKey)
|
||||
{
|
||||
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicense(const LicenseT<char> * license)
|
||||
{
|
||||
m_Impl.SetLicense(&license->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicense(const LicenseT<wchar_t> * license)
|
||||
{
|
||||
m_Impl.SetLicense(&license->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int fieldValue)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), fieldValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, const wchar_t * fieldValue)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), w2s(fieldValue).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(fieldName, data, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, void * data, int len)
|
||||
{
|
||||
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), data, len);
|
||||
}
|
||||
};
|
||||
};
|
||||
109
core/anslicensing/licensevalidationargs.h
Normal file
109
core/anslicensing/licensevalidationargs.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
#include "license.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct NameValuePair {
|
||||
public:
|
||||
NameValuePair(const char* _name, const char* _value):
|
||||
name(_name),
|
||||
stringValue(_value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NameValuePair(const char* _name, int _value):
|
||||
name(_name),
|
||||
intValue(_value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NameValuePair(const char* _name, int _year, int _month, int _day):
|
||||
name(_name),
|
||||
dateValue { _year, _month, _day }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NameValuePair(const char* _name, const unsigned char* _value, int _len):
|
||||
name(_name),
|
||||
binaryValue(_value, _value + _len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string name;
|
||||
|
||||
int intValue;
|
||||
|
||||
string stringValue;
|
||||
|
||||
struct {
|
||||
int year, month, day;
|
||||
} dateValue;
|
||||
|
||||
vector<unsigned char> binaryValue;
|
||||
};
|
||||
|
||||
class LicenseValidationArgsImpl
|
||||
{
|
||||
friend LicensingClient;
|
||||
|
||||
public:
|
||||
LicenseValidationArgsImpl():
|
||||
m_license(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetLicense(LicenseImpl * license)
|
||||
{
|
||||
m_license = license;
|
||||
}
|
||||
|
||||
const LicenseImpl * GetLicense()
|
||||
{
|
||||
return m_license;
|
||||
}
|
||||
|
||||
void SetLicenseKey(const char * licenseKey, int validationDataSize = 0)
|
||||
{
|
||||
m_licenseKey = licenseKey;
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
|
||||
{
|
||||
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
|
||||
{
|
||||
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_licenseKeyValidationData.emplace_back(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
|
||||
{
|
||||
m_licenseKeyValidationData.emplace_back(fieldName, (unsigned char*)data, len);
|
||||
}
|
||||
|
||||
const char * GetLicenseKey()
|
||||
{
|
||||
return m_licenseKey.c_str();
|
||||
}
|
||||
|
||||
public:
|
||||
const LicenseImpl* m_license;
|
||||
int m_validationDataSize;
|
||||
string m_licenseKey;
|
||||
list<NameValuePair> m_licenseKeyValidationData;
|
||||
};
|
||||
111
core/anslicensing/licensevalidationresult.cpp
Normal file
111
core/anslicensing/licensevalidationresult.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "precomp.h"
|
||||
#include "anslicensing.h"
|
||||
#include "uniconv.h"
|
||||
#include "licensevalidationresult.h"
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<char>::LicenseValidationResultT() :
|
||||
m_Impl(*new LicenseValidationResultImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<wchar_t>::LicenseValidationResultT() :
|
||||
m_Impl(*new LicenseValidationResultImpl())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<char>::~LicenseValidationResultT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<wchar_t>::~LicenseValidationResultT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseT<char> * LicenseValidationResultT<char>::GetLicense()
|
||||
{
|
||||
static LicenseT<char> result;
|
||||
|
||||
LicenseImpl * resultImpl = m_Impl.GetLicense();
|
||||
|
||||
if (!resultImpl) return NULL;
|
||||
|
||||
result.m_Impl.CopyFrom(resultImpl);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseT<wchar_t> * LicenseValidationResultT<wchar_t>::GetLicense()
|
||||
{
|
||||
static LicenseT<wchar_t> result;
|
||||
|
||||
LicenseImpl * resultImpl = m_Impl.GetLicense();
|
||||
|
||||
if (!resultImpl) return NULL;
|
||||
|
||||
result.m_Impl.CopyFrom(resultImpl);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseValidationResultT<char>::IsLicenseExpired()
|
||||
{
|
||||
return m_Impl.IsLicenseExpired();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseValidationResultT<wchar_t>::IsLicenseExpired()
|
||||
{
|
||||
return m_Impl.IsLicenseExpired();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseValidationResultT<char>::IsPaymentRequired()
|
||||
{
|
||||
return m_Impl.IsPaymentRequired();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicenseValidationResultT<wchar_t>::IsPaymentRequired()
|
||||
{
|
||||
return m_Impl.IsPaymentRequired();
|
||||
}
|
||||
|
||||
template<>
|
||||
int LicenseValidationResultT<char>::GetLicenseValidityDays()
|
||||
{
|
||||
return m_Impl.GetLicenseValidityDays();
|
||||
}
|
||||
|
||||
template<>
|
||||
int LicenseValidationResultT<wchar_t>::GetLicenseValidityDays()
|
||||
{
|
||||
return m_Impl.GetLicenseValidityDays();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationResultT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.GetLicenseExpirationDate(year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicenseValidationResultT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.GetLicenseExpirationDate(year, month, day);
|
||||
}
|
||||
};
|
||||
};
|
||||
118
core/anslicensing/licensevalidationresult.h
Normal file
118
core/anslicensing/licensevalidationresult.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef __LICENSEVALIDATIONRESULT_H
|
||||
#define __LICENSEVALIDATIONRESULT_H
|
||||
|
||||
#include <memory>
|
||||
#include "license.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LicensingClientImpl;
|
||||
|
||||
class LicenseValidationResultImpl
|
||||
{
|
||||
//friend class LicensingClientT<char>;
|
||||
//friend class LicensingClientT<wchar_t>;
|
||||
friend class LicensingClientImpl;
|
||||
friend class LicenseValidationResultT<char>;
|
||||
friend class LicenseValidationResultT<wchar_t>;
|
||||
|
||||
public:
|
||||
LicenseValidationResultImpl()
|
||||
{
|
||||
m_isLicenseExpired = false;
|
||||
m_isPaymentRequired = false;
|
||||
m_licenseValidityDays = 0;
|
||||
m_licenseExpirationYear = m_licenseExpirationMonth = m_licenseExpirationDay = 0;
|
||||
}
|
||||
|
||||
~LicenseValidationResultImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MoveFrom(LicenseValidationResultImpl& src)
|
||||
{
|
||||
m_isLicenseExpired = src.m_isLicenseExpired;
|
||||
m_isLicenseValid = src.m_isLicenseValid;
|
||||
m_isPaymentRequired = src.m_isPaymentRequired;
|
||||
m_license = std::move(src.m_license);
|
||||
m_licenseValidityDays = src.m_licenseValidityDays;
|
||||
m_licenseExpirationDay = src.m_licenseExpirationDay;
|
||||
m_licenseExpirationMonth = src.m_licenseExpirationMonth;
|
||||
m_licenseExpirationYear = src.m_licenseExpirationYear;
|
||||
}
|
||||
|
||||
LicenseImpl * GetLicense()
|
||||
{
|
||||
return m_license.get();
|
||||
}
|
||||
|
||||
void SetLicense(LicenseImpl * lic)
|
||||
{
|
||||
m_license.reset(lic);
|
||||
}
|
||||
|
||||
bool IsLicenseValid()
|
||||
{
|
||||
return m_isLicenseValid;
|
||||
}
|
||||
|
||||
void SetLicenseValid(bool isValid)
|
||||
{
|
||||
m_isLicenseValid = isValid;
|
||||
}
|
||||
|
||||
bool IsLicenseExpired()
|
||||
{
|
||||
return m_isLicenseExpired;
|
||||
}
|
||||
|
||||
void SetLicenseExpired(bool licenseExpired)
|
||||
{
|
||||
m_isLicenseExpired = licenseExpired;
|
||||
}
|
||||
|
||||
bool IsPaymentRequired()
|
||||
{
|
||||
return m_isPaymentRequired;
|
||||
}
|
||||
|
||||
void SetPaymentRequired(bool paymentRequired)
|
||||
{
|
||||
m_isPaymentRequired = paymentRequired;
|
||||
}
|
||||
|
||||
int GetLicenseValidityDays()
|
||||
{
|
||||
return m_licenseValidityDays;
|
||||
}
|
||||
|
||||
void SetLicenseValidityDays(int days)
|
||||
{
|
||||
m_licenseValidityDays = days;
|
||||
}
|
||||
|
||||
void GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
*year = m_licenseExpirationYear;
|
||||
*month = m_licenseExpirationMonth;
|
||||
*day = m_licenseExpirationDay;
|
||||
}
|
||||
|
||||
void SetLicenseExpirationDate(int year, int month, int day)
|
||||
{
|
||||
m_licenseExpirationYear = year;
|
||||
m_licenseExpirationMonth = month;
|
||||
m_licenseExpirationDay = day;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isLicenseValid;
|
||||
bool m_isLicenseExpired;
|
||||
bool m_isPaymentRequired;
|
||||
int m_licenseValidityDays;
|
||||
int m_licenseExpirationYear, m_licenseExpirationMonth, m_licenseExpirationDay;
|
||||
unique_ptr<LicenseImpl> m_license;
|
||||
};
|
||||
|
||||
#endif
|
||||
289
core/anslicensing/licensingclient.cpp
Normal file
289
core/anslicensing/licensingclient.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "licensingclient.h"
|
||||
#include "licensevalidationargs.h"
|
||||
#include "licensevalidationresult.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
|
||||
template<>
|
||||
LicensingClientT<wchar_t>::LicensingClientT():
|
||||
m_Impl(*(new LicensingClientImpl(this, true)))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicensingClientT<char>::LicensingClientT():
|
||||
m_Impl(*(new LicensingClientImpl(this, false)))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
LicensingClientT<char>::~LicensingClientT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicensingClientT<wchar_t>::~LicensingClientT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetLicenseTemplate(LicenseTemplateT<char> * tmpl)
|
||||
{
|
||||
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetLicenseTemplate(LicenseTemplateT<wchar_t> * tmpl)
|
||||
{
|
||||
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetLicenseKey(const char * key)
|
||||
{
|
||||
m_Impl.SetLicenseKey(key);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetLicenseKey(const wchar_t * key)
|
||||
{
|
||||
m_Impl.SetLicenseKey(w2s(key).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetActivationKey(const char * key)
|
||||
{
|
||||
m_Impl.SetActivationKey(key);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetActivationKey(const wchar_t * key)
|
||||
{
|
||||
m_Impl.SetActivationKey(w2s(key).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
const char * LicensingClientT<char>::GetActivationKey()
|
||||
{
|
||||
return m_Impl.GetActivationKey();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t * LicensingClientT<wchar_t>::GetActivationKey()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetActivationKey());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetHardwareId(const char * hwid)
|
||||
{
|
||||
m_Impl.SetHardwareId(hwid);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetHardwareId(const wchar_t * hwid)
|
||||
{
|
||||
m_Impl.SetHardwareId(w2s(hwid).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
const char * LicensingClientT<char>::GetHardwareId()
|
||||
{
|
||||
return m_Impl.GetHardwareId();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t * LicensingClientT<wchar_t>::GetHardwareId()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetHardwareId());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
const wchar_t * LicensingClientT<wchar_t>::GetCurrentHardwareId()
|
||||
{
|
||||
static wstring wstr1;
|
||||
|
||||
wstr1 = s2w(m_Impl.GetCurrentHardwareId());
|
||||
return wstr1.c_str();
|
||||
}
|
||||
|
||||
template<>
|
||||
const char * LicensingClientT<char>::GetCurrentHardwareId()
|
||||
{
|
||||
return m_Impl.GetCurrentHardwareId();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicensingClientT<char>::MatchCurrentHardwareId(const char * hwid)
|
||||
{
|
||||
return m_Impl.MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicensingClientT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
|
||||
{
|
||||
return m_Impl.MatchCurrentHardwareId(w2s(hwid).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetLicensingServiceUrl(const char * url)
|
||||
{
|
||||
|
||||
m_Impl.SetLicensingServiceUrl(url);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetLicensingServiceUrl(const wchar_t * url)
|
||||
{
|
||||
m_Impl.SetLicensingServiceUrl(w2s(url).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetLicenseTemplateId(const char * templateId)
|
||||
{
|
||||
m_Impl.SetLicenseTemplateId(templateId);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetLicenseTemplateId(const wchar_t * templateId)
|
||||
{
|
||||
m_Impl.SetLicenseTemplateId(w2s(templateId).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::AcquireLicense()
|
||||
{
|
||||
m_Impl.AcquireLicense();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::AcquireLicense()
|
||||
{
|
||||
m_Impl.AcquireLicense();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicensingClientT<char>::IsLicenseValid()
|
||||
{
|
||||
return m_Impl.IsLicenseValid();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool LicensingClientT<wchar_t>::IsLicenseValid()
|
||||
{
|
||||
return m_Impl.IsLicenseValid();
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<char> * LicensingClientT<char>::ValidateLicense(LicenseValidationArgsT<char> * args)
|
||||
{
|
||||
static LicenseValidationResultT<char> result;
|
||||
|
||||
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
|
||||
|
||||
result.m_Impl.MoveFrom(resultImpl);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LicenseValidationResultT<wchar_t> * LicensingClientT<wchar_t>::ValidateLicense(LicenseValidationArgsT<wchar_t> * args)
|
||||
{
|
||||
static LicenseValidationResultT<wchar_t> result;
|
||||
|
||||
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
|
||||
|
||||
result.m_Impl.MoveFrom(resultImpl);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetLicenseKeyValidationData(void * data, int len)
|
||||
{
|
||||
return m_Impl.SetLicenseKeyValidationData(data, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetLicenseKeyValidationData(void * data, int len)
|
||||
{
|
||||
return m_Impl.SetLicenseKeyValidationData(data, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
int LicensingClientT<char>::GetLicenseActivationStatus()
|
||||
{
|
||||
return m_Impl.GetLicenseActivationStatus();
|
||||
}
|
||||
|
||||
template<>
|
||||
int LicensingClientT<wchar_t>::GetLicenseActivationStatus()
|
||||
{
|
||||
return m_Impl.GetLicenseActivationStatus();
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.GetLicenseExpirationDate(year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.GetLicenseExpirationDate(year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<char>::SetTimeValidationMethod(int method)
|
||||
{
|
||||
return m_Impl.SetTimeValidationMethod(method);
|
||||
}
|
||||
|
||||
template<>
|
||||
void LicensingClientT<wchar_t>::SetTimeValidationMethod(int method)
|
||||
{
|
||||
return m_Impl.SetTimeValidationMethod(method);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const wchar_t * GetCurrentHardwareIdW(void * licensingClient)
|
||||
{
|
||||
|
||||
static std::wstring result = ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->GetCurrentHardwareId();
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
const char * GetCurrentHardwareIdA(void * licensingClient)
|
||||
{
|
||||
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->GetCurrentHardwareId();
|
||||
}
|
||||
|
||||
bool MatchCurrentHardwareIdW(void * licensingClient, const wchar_t * hwid)
|
||||
{
|
||||
|
||||
return ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
|
||||
bool MatchCurrentHardwareIdA(void * licensingClient, const char * hwid)
|
||||
{
|
||||
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
602
core/anslicensing/licensingclient.h
Normal file
602
core/anslicensing/licensingclient.h
Normal file
@@ -0,0 +1,602 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "except.h"
|
||||
#include "template.h"
|
||||
#include "generator.h"
|
||||
#include "validator.h"
|
||||
#include "ntpclient.h"
|
||||
#include "uniconv.h"
|
||||
#include "license.h"
|
||||
#include "licensevalidationargs.h"
|
||||
#include "licensevalidationresult.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winhttp.h>
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
// these methods are compiler workarounds to eliminate circular references.
|
||||
// They only call the corresponding LicensingClient::... methods
|
||||
// GCC complains of cross-references between LicensingClientImpl and LicensingClientT
|
||||
|
||||
const wchar_t * GetCurrentHardwareIdW(void *);
|
||||
const char * GetCurrentHardwareIdA(void *);
|
||||
bool MatchCurrentHardwareIdW(void *, const wchar_t *);
|
||||
bool MatchCurrentHardwareIdA(void *, const char *);
|
||||
|
||||
class LicensingClientImpl
|
||||
{
|
||||
public:
|
||||
LicensingClientImpl(void * licensingClient, bool usesWideChar)
|
||||
{
|
||||
licenseKeyValidationDataLen = 0;
|
||||
licenseTemplateId.clear();
|
||||
parentLicensingClient = licensingClient;
|
||||
parentUsesWideChar = usesWideChar;
|
||||
timeValidationMethod = PREFER_INTERNET_TIME;
|
||||
m_licenseValidityDays = 0;
|
||||
// GetCurrentHardwareIdCallback = GetCurrentHardwareId;
|
||||
// MatchCurrentHardwareIdCallback = MatchCurrentHardwareId;
|
||||
}
|
||||
|
||||
void SetLicenseTemplate(const LicenseTemplateImpl* tmpl)
|
||||
{
|
||||
licenseTemplate = tmpl;
|
||||
}
|
||||
|
||||
void SetLicenseKey(const char * key)
|
||||
{
|
||||
licenseKey = key;
|
||||
}
|
||||
|
||||
void SetActivationKey(const char * key)
|
||||
{
|
||||
activationKey = key;
|
||||
}
|
||||
|
||||
const char * GetActivationKey()
|
||||
{
|
||||
return activationKey.c_str();
|
||||
}
|
||||
|
||||
void SetHardwareId(const char * hwid)
|
||||
{
|
||||
hardwareId = hwid;
|
||||
}
|
||||
|
||||
const char * GetHardwareId()
|
||||
{
|
||||
return hardwareId.c_str();
|
||||
}
|
||||
|
||||
void SetLicenseTemplateId(const char * templateId)
|
||||
{
|
||||
licenseTemplateId = templateId;
|
||||
}
|
||||
|
||||
const char * GetLicenseTemplateId()
|
||||
{
|
||||
return licenseTemplateId.c_str();
|
||||
}
|
||||
|
||||
void SetLicenseKeyValidationData(const void* data, unsigned len)
|
||||
{
|
||||
licenseKeyValidationData.resize(len);
|
||||
|
||||
memcpy(licenseKeyValidationData.data(), data, len);
|
||||
|
||||
licenseKeyValidationDataLen = len;
|
||||
}
|
||||
|
||||
LicenseTemplateImpl * CreateActivationTemplate()
|
||||
{
|
||||
LicenseTemplateImpl * tmpl = new LicenseTemplateImpl();
|
||||
|
||||
tmpl->SetCharactersPerGroup(licenseTemplate->GetCharactersPerGroup());
|
||||
tmpl->SetNumberOfGroups(licenseTemplate->GetNumberOfGroups());
|
||||
tmpl->SetGroupSeparator(licenseTemplate->GetGroupSeparator());
|
||||
//activationKeyTemplate.SetDataSize(t.GetDataSize());
|
||||
tmpl->SetSignatureSize(licenseTemplate->GetSignatureSize());
|
||||
tmpl->SetEncoding(licenseTemplate->GetEncoding());
|
||||
tmpl->SetPublicKeyCertificate(licenseTemplate->GetPublicKeyCertificate());
|
||||
|
||||
int keyLen = tmpl->GetNumberOfGroups() * tmpl->GetCharactersPerGroup()
|
||||
+ (tmpl->GetNumberOfGroups() - 1) * strlen(tmpl->GetGroupSeparator());
|
||||
|
||||
int hwidLen = 29;
|
||||
|
||||
if (hardwareId.length() > 0)
|
||||
hwidLen = hardwareId.length();
|
||||
|
||||
tmpl->SetDataSize(tmpl->GetCharactersPerGroup() * tmpl->GetNumberOfGroups() * tmpl->GetEncoding() - tmpl->GetSignatureSize());
|
||||
tmpl->SetValidationDataSize((keyLen + hwidLen ) * 8 + licenseTemplate->GetValidationDataSize());
|
||||
|
||||
tmpl->AddDataField("ExpirationDate", FIELD_TYPE_RAW, 16, 0);
|
||||
tmpl->AddValidationField("LicenseKey", FIELD_TYPE_STRING, keyLen * 8, 0);
|
||||
tmpl->AddValidationField("HardwareId", FIELD_TYPE_STRING, hwidLen * 8, keyLen * 8);
|
||||
|
||||
if (!licenseKeyValidationData.empty())
|
||||
{
|
||||
tmpl->AddValidationField("LicenseKeyValidationData", FIELD_TYPE_RAW, licenseKeyValidationDataLen * 8, (keyLen + hwidLen) * 8);
|
||||
}
|
||||
|
||||
if (licensingServiceUrl.empty())
|
||||
tmpl->SetLicensingServiceUrl(licenseTemplate->GetLicensingServiceUrl());
|
||||
else
|
||||
tmpl->SetLicensingServiceUrl(licensingServiceUrl.c_str());
|
||||
|
||||
if (licenseTemplateId.empty())
|
||||
tmpl->SetTemplateId(licenseTemplate->GetTemplateId());
|
||||
else
|
||||
tmpl->SetTemplateId(licenseTemplateId.c_str());
|
||||
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
bool ValidateHardwareId()
|
||||
{
|
||||
if (!MatchCurrentHardwareIdCallback(hardwareId.c_str()))
|
||||
{
|
||||
activationStatus = STATUS_INVALID_HARDWARE_ID;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateActivationKey(LicenseTemplateImpl* activationTemplate = nullptr, bool validateExpirationDate = true)
|
||||
{
|
||||
bool ownActivationTemplate = false;
|
||||
|
||||
try {
|
||||
if (!activationTemplate)
|
||||
{
|
||||
activationTemplate = CreateActivationTemplate();
|
||||
ownActivationTemplate = true;
|
||||
}
|
||||
|
||||
KeyValidatorImpl validator(activationTemplate);
|
||||
|
||||
validator.SetValidationData("LicenseKey", licenseKey.c_str());
|
||||
validator.SetValidationData("HardwareId", hardwareId.c_str());
|
||||
|
||||
if (!licenseKeyValidationData.empty())
|
||||
validator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), (activationTemplate->GetValidationDataSize() + 7) >> 3);
|
||||
|
||||
try
|
||||
{
|
||||
validator.SetKey(activationKey.c_str());
|
||||
}
|
||||
catch (Exception * ex)
|
||||
{
|
||||
ex->Destroy();
|
||||
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validator.IsKeyValid())
|
||||
{
|
||||
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char rawKeyData[2];
|
||||
int rawKeyDataBits = 16;
|
||||
|
||||
validator.QueryKeyData("ExpirationDate", rawKeyData, &rawKeyDataBits);
|
||||
|
||||
unsigned short keyData = (unsigned short)(((unsigned short)rawKeyData[0]) << 8 | rawKeyData[1]);
|
||||
|
||||
memset(&licenseExpirationTime, 0, sizeof(licenseExpirationTime));
|
||||
|
||||
if (keyData != 0)
|
||||
{
|
||||
licenseExpirationTime.tm_year = (2000 + (keyData >> 9)) - 1900;
|
||||
licenseExpirationTime.tm_mon = ((keyData & 0x01FF) >> 5) - 1;
|
||||
licenseExpirationTime.tm_mday = keyData & 0x001F;
|
||||
|
||||
if (!validateExpirationDate)
|
||||
{
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t currentTime;
|
||||
|
||||
if (timeValidationMethod != USE_LOCAL_TIME)
|
||||
{
|
||||
currentTime = NTPClient::GetCurrentTimeUTC();
|
||||
|
||||
if (currentTime == 0) // if couldn't obtain internet time
|
||||
{
|
||||
if (timeValidationMethod == USE_INTERNET_TIME) // internet time was mandatory
|
||||
{
|
||||
activationStatus = STATUS_NET_ERROR;
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
return false;
|
||||
}
|
||||
|
||||
// fallback to local time
|
||||
currentTime = time(NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
currentTime = time(NULL);
|
||||
|
||||
double diffSeconds = difftime(mktime(&licenseExpirationTime), currentTime);
|
||||
|
||||
if (diffSeconds < 0)
|
||||
{
|
||||
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() - (int)(((time_t)(-diffSeconds) + 86400 - 1) / 86400);
|
||||
|
||||
if (m_licenseValidityDays < 0)
|
||||
m_licenseValidityDays = 0;
|
||||
|
||||
activationStatus = STATUS_LICENSE_EXPIRED;
|
||||
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
|
||||
return false;
|
||||
} else
|
||||
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() + (int)(((time_t)diffSeconds + 86400 - 1) / 86400);
|
||||
}
|
||||
else
|
||||
m_licenseValidityDays = -1;
|
||||
|
||||
if (ownActivationTemplate) delete activationTemplate;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (ownActivationTemplate && activationTemplate)
|
||||
delete activationTemplate;
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLicenseValid()
|
||||
{
|
||||
activationStatus = STATUS_GENERIC_ERROR;
|
||||
|
||||
try
|
||||
{
|
||||
if (ValidateHardwareId() && ValidateActivationKey())
|
||||
{
|
||||
activationStatus = STATUS_SUCCESS;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
catch (Exception * ex)
|
||||
{
|
||||
ex->Destroy();
|
||||
|
||||
activationStatus = STATUS_GENERIC_ERROR;
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
activationStatus = STATUS_GENERIC_ERROR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LicenseValidationResultImpl& ValidateLicense(LicenseValidationArgsImpl * args)
|
||||
{
|
||||
const LicenseImpl * license = args->GetLicense();
|
||||
const char * lk = args->GetLicenseKey();
|
||||
|
||||
licenseKey = (lk) ? lk : "";
|
||||
|
||||
if (license == NULL && licenseKey.length() == 0)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "either a license or a license key must be provided");
|
||||
|
||||
if (license == NULL)
|
||||
{
|
||||
try {
|
||||
KeyValidatorImpl keyValidator;
|
||||
|
||||
keyValidator.SetKeyTemplate(licenseTemplate);
|
||||
|
||||
keyValidator.SetKey(lk);
|
||||
|
||||
if (licenseTemplate->GetValidationDataSize() > 0)
|
||||
{
|
||||
int fieldType, fieldSize, fieldOffset;
|
||||
|
||||
for (std::list<NameValuePair>::iterator iter = args->m_licenseKeyValidationData.begin(); iter != args->m_licenseKeyValidationData.end(); iter++)
|
||||
{
|
||||
if (!licenseTemplate->GetValidationField(iter->name.c_str(), &fieldType, &fieldSize, &fieldOffset))
|
||||
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key validation data is invalid");
|
||||
|
||||
switch (fieldType)
|
||||
{
|
||||
case FIELD_TYPE_INTEGER:
|
||||
keyValidator.SetValidationData(iter->name.c_str(), iter->intValue);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_STRING:
|
||||
keyValidator.SetValidationData(iter->name.c_str(), iter->stringValue.c_str());
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_DATE13:
|
||||
case FIELD_TYPE_DATE14:
|
||||
case FIELD_TYPE_DATE16:
|
||||
keyValidator.SetValidationData(iter->name.c_str(), iter->dateValue.year, iter->dateValue.month, iter->dateValue.day);
|
||||
break;
|
||||
|
||||
case FIELD_TYPE_RAW:
|
||||
// keyValidator.SetValidationData(iter->name.c_str(), &(iter->value.binaryValue[0]), iter->value.binaryValue.size);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
licenseKeyValidationDataLen = (licenseTemplate->GetValidationDataSize() + 7) >> 3;
|
||||
|
||||
licenseKeyValidationData.resize(licenseKeyValidationDataLen);
|
||||
|
||||
keyValidator.QueryValidationData(NULL, licenseKeyValidationData.data(), &licenseKeyValidationDataLen);
|
||||
}
|
||||
|
||||
if (!keyValidator.IsKeyValid())
|
||||
{
|
||||
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key is not valid");
|
||||
}
|
||||
|
||||
AcquireLicense();
|
||||
}
|
||||
catch (LicensingException * ex)
|
||||
{
|
||||
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
|
||||
{
|
||||
m_licenseValidationResult.SetPaymentRequired(true);
|
||||
ex->Destroy();
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
licenseKey = license->GetLicenseKey();
|
||||
hardwareId = license->GetHardwareId();
|
||||
activationKey = license->GetActivationKey();
|
||||
|
||||
const void* buf; int len;
|
||||
license->GetLicenseKeyValidationData(&buf, &len);
|
||||
|
||||
if (buf && (len > 0))
|
||||
SetLicenseKeyValidationData(buf, (unsigned int)len);
|
||||
|
||||
if (ValidateActivationKey(NULL, true))
|
||||
{
|
||||
m_licenseValidationResult.SetLicenseValid(true);
|
||||
m_licenseValidationResult.SetPaymentRequired(false);
|
||||
m_licenseValidationResult.SetLicenseExpired(false);
|
||||
m_licenseValidationResult.SetLicense(NULL);
|
||||
return m_licenseValidationResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (activationStatus == STATUS_LICENSE_EXPIRED)
|
||||
{
|
||||
m_licenseValidationResult.SetLicenseExpired(true);
|
||||
}
|
||||
|
||||
if ((activationStatus == STATUS_LICENSE_EXPIRED) && (m_licenseValidityDays > 0) && license->IsLease())
|
||||
{
|
||||
try
|
||||
{
|
||||
AcquireLicense();
|
||||
m_licenseValidationResult.SetLicenseExpired(false);
|
||||
}
|
||||
catch (LicensingException * ex)
|
||||
{
|
||||
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
|
||||
{
|
||||
m_licenseValidationResult.SetPaymentRequired(true);
|
||||
ex->Destroy();
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (licenseExpirationTime.tm_year > 0)
|
||||
{
|
||||
m_licenseValidationResult.SetLicenseExpirationDate(
|
||||
1900 + licenseExpirationTime.tm_year,
|
||||
1 + licenseExpirationTime.tm_mon,
|
||||
licenseExpirationTime.tm_mday);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_licenseValidationResult.SetLicenseExpirationDate(0, 0, 0);
|
||||
}
|
||||
|
||||
return m_licenseValidationResult;
|
||||
}
|
||||
|
||||
void AcquireLicense()
|
||||
{
|
||||
if (hardwareId.empty())
|
||||
hardwareId = (parentLicensingClient) ? GetCurrentHardwareIdCallback() : GetCurrentHardwareId();
|
||||
|
||||
unique_ptr<LicenseTemplateImpl> activationTemplate(CreateActivationTemplate());
|
||||
|
||||
const char * templateId = activationTemplate->GetTemplateId();
|
||||
|
||||
if (templateId != NULL && templateId[0] != '\0')
|
||||
{
|
||||
char params[64] = "ProductId=";
|
||||
sprintf(params + sizeof("ProductId"), "%s", activationTemplate->GetTemplateId());
|
||||
activationTemplate->SetLicensingServiceParameters(params);
|
||||
}
|
||||
|
||||
KeyGeneratorImpl generator(activationTemplate.get());
|
||||
|
||||
generator.SetKeyData("ExpirationDate", (int)0);
|
||||
|
||||
generator.SetValidationData("LicenseKey", licenseKey.c_str());
|
||||
|
||||
generator.SetValidationData("HardwareId", hardwareId.c_str());
|
||||
|
||||
if (!licenseKeyValidationData.empty())
|
||||
{
|
||||
generator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), licenseKeyValidationDataLen * 8);
|
||||
}
|
||||
|
||||
try {
|
||||
activationKey = generator.GenerateKey();
|
||||
}
|
||||
catch (LicensingException * ex)
|
||||
{
|
||||
if ((ex->GetCode() == STATUS_NET_ERROR) && (generator.GetSigningServiceStatusCode() == 406))
|
||||
{
|
||||
m_licenseValidationResult.SetPaymentRequired(true);
|
||||
ex->Destroy();
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
|
||||
if (ValidateActivationKey(activationTemplate.get(), false))
|
||||
{
|
||||
activationStatus = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "internal error - invalid returned activation key");
|
||||
|
||||
m_licenseValidationResult.m_license = std::make_unique<LicenseImpl>();
|
||||
|
||||
m_licenseValidationResult.m_license->SetHardwareId(hardwareId.c_str());
|
||||
m_licenseValidationResult.m_license->SetActivationKey(activationKey.c_str());
|
||||
m_licenseValidationResult.m_license->SetLicenseKey(licenseKey.c_str());
|
||||
m_licenseValidationResult.m_license->SetLicenseKeyValidationData(licenseKeyValidationData.data(), licenseKeyValidationDataLen);
|
||||
|
||||
int status = generator.GetSigningServiceStatusCode();
|
||||
|
||||
if (status == 200 /* HTTP OK */)
|
||||
m_licenseValidationResult.m_license->SetLease(false);
|
||||
else
|
||||
if (status == 201 || status == 202)
|
||||
m_licenseValidationResult.m_license->SetLease(true);
|
||||
|
||||
m_licenseValidationResult.SetLicenseValid(true);
|
||||
}
|
||||
|
||||
void SetLicensingServiceUrl(const char * url)
|
||||
{
|
||||
licensingServiceUrl = url;
|
||||
}
|
||||
|
||||
int GetLicenseActivationStatus()
|
||||
{
|
||||
return activationStatus;
|
||||
}
|
||||
|
||||
void GetLicenseExpirationDate(int * year, int * month, int * day)
|
||||
{
|
||||
if (licenseExpirationTime.tm_year > 0)
|
||||
{
|
||||
*year = 1900 + licenseExpirationTime.tm_year;
|
||||
*month = 1 + licenseExpirationTime.tm_mon;
|
||||
*day = licenseExpirationTime.tm_mday;
|
||||
} else
|
||||
{
|
||||
*year = 0;
|
||||
*month = 0;
|
||||
*day = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char * GetCurrentHardwareIdCallback()
|
||||
{
|
||||
if (parentUsesWideChar)
|
||||
{
|
||||
static string hwid = w2s(GetCurrentHardwareIdW(parentLicensingClient));
|
||||
return hwid.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCurrentHardwareIdA(parentLicensingClient);
|
||||
}
|
||||
}
|
||||
|
||||
bool MatchCurrentHardwareIdCallback(const char * hwid)
|
||||
{
|
||||
if (parentUsesWideChar)
|
||||
{
|
||||
return MatchCurrentHardwareIdW(parentLicensingClient, s2w(hwid).c_str());
|
||||
}
|
||||
else
|
||||
return MatchCurrentHardwareIdA(parentLicensingClient, hwid);
|
||||
}
|
||||
|
||||
static const char * GetCurrentHardwareId()
|
||||
{
|
||||
return KeyHelper::GetCurrentHardwareId();
|
||||
}
|
||||
|
||||
static bool MatchCurrentHardwareId(const char * hwid)
|
||||
{
|
||||
return KeyHelper::MatchCurrentHardwareId(hwid);
|
||||
}
|
||||
|
||||
void SetTimeValidationMethod(int method)
|
||||
{
|
||||
timeValidationMethod = method;
|
||||
}
|
||||
|
||||
private:
|
||||
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(oldStr, pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const LicenseTemplateImpl* licenseTemplate;
|
||||
|
||||
LicenseValidationResultImpl m_licenseValidationResult;
|
||||
|
||||
struct tm licenseExpirationTime;
|
||||
string licenseKey;
|
||||
string activationKey;
|
||||
string hardwareId;
|
||||
string licensingServiceUrl;
|
||||
|
||||
vector<unsigned char> licenseKeyValidationData;
|
||||
int licenseKeyValidationDataLen;
|
||||
int activationStatus;
|
||||
string licenseTemplateId;
|
||||
void * parentLicensingClient;
|
||||
bool parentUsesWideChar;
|
||||
int timeValidationMethod;
|
||||
int m_licenseValidityDays;
|
||||
//const char * (*GetCurrentHardwareIdCallback)(void * callerContext);
|
||||
//bool (*MatchCurrentHardwareIdCallback)(void * callerContext, const char * hwid);
|
||||
};
|
||||
2
core/anslicensing/ntpclient.cpp
Normal file
2
core/anslicensing/ntpclient.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "precomp.h"
|
||||
#include "ntpclient.h"
|
||||
113
core/anslicensing/ntpclient.h
Normal file
113
core/anslicensing/ntpclient.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#define INVALID_SOCKET (-1)
|
||||
#define SOCKET int
|
||||
#define SOCKET_ERROR (-1)
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
class NTPClient
|
||||
{
|
||||
public:
|
||||
static time_t GetCurrentTimeUTC(const char * ntpserver = NULL)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA w;
|
||||
int remote_length;
|
||||
#else
|
||||
socklen_t remote_length;
|
||||
#endif
|
||||
SOCKET sd = INVALID_SOCKET;
|
||||
char ntp_buffer[48];
|
||||
time_t current_time = 0;
|
||||
struct hostent *hp;
|
||||
struct sockaddr_in remote;
|
||||
struct sockaddr_in local;
|
||||
char host_name[256];
|
||||
hostent * host = NULL;
|
||||
|
||||
do {
|
||||
#ifdef _WIN32
|
||||
if (WSAStartup(MAKEWORD(2, 2), &w) != 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if ((sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||
break;
|
||||
|
||||
memset((void *)&remote, '\0', sizeof(struct sockaddr_in));
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(123);
|
||||
|
||||
if ((host = gethostbyname((ntpserver) ? ntpserver : "time.windows.com")) == NULL)
|
||||
break;
|
||||
|
||||
remote.sin_addr.s_addr = *(u_long *)host->h_addr_list[0];
|
||||
|
||||
memset((void *)&local, '\0', sizeof(local));
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(0);
|
||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (::bind(sd, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
|
||||
break;
|
||||
|
||||
memset(ntp_buffer, 0, sizeof(ntp_buffer));
|
||||
ntp_buffer[0] = 0x1B;
|
||||
|
||||
remote_length = sizeof(struct sockaddr_in);
|
||||
|
||||
if (sendto(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, remote_length) == -1)
|
||||
break;
|
||||
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sd, &fds);
|
||||
|
||||
timeval timeout;
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
if (select(1, &fds, NULL, NULL, &timeout) != 1)
|
||||
break;
|
||||
|
||||
if (recvfrom(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, &remote_length) < 0)
|
||||
break;
|
||||
|
||||
unsigned int int_part = *(unsigned int *)(ntp_buffer + 40);
|
||||
unsigned int fract_part = *(unsigned int *)(ntp_buffer + 44);
|
||||
|
||||
int_part = SwapEndianness(int_part);
|
||||
|
||||
current_time = (time_t)(int_part -= 2208988800U);
|
||||
}
|
||||
while (0);
|
||||
|
||||
if (sd != INVALID_SOCKET)
|
||||
closesocket(sd);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
return current_time;
|
||||
}
|
||||
|
||||
static unsigned int SwapEndianness(unsigned int x)
|
||||
{
|
||||
return (unsigned int)(((x & 0x000000ff) << 24) +
|
||||
((x & 0x0000ff00) << 8) +
|
||||
((x & 0x00ff0000) >> 8) +
|
||||
((x & 0xff000000) >> 24));
|
||||
}
|
||||
};
|
||||
1200
core/anslicensing/picojson.h
Normal file
1200
core/anslicensing/picojson.h
Normal file
File diff suppressed because it is too large
Load Diff
6
core/anslicensing/precomp.cpp
Normal file
6
core/anslicensing/precomp.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
//
|
||||
// Copyright (c) ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
32
core/anslicensing/precomp.h
Normal file
32
core/anslicensing/precomp.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "anslicensing.h"
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h> /* memset(), memcpy() */
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define _alloca alloca
|
||||
#define _stricmp strcasecmp
|
||||
#define _snprintf snprintf
|
||||
#define _atoi64(s) strtoull(s, NULL, 10)
|
||||
|
||||
#endif
|
||||
285
core/anslicensing/prime.cpp
Normal file
285
core/anslicensing/prime.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
//
|
||||
// Copyright (c) ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
// prime factory implementation
|
||||
#include "precomp.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bigint.h"
|
||||
#include "prime.h"
|
||||
|
||||
extern void print( bigint x );
|
||||
|
||||
static int maybe_prime( const bigint & p )
|
||||
{
|
||||
return modexp( 2, p - 1, p ) == 1;
|
||||
}
|
||||
|
||||
static int fermat_is_probable_prime( const bigint & p )
|
||||
{
|
||||
// Test based on Fermats theorem a**(p-1) = 1 mod p for prime p
|
||||
// For 1000 bit numbers this can take quite a while
|
||||
const int rep = 4;
|
||||
const unsigned any[ rep ] = { 2,3,5,7 /*,11,13,17,19,23,29,31,37..*/ };
|
||||
|
||||
for ( unsigned i = 0; i < rep; i += 1 )
|
||||
if ( modexp( any[ i ], p - 1, p ) != 1 )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bigint random( const bigint & n )
|
||||
{
|
||||
bigint x = 0;
|
||||
|
||||
while ( x < n )
|
||||
x = x * RAND_MAX + rand();
|
||||
|
||||
return x % n;
|
||||
}
|
||||
|
||||
static int miller_rabin_is_probable_prime( const bigint & n )
|
||||
{
|
||||
unsigned T = 100;
|
||||
unsigned v = 0;
|
||||
bigint w = n - 1;
|
||||
|
||||
srand( (unsigned) time( 0 ) );
|
||||
|
||||
while ( w % 2 != 0 )
|
||||
{
|
||||
v += 1;
|
||||
w = w / 2;
|
||||
}
|
||||
|
||||
for ( unsigned j = 1; j <= T; j += 1 )
|
||||
{
|
||||
bigint a = 1 + random( n );
|
||||
bigint b = modexp( a, w, n );
|
||||
|
||||
if ( b != 1 && b != n - 1 )
|
||||
{
|
||||
unsigned i = 1;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( i == v )
|
||||
return 0;
|
||||
|
||||
b = ( b * b ) % n;
|
||||
|
||||
if ( b == n - 1 )
|
||||
break;
|
||||
|
||||
if ( b == 1 )
|
||||
return 0;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int is_probable_prime( const bigint & n )
|
||||
{
|
||||
return fermat_is_probable_prime( n )
|
||||
&& miller_rabin_is_probable_prime( n );
|
||||
}
|
||||
|
||||
prime_factory::prime_factory( unsigned MP )
|
||||
{
|
||||
// Initialise pl
|
||||
unsigned p = 2;
|
||||
char * b = new char[ MP + 1 ]; // one extra to stop search
|
||||
|
||||
for ( unsigned i = 0; i <= MP; i += 1 )
|
||||
b[ i ] = 1;
|
||||
|
||||
np = 0;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// skip composites
|
||||
while ( b[ p ] == 0 )
|
||||
p += 1;
|
||||
|
||||
if ( p == MP )
|
||||
break;
|
||||
|
||||
np += 1;
|
||||
|
||||
// cross off multiples
|
||||
unsigned c = p * 2;
|
||||
|
||||
while ( c < MP )
|
||||
{
|
||||
b[ c ] = 0;
|
||||
c += p;
|
||||
}
|
||||
|
||||
p += 1;
|
||||
}
|
||||
|
||||
pl = new unsigned[ np ];
|
||||
np = 0;
|
||||
|
||||
for ( p = 2; p < MP; p += 1 )
|
||||
if ( b[ p ] )
|
||||
{
|
||||
pl[ np ] = p;
|
||||
np += 1;
|
||||
}
|
||||
|
||||
delete [] b;
|
||||
}
|
||||
|
||||
prime_factory::~prime_factory()
|
||||
{
|
||||
delete [] pl;
|
||||
}
|
||||
|
||||
bigint prime_factory::find_prime( bigint start )
|
||||
{
|
||||
unsigned SS = 1000; // should be enough unless we are unlucky
|
||||
char * b = new char[ SS ]; // bitset of candidate primes
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < SS; i += 1 )
|
||||
b[ i ] = 1;
|
||||
|
||||
for ( i = 0; i < np; i += 1 )
|
||||
{
|
||||
unsigned p = pl[ i ];
|
||||
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
|
||||
|
||||
if ( r )
|
||||
r = p - r;
|
||||
|
||||
// cross off multiples of p
|
||||
while ( r < SS )
|
||||
{
|
||||
b[ r ] = 0;
|
||||
r += p;
|
||||
}
|
||||
}
|
||||
|
||||
// now test candidates
|
||||
for ( i = 0; i < SS; i+=1 )
|
||||
{
|
||||
if ( b[ i ] )
|
||||
{
|
||||
if ( is_probable_prime( start ) )
|
||||
{
|
||||
delete [] b;
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
start += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bigint prime_factory::find_special( bigint start, bigint base )
|
||||
{
|
||||
// Returns a (probable) prime number x > start such that
|
||||
// x and x*2+1 are both probable primes,
|
||||
// i.e. x is a probable Sophie-Germain prime
|
||||
unsigned SS = 40000; // should be enough unless we are unlucky
|
||||
char * b1 = new char[ SS ]; // bitset of candidate primes
|
||||
char * b2 = new char[ 2 * SS ];
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < SS; i += 1 )
|
||||
b1[ i ] = 1;
|
||||
|
||||
for ( i = 0; i < 2 * SS; i += 1 )
|
||||
b2[ i ] = 1;
|
||||
|
||||
for ( i = 0; i < np; i += 1 )
|
||||
{
|
||||
unsigned p = pl[ i ];
|
||||
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
|
||||
|
||||
if ( r )
|
||||
r = p - r;
|
||||
|
||||
// cross off multiples of p
|
||||
while ( r < SS )
|
||||
{
|
||||
b1[ r ] = 0;
|
||||
r += p;
|
||||
}
|
||||
|
||||
r = to_unsigned( ( start * 2 + 1 ) % p );
|
||||
|
||||
if ( r )
|
||||
r = p - r;
|
||||
|
||||
while ( r < 2 * SS )
|
||||
{
|
||||
b2[ r ] = 0;
|
||||
r += p;
|
||||
}
|
||||
}
|
||||
|
||||
// now test candidates
|
||||
for ( i = 0; i < SS; i += 1 )
|
||||
{
|
||||
if ( b1[ i ] && b2[ i * 2 ] )
|
||||
{
|
||||
printf("D=%u\n", to_unsigned( start * 2 + 1 - base ) );
|
||||
|
||||
if ( maybe_prime( start )
|
||||
&& maybe_prime( start * 2 + 1 )
|
||||
&& is_probable_prime( start )
|
||||
&& is_probable_prime( start * 2 + 1 )
|
||||
)
|
||||
{
|
||||
delete [] b1;
|
||||
delete [] b2;
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
start += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int prime_factory::make_prime( bigint & r, bigint & k, const bigint & min_p )
|
||||
// Divide out small factors or r
|
||||
{
|
||||
k = 1;
|
||||
for ( unsigned i = 0; i < np; i += 1 )
|
||||
{
|
||||
unsigned p = pl[ i ];
|
||||
// maybe pre-computing product of several primes
|
||||
// and then GCD(r,p) would be faster ?
|
||||
while ( r % p == 0 )
|
||||
{
|
||||
if ( r == p )
|
||||
return 1; // can only happen if min_p is small
|
||||
|
||||
r = r / p;
|
||||
k = k * p;
|
||||
|
||||
if ( r < min_p )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return is_probable_prime( r );
|
||||
}
|
||||
25
core/anslicensing/prime.h
Normal file
25
core/anslicensing/prime.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __PRIME_H
|
||||
#define __PRIME_H
|
||||
|
||||
class prime_factory
|
||||
{
|
||||
// construction
|
||||
public:
|
||||
prime_factory( unsigned MP = 2000 ); // sieve size
|
||||
~prime_factory();
|
||||
|
||||
// methods
|
||||
public:
|
||||
bigint find_prime( bigint start );
|
||||
int make_prime( bigint & r, bigint &k, const bigint & rmin );
|
||||
bigint find_special( bigint start, bigint base=0 );
|
||||
|
||||
// properties
|
||||
public:
|
||||
unsigned np;
|
||||
unsigned *pl;
|
||||
};
|
||||
|
||||
int is_probable_prime( const bigint &p );
|
||||
|
||||
#endif
|
||||
353
core/anslicensing/propertycollection.h
Normal file
353
core/anslicensing/propertycollection.h
Normal file
@@ -0,0 +1,353 @@
|
||||
#pragma once
|
||||
|
||||
#include "precomp.h"
|
||||
#include "uniconv.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "picojson.h"
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#ifndef MAX_XML_BUFFER_SIZE
|
||||
#define MAX_XML_BUFFER_SIZE 4096
|
||||
#endif
|
||||
|
||||
class PathEntry
|
||||
{
|
||||
friend class PropertyCollection;
|
||||
|
||||
public:
|
||||
PathEntry()
|
||||
{
|
||||
processed = false;
|
||||
}
|
||||
|
||||
PathEntry(const PathEntry & copy)
|
||||
{
|
||||
processed = false;
|
||||
path = copy.path;
|
||||
nameValueCollection = copy.nameValueCollection;
|
||||
}
|
||||
|
||||
PathEntry(const PathEntry * copy)
|
||||
{
|
||||
processed = false;
|
||||
path = copy->path;
|
||||
nameValueCollection = copy->nameValueCollection;
|
||||
}
|
||||
|
||||
private:
|
||||
string path;
|
||||
std::map<string, string> nameValueCollection;
|
||||
bool processed;
|
||||
};
|
||||
|
||||
class PropertyCollection
|
||||
{
|
||||
public:
|
||||
PropertyCollection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetProperty(const char * path, const char * name, const char * value)
|
||||
{
|
||||
string propName = (name != NULL) ? name : "";
|
||||
std::map<string, PathEntry>::iterator entry;
|
||||
|
||||
if ((entry = m_properties.find(path)) == m_properties.end())
|
||||
{
|
||||
PathEntry entry;
|
||||
entry.path = path;
|
||||
entry.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
|
||||
m_properties.insert(std::map<string, PathEntry>::value_type(path, entry));
|
||||
} else
|
||||
entry->second.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
|
||||
}
|
||||
|
||||
const char * GetProperty(const char * path, const char * name) const
|
||||
{
|
||||
std::map<string, PathEntry>::const_iterator entry = m_properties.find(path);
|
||||
|
||||
if (entry == m_properties.end())
|
||||
return NULL;
|
||||
|
||||
std::map<string, string>::const_iterator nv = entry->second.nameValueCollection.find((name != NULL) ? name : "");
|
||||
|
||||
if (nv == entry->second.nameValueCollection.end())
|
||||
return NULL;
|
||||
|
||||
return nv->second.c_str();
|
||||
}
|
||||
|
||||
void LoadXml(tinyxml2::XMLElement * src)
|
||||
{
|
||||
XmlToPathList("", src);
|
||||
}
|
||||
|
||||
void SaveXml(std::string & xml)
|
||||
{
|
||||
PathListToXml("/", &m_properties, xml, 1);
|
||||
}
|
||||
|
||||
void LoadJson(picojson::object & json)
|
||||
{
|
||||
|
||||
string path;
|
||||
size_t pos;
|
||||
|
||||
for (picojson::object::iterator iter = json.begin(); iter != json.end(); iter++)
|
||||
{
|
||||
path = iter->first.c_str();
|
||||
|
||||
if ((pos = path.find_last_of('#')) == string::npos)
|
||||
SetProperty(path.c_str(), NULL, iter->second.get<std::string>().c_str());
|
||||
else
|
||||
{
|
||||
SetProperty(path.substr(0, pos).c_str(), path.substr(pos + 1).c_str(), iter->second.get<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SaveJson(std::string & json, const char * indent = "")
|
||||
{
|
||||
|
||||
bool first = true;
|
||||
json.append("{");
|
||||
|
||||
for (std::map<string, PathEntry>::const_iterator item = m_properties.begin(); item != m_properties.end(); item++)
|
||||
{
|
||||
for (std::map<string, string>::const_iterator innerItem = item->second.nameValueCollection.begin(); innerItem != item->second.nameValueCollection.end(); innerItem++)
|
||||
{
|
||||
if (!first) json.append(",");
|
||||
json.append("\n");
|
||||
json.append(indent);
|
||||
json.append("\t");
|
||||
json.append("\"");
|
||||
json.append(item->first.c_str());
|
||||
if (innerItem->first.length() > 0)
|
||||
{
|
||||
json.append("#"); json.append(innerItem->first.c_str());
|
||||
}
|
||||
json.append("\":\""); json.append(innerItem->second.c_str()); json.append("\"");
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
json.append("\n"); json.append(indent); json.append("}");
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return m_properties.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<string, PathEntry> m_properties;
|
||||
|
||||
void XmlToPathList(const std::string prefix, const tinyxml2::XMLElement * node)
|
||||
{
|
||||
const char * text = node->GetText();
|
||||
|
||||
if (text != NULL)
|
||||
SetProperty(prefix.c_str(), "", text);
|
||||
|
||||
const tinyxml2::XMLAttribute * attr = node->FirstAttribute();
|
||||
|
||||
// risk of stack overflow because _alloca is called in loop. However the current number of properties
|
||||
// is very low so it is acceptable
|
||||
while (attr)
|
||||
{
|
||||
SetProperty(prefix.c_str(), attr->Name(), attr->Value());
|
||||
|
||||
attr = attr->Next();
|
||||
}
|
||||
|
||||
tinyxml2::XMLElement * child;
|
||||
|
||||
for (child = (tinyxml2::XMLElement *)node->FirstChildElement(); child != NULL; child = child->NextSiblingElement())
|
||||
{
|
||||
XmlToPathList(prefix + "/" + child->Name(), child);
|
||||
}
|
||||
}
|
||||
|
||||
void PathListToXml(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
|
||||
{
|
||||
std::string elementValue;
|
||||
bool startElementClosed = false;
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
if (indent > 0)
|
||||
xml.append(indent, '\t');
|
||||
|
||||
xml.append("<"); xml.append(1 + strrchr(pathPrefix.c_str(), '/'));
|
||||
}
|
||||
|
||||
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
|
||||
{
|
||||
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
|
||||
{
|
||||
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
|
||||
nvItem != item->second.nameValueCollection.end();
|
||||
nvItem++)
|
||||
{
|
||||
if (nvItem->first.length() == 0)
|
||||
{
|
||||
elementValue = nvItem->second.c_str();
|
||||
} else
|
||||
{
|
||||
xml.append(" ");
|
||||
xml.append(nvItem->first.c_str());
|
||||
xml.append("=\"");
|
||||
xml.append(nvItem->second.c_str());
|
||||
xml.append("\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
xml.append(">");
|
||||
|
||||
if (elementValue.length() > 0)
|
||||
{
|
||||
xml.append(elementValue);
|
||||
} else
|
||||
if (indent >= 0)
|
||||
xml.append("\n");
|
||||
}
|
||||
|
||||
bool finished = false;
|
||||
|
||||
while (!finished)
|
||||
{
|
||||
finished = true;
|
||||
std::string firstUnprocessedPrefix;
|
||||
|
||||
std::map<string, PathEntry> innerPathList;
|
||||
|
||||
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
|
||||
{
|
||||
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
|
||||
{
|
||||
if (firstUnprocessedPrefix.empty())
|
||||
{
|
||||
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
|
||||
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
|
||||
}
|
||||
|
||||
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
|
||||
|
||||
item->second.processed = true;
|
||||
finished = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!finished)
|
||||
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
|
||||
}
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
if (indent > 0 && elementValue.length() == 0)
|
||||
xml.append(indent, '\t');
|
||||
|
||||
xml.append("</"); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append(">");
|
||||
|
||||
if (indent >= 0) xml.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PathListToJson(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
|
||||
{
|
||||
std::string elementValue;
|
||||
bool startElementClosed = false;
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
if (indent > 0)
|
||||
xml.append(indent, '\t');
|
||||
|
||||
xml.append("\""); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append("\":");
|
||||
}
|
||||
|
||||
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
|
||||
{
|
||||
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
|
||||
{
|
||||
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
|
||||
nvItem != item->second.nameValueCollection.end();
|
||||
nvItem++)
|
||||
{
|
||||
if (nvItem->first.length() == 0)
|
||||
{
|
||||
elementValue = nvItem->second.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.append(" ");
|
||||
xml.append(nvItem->first.c_str());
|
||||
xml.append("=\"");
|
||||
xml.append(nvItem->second.c_str());
|
||||
xml.append("\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
xml.append(">");
|
||||
|
||||
if (elementValue.length() > 0)
|
||||
{
|
||||
xml.append(elementValue);
|
||||
}
|
||||
else
|
||||
if (indent >= 0)
|
||||
xml.append("\n");
|
||||
}
|
||||
|
||||
bool finished = false;
|
||||
|
||||
while (!finished)
|
||||
{
|
||||
finished = true;
|
||||
std::string firstUnprocessedPrefix;
|
||||
|
||||
std::map<string, PathEntry> innerPathList;
|
||||
|
||||
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
|
||||
{
|
||||
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
|
||||
{
|
||||
if (firstUnprocessedPrefix.empty())
|
||||
{
|
||||
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
|
||||
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
|
||||
}
|
||||
|
||||
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
|
||||
|
||||
item->second.processed = true;
|
||||
finished = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!finished)
|
||||
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
|
||||
}
|
||||
|
||||
if (pathPrefix != "/")
|
||||
{
|
||||
if (indent > 0 && elementValue.length() == 0)
|
||||
xml.append(indent, '\t');
|
||||
|
||||
xml.append("}");
|
||||
|
||||
if (indent >= 0) xml.append("\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
66
core/anslicensing/rand.cpp
Normal file
66
core/anslicensing/rand.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include "bigint.h"
|
||||
#include "rand.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
random::random()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if ( !CryptAcquireContext( (HCRYPTPROV *)&m_hCryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )
|
||||
m_hCryptProv = NULL;
|
||||
#else
|
||||
::srand(time(NULL));
|
||||
#endif
|
||||
}
|
||||
|
||||
random::~random()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if ( m_hCryptProv )
|
||||
CryptReleaseContext( (HCRYPTPROV)m_hCryptProv, 0L );
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned random::rand( unsigned max )
|
||||
{
|
||||
unsigned rnd;
|
||||
|
||||
#ifdef _WIN32
|
||||
if ( m_hCryptProv )
|
||||
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, sizeof( unsigned ), (BYTE *)&rnd );
|
||||
#else
|
||||
rnd = ::rand();
|
||||
#endif
|
||||
|
||||
return rnd % max;
|
||||
}
|
||||
|
||||
bigint random::rand( bigint & max )
|
||||
{
|
||||
unsigned n = ( max.bits() + ( ( sizeof( unsigned ) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
|
||||
unsigned * buf = (unsigned*)malloc(n * sizeof(unsigned));
|
||||
if ( !buf ) return max - 1;
|
||||
|
||||
bigint rnd;
|
||||
|
||||
#ifdef _WIN32
|
||||
if ( m_hCryptProv )
|
||||
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, n * sizeof( unsigned ), (BYTE *)buf );
|
||||
#else
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
*((unsigned *)buf + i) = ::rand();
|
||||
#endif
|
||||
|
||||
rnd.load( buf, n );
|
||||
|
||||
free(buf);
|
||||
|
||||
return rnd % max;
|
||||
}
|
||||
18
core/anslicensing/rand.h
Normal file
18
core/anslicensing/rand.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef __RAND_H
|
||||
#define __RAND_H
|
||||
|
||||
#include "bigint.h"
|
||||
|
||||
class random {
|
||||
public:
|
||||
random();
|
||||
~random();
|
||||
|
||||
unsigned rand( unsigned max );
|
||||
bigint rand( bigint & max );
|
||||
|
||||
protected:
|
||||
void * m_hCryptProv;
|
||||
};
|
||||
|
||||
#endif
|
||||
14
core/anslicensing/resource.h
Normal file
14
core/anslicensing/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by licensing.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
49
core/anslicensing/sdkregistration.cpp
Normal file
49
core/anslicensing/sdkregistration.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "precomp.h"
|
||||
#include "uniconv.h"
|
||||
#include "template.h"
|
||||
#include "validator.h"
|
||||
#include "sdkregistration.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
bool SDKRegistrationImpl::isRegistered = true;
|
||||
bool SDKRegistrationImpl::isExpired = false;
|
||||
string SDKRegistrationImpl::licenseKey;
|
||||
|
||||
void SDKRegistrationImpl::SetLicenseKey(const char * key)
|
||||
{
|
||||
licenseKey = key;
|
||||
}
|
||||
|
||||
bool SDKRegistrationImpl::IsRegistered()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDKRegistrationImpl::IsExpired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * SDKRegistrationImpl::GetLicenseKey()
|
||||
{
|
||||
return licenseKey.c_str();
|
||||
}
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
template<>
|
||||
void SDKRegistrationT<char>::SetLicenseKey(const char * key)
|
||||
{
|
||||
SDKRegistrationImpl::SetLicenseKey(key);
|
||||
}
|
||||
|
||||
template<>
|
||||
void SDKRegistrationT<wchar_t>::SetLicenseKey(const wchar_t * key)
|
||||
{
|
||||
string wkey = w2s(key);
|
||||
SDKRegistrationImpl::SetLicenseKey(wkey.c_str());
|
||||
}
|
||||
};
|
||||
};
|
||||
21
core/anslicensing/sdkregistration.h
Normal file
21
core/anslicensing/sdkregistration.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef __SDKREGISTRATION_H__
|
||||
#define __SDKREGISTRATION_H__
|
||||
|
||||
class SDKRegistrationImpl
|
||||
{
|
||||
public:
|
||||
static void SetLicenseKey(const char * key);
|
||||
|
||||
static const char * GetLicenseKey();
|
||||
|
||||
static bool IsRegistered();
|
||||
|
||||
static bool IsExpired();
|
||||
|
||||
private:
|
||||
static bool isRegistered;
|
||||
static bool isExpired;
|
||||
static string licenseKey;
|
||||
};
|
||||
|
||||
#endif
|
||||
160
core/anslicensing/sha1.cpp
Normal file
160
core/anslicensing/sha1.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "precomp.h"
|
||||
#include "sha1.h"
|
||||
|
||||
#define MAX_FILE_READ_BUFFER 8000
|
||||
|
||||
// Rotate x bits to the left
|
||||
#ifndef ROL32
|
||||
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_LITTLE_ENDIAN
|
||||
#define SHABLK0(i) (m_block->l[i] = \
|
||||
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
|
||||
#else
|
||||
#define SHABLK0(i) (m_block->l[i])
|
||||
#endif
|
||||
|
||||
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
|
||||
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
|
||||
|
||||
// SHA-1 rounds
|
||||
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
|
||||
|
||||
SHA1::SHA1()
|
||||
{
|
||||
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
SHA1::~SHA1()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SHA1::Reset()
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
m_state[0] = 0x67452301;
|
||||
m_state[1] = 0xEFCDAB89;
|
||||
m_state[2] = 0x98BADCFE;
|
||||
m_state[3] = 0x10325476;
|
||||
m_state[4] = 0xC3D2E1F0;
|
||||
|
||||
m_count[0] = 0;
|
||||
m_count[1] = 0;
|
||||
}
|
||||
|
||||
void SHA1::Transform(unsigned int state[5], unsigned char buffer[64])
|
||||
{
|
||||
unsigned int a = 0, b = 0, c = 0, d = 0, e = 0;
|
||||
|
||||
memcpy(m_block, buffer, 64);
|
||||
|
||||
// Copy state[] to working vars
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
// 4 rounds of 20 operations each. Loop unrolled.
|
||||
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
|
||||
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
|
||||
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
|
||||
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
|
||||
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
|
||||
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
|
||||
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
|
||||
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
|
||||
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
|
||||
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
|
||||
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
|
||||
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
|
||||
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
|
||||
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
|
||||
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
|
||||
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
|
||||
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
|
||||
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
|
||||
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
|
||||
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
|
||||
|
||||
// Add the working vars back into state[]
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
// Wipe variables
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
// Use this function to hash in binary data and strings
|
||||
void SHA1::Update(unsigned char *data, unsigned int len)
|
||||
{
|
||||
unsigned int i = 0, j;
|
||||
|
||||
j = (m_count[0] >> 3) & 63;
|
||||
|
||||
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
|
||||
|
||||
m_count[1] += (len >> 29);
|
||||
|
||||
if((j + len) > 63)
|
||||
{
|
||||
memcpy(&m_buffer[j], data, (i = 64 - j));
|
||||
Transform(m_state, m_buffer);
|
||||
|
||||
for (; i+63 < len; i += 64)
|
||||
Transform(m_state, &data[i]);
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
|
||||
memcpy(&m_buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
void SHA1::Final()
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
|
||||
|
||||
Update((unsigned char *)"\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((unsigned char *)"\0", 1);
|
||||
|
||||
Update(finalcount, 8); // Cause a SHA1Transform()
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
|
||||
}
|
||||
|
||||
// Wipe variables for security reasons
|
||||
i = 0;
|
||||
memset(m_buffer, 0, 64);
|
||||
memset(m_state, 0, 20);
|
||||
memset(m_count, 0, 8);
|
||||
memset(finalcount, 0, 8);
|
||||
|
||||
Transform(m_state, m_buffer);
|
||||
}
|
||||
|
||||
// Get the raw message digest
|
||||
void SHA1::GetHash(unsigned char *uDest)
|
||||
{
|
||||
memcpy(uDest, m_digest, 20);
|
||||
}
|
||||
58
core/anslicensing/sha1.h
Normal file
58
core/anslicensing/sha1.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef ___SHA1_H___
|
||||
#define ___SHA1_H___
|
||||
|
||||
#include <stdio.h> // Needed for file access
|
||||
#include <memory.h> // Needed for memset and memcpy
|
||||
#include <string.h> // Needed for strcat and strcpy
|
||||
|
||||
#define SHA1_LITTLE_ENDIAN
|
||||
|
||||
#ifdef LICENSING_BIG_ENDIAN
|
||||
// If you're compiling big endian, just comment out the following line
|
||||
#undef SHA1_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char c[64];
|
||||
unsigned int l[16];
|
||||
} SHA1_WORKSPACE_BLOCK;
|
||||
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
// Two different formats for ReportHash(...)
|
||||
enum
|
||||
{
|
||||
REPORT_HEX = 0,
|
||||
REPORT_DIGIT = 1
|
||||
};
|
||||
|
||||
// Constructor and Destructor
|
||||
SHA1();
|
||||
virtual ~SHA1();
|
||||
|
||||
unsigned int m_state[5];
|
||||
unsigned int m_count[2];
|
||||
unsigned char m_buffer[64];
|
||||
unsigned char m_digest[20];
|
||||
|
||||
void Reset();
|
||||
|
||||
// Update the hash value
|
||||
void Update(unsigned char *data, unsigned int len);
|
||||
|
||||
// Finalize hash and report
|
||||
void Final();
|
||||
void GetHash(unsigned char *uDest);
|
||||
|
||||
private:
|
||||
// Private SHA-1 transformation
|
||||
void Transform(unsigned int state[5], unsigned char buffer[64]);
|
||||
|
||||
// Member variables
|
||||
unsigned char m_workspace[64];
|
||||
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
|
||||
};
|
||||
|
||||
#endif
|
||||
1314
core/anslicensing/template.cpp
Normal file
1314
core/anslicensing/template.cpp
Normal file
File diff suppressed because it is too large
Load Diff
528
core/anslicensing/template.h
Normal file
528
core/anslicensing/template.h
Normal file
@@ -0,0 +1,528 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "ecc.h"
|
||||
#include "base64.h"
|
||||
#include "uniconv.h"
|
||||
#include "except.h"
|
||||
#include "sdkregistration.h"
|
||||
#include "certificate.h"
|
||||
#include "propertycollection.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class LicenseTemplateImpl {
|
||||
friend LicenseTemplate;
|
||||
|
||||
struct FieldInfo
|
||||
{
|
||||
FieldInfo(int _type, int _size, int _offset)
|
||||
{
|
||||
type = (BitStruct::FIELD_TYPE)_type;
|
||||
size = _size;
|
||||
offset = _offset;
|
||||
}
|
||||
|
||||
BitStruct::FIELD_TYPE type;
|
||||
int size;
|
||||
int offset;
|
||||
};
|
||||
|
||||
public:
|
||||
LicenseTemplateImpl(const char * xmlTemplate = NULL):
|
||||
m_defaultDataOffset(0),
|
||||
m_defaultValidationOffset(0)
|
||||
{
|
||||
Init();
|
||||
|
||||
if (xmlTemplate)
|
||||
LoadXml(xmlTemplate);
|
||||
}
|
||||
|
||||
void SetVersion(int version)
|
||||
{
|
||||
if (version > 3)
|
||||
throw new LicensingException(STATUS_UNSUPPORTED_VERSION);
|
||||
|
||||
m_version = version;
|
||||
}
|
||||
|
||||
unsigned GetVersion() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
void SetNumberOfGroups(int numGroups)
|
||||
{
|
||||
m_numGroups = numGroups;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfGroups() const
|
||||
{
|
||||
return m_numGroups;
|
||||
}
|
||||
|
||||
void SetCharactersPerGroup(int charsPerGroup)
|
||||
{
|
||||
m_charsPerGroup = charsPerGroup;
|
||||
}
|
||||
|
||||
unsigned GetCharactersPerGroup() const
|
||||
{
|
||||
return m_charsPerGroup;
|
||||
}
|
||||
|
||||
void SetGroupSeparator(const char * groupSep)
|
||||
{
|
||||
m_groupSeparator = groupSep;
|
||||
}
|
||||
|
||||
const char * GetGroupSeparator() const
|
||||
{
|
||||
return m_groupSeparator.c_str();
|
||||
}
|
||||
|
||||
void SetEncoding(int encoding)
|
||||
{
|
||||
m_keyEncoding = encoding;
|
||||
}
|
||||
|
||||
int GetEncoding() const
|
||||
{
|
||||
return m_keyEncoding;
|
||||
}
|
||||
|
||||
void SetHeader(const char * header)
|
||||
{
|
||||
m_header = header;
|
||||
}
|
||||
|
||||
const char * GetHeader() const
|
||||
{
|
||||
return m_header.c_str();
|
||||
}
|
||||
|
||||
void SetFooter(const char * footer)
|
||||
{
|
||||
m_footer = footer;
|
||||
}
|
||||
|
||||
const char * GetFooter() const
|
||||
{
|
||||
return m_footer.c_str();
|
||||
}
|
||||
|
||||
void SetDataSize(int sizeInBits)
|
||||
{
|
||||
m_dataSize = sizeInBits;
|
||||
}
|
||||
|
||||
unsigned GetDataSize() const
|
||||
{
|
||||
return m_dataSize;
|
||||
}
|
||||
|
||||
void AddDataField(const char * fieldName, int fieldType, int fieldSizeInBits, int fieldOffset = -1)
|
||||
{
|
||||
if (fieldOffset < 0)
|
||||
fieldOffset = m_defaultDataOffset;
|
||||
|
||||
m_dataFields.emplace(std::piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldSizeInBits, fieldOffset));
|
||||
|
||||
m_defaultDataOffset += fieldSizeInBits;
|
||||
}
|
||||
|
||||
bool GetDataField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
|
||||
{
|
||||
auto info = m_dataFields.find(fieldName);
|
||||
|
||||
if (info == m_dataFields.end())
|
||||
return false;
|
||||
|
||||
*fieldType = info->second.type;
|
||||
*fieldSizeInBits = info->second.size;
|
||||
*fieldOffset = info->second.offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnumDataFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
|
||||
{
|
||||
map<string, FieldInfo>::const_iterator* pIter;
|
||||
static string name;
|
||||
|
||||
if (*enumHandle == NULL)
|
||||
{
|
||||
pIter = new map<string, FieldInfo>::const_iterator(m_dataFields.begin());
|
||||
if (!pIter)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
|
||||
|
||||
if (*pIter == m_dataFields.end())
|
||||
{
|
||||
delete pIter;
|
||||
return false;
|
||||
}
|
||||
|
||||
name = (*pIter)->first;
|
||||
*fieldName = name.c_str();
|
||||
|
||||
*fieldType = (*pIter)->second.type;
|
||||
*fieldSizeInBits = (*pIter)->second.size;
|
||||
*fieldOffset = (*pIter)->second.offset;
|
||||
|
||||
pIter->operator ++(); // *Iter++ does not work. Think why :)
|
||||
|
||||
*enumHandle = pIter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetValidationDataSize(int sizeInBits)
|
||||
{
|
||||
m_validationDataSize = sizeInBits;
|
||||
}
|
||||
|
||||
unsigned GetValidationDataSize() const
|
||||
{
|
||||
return m_validationDataSize;
|
||||
}
|
||||
|
||||
void AddValidationField(const char * fieldName, int fieldType, int fieldBitSize, int fieldOffset = 0)
|
||||
{
|
||||
if (fieldOffset < 0)
|
||||
fieldOffset = m_defaultValidationOffset;
|
||||
|
||||
m_validationFields.emplace(piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldBitSize, fieldOffset));
|
||||
|
||||
m_defaultValidationOffset += fieldBitSize;
|
||||
}
|
||||
|
||||
bool GetValidationField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
|
||||
{
|
||||
auto info = m_validationFields.find(fieldName);
|
||||
|
||||
if (info == m_validationFields.end())
|
||||
return false;
|
||||
|
||||
*fieldType = info->second.type;
|
||||
*fieldSizeInBits = info->second.size;
|
||||
*fieldOffset = info->second.offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnumValidationFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSize, int * fieldOffset) const
|
||||
{
|
||||
map<string, FieldInfo>::const_iterator* pIter;
|
||||
static string name;
|
||||
|
||||
if (*enumHandle == NULL)
|
||||
{
|
||||
pIter = new map<string, FieldInfo>::const_iterator(m_validationFields.begin());
|
||||
if (!pIter)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
|
||||
|
||||
if (*pIter == m_validationFields.end())
|
||||
{
|
||||
delete pIter;
|
||||
return false;
|
||||
}
|
||||
|
||||
name = (*pIter)->first;
|
||||
*fieldName = name.c_str();
|
||||
|
||||
*fieldType = (*pIter)->second.type;
|
||||
*fieldSize = (*pIter)->second.size;
|
||||
*fieldOffset = (*pIter)->second.offset;
|
||||
|
||||
pIter->operator ++(); // *Iter++ does not work. Think why :)
|
||||
|
||||
*enumHandle = pIter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetSignatureSize(int sizeInBits)
|
||||
{
|
||||
if (sizeInBits < 76 || sizeInBits > 322)
|
||||
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
|
||||
|
||||
m_signatureSize = sizeInBits;
|
||||
|
||||
if (sizeInBits <= 108)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_54;
|
||||
m_signatureKeySize = 54;
|
||||
} else
|
||||
if (sizeInBits <= 146)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_73;
|
||||
m_signatureKeySize = 73;
|
||||
} else
|
||||
if (sizeInBits <= 158)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_79;
|
||||
m_signatureKeySize = 79;
|
||||
} else
|
||||
if (sizeInBits <= 182)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_91;
|
||||
m_signatureKeySize = 91;
|
||||
} else
|
||||
if (sizeInBits <= 200)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_100;
|
||||
m_signatureKeySize = 100;
|
||||
} else
|
||||
if (sizeInBits <= 240)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_120;
|
||||
m_signatureKeySize = 120;
|
||||
} else
|
||||
if (sizeInBits <= 262)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_131;
|
||||
m_signatureKeySize = 131;
|
||||
} else
|
||||
if (sizeInBits <= 282)
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_141;
|
||||
m_signatureKeySize = 141;
|
||||
} else
|
||||
{
|
||||
m_signatureKeyType = ECC::ECC_161;
|
||||
m_signatureKeySize = 161;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GetSignatureSize() const
|
||||
{
|
||||
return m_signatureSize;
|
||||
}
|
||||
|
||||
void LoadXml(const char * xmlTemplate);
|
||||
const char * SaveXml(bool savePrivateKey);
|
||||
|
||||
void LoadJson(const char * jsonTemplate);
|
||||
const char * SaveJson(bool savePrivateKey);
|
||||
|
||||
void SetLicensingServiceUrl(const char * url)
|
||||
{
|
||||
m_licensingServiceUrl = url;
|
||||
}
|
||||
|
||||
const char * GetLicensingServiceUrl() const
|
||||
{
|
||||
return m_licensingServiceUrl.c_str();
|
||||
}
|
||||
|
||||
void SetTemplateId(const char * templateId)
|
||||
{
|
||||
m_templateId = templateId;
|
||||
}
|
||||
|
||||
const char * GetTemplateId() const
|
||||
{
|
||||
return m_templateId.c_str();
|
||||
}
|
||||
|
||||
void SetLicensingServiceParameters(const char * params)
|
||||
{
|
||||
m_licensingServiceParameters = params;
|
||||
}
|
||||
|
||||
void SetLicenseGracePeriod(int days)
|
||||
{
|
||||
m_licenseGracePeriod = days;
|
||||
}
|
||||
|
||||
int GetLicenseGracePeriod() const
|
||||
{
|
||||
return m_licenseGracePeriod;
|
||||
}
|
||||
|
||||
void SetPublicKeyCertificate(const char * base64Certificate)
|
||||
{
|
||||
m_certificate = make_unique<Certificate>(base64Certificate);
|
||||
|
||||
ValidateCertificate();
|
||||
|
||||
unsigned char keyBuf[256]; int keyLen = 256;
|
||||
|
||||
m_certificate->GetPublicKey(keyBuf, &keyLen);
|
||||
|
||||
m_verificationKey = make_unique<ECC::Key>(keyBuf, keyLen);
|
||||
}
|
||||
|
||||
const char * GetPublicKeyCertificate() const
|
||||
{
|
||||
if (!m_certificate)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a certificate");
|
||||
|
||||
return m_certificate->ToString();
|
||||
}
|
||||
|
||||
void SetPrivateKey(const char * base64Key)
|
||||
{
|
||||
|
||||
BASE64 base64;
|
||||
int keyLen;
|
||||
int keyLenSizeT;
|
||||
|
||||
auto keyData = base64.decode(base64Key, (unsigned)strlen(base64Key), &keyLenSizeT);
|
||||
|
||||
if (keyData.empty())
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 private key");
|
||||
|
||||
keyLen = (unsigned)keyLenSizeT;
|
||||
|
||||
SetPrivateKey(keyData.data(), keyLen);
|
||||
}
|
||||
|
||||
const char * GetPrivateKey() const
|
||||
{
|
||||
if (!m_signingKey)
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a private key");
|
||||
|
||||
return m_signingKey->ToString();
|
||||
}
|
||||
|
||||
void GenerateSigningKeyPair()
|
||||
{
|
||||
Key * privateKey = NULL,
|
||||
* publicKey = NULL;
|
||||
|
||||
if (!SDKRegistrationImpl::IsRegistered())
|
||||
{
|
||||
privateKey = new Key(); privateKey->Load(&m_demoPrivateKeys[m_signatureKeyType][1], m_demoPrivateKeys[m_signatureKeyType][0], m_signatureKeyType);
|
||||
publicKey = new Key(); publicKey->Load(&m_demoPublicKeys[m_signatureKeyType][1], m_demoPublicKeys[m_signatureKeyType][0], m_signatureKeyType);
|
||||
} else
|
||||
{
|
||||
ECC::GenerateKeyPair(m_signatureKeyType, &privateKey, &publicKey);
|
||||
}
|
||||
|
||||
m_certificate.reset(Certificate::Generate(m_signatureSize, privateKey, publicKey, NULL, NULL, NULL, 0));
|
||||
|
||||
ValidateCertificate();
|
||||
|
||||
m_signingKey.reset(privateKey);
|
||||
|
||||
m_verificationKey.reset(publicKey);
|
||||
}
|
||||
|
||||
void SetProperty(const char * path, const char * name, const char * value)
|
||||
{
|
||||
m_properties.SetProperty(path, name, value);
|
||||
}
|
||||
|
||||
const char * GetProperty(const char * path, const char * name) const
|
||||
{
|
||||
return m_properties.GetProperty(path, name);
|
||||
}
|
||||
|
||||
public:
|
||||
// general
|
||||
int m_version;
|
||||
|
||||
// key format
|
||||
int m_numGroups;
|
||||
int m_charsPerGroup;
|
||||
int m_keyEncoding;
|
||||
string m_groupSeparator;
|
||||
string m_header;
|
||||
string m_footer;
|
||||
string m_licensingServiceUrl;
|
||||
string m_templateId;
|
||||
string m_licensingServiceParameters;
|
||||
|
||||
map<string, FieldInfo> m_dataFields;
|
||||
int m_defaultDataOffset;
|
||||
|
||||
map<string, FieldInfo> m_validationFields;
|
||||
int m_defaultValidationOffset;
|
||||
|
||||
// key signature
|
||||
unique_ptr<ECC::Key> m_verificationKey;
|
||||
unique_ptr<ECC::Key> m_signingKey;
|
||||
|
||||
unique_ptr<Certificate> m_certificate;
|
||||
bool m_hasPrivateKey;
|
||||
|
||||
ECC::KEY_TYPE m_signatureKeyType;
|
||||
int m_signatureKeySize;
|
||||
int m_signatureSize;
|
||||
int m_dataSize;
|
||||
int m_validationDataSize;
|
||||
|
||||
// buffer used to hold the xml representation of the template
|
||||
string m_xmlTemplate;
|
||||
|
||||
// other stuff
|
||||
int m_licenseGracePeriod;
|
||||
|
||||
PropertyCollection m_properties;
|
||||
|
||||
protected:
|
||||
static const unsigned char m_demoPublicKeys[10][23];
|
||||
static const unsigned char m_demoPrivateKeys[10][23];
|
||||
|
||||
private:
|
||||
void Init()
|
||||
{
|
||||
SetVersion(3);
|
||||
SetLicenseGracePeriod(0);
|
||||
SetGroupSeparator("-");
|
||||
SetNumberOfGroups(6);
|
||||
SetCharactersPerGroup(6);
|
||||
SetEncoding(ENCODING_BASE32X);
|
||||
SetSignatureSize(158);
|
||||
SetDataSize(22); // 6 groups * 6 chars per group * 5 bits per char - 158 signature size = 22 data size
|
||||
SetValidationDataSize(0);
|
||||
m_hasPrivateKey = false;
|
||||
}
|
||||
|
||||
void SetPrivateKey(const void * keyBuf, int keyLen)
|
||||
{
|
||||
ValidatePrivateKey(keyBuf, keyLen);
|
||||
|
||||
m_signingKey.reset(new Key(keyBuf, keyLen));
|
||||
|
||||
m_hasPrivateKey = true;
|
||||
}
|
||||
|
||||
void ValidatePrivateKey(const void * keyBuf, int keyLen)
|
||||
{
|
||||
if (keyLen <= 2)
|
||||
{
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid private key length");
|
||||
}
|
||||
|
||||
keyLen -= 2;
|
||||
keyBuf = (unsigned char *)keyBuf + 2;
|
||||
|
||||
if (!SDKRegistrationImpl::IsRegistered())
|
||||
{
|
||||
if (keyLen != m_demoPrivateKeys[m_signatureKeyType][0] || memcmp(keyBuf, &m_demoPrivateKeys[m_signatureKeyType][1], keyLen) != 0)
|
||||
{
|
||||
m_signingKey.reset();
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid public/private key. The SDK is in DEMO mode because a SDK license key was not set. In this mode, only certain public/private keys can be set. Did you set a valid SDK license key via ANSCENTER::Licensing::SDKRegistration::SetLicenseKey() ?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateCertificate()
|
||||
{
|
||||
unique_ptr<Certificate> validationCertificate = make_unique<Certificate>("AE4vDQELjMGgCJew5QSVMBWSAN2PaBa0zzYpjSYe0rcu88lYggE=");
|
||||
|
||||
if (!Certificate::VerifySignature(m_certificate.get(), validationCertificate.get()))
|
||||
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signature is not valid");
|
||||
}
|
||||
};
|
||||
2095
core/anslicensing/tinyxml2.cpp
Normal file
2095
core/anslicensing/tinyxml2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1968
core/anslicensing/tinyxml2.h
Normal file
1968
core/anslicensing/tinyxml2.h
Normal file
File diff suppressed because it is too large
Load Diff
80
core/anslicensing/uniconv.h
Normal file
80
core/anslicensing/uniconv.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef _WIN32
|
||||
inline wstring s2w(const char* str, size_t size = -1)
|
||||
{
|
||||
if (size == -1)
|
||||
size = strlen(str);
|
||||
|
||||
if (size == 0)
|
||||
return wstring();
|
||||
|
||||
size_t req_size = ::MultiByteToWideChar(CP_UTF8, 0,
|
||||
str, (int)size, NULL, 0);
|
||||
|
||||
if (req_size == 0)
|
||||
throw runtime_error("Failed converting UTF-8 string to UTF-16");
|
||||
|
||||
wstring wstr(req_size, 0);
|
||||
|
||||
int conv_size = ::MultiByteToWideChar(CP_UTF8, 0,
|
||||
str, (int)size, wstr.data(), req_size);
|
||||
|
||||
if (conv_size == 0)
|
||||
throw runtime_error("Failed converting UTF-8 string to UTF-16");
|
||||
|
||||
return wstr;
|
||||
}
|
||||
|
||||
inline wstring s2w(const string& str)
|
||||
{
|
||||
return s2w(str.data(), str.size());
|
||||
}
|
||||
|
||||
inline string w2s(const wchar_t* wstr, size_t size = -1)
|
||||
{
|
||||
size_t req_size = WideCharToMultiByte(CP_UTF8, 0, wstr, size, nullptr, 0, nullptr, nullptr);
|
||||
|
||||
if (!req_size)
|
||||
throw runtime_error("wide to multibyte conversion failed");
|
||||
|
||||
string str(req_size, 0);
|
||||
|
||||
int conv_size = WideCharToMultiByte(CP_UTF8, 0L, wstr, size, str.data(), req_size, nullptr, nullptr);
|
||||
|
||||
if (!conv_size)
|
||||
throw runtime_error("wide to multibyte conversion failed");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline string w2s(const wstring& wstr)
|
||||
{
|
||||
return w2s(wstr.data(), wstr.size());
|
||||
}
|
||||
#else
|
||||
inline wstring s2w(const char* str, size_t size = -1)
|
||||
{
|
||||
throw runtime_error("not implemented");
|
||||
}
|
||||
|
||||
inline wstring s2w(const string& str)
|
||||
{
|
||||
return s2w(str.data(), str.size());
|
||||
}
|
||||
|
||||
inline string w2s(const wchar_t* wstr, size_t size = -1)
|
||||
{
|
||||
throw runtime_error("not implemented");
|
||||
}
|
||||
|
||||
inline string w2s(const wstring& wstr)
|
||||
{
|
||||
return w2s(wstr.data(), wstr.size());
|
||||
}
|
||||
#endif
|
||||
205
core/anslicensing/validator.cpp
Normal file
205
core/anslicensing/validator.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// Copyright (c) ANSCENTER. All rights reserved.
|
||||
//
|
||||
|
||||
#include "precomp.h"
|
||||
#include "anslicensing.h"
|
||||
#include "template.h"
|
||||
#include "bitstream.h"
|
||||
#include "base32.h"
|
||||
#include "base64.h"
|
||||
#include "sha1.h"
|
||||
#include "except.h"
|
||||
#include "uniconv.h"
|
||||
#include "validator.h"
|
||||
|
||||
namespace ANSCENTER {
|
||||
namespace Licensing {
|
||||
template<>
|
||||
KeyValidatorT<char>::KeyValidatorT():
|
||||
m_Impl( *new KeyValidatorImpl() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<wchar_t>::KeyValidatorT():
|
||||
m_Impl( *new KeyValidatorImpl() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<char>::KeyValidatorT(const LicenseTemplateT<char> * keyTemplate):
|
||||
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<wchar_t>::KeyValidatorT(const LicenseTemplateT<wchar_t> * keyTemplate):
|
||||
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<char>::~KeyValidatorT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<wchar_t>::~KeyValidatorT()
|
||||
{
|
||||
delete & m_Impl;
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<char> * KeyValidatorT<char>::Create()
|
||||
{
|
||||
return new KeyValidatorT<char>();
|
||||
}
|
||||
|
||||
template<>
|
||||
KeyValidatorT<wchar_t> * KeyValidatorT<wchar_t>::Create()
|
||||
{
|
||||
return new KeyValidatorT<wchar_t>();
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::Destroy(KeyValidatorT<char> * obj)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::Destroy(KeyValidatorT<wchar_t> * obj)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
|
||||
{
|
||||
m_Impl.SetKeyTemplate(&templ->m_Impl);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
|
||||
m_Impl.SetValidationData(fieldName, buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_Impl.SetValidationData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
|
||||
{
|
||||
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::SetValidationData(const char * fieldName, int data)
|
||||
{
|
||||
|
||||
m_Impl.SetValidationData(fieldName, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
|
||||
{
|
||||
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::SetKey(const char * key)
|
||||
{
|
||||
m_Impl.SetKey(key);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::SetKey(const wchar_t * key)
|
||||
{
|
||||
m_Impl.SetKey(w2s(key).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyValidatorT<char>::IsKeyValid()
|
||||
{
|
||||
return m_Impl.IsKeyValid();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool KeyValidatorT<wchar_t>::IsKeyValid()
|
||||
{
|
||||
return m_Impl.IsKeyValid();
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::QueryKeyData(const char * dataField, void * buf, int * len)
|
||||
{
|
||||
m_Impl.QueryKeyData(dataField, buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::QueryKeyData(const wchar_t * dataField, void * buf, int * len)
|
||||
{
|
||||
m_Impl.QueryKeyData(w2s(dataField).c_str(), buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
int KeyValidatorT<char>::QueryIntKeyData(const char * dataField)
|
||||
{
|
||||
return m_Impl.QueryIntKeyData(dataField);
|
||||
}
|
||||
|
||||
template<>
|
||||
int KeyValidatorT<wchar_t>::QueryIntKeyData(const wchar_t * dataField)
|
||||
{
|
||||
return m_Impl.QueryIntKeyData(w2s(dataField).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::QueryDateKeyData(const char * dataField, int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.QueryDateKeyData(dataField, year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::QueryDateKeyData(const wchar_t * dataField, int * year, int * month, int * day)
|
||||
{
|
||||
m_Impl.QueryDateKeyData(w2s(dataField).c_str(), year, month, day);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<char>::QueryValidationData(const char * dataField, void * buf, int * len)
|
||||
{
|
||||
m_Impl.QueryValidationData(dataField, buf, len);
|
||||
}
|
||||
|
||||
template<>
|
||||
void KeyValidatorT<wchar_t>::QueryValidationData(const wchar_t * dataField, void * buf, int * len)
|
||||
{
|
||||
m_Impl.QueryValidationData((dataField) ? w2s(dataField).c_str() : NULL, buf, len);
|
||||
}
|
||||
};
|
||||
};
|
||||
224
core/anslicensing/validator.h
Normal file
224
core/anslicensing/validator.h
Normal file
@@ -0,0 +1,224 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "base64.h"
|
||||
#include "base32.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class KeyValidatorImpl {
|
||||
public:
|
||||
KeyValidatorImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KeyValidatorImpl(const LicenseTemplateImpl* templ, const char * key = NULL)
|
||||
{
|
||||
SetKeyTemplate(templ);
|
||||
|
||||
if (key)
|
||||
SetKey(key);
|
||||
}
|
||||
|
||||
~KeyValidatorImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetKeyTemplate(const LicenseTemplateImpl* templ)
|
||||
{
|
||||
m_keyTemplate = templ;
|
||||
|
||||
|
||||
if (templ->m_validationDataSize)
|
||||
{
|
||||
m_validationData.Create(templ->m_validationDataSize);
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_validationFields)
|
||||
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
}
|
||||
else
|
||||
m_validationData.Create(0);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_validationData.Set(fieldName, buf, len);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, int data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_validationData.Set(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
void SetKey(const char * licKey)
|
||||
{
|
||||
if (!licKey)
|
||||
throw new LicensingException(STATUS_INVALID_PARAM, "invalid license key");
|
||||
|
||||
string key(licKey);
|
||||
|
||||
if (key.length() < m_keyTemplate->GetCharactersPerGroup() * m_keyTemplate->GetNumberOfGroups() +
|
||||
strlen(m_keyTemplate->GetHeader()) +
|
||||
strlen(m_keyTemplate->GetFooter()) +
|
||||
strlen(m_keyTemplate->GetGroupSeparator()) * (m_keyTemplate->GetNumberOfGroups() - 1))
|
||||
{
|
||||
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "invalid license key (too short)");
|
||||
}
|
||||
|
||||
// remove header and footer (if any)
|
||||
if (!m_keyTemplate->m_header.empty())
|
||||
{
|
||||
key.erase(0, m_keyTemplate->m_header.length() + 2);
|
||||
}
|
||||
|
||||
if (!m_keyTemplate->m_footer.empty())
|
||||
{
|
||||
key.erase(key.length() - m_keyTemplate->m_footer.length() - 2, m_keyTemplate->m_footer.length() + 2);
|
||||
}
|
||||
|
||||
// ungroup license key
|
||||
for (int i = 0, erasePos = 0; i < m_keyTemplate->m_numGroups - 1; i++)
|
||||
{
|
||||
erasePos += m_keyTemplate->m_charsPerGroup;
|
||||
key.erase(erasePos, m_keyTemplate->m_groupSeparator.length());
|
||||
}
|
||||
|
||||
// decode license key
|
||||
switch ( m_keyTemplate->m_keyEncoding )
|
||||
{
|
||||
case ENCODING_BASE32X:
|
||||
{
|
||||
BASE32 base32;
|
||||
int padLen;
|
||||
int len = base32.encode_pad_length(((int)key.length() * 5 + 7) >> 3, &padLen);
|
||||
|
||||
if (len > (int)key.length())
|
||||
key.append(len - key.length(), 'A');
|
||||
|
||||
if (padLen)
|
||||
key.append(padLen,'=');
|
||||
|
||||
auto keyBuf = base32.decode(key.c_str(), (int)key.length(), &len );
|
||||
|
||||
if (keyBuf.empty())
|
||||
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
|
||||
|
||||
// reverse last byte
|
||||
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
|
||||
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ENCODING_BASE64X:
|
||||
{
|
||||
BASE64 base64;
|
||||
int padLen;
|
||||
int len = base64.encode_pad_length(((int)key.length() * 6 + 7) >> 3, &padLen);
|
||||
|
||||
if (len > (int)key.length())
|
||||
key.append(len - key.length(), 'A');
|
||||
|
||||
if (padLen)
|
||||
key.append(padLen,'=');
|
||||
|
||||
auto keyBuf = base64.decode(key.c_str(), (int)key.length(), &len );
|
||||
|
||||
if (keyBuf.empty())
|
||||
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
|
||||
|
||||
// reverse last byte
|
||||
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
|
||||
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
|
||||
}
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_dataFields)
|
||||
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
}
|
||||
|
||||
bool IsKeyValid()
|
||||
{
|
||||
ECC::Verifier verifier;
|
||||
BitStream signedData,
|
||||
signature;
|
||||
|
||||
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
|
||||
signedData.Clear();
|
||||
|
||||
if (m_keyTemplate->m_dataSize)
|
||||
signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize);
|
||||
|
||||
if (m_keyTemplate->m_validationDataSize)
|
||||
signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize);
|
||||
|
||||
signature.Create(m_keyTemplate->m_signatureSize);
|
||||
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
|
||||
m_keyData.GetBitStream().Read(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
|
||||
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
|
||||
signature.Seek(m_keyTemplate->m_signatureSize);
|
||||
signature.ZeroPadToNextByte();
|
||||
|
||||
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
|
||||
|
||||
// we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size
|
||||
if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1))
|
||||
verifier.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
|
||||
else
|
||||
verifier.SetHashSize(0);
|
||||
|
||||
verifier.SetPublicKey(m_keyTemplate->m_verificationKey.get());
|
||||
|
||||
return verifier.Verify(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3, signature.GetBuffer(), (signature.GetSize() + 7) >> 3 , m_keyTemplate->m_signatureSize);
|
||||
}
|
||||
|
||||
void QueryKeyData(const char * fieldName, void * buf, int * len)
|
||||
{
|
||||
m_keyData.Get(fieldName, buf, len);
|
||||
}
|
||||
|
||||
int QueryIntKeyData(const char * fieldName)
|
||||
{
|
||||
return m_keyData.GetInt(fieldName);
|
||||
}
|
||||
|
||||
void QueryDateKeyData(const char * fieldName, int * year, int * month, int * day)
|
||||
{
|
||||
m_keyData.GetDate(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
void QueryValidationData(const char * fieldName, void * buf, int * len)
|
||||
{
|
||||
return m_validationData.Get(fieldName, buf, len);
|
||||
}
|
||||
|
||||
public:
|
||||
const LicenseTemplateImpl* m_keyTemplate;
|
||||
BitStruct m_keyData;
|
||||
BitStruct m_validationData;
|
||||
};
|
||||
6
core/anslicensing/version.h
Normal file
6
core/anslicensing/version.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define VERSION_MAJOR 3
|
||||
#define VERSION_MINOR 9
|
||||
#define VERSION_BUILD 52
|
||||
#define BUILD_TIMESTAMP 1479947203
|
||||
209
core/anslicensing/wmihelper.h
Normal file
209
core/anslicensing/wmihelper.h
Normal file
@@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
|
||||
#define _WIN32_DCOM
|
||||
#include <iostream>
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "uniconv.h"
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
using namespace std;
|
||||
|
||||
class WmiHelper
|
||||
{
|
||||
public:
|
||||
WmiHelper()
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
wbemServices = NULL;
|
||||
wbemLocator = NULL;
|
||||
ownCoInitialize = false;
|
||||
|
||||
// Initialize COM.
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (hres == S_OK)
|
||||
{
|
||||
ownCoInitialize = true;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
hres = CoInitializeSecurity(
|
||||
NULL,
|
||||
-1, // COM negotiates service
|
||||
NULL, // Authentication services
|
||||
NULL, // Reserved
|
||||
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
|
||||
NULL, // Authentication info
|
||||
EOAC_NONE, // Additional capabilities
|
||||
NULL // Reserved
|
||||
);
|
||||
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
0,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator, (LPVOID *) &wbemLocator);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
if (ownCoInitialize)
|
||||
CoUninitialize();
|
||||
|
||||
throw new exception("failed to create IWbemLocator", hres);
|
||||
}
|
||||
|
||||
// Connect to the root\cimv2 namespace with the
|
||||
// current user and obtain pointer pSvc
|
||||
// to make IWbemServices calls.
|
||||
|
||||
hres = wbemLocator->ConnectServer(
|
||||
|
||||
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
|
||||
NULL, // User name
|
||||
NULL, // User password
|
||||
0, // Locale
|
||||
NULL, // Security flags
|
||||
0, // Authority
|
||||
0, // Context object
|
||||
&wbemServices // IWbemServices proxy
|
||||
);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
wbemLocator->Release();
|
||||
|
||||
if (ownCoInitialize)
|
||||
CoUninitialize();
|
||||
|
||||
throw new exception("could not connect to WMI", hres);
|
||||
}
|
||||
|
||||
// Set the IWbemServices proxy so that impersonation
|
||||
// of the user (client) occurs.
|
||||
hres = CoSetProxyBlanket(
|
||||
wbemServices, // the proxy to set
|
||||
RPC_C_AUTHN_WINNT, // authentication service
|
||||
RPC_C_AUTHZ_NONE, // authorization service
|
||||
NULL, // Server principal name
|
||||
RPC_C_AUTHN_LEVEL_CALL, // authentication level
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
|
||||
NULL, // client identity
|
||||
EOAC_NONE // proxy capabilities
|
||||
);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
wbemServices->Release();
|
||||
wbemLocator->Release();
|
||||
if (ownCoInitialize) CoUninitialize();
|
||||
throw new exception("could not connecto to WMI", hres);
|
||||
}
|
||||
}
|
||||
|
||||
~WmiHelper()
|
||||
{
|
||||
if (wbemServices) wbemServices->Release();
|
||||
if (wbemLocator) wbemLocator->Release();
|
||||
if (ownCoInitialize) CoUninitialize();
|
||||
}
|
||||
|
||||
void GetPropertyList(const char * wqlQuery, const char * propertyName, list<string> * propList, int maxElements = 0x7FFFFFFF)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
// For example, query for all the running processes
|
||||
IEnumWbemClassObject* pEnumerator = NULL;
|
||||
hres = wbemServices->ExecQuery(
|
||||
bstr_t("WQL"),
|
||||
bstr_t(wqlQuery),
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL,
|
||||
&pEnumerator);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
throw new exception("WMI query failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
IWbemClassObject *pclsObj;
|
||||
ULONG uReturn = 0;
|
||||
int numElements = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
hres = pEnumerator->Next(WBEM_INFINITE, 1,
|
||||
&pclsObj, &uReturn);
|
||||
|
||||
if(0 == uReturn)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
VARIANT vtProp;
|
||||
VariantInit(&vtProp);
|
||||
|
||||
// Get the value of the Name property
|
||||
hres = pclsObj->Get(_bstr_t(propertyName), 0, &vtProp, 0, 0);
|
||||
//
|
||||
if (SUCCEEDED(hres))
|
||||
{
|
||||
switch (vtProp.vt)
|
||||
{
|
||||
case VT_BSTR:
|
||||
propList->push_back(w2s(vtProp.bstrVal).c_str());
|
||||
numElements++;
|
||||
break;
|
||||
|
||||
case VT_I1:
|
||||
case VT_UI1:
|
||||
case VT_I2:
|
||||
case VT_UI2:
|
||||
case VT_I4:
|
||||
case VT_UI4:
|
||||
{
|
||||
char strVal[32];
|
||||
_itoa(vtProp.intVal, strVal, 10);
|
||||
propList->push_back(strVal);
|
||||
numElements++;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
{
|
||||
char strVal[32];
|
||||
_i64toa(vtProp.llVal, strVal, 10);
|
||||
propList->push_back(strVal);
|
||||
numElements++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
VariantClear(&vtProp);
|
||||
}
|
||||
|
||||
pclsObj->Release();
|
||||
|
||||
if (numElements >= maxElements)
|
||||
break;
|
||||
}
|
||||
|
||||
pEnumerator->Release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool ownCoInitialize;
|
||||
IWbemServices * wbemServices;
|
||||
IWbemLocator * wbemLocator;
|
||||
};
|
||||
Reference in New Issue
Block a user