port 2D step 5a: EterPack/EterPackManager + EterBase file units against the real 40250 packs

- Mirror copies: EterPack (EterPack, EterPackManager, EterPackCursor, CSHybridCrypt policy, Inline.h)
  and EterBase logic units tea/lzo/Timer/Stl/Random, with PORT-tagged width fixes (LONG index
  fields, static_assert(sizeof(TEterPackIndex) == 192), tea_word = Win32 unsigned long).
- TEA pack keys are extracted from the reference EterPack.cpp at configure time into
  build/.../EterPackKeys.generated.h; nothing key-bearing is tracked.
- Platform EterBase: FileBase (stdio, case-insensitive fallback), MappedFile (mmap /
  MapViewOfFile), CRC32, Debug, Utils StringPath/StringLowers.
- Win32Crt: CreateDirectory/DeleteFile/_access/MAKEFOURCC; Win32MinMax.h min/max (force-included
  on MinGW, whose windows.h omits them in C++).
- tests/port_eterpack_test: registers pack/Index like PackInitialize and checks 119
  registrations / 103 packs + root / 54891 entries / 52609 paths / 2282 overrides with
  first-registered-wins, and that exactly the 4 short-layout SECURITY files fail to load.
- 2R count corrected (136 -> 119 registrations, 103 distinct packs + root).

