Serenity Operating System
at master 67 lines 2.6 kB view raw
1/* 2 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibCompress/Gzip.h> 8#include <LibCore/ArgsParser.h> 9#include <LibCore/File.h> 10#include <LibCore/MappedFile.h> 11#include <LibCore/System.h> 12#include <LibMain/Main.h> 13#include <unistd.h> 14 15ErrorOr<int> serenity_main(Main::Arguments arguments) 16{ 17 Vector<StringView> filenames; 18 bool keep_input_files { false }; 19 bool write_to_stdout { false }; 20 bool decompress { false }; 21 22 Core::ArgsParser args_parser; 23 args_parser.add_option(keep_input_files, "Keep (don't delete) input files", "keep", 'k'); 24 args_parser.add_option(write_to_stdout, "Write to stdout, keep original files unchanged", "stdout", 'c'); 25 args_parser.add_option(decompress, "Decompress", "decompress", 'd'); 26 args_parser.add_positional_argument(filenames, "Files", "FILES"); 27 args_parser.parse(arguments); 28 29 if (write_to_stdout) 30 keep_input_files = true; 31 32 for (auto const& input_filename : filenames) { 33 DeprecatedString output_filename; 34 if (decompress) { 35 if (!input_filename.ends_with(".gz"sv)) { 36 warnln("unknown suffix for: {}, skipping", input_filename); 37 continue; 38 } 39 output_filename = input_filename.substring_view(0, input_filename.length() - ".gz"sv.length()); 40 } else { 41 output_filename = DeprecatedString::formatted("{}.gz", input_filename); 42 } 43 44 // We map the whole file instead of streaming to reduce size overhead (gzip header) and increase the deflate block size (better compression) 45 // TODO: automatically fallback to buffered streaming for very large files 46 RefPtr<Core::MappedFile> file; 47 ReadonlyBytes input_bytes; 48 if (TRY(Core::System::stat(input_filename)).st_size > 0) { 49 file = TRY(Core::MappedFile::map(input_filename)); 50 input_bytes = file->bytes(); 51 } 52 53 ByteBuffer output_bytes; 54 if (decompress) 55 output_bytes = TRY(Compress::GzipDecompressor::decompress_all(input_bytes)); 56 else 57 output_bytes = TRY(Compress::GzipCompressor::compress_all(input_bytes)); 58 59 auto output_stream = write_to_stdout ? TRY(Core::File::standard_output()) : TRY(Core::File::open(output_filename, Core::File::OpenMode::Write)); 60 TRY(output_stream->write_until_depleted(output_bytes)); 61 62 if (!keep_input_files) { 63 TRY(Core::System::unlink(input_filename)); 64 } 65 } 66 return 0; 67}