1 /* 2 * (C) 2014,2015 Jack Lloyd 3 * 4 * Botan is released under the Simplified BSD License (see license.txt) 5 */ 6 7 #include "cli.h" 8 9 #if defined(BOTAN_HAS_COMPRESSION) 10 #include <botan/compression.h> 11 #include <fstream> 12 #endif 13 14 namespace Botan_CLI { 15 16 #if defined(BOTAN_HAS_COMPRESSION) 17 18 class Compress final : public Command 19 { 20 public: Compress()21 Compress() : Command("compress --type=gzip --level=6 --buf-size=8192 file") {} 22 output_filename(const std::string & input_fsname,const std::string & comp_type)23 std::string output_filename(const std::string& input_fsname, const std::string& comp_type) 24 { 25 const std::map<std::string, std::string> suffixes = 26 { 27 { "zlib", "zlib" }, 28 { "gzip", "gz" }, 29 { "bzip2", "bz2" }, 30 { "lzma", "xz" }, 31 }; 32 33 auto suffix_info = suffixes.find(comp_type); 34 if(suffixes.count(comp_type) == 0) 35 { 36 throw CLI_Error_Unsupported("Compressing", comp_type); 37 } 38 39 return input_fsname + "." + suffix_info->second; 40 } 41 group() const42 std::string group() const override 43 { 44 return "compression"; 45 } 46 description() const47 std::string description() const override 48 { 49 return "Compress a given file"; 50 } 51 go()52 void go() override 53 { 54 const std::string comp_type = get_arg("type"); 55 const size_t buf_size = get_arg_sz("buf-size"); 56 const size_t comp_level = get_arg_sz("level"); 57 58 std::unique_ptr<Botan::Compression_Algorithm> compress; 59 60 compress.reset(Botan::make_compressor(comp_type)); 61 62 if(!compress) 63 { 64 throw CLI_Error_Unsupported("Compression", comp_type); 65 } 66 67 const std::string in_file = get_arg("file"); 68 std::ifstream in(in_file, std::ios::binary); 69 70 if(!in.good()) 71 { 72 throw CLI_IO_Error("reading", in_file); 73 } 74 75 const std::string out_file = output_filename(in_file, comp_type); 76 std::ofstream out(out_file, std::ios::binary); 77 if(!out.good()) 78 { 79 throw CLI_IO_Error("writing", out_file); 80 } 81 82 Botan::secure_vector<uint8_t> buf; 83 84 compress->start(comp_level); 85 86 while(in.good()) 87 { 88 buf.resize(buf_size); 89 in.read(reinterpret_cast<char*>(buf.data()), buf.size()); 90 buf.resize(in.gcount()); 91 92 compress->update(buf); 93 94 out.write(reinterpret_cast<const char*>(buf.data()), buf.size()); 95 } 96 97 buf.clear(); 98 compress->finish(buf); 99 out.write(reinterpret_cast<const char*>(buf.data()), buf.size()); 100 out.close(); 101 } 102 }; 103 104 BOTAN_REGISTER_COMMAND("compress", Compress); 105 106 class Decompress final : public Command 107 { 108 public: Decompress()109 Decompress() : Command("decompress --buf-size=8192 file") {} 110 parse_extension(const std::string & in_file,std::string & out_file,std::string & suffix)111 void parse_extension(const std::string& in_file, 112 std::string& out_file, 113 std::string& suffix) 114 { 115 auto last_dot = in_file.find_last_of('.'); 116 if(last_dot == std::string::npos || last_dot == 0) 117 { 118 throw CLI_Error("No extension detected in filename '" + in_file + "'"); 119 } 120 121 out_file = in_file.substr(0, last_dot); 122 suffix = in_file.substr(last_dot + 1, std::string::npos); 123 } 124 group() const125 std::string group() const override 126 { 127 return "compression"; 128 } 129 description() const130 std::string description() const override 131 { 132 return "Decompress a given compressed archive"; 133 } 134 go()135 void go() override 136 { 137 const size_t buf_size = get_arg_sz("buf-size"); 138 const std::string in_file = get_arg("file"); 139 std::string out_file, suffix; 140 parse_extension(in_file, out_file, suffix); 141 142 std::ifstream in(in_file, std::ios::binary); 143 144 if(!in.good()) 145 { 146 throw CLI_IO_Error("reading", in_file); 147 } 148 149 std::unique_ptr<Botan::Decompression_Algorithm> decompress; 150 151 decompress.reset(Botan::make_decompressor(suffix)); 152 153 if(!decompress) 154 { 155 throw CLI_Error_Unsupported("Decompression", suffix); 156 } 157 158 std::ofstream out(out_file, std::ios::binary); 159 if(!out.good()) 160 { 161 throw CLI_IO_Error("writing", out_file); 162 } 163 164 Botan::secure_vector<uint8_t> buf; 165 166 decompress->start(); 167 168 while(in.good()) 169 { 170 buf.resize(buf_size); 171 in.read(reinterpret_cast<char*>(buf.data()), buf.size()); 172 buf.resize(in.gcount()); 173 174 decompress->update(buf); 175 176 out.write(reinterpret_cast<const char*>(buf.data()), buf.size()); 177 } 178 179 buf.clear(); 180 decompress->finish(buf); 181 out.write(reinterpret_cast<const char*>(buf.data()), buf.size()); 182 out.close(); 183 } 184 }; 185 186 BOTAN_REGISTER_COMMAND("decompress", Decompress); 187 188 #endif 189 190 } 191