소스 검색

LibArchive: Extract logic for calculating ZIP statistics

Sam Atkins 1 년 전
부모
커밋
8d53442187

+ 33 - 0
Userland/Libraries/LibArchive/Statistics.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+
+namespace Archive {
+
+class Statistics {
+public:
+    Statistics(size_t file_count, size_t directory_count, size_t total_uncompressed_bytes)
+        : m_file_count(file_count)
+        , m_directory_count(directory_count)
+        , m_total_uncompressed_bytes(total_uncompressed_bytes)
+    {
+    }
+
+    size_t file_count() const { return m_file_count; }
+    size_t directory_count() const { return m_directory_count; }
+    size_t member_count() const { return file_count() + directory_count(); }
+    size_t total_uncompressed_bytes() const { return m_total_uncompressed_bytes; }
+
+private:
+    size_t m_file_count { 0 };
+    size_t m_directory_count { 0 };
+    size_t m_total_uncompressed_bytes { 0 };
+};
+
+}

+ 19 - 1
Userland/Libraries/LibArchive/Zip.cpp

@@ -77,7 +77,7 @@ Optional<Zip> Zip::try_create(ReadonlyBytes buffer)
     };
 }
 
-ErrorOr<bool> Zip::for_each_member(Function<ErrorOr<IterationDecision>(ZipMember const&)> callback)
+ErrorOr<bool> Zip::for_each_member(Function<ErrorOr<IterationDecision>(ZipMember const&)> callback) const
 {
     size_t member_offset = m_members_start_offset;
     for (size_t i = 0; i < m_member_count; i++) {
@@ -104,6 +104,24 @@ ErrorOr<bool> Zip::for_each_member(Function<ErrorOr<IterationDecision>(ZipMember
     return true;
 }
 
+ErrorOr<Statistics> Zip::calculate_statistics() const
+{
+    size_t file_count = 0;
+    size_t directory_count = 0;
+    size_t uncompressed_bytes = 0;
+
+    TRY(for_each_member([&](auto zip_member) -> ErrorOr<IterationDecision> {
+        if (zip_member.is_directory)
+            directory_count++;
+        else
+            file_count++;
+        uncompressed_bytes += zip_member.uncompressed_size;
+        return IterationDecision::Continue;
+    }));
+
+    return Statistics(file_count, directory_count, uncompressed_bytes);
+}
+
 ZipOutputStream::ZipOutputStream(NonnullOwnPtr<Stream> stream)
     : m_stream(move(stream))
 {

+ 3 - 1
Userland/Libraries/LibArchive/Zip.h

@@ -15,6 +15,7 @@
 #include <AK/Stream.h>
 #include <AK/String.h>
 #include <AK/Vector.h>
+#include <LibArchive/Statistics.h>
 #include <LibCore/DateTime.h>
 #include <string.h>
 
@@ -254,7 +255,8 @@ struct ZipMember {
 class Zip {
 public:
     static Optional<Zip> try_create(ReadonlyBytes buffer);
-    ErrorOr<bool> for_each_member(Function<ErrorOr<IterationDecision>(ZipMember const&)>);
+    ErrorOr<bool> for_each_member(Function<ErrorOr<IterationDecision>(ZipMember const&)>) const;
+    ErrorOr<Statistics> calculate_statistics() const;
 
 private:
     static bool find_end_of_central_directory_offset(ReadonlyBytes, size_t& offset);

+ 6 - 16
Userland/Utilities/file.cpp

@@ -110,24 +110,14 @@ static ErrorOr<Optional<String>> zip_details(StringView description, StringView
 {
     auto mapped_file = TRY(Core::MappedFile::map(path));
     auto zip_file = Archive::Zip::try_create(mapped_file->bytes());
-    u32 files = 0;
-    u32 directories = 0;
-    u64 total_bytes = 0;
-    TRY(zip_file->for_each_member([&](auto zip_member) -> ErrorOr<IterationDecision> {
-        if (zip_member.is_directory)
-            directories++;
-        else
-            files++;
-        total_bytes += zip_member.uncompressed_size;
-        return IterationDecision::Continue;
-    }));
+    auto statistics = TRY(zip_file->calculate_statistics());
     return TRY(String::formatted("{}, {} {}, {} {} totaling {} uncompressed",
         description,
-        directories,
-        directories == 1 ? "directory" : "directories",
-        files,
-        files == 1 ? "file" : "files",
-        AK::human_readable_size(total_bytes)));
+        statistics.directory_count(),
+        statistics.directory_count() == 1 ? "directory" : "directories",
+        statistics.file_count(),
+        statistics.file_count() == 1 ? "file" : "files",
+        AK::human_readable_size(statistics.total_uncompressed_bytes())));
 }
 
 static ErrorOr<Optional<String>> elf_details(StringView description, StringView path)

+ 2 - 7
Userland/Utilities/unzip.cpp

@@ -146,22 +146,17 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     if (list_files) {
         outln("  Length     Date      Time     Name");
         outln("--------- ---------- --------   ----");
-        u32 members_count = 0;
-        u64 total_size = 0;
         TRY(zip_file->for_each_member([&](auto zip_member) -> ErrorOr<IterationDecision> {
-            members_count++;
-
             auto time = time_from_packed_dos(zip_member.modification_date, zip_member.modification_time);
             auto time_str = TRY(Core::DateTime::from_timestamp(time.seconds_since_epoch()).to_string());
 
-            total_size += zip_member.uncompressed_size;
-
             outln("{:>9} {}   {}", zip_member.uncompressed_size, time_str, zip_member.name);
 
             return IterationDecision::Continue;
         }));
+        auto statistics = TRY(zip_file->calculate_statistics());
         outln("---------                       ----");
-        outln("{:>9}                       {} files", total_size, members_count);
+        outln("{:>9}                       {} files", statistics.total_uncompressed_bytes(), statistics.member_count());
         return 0;
     }