-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
148 lines (112 loc) · 3.97 KB
/
main.cpp
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
#include <iostream>
#include <fstream>
#include <cstring>
#include "HuffmanTree.h"
#include "HuffmanReader.h"
using namespace std;
void compress(const string &sourceFile, unsigned long long bytesPerTree);
void decompress(const string &sourceFile);
int main(int argc, char** argv) {
clock_t initialTime = clock(), finalTime;
if ((argc < 3 || argc > 4) || (argv[1][1] != 'c' && argv[1][1] != 'd') || (argc == 4 && argv[1][1] != 'c') || (argc == 3 && argv[1][1] != 'd')) {
cout << "Arguments: [-c N |-d] file" << endl;
exit(1);
} else if (argv[1][1] == 'c') {
unsigned long long bytesPerTree = static_cast<unsigned long long>(stoi(argv[2]));
bytesPerTree = bytesPerTree == 0 ? UINT64_MAX : bytesPerTree;
compress(argv[3], bytesPerTree);
} else if (argv[1][1] == 'd') {
decompress(argv[2]);
}
finalTime = clock();
long executionTime = ((finalTime - initialTime) / (CLOCKS_PER_SEC / 1000));
cout << "t: " << executionTime << " ms" << endl;
return 0;
}
void compress(const string &sourceFile, const unsigned long long bytesPerTree) {
ifstream inFile(sourceFile, ifstream::in);
if(!inFile.good()) {
cout << "Failed to open the file!" << endl;
}
// frequency and totalBytes declaration
unsigned long frequencies[256];
memset(&frequencies, 0, sizeof(unsigned long) * 256);
short totalSymbols = 0;
// read file frequency and total bytes
int symbol;
while((symbol = inFile.get()) != EOF) {
if(frequencies[symbol] == 0) totalSymbols++;
frequencies[symbol]++;
}
// return to begin of inFile
inFile.clear();
inFile.seekg(0, inFile.beg);
// output file
HuffmanWriter writer(sourceFile + ".huff", frequencies, bytesPerTree);
unsigned long long bytesThisTree = 0;
HuffmanTree* tree = nullptr;
// file compression
while(totalSymbols > 1) {
if(tree == nullptr)
tree = buildHuffmanTree(frequencies);
int value = inFile.get(); // get char value from file
tree->leafPointers[value]->writeCodeIn(writer);
frequencies[value]--;
if(frequencies[value] == 0) totalSymbols--;
bytesThisTree++;
if(bytesThisTree == bytesPerTree) {
delete tree;
tree = nullptr;
bytesThisTree = 0;
}
}
inFile.close();
writer.close();
}
void decompress(const string &sourceFile) {
if(sourceFile.size() <= 5 || sourceFile.substr(sourceFile.find_last_of('.')) != ".huff") {
cout << "Invalid compressed file! (not .huff)!" << endl;
exit(1);
}
string outFileName = sourceFile.substr(0, sourceFile.find_last_of('.'));
HuffmanReader reader(sourceFile);
ofstream outFile(outFileName, ofstream::binary);
unsigned long (&frequencies)[256] = reader.frequencies;
unsigned long long &bytesPerTree = reader.bytesPerTree;
short totalSymbols = 0;
// count number of different symbols in the source file
for(auto& frequency : frequencies) if(frequency > 0) totalSymbols++;
unsigned long long bytesThisTree = 0;
HuffmanTree* tree = nullptr;
// decompress file
while(totalSymbols > 1) {
if(tree == nullptr)
tree = buildHuffmanTree(frequencies);
Node* node = tree->root;
while(!node->isLeaf()) {
node = node->getChild(reader.getBit());
}
unsigned char value = node->character;
outFile.put(value);
frequencies[value]--;
if(frequencies[value] == 0) {
totalSymbols--;
}
bytesThisTree++;
if(bytesThisTree == bytesPerTree) {
delete tree;
tree = nullptr;
bytesThisTree = 0;
}
}
// search and writes the remaining symbol
for (int i = 0; i < 256; i++) {
if(frequencies[i] > 0) {
while(frequencies[i]--) {
outFile.put((unsigned char)i);
}
}
}
reader.close();
outFile.close();
}