-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompressor.cpp
More file actions
136 lines (113 loc) · 5.27 KB
/
Copy pathcompressor.cpp
File metadata and controls
136 lines (113 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <zlib.h> // For compress() and crc32()
#include <filesystem> // For handling file paths and extensions
#include <sstream>
#include <iomanip>
#include <openssl/sha.h> // For SHA-256
namespace fs = std::filesystem;
// Computes salted SHA-256 hash of filename for consistent hashed output name
std::string sha256(const std::string& input) {
const std::string salt = "$packerx_";
std::string salted = salt + input;
unsigned char hash[SHA256_DIGEST_LENGTH];
// the SHA256 function from OpenSSL expects const unsigned char* as input
SHA256(reinterpret_cast<const unsigned char*>(salted.c_str()), salted.size(), hash);
std::ostringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
return ss.str();
}
// Compress the file content and calculate CRC32 of the original content
std::vector<unsigned char> compressFile(const std::string& filename, uLong& crcOut) {
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "Ran into error: Opening file: " << filename << std::endl;
return {};
}
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(file), {});
file.close();
if (buffer.empty()) {
std::cerr << "Oops! Received an empty file." << std::endl;
return {};
}
// Compute CRC32 checksum of original file content
crcOut = crc32(0L, Z_NULL, 0);
crcOut = crc32(crcOut, buffer.data(), buffer.size());
// Compress using zlib
uLong sourceSize = buffer.size();
uLong destSize = compressBound(sourceSize);
std::vector<unsigned char> compressed(destSize);
int result = compress(compressed.data(), &destSize, buffer.data(), sourceSize);
if (result != Z_OK)
{
std::cerr << "Compression failed with zlib error code: " << result << std::endl;
switch (result)
{
case Z_MEM_ERROR:
std::cerr << "Reason: Not enough memory." << std::endl;
break;
case Z_BUF_ERROR:
std::cerr << "Reason: Output buffer too small." << std::endl;
break;
case Z_DATA_ERROR:
std::cerr << "Reason: Input data corrupted or invalid." << std::endl;
break;
default:
std::cerr << "Reason: Unknown zlib error." << std::endl;
}
return {};
}
compressed.resize(destSize); // Trim buffer to actual compressed size
return compressed;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <file_to_compress>" << std::endl;
return 1;
}
std::string filepath = argv[1];
std::string filenameOnly = fs::path(filepath).stem().string();
// Hash the filename for anonymized output
std::string hashedName = sha256(filenameOnly);
// Extract extension (remove the leading dot)
std::string extension = fs::path(filepath).extension().string();
if (!extension.empty() && extension[0] == '.') extension = extension.substr(1);
if (extension.empty()) extension = "bin"; // Fallback extension
// Compress and get CRC32
uLong crc = 0;
std::vector<unsigned char> compressedData = compressFile(filepath, crc);
if (compressedData.empty()) return 1;
// Compose final binary: [1-byte extLen][extension][compressedData][4-byte CRC32]
unsigned char extLen = static_cast<unsigned char>(extension.length()); // int would be in 4 bytes so casting to char for 1 byte
std::vector<unsigned char> finalOutput;
finalOutput.push_back(extLen);
finalOutput.insert(finalOutput.end(), extension.begin(), extension.end());
finalOutput.insert(finalOutput.end(), compressedData.begin(), compressedData.end());
// Append CRC32 checksum : 4 bytes are added at last. computed in compressFile functions
finalOutput.push_back((crc >> 0) & 0xFF); // first 1 byte : 11111111 && crc right shift hence pushed last 8 bits
finalOutput.push_back((crc >> 8) & 0xFF); // last 8 to 15 bits
finalOutput.push_back((crc >> 16) & 0xFF); // last 16 to 23 bits
finalOutput.push_back((crc >> 24) & 0xFF); // last 24 to 31 bits pushed
// Output file path: compressed_output/<hashed>.bin
std::string outputFolder = "compressed_output";
std::string fullOutputPath = outputFolder + "/" + hashedName + ".bin";
std::ofstream out(fullOutputPath, std::ios::binary);
if (!out) {
std::cerr << "Failed to create output file: " << fullOutputPath << std::endl;
return 1;
}
// binary operations needed unsigned chars for proper low level functions, but here we have to write in char*. hence reinterpret casting
out.write(reinterpret_cast<const char*>(finalOutput.data()), finalOutput.size());
out.close();
std::cout << "Compression complete.\n";
std::cout << "Output: " << fullOutputPath << "\n";
std::cout << "SHA-256 (salted): " << hashedName << "\n";
std::cout << "Extension embedded: ." << extension << "\n";
std::cout << "CRC32: 0x" << std::hex << std::uppercase << crc << std::dec << "\n";
std::cout << "Original size: " << fs::file_size(filepath) << " bytes\n";
std::cout << "Compressed size (+meta): " << finalOutput.size() << " bytes\n";
return 0;
}