diff --git a/Source/Core/Core/NetPlayCommon.cpp b/Source/Core/Core/NetPlayCommon.cpp index 910c7308fd..a72e03236b 100644 --- a/Source/Core/Core/NetPlayCommon.cpp +++ b/Source/Core/Core/NetPlayCommon.cpp @@ -3,6 +3,7 @@ #include "Core/NetPlayCommon.h" +#include #include #include "Common/FileUtil.h" @@ -84,6 +85,35 @@ bool CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet) return true; } +static bool CompressFolderIntoPacketInternal(const File::FSTEntry& folder, sf::Packet& packet) +{ + const sf::Uint64 size = folder.children.size(); + packet << size; + for (const auto& child : folder.children) + { + const bool is_folder = child.isDirectory; + packet << child.virtualName; + packet << is_folder; + const bool success = is_folder ? CompressFolderIntoPacketInternal(child, packet) : + CompressFileIntoPacket(child.physicalName, packet); + if (!success) + return false; + } + return true; +} + +bool CompressFolderIntoPacket(const std::string& folder_path, sf::Packet& packet) +{ + if (!File::IsDirectory(folder_path)) + { + packet << false; + return true; + } + + packet << true; + return CompressFolderIntoPacketInternal(File::ScanDirectoryTree(folder_path, true), packet); +} + bool CompressBufferIntoPacket(const std::vector& in_buffer, sf::Packet& packet) { const sf::Uint64 size = in_buffer.size(); @@ -187,6 +217,47 @@ bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path) return true; } +static bool DecompressPacketIntoFolderInternal(sf::Packet& packet, const std::string& folder_path) +{ + if (!File::CreateFullPath(folder_path + "/")) + return false; + + sf::Uint64 size; + packet >> size; + for (size_t i = 0; i < size; ++i) + { + std::string name; + packet >> name; + + if (name.find('/') != std::string::npos) + return false; +#ifdef _WIN32 + if (name.find('\\') != std::string::npos) + return false; +#endif + if (std::all_of(name.begin(), name.end(), [](char c) { return c == '.'; })) + return false; + + bool is_folder; + packet >> is_folder; + std::string path = fmt::format("{}/{}", folder_path, name); + const bool success = is_folder ? DecompressPacketIntoFolderInternal(packet, path) : + DecompressPacketIntoFile(packet, path); + if (!success) + return false; + } + return true; +} + +bool DecompressPacketIntoFolder(sf::Packet& packet, const std::string& folder_path) +{ + bool folder_existed; + packet >> folder_existed; + if (!folder_existed) + return true; + return DecompressPacketIntoFolderInternal(packet, folder_path); +} + std::optional> DecompressPacketIntoBuffer(sf::Packet& packet) { u64 size = Common::PacketReadU64(packet); diff --git a/Source/Core/Core/NetPlayCommon.h b/Source/Core/Core/NetPlayCommon.h index fc2a017047..9893131772 100644 --- a/Source/Core/Core/NetPlayCommon.h +++ b/Source/Core/Core/NetPlayCommon.h @@ -15,7 +15,9 @@ namespace NetPlay { bool CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet); +bool CompressFolderIntoPacket(const std::string& folder_path, sf::Packet& packet); bool CompressBufferIntoPacket(const std::vector& in_buffer, sf::Packet& packet); bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path); +bool DecompressPacketIntoFolder(sf::Packet& packet, const std::string& folder_path); std::optional> DecompressPacketIntoBuffer(sf::Packet& packet); } // namespace NetPlay