#include "libNPK_FileList.h" #include "libNPK_Errors.h" #include "libNPK_Utils.h" #include #include #include #include #include #include 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 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> 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); } }