使用lua实现npk操作

This commit is contained in:
2025-09-03 09:34:30 +08:00
parent 25e7cff75d
commit 80390e48a7
10 changed files with 34 additions and 354 deletions
+2 -2
View File
@@ -27,10 +27,10 @@ uint8_t* readFileToBuffer(const char* filename, int64_t& outSize);
void freeFileBuffer(uint8_t* buffer); void freeFileBuffer(uint8_t* buffer);
// Clears the specified path by deleting all files and optionally removing the directory itself. // Clears the specified path by deleting all files and optionally removing the directory itself.
bool clearPath(const char* szPath, bool recursion, bool removeSelf); bool clearPath(const wchar_t* szPath, bool recursion, bool removeSelf);
//Creates an empty directory at the specified path. If the path already exists and is a directory, clears its contents. //Creates an empty directory at the specified path. If the path already exists and is a directory, clears its contents.
bool createEmptyPath(const char* szPath); bool createEmptyPath(const wchar_t* szPath);
// Force create a directory path, ensuring all parent directories are created as needed. // Force create a directory path, ensuring all parent directories are created as needed.
bool forceCreatePath(const wchar_t* szPath); bool forceCreatePath(const wchar_t* szPath);
+16 -16
View File
@@ -186,13 +186,13 @@ void freeFileBuffer(uint8_t* buffer)
delete[] buffer; delete[] buffer;
} }
bool clearPath(const char* szPath, bool recursion, bool removeSelf) bool clearPath(const wchar_t* szPath, bool recursion, bool removeSelf)
{ {
char szTemp[MAX_PATH] = { 0 }; wchar_t szTemp[MAX_PATH] = { 0 };
StringCbCopyA(szTemp, sizeof(szTemp)-1, szPath); StringCbCopyW(szTemp, sizeof(szTemp)-1, szPath);
PathAppend(szTemp, "*.*"); PathAppendW(szTemp, L"*.*");
SHFILEOPSTRUCT shf; SHFILEOPSTRUCTW shf;
SecureZeroMemory(&shf, sizeof(SHFILEOPSTRUCT)); SecureZeroMemory(&shf, sizeof(SHFILEOPSTRUCT));
shf.hwnd = NULL; shf.hwnd = NULL;
@@ -204,37 +204,37 @@ bool clearPath(const char* szPath, bool recursion, bool removeSelf)
shf.fFlags |= FOF_NORECURSION; shf.fFlags |= FOF_NORECURSION;
} }
if (0 != SHFileOperation(&shf)) if (0 != SHFileOperationW(&shf))
{ {
return false; // Failed to delete files return false; // Failed to delete files
} }
if (removeSelf) if (removeSelf)
{ {
if (!RemoveDirectory(szPath)) if (!RemoveDirectoryW(szPath))
{ {
printf("Error: Failed to remove directory %s\n", szPath); printf("Error: Failed to remove directory\n");
return false; // Failed to remove directory return false; // Failed to remove directory
} }
} }
return true; // Successfully cleared the path return true; // Successfully cleared the path
} }
bool createEmptyPath(const char* szPath) bool createEmptyPath(const wchar_t* szPath)
{ {
if (!szPath || szPath[0] == 0) if (!szPath || szPath[0] == 0)
{ {
printf("Error: Invalid path provided for directory creation.\n"); printf("Error: Invalid path provided for directory creation.\n");
return false; // Invalid path return false; // Invalid path
} }
if (::PathFileExists(szPath)) if (::PathFileExistsW(szPath))
{ {
if (::PathIsDirectory(szPath)) if (::PathIsDirectoryW(szPath))
{ {
// Clear the directory // Clear the directory
if (!clearPath(szPath, true, false)) if (!clearPath(szPath, true, false))
{ {
printf("Failed to clear output directory: '%s'\n", szPath); printf("Failed to clear output directory\n");
return false; // Failed to clear output directory return false; // Failed to clear output directory
} }
return true; // Directory exists and is cleared return true; // Directory exists and is cleared
@@ -242,17 +242,17 @@ bool createEmptyPath(const char* szPath)
else else
{ {
// If it exists but is not a directory, delete the file // If it exists but is not a directory, delete the file
if(!DeleteFileA(szPath) && ::GetLastError() != ERROR_FILE_NOT_FOUND) if(!DeleteFileW(szPath) && ::GetLastError() != ERROR_FILE_NOT_FOUND)
{ {
printf("Failed to delete existing file: '%s', Error=%d\n", szPath, ::GetLastError()); printf("Failed to delete existing file, Error=%d\n", ::GetLastError());
return false; // Failed to delete existing file return false; // Failed to delete existing file
} }
} }
} }
if (!::CreateDirectory(szPath, NULL) && ::GetLastError() != ERROR_ALREADY_EXISTS) if (!::CreateDirectoryW(szPath, NULL) && ::GetLastError() != ERROR_ALREADY_EXISTS)
{ {
printf("Failed to create output directory: '%s', Error=%d\n", szPath, ::GetLastError()); printf("Failed to create output directory, Error=%d\n", ::GetLastError());
return false; // Failed to create output directory return false; // Failed to create output directory
} }
return true; return true;
-4
View File
@@ -22,10 +22,6 @@ add_executable(sgutil
sgu_mode_rand_modify.h sgu_mode_rand_modify.h
sgu_mode_rand_remove.cpp sgu_mode_rand_remove.cpp
sgu_mode_rand_remove.h sgu_mode_rand_remove.h
sgu_mode_npk_dump_list.h
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.h
sgu_mode_run_lua_file.cpp sgu_mode_run_lua_file.cpp
sgu_utils.cpp sgu_utils.cpp
+8 -1
View File
@@ -10,6 +10,13 @@ function M.extract_npk_files(npkFileName, outputPath)
local ret = npk:openPakFile(npkFileName) local ret = npk:openPakFile(npkFileName)
if(not ret) then if(not ret) then
print("Can't open npk file:" .. npkFileName)
return false
end
ret = createEmptyPath(outputPath)
if(not ret) then
print("Can't create ouput path: " .. outputPath)
return false return false
end end
@@ -19,7 +26,7 @@ function M.extract_npk_files(npkFileName, outputPath)
local fileStream = npk:openFileStream(baseInfo:keyName()) local fileStream = npk:openFileStream(baseInfo:keyName())
print("keyName=" .. fileStream:name() .. "\n") print("keyName=" .. fileStream:name())
local diskFileName = outputPath .. "/" .. baseInfo:keyName() local diskFileName = outputPath .. "/" .. baseInfo:keyName()
ret = forceCreatePathForFile(diskFileName); ret = forceCreatePathForFile(diskFileName);
+8
View File
@@ -27,8 +27,16 @@ bool luaForceCreatePath(const char* szPath)
return forceCreatePath(strPath.c_str()); return forceCreatePath(strPath.c_str());
} }
//utf8
bool luaCreateEmptyPath(const char* szPath)
{
std::wstring strPath = convertUtf8StringToWide(szPath);
return createEmptyPath(strPath.c_str());
}
void registerUtilsLuaLibs(struct lua_State* L) void registerUtilsLuaLibs(struct lua_State* L)
{ {
lua_tinker::def(L, "forceCreatePath", &luaForceCreatePath); lua_tinker::def(L, "forceCreatePath", &luaForceCreatePath);
lua_tinker::def(L, "forceCreatePathForFile", &luaForceCreatePathForFile); lua_tinker::def(L, "forceCreatePathForFile", &luaForceCreatePathForFile);
lua_tinker::def(L, "createEmptyPath", &luaCreateEmptyPath);
} }
-138
View File
@@ -8,104 +8,11 @@
#include "sgu_mode_make_diff.h" #include "sgu_mode_make_diff.h"
#include "sgu_mode_apply_patch.h" #include "sgu_mode_apply_patch.h"
#include "sgu_mode_hash_file.h" #include "sgu_mode_hash_file.h"
#include "sgu_mode_npk_dump_list.h"
#include "sgu_mode_npk_extract_files.h"
#include "sgu_mode_download.h" #include "sgu_mode_download.h"
#include "sgu_mode_run_lua_file.h" #include "sgu_mode_run_lua_file.h"
#include "libEncrypt_AES.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<TestClass>(L, "TestClass");
// lua_tinker::class_def<TestClass>(L, "TestFunc", &TestClass::TestFunc);
// lua_tinker::class_def<TestClass>(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, enum { OPT_MODE,
OPT_INPUT, OPT_INPUT2, OPT_OUTPUT, OPT_INPUT, OPT_INPUT2, OPT_OUTPUT,
OPT_MIN_SIZE, OPT_MAX_SIZE, OPT_MIN_SIZE, OPT_MAX_SIZE,
@@ -153,8 +60,6 @@ static void printUsage(const char* moduleName)
printf(" MakeDiff\tCreates a binary diff patch file between two input files using BSDIFF43.\n"); printf(" MakeDiff\tCreates a binary diff patch file between two input files using BSDIFF43.\n");
printf(" ApplyPatch\tApplies a BSDIFF43 binary patch to an input file and writes the patched result to an output file.\n"); printf(" ApplyPatch\tApplies a BSDIFF43 binary patch to an input file and writes the patched result to an output file.\n");
printf(" HashFile\tCalculates the hash(MD5|SHA256) of the contents of a specified file.\n"); printf(" HashFile\tCalculates the hash(MD5|SHA256) of the contents of a specified file.\n");
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(" HttpDownload\tDownloads a file from a specified URL and saves it to a local file.\n");
printf(" RunLuaFile\t xxxx \n"); printf(" RunLuaFile\t xxxx \n");
printf("\nSample:\n"); printf("\nSample:\n");
@@ -166,8 +71,6 @@ static void printUsage(const char* moduleName)
printf(" -m ApplyPatch -i ver01.bin -i2 patch_ver01_ver02.diff -o ver02.bin\n"); printf(" -m ApplyPatch -i ver01.bin -i2 patch_ver01_ver02.diff -o ver02.bin\n");
printf(" -m HashFile -t md5 -i ver01.bin\n"); printf(" -m HashFile -t md5 -i ver01.bin\n");
printf(" -m HashFile -t sha256 -i ver01.bin\n"); printf(" -m HashFile -t sha256 -i ver01.bin\n");
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 HttpDownload -i http://download.com/file.txt -o file.txt\n");
printf(" -m RunLuaFile -i script.lua\n"); printf(" -m RunLuaFile -i script.lua\n");
} }
@@ -183,8 +86,6 @@ enum WorkMode {
WM_APPLY_PATCH, WM_APPLY_PATCH,
WM_HASH_FILE, WM_HASH_FILE,
WM_HTTP_DOWNLOAD, WM_HTTP_DOWNLOAD,
WM_NPK_DUMPLIST,
WM_NPK_EXTRACT_FILES,
WM_RUN_LUA_FILE, WM_RUN_LUA_FILE,
}; };
@@ -226,12 +127,6 @@ WorkMode parserWorkMode(const char* modeStr)
else if (_stricmp(modeStr, "HttpDownload") == 0) { else if (_stricmp(modeStr, "HttpDownload") == 0) {
return WM_HTTP_DOWNLOAD; return WM_HTTP_DOWNLOAD;
} }
else if (_stricmp(modeStr, "NPKDumpList") == 0) {
return WM_NPK_DUMPLIST;
}
else if (_stricmp(modeStr, "NPKExtractFiles") == 0) {
return WM_NPK_EXTRACT_FILES;
}
else if (_stricmp(modeStr, "RunLuaFile") == 0) { else if (_stricmp(modeStr, "RunLuaFile") == 0) {
return WM_RUN_LUA_FILE; return WM_RUN_LUA_FILE;
} }
@@ -482,39 +377,6 @@ int main(int argc, char* argv[])
} }
break; break;
case WM_NPK_DUMPLIST:
{
if (inputFilename == nullptr || outputFilename == nullptr)
{
printf("Error: For 'NPKDumpList' mode, you must specify input NPK file and output file.\n");
printUsage(::PathFindFileNameA(argv[0]));
return 1;
}
printf("Dumping NPK list from %s to %s\n", inputFilename, outputFilename);
if (!dumpNPKFileList(inputFilename, outputFilename))
{
printf("Error: Failed to dump NPK list.\n");
return 1;
}
}
break;
case WM_NPK_EXTRACT_FILES:
{
if (inputFilename == nullptr || outputFilename == nullptr)
{
printf("Error: For 'NPKExtractFiles' mode, you must specify input NPK file and output directory.\n");
printUsage(::PathFindFileNameA(argv[0]));
return 1;
}
printf("Extracting files from NPK '%s' to directory '%s'\n", inputFilename, outputFilename);
if(!extractNPKFiles(inputFilename, outputFilename))
{
printf("Error: Failed to extract files from NPK.\n");
return 1;
}
}
break;
case WM_RUN_LUA_FILE: case WM_RUN_LUA_FILE:
{ {
if (inputFilename == nullptr) if (inputFilename == nullptr)
-64
View File
@@ -1,64 +0,0 @@
#include "sgu_stdafx.h"
#include "sgu_mode_npk_dump_list.h"
#include "libNPK.h"
bool dumpNPKFileList(const char* inputFilename, const char* outputFilename)
{
if (!inputFilename || inputFilename[0] == 0)
{
printf("Error: Input filename is not specified.\n");
return false;
}
if (!outputFilename || outputFilename[0] == 0)
{
printf("Error: Output filename is not specified.\n");
return false;
}
NPK::INPKFile* pakFile = NPK::createNPKFile();
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;
}
FILE* fpOutput = fopen(outputFilename, "a+");
if (!fpOutput)
{
printf("Error: Failed to open output file: %s\n", outputFilename);
return false;
}
int32_t fileCount = pakFile->getFileCounts();
// Dump file list
for(int32_t i=0; i < fileCount; i++)
{
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(baseInfo.keyName.c_str());
if (!fileStream)
{
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", baseInfo.keyName.c_str(), crc32, baseInfo.fileSize);
pakFile->closeFileStream(fileStream);
}
fclose(fpOutput);
pakFile->closePakFile();
NPK::closeNPKFile(pakFile);
return true;
}
-18
View File
@@ -1,18 +0,0 @@
#pragma once
/**
* Dumps the file list from an NPK archive to a text file.
*
* @param inputFilename The path to the NPK archive file to be read.
* @param outputFilename The path to the output text file where the file list will be written.
* @return true if the operation succeeds; false otherwise.
*
* The function performs the following steps:
* 1. Validates the input and output file names.
* 2. Opens the NPK archive and retrieves the number of contained files.
* 3. Iterates through each file entry in the archive, extracting its name, offset, and size.
* 4. Writes the file list to the output text file in tab-separated format: fileName, fileOffset, fileSize.
* 5. Closes all files and releases resources.
* 6. Returns true on success, or false if any error occurs during processing.
*/
bool dumpNPKFileList(const char* szNPKFileName, const char* szListFileName);
-90
View File
@@ -1,90 +0,0 @@
#include "sgu_stdafx.h"
#include "sgu_mode_npk_extract_files.h"
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");
return false; // Invalid parameters
}
if (!createEmptyPath(szOutputDir))
{
printf("Error: Failed to create output directory '%s'.\n", szOutputDir);
return false;
}
NPK::INPKFile* npkFile = NPK::createNPKFile();
if (!npkFile)
{
return false; // Failed to create NPK file interface
}
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->getFileCounts();
for (int32_t i = 0; i < fileCount; ++i)
{
NPK::FileItemBaseInfo baseInfo;
if (!npkFile->getFileItemBaseInfo(i, &baseInfo))
{
std::string outputPathName = std::string(szOutputDir) + "/" + baseInfo.keyName;
char szOutputPath[MAX_PATH];
StringCbCopyA(szOutputPath, sizeof(szOutputPath), outputPathName.c_str());
getParentPath(szOutputPath);// Get the directory part of the path
if (!forceCreatePath(szOutputPath))
{
printf("Error: Failed to create output path '%s'.\n", szOutputPath);
NPK::closeNPKFile(npkFile);
return false;
}
NPK::IFileStream* fileStream = npkFile->openFileStream(baseInfo.keyName.c_str());
if(fileStream == nullptr)
{
printf("Error: Failed to open file stream for '%s', Error=%s\n",
baseInfo.keyName.c_str(), NPK::getLastErrorMessage());
NPK::closeNPKFile(npkFile);
return false;
}
FILE* fpOutput = fopen(outputPathName.c_str(), "wb");
if (!fpOutput)
{
printf("Error: Failed to open output file '%s' for writing.\n", outputPathName.c_str());
npkFile->closeFileStream(fileStream);
NPK::closeNPKFile(npkFile);
return false; // Failed to open output file
}
char buffer[4096] = { 0 };
uint32_t bytesRead = 0;
while ((bytesRead = fileStream->read(buffer, sizeof(buffer))) > 0)
{
if (fwrite(buffer, 1, bytesRead, fpOutput) != bytesRead)
{
printf("Error: Failed to write to output file '%s'.\n", outputPathName.c_str());
fclose(fpOutput);
npkFile->closeFileStream(fileStream);
NPK::closeNPKFile(npkFile);
return false; // Failed to write to output file
}
}
fclose(fpOutput);
npkFile->closeFileStream(fileStream);
}
}
NPK::closeNPKFile(npkFile);
#endif
return true;
}
-21
View File
@@ -1,21 +0,0 @@
#pragma once
/**
* Extracts all files from an NPK archive to a specified output directory.
*
* @param szNPKFileName The path to the NPK archive file to be extracted.
* @param szOutputDir The path to the output directory where files will be extracted.
* @return true if extraction succeeds; false otherwise.
*
* The function performs the following steps:
* 1. Validates the input parameters.
* 2. Creates or clears the output directory.
* 3. Opens the NPK archive and retrieves the file list.
* 4. For each file in the archive:
* - Ensures the output path exists.
* - Opens a stream to the file in the archive.
* - Creates the corresponding output file.
* - Copies the file data from the archive to the output file in chunks.
* 5. Closes all resources and returns true on success, or false if any error occurs.
*/
bool extractNPKFiles(const char* szNPKFileName, const char* szOutputDir);