Not runtime-reachable yet (asset_io pack backend is step 5b), so port-map statuses stay TODO.
port_gate: macos/android/ios/windows PASS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 00:56:39 +09:00
co-authored by Claude Opus 5
parent f210f47076
commit 1f1004da79
31 changed files with 4640 additions and 142 deletions
+50
View File
@@ -30,6 +30,44 @@ if(NOT MSVC)
endif()
target_compile_options(port_logic PUBLIC ${MT_PORT_WARNING_FLAGS})
target_compile_features(port_logic PUBLIC cxx_std_20)
# Armadillo nanomite markers (StdAfx.h `__asm _emit` jumps over a signature): x86-32 MSVC inline asm that no
# target here accepts, and a no-op without the Armadillo wrapper, so they expand to nothing.
target_compile_definitions(port_logic PUBLIC "NANOBEGIN=" "NANOEND=")
if(MINGW)
target_compile_options(port_logic PUBLIC -include ${CMAKE_CURRENT_SOURCE_DIR}/common/Win32MinMax.h)
endif()
# EterPack/EterPack.cpp includes EterPackKeys.generated.h in place of the two TEA key arrays: the keys are
# read from the reference EterPack.cpp at configure time and written into the build tree, never the repository.
# Without the reference the arrays are zero and every COMPRESS/SECURITY entry fails to decode.
set(MT_40250_SOURCE "$ENV{MT_40250_SOURCE}" CACHE PATH "40250 ClientVS22/source reference root")
if(NOT MT_40250_SOURCE)
set(MT_40250_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/../../../../40250/Server Client TMP4/ClientVS22/source")
endif()
set(MT_PORT_GENERATED ${CMAKE_CURRENT_BINARY_DIR}/generated)
set(mt_eterpack_ref "${MT_40250_SOURCE}/EterPack/EterPack.cpp")
set(mt_eterpack_keys "")
if(EXISTS "${mt_eterpack_ref}")
file(READ "${mt_eterpack_ref}" mt_ref_text)
foreach(arr s_adwEterPackKey s_adwEterPackSecurityKey)
string(REGEX MATCH "static DWORD ${arr}\\[\\][ \t\r\n]*=[ \t\r\n]*{[^}]*}" block "${mt_ref_text}")
string(REGEX MATCHALL "[0-9]+" values "${block}")
list(LENGTH values n)
if(NOT n EQUAL 4)
message(FATAL_ERROR "port: ${arr} not found in ${mt_eterpack_ref}")
endif()
list(JOIN values ", " values)
string(APPEND mt_eterpack_keys "static DWORD ${arr}[] = { ${values} };\n")
endforeach()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${mt_eterpack_ref}")
else()
message(WARNING "port: ${mt_eterpack_ref} not found (set MT_40250_SOURCE); EterPack keys are zero")
string(APPEND mt_eterpack_keys "static DWORD s_adwEterPackKey[] = { 0, 0, 0, 0 };\n"
"static DWORD s_adwEterPackSecurityKey[] = { 0, 0, 0, 0 };\n")
endif()
file(CONFIGURE OUTPUT ${MT_PORT_GENERATED}/EterPackKeys.generated.h
CONTENT "// Generated from the 40250 reference EterPack.cpp by port/CMakeLists.txt; do not commit.\n#pragma once\n${mt_eterpack_keys}")
target_include_directories(port_logic PRIVATE ${MT_PORT_GENERATED})
if(WIN32)
target_link_libraries(port_logic PUBLIC winmm)
endif()
@@ -86,6 +124,10 @@ add_library(port_header_gate OBJECT ${MT_PORT_GATE_SOURCES})
target_include_directories(port_header_gate PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MT_PORT_SHIMS})
target_link_libraries(port_header_gate PRIVATE mt3p::minilzo mt3p::cryptopp)
target_compile_features(port_header_gate PRIVATE cxx_std_20)
target_compile_definitions(port_header_gate PRIVATE "NANOBEGIN=" "NANOEND=")
if(MINGW)
target_compile_options(port_header_gate PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/common/Win32MinMax.h)
endif()
target_compile_options(port_header_gate PRIVATE ${MT_PORT_WARNING_FLAGS})
add_dependencies(port_logic port_header_gate)
@@ -95,4 +137,12 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
add_executable(port_common_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_common_test.cpp)
target_link_libraries(port_common_test PRIVATE port_logic)
add_test(NAME port.common COMMAND $<TARGET_FILE:port_common_test>)
# Against the real 40250 Client/pack next to the reference source; skipped (77) when it is missing,
# failed instead under MT_ASSETS_STRICT=1.
set(MT_40250_CLIENT "${MT_40250_SOURCE}/../../Client" CACHE PATH "40250 Client directory (pack/, Eternexus/)")
add_executable(port_eterpack_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_eterpack_test.cpp)
target_link_libraries(port_eterpack_test PRIVATE port_platform)
add_test(NAME port.eterpack COMMAND $<TARGET_FILE:port_eterpack_test> ${MT_40250_CLIENT})
set_tests_properties(port.eterpack PROPERTIES SKIP_RETURN_CODE 77)
endif()
+49
View File
@@ -0,0 +1,49 @@
#include "StdAfx.h"
#include "Random.h" // PORT: the POSIX-safe names (Random.h) must be in scope for the definitions
#include <assert.h>
static unsigned long randseed = 1;
void srandom(unsigned long seed)
{
randseed = seed;
}
/*
* Pseudo-random number generator for randomizing the profiling clock,
* and whatever else we might use it for. The result is uniform on
* [0, 2^31 - 1].
*/
unsigned long random()
{
long x, hi, lo, t;
/*
* Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
x = randseed;
hi = x / 127773;
lo = x % 127773;
t = 16807 * lo - 2836 * hi;
if (t <= 0)
t += 0x7fffffff;
randseed = t;
return (t);
}
float frandom(float flLow, float flHigh)
{
float fl = float(random()) / float(2147483648.0f); // float in [0,1)
return (fl * (flHigh - flLow)) + flLow; // float in [low,high)
}
long random_range(long from, long to)
{
assert(from <= to);
return ((random() % (to - from + 1)) + from);
}
+92
View File
@@ -0,0 +1,92 @@
#include "StdAfx.h"
#include "Stl.h"
static std::list<std::string> s_stList;
char korean_tolower(const char c)
{
char ret = c;
if (c >= 'A' && c <= 'Z')
ret = c - 'A' + 'a';
assert(ret == tolower(c));
return ret;
}
std::string& stl_static_string(const char * c_sz)
{
std::string str;
str.assign(c_sz);
s_stList.push_back(str);
return s_stList.back();
}
void stl_lowers(std::string& rstRet)
{
for (size_t i = 0; i < rstRet.length(); ++i)
rstRet[i] = korean_tolower(rstRet[i]);
}
int split_string(const std::string& input, const std::string& delimiter, std::vector<std::string>& results, bool includeEmpties)
{
int iPos = 0;
int newPos = -1;
UINT sizeS2 = delimiter.size();
UINT isize = input.size();
if ((isize == 0) || (sizeS2 == 0))
{
return 0;
}
std::vector<int> positions;
newPos = input.find(delimiter, 0);
if (newPos < 0)
return 0;
int numFound = 0;
while (newPos >= iPos)
{
numFound++;
positions.push_back(newPos);
iPos = newPos;
newPos = input.find(delimiter, iPos+sizeS2);
}
if (numFound == 0)
return 0;
for (UINT i = 0; i <= positions.size(); ++i)
{
std::string s("");
if (i == 0)
{
s = input.substr(i, positions[i]);
}
else
{
UINT offset = positions[i-1] + sizeS2;
if (offset < isize)
{
if (i == positions.size())
{
s = input.substr(offset);
}
else if (i > 0)
{
s = input.substr(positions[i-1] + sizeS2, positions[i] - positions[i-1] - sizeS2);
}
}
}
if (includeEmpties || (s.size() > 0))
{
results.push_back(s);
}
}
return numFound;
}
+156
View File
@@ -0,0 +1,156 @@
#include "StdAfx.h"
#include "Timer.h"
static LARGE_INTEGER gs_liTickCountPerSec;
static DWORD gs_dwBaseTime=0;
static DWORD gs_dwServerTime=0;
static DWORD gs_dwClientTime=0;
static DWORD gs_dwFrameTime=0;
#pragma comment(lib, "winmm.lib")
BOOL ELTimer_Init()
{
/*
gs_liTickCountPerSec.QuadPart=0;
if (!QueryPerformanceFrequency(&gs_liTickCountPerSec))
return 0;
LARGE_INTEGER liTickCount;
QueryPerformanceCounter(&liTickCount);
gs_dwBaseTime= (liTickCount.QuadPart*1000 / gs_liTickCountPerSec.QuadPart);
*/
gs_dwBaseTime = timeGetTime();
return 1;
}
DWORD ELTimer_GetMSec()
{
//assert(gs_dwBaseTime!=0 && "ELTimer_Init 를 먼저 실행하세요");
//LARGE_INTEGER liTickCount;
//QueryPerformanceCounter(&liTickCount);
return timeGetTime() - gs_dwBaseTime; //(liTickCount.QuadPart*1000 / gs_liTickCountPerSec.QuadPart)-gs_dwBaseTime;
}
VOID ELTimer_SetServerMSec(DWORD dwServerTime)
{
NANOBEGIN
if (0 != dwServerTime) // nanomite를 위한 더미 if
{
gs_dwServerTime = dwServerTime;
gs_dwClientTime = CTimer::instance().GetCurrentMillisecond();
}
NANOEND
}
DWORD ELTimer_GetServerMSec()
{
return CTimer::instance().GetCurrentMillisecond() - gs_dwClientTime + gs_dwServerTime;
//return ELTimer_GetMSec() - gs_dwClientTime + gs_dwServerTime;
}
DWORD ELTimer_GetFrameMSec()
{
return gs_dwFrameTime;
}
DWORD ELTimer_GetServerFrameMSec()
{
return ELTimer_GetFrameMSec() - gs_dwClientTime + gs_dwServerTime;
}
VOID ELTimer_SetFrameMSec()
{
gs_dwFrameTime = ELTimer_GetMSec();
}
CTimer::CTimer()
{
ELTimer_Init();
NANOBEGIN
if (this) // nanomite를 위한 더미 if
{
m_dwCurrentTime = 0;
m_bUseRealTime = true;
m_index = 0;
m_dwElapsedTime = 0;
m_fCurrentTime = 0.0f;
}
NANOEND
}
CTimer::~CTimer()
{
}
void CTimer::SetBaseTime()
{
m_dwCurrentTime = 0;
}
void CTimer::Advance()
{
if (!m_bUseRealTime)
{
++m_index;
if (m_index == 1)
m_index = -1;
m_dwCurrentTime += 16 + (m_index & 1);
m_fCurrentTime = m_dwCurrentTime / 1000.0f;
}
else
{
DWORD currentTime = ELTimer_GetMSec();
if (m_dwCurrentTime == 0)
m_dwCurrentTime = currentTime;
m_dwElapsedTime = currentTime - m_dwCurrentTime;
m_dwCurrentTime = currentTime;
}
}
void CTimer::Adjust(int iTimeGap)
{
m_dwCurrentTime += iTimeGap;
}
float CTimer::GetCurrentSecond()
{
if (m_bUseRealTime)
return ELTimer_GetMSec() / 1000.0f;
return m_fCurrentTime;
}
DWORD CTimer::GetCurrentMillisecond()
{
if (m_bUseRealTime)
return ELTimer_GetMSec();
return m_dwCurrentTime;
}
float CTimer::GetElapsedSecond()
{
return GetElapsedMilliecond() / 1000.0f;
}
DWORD CTimer::GetElapsedMilliecond()
{
if (!m_bUseRealTime)
return 16 + (m_index & 1);
return m_dwElapsedTime;
}
void CTimer::UseCustomTime()
{
m_bUseRealTime = false;
}
+411
View File
@@ -0,0 +1,411 @@
#include "StdAfx.h"
#include <stdlib.h>
#include <lzo/lzoLibLink.h>
#include "lzo.h"
#include "tea.h"
#include "Debug.h"
#define dbg_printf
static class LZOFreeMemoryMgr
{
public:
enum
{
REUSING_CAPACITY = 64*1024,
};
public:
~LZOFreeMemoryMgr()
{
std::vector<BYTE*>::iterator i;
for (i = m_freeVector.begin(); i != m_freeVector.end(); ++i)
delete *i;
m_freeVector.clear();
}
BYTE* Alloc(unsigned capacity)
{
assert(capacity > 0);
if (capacity < REUSING_CAPACITY)
{
if (!m_freeVector.empty())
{
BYTE* freeMem = m_freeVector.back();
m_freeVector.pop_back();
dbg_printf("lzo.reuse_alloc\t%p(%d) free\n", freeMem, capacity);
return freeMem;
}
BYTE* newMem = new BYTE[REUSING_CAPACITY];
dbg_printf("lzo.reuse_alloc\t%p(%d) real\n", newMem, capacity);
return newMem;
}
BYTE* newMem = new BYTE[capacity];
dbg_printf("lzo.real_alloc\t%p(%d)\n", newMem, capacity);
return newMem;
}
void Free(BYTE* ptr, unsigned capacity)
{
assert(ptr != NULL);
assert(capacity > 0);
if (capacity < REUSING_CAPACITY)
{
dbg_printf("lzo.reuse_free\t%p(%d)\n", ptr, capacity);
m_freeVector.push_back(ptr);
return;
}
dbg_printf("lzo.real_free\t%p(%d)\n", ptr, capacity);
delete [] ptr;
}
private:
std::vector<BYTE*> m_freeVector;
} gs_freeMemMgr;
DWORD CLZObject::ms_dwFourCC = MAKEFOURCC('M', 'C', 'O', 'Z');
CLZObject::CLZObject()
{
Initialize();
}
void CLZObject::Initialize()
{
m_bInBuffer = false;
m_pbBuffer = NULL;
m_dwBufferSize = 0;
m_pHeader = NULL;
m_pbIn = NULL;
m_bCompressed = false;
}
void CLZObject::Clear()
{
if (m_pbBuffer && !m_bInBuffer)
gs_freeMemMgr.Free(m_pbBuffer, m_dwBufferSize);
if (m_dwBufferSize > 0)
{
dbg_printf("lzo.free %d\n", m_dwBufferSize);
}
Initialize();
}
CLZObject::~CLZObject()
{
Clear();
}
DWORD CLZObject::GetSize()
{
assert(m_pHeader);
if (m_bCompressed)
{
if (m_pHeader->dwEncryptSize)
return sizeof(THeader) + sizeof(DWORD) + m_pHeader->dwEncryptSize;
else
return sizeof(THeader) + sizeof(DWORD) + m_pHeader->dwCompressedSize;
}
else
return m_pHeader->dwRealSize;
}
void CLZObject::BeginCompress(const void * pvIn, UINT uiInLen)
{
m_pbIn = (const BYTE *) pvIn;
// sizeof(SHeader) +
// 암호화를 위한 fourCC 4바이트
// 압축된 후 만들어질 수 있는 최대 용량 +
// 암호화를 위한 8 바이트
m_dwBufferSize = sizeof(THeader) + sizeof(DWORD) + (uiInLen + uiInLen / 64 + 16 + 3) + 8;
m_pbBuffer = gs_freeMemMgr.Alloc(m_dwBufferSize);
memset(m_pbBuffer, 0, m_dwBufferSize);
m_pHeader = (THeader *) m_pbBuffer;
m_pHeader->dwFourCC = ms_dwFourCC;
m_pHeader->dwEncryptSize = m_pHeader->dwCompressedSize = m_pHeader->dwRealSize = 0;
m_pHeader->dwRealSize = uiInLen;
}
void CLZObject::BeginCompressInBuffer(const void * pvIn, UINT uiInLen, void * /*pvOut*/)
{
m_pbIn = (const BYTE *) pvIn;
// sizeof(SHeader) +
// 암호화를 위한 fourCC 4바이트
// 압축된 후 만들어질 수 있는 최대 용량 +
// 암호화를 위한 8 바이트
m_dwBufferSize = sizeof(THeader) + sizeof(DWORD) + (uiInLen + uiInLen / 64 + 16 + 3) + 8;
m_pbBuffer = gs_freeMemMgr.Alloc(m_dwBufferSize);
memset(m_pbBuffer, 0, m_dwBufferSize);
m_pHeader = (THeader *) m_pbBuffer;
m_pHeader->dwFourCC = ms_dwFourCC;
m_pHeader->dwEncryptSize = m_pHeader->dwCompressedSize = m_pHeader->dwRealSize = 0;
m_pHeader->dwRealSize = uiInLen;
m_bInBuffer = true;
}
bool CLZObject::Compress()
{
UINT iOutLen;
BYTE * pbBuffer;
pbBuffer = m_pbBuffer + sizeof(THeader);
*(DWORD *) pbBuffer = ms_dwFourCC;
pbBuffer += sizeof(DWORD);
#if defined( LZO1X_999_MEM_COMPRESS )
int r = lzo1x_999_compress((BYTE *) m_pbIn, m_pHeader->dwRealSize, pbBuffer, (lzo_uint*) &iOutLen, CLZO::Instance().GetWorkMemory());
#else
int r = lzo1x_1_compress((BYTE *) m_pbIn, m_pHeader->dwRealSize, pbBuffer, (lzo_uint*) &iOutLen, CLZO::Instance().GetWorkMemory());
#endif
if (LZO_E_OK != r)
{
TraceError("LZO: lzo1x_999_compress failed");
return false;
}
m_pHeader->dwCompressedSize = iOutLen;
m_bCompressed = true;
return true;
}
bool CLZObject::BeginDecompress(const void * pvIn)
{
THeader * pHeader = (THeader *) pvIn;
if (pHeader->dwFourCC != ms_dwFourCC)
{
TraceError("LZObject: not a valid data");
return false;
}
m_pHeader = pHeader;
m_pbIn = (const BYTE *) pvIn + (sizeof(THeader) + sizeof(DWORD));
/*
static unsigned sum = 0;
static unsigned count = 0;
sum += pHeader->dwRealSize;
count++;
printf("decompress cur: %d, ave: %d\n", pHeader->dwRealSize, sum/count);
*/
m_dwBufferSize = pHeader->dwRealSize;
m_pbBuffer = gs_freeMemMgr.Alloc(m_dwBufferSize);
memset(m_pbBuffer, 0, pHeader->dwRealSize);
return true;
}
class DecryptBuffer
{
public:
enum
{
LOCAL_BUF_SIZE = 8 * 1024,
};
public:
DecryptBuffer(unsigned size)
{
static unsigned count = 0;
static unsigned sum = 0;
static unsigned maxSize = 0;
sum += size;
count++;
maxSize = max(size, maxSize);
if (size >= LOCAL_BUF_SIZE)
{
m_buf = new char[size];
dbg_printf("DecryptBuffer - AllocHeap %d max(%d) ave(%d)\n", size, maxSize/1024, sum/count);
}
else
{
dbg_printf("DecryptBuffer - AllocStack %d max(%d) ave(%d)\n", size, maxSize/1024, sum/count);
m_buf = m_local_buf;
}
}
~DecryptBuffer()
{
if (m_local_buf != m_buf)
{
dbg_printf("DecruptBuffer - FreeHeap\n");
delete [] m_buf;
}
else
{
dbg_printf("DecruptBuffer - FreeStack\n");
}
}
void* GetBufferPtr()
{
return m_buf;
}
private:
char* m_buf;
char m_local_buf[LOCAL_BUF_SIZE];
};
bool CLZObject::Decompress(DWORD * pdwKey)
{
UINT uiSize;
int r;
if (m_pHeader->dwEncryptSize)
{
DecryptBuffer buf(m_pHeader->dwEncryptSize);
BYTE* pbDecryptedBuffer = (BYTE*)buf.GetBufferPtr();
__Decrypt(pdwKey, pbDecryptedBuffer);
if (*(DWORD *) pbDecryptedBuffer != ms_dwFourCC)
{
TraceError("LZObject: key incorrect");
return false;
}
if (LZO_E_OK != (r = lzo1x_decompress(pbDecryptedBuffer + sizeof(DWORD), m_pHeader->dwCompressedSize, m_pbBuffer, (lzo_uint*) &uiSize, NULL)))
{
TraceError("LZObject: Decompress failed(decrypt) ret %d\n", r);
return false;
}
}
else
{
uiSize = m_pHeader->dwRealSize;
//if (LZO_E_OK != (r = lzo1x_decompress_safe(m_pbIn, m_pHeader->dwCompressedSize, m_pbBuffer, (lzo_uint*) &uiSize, NULL)))
if (LZO_E_OK != (r = lzo1x_decompress(m_pbIn, m_pHeader->dwCompressedSize, m_pbBuffer, (lzo_uint*) &uiSize, NULL)))
{
TraceError("LZObject: Decompress failed : ret %d, CompressedSize %d\n", r, m_pHeader->dwCompressedSize);
return false;
}
}
if (uiSize != m_pHeader->dwRealSize)
{
TraceError("LZObject: Size differs");
return false;
}
return true;
}
bool CLZObject::Encrypt(DWORD * pdwKey)
{
if (!m_bCompressed)
{
assert(!"not compressed yet");
return false;
}
BYTE * pbBuffer = m_pbBuffer + sizeof(THeader);
m_pHeader->dwEncryptSize = tea_encrypt((DWORD *) pbBuffer, (const DWORD *) pbBuffer, pdwKey, m_pHeader->dwCompressedSize + 19);
return true;
}
bool CLZObject::__Decrypt(DWORD * key, BYTE* data)
{
assert(m_pbBuffer);
tea_decrypt((DWORD *) data, (const DWORD *) (m_pbIn - sizeof(DWORD)), key, m_pHeader->dwEncryptSize);
return true;
}
void CLZObject::AllocBuffer(DWORD dwSrcSize)
{
if (m_pbBuffer && !m_bInBuffer)
gs_freeMemMgr.Free(m_pbBuffer, m_dwBufferSize);
m_pbBuffer = gs_freeMemMgr.Alloc(dwSrcSize);
m_dwBufferSize = dwSrcSize;
}
/*
void CLZObject::CopyBuffer(const char* pbSrc, DWORD dwSrcSize)
{
AllocBuffer(dwSrcSize);
memcpy(m_pbBuffer, pbSrc, dwSrcSize);
}
*/
CLZO::CLZO() : m_pWorkMem(NULL)
{
if (lzo_init() != LZO_E_OK)
{
TraceError("LZO: cannot initialize");
return;
}
#if defined( LZO1X_999_MEM_COMPRESS )
m_pWorkMem = (BYTE *) malloc(LZO1X_999_MEM_COMPRESS);
#else
m_pWorkMem = (BYTE *) malloc(LZO1X_1_MEM_COMPRESS);
#endif
if (NULL == m_pWorkMem)
{
TraceError("LZO: cannot alloc memory");
return;
}
}
CLZO::~CLZO()
{
if (m_pWorkMem)
{
free(m_pWorkMem);
m_pWorkMem = NULL;
}
}
bool CLZO::CompressMemory(CLZObject & rObj, const void * pIn, UINT uiInLen)
{
rObj.BeginCompress(pIn, uiInLen);
return rObj.Compress();
}
bool CLZO::CompressEncryptedMemory(CLZObject & rObj, const void * pIn, UINT uiInLen, DWORD * pdwKey)
{
rObj.BeginCompress(pIn, uiInLen);
if (rObj.Compress())
{
if (rObj.Encrypt(pdwKey))
return true;
return false;
}
return false;
}
bool CLZO::Decompress(CLZObject & rObj, const BYTE * pbBuf, DWORD * pdwKey)
{
if (!rObj.BeginDecompress(pbBuf))
return false;
if (!rObj.Decompress(pdwKey))
return false;
return true;
}
BYTE * CLZO::GetWorkMemory()
{
return m_pWorkMem;
}
+101
View File
@@ -0,0 +1,101 @@
/*
* Filename: tea.c
* Description: TEA 암호화 모듈
*
* Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루)
*/
#include "StdAfx.h"
#include "tea.h"
#include <memory.h>
/*
* TEA Encryption Module Instruction
* Edited by 김한주 aka. 비엽, Cronan
*
* void tea_code(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest)
* void tea_decode(const unsigned long sz, const unsigned long sy, const unsigned long *key, unsigned long *dest)
* 8바이트를 암호/복호화 할때 사용된다. key 는 16 바이트여야 한다.
* sz, sy 는 8바이트의 역순으로 대입한다.
*
* int tea_decrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size);
* int tea_encrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size);
* 한꺼번에 8 바이트 이상을 암호/복호화 할때 사용한다. 만약 size 가
* 8의 배수가 아니면 8의 배수로 크기를 "늘려서" 암호화 한다.
*
* ex. tea_code(pdwSrc[1], pdwSrc[0], pdwKey, pdwDest);
* tea_decrypt(pdwDest, pdwSrc, pdwKey, nSize);
*/
#define TEA_ROUND 32 // 32 를 권장하며, 높을 수록 결과가 난해해 진다.
#define DELTA 0x9E3779B9 // DELTA 값 바꾸지 말것.
void tea_code(const tea_word sz, const tea_word sy, const tea_word *key, tea_word *dest) // PORT: tea_word (32-bit Win32 unsigned long)
{
tea_word y = sy, z = sz, sum = 0; // PORT: tea_word (32-bit Win32 unsigned long)
tea_word n = TEA_ROUND; // PORT: tea_word (32-bit Win32 unsigned long)
while (n-- > 0)
{
y += ((z << 4 ^ z >> 5) + z) ^ (sum + key[sum & 3]);
sum += DELTA;
z += ((y << 4 ^ y >> 5) + y) ^ (sum + key[sum >> 11 & 3]);
}
*(dest++) = y;
*dest = z;
}
void tea_decode(const tea_word sz, const tea_word sy, const tea_word *key, tea_word *dest) // PORT: tea_word (32-bit Win32 unsigned long)
{
#pragma warning(disable:4307)
tea_word y = sy, z = sz, sum = DELTA * TEA_ROUND; // PORT: tea_word (32-bit Win32 unsigned long)
#pragma warning(default:4307)
tea_word n = TEA_ROUND; // PORT: tea_word (32-bit Win32 unsigned long)
while (n-- > 0)
{
z -= ((y << 4 ^ y >> 5) + y) ^ (sum + key[sum >> 11 & 3]);
sum -= DELTA;
y -= ((z << 4 ^ z >> 5) + z) ^ (sum + key[sum & 3]);
}
*(dest++) = y;
*dest = z;
}
int tea_encrypt(tea_word *dest, const tea_word *src, const tea_word * key, int size) // PORT: tea_word (32-bit Win32 unsigned long)
{
int i;
int resize;
if (size % 8 != 0)
{
resize = size + 8 - (size % 8);
memset((char *) src + size, 0, resize - size);
}
else
resize = size;
for (i = 0; i < resize >> 3; i++, dest += 2, src += 2)
tea_code(*(src + 1), *src, key, dest);
return (resize);
}
int tea_decrypt(tea_word *dest, const tea_word *src, const tea_word * key, int size) // PORT: tea_word (32-bit Win32 unsigned long)
{
int i;
int resize;
if (size % 8 != 0)
resize = size + 8 - (size % 8);
else
resize = size;
for (i = 0; i < resize >> 3; i++, dest += 2, src += 2)
tea_decode(*(src + 1), *src, key, dest);
return (resize);
}
+10 -2
View File
@@ -1,3 +1,11 @@
// PORT: the 32-bit Win32 unsigned long; on Windows it stays unsigned long so DWORD* callers match.
#if defined(_WIN32)
typedef unsigned long tea_word;
#else
#include <stdint.h>
typedef uint32_t tea_word;
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -11,8 +19,8 @@ extern "C" {
#define TEA_KEY_LENGTH 16
int tea_encrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size);
int tea_decrypt(unsigned long *dest, const unsigned long *src, const unsigned long *key, int size);
int tea_encrypt(tea_word *dest, const tea_word *src, const tea_word *key, int size); // PORT: tea_word (32-bit)
int tea_decrypt(tea_word *dest, const tea_word *src, const tea_word *key, int size); // PORT: tea_word (32-bit)
#ifdef __cplusplus
};
File diff suppressed because it is too large Load Diff
+7 -6
View File
@@ -23,7 +23,7 @@ namespace eterpack
const DWORD c_IndexCC = MAKEFOURCC('E', 'P', 'K', 'D');
const DWORD c_Version = 2;
// FourCC + Version + m_indexCount
const DWORD c_HeaderSize = sizeof(DWORD) + sizeof(DWORD) + sizeof(long);
const DWORD c_HeaderSize = sizeof(DWORD) + sizeof(DWORD) + sizeof(LONG); // PORT: LONG (32-bit) for Win32 long
};
enum EEterPackTypes
@@ -46,20 +46,21 @@ enum EEterPackTypes
#pragma pack(push, 4)
typedef struct SEterPackIndex
{
long id;
LONG id; // PORT: fixed-width Win32 long
char filename[FILENAME_MAX_LEN + 1];
DWORD filename_crc;
long real_data_size;
long data_size;
LONG real_data_size; // PORT: fixed-width Win32 long
LONG data_size; // PORT: fixed-width Win32 long
#ifdef CHECKSUM_CHECK_MD5
BYTE MD5Digest[16];
#else
DWORD data_crc;
#endif
long data_position;
LONG data_position; // PORT: fixed-width Win32 long
char compressed_type;
} TEterPackIndex;
#pragma pack(pop)
static_assert(sizeof(TEterPackIndex) == 192, "TEterPackIndex on-disk layout"); // PORT: on-disk struct
typedef std::unordered_map<DWORD, TEterPackIndex *> TDataPositionMap;
typedef std::list<TEterPackIndex *> TFreeIndexList;
@@ -170,7 +171,7 @@ class CEterPack
char* m_file_data;
unsigned m_file_size;
long m_indexCount;
LONG m_indexCount; // PORT: read as 32-bit from the index header
bool m_bEncrypted;
char m_dbName[DBNAME_MAX_LEN+1];
@@ -0,0 +1,59 @@
#include "StdAfx.h"
#include "EterPackCursor.h"
#include "Inline.h"
CEterPackCursor::CEterPackCursor(CEterPack* pack) : m_pPack(pack), m_pData(NULL), m_ReadPoint(0)
{
}
CEterPackCursor::~CEterPackCursor()
{
Close();
}
bool CEterPackCursor::Open(const char* filename)
{
assert(m_pPack != NULL);
char tmpFilename[MAX_PATH + 1];
strncpy(tmpFilename, filename, MAX_PATH);
inlineConvertPackFilename(tmpFilename);
if (!m_pPack->Get(m_file, tmpFilename, &m_pData))
return false;
return true;
}
void CEterPackCursor::Close()
{
m_file.Destroy();
m_pData = NULL;
m_ReadPoint = 0;
}
void CEterPackCursor::Seek(long offset)
{
m_ReadPoint = max(0, min(Size(), offset));
}
bool CEterPackCursor::Read(LPVOID data, long size)
{
if (m_file.IsNull())
return false;
if (m_ReadPoint + size > Size())
return false;
memcpy(data, (char*) m_pData + m_ReadPoint, size);
m_ReadPoint += size;
return true;
}
long CEterPackCursor::Size()
{
if (m_file.IsNull())
return 0;
return m_file.Size();
}
@@ -0,0 +1,25 @@
#ifndef __INC_ETERPACKCURSOR_H__
#define __INC_ETERPACKCURSOR_H__
#include "EterPack.h"
class CEterPackCursor
{
public:
CEterPackCursor(CEterPack * pack);
~CEterPackCursor();
bool Open(const char* filename);
void Close();
void Seek(long offset);
bool Read(LPVOID data, long size);
long Size();
private:
CEterPack * m_pPack;
CMappedFile m_file;
LPCVOID m_pData;
long m_ReadPoint;
};
#endif
@@ -0,0 +1,621 @@
#include "StdAfx.h"
#include <io.h>
#include <assert.h>
#include "EterPackManager.h"
#include "EterPackPolicy_CSHybridCrypt.h"
#include "../EterBase/Debug.h"
#include "../EterBase/CRC32.h"
#define PATH_ABSOLUTE_YMIRWORK1 "d:/ymir work/"
#define PATH_ABSOLUTE_YMIRWORK2 "d:\\ymir work\\"
#ifdef __THEMIDA__
#include <ThemidaSDK.h>
#endif
CEterPack* CEterPackManager::FindPack(const char* c_szPathName)
{
std::string strFileName;
if (0 == ConvertFileName(c_szPathName, strFileName))
{
return &m_RootPack;
}
else
{
for (TEterPackMap::iterator itor = m_DirPackMap.begin(); itor != m_DirPackMap.end(); ++itor)
{
const std::string & c_rstrName = itor->first;
CEterPack * pEterPack = itor->second;
if (CompareName(c_rstrName.c_str(), c_rstrName.length(), strFileName.c_str()))
{
return pEterPack;
}
}
}
return NULL;
}
void CEterPackManager::SetCacheMode()
{
m_isCacheMode=true;
}
void CEterPackManager::SetRelativePathMode()
{
m_bTryRelativePath = true;
}
// StringPath std::string 버전
int CEterPackManager::ConvertFileName(const char * c_szFileName, std::string & rstrFileName)
{
rstrFileName = c_szFileName;
stl_lowers(rstrFileName);
int iCount = 0;
for (DWORD i = 0; i < rstrFileName.length(); ++i)
{
if (rstrFileName[i] == '/')
++iCount;
else if (rstrFileName[i] == '\\')
{
rstrFileName[i] = '/';
++iCount;
}
}
return iCount;
}
bool CEterPackManager::CompareName(const char * c_szDirectoryName, DWORD /*dwLength*/, const char * c_szFileName)
{
const char * c_pszSrc = c_szDirectoryName;
const char * c_pszCmp = c_szFileName;
while (*c_pszSrc)
{
if (*(c_pszSrc++) != *(c_pszCmp++))
return false;
if (!*c_pszCmp)
return false;
}
return true;
}
void CEterPackManager::LoadStaticCache(const char* c_szFileName)
{
if (!m_isCacheMode)
return;
std::string strFileName;
if (0 == ConvertFileName(c_szFileName, strFileName))
{
return;
}
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
std::unordered_map<DWORD, SCache>::iterator f = m_kMap_dwNameKey_kCache.find(dwFileNameHash);
if (m_kMap_dwNameKey_kCache.end() != f)
return;
CMappedFile kMapFile;
const void* c_pvData;
if (!Get(kMapFile, c_szFileName, &c_pvData))
return;
SCache kNewCache;
kNewCache.m_dwBufSize = kMapFile.Size();
kNewCache.m_abBufData = new BYTE[kNewCache.m_dwBufSize];
memcpy(kNewCache.m_abBufData, c_pvData, kNewCache.m_dwBufSize);
m_kMap_dwNameKey_kCache.insert(std::unordered_map<DWORD, SCache>::value_type(dwFileNameHash, kNewCache));
}
CEterPackManager::SCache* CEterPackManager::__FindCache(DWORD dwFileNameHash)
{
std::unordered_map<DWORD, SCache>::iterator f=m_kMap_dwNameKey_kCache.find(dwFileNameHash);
if (m_kMap_dwNameKey_kCache.end()==f)
return NULL;
return &f->second;
}
void CEterPackManager::__ClearCacheMap()
{
std::unordered_map<DWORD, SCache>::iterator i;
for (i = m_kMap_dwNameKey_kCache.begin(); i != m_kMap_dwNameKey_kCache.end(); ++i)
delete [] i->second.m_abBufData;
m_kMap_dwNameKey_kCache.clear();
}
struct TimeChecker
{
TimeChecker(const char* name) : name(name)
{
baseTime = timeGetTime();
}
~TimeChecker()
{
printf("load %s (%d)\n", name, timeGetTime() - baseTime);
}
const char* name;
DWORD baseTime;
};
bool CEterPackManager::Get(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
{
//TimeChecker timeChecker(c_szFileName);
//Logf(1, "Load %s\n", c_szFileName);
if (m_iSearchMode == SEARCH_FILE_FIRST)
{
if (GetFromFile(rMappedFile, c_szFileName, pData))
{
return true;
}
return GetFromPack(rMappedFile, c_szFileName, pData);
}
if (GetFromPack(rMappedFile, c_szFileName, pData))
{
return true;
}
return GetFromFile(rMappedFile, c_szFileName, pData);
}
struct FinderLock
{
FinderLock(CRITICAL_SECTION& cs) : p_cs(&cs)
{
EnterCriticalSection(p_cs);
}
~FinderLock()
{
LeaveCriticalSection(p_cs);
}
CRITICAL_SECTION* p_cs;
};
bool CEterPackManager::GetFromPack(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
{
FinderLock lock(m_csFinder);
static std::string strFileName;
if (0 == ConvertFileName(c_szFileName, strFileName))
{
return m_RootPack.Get(rMappedFile, strFileName.c_str(), pData);
}
else
{
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
SCache* pkCache = __FindCache(dwFileNameHash);
if (pkCache)
{
rMappedFile.Link(pkCache->m_dwBufSize, pkCache->m_abBufData);
return true;
}
CEterFileDict::Item* pkFileItem = m_FileDict.GetItem(dwFileNameHash, strFileName.c_str());
if (pkFileItem)
if (pkFileItem->pkPack)
{
bool r = pkFileItem->pkPack->Get2(rMappedFile, strFileName.c_str(), pkFileItem->pkInfo, pData);
//pkFileItem->pkPack->ClearDataMemoryMap();
return r;
}
}
#ifdef _DEBUG
TraceError("CANNOT_FIND_PACK_FILE [%s]", strFileName.c_str());
#endif
return false;
}
const time_t g_tCachingInterval = 10; // 10초
void CEterPackManager::ArrangeMemoryMappedPack()
{
//time_t curTime = time(NULL);
//CEterFileDict::TDict dict = m_FileDict.GetDict();
//for (CEterFileDict::TDict::iterator it = dict.begin(); it != dict.end(); ++it)
//{
// CEterFileDict::Item &rFileItem = it->second;
// CEterPack* pkPack = rFileItem.pkPack;
// if (pkPack)
// {
// if (curTime - pkPack->GetLastAccessTime() > g_tCachingInterval)
// {
// pkPack->ClearDataMemoryMap();
// }
// }
//}
}
bool CEterPackManager::GetFromFile(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
{
#ifndef _DEBUG
//const char *pcExt = strchr(c_szFileName, '.');
//if (pcExt &&
// _strnicmp(pcExt, ".py", 3) == 0 && // python 스크립트 중
// stricmp(c_szFileName, "logininfo.py") != 0 && // 로그인 정보 파일이 아니고
// strnicmp(c_szFileName, "locale", 6) != 0
// )
//{
// return false;
//}
#endif
//if(m_bTryRelativePath) {
// if (strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK1, strlen(PATH_ABSOLUTE_YMIRWORK1)) == 0 || strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK2, strlen(PATH_ABSOLUTE_YMIRWORK2)) == 0) {
// if(rMappedFile.Create(c_szFileName+strlen(PATH_ABSOLUTE_YMIRWORK1), pData, 0, 0))
// {
// return true;
// }
// }
//}
return rMappedFile.Create(c_szFileName, pData, 0, 0) ? true : false;
}
bool CEterPackManager::isExistInPack(const char * c_szFileName)
{
std::string strFileName;
if (0 == ConvertFileName(c_szFileName, strFileName))
{
return m_RootPack.IsExist(strFileName.c_str());
}
else
{
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
CEterFileDict::Item* pkFileItem = m_FileDict.GetItem(dwFileNameHash, strFileName.c_str());
if (pkFileItem)
if (pkFileItem->pkPack)
return pkFileItem->pkPack->IsExist(strFileName.c_str());
}
// NOTE : 매치 되는 팩이 없다면 false - [levites]
return false;
}
bool CEterPackManager::isExist(const char * c_szFileName)
{
if (m_iSearchMode == SEARCH_PACK_FIRST)
{
if (isExistInPack(c_szFileName))
return true;
return _access(c_szFileName, 0) == 0 ? true : false;
}
//if(m_bTryRelativePath) {
// if (strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK1, strlen(PATH_ABSOLUTE_YMIRWORK1)) == 0 || strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK2, strlen(PATH_ABSOLUTE_YMIRWORK2)) == 0) {
// if(access(c_szFileName+strlen(PATH_ABSOLUTE_YMIRWORK1), 0) == 0)
// return true;
// }
//}
if (_access(c_szFileName, 0) == 0)
return true;
return isExistInPack(c_szFileName);
}
void CEterPackManager::RegisterRootPack(const char * c_szName)
{
if (!m_RootPack.Create(m_FileDict, c_szName, ""))
{
TraceError("%s: Pack file does not exist", c_szName);
}
}
const char * CEterPackManager::GetRootPackFileName()
{
return m_RootPack.GetDBName();
}
bool CEterPackManager::DecryptPackIV(DWORD dwPanamaKey)
{
TEterPackMap::iterator itor = m_PackMap.begin();
while (itor != m_PackMap.end())
{
itor->second->DecryptIV(dwPanamaKey);
itor++;
}
return true;
}
bool CEterPackManager::RegisterPackWhenPackMaking(const char * c_szName, const char * c_szDirectory, CEterPack* pPack)
{
m_PackMap.insert(TEterPackMap::value_type(c_szName, pPack));
m_PackList.push_front(pPack);
m_DirPackMap.insert(TEterPackMap::value_type(c_szDirectory, pPack));
return true;
}
bool CEterPackManager::RegisterPack(const char * c_szName, const char * c_szDirectory, const BYTE* c_pbIV)
{
CEterPack * pEterPack = NULL;
{
TEterPackMap::iterator itor = m_PackMap.find(c_szName);
if (m_PackMap.end() == itor)
{
bool bReadOnly = true;
pEterPack = new CEterPack;
if (pEterPack->Create(m_FileDict, c_szName, c_szDirectory, bReadOnly, c_pbIV))
{
m_PackMap.insert(TEterPackMap::value_type(c_szName, pEterPack));
}
else
{
#ifdef _DEBUG
Tracef("The eterpack doesn't exist [%s]\n", c_szName);
#endif
delete pEterPack;
pEterPack = NULL;
return false;
}
}
else
{
pEterPack = itor->second;
}
}
if (c_szDirectory && c_szDirectory[0] != '*')
{
TEterPackMap::iterator itor = m_DirPackMap.find(c_szDirectory);
if (m_DirPackMap.end() == itor)
{
m_PackList.push_front(pEterPack);
m_DirPackMap.insert(TEterPackMap::value_type(c_szDirectory, pEterPack));
}
}
return true;
}
void CEterPackManager::SetSearchMode(bool bPackFirst)
{
m_iSearchMode = bPackFirst ? SEARCH_PACK_FIRST : SEARCH_FILE_FIRST;
}
int CEterPackManager::GetSearchMode()
{
return m_iSearchMode;
}
CEterPackManager::CEterPackManager() : m_bTryRelativePath(false), m_iSearchMode(SEARCH_FILE_FIRST), m_isCacheMode(false)
{
InitializeCriticalSection(&m_csFinder);
}
CEterPackManager::~CEterPackManager()
{
__ClearCacheMap();
TEterPackMap::iterator i = m_PackMap.begin();
TEterPackMap::iterator e = m_PackMap.end();
while (i != e)
{
delete i->second;
i++;
}
DeleteCriticalSection(&m_csFinder);
}
void CEterPackManager::RetrieveHybridCryptPackKeys(const BYTE *pStream)
{
////dump file format
//total packagecnt (4byte)
// for packagecntpackage
// db name hash ( stl.h stringhash )
// extension cnt( 4byte)
// for extension cnt
// ext hash ( stl.h stringhash )
// key-16byte
// iv-16byte
int iMemOffset = 0;
int iPackageCnt;
DWORD dwPackageNameHash;
memcpy( &iPackageCnt, pStream + iMemOffset, sizeof(int) );
iMemOffset += sizeof(iPackageCnt);
for( int i = 0; i < iPackageCnt; ++i )
{
int iRecvedCryptKeySize = 0;
memcpy( &iRecvedCryptKeySize, pStream + iMemOffset, sizeof(iRecvedCryptKeySize) );
iRecvedCryptKeySize -= sizeof(dwPackageNameHash); // 서버에서 받은 key stream에는 filename hash가 포함되어 있으므로, hash 사이즈 만큼 배줌.
iMemOffset += sizeof(iRecvedCryptKeySize);
memcpy( &dwPackageNameHash, pStream + iMemOffset, sizeof(dwPackageNameHash) );
iMemOffset += sizeof(dwPackageNameHash);
TEterPackMap::const_iterator cit;
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
{
auto ssvv = std::string(cit->first);
std::string noPathName = CFileNameHelper::NoPath(ssvv);
if( dwPackageNameHash == stringhash().GetHash(noPathName) )
{
EterPackPolicy_CSHybridCrypt* pCryptPolicy = cit->second->GetPackPolicy_HybridCrypt();
int iHavedCryptKeySize = pCryptPolicy->ReadCryptKeyInfoFromStream( pStream + iMemOffset );
if (iRecvedCryptKeySize != iHavedCryptKeySize)
{
TraceError("CEterPackManager::RetrieveHybridCryptPackKeys cryptokey length of file(%s) is not matched. received(%d) != haved(%d)", noPathName.c_str(), iRecvedCryptKeySize, iHavedCryptKeySize);
}
break;
}
}
iMemOffset += iRecvedCryptKeySize;
}
}
void CEterPackManager::RetrieveHybridCryptPackSDB( const BYTE* pStream )
{
//cnt
//for cnt
//DWORD dwPackageIdentifier;
//DWORD dwFileIdentifier;
//std::vector<BYTE> vecSDBStream;
int iReadOffset = 0;
int iSDBInfoCount = 0;
memcpy( &iSDBInfoCount, pStream+iReadOffset, sizeof(int) );
iReadOffset += sizeof(int);
for( int i = 0; i < iSDBInfoCount; ++i )
{
DWORD dwPackgeIdentifier;
memcpy( &dwPackgeIdentifier, pStream+iReadOffset, sizeof(DWORD) );
iReadOffset += sizeof(DWORD);
TEterPackMap::const_iterator cit;
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
{
auto ssvv = std::string(cit->first);
std::string noPathName = CFileNameHelper::NoPath(ssvv);
if( dwPackgeIdentifier == stringhash().GetHash(noPathName) )
{
EterPackPolicy_CSHybridCrypt* pCryptPolicy = cit->second->GetPackPolicy_HybridCrypt();
iReadOffset += pCryptPolicy->ReadSupplementatyDataBlockFromStream( pStream+iReadOffset );
break;
}
}
}
}
void CEterPackManager::WriteHybridCryptPackInfo(const char* pFileName)
{
//NOTE : this file format contains a little bit of redundant data.
//however it`s better for seperating cryptkey & supplementary data block.
//dump file format
//SDB data offset(4)
// about cryptkey
//total packagecnt (4byte)
// for packagecnt
// db name hash 4byte( stl.h stringhash )
// extension cnt( 4byte)
// for extension cnt
// ext hash ( stl.h stringhash )
// key-16byte
// iv-16byte
//about SDB data
//total packagecnt (4byte)
// for packagecnt
// db name hash 4byte( stl.h stringhash ) +child node size(4byte)
// sdb file cnt( 4byte )
// for sdb file cnt
// filename hash ( stl.h stringhash )
// related map name size(4), relate map name
// sdb block size( 1byte )
// sdb blocks
CFileBase keyFile;
if( !keyFile.Create( pFileName, CFileBase::FILEMODE_WRITE) )
{
//TODO : write log
return;
}
int iKeyPackageCount = 0;
//write later ( SDB Offset & PackageCnt for Key )
keyFile.SeekCur(2*sizeof(int));
TEterPackMap::const_iterator cit;
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
{
EterPackPolicy_CSHybridCrypt* pPolicy = cit->second->GetPackPolicy_HybridCrypt();
if( !pPolicy || !pPolicy->IsContainingCryptKey() )
continue;
iKeyPackageCount++;
auto ssvv = std::string(cit->first);
std::string noPathName = CFileNameHelper::NoPath(ssvv);
DWORD dwPackNamehash = stringhash().GetHash(noPathName);
CMakePackLog::GetSingleton().Writef("CEterPackManager::WriteHybridCryptPackInfo PackName : %s, Hash : %x", noPathName.c_str(), dwPackNamehash);
keyFile.Write( &dwPackNamehash, sizeof(DWORD) );
pPolicy->WriteCryptKeyToFile( keyFile );
}
//Write SDB Data
int iSDBDataOffset = keyFile.GetPosition();
int iSDBPackageCnt = 0;
//Write SDB PackageCnt Later
keyFile.SeekCur(sizeof(int));
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
{
EterPackPolicy_CSHybridCrypt* pPolicy = cit->second->GetPackPolicy_HybridCrypt();
if( !pPolicy || !pPolicy->IsContainingSDBFile() )
continue;
iSDBPackageCnt++;
auto ssvv1 = std::string(cit->first);
auto noPathName = CFileNameHelper::NoPath(ssvv1);
DWORD dwPackNamehash = stringhash().GetHash(noPathName);
keyFile.Write( &dwPackNamehash, sizeof(DWORD) );
int iSDBSizeWriteOffset = keyFile.GetPosition();
keyFile.SeekCur(sizeof(int));
pPolicy->WriteSupplementaryDataBlockToFile( keyFile );
int iSDBSizeAfterWrite = keyFile.GetPosition();
keyFile.Seek(iSDBSizeWriteOffset);
int iSDBSize = iSDBSizeAfterWrite-(iSDBSizeWriteOffset+4);
keyFile.Write( &iSDBSize, sizeof(int) );
keyFile.Seek(iSDBSizeAfterWrite);
}
//write sdb data start offset & package cnt
keyFile.Seek(0);
keyFile.Write( &iSDBDataOffset, sizeof(int));
keyFile.Write( &iKeyPackageCount, sizeof(int));
keyFile.Seek(iSDBDataOffset);
keyFile.Write( &iSDBPackageCnt, sizeof(int));
keyFile.Close();
}
@@ -0,0 +1,503 @@
#include "StdAfx.h"
#include "EterPackPolicy_CSHybridCrypt.h"
#include "../EterBase/Stl.h"
#include "../EterBase/Filename.h"
#include "../EterBase/FileBase.h"
#include "../EterBase/CRC32.h"
#include "../EterBase/lzo.h"
#include "../EterBase/Random.h"
#include <cryptopp/modes.h>
#include <cryptopp/osrng.h>
using namespace CryptoPP;
#define CIPHER_MODE CTR_Mode
#ifdef __THEMIDA__
#include <ThemidaSDK.h>
#endif
//Cipher
//Block Size
//Key Length
//
//Default Minimum Maximum
//AES(Rijndael) 16 16 16 32
//Blowfish 8 16 0 56
//Camellia 16 16 16 32
//CAST-128 8 16 5 16
//CAST-256 16 16 16 32
//DES 8 8 8 8
//DES-EDE2 8 16 16 16
//DES-EDE3 8 24 24 24
//DES-XEX3 8 24 24 24
//GOST 8 32 32 32
//IDEA 8 16 16 16
//MARS 16 16 16 56
//RC2 8 16 1 128
//RC5 8 16 0 255
//RC6 16 16 0 255
//SAFER-K 8 16 8 16
//SAFER-SK 8 16 8 16
//Serpent 16 16 1 32
//SHACAL-2 32 16 1 64
//SHARK-E 8 16 1 16
//SKIPJACK 8 10 1 10
//3-Way 12 12 1 12
//Twofish 16 16 0 32
//XTEA 8 16 1 16
inline std::string GetFileExt( std::string& rfileName )
{
stl_lowers(rfileName);
return CFileNameHelper::GetExtension(rfileName);
}
EterPackPolicy_CSHybridCrypt::~EterPackPolicy_CSHybridCrypt()
{
m_mapHybridCryptKey.clear();
m_mapSDBMap.clear();
}
bool EterPackPolicy_CSHybridCrypt::IsContainingCryptKey() const
{
return (m_mapHybridCryptKey.size() > 0) ? true : false;
}
bool EterPackPolicy_CSHybridCrypt::GenerateCryptKey( std::string& rfileName )
{
#ifdef __THEMIDA__
VM_START
#endif
//make lower & extract ext
std::string extName = GetFileExt(rfileName);
stl_lowers(extName);
DWORD dwExtHash = stringhash().GetHash(extName);
TCSHybridCryptKeyMap::const_iterator cit = m_mapHybridCryptKey.find( dwExtHash );
if( cit != m_mapHybridCryptKey.end() )
{
//TODO : log already registered
return false;
}
static AutoSeededRandomPool rnd;
TCSHybridCryptKey info;
{
rnd.GenerateBlock( &(info.uEncryptKey.key[0]), sizeof(info.uEncryptKey) );
rnd.GenerateBlock( &(info.uEncryptIV.iv[0]), sizeof(info.uEncryptIV) );
//for test
/* memset( &info.uEncryptKey.key, 0x10, sizeof(info.uEncryptKey) );
memset( &info.uEncryptIV.iv, 0x10, sizeof(info.uEncryptIV) ); */
}
m_mapHybridCryptKey[dwExtHash] = info;
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
bool EterPackPolicy_CSHybridCrypt::GetPerFileCryptKey( std::string& rfileName, eHybridCipherAlgorithm& eAlgorithm, TEncryptKey& key, TEncryptIV& iv )
{
#ifdef __THEMIDA__
VM_START
#endif
std::string fileNamelower = rfileName;
stl_lowers(fileNamelower);
std::string extName = GetFileExt(fileNamelower);
TCSHybridCryptKeyMap::const_iterator cit = m_mapHybridCryptKey.find( stringhash().GetHash(extName));
if( cit == m_mapHybridCryptKey.end() )
{
//TODO : log no file ext info
return false;
}
DWORD dwfileNameCrc = GetCRC32(fileNamelower.c_str(), fileNamelower.size());
//make file specific algorithm & key & iv
eAlgorithm = (eHybridCipherAlgorithm)(dwfileNameCrc % Num_Of_Ciphers);
::memcpy(key.key, cit->second.uEncryptKey.key, sizeof(key) );
::memcpy(iv.iv, cit->second.uEncryptIV.iv, sizeof(iv) );
//Themida Warning
for( int i = 0; i < (sizeof(key)/sizeof(dwfileNameCrc)); ++i)
{
*((DWORD*)key.key + i) ^= dwfileNameCrc;
}
for( int i = 0; i < (sizeof(iv)/sizeof(dwfileNameCrc)); ++i)
{
*((DWORD*)iv.iv + i) ^= dwfileNameCrc;
}
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
bool EterPackPolicy_CSHybridCrypt::EncryptMemory( std::string& rfileName, IN const BYTE* pSrcData, IN int iSrcLen, OUT CLZObject& zObj )
{
#ifdef __THEMIDA__
VM_START
#endif
eHybridCipherAlgorithm eAlgorithm;
TEncryptKey key;
TEncryptIV iv;
if( !GetPerFileCryptKey( rfileName, eAlgorithm, key, iv ) )
{
return false;
}
// start cipher
std::string strCipher;
//NOTE : ciphered stream size could be different from original size if you choose diffrent cipher mode & algorithm
//( i.e ECB or CBC mode )
strCipher.reserve(iSrcLen);
if( eAlgorithm == e_Cipher_Camellia )
{
// Encryptor
CIPHER_MODE<Camellia>::Encryption Encryptor;
Encryptor.SetKeyWithIV(key.keyCamellia, sizeof(key.keyCamellia), iv.ivCamellia, sizeof(iv.ivCamellia));
ArraySource(pSrcData, iSrcLen, true,
new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher)));
}
else if( eAlgorithm == e_Cipher_Twofish )
{
// Encryptor
CIPHER_MODE<Twofish>::Encryption Encryptor;
Encryptor.SetKeyWithIV(key.keyTwofish, sizeof(key.keyTwofish), iv.ivTwofish, sizeof(iv.ivTwofish));
ArraySource(pSrcData, iSrcLen, true,
new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher)));
}
else if( eAlgorithm == e_Cipher_XTEA )
{
// Encryptor
CIPHER_MODE<XTEA>::Encryption Encryptor;
Encryptor.SetKeyWithIV(key.keyXTEA, sizeof(key.keyXTEA), iv.ivXTEA, sizeof(iv.ivXTEA));
ArraySource(pSrcData, iSrcLen, true,
new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher)));
}
if (strCipher.length() != iSrcLen)
{
//TODO: size error log
return false;
}
zObj.AllocBuffer(iSrcLen);
memcpy(zObj.GetBuffer(), strCipher.c_str(), strCipher.length() );
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
bool EterPackPolicy_CSHybridCrypt::DecryptMemory( std::string& rfilename, IN const BYTE* pEncryptedData, IN int iEncryptedLen, OUT CLZObject& zObj )
{
#ifdef __THEMIDA__
VM_START
#endif
eHybridCipherAlgorithm eAlgorithm;
TEncryptKey key;
TEncryptIV iv;
if( !GetPerFileCryptKey( rfilename, eAlgorithm, key, iv ) )
{
return false;
}
// start decipher
std::string strDecipher;
//NOTE : ciphered stream size could be different from original size if you choose diffrent cipher mode & algorithm
//( i.e ECB or CBC mode )
strDecipher.reserve(iEncryptedLen);
if( eAlgorithm == e_Cipher_Camellia )
{
// Decryptor
CIPHER_MODE<Camellia>::Decryption Decryptor;
Decryptor.SetKeyWithIV(key.keyCamellia, sizeof(key.keyCamellia), iv.ivCamellia, sizeof(iv.ivCamellia));
ArraySource(pEncryptedData, iEncryptedLen, true,
new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher)));
}
else if( eAlgorithm == e_Cipher_Twofish )
{
// Decryptor
CIPHER_MODE<Twofish>::Decryption Decryptor;
Decryptor.SetKeyWithIV(key.keyTwofish, sizeof(key.keyTwofish), iv.ivTwofish, sizeof(iv.ivTwofish));
ArraySource(pEncryptedData, iEncryptedLen, true,
new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher)));
}
else if( eAlgorithm == e_Cipher_XTEA )
{
// Decryptor
CIPHER_MODE<XTEA>::Decryption Decryptor;
Decryptor.SetKeyWithIV(key.keyXTEA, sizeof(key.keyXTEA), iv.ivXTEA, sizeof(iv.ivXTEA));
ArraySource(pEncryptedData, iEncryptedLen, true,
new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher)));
}
if (strDecipher.length() != iEncryptedLen)
{
//TODO: size error log
return false;
}
zObj.AllocBuffer(iEncryptedLen);
memcpy(zObj.GetBuffer(), strDecipher.c_str(), strDecipher.length() );
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
void EterPackPolicy_CSHybridCrypt::WriteCryptKeyToFile( CFileBase& rFile )
{
// ext cnt 4byte
// for ext hash ( crc32 )
// key-16byte
// iv-16byte
DWORD dwCryptKeySize = m_mapHybridCryptKey.size();
rFile.Write( &dwCryptKeySize, sizeof(DWORD) );
TCSHybridCryptKeyMap::const_iterator cit;
for( cit = m_mapHybridCryptKey.begin(); cit != m_mapHybridCryptKey.end(); ++cit )
{
DWORD extNamehash = cit->first;
const TCSHybridCryptKey& CryptKey = cit->second;
rFile.Write( &extNamehash, sizeof(DWORD) );
rFile.Write( CryptKey.uEncryptKey.key, sizeof(TEncryptKey) );
rFile.Write( CryptKey.uEncryptIV.iv, sizeof(TEncryptIV) );
}
}
int EterPackPolicy_CSHybridCrypt::ReadCryptKeyInfoFromStream( IN const BYTE* pStream )
{
int iStreamOffset = 0;
DWORD dwCryptoInfoSize;
memcpy(&dwCryptoInfoSize, pStream, sizeof(DWORD) );
iStreamOffset += sizeof(DWORD);
DWORD dwExtHash;
m_mapHybridCryptKey.clear();
for( int i = 0; i < dwCryptoInfoSize; ++i )
{
memcpy(&dwExtHash, pStream + iStreamOffset, sizeof(DWORD) );
iStreamOffset += sizeof(DWORD);
TCSHybridCryptKey info;
{
memcpy(info.uEncryptKey.key, pStream + iStreamOffset, sizeof(TEncryptKey) );
iStreamOffset += sizeof(TEncryptKey);
memcpy(info.uEncryptIV.iv, pStream + iStreamOffset, sizeof(TEncryptIV) );
iStreamOffset += sizeof(TEncryptIV);
}
m_mapHybridCryptKey[dwExtHash] = info;
}
return iStreamOffset;
}
bool EterPackPolicy_CSHybridCrypt::GenerateSupplementaryDataBlock(std::string& rfilename, const std::string& strMapName, IN const BYTE* pSrcData, IN int iSrcLen, OUT LPBYTE& pDestData, OUT int& iDestLen )
{
#ifdef __THEMIDA__
VM_START
#endif
std::string fileNamelower = rfilename;
stl_lowers( fileNamelower );
DWORD dwFileNameHash = stringhash().GetHash(fileNamelower);
TSupplementaryDataBlockMap::const_iterator cit = m_mapSDBMap.find( dwFileNameHash );
if( cit != m_mapSDBMap.end() )
{
//TODO : log already registered
return false;
}
//TODO : Find Better Method for deciding SDB Postion & Size
//prevent stream copy duplication
TSupplementaryDataBlockInfo info;
m_mapSDBMap[dwFileNameHash] = info;
std::string& strRelatedMapName = m_mapSDBMap[dwFileNameHash].strRelatedMapName;
std::vector<BYTE>& sdbVector = m_mapSDBMap[dwFileNameHash].vecStream;
//fill the data!!
{
strRelatedMapName = strMapName;
int iSDBSize = random_range( 64, 128 );
if( iSrcLen < iSDBSize )
{
iSDBSize = iSrcLen - 1;
if( iSDBSize <= 0 )
{
//TODO : is there 1byte file exist???
return false;
}
}
sdbVector.resize( iSDBSize );
iDestLen = iSrcLen - iSDBSize;
pDestData = (LPBYTE)pSrcData;
memcpy( &sdbVector[0], pDestData + iDestLen, iSDBSize );
}
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
bool EterPackPolicy_CSHybridCrypt::GetSupplementaryDataBlock( std::string& rfilename, OUT LPBYTE& pSDB, OUT int& iSDBSize )
{
#ifdef __THEMIDA__
VM_START
#endif
std::string fileNamelower = rfilename;
stl_lowers( fileNamelower );
DWORD dwFileNameHash = stringhash().GetHash(fileNamelower);
TSupplementaryDataBlockMap::const_iterator cit = m_mapSDBMap.find( dwFileNameHash );
if( cit == m_mapSDBMap.end() )
{
//TODO : log already registered
return false;
}
const std::vector<BYTE>& vecSDB = cit->second.vecStream;
iSDBSize = vecSDB.size();
if(iSDBSize <= 0)
{
pSDB = NULL;
return false;
}
pSDB = (BYTE*)&vecSDB[0];
#ifdef __THEMIDA__
VM_END
#endif
return true;
}
bool EterPackPolicy_CSHybridCrypt::IsContainingSDBFile() const
{
return m_mapSDBMap.size() > 0 ? true : false;
}
void EterPackPolicy_CSHybridCrypt::WriteSupplementaryDataBlockToFile( CFileBase& rFile )
{
//about SDB data
// sdb file cnt( 4byte )
// for sdb file cnt
// filename hash ( stl.h stringhash )
// related map name size(4), relate map name
// sdb block size( 1byte )
// sdb blocks
DWORD dwSDBMapSize = m_mapSDBMap.size();
rFile.Write( &dwSDBMapSize, sizeof(DWORD) );
TSupplementaryDataBlockMap::const_iterator cit;
for( cit = m_mapSDBMap.begin(); cit != m_mapSDBMap.end(); ++cit )
{
DWORD dwFileNamehash = cit->first;
rFile.Write( &dwFileNamehash, sizeof(DWORD) );
const std::string strRelatedMapName = cit->second.strRelatedMapName;
DWORD dwMapNameSize = strRelatedMapName.size();
rFile.Write( &dwMapNameSize, sizeof(DWORD) );
rFile.Write( strRelatedMapName.c_str(), dwMapNameSize );
const std::vector<BYTE>& sdbVector = cit->second.vecStream;
BYTE bSDBSize = (BYTE)(sdbVector.size());
rFile.Write( &bSDBSize, sizeof(bSDBSize) );
if( bSDBSize > 0 )
rFile.Write( &sdbVector[0], bSDBSize );
}
}
int EterPackPolicy_CSHybridCrypt::ReadSupplementatyDataBlockFromStream( IN const BYTE* pStream )
{
#ifdef __THEMIDA__
VM_START
#endif
//DWORD dwFileIdentifier;
//std::vector<BYTE> vecSDBStream;
DWORD dwFileNameHash;
BYTE bSDBSize;
int iStreamOffset = 0;
memcpy(&dwFileNameHash, pStream + iStreamOffset, sizeof(DWORD) );
iStreamOffset += sizeof(DWORD);
memcpy(&bSDBSize, pStream + iStreamOffset, sizeof(BYTE) );
iStreamOffset += sizeof(BYTE);
// NOTE : related map name isn`t required in client. so we don`t recv it from stream to reduce packet size.
TSupplementaryDataBlockInfo info;
{
info.vecStream.resize( bSDBSize );
memcpy(&info.vecStream[0], pStream + iStreamOffset, bSDBSize );
iStreamOffset += bSDBSize;
m_mapSDBMap[dwFileNameHash] = info;
}
#ifdef __THEMIDA__
VM_END
#endif
return iStreamOffset;
}
@@ -0,0 +1,94 @@
#ifndef __INC_ETERPACKLIB_ETERPACKPOLICY_CSHYBRIDCRYPT_H__
#define __INC_ETERPACKLIB_ETERPACKPOLICY_CSHYBRIDCRYPT_H__
#include <unordered_map>
#include <cryptopp/cryptlib.h>
#include <cryptopp/camellia.h>
#include <cryptopp/twofish.h>
#include <cryptopp/tea.h>
enum eHybridCipherAlgorithm
{
e_Cipher_Camellia,
e_Cipher_Twofish,
e_Cipher_XTEA,
Num_Of_Ciphers
};
class CFileBase;
class CLZObject;
//THEMIDA
class EterPackPolicy_CSHybridCrypt
{
public:
~EterPackPolicy_CSHybridCrypt();
bool GenerateCryptKey( std::string& rfileName );
bool EncryptMemory( std::string& rfilename, IN const BYTE* pSrcData, IN int iSrcLen, OUT CLZObject& zObj );
bool DecryptMemory( std::string& rfilename, IN const BYTE* pSrcData, IN int iSrcLen, OUT CLZObject& zObj );
bool IsContainingCryptKey() const;
//Supplementary Data Block (SDB)
bool GenerateSupplementaryDataBlock(std::string& rfilename, const std::string& strMapName, IN const BYTE* pSrcData, IN int iSrcLen, OUT LPBYTE& pDestData, OUT int& iDestLen );
bool GetSupplementaryDataBlock( std::string& rfilename, OUT LPBYTE& pSDB, OUT int& iSDBSize );
bool IsContainingSDBFile() const;
// Read/Write IO
void WriteCryptKeyToFile( CFileBase& rFile );
int ReadCryptKeyInfoFromStream( IN const BYTE* pStream );
void WriteSupplementaryDataBlockToFile( CFileBase& rFile );
int ReadSupplementatyDataBlockFromStream( IN const BYTE* pStream );
protected:
typedef union UEncryptKey
{
BYTE key[16];
BYTE keyCamellia[ CryptoPP::Camellia::DEFAULT_KEYLENGTH];
BYTE keyTwofish [ CryptoPP::Twofish::DEFAULT_KEYLENGTH];
BYTE keyXTEA [ CryptoPP::XTEA::DEFAULT_KEYLENGTH];
} TEncryptKey;
typedef union UEncryptIV
{
BYTE iv[16];
BYTE ivCamellia [ CryptoPP::Camellia::BLOCKSIZE];
BYTE ivTwofish [ CryptoPP::Twofish::BLOCKSIZE];
BYTE ivXTEA [ CryptoPP::XTEA::BLOCKSIZE];
} TEncryptIV;
typedef struct SCSHybridCryptKey
{
TEncryptKey uEncryptKey;
TEncryptIV uEncryptIV;
} TCSHybridCryptKey;
typedef std::unordered_map<DWORD, TCSHybridCryptKey> TCSHybridCryptKeyMap;
TCSHybridCryptKeyMap m_mapHybridCryptKey;
typedef struct SSupplementaryDataBlockInfo
{
std::string strRelatedMapName;
std::vector<BYTE> vecStream;
} TSupplementaryDataBlockInfo;
typedef std::unordered_map<DWORD, TSupplementaryDataBlockInfo> TSupplementaryDataBlockMap; //key filename hash
TSupplementaryDataBlockMap m_mapSDBMap;
private:
bool GetPerFileCryptKey( std::string& rfileName, eHybridCipherAlgorithm& eAlgorithm, TEncryptKey& key, TEncryptIV& iv );
};
#endif // __INC_ETERPACKLIB_ETERPACKPOLICY_CSHYBRIDCRYPT_H__
+34
View File
@@ -0,0 +1,34 @@
#ifndef __INC_ETERPACK_INLINE_H__
#define __INC_ETERPACK_INLINE_H__
inline void inlinePathCreate(const char* path)
{
char dir[64];
const char* p, *k;
p = path + 3;
while (NULL != (k = strchr(p, '/')))
{
memset(dir, 0, sizeof(dir));
strncpy(dir, path, k - path);
CreateDirectory(dir, NULL);
p = k + 1;
}
}
inline void inlineConvertPackFilename(char* name)
{
char * p = name;
while (*p)
{
if (*p == '\\')
*p = '/';
else
*p = (int) tolower(*p);
p++;
}
}
#endif
+2
View File
@@ -0,0 +1,2 @@
#include "StdAfx.h"
+23
View File
@@ -8,6 +8,9 @@
#include <new>
#include <vector>
#include <sys/stat.h>
#include <unistd.h>
static_assert(sizeof(std::recursive_mutex) <= sizeof(CRITICAL_SECTION::storage), "CRITICAL_SECTION storage");
static_assert(alignof(std::recursive_mutex) <= 16, "CRITICAL_SECTION alignment");
@@ -21,6 +24,26 @@ void DeleteCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).~recursive_mute
void EnterCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).lock(); }
void LeaveCriticalSection(LPCRITICAL_SECTION cs) { cs_mutex(cs).unlock(); }
BOOL CreateDirectory(LPCSTR path, void*)
{
return mkdir(path, 0777) == 0 ? TRUE : FALSE;
}
BOOL DeleteFile(LPCSTR path)
{
return unlink(path) == 0 ? TRUE : FALSE;
}
int _access(const char* path, int mode)
{
int m = F_OK;
if (mode & 2)
m |= W_OK;
if (mode & 4)
m |= R_OK;
return access(path, m);
}
char* _strlwr(char* s)
{
for (char* p = s; *p; ++p)
+14
View File
@@ -12,6 +12,14 @@
#if !defined(_WIN32)
#include <strings.h>
#include "Win32MinMax.h"
// mmsystem.h
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
#endif
#define ZeroMemory(dst, len) std::memset((dst), 0, (len))
#define FillMemory(dst, len, fill) std::memset((dst), (fill), (len))
#define CopyMemory(dst, src, len) std::memcpy((dst), (src), (len))
@@ -41,6 +49,12 @@ int _snprintf(char* buf, size_t count, const char* fmt, ...)
#endif
;
// kernel32 file-system calls (ANSI). CreateDirectory ignores the security attributes; _access takes
// the MSVC modes 0 (exists), 2 (write), 4 (read), 6 (read/write).
BOOL CreateDirectory(LPCSTR path, void* security_attributes);
BOOL DeleteFile(LPCSTR path);
int _access(const char* path, int mode);
// winmm `timeGetTime`: milliseconds since system start, wrapping at 2^32.
DWORD timeGetTime();
DWORD GetTickCount();
+13
View File
@@ -0,0 +1,13 @@
#pragma once
// windef.h `min`/`max` macros (40250 builds without NOMINMAX), as functions so <algorithm> and
// numeric_limits<T>::max() keep working: same usual-arithmetic-conversion result as the macro, and a
// same-typed call under `using namespace std` still resolves to the more specialized std::min/max.
// Included by Win32Crt.h off Windows, and force-included on MinGW, whose <windows.h> leaves them out in C++.
#include <type_traits>
#if !defined(min) && !defined(max)
template <class A, class B>
constexpr std::common_type_t<A, B> min(A a, B b) { return (a < b) ? a : b; }
template <class A, class B>
constexpr std::common_type_t<A, B> max(A a, B b) { return (a > b) ? a : b; }
#endif
@@ -0,0 +1,3 @@
#pragma once
// Shim for 40250's <cryptopp/cryptoppLibLink.h>, which only holds MSVC `#pragma comment(lib, ...)` auto-link
// lines; the vendored Crypto++ (mt3p::cryptopp) is linked by CMake.
@@ -0,0 +1,3 @@
#pragma once
// Shim for 40250's <lzo/lzoLibLink.h>, which only holds MSVC `#pragma comment(lib, ...)` auto-link lines;
// the vendored minilzo (mt3p::minilzo) is linked by CMake.
@@ -0,0 +1,3 @@
#pragma once
// Shim for <io.h> on non-Windows targets; what 40250 logic uses from it (_access) is in <windows.h>.
#include "windows.h"