diff --git a/libnpk/CMakeLists.txt b/libnpk/CMakeLists.txt index 6336b33..78320fd 100644 --- a/libnpk/CMakeLists.txt +++ b/libnpk/CMakeLists.txt @@ -11,6 +11,8 @@ set(LIBNPK_SOURCE_FILES ./source/libNPK_Utils.cpp ./source/libNPK_FileStream.h ./source/libNPK_FileStream.cpp + ./source/libNPK_FileList.h + ./source/libNPK_FileList.cpp ) add_library(libNPK STATIC diff --git a/libnpk/libNPK.h b/libnpk/libNPK.h index 43c73c9..a79eb33 100644 --- a/libnpk/libNPK.h +++ b/libnpk/libNPK.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace NPK { @@ -8,6 +11,7 @@ namespace NPK //------------------------------------ class INPKFile; class IFileStream; +class IFileList; //------------------------------------ // NPK file error codes @@ -24,6 +28,7 @@ enum ErrorCode NPK_ERR_FILE_WRITE, NPK_ERR_PARAM, NPK_ERR_INVALID_STATE, + NPK_ERR_NEW_FAILED, //Other errors NPK_ERR_UNKNOWN @@ -39,6 +44,12 @@ INPKFile* createNPKFile(); // destroy an NPK interface void closeNPKFile(INPKFile* npkFile); +// Create empty file list +IFileList* createEmptyFileList(); + +// destroy a file list +void destoryFileList(IFileList* fileList); + // Get the last error code ErrorCode getLastErrorCode(); @@ -48,27 +59,33 @@ const char* getLastErrorMessage(); //------------------------------------ // define the NPK file interface //------------------------------------ +struct FileItemBaseInfo +{ + std::string keyName; // utf8 'common/etc/tribe.img' + uint32_t fileOffset = 0; + uint32_t fileSize = 0; +}; + +struct FileItemFullInfo +{ + std::string npkName; // utf8 'sprite_interface2_hud.npk' + std::string npkBase; // utf8 'd:/dnf/ImagePacks2' + std::string keyName; // 'common/etc/tribe.img' + uint32_t fileOffset = 0; + uint32_t fileSize = 0; + uint32_t fileCRC = 0; +}; + class INPKFile { public: - struct FileNode - { - std::string fileName; - uint32_t fileOffset = 0; - uint32_t fileSize = 0; - }; -public: - virtual bool openPakFile(const char* szPackFileName) = 0; - + virtual bool openPakFile(const wchar_t* wszNpkPathName) = 0; virtual bool closePakFile(void) = 0; - - virtual int32_t getFileCount(void) const = 0; - - virtual bool getFileNode(int32_t index, FileNode& fileNode) const = 0; - + virtual int32_t getFileCounts(void) const = 0; + virtual bool getFileItemBaseInfo(int32_t index, FileItemBaseInfo* baseInfo) const = 0; virtual IFileStream* openFileStream(const char* szFileName) = 0; - virtual void closeFileStream(IFileStream* fileStream) = 0; + virtual IFileList* generateFullInfoList(void) = 0; }; class IFileStream @@ -83,4 +100,13 @@ public: virtual bool isEOF(void) const = 0; }; +class IFileList +{ +public: + virtual int32_t getFileCounts(void) const = 0; + virtual bool getFileItem(int32_t index, FileItemFullInfo* fileItemFullInfo) const = 0; + virtual void addFileNode(const FileItemFullInfo& fileItemFullInfo) = 0; + virtual void mergeOtherListInto(const IFileList* sourceFileList) = 0; +}; + } diff --git a/libnpk/libNPK_Utils.h b/libnpk/libNPK_Utils.h index ea258a4..59f5a2b 100644 --- a/libnpk/libNPK_Utils.h +++ b/libnpk/libNPK_Utils.h @@ -14,6 +14,12 @@ int compareTwoFileName(const char* szFileName1, const char* szFileName2); // Convert a standard ANSI string to a wide string (UTF-16) std::wstring convertAnsiStringToWide(const char* szSource); +// Convert a wide string(UTF-16) to utf8 string +std::string convertWideStringToUtf8(const wchar_t* source); + +// Convert a utf8 string to wide string(UTF-16) +std::wstring convertUtf8StringToWide(const char* szSource); + // Read a file into a buffer and return the buffer pointer. uint8_t* readFileToBuffer(const char* filename, int64_t& outSize); diff --git a/libnpk/source/libNPK_FileList.cpp b/libnpk/source/libNPK_FileList.cpp new file mode 100644 index 0000000..12bdfff --- /dev/null +++ b/libnpk/source/libNPK_FileList.cpp @@ -0,0 +1,43 @@ +#include "libNPK_FileList.h" + +namespace NPK +{ + + +int32_t NPKFileList::getFileCounts(void) const +{ + return (int32_t)m_fileList.size(); +} + +bool NPKFileList::getFileItem(int32_t index, FileItemFullInfo* fullInfo) const +{ + if(index< 0 || index >= getFileCounts()) + { + return false; + } + *fullInfo = m_fileList[index]; + return true; +} + +void NPKFileList::addFileNode(const FileItemFullInfo& fullInfo) +{ + //TODO: check duplicate file name? + m_fileList.push_back(fullInfo); +} + +void NPKFileList::mergeOtherListInto(const IFileList* source) +{ + +} + +IFileList* createEmptyFileList() +{ + return new NPKFileList(); +} + +// destroy a file list +void destoryFileList(IFileList* fileList) +{ + delete ((NPKFileList*)fileList); +} +} diff --git a/libnpk/source/libNPK_FileList.h b/libnpk/source/libNPK_FileList.h new file mode 100644 index 0000000..543c645 --- /dev/null +++ b/libnpk/source/libNPK_FileList.h @@ -0,0 +1,20 @@ +#pragma once + +#include "libNPK.h" +#include + +namespace NPK +{ +class NPKFileList : public IFileList +{ +public: + virtual int32_t getFileCounts(void) const override; + virtual bool getFileItem(int32_t index, FileItemFullInfo* fullInfo) const override; + virtual void addFileNode(const FileItemFullInfo& fullInfo) override; + virtual void mergeOtherListInto(const IFileList* sourceFileList) override; + +private: + std::vector m_fileList; +}; + +} diff --git a/libnpk/source/libNPK_FileStream.cpp b/libnpk/source/libNPK_FileStream.cpp index 7f4c5d9..c2bd747 100644 --- a/libnpk/source/libNPK_FileStream.cpp +++ b/libnpk/source/libNPK_FileStream.cpp @@ -7,12 +7,12 @@ namespace NPK { -CFileStream::CFileStream(CNPKFile* pNPKFile, HANDLE hFile, const INPKFile::FileNode& fileNode) +CFileStream::CFileStream(CNPKFile* pNPKFile, HANDLE hFile, const FileItemBaseInfo& baseFileInfo) : m_pNPKFile(pNPKFile) , m_hFileandle(hFile) - , m_fileName(fileNode.fileName) - , m_fileOffset(fileNode.fileOffset) - , m_fileSize(fileNode.fileSize) + , m_fileName(baseFileInfo.keyName) + , m_fileOffset(baseFileInfo.fileOffset) + , m_fileSize(baseFileInfo.fileSize) , m_currentOffset(0) { diff --git a/libnpk/source/libNPK_FileStream.h b/libnpk/source/libNPK_FileStream.h index f4c97ea..26c3035 100644 --- a/libnpk/source/libNPK_FileStream.h +++ b/libnpk/source/libNPK_FileStream.h @@ -49,7 +49,7 @@ protected: bool m_crc32Calculated = false; private: - CFileStream(CNPKFile* pNPKFile, HANDLE hFile, const INPKFile::FileNode& fileNode); + CFileStream(CNPKFile* pNPKFile, HANDLE hFile, const FileItemBaseInfo& baseFileInfo); virtual ~CFileStream(); friend IFileStream* CNPKFile::openFileStream(const char* szFileName); diff --git a/libnpk/source/libNPK_NPKFile.cpp b/libnpk/source/libNPK_NPKFile.cpp index 5fa5456..94558e0 100644 --- a/libnpk/source/libNPK_NPKFile.cpp +++ b/libnpk/source/libNPK_NPKFile.cpp @@ -3,6 +3,7 @@ #include "libNPK_Errors.h" #include "libEncrypt_SHA256.h" #include "libNPK_FileStream.h" +#include "libNPK_Utils.h" #include @@ -20,13 +21,20 @@ CNPKFile::CNPKFile() CNPKFile::~CNPKFile() { - + if (m_hPakFile != NULL) + { + ::CloseHandle(m_hPakFile); + m_hPakFile = NULL; + } + m_nFileCounts = 0; + m_fileList.clear(); + m_hashFileList.clear(); } -bool CNPKFile::openPakFile(const char* szPackFileName) +bool CNPKFile::openPakFile(const wchar_t* wszNpkPathName) { - assert(szPackFileName); - if (!szPackFileName || szPackFileName[0] == 0) + assert(wszNpkPathName); + if (!wszNpkPathName || wszNpkPathName[0] == 0) { setLastError(NPK_ERR_PARAM); return false; @@ -35,10 +43,15 @@ bool CNPKFile::openPakFile(const char* szPackFileName) //close current pak file if it is open closePakFile(); - m_strPackFileName = szPackFileName; + wchar_t wszNpkBaseName[1024] = { 0 }; + StringCchCopyW(wszNpkBaseName, 1024, wszNpkPathName); + PathRemoveFileSpecW(wszNpkBaseName); + + m_strPackBaseName = convertWideStringToUtf8(wszNpkBaseName); + m_strPackFileName = convertWideStringToUtf8(::PathFindFileNameW(wszNpkPathName)); //open the pak file - m_hPakFile = ::CreateFile(szPackFileName, + m_hPakFile = ::CreateFileW(wszNpkPathName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, @@ -48,7 +61,8 @@ bool CNPKFile::openPakFile(const char* szPackFileName) if (m_hPakFile == INVALID_HANDLE_VALUE) { - setLastError(NPK_ERR_FILE_ACCESS, "File=%s, WinErr=%d", szPackFileName, ::GetLastError()); + setLastError(NPK_ERR_FILE_ACCESS, "File=%s, WinErr=%d", + convertWideStringToUtf8(wszNpkPathName).c_str(), ::GetLastError()); return false; } @@ -67,7 +81,8 @@ bool CNPKFile::openPakFile(const char* szPackFileName) //Check NPK Magic Header if(memcmp(fileHeader.szFileHeadMagic, kNPKFileHeaderMagic, kNPKFileHeaderMagicSize) != 0) { - setLastError(NPK_ERR_INVALID_FILE_FORMAT, "File=%s, Magic=%s", szPackFileName, fileHeader.szFileHeadMagic); + setLastError(NPK_ERR_INVALID_FILE_FORMAT, "File=%s, Magic=%s", + convertWideStringToUtf8(wszNpkPathName).c_str(), fileHeader.szFileHeadMagic); return false; } @@ -94,7 +109,7 @@ bool CNPKFile::openPakFile(const char* szPackFileName) fileInfo.szFileName[j] ^= kNPKFileNameXorCode[j]; } - m_fileList[i].fileName = fileInfo.szFileName; + m_fileList[i].keyName = fileInfo.szFileName; m_fileList[i].fileOffset = fileInfo.fileOffset; m_fileList[i].fileSize = fileInfo.fileSize; } @@ -177,8 +192,8 @@ void CNPKFile::buildHashFileList() m_hashFileList.clear(); for (int32_t i = 0; i < m_nFileCounts; i++) { - const FileNode& fileNode = m_fileList[i]; - m_hashFileList[fileNode.fileName] = i; + const FileItemBaseInfo& baseInfo = m_fileList[i]; + m_hashFileList[baseInfo.keyName] = i; } } @@ -194,13 +209,13 @@ bool CNPKFile::closePakFile(void) return true; } -bool CNPKFile::getFileNode(int32_t index, INPKFile::FileNode& fileNode) const +bool CNPKFile::getFileItemBaseInfo(int32_t index, FileItemBaseInfo* baseInfo) const { - if (index < 0 || index >= getFileCount()) + if (index < 0 || index >= getFileCounts()) { return false; } - fileNode = m_fileList[index]; + *baseInfo = m_fileList[index]; return true; } @@ -231,13 +246,13 @@ IFileStream* CNPKFile::openFileStream(const char* szFileName) fileIndex = it->second; } - if (fileIndex < 0 || fileIndex >= getFileCount()) + if (fileIndex < 0 || fileIndex >= getFileCounts()) { setLastError(NPK_ERR_FILE_NOT_FOUND, "File=%s, FileIndex=%d, not found in NPK file", szFileName, fileIndex); return nullptr; } - FileNode& fileNode = m_fileList[fileIndex]; + FileItemBaseInfo& fileNode = m_fileList[fileIndex]; CFileStream* pFileStream = new CFileStream(this, m_hPakFile, fileNode); return pFileStream; @@ -251,6 +266,47 @@ void CNPKFile::closeFileStream(IFileStream* fileStream) } } +IFileList* CNPKFile::generateFullInfoList(void) +{ + if (m_hPakFile == NULL) + { + setLastError(NPK_ERR_INVALID_STATE, "NPK file is not opened"); + return nullptr; + } + IFileList* pFileList = createEmptyFileList(); + if (!pFileList) + { + setLastError(NPK_ERR_NEW_FAILED, "Failed to create empty file list"); + return nullptr; + } + + for (int32_t i = 0; i < m_nFileCounts; i++) + { + const FileItemBaseInfo& baseInfo = m_fileList[i]; + + FileItemFullInfo fullInfo; + fullInfo.keyName = baseInfo.keyName; + fullInfo.npkName = m_strPackFileName; + fullInfo.npkBase = m_strPackBaseName; + fullInfo.fileSize = baseInfo.fileSize; + fullInfo.fileOffset = baseInfo.fileOffset; + + IFileStream* pFileStream = openFileStream(baseInfo.keyName.c_str()); + if (pFileStream) + { + fullInfo.fileCRC = pFileStream->crc32(); + closeFileStream(pFileStream); + pFileStream = nullptr; + } + else + { + fullInfo.fileCRC = 0; + } + pFileList->addFileNode(fullInfo); // Add file item to the list + } + return pFileList; +} + INPKFile* createNPKFile() { return new CNPKFile(); diff --git a/libnpk/source/libNPK_NPKFile.h b/libnpk/source/libNPK_NPKFile.h index b4b108f..8f52147 100644 --- a/libnpk/source/libNPK_NPKFile.h +++ b/libnpk/source/libNPK_NPKFile.h @@ -28,30 +28,33 @@ public: } FileInfo; public: - virtual bool openPakFile(const char* szPackFileName) override; + virtual bool openPakFile(const wchar_t* wszNpkPathName) override; virtual bool closePakFile(void) override; - virtual int32_t getFileCount(void) const override { + virtual int32_t getFileCounts(void) const override { return m_nFileCounts; } - virtual bool getFileNode(int32_t index, FileNode& fileNode) const override; + virtual bool getFileItemBaseInfo(int32_t index, FileItemBaseInfo* baseInfo) const override; virtual IFileStream* openFileStream(const char* szFileName) override; virtual void closeFileStream(IFileStream* fileStream) override; + virtual IFileList* generateFullInfoList(void); + private: bool checkPakFileHash(void); void buildHashFileList(void); private: - std::string m_strPackFileName; + std::string m_strPackBaseName; //utf8 + std::string m_strPackFileName; //utf8 HANDLE m_hPakFile = NULL; int32_t m_nFileCounts = 0; - typedef std::vector FileList; + typedef std::vector FileList; FileList m_fileList; typedef std::unordered_map FileHashList; diff --git a/libnpk/source/libNPK_Utils.cpp b/libnpk/source/libNPK_Utils.cpp index 015a827..b9499e2 100644 --- a/libnpk/source/libNPK_Utils.cpp +++ b/libnpk/source/libNPK_Utils.cpp @@ -109,6 +109,52 @@ std::wstring convertAnsiStringToWide(const char* szSource) return strReturn; } +std::string convertWideStringToUtf8(const wchar_t* source) +{ + const static int DEFAULT_CHAR_BUF_SIZE = 1024; + char DEFAULT_CHAR_BUF[DEFAULT_CHAR_BUF_SIZE] = { 0 }; + + if(source==nullptr || source[0]==L'\0') + return std::string(); + + int targetLen = WideCharToMultiByte(CP_UTF8, 0, source, -1, nullptr, 0, nullptr, nullptr); + if (targetLen == 0) + return std::string(); + + char* szTemp = 0; + + if (targetLen >= DEFAULT_CHAR_BUF_SIZE) + szTemp = new char[targetLen]; + else + szTemp = DEFAULT_CHAR_BUF; + + WideCharToMultiByte(CP_UTF8, 0, source, -1, szTemp, targetLen, nullptr, nullptr); + + return std::string(szTemp); +} + +std::wstring convertUtf8StringToWide(const char* source) +{ + const static int DEFAULT_WCHAR_BUF_SIZE = 1024; + wchar_t DEFAULT_WCHAR_BUF[DEFAULT_WCHAR_BUF_SIZE] = { 0 }; + + if (source == nullptr || source[0] == '\0') + return std::wstring(); + + int targetLen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, source, -1, nullptr, 0); + if (targetLen == 0) + return std::wstring(); + + wchar_t* wszTemp = 0; + if (targetLen >= DEFAULT_WCHAR_BUF_SIZE) + wszTemp = new wchar_t[targetLen]; + else + wszTemp = DEFAULT_WCHAR_BUF; + + int result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, source, -1, wszTemp, targetLen); + return std::wstring(wszTemp); +} + uint8_t* readFileToBuffer(const char* filename, int64_t& outSize) { FILE* file = nullptr; diff --git a/sgutil/CMakeLists.txt b/sgutil/CMakeLists.txt index fb110a3..3fcb573 100644 --- a/sgutil/CMakeLists.txt +++ b/sgutil/CMakeLists.txt @@ -26,8 +26,12 @@ add_executable(sgutil sgu_mode_npk_dump_list.cpp sgu_mode_npk_extract_files.h sgu_mode_npk_extract_files.cpp + sgu_mode_run_lua_file.h + sgu_mode_run_lua_file.cpp sgu_utils.cpp sgu_utils.h + sgu_lua_npk_file.h + sgu_lua_npk_file.cpp ) target_include_directories(sgutil diff --git a/sgutil/sgu_lua_npk_file.cpp b/sgutil/sgu_lua_npk_file.cpp new file mode 100644 index 0000000..55c8e00 --- /dev/null +++ b/sgutil/sgu_lua_npk_file.cpp @@ -0,0 +1,197 @@ +#include "sgu_lua_npk_file.h" +#include "libNPK_Utils.h" + +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +}; + +#include "lua_tinker.h" + +//////////////////////////////////////////////////////////////////////////////////// +void LuaNPKFile::registerLuaApi(lua_State* L) +{ + lua_tinker::def(L, "createNPKFile", &LuaNPKFile::create); + lua_tinker::def(L, "destroyNPKFile", &LuaNPKFile::destroy); + lua_tinker::def(L, "createEmptyFileList", &LuaNPKFileList::createEmpty); + lua_tinker::def(L, "destroyFileList", &LuaNPKFileList::destroy); + + lua_tinker::class_add(L, "NPKFile"); + lua_tinker::class_def(L, "openPakFile", &LuaNPKFile::openPakFile); + lua_tinker::class_def(L, "closePakFile", &LuaNPKFile::closePakFile); + lua_tinker::class_def(L, "getFileCounts", &LuaNPKFile::getFileCounts); + lua_tinker::class_def(L, "getFileNode", &LuaNPKFile::getFileNode); + lua_tinker::class_def(L, "openFileStream", &LuaNPKFile::openFileStream); + lua_tinker::class_def(L, "closeFileStream", &LuaNPKFile::closeFileStream); + lua_tinker::class_def(L, "generateFullInfoList", &LuaNPKFile::generateFullInfoList); + + lua_tinker::class_add(L, "NPKFileItemBaseInfo"); + lua_tinker::class_def(L, "keyName", &LuaNPKFileItemBaseInfo::c_keyName); + lua_tinker::class_mem(L, "fileOffset", &LuaNPKFileItemBaseInfo::fileOffset); + lua_tinker::class_mem(L, "fileSize", &LuaNPKFileItemBaseInfo::fileSize); + + lua_tinker::class_add(L, "LuaNPKFileItemFullInfo"); + lua_tinker::class_def(L, "npkName", &LuaNPKFileItemFullInfo::c_npkName); + lua_tinker::class_def(L, "npkBase", &LuaNPKFileItemFullInfo::c_npkBase); + lua_tinker::class_def(L, "keyName", &LuaNPKFileItemFullInfo::c_keyName); + lua_tinker::class_mem(L, "fileOffset", &LuaNPKFileItemFullInfo::fileOffset); + lua_tinker::class_mem(L, "fileSize", &LuaNPKFileItemFullInfo::fileSize); + lua_tinker::class_mem(L, "fileCRC", &LuaNPKFileItemFullInfo::fileCRC); + + lua_tinker::class_add(L, "LuaNPKFileList"); + lua_tinker::class_def(L, "getFileCounts", &LuaNPKFileList::getFileCounts); + lua_tinker::class_def(L, "getFileItem", &LuaNPKFileList::getFileItem); + + lua_tinker::class_add(L, "NPKFileStream"); + lua_tinker::class_def(L, "name", &LuaNPKFileStream::name); + lua_tinker::class_def(L, "size", &LuaNPKFileStream::size); + lua_tinker::class_def(L, "read", &LuaNPKFileStream::read); + lua_tinker::class_def(L, "seek", &LuaNPKFileStream::seek); + lua_tinker::class_def(L, "tell", &LuaNPKFileStream::tell); + lua_tinker::class_def(L, "crc32", &LuaNPKFileStream::crc32); + lua_tinker::class_def(L, "isEOF", &LuaNPKFileStream::isEOF); +} + +LuaNPKFile* LuaNPKFile::create() +{ + return new LuaNPKFile(); +} + +void LuaNPKFile::destroy(LuaNPKFile* instance) +{ + delete instance; +} + +LuaNPKFile::LuaNPKFile() +{ + m_pNPKFile = NPK::createNPKFile(); +} + +LuaNPKFile::~LuaNPKFile() +{ + closeNPKFile(m_pNPKFile); + m_pNPKFile = nullptr; +} + +bool LuaNPKFile::openPakFile(const char* szPackFileName) +{ + std::wstring strFullName = convertUtf8StringToWide(szPackFileName); + + return m_pNPKFile && m_pNPKFile->openPakFile(strFullName.c_str()); +} + +bool LuaNPKFile::closePakFile(void) +{ + return m_pNPKFile && m_pNPKFile->closePakFile(); +} + +int32_t LuaNPKFile::getFileCounts(void) const +{ + return m_pNPKFile ? m_pNPKFile->getFileCounts() : 0; +} + +LuaNPKFileItemBaseInfo LuaNPKFile::getFileNode(int32_t index) const +{ + LuaNPKFileItemBaseInfo baseInfo; + m_pNPKFile->getFileItemBaseInfo(index, &baseInfo); + return baseInfo; +} + +LuaNPKFileList* LuaNPKFile::generateFullInfoList() +{ + LuaNPKFileList* fileList = new LuaNPKFileList(); + fileList->m_pFileList = m_pNPKFile->generateFullInfoList(); + return fileList; +} + +LuaNPKFileStream* LuaNPKFile::openFileStream(const char* szFileName) +{ + if(m_pNPKFile) + { + LuaNPKFileStream* fileStream = new LuaNPKFileStream(); + fileStream->m_pFileStream = m_pNPKFile->openFileStream(szFileName); + if (fileStream->m_pFileStream) + { + return fileStream; + } + delete fileStream; + } + return nullptr; +} + +void LuaNPKFile::closeFileStream(LuaNPKFileStream* fileStream) +{ + if (m_pNPKFile && fileStream) + { + m_pNPKFile->closeFileStream(fileStream->m_pFileStream); + fileStream->m_pFileStream = nullptr; + } + delete fileStream; +} + +//////////////////////////////////////////////////////////////////////////////////// +const char* LuaNPKFileStream::name(void) const +{ + return m_pFileStream ? m_pFileStream->name() : nullptr; +} + +uint32_t LuaNPKFileStream::size(void) const +{ + return m_pFileStream ? m_pFileStream->size() : 0; +} + +uint32_t LuaNPKFileStream::read(void* buffer, uint32_t size) +{ + return m_pFileStream ? m_pFileStream->read(buffer, size) : 0; +} + +bool LuaNPKFileStream::seek(uint32_t offset) +{ + return m_pFileStream ? m_pFileStream->seek(offset) : false; +} + +uint32_t LuaNPKFileStream::tell(void) const +{ + return m_pFileStream ? m_pFileStream->tell() : 0; +} + +uint32_t LuaNPKFileStream::crc32(void) +{ + return m_pFileStream ? m_pFileStream->crc32() : 0; +} + +bool LuaNPKFileStream::isEOF(void) const +{ + return m_pFileStream ? m_pFileStream->isEOF() : true; +} + +/// ///////////////////////////////////////////////////////////////////////////////// +LuaNPKFileList* LuaNPKFileList::createEmpty() +{ + LuaNPKFileList* pNewLuaFileList = new LuaNPKFileList(); + pNewLuaFileList->m_pFileList = NPK::createEmptyFileList(); + return pNewLuaFileList; +} + +void LuaNPKFileList::destroy(LuaNPKFileList* instance) +{ + NPK::destoryFileList(instance->m_pFileList); + delete instance; +} + +int32_t LuaNPKFileList::getFileCounts(void) const +{ + return m_pFileList ? m_pFileList->getFileCounts() : 0; +} + +LuaNPKFileItemFullInfo LuaNPKFileList::getFileItem(int32_t index) const +{ + LuaNPKFileItemFullInfo fullInfo; + if (m_pFileList) + { + m_pFileList->getFileItem(index, &fullInfo); + } + return fullInfo; +} diff --git a/sgutil/sgu_lua_npk_file.h b/sgutil/sgu_lua_npk_file.h new file mode 100644 index 0000000..5ed805a --- /dev/null +++ b/sgutil/sgu_lua_npk_file.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include "libNPK.h" + + +struct LuaNPKFileItemBaseInfo : public NPK::FileItemBaseInfo +{ + const char* c_keyName() const { return keyName.c_str(); } +}; + +struct LuaNPKFileItemFullInfo : public NPK::FileItemFullInfo +{ + const char* c_npkName() const { return npkName.c_str(); } + const char* c_npkBase() const { return npkBase.c_str(); } + const char* c_keyName() const { return keyName.c_str(); } +}; + +class LuaNPKFileStream +{ +public: + const char* name(void) const; + uint32_t size(void) const; + uint32_t read(void* buffer, uint32_t size); + bool seek(uint32_t offset); + uint32_t tell(void) const; + uint32_t crc32(void); + bool isEOF(void) const; + + NPK::IFileStream* m_pFileStream = nullptr; +}; + +class LuaNPKFileList +{ +public: + static LuaNPKFileList* createEmpty(); + static void destroy(LuaNPKFileList* instance); +public: + int32_t getFileCounts(void) const; + LuaNPKFileItemFullInfo getFileItem(int32_t index) const; + +public: + NPK::IFileList* m_pFileList = nullptr; +}; + +class LuaNPKFile +{ +public: + static void registerLuaApi(struct lua_State* L); + static LuaNPKFile* create(); + static void destroy(LuaNPKFile* instance); + +public: + bool openPakFile(const char* szPackFileName); + bool closePakFile(void); + int32_t getFileCounts(void) const; + + LuaNPKFileList* generateFullInfoList(); + + LuaNPKFileItemBaseInfo getFileNode(int32_t index) const; + LuaNPKFileStream* openFileStream(const char* szFileName); + void closeFileStream(LuaNPKFileStream* fileStream); + +public: + NPK::INPKFile* m_pNPKFile = nullptr; + +public: + LuaNPKFile(); + ~LuaNPKFile(); +}; diff --git a/sgutil/sgu_main.cpp b/sgutil/sgu_main.cpp index 6462697..610ec32 100644 --- a/sgutil/sgu_main.cpp +++ b/sgutil/sgu_main.cpp @@ -11,9 +11,100 @@ #include "sgu_mode_npk_dump_list.h" #include "sgu_mode_npk_extract_files.h" #include "sgu_mode_download.h" +#include "sgu_mode_run_lua_file.h" #include "libEncrypt_AES.h" +//int TestFunc(lua_State* L) +//{ +// printf("# TestFunc\n"); +// return lua_yield(L, 0); +//} +// +//int TestFunc2(lua_State* L, float a) +//{ +// printf("# TestFunc2(L,%f)\n", a); +// return lua_yield(L, 0); +//} +// +//class TestClass +//{ +//public: +// +// int TestFunc(lua_State* L, int a) +// { +// m_data = a; +// printf("# TestClass::TestFunc\n"); +// return lua_yield(L, 0); +// } +// +// int TestFunc2(lua_State* L, float a) +// { +// printf("# TestClass::TestFunc2(L,%d, %f)\n", m_data, a); +// return lua_yield(L, 0); +// } +// +//private: +// int m_data; +//}; +// +//int foo() +//{ +// lua_State* L = lua_open(); +// luaopen_base(L); +// luaopen_string(L); +// +// lua_tinker::def(L, "TestFunc", &TestFunc); +// lua_tinker::def(L, "TestFunc2", &TestFunc2); +// +// lua_tinker::class_add(L, "TestClass"); +// lua_tinker::class_def(L, "TestFunc", &TestClass::TestFunc); +// lua_tinker::class_def(L, "TestFunc2", &TestClass::TestFunc2); +// +// TestClass g_test; +// lua_tinker::set(L, "g_test", &g_test); +// +// +// +// lua_tinker::dostring(L, +// "function ThreadTest()\n" +// " print(\"ThreadTest\")\n" +// +// " print(\"TestFunc Begin\")" +// " TestFunc()\n" +// " TestFunc2(1.2)\n" +// " print(\"TestFunc End\")\n" +// +// " print(\"g_test::TestFunc()\")\n" +// " g_test:TestFunc(123)\n" +// " g_test:TestFunc2(2.3)\n" +// " print(\"g_test::TestFunc()\")\n" +// "end\n" +// ); +// +// lua_newthread(L); +// lua_pushstring(L, "ThreadTest"); +// lua_gettable(L, LUA_GLOBALSINDEX); +// +// printf("* lua_resume() 1\n"); +// lua_resume(L, 0); +// +// printf("* lua_resume() 2\n"); +// lua_resume(L, 0); +// +// printf("* lua_resume() 3\n"); +// lua_resume(L, 0); +// +// printf("* lua_resume() 4\n"); +// lua_resume(L, 0); +// +// printf("* lua_resume() 5\n"); +// lua_resume(L, 0); +// +// lua_close(L); +// +// return 0; +//} //////////////////////////////////////////////////////////////////////////////////////////// enum { OPT_MODE, OPT_INPUT, OPT_INPUT2, OPT_OUTPUT, @@ -65,6 +156,7 @@ static void printUsage(const char* moduleName) printf(" NPKDumpList\tDumps the file list from an NPK archive to a text file.\n"); printf(" NPKExtractFiles\tExtracts all files from an NPK archive to a specified output directory.\n"); printf(" HttpDownload\tDownloads a file from a specified URL and saves it to a local file.\n"); + printf(" RunLuaFile\t xxxx \n"); printf("\nSample:\n"); printf(" -m GenRandFile -min 500 -max 1k -o rand.bin\n"); printf(" -m RandModifyFile -i ver01.bin -min 100 -max 1k -c 3 -o ver02.bin\n"); @@ -77,6 +169,7 @@ static void printUsage(const char* moduleName) printf(" -m NPKDumpList -i abc.npk -o abc_file_list.txt\n"); printf(" -m NPKExtractFiles -i abc.npk -o output\n"); printf(" -m HttpDownload -i http://download.com/file.txt -o file.txt\n"); + printf(" -m RunLuaFile -i script.lua\n"); } enum WorkMode { @@ -92,6 +185,7 @@ enum WorkMode { WM_HTTP_DOWNLOAD, WM_NPK_DUMPLIST, WM_NPK_EXTRACT_FILES, + WM_RUN_LUA_FILE, }; enum HashType { @@ -138,6 +232,9 @@ WorkMode parserWorkMode(const char* modeStr) else if (_stricmp(modeStr, "NPKExtractFiles") == 0) { return WM_NPK_EXTRACT_FILES; } + else if (_stricmp(modeStr, "RunLuaFile") == 0) { + return WM_RUN_LUA_FILE; + } return WM_NONE; } @@ -418,7 +515,22 @@ int main(int argc, char* argv[]) } } break; - + case WM_RUN_LUA_FILE: + { + if (inputFilename == nullptr) + { + printf("Error: For 'RunLuaFile' mode, you must specify input Lua script file.\n"); + printUsage(::PathFindFileNameA(argv[0])); + return 1; + } + printf("Running Lua script file: %s\n", inputFilename); + if (!run_lua_file(inputFilename)) + { + printf("Error: Failed to run Lua script file.\n"); + return 1; + } + } + break; case WM_NONE: default: { diff --git a/sgutil/sgu_mode_npk_dump_list.cpp b/sgutil/sgu_mode_npk_dump_list.cpp index 24630a5..4483e27 100644 --- a/sgutil/sgu_mode_npk_dump_list.cpp +++ b/sgutil/sgu_mode_npk_dump_list.cpp @@ -16,7 +16,9 @@ bool dumpNPKFileList(const char* inputFilename, const char* outputFilename) return false; } NPK::INPKFile* pakFile = NPK::createNPKFile(); - if (!(pakFile->openPakFile(inputFilename))) + + std::wstring strFullName = convertAnsiStringToWide(inputFilename); + if (!(pakFile->openPakFile(strFullName.c_str()))) { printf("Error: Failed to open NPK file: %s, ErrorCode:%d\n", inputFilename, NPK::getLastErrorCode()); return false; @@ -28,27 +30,27 @@ bool dumpNPKFileList(const char* inputFilename, const char* outputFilename) printf("Error: Failed to open output file: %s\n", outputFilename); return false; } - int32_t fileCount = pakFile->getFileCount(); + int32_t fileCount = pakFile->getFileCounts(); // Dump file list for(int32_t i=0; i < fileCount; i++) { - NPK::INPKFile::FileNode fileNode; - if (!pakFile->getFileNode(i, fileNode)) + NPK::FileItemBaseInfo baseInfo; + if (!pakFile->getFileItemBaseInfo(i, &baseInfo)) { printf("Error: Failed to get file node at index %d\n", i); fclose(fpOutput); return false; } - NPK::IFileStream* fileStream = pakFile->openFileStream(fileNode.fileName.c_str()); + NPK::IFileStream* fileStream = pakFile->openFileStream(baseInfo.keyName.c_str()); if (!fileStream) { - printf("Error: Failed to open file stream for '%s', Error=%s\n", fileNode.fileName.c_str(), NPK::getLastErrorMessage()); + printf("Error: Failed to open file stream for '%s', Error=%s\n", baseInfo.keyName.c_str(), NPK::getLastErrorMessage()); fclose(fpOutput); return false; } uint32_t crc32 = fileStream->crc32(); - fprintf(fpOutput, "%s\t%08x\t%u\n", fileNode.fileName.c_str(), crc32, fileNode.fileSize); + fprintf(fpOutput, "%s\t%08x\t%u\n", baseInfo.keyName.c_str(), crc32, baseInfo.fileSize); pakFile->closeFileStream(fileStream); } diff --git a/sgutil/sgu_mode_npk_extract_files.cpp b/sgutil/sgu_mode_npk_extract_files.cpp index 812e237..e8a99f6 100644 --- a/sgutil/sgu_mode_npk_extract_files.cpp +++ b/sgutil/sgu_mode_npk_extract_files.cpp @@ -21,19 +21,21 @@ bool extractNPKFiles(const char* szNPKFileName, const char* szOutputDir) { return false; // Failed to create NPK file interface } - if (!npkFile->openPakFile(szNPKFileName)) + + std::wstring strFullName = convertAnsiStringToWide(szNPKFileName); + if (!(npkFile->openPakFile(strFullName.c_str()))) { printf("Failed to open NPK file: '%s', Error=%s\n", szNPKFileName, NPK::getLastErrorMessage()); NPK::closeNPKFile(npkFile); return false; // Failed to open NPK file } - int32_t fileCount = npkFile->getFileCount(); + int32_t fileCount = npkFile->getFileCounts(); for (int32_t i = 0; i < fileCount; ++i) { - NPK::INPKFile::FileNode fileNode; - if (npkFile->getFileNode(i, fileNode)) + NPK::FileItemBaseInfo baseInfo; + if (!npkFile->getFileItemBaseInfo(i, &baseInfo)) { - std::string outputPathName = std::string(szOutputDir) + "/" + fileNode.fileName; + std::string outputPathName = std::string(szOutputDir) + "/" + baseInfo.keyName; char szOutputPath[MAX_PATH]; StringCbCopyA(szOutputPath, sizeof(szOutputPath), outputPathName.c_str()); @@ -46,10 +48,11 @@ bool extractNPKFiles(const char* szNPKFileName, const char* szOutputDir) return false; } - NPK::IFileStream* fileStream = npkFile->openFileStream(fileNode.fileName.c_str()); + NPK::IFileStream* fileStream = npkFile->openFileStream(baseInfo.keyName.c_str()); if(fileStream == nullptr) { - printf("Error: Failed to open file stream for '%s', Error=%s\n", fileNode.fileName.c_str(), NPK::getLastErrorMessage()); + printf("Error: Failed to open file stream for '%s', Error=%s\n", + baseInfo.keyName.c_str(), NPK::getLastErrorMessage()); NPK::closeNPKFile(npkFile); return false; } diff --git a/sgutil/sgu_mode_run_lua_file.cpp b/sgutil/sgu_mode_run_lua_file.cpp new file mode 100644 index 0000000..6f69201 --- /dev/null +++ b/sgutil/sgu_mode_run_lua_file.cpp @@ -0,0 +1,33 @@ +#include "sgu_mode_run_lua_file.h" +#include "sgu_lua_npk_file.h" + +#include "libNPK.h" + +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +}; + +#include "lua_tinker.h" + +bool run_lua_file(const char* szLuaFilename) +{ + lua_State* L = lua_open(); + luaL_openlibs(L); + + //register global functions + lua_tinker::def(L, "getLastErrorCode", &NPK::getLastErrorCode); + lua_tinker::def(L, "getLastErrorMessage", &NPK::getLastErrorMessage); + + //register classes + LuaNPKFile::registerLuaApi(L); + + //run lua file + lua_tinker::dofile(L, szLuaFilename); + + //cleanup + lua_close(L); + return true; +} \ No newline at end of file diff --git a/sgutil/sgu_mode_run_lua_file.h b/sgutil/sgu_mode_run_lua_file.h new file mode 100644 index 0000000..09b3f19 --- /dev/null +++ b/sgutil/sgu_mode_run_lua_file.h @@ -0,0 +1,3 @@ +#pragma once + +bool run_lua_file(const char* szLuaFilename);