288 lines
6.3 KiB
C++
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);
|
|
}
|
|
}
|