WORD RsfsFormatter::getFileIndexSize(const DirectoryEntry& rootDir) { const std::vector<DirectoryEntry>& dirs = rootDir.getDirectories(); WORD wDataRegionOffset = rootDir.getFiles().size() * RSFS_FILEENTRY_SIZE + dirs.size() * RSFS_DIRECTORYENTRY_SIZE; for(std::vector<DirectoryEntry>::const_iterator it = dirs.begin(); it != dirs.end(); it++) wDataRegionOffset += getFileIndexSize(*it); return wDataRegionOffset; }
void RsfsFormatter::create(std::ostream& out, const DirectoryEntry& rootDir) { std::stringstream ssFileIndexBuffer; std::stringstream ssFileRawBuffer; WORD wDataRegionOffset = getFileIndexSize(rootDir) + RSFS_HEADER_SIZE; writeDirectory(rootDir, wDataRegionOffset, ssFileIndexBuffer, ssFileRawBuffer); //Write out header out.put(1); out.put(0); WORD numRootEntries = rootDir.getDirectories().size() + rootDir.getFiles().size(); out.write(reinterpret_cast<char*>(&numRootEntries), sizeof(WORD)); //write file directories for(unsigned char b = ssFileIndexBuffer.get(); !ssFileIndexBuffer.eof(); b = ssFileIndexBuffer.get()) out.put(b); for(unsigned char b = ssFileRawBuffer.get(); !ssFileRawBuffer.eof(); b = ssFileRawBuffer.get()) out.put(b); }
void PluginList::refresh(const QString &profileName , const DirectoryEntry &baseDirectory , const QString &pluginsFile , const QString &loadOrderFile , const QString &lockedOrderFile) { ChangeBracket<PluginList> layoutChange(this); m_ESPsByName.clear(); m_ESPsByPriority.clear(); m_ESPs.clear(); QStringList primaryPlugins = m_GamePlugin->primaryPlugins(); m_CurrentProfile = profileName; std::vector<FileEntry::Ptr> files = baseDirectory.getFiles(); for (auto iter = files.begin(); iter != files.end(); ++iter) { FileEntry::Ptr current = *iter; if (current.get() == nullptr) { continue; } QString filename = ToQString(current->getName()); QString extension = filename.right(3).toLower(); if ((extension == "esp") || (extension == "esm")) { bool forceEnabled = Settings::instance().forceEnableCoreFiles() && std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end(); bool archive = false; try { FilesOrigin &origin = baseDirectory.getOriginByID(current->getOrigin(archive)); QString iniPath = QFileInfo(filename).baseName() + ".ini"; bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != nullptr; QString originName = ToQString(origin.getName()); unsigned int modIndex = ModInfo::getIndex(originName); if (modIndex != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); originName = modInfo->name(); } m_ESPs.push_back(ESPInfo(filename, forceEnabled, originName, ToQString(current->getFullPath()), hasIni)); } catch (const std::exception &e) { reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3").arg(filename).arg(current->getOrigin(archive)).arg(e.what())); } } } if (readLoadOrder(loadOrderFile)) { int maxPriority = 0; // assign known load orders for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) { std::map<QString, int>::const_iterator priorityIter = m_ESPLoadOrder.find(espIter->m_Name.toLower()); if (priorityIter != m_ESPLoadOrder.end()) { if (priorityIter->second > maxPriority) { maxPriority = priorityIter->second; } espIter->m_Priority = priorityIter->second; } else { espIter->m_Priority = -1; } } ++maxPriority; // assign maximum priorities for plugins with unknown priority for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) { if (espIter->m_Priority == -1) { espIter->m_Priority = maxPriority++; } } } else { // no load order stored, determine by date std::sort(m_ESPs.begin(), m_ESPs.end(), ByDate); for (size_t i = 0; i < m_ESPs.size(); ++i) { m_ESPs[i].m_Priority = i; } } std::sort(m_ESPs.begin(), m_ESPs.end(), ByPriority); // first, sort by priority // remove gaps from the priorities so we can use them as array indices without overflow for (int i = 0; i < static_cast<int>(m_ESPs.size()); ++i) { m_ESPs[i].m_Priority = i; } std::sort(m_ESPs.begin(), m_ESPs.end(), ByName); // sort by name so alphabetical sorting works updateIndices(); readEnabledFrom(pluginsFile); readLockedOrderFrom(lockedOrderFile); layoutChange.finish(); refreshLoadOrder(); emit dataChanged(this->index(0, 0), this->index(m_ESPs.size(), columnCount())); m_Refreshed(); }
void RsfsFormatter::writeDirectory(const DirectoryEntry& dir, const WORD wDataRegionOffset, std::ostream& fileIndexBuffer, std::ostream& fileRawDataBuffer) { char fileReadBuffer[100]; const std::vector<DirectoryEntry>& dirs = dir.getDirectories(); const std::vector<FileEntry>& files = dir.getFiles(); WORD wBuffer = 0; if(dir.getName().length() > 0) { wBuffer = RSFS_ENTRYTYPE_DIRECTORY; fileIndexBuffer.write(reinterpret_cast<char*>(&wBuffer), sizeof(WORD)); fileIndexBuffer.write(dir.getName().c_str(), dir.getName().length()); for(unsigned int i = RSFS_NAME_SIZE - dir.getName().length(); i > 0; i--) fileIndexBuffer.put(0); if(dir.getDirectories().size() > 0xFFFF) throw FormattingException("The number of sub-directories exceeds the max permittable number of sub-directories."); wBuffer = static_cast<WORD>(dir.getDirectories().size() + dir.getFiles().size()); fileIndexBuffer.write(reinterpret_cast<char*>(&wBuffer), sizeof(WORD)); fileIndexBuffer.put(0); fileIndexBuffer.put(0); } for(std::vector<FileEntry>::const_iterator it = files.begin(); it != files.end(); it++) { if(it->getName().length() >= RSFS_NAME_SIZE) { throw new FormattingException(std::string("Skipped due to file name exceeding max length: ") + it->getName()); continue; } wBuffer = RSFS_ENTRYTYPE_FILE; fileIndexBuffer.write(reinterpret_cast<char*>(&wBuffer), sizeof(WORD)); fileIndexBuffer.write(it->getName().c_str(), it->getName().length()); //Padd the file name with nulls. for(unsigned int i = RSFS_NAME_SIZE - it->getName().length(); i > 0; i--) fileIndexBuffer.put(0); if(it->getSize() > 0xFFFF) throw FormattingException("Size of file exceeded permitable size."); wBuffer = static_cast<WORD>(it->getSize()); fileIndexBuffer.write(reinterpret_cast<char*>(&wBuffer), sizeof(WORD)); //Make sure data is aligned in words std::streamoff offset = 0; for(offset = wDataRegionOffset + fileRawDataBuffer.tellp(); offset % 2; offset++) fileRawDataBuffer.put(0); if(offset + it->getSize() > 0xFFFF) throw FormattingException("Size of medium exceeded permitable size."); WORD wFileDataOffset = static_cast<WORD>(offset) / 2; //Offset in terms of words. fileIndexBuffer.write(reinterpret_cast<char*>(&wFileDataOffset), sizeof(WORD)); //Write our file's data to the fileRawBuffer. std::ifstream inFile(it->getSourceFile(), std::ifstream::binary | std::ifstream::in); if(!inFile.good()) throw FormattingException(std::string("Error reading from source file") + it->getName()); while(!inFile.eof()) { inFile.read(fileReadBuffer, sizeof(fileReadBuffer)); fileRawDataBuffer.write(fileReadBuffer, inFile.gcount()); } } for(std::vector<DirectoryEntry>::const_iterator it = dirs.begin(); it != dirs.end(); it++) writeDirectory(*it, wDataRegionOffset, fileIndexBuffer, fileRawDataBuffer); }