diff --git a/libnpk/libNPK.h b/libnpk/libNPK.h index a79eb33..f8b5858 100644 --- a/libnpk/libNPK.h +++ b/libnpk/libNPK.h @@ -29,7 +29,7 @@ enum ErrorCode NPK_ERR_PARAM, NPK_ERR_INVALID_STATE, NPK_ERR_NEW_FAILED, - + NPK_ERR_FILE_CREATE, //Other errors NPK_ERR_UNKNOWN }; @@ -98,6 +98,8 @@ public: virtual uint32_t tell(void) const = 0; virtual uint32_t crc32(void) = 0; virtual bool isEOF(void) const = 0; + + virtual bool writeToDiskFile(const wchar_t* diskPathFile) = 0; }; class IFileList diff --git a/libnpk/libNPK_Utils.h b/libnpk/libNPK_Utils.h index 59f5a2b..d8e6cb2 100644 --- a/libnpk/libNPK_Utils.h +++ b/libnpk/libNPK_Utils.h @@ -33,7 +33,10 @@ bool clearPath(const char* szPath, bool recursion, bool removeSelf); bool createEmptyPath(const char* szPath); // Force create a directory path, ensuring all parent directories are created as needed. -bool forceCreatePath(const char* szPath); +bool forceCreatePath(const wchar_t* szPath); + +// Force create a directory path for the file +bool forceCreatePathForFile(const wchar_t* szFilePath); // Get the parent directory path of the specified path. -void getParentPath(char* szPath); +void getParentPath(wchar_t* szPath); diff --git a/libnpk/source/libNPK_FileStream.cpp b/libnpk/source/libNPK_FileStream.cpp index c2bd747..1c16b98 100644 --- a/libnpk/source/libNPK_FileStream.cpp +++ b/libnpk/source/libNPK_FileStream.cpp @@ -84,4 +84,46 @@ uint32_t CFileStream::crc32(void) return m_crc32; } +bool CFileStream::writeToDiskFile(const wchar_t* diskPathFile) +{ + HANDLE hFile = ::CreateFileW(diskPathFile, + FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + CREATE_ALWAYS, + FILE_ATTRIBUTE_ARCHIVE, + 0); + + if (hFile == INVALID_HANDLE_VALUE) + { + setLastError(NPK_ERR_FILE_CREATE, "Failed to open output file for writing, LastError=%d.", ::GetLastError()); + return false; // Failed to open output file + } + + //store current read offset + uint32_t currentOffset = m_currentOffset; + m_currentOffset = 0; + + //read loop + char buffer[4096] = { 0 }; + uint32_t bytesRead = 0; + + while ((bytesRead = this->read(buffer, sizeof(buffer))) > 0) + { + DWORD dwWriteBytes = 0; + if (!WriteFile(hFile, buffer, bytesRead, &dwWriteBytes, 0) || + dwWriteBytes != bytesRead) + { + setLastError(NPK_ERR_FILE_WRITE, "Failed to write to output file, LastError=%d", ::GetLastError()); + + CloseHandle(hFile); + m_currentOffset = currentOffset; + return false; // Failed to write to output file + } + } + CloseHandle(hFile); + m_currentOffset = currentOffset; + return true; +} + } diff --git a/libnpk/source/libNPK_FileStream.h b/libnpk/source/libNPK_FileStream.h index 26c3035..953fca0 100644 --- a/libnpk/source/libNPK_FileStream.h +++ b/libnpk/source/libNPK_FileStream.h @@ -31,6 +31,8 @@ public: return m_currentOffset >= m_fileSize; } + virtual bool writeToDiskFile(const wchar_t* diskPathFile); + protected: //Pack file CNPKFile* m_pNPKFile; @@ -38,9 +40,9 @@ protected: HANDLE m_hFileandle; std::string m_fileName; //offset of the file in the pak file - uint32_t m_fileOffset = 0; + const uint32_t m_fileOffset = 0; //size of the file - uint32_t m_fileSize = 0; + const uint32_t m_fileSize = 0; //current read offset in the file uint32_t m_currentOffset = 0; //CRC32 checksum of the file diff --git a/libnpk/source/libNPK_Utils.cpp b/libnpk/source/libNPK_Utils.cpp index b9499e2..0305114 100644 --- a/libnpk/source/libNPK_Utils.cpp +++ b/libnpk/source/libNPK_Utils.cpp @@ -258,34 +258,42 @@ bool createEmptyPath(const char* szPath) return true; } -void getParentPath(char* szPath) +void getParentPath(wchar_t* szPath) { if (!szPath || szPath[0] == 0) return; - size_t length = strlen(szPath); - std::replace(szPath, szPath+length, '/', '\\'); + size_t length = wcslen(szPath); + std::replace(szPath, szPath+length, L'/', L'\\'); - ::PathRemoveFileSpecA(szPath); + ::PathRemoveFileSpecW(szPath); } -bool forceCreatePath(const char* szPath) +bool forceCreatePath(const wchar_t* szPath) { - char szCurrentPath[MAX_PATH] = { 0 }; - StringCchCopyA(szCurrentPath, MAX_PATH, szPath); - size_t length = strlen(szPath); - std::replace(szCurrentPath, szCurrentPath + length, '/', '\\'); + wchar_t szCurrentPath[MAX_PATH] = { 0 }; + StringCchCopyW(szCurrentPath, MAX_PATH, szPath); + size_t length = wcslen(szPath); + std::replace(szCurrentPath, szCurrentPath + length, L'/', L'\\'); //目录已经存在 - if (::PathFileExists(szCurrentPath)) return true; + if (::PathFileExistsW(szCurrentPath)) return true; //能够直接创建 - if (::CreateDirectory(szCurrentPath, 0)) return true; + if (::CreateDirectoryW(szCurrentPath, 0)) return true; //取得上一级目录 - char szParentPath[MAX_PATH] = { 0 }; - StringCchCopyA(szParentPath, MAX_PATH, szPath); + wchar_t szParentPath[MAX_PATH] = { 0 }; + StringCchCopyW(szParentPath, MAX_PATH, szPath); getParentPath(szParentPath); //创建上一级目录 if (!forceCreatePath(szParentPath)) return false; - return TRUE == ::CreateDirectory(szCurrentPath, 0); + return TRUE == ::CreateDirectoryW(szCurrentPath, 0); } + +bool forceCreatePathForFile(const wchar_t* szFilePath) +{ + wchar_t szPathForFile[MAX_PATH] = { 0 }; + StringCchCopyW(szPathForFile, MAX_PATH, szFilePath); + getParentPath(szPathForFile); + return forceCreatePath(szPathForFile); +} \ No newline at end of file diff --git a/sgutil/CMakeLists.txt b/sgutil/CMakeLists.txt index 3fcb573..25cd371 100644 --- a/sgutil/CMakeLists.txt +++ b/sgutil/CMakeLists.txt @@ -32,6 +32,8 @@ add_executable(sgutil sgu_utils.h sgu_lua_npk_file.h sgu_lua_npk_file.cpp + sgu_lua_utils.h + sgu_lua_utils.cpp ) target_include_directories(sgutil diff --git a/sgutil/lua/dump_npk_list.lua b/sgutil/lua/dump_npk_list.lua new file mode 100644 index 0000000..d3826dc --- /dev/null +++ b/sgutil/lua/dump_npk_list.lua @@ -0,0 +1,78 @@ +--print npk file list to file +--[[ +npkFileName(string): npk file path name(utf8) +listFileName(string): list output path name(utf8) +keyName(boolean): print key name +npkName(boolean): print npk file name +npkBase(boolean): print npk base dir name +fileSize(boolean): print file size +fileCRC(boolean): print file crc +fileOffset(boolean): print file offset + +return(boolean): is success +--]] + +local M={} +function M.dump_npk_file_list(npkFileName, listFileName, npkBase, npkName, keyName, fileOffset, fileSize, fileCRC) + local npk = createNPKFile(); + + local ret = npk:openPakFile(npkFileName) + if(not ret) then + return false + end + + listOutputFile = io.open(listFileName, "w") + fileList = npk:generateFullInfoList(); + + counts = fileList:getFileCounts() + + for i=0, counts-1, 1 do + local fileInfo = fileList:getFileItem(i) + + outputLine="" + + if(npkBase) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. fileInfo:npkBase(); + end + + if(npkName) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. fileInfo:npkName(); + end + + if(keyName) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. fileInfo:keyName(); + end + + if(fileOffset) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. tostring(fileInfo.fileOffset); + end + + if(fileSize) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. tostring(fileInfo.fileSize); + end + + if(fileCRC) then + if(#outputLine>0) then outputLine = outputLine .. "|" end + outputLine = outputLine .. tostring(fileInfo.fileCRC); + end + + if(#outputLine>0) then + listOutputFile:write(outputLine .. "\n") + end + end + + listOutputFile:close() + + destroyFileList(fileList) + npk:closePakFile() + destroyNPKFile(npk) + return true +end + +return M; + diff --git a/sgutil/lua/extrace_npk_file.lua b/sgutil/lua/extrace_npk_file.lua new file mode 100644 index 0000000..ccfd209 --- /dev/null +++ b/sgutil/lua/extrace_npk_file.lua @@ -0,0 +1,48 @@ +--Extracts all files from an NPK archive to a specified output directory. +--[[ +npkFileName The path to the NPK archive file to be extracted. +outputPath The path to the output directory where files will be extracted. +return true if extraction succeeds; false otherwise. +--]] +local M={} +function M.extract_npk_files(npkFileName, outputPath) + local npk = createNPKFile(); + + local ret = npk:openPakFile(npkFileName) + if(not ret) then + return false + end + + local counts = npk:getFileCounts() + for i=0, counts-1, 1 do + local baseInfo = npk:getFileNode(i) + + local fileStream = npk:openFileStream(baseInfo:keyName()) + + print("keyName=" .. fileStream:name() .. "\n") + + local diskFileName = outputPath .. "/" .. baseInfo:keyName() + ret = forceCreatePathForFile(diskFileName); + if(not ret) then + print("CreatePathForFile failed: " .. diskFileName) + npk:closeFileStream(fileStream) + break + end + + ret = fileStream:writeToDiskFile(diskFileName) + if(not ret) then + print("dump file failed: " .. baseInfo:keyName()) + print("LastErrorMsg=" .. getLastErrorMessage()) + npk:closeFileStream(fileStream) + break + end + npk:closeFileStream(fileStream) + end + + npk:closePakFile() + destroyNPKFile(npk) + return true +end + + +return M; diff --git a/sgutil/sgu_lua_npk_file.cpp b/sgutil/sgu_lua_npk_file.cpp index 55c8e00..c7613bb 100644 --- a/sgutil/sgu_lua_npk_file.cpp +++ b/sgutil/sgu_lua_npk_file.cpp @@ -11,12 +11,13 @@ extern "C" #include "lua_tinker.h" //////////////////////////////////////////////////////////////////////////////////// -void LuaNPKFile::registerLuaApi(lua_State* L) +void registerNPKLuaLibs(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::def(L, "getLastErrorMessage", &NPK::getLastErrorMessage); lua_tinker::class_add(L, "NPKFile"); lua_tinker::class_def(L, "openPakFile", &LuaNPKFile::openPakFile); @@ -52,6 +53,7 @@ void LuaNPKFile::registerLuaApi(lua_State* L) lua_tinker::class_def(L, "tell", &LuaNPKFileStream::tell); lua_tinker::class_def(L, "crc32", &LuaNPKFileStream::crc32); lua_tinker::class_def(L, "isEOF", &LuaNPKFileStream::isEOF); + lua_tinker::class_def(L, "writeToDiskFile", &LuaNPKFileStream::writeToDiskFile); } LuaNPKFile* LuaNPKFile::create() @@ -167,6 +169,12 @@ bool LuaNPKFileStream::isEOF(void) const return m_pFileStream ? m_pFileStream->isEOF() : true; } +bool LuaNPKFileStream::writeToDiskFile(const char* wszFileName) +{ + std::wstring wstrLocalDiskFile = convertUtf8StringToWide(wszFileName); + return m_pFileStream ? m_pFileStream->writeToDiskFile(wstrLocalDiskFile.c_str()) : false; +} + /// ///////////////////////////////////////////////////////////////////////////////// LuaNPKFileList* LuaNPKFileList::createEmpty() { diff --git a/sgutil/sgu_lua_npk_file.h b/sgutil/sgu_lua_npk_file.h index 5ed805a..11f60d7 100644 --- a/sgutil/sgu_lua_npk_file.h +++ b/sgutil/sgu_lua_npk_file.h @@ -27,6 +27,9 @@ public: uint32_t crc32(void); bool isEOF(void) const; + //write total file content to local disk file, wszFileName(utf8) + bool writeToDiskFile(const char* wszFileName); +public: NPK::IFileStream* m_pFileStream = nullptr; }; @@ -46,7 +49,6 @@ public: class LuaNPKFile { public: - static void registerLuaApi(struct lua_State* L); static LuaNPKFile* create(); static void destroy(LuaNPKFile* instance); @@ -68,3 +70,5 @@ public: LuaNPKFile(); ~LuaNPKFile(); }; + +void registerNPKLuaLibs(struct lua_State* L); diff --git a/sgutil/sgu_lua_utils.cpp b/sgutil/sgu_lua_utils.cpp new file mode 100644 index 0000000..2c8a434 --- /dev/null +++ b/sgutil/sgu_lua_utils.cpp @@ -0,0 +1,34 @@ +#include "sgu_lua_utils.h" +#include "libNPK_Utils.h" +#include +#include +#include + +extern "C" +{ +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +}; + +#include "lua_tinker.h" + +//utf8 +bool luaForceCreatePathForFile(const char* szPath) +{ + std::wstring strPath = convertUtf8StringToWide(szPath); + return forceCreatePathForFile(strPath.c_str()); +} + +//utf8 +bool luaForceCreatePath(const char* szPath) +{ + std::wstring strPath = convertUtf8StringToWide(szPath); + return forceCreatePath(strPath.c_str()); +} + +void registerUtilsLuaLibs(struct lua_State* L) +{ + lua_tinker::def(L, "forceCreatePath", &luaForceCreatePath); + lua_tinker::def(L, "forceCreatePathForFile", &luaForceCreatePathForFile); +} diff --git a/sgutil/sgu_lua_utils.h b/sgutil/sgu_lua_utils.h new file mode 100644 index 0000000..59327d1 --- /dev/null +++ b/sgutil/sgu_lua_utils.h @@ -0,0 +1,3 @@ +#pragma once + +void registerUtilsLuaLibs(struct lua_State* L); diff --git a/sgutil/sgu_mode_npk_extract_files.cpp b/sgutil/sgu_mode_npk_extract_files.cpp index e8a99f6..8ad1f2a 100644 --- a/sgutil/sgu_mode_npk_extract_files.cpp +++ b/sgutil/sgu_mode_npk_extract_files.cpp @@ -4,6 +4,7 @@ bool extractNPKFiles(const char* szNPKFileName, const char* szOutputDir) { +#if 0 if (!szNPKFileName || !szOutputDir || szNPKFileName[0] == 0 || szOutputDir[0] == 0) { printf("Error: Invalid parameters. NPK file name and output directory must be specified.\n"); @@ -84,5 +85,6 @@ bool extractNPKFiles(const char* szNPKFileName, const char* szOutputDir) } } NPK::closeNPKFile(npkFile); +#endif return true; } \ No newline at end of file diff --git a/sgutil/sgu_mode_run_lua_file.cpp b/sgutil/sgu_mode_run_lua_file.cpp index 6f69201..7bd93c2 100644 --- a/sgutil/sgu_mode_run_lua_file.cpp +++ b/sgutil/sgu_mode_run_lua_file.cpp @@ -1,5 +1,6 @@ #include "sgu_mode_run_lua_file.h" #include "sgu_lua_npk_file.h" +#include "sgu_lua_utils.h" #include "libNPK.h" @@ -22,7 +23,8 @@ bool run_lua_file(const char* szLuaFilename) lua_tinker::def(L, "getLastErrorMessage", &NPK::getLastErrorMessage); //register classes - LuaNPKFile::registerLuaApi(L); + registerNPKLuaLibs(L); + registerUtilsLuaLibs(L); //run lua file lua_tinker::dofile(L, szLuaFilename);