| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
#include "Base64.hh" |
| 6 |
|
| 7 |
#include <zlib.h> |
| 8 |
|
| 9 |
#include <bit> |
| 10 |
#include <cstdio> |
| 11 |
#include <cstdlib> |
| 12 |
#include <cstring> |
| 13 |
#include <iostream> |
| 14 |
#include <memory> |
| 15 |
#include <span> |
| 16 |
#include <sys/stat.h> |
| 17 |
#include <vector> |
| 18 |
|
| 19 |
std::string encode(std::span<const char> src) |
| 20 |
{ |
| 21 |
auto len = src.size(); |
| 22 |
uLongf dstLen = len + len / 1000 + 12 + 1; |
| 23 |
std::vector<unsigned char> buf(dstLen); |
| 24 |
if (compress2(buf.data(), &dstLen, |
| 25 |
std::bit_cast<const Bytef*>(src.data()), len, 9) |
| 26 |
!= Z_OK) { |
| 27 |
std::cerr << "Error while compressing blob.\n"; |
| 28 |
exit(1); |
| 29 |
} |
| 30 |
return Base64::encode(std::span(buf.data(), dstLen)); |
| 31 |
} |
| 32 |
|
| 33 |
std::string decode(std::span<const char> src) |
| 34 |
{ |
| 35 |
static const unsigned MAX_SIZE = 1024 * 1024; |
| 36 |
auto decBuf = Base64::decode(std::string_view(src.data(), src.size())); |
| 37 |
std::vector<char> buf(MAX_SIZE); |
| 38 |
uLongf dstLen = MAX_SIZE; |
| 39 |
if (uncompress(std::bit_cast<Bytef*>(buf.data()), &dstLen, |
| 40 |
std::bit_cast<const Bytef*>(decBuf.data()), uLong(decBuf.size())) |
| 41 |
!= Z_OK) { |
| 42 |
std::cerr << "Error while decompressing blob.\n"; |
| 43 |
exit(1); |
| 44 |
} |
| 45 |
return {buf.data(), dstLen}; |
| 46 |
} |
| 47 |
|
| 48 |
int main(int argc, const char** argv) |
| 49 |
{ |
| 50 |
std::span<const char*> arg(argv, argc); |
| 51 |
if (arg.size() != 3) { |
| 52 |
std::cerr << "Usage: " << arg[0] << " <input> <output>\n"; |
| 53 |
exit(1); |
| 54 |
} |
| 55 |
using FILE_t = std::unique_ptr<FILE, decltype([](FILE* f) { fclose(f); })>; |
| 56 |
FILE_t inf(fopen(arg[1], "rb")); |
| 57 |
if (!inf) { |
| 58 |
std::cerr << "Error while opening " << arg[1] << '\n'; |
| 59 |
exit(1); |
| 60 |
} |
| 61 |
struct stat st; |
| 62 |
fstat(fileno(inf.get()), &st); |
| 63 |
size_t size = st.st_size; |
| 64 |
std::vector<char> inBuf(size); |
| 65 |
if (fread(inBuf.data(), size, 1, inf.get()) != 1) { |
| 66 |
std::cerr << "Error while reading " << arg[1] << '\n'; |
| 67 |
exit(1); |
| 68 |
} |
| 69 |
|
| 70 |
std::string result; |
| 71 |
if (strstr(arg[0], "encode-gz-base64")) { |
| 72 |
result = encode(inBuf); |
| 73 |
} else if (strstr(arg[0], "decode-gz-base64")) { |
| 74 |
result = decode(inBuf); |
| 75 |
} else { |
| 76 |
std::cerr << "This executable should be named 'encode-gz-base64' or " |
| 77 |
"'decode-gz-base64'.\n"; |
| 78 |
exit(1); |
| 79 |
} |
| 80 |
|
| 81 |
FILE_t outf(fopen(arg[2], "wb+")); |
| 82 |
if (!outf) { |
| 83 |
std::cerr << "Error while opening " << arg[2] << '\n'; |
| 84 |
exit(1); |
| 85 |
} |
| 86 |
|
| 87 |
if (fwrite(result.data(), result.size(), 1, outf.get()) != 1) { |
| 88 |
std::cerr << "Error while writing " << arg[2] << '\n'; |
| 89 |
exit(1); |
| 90 |
} |
| 91 |
} |