#pragma once #include "tl/result.h" #include "tl/string.h" #include "tl/vector_map.h" #include "fs/IPack.h" #include "fs/AbsPath.h" #include "fs/zip/ZipReader.h" #include "fs/Api.h" namespace fs { class MapSourceView; class FS_API ZipPack final : virtual public IPack { public: ZipPack() = default; ~ZipPack() override = default; typedef tl::result, Error> CreateResult; static CreateResult create(tl::unique_ref zipFileSource); static CreateResult create(tl::lent_ref filesystem, AbsPathView zipFileLocation); virtual void setEncryptionData(const tl::string& key, uint32_t rounds); OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override; OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override; OpenMapSourceResult openMapSource(AbsPathView path, MapView mapView = MapView(), SourceFlags flags = SourceFlags()) const override; IsFileResult isFile(AbsPathView path) const override; IsFolderResult isFolder(AbsPathView path) const override; ExistsResult exists(AbsPathView path) const override; GetStatResult getStat(AbsPathView path) const override; cppcoro::generator enumerate(AbsPath path) const override; cppcoro::generator enumerateRecursively(AbsPath path) const override; tl::result convertToNativePath(AbsPathView path) const override; protected: struct File; struct Folder; struct EntryIndex; ZipPack(tl::unique_ref zipFileSource, ZipReader zipReader); ZipPack(tl::lent_ref filesystem, AbsPathView zipFileLocation, ZipReader zipReader); OpenMapSourceResult openRawMapSource(const File& file, MapView mapView) const; OpenSourceResult openRawSource(const File& file) const; OpenSourceResult openZipSource(const File& file) const; OpenMapSourceResult openZipMapSource(const File& file) const; OpenStreamSourceResult openZipStreamSource(const File& file) const; uint16_t getOrAddFolder(AbsPathView folderPath, tl::vector>& io_childrenIndices); void createEntries(ZipReader zipReader); struct File { tl::string name; uint8_t isCompressed : 1; uint8_t uncompressedSizeH = 0; uint8_t compressedSizeH = 0; uint8_t dataOffsetH = 0; uint16_t parentIndex = 0; uint32_t lastModTimePoint = 0; uint32_t uncompressedSizeL = 0; uint32_t compressedSizeL = 0; uint32_t dataOffsetL = 0; }; static_assert(sizeof(File) <= sizeof(tl::string) + 40, "Check your sizes!!!"); struct Folder { tl::string name; uint16_t parentIndex = 0; uint16_t childrenStartIndex = 0; // this is an index inside m_childrenIndices uint16_t childrenCount = 0; uint32_t lastModTimePoint = 0; }; static_assert(sizeof(Folder) <= sizeof(tl::string) + 20, "Check your sizes!!!"); struct EntryIndex { EntryIndex() = default; EntryIndex(bool isFolder, uint16_t index) : isFolder(isFolder) , index(index) { } uint32_t isFolder : 1; uint32_t index : 16; }; static_assert(sizeof(EntryIndex) == 4, "Check your sizes!!!"); private: tl::lent_ptr m_filesystem; mutable std::mutex m_zipMapSourceLock; tl::unique_ptr m_zipMapSource; AbsPath m_zipFileLocation; tl::string m_encryptionKey; uint32_t m_encryptionRounds = 32; tl::vector_map m_pathToIndex; tl::vector m_files; tl::vector m_folders; tl::vector m_childrenIndices; // these are indices inside the m_files or m_folders void buildUpPath(RelPath& path, const Folder& folder, uint32_t toIndex) const; void buildUpPath(RelPath& path, const File& file, uint32_t toIndex) const; }; }