-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.cpp
More file actions
179 lines (146 loc) · 5.17 KB
/
main.cpp
File metadata and controls
179 lines (146 loc) · 5.17 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <string>
#include <fstream>
#include <filesystem>
#include "file_reader.h"
#include "chunk_manager.h"
#define CHUNK_SIZE 4096
#include <filesystem>
namespace fs = std::filesystem;
void compress();
void decompress();
int main() {
while (true) {
std::cout << "\n1. Compress\n2. Decompress\n3. Exit\nChoice: ";
int choice;
std::cin >> choice;
switch (choice)
{
case 1:
compress();
break;
case 2:
decompress();
break;
case 3:
std::cout<<"Exiting....";
return 0;
break;
default:
std::cout<<"Invalid Choice..";
}
}
}
void compress() {
std::cout << "Enter source file: ";
std::string file;
std::cin >> file;
FileReader reader(file);
if (!reader.isOpen()) {
std::cerr << "Error: Could not open " << file << "\n";
return;
}
ChunkManager manager;
// We append .hce to the output filename
if (manager.start_session(file + ".hce")) {
char buffer[CHUNK_SIZE];
while (true) {
size_t bytes_read = reader.read(buffer, CHUNK_SIZE);
// 1. If we read data, process it (even if it's less than 4096)
if (bytes_read > 0) {
manager.process_chunk(buffer, bytes_read);
}
// 2. Check if we've reached the end of the file
// If bytes_read is less than CHUNK_SIZE, there's no more data left.
if (bytes_read < CHUNK_SIZE) {
break;
}
}
manager.end_session();
manager.print_stats(); // Display the final report
std::cout << "\nCompression successful: " << file << ".hce\n";
}
reader.close();
}
void decompress() {
std::cout << "Enter .hce file to decompress: ";
std::string input_path;
std::cin >> input_path;
// 1. Find the last slash to get JUST the filename
size_t last_slash = input_path.find_last_of("\\/");
std::string folder_path = "";
std::string filename = input_path;
if (last_slash != std::string::npos) {
folder_path = input_path.substr(0, last_slash + 1);
filename = input_path.substr(last_slash + 1);
}
// 2. Remove .hce extension if it exists
size_t ext_pos = filename.find(".hce");
std::string clean_name = (ext_pos != std::string::npos) ? filename.substr(0, ext_pos) : filename;
// 3. Combine them: Folder + "decompressed_" + Filename
std::string output_file = folder_path + "decompressed_" + clean_name;
std::ifstream in(input_path, std::ios::binary);
std::ofstream out(output_file, std::ios::binary);
if (!in.is_open()) {
std::cerr << "Error: Could not open INPUT file at: " << input_path << "\n";
return;
}
if (!out.is_open()) {
std::cerr << "Error: Could not create OUTPUT file at: " << output_file << "\n";
std::cerr << "Hint: Check if the folder is read-only or the path is invalid.\n";
return;
}
// 2. Verify Magic Signature (4 bytes)
char magic[4];
in.read(magic, 4);
if (std::string(magic, 3) != "HCE") {
std::cerr << "Error: Invalid HCE signature.\n";
return;
}
// Initialize algorithms
RLECompressor rle;
LZ4Compressor lz4;
ANSCompressor ans;
ChunkHeader header;
int chunkCount = 0;
// 3. Main Loop: Read the header FIRST
while (in.read(reinterpret_cast<char*>(&header), sizeof(ChunkHeader))) {
// Safety: Ensure we don't try to allocate zero or impossible memory
if (header.compressed_size == 0) continue;
std::vector<char> compressed_buffer(header.compressed_size);
// 4. Read exactly the amount specified by the header
if (!in.read(compressed_buffer.data(), header.compressed_size)) {
std::cerr << "Error: Unexpected end of file at chunk " << chunkCount << "\n";
break;
}
std::vector<char> decompressed_data;
// 5. Algorithm Selection based on Header ID
switch (header.algorithm) {
case PATH_RLE: // PATH_RLE
decompressed_data = rle.decompress(compressed_buffer);
break;
case PATH_LZ4: // PATH_LZ77
decompressed_data = lz4.decompress(compressed_buffer, header.original_size);;
break;
case PATH_ANS: // PATH_ANS
decompressed_data = ans.decompress(compressed_buffer);
break;
default: // PATH_BYPASS
decompressed_data = compressed_buffer;
break;
}
// 6. Hard-Constraint: Ensure the output matches the original chunk size
if (decompressed_data.size() > header.original_size) {
decompressed_data.resize(header.original_size);
}
if (!decompressed_data.empty()) {
out.write(decompressed_data.data(), decompressed_data.size());
}
chunkCount++;
}
// 7. Cleanup
out.flush();
out.close();
in.close();
std::cout << "\nDecompression finished. Processed " << chunkCount << " chunks." << std::endl;
}