Files
2025-09-04 14:30:09 +08:00

288 lines
6.3 KiB
C++

#include "libNPK_FileList.h"
#include "libNPK_Errors.h"
#include "libNPK_Utils.h"
#include <Shlwapi.h>
#include <strsafe.h>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <map>
namespace NPK
{
const char LIST_FILE_SPE_CHAR = '|';
void NPKFileList::clear()
{
m_fileList.clear();
}
bool NPKFileList::loadListFromFile(const wchar_t* wszListFile, const char* prefix,
bool bNpkBase, bool bNpkName, bool bFileOffset, bool bFileSize, bool bFileCRC,
bool bEnableDuplicate)
{
int tokeCounts = 1;
tokeCounts += bNpkBase ? 1 : 0;
tokeCounts += bNpkName ? 1 : 0;
tokeCounts += bFileOffset ? 1 : 0;
tokeCounts += bFileSize ? 1 : 0;
tokeCounts += bFileCRC ? 1 : 0;
std::ifstream file(wszListFile);
if (!file.is_open())
{
setLastError(NPK_ERR_FILE_ACCESS);
return false;
}
size_t prefixLen = (prefix!= nullptr ? strlen(prefix) : 0);
std::string line;
while (std::getline(file, line))
{
if (line.empty()) continue;
if (prefix != nullptr)
{
if (strncmp(prefix, line.c_str(), prefixLen) != 0)
{
continue;
}
}
std::stringstream lineSteam(line);
std::vector<std::string> fileData;
std::string token;
while (std::getline(lineSteam, token, LIST_FILE_SPE_CHAR))
{
fileData.push_back(token);
}
if (fileData.size() != tokeCounts)
{
continue;
}
FileItemFullInfo fullInfo;
int32_t currentIT = 0;
//parser key name
fullInfo.keyName = fileData[currentIT++];
if (bNpkBase) {
fullInfo.npkBase = fileData[currentIT++];
}
if (bNpkName) {
fullInfo.npkName = fileData[currentIT++];
}
if (bFileOffset) {
fullInfo.fileOffset = (uint32_t)(_atoi64(fileData[currentIT++].c_str()));
}
if (bFileSize) {
fullInfo.fileSize = (uint32_t)(_atoi64(fileData[currentIT++].c_str()));
}
if (bFileCRC) {
fullInfo.fileCRC = (uint32_t)(_atoi64(fileData[currentIT++].c_str()));
}
if (!addFileNode(fullInfo, bEnableDuplicate))
{
file.close();
clear();
setLastError(NPK_ERR_DUPLICATE_KEYNAME);
return false;
}
}
file.close();
return true;
}
bool NPKFileList::dumpToLocalFile(const wchar_t* wszListFile,
bool bNpkBase, bool bNpkName, bool bFileOffset, bool bFileSize, bool bFileCRC)
{
std::ofstream file(wszListFile);
if (!file.is_open())
{
setLastError(NPK_ERR_FILE_ACCESS);
return false;
}
for (size_t i = 0; i < m_fileList.size(); i++)
{
const FileItemFullInfo& fullInfo = m_fileList[i];
std::string line = fullInfo.keyName;
if (bNpkBase)
{
line += LIST_FILE_SPE_CHAR + fullInfo.npkBase;
}
if (bNpkName)
{
line += LIST_FILE_SPE_CHAR + fullInfo.npkName;
}
if (bFileOffset)
{
line += LIST_FILE_SPE_CHAR + std::to_string(fullInfo.fileOffset);
}
if (bFileSize)
{
line += LIST_FILE_SPE_CHAR + std::to_string(fullInfo.fileSize);
}
if (bFileCRC)
{
line += LIST_FILE_SPE_CHAR + std::to_string(fullInfo.fileCRC);
}
file << line << std::endl;
}
file.close();
return true;
}
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;
}
bool NPKFileList::getFileItem(const char* szKeyName, FileItemFullInfo* fileItemFullInfo) const
{
auto it = m_hashList.find(szKeyName);
if (it == m_hashList.end())
{
return false;
}
*fileItemFullInfo = m_fileList[it->second];
return true;
}
bool NPKFileList::addFileNode(const FileItemFullInfo& fullInfo, bool bEnableDuplicate)
{
auto currentIT = m_hashList.find(fullInfo.keyName);
//check duplicate file name?
if (currentIT != m_hashList.end())
{
if (bEnableDuplicate)
{
m_fileList[currentIT->second] = fullInfo;
return true;
}
else
{
return false;
}
}
auto newIT = m_fileList.size();
m_fileList.push_back(fullInfo);
m_hashList.insert(std::make_pair(fullInfo.keyName, newIT));
return true;
}
bool NPKFileList::mergeOtherListInto(const IFileList* source, bool bEnableDuplicate)
{
if (source == nullptr)
{
setLastError(NPK_ERR_PARAM);
return false;
}
int32_t counts = source->getFileCounts();
for (int32_t i = 0; i < counts; i++)
{
FileItemFullInfo fullInfo;
source->getFileItem(i, &fullInfo);
if (!addFileNode(fullInfo, bEnableDuplicate))
{
return false;
}
}
return true;
}
bool NPKFileList::applyToLocalNPKFiles(const wchar_t* wszNPKBase)
{
if (wszNPKBase == 0 || wszNPKBase[0] == L'\0')
{
setLastError(NPK_ERR_PARAM);
return false;
}
if (!PathFileExistsW(wszNPKBase) || !PathIsDirectoryW(wszNPKBase))
{
setLastError(NPK_ERR_FILE_ACCESS);
return false;
}
bool result = true;
std::map<std::wstring, std::pair<INPKFile*, IFileList*>> npkFileMap;
for (size_t i = 0; i < m_fileList.size(); i++)
{
FileItemFullInfo& fullInfo = m_fileList[i];
std::wstring strNPKName = getNPKPathNameFromKeyName(wszNPKBase, fullInfo.keyName.c_str());
auto it = npkFileMap.find(strNPKName);
if (it == npkFileMap.end())
{
INPKFile* npkFile = NPK::createNPKFile();
if (!(npkFile->openPakFile(strNPKName.c_str())))
{
result = false;
setLastError(NPK_ERR_FILE_ACCESS);
break;
}
IFileList* fullList = npkFile->generateFullInfoList();
npkFileMap.insert(std::make_pair(strNPKName, std::make_pair(npkFile, fullList)));
it = npkFileMap.find(strNPKName);
}
IFileList* fullList = it->second.second;
fullList->getFileItem(fullInfo.keyName.c_str(), &fullInfo);
}
for (auto it = npkFileMap.begin(); it != npkFileMap.end(); ++it)
{
destoryFileList(it->second.second);
it->second.first->closePakFile();
}
npkFileMap.clear();
return result;
}
std::wstring NPKFileList::getNPKPathNameFromKeyName(const wchar_t* wszNPKBase, const char* keyName)
{
std::wstring strKeyName = convertUtf8StringToWide(keyName);
std::string::size_type lastSep = strKeyName.rfind(L'/');
if (lastSep != std::string::npos)
{
strKeyName = strKeyName.substr(0, lastSep);
}
std::replace(strKeyName.begin(), strKeyName.end(), L'/', L'_');
wchar_t wszNPKPathName[1024] = { 0 };
StringCchCopyW(wszNPKPathName, 1024, wszNPKBase);
PathAppendW(wszNPKPathName, strKeyName.c_str());
PathAddExtensionW(wszNPKPathName, L".NPK");
return std::wstring(wszNPKPathName);
}
IFileList* createEmptyFileList()
{
return new NPKFileList();
}
// destroy a file list
void destoryFileList(IFileList* fileList)
{
delete ((NPKFileList*)fileList);
}
}