162 lines
5.8 KiB
C++
162 lines
5.8 KiB
C++
//======================================================================================================
|
|
// Copyright 2025, Rokoko Glove OptiTrack Integration
|
|
//======================================================================================================
|
|
|
|
#include "LZ4Wrapper.h"
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <windows.h>
|
|
|
|
// Unity LZ4 DLL 동적 로딩
|
|
static HMODULE lz4Module = nullptr;
|
|
static decltype(&Unity_LZ4_uncompressSize) pUnity_LZ4_uncompressSize = nullptr;
|
|
static decltype(&Unity_LZ4_decompress) pUnity_LZ4_decompress = nullptr;
|
|
|
|
static bool LoadUnityLZ4()
|
|
{
|
|
if (lz4Module == nullptr) {
|
|
// 다양한 경로에서 Unity LZ4 DLL 로드 시도
|
|
const wchar_t* dllPaths[] = {
|
|
L"lz4.dll", // 현재 디렉토리
|
|
L".\\lz4.dll", // 명시적 현재 디렉토리
|
|
L"x64\\Debug\\lz4.dll", // 디버그 폴더
|
|
L"C:\\Users\\user\\Documents\\Streamingle_URP\\Assets\\External\\Rokoko\\Scripts\\Plugins\\LZ4\\x86_64\\lz4.dll" // Unity 절대 경로
|
|
};
|
|
|
|
for (const auto& path : dllPaths) {
|
|
lz4Module = LoadLibrary(path);
|
|
if (lz4Module != nullptr) {
|
|
// DLL 로드 성공 - 함수 포인터 획득
|
|
pUnity_LZ4_uncompressSize = (decltype(pUnity_LZ4_uncompressSize))GetProcAddress(lz4Module, "Unity_LZ4_uncompressSize");
|
|
pUnity_LZ4_decompress = (decltype(pUnity_LZ4_decompress))GetProcAddress(lz4Module, "Unity_LZ4_decompress");
|
|
|
|
if (pUnity_LZ4_uncompressSize != nullptr && pUnity_LZ4_decompress != nullptr) {
|
|
// 성공
|
|
break;
|
|
} else {
|
|
// 함수를 찾지 못함 - DLL 언로드하고 다음 시도
|
|
FreeLibrary(lz4Module);
|
|
lz4Module = nullptr;
|
|
pUnity_LZ4_uncompressSize = nullptr;
|
|
pUnity_LZ4_decompress = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (lz4Module != nullptr && pUnity_LZ4_uncompressSize != nullptr && pUnity_LZ4_decompress != nullptr);
|
|
}
|
|
|
|
namespace RokokoIntegration
|
|
{
|
|
std::vector<uint8_t> LZ4Wrapper::Decompress(const uint8_t* compressedData, int compressedSize)
|
|
{
|
|
try {
|
|
// 입력 데이터 검증
|
|
if (!compressedData || compressedSize <= 0) {
|
|
return {};
|
|
}
|
|
|
|
// Unity LZ4 DLL 로드
|
|
if (!LoadUnityLZ4()) {
|
|
return {};
|
|
}
|
|
|
|
// Unity 방식 정확히 구현
|
|
// 1. Unity_LZ4_uncompressSize로 압축 해제된 크기 구하기
|
|
int uncompressedSize = pUnity_LZ4_uncompressSize(
|
|
reinterpret_cast<const char*>(compressedData),
|
|
compressedSize
|
|
);
|
|
|
|
if (uncompressedSize <= 0) {
|
|
return {};
|
|
}
|
|
|
|
// 크기 유효성 검사
|
|
if (uncompressedSize > MAX_DECOMPRESSED_SIZE) {
|
|
return {};
|
|
}
|
|
|
|
// 2. Unity_LZ4_decompress로 압축 해제
|
|
std::vector<uint8_t> decompressed(uncompressedSize);
|
|
int result = pUnity_LZ4_decompress(
|
|
reinterpret_cast<const char*>(compressedData),
|
|
compressedSize,
|
|
reinterpret_cast<char*>(decompressed.data()),
|
|
uncompressedSize
|
|
);
|
|
|
|
// Unity에서는 result != 0이면 실패
|
|
if (result != 0) {
|
|
return {};
|
|
}
|
|
|
|
return decompressed;
|
|
|
|
} catch (...) {
|
|
// 모든 예외 상황에서 안전하게 빈 벡터 반환
|
|
return {};
|
|
}
|
|
}
|
|
|
|
bool LZ4Wrapper::IsValidLZ4Data(const uint8_t* data, int size)
|
|
{
|
|
if (!data || size < 4) {
|
|
return false;
|
|
}
|
|
|
|
// Rokoko Studio의 LZ4 데이터는 일반적으로 JSON이 아니므로
|
|
// 첫 번째 바이트가 '{'가 아닌 경우 LZ4로 간주
|
|
if (size > 0 && data[0] == '{') {
|
|
return false; // JSON 데이터는 LZ4가 아님
|
|
}
|
|
|
|
// 기본적인 LZ4 매직 넘버 확인
|
|
// LZ4 프레임 헤더의 일부 패턴 확인
|
|
if (size >= 4) {
|
|
// LZ4 프레임 헤더의 매직 넘버 (0x184D2204)
|
|
if (data[0] == 0x04 && data[1] == 0x22 && data[2] == 0x4D && data[3] == 0x18) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// 매직 넘버가 없어도 압축된 데이터로 간주 (Rokoko Studio 특성상)
|
|
return true;
|
|
}
|
|
|
|
int LZ4Wrapper::GetDecompressedSize(const uint8_t* compressedData, int compressedSize)
|
|
{
|
|
try {
|
|
// Unity LZ4 DLL 로드
|
|
if (!LoadUnityLZ4()) {
|
|
return -1;
|
|
}
|
|
|
|
// Unity 방식으로 압축 해제된 크기 구하기
|
|
int decompressedSize = pUnity_LZ4_uncompressSize(
|
|
reinterpret_cast<const char*>(compressedData),
|
|
compressedSize
|
|
);
|
|
return decompressedSize;
|
|
|
|
} catch (...) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
bool LZ4Wrapper::ValidateDecompressedSize(int compressedSize, int decompressedSize)
|
|
{
|
|
// 압축 해제된 크기가 합리적인 범위인지 확인
|
|
if (decompressedSize <= 0 || decompressedSize > MAX_DECOMPRESSED_SIZE) {
|
|
return false;
|
|
}
|
|
|
|
// 압축률이 합리적인지 확인 (일반적으로 1:1 ~ 1:10)
|
|
if (decompressedSize < compressedSize || decompressedSize > compressedSize * 10) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|