From edb581bee30f47a241db6865e4422e4f1304130c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 24 Feb 2025 21:00:23 +0300 Subject: [PATCH] add io::copy, io::copy_all & fix ZipFileDevice::list --- src/io/devices/ZipFileDevice.cpp | 29 +++++++++++------- src/io/io.cpp | 50 ++++++++++++++++++++++++++++++++ src/io/io.hpp | 9 ++++++ 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/io/devices/ZipFileDevice.cpp b/src/io/devices/ZipFileDevice.cpp index 1e237a3f..0496fc57 100644 --- a/src/io/devices/ZipFileDevice.cpp +++ b/src/io/devices/ZipFileDevice.cpp @@ -60,6 +60,16 @@ ZipFileDevice::Entry ZipFileDevice::readEntry() { if (entry.diskNumberStart == 0xFF) { throw std::runtime_error("zip64 is not supported"); } + + for (size_t i = 0; i < entry.fileName.length(); i++) { + if (entry.fileName[i] == '\\') { + entry.fileName[i] = '/'; + } + } + if (entry.fileName[entry.fileName.length() - 1] == '/') { + entry.isDirectory = true; + entry.fileName = entry.fileName.substr(0, entry.fileName.length() - 1); + } return entry; } @@ -82,16 +92,6 @@ void ZipFileDevice::findBlob(Entry& entry) { // Skip extra field and file comment file->seekg(nameLength + extraFieldLength, std::ios::cur); entry.blobOffset = file->tellg(); - - for (size_t i = 0; i < entry.fileName.length(); i++) { - if (entry.fileName[i] == '\\') { - entry.fileName[i] = '/'; - } - } - if (entry.fileName[entry.fileName.length() - 1] == '/') { - entry.isDirectory = true; - entry.fileName = entry.fileName.substr(0, entry.fileName.length() - 1); - } } ZipFileDevice::ZipFileDevice( @@ -248,9 +248,16 @@ private: std::unique_ptr ZipFileDevice::list(std::string_view path) { std::vector names; auto folder = std::string(path) + "/"; + size_t folderLen = folder.length(); for (const auto& [name, entry] : entries) { if (name.find(folder) == 0) { - names.push_back(name); + size_t pos = name.find('/', folderLen); + if (pos == std::string::npos) { + names.push_back(name.substr(folderLen, pos - folderLen)); + } + if (pos == name.length() - 1) { + names.push_back(name.substr(folderLen, pos - folderLen)); + } } } return std::make_unique(std::move(names)); diff --git a/src/io/io.cpp b/src/io/io.cpp index bef794b4..8ee9f8ce 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -252,6 +252,56 @@ uint64_t io::remove_all(const io::path& file) { return device.removeAll(file.pathPart()); } +bool io::copy(const io::path& src, const io::path& dst) { + auto& srcDevice = io::require_device(src.entryPoint()); + auto& dstDevice = io::require_device(dst.entryPoint()); + if (!srcDevice.isfile(src.pathPart())) { + return false; + } + auto input = srcDevice.read(src.pathPart()); + auto output = dstDevice.write(dst.pathPart()); + size_t size = srcDevice.size(src.pathPart()); + std::vector buffer(16'384); + while (size > 0) { + size_t read = std::min(size, buffer.size()); + input->read(buffer.data(), read); + auto gcount = input->gcount(); + output->write(buffer.data(), gcount); + size -= gcount; + if (input->eof()) { + break; + } + if (!input->good() || !output->good()) { + return false; + } + } + return output->good(); +} + +uint64_t io::copy_all(const io::path& src, const io::path& dst) { + auto& srcDevice = io::require_device(src.entryPoint()); + auto& dstDevice = io::require_device(dst.entryPoint()); + auto dstPath = dst.pathPart(); + if (!dstDevice.isdir(dstPath) && !dstDevice.mkdirs(dstPath)) { + return 0; + } + uint64_t count = 0; + for (auto& srcSubFile : directory_iterator(src)) { + auto dstSubFile = dst / srcSubFile.name(); + auto srcSubPath = srcSubFile.pathPart(); + auto dstSubPath = dstSubFile.pathPart(); + if (srcDevice.isdir(srcSubPath)) { + if (!dstDevice.mkdirs(dstSubPath)) { + continue; + } + count += copy_all(srcSubFile, dstSubFile); + } else if (copy(srcSubFile, dstSubFile)) { + count++; + } + } + return count; +} + size_t io::file_size(const io::path& file) { auto& device = io::require_device(file.entryPoint()); return device.size(file.pathPart()); diff --git a/src/io/io.hpp b/src/io/io.hpp index 46582400..0b2f950d 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -187,6 +187,15 @@ namespace io { /// @brief Remove file or empty directory bool remove(const io::path& file); + /// @brief Copy src file to dst file + /// @param src source file path + /// @param dst destination file path + /// @return true if success + bool copy(const io::path& src, const io::path& dst); + + /// @brief Copy all files and directories in the folder recursively + uint64_t copy_all(const io::path& src, const io::path& dst); + /// @brief Remove all files and directories in the folder recursively uint64_t remove_all(const io::path& file);