#include "StdAfx.h" #include "fs/IFilesystem.h" #include "fs/zip/ZipUtils.h" #include "fs/zip/ZipPack.h" #include "fs/WritableFolderPack.h" #include "fs/CopyStream.h" #include "fs/zip/ZipWriter.h" namespace fs { namespace { UnzipResult unzip(IFilesystem& dstFilesystem, AbsPathView filePath, tl::unique_ref zipPack) { MakeFolderResult makeFolderResult = dstFilesystem.makeFolder(filePath); if (makeFolderResult.has_error()) return makeFolderResult.error(); for (const EnumerateEntry& ee: zipPack->enumerateRecursively(AbsPath("/"))) { AbsPath dstPath = filePath + ee.path; OUTCOME_TRY(dstFilesystem.makeFolder(ee.isFolder ? AbsPathView(dstPath) : dstPath.parent())); if (!ee.isFolder) { OUTCOME_TRY(auto source, zipPack->openStreamSource(AbsPath("/") + ee.path)); OUTCOME_TRY(auto sink, dstFilesystem.openStreamSink(dstPath, Mode::CreateOrOpenAndClear)); OUTCOME_TRY(copyStream(*sink, *source)); } } return tl::success(); } } UnzipResult unzipSource(IFilesystem& dstFilesystem, AbsPathView filePath, tl::unique_ref source) { OUTCOME_TRY(auto pack, ZipPack::create(std::move(source))); return unzip(dstFilesystem, filePath, std::move(pack)); } UnzipResult unzipFile(IFilesystem& dstFilesystem, AbsPathView filePath, tl::lent_ref filesystem, AbsPathView srcFilePath) { OUTCOME_TRY(auto pack, ZipPack::create(std::move(filesystem), std::move(srcFilePath))); return unzip(dstFilesystem, filePath, std::move(pack)); } ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel) { ZipWriter writer(sink); OUTCOME_TRY(const bool isFile, filesystem->isFile(path)); if (isFile) { const auto openResult = filesystem->openSource(path); if (openResult.has_error()) return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}' zip: {}", path, openResult.error()); const auto addResult = writer.addFile(path.str(), compressionLevel, *openResult.value()); if (addResult.has_error()) return tl::make_error(ErrorCode::SystemError, "Cannot add file '{}' zip: {}", path, addResult.error()); } else { for (EnumerateEntry ee: filesystem->enumerateRecursively(path)) { if (!ee.isFolder) { auto localPath = path + ee.path; const auto openResult = filesystem->openSource(localPath); if (openResult.has_error()) return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}' zip: {}", localPath, openResult.error()); const auto addResult = writer.addFile(localPath.str(), compressionLevel, *openResult.value()); if (addResult.has_error()) return tl::make_error(ErrorCode::SystemError, "Cannot add file '{}' zip: {}", localPath, addResult.error()); } } } writer.finish(); return tl::success(); } ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel) { OUTCOME_TRY(const auto sink, dstFilesystem.openSink(dstFilePath, Mode::CreateOrOpenAndClear)); return zipToSink(*sink, std::move(filesystem), path, compressionLevel); } }