Huffman Zipper  v-1.0
Data Compression and Decompression using Greedy Huffman Algorithm
Decompressor.cpp
Go to the documentation of this file.
1 #include "Decompressor.h"
2 
3 Decompressor::Decompressor() :rootNode(nullptr) {}
4 
6  //clear();
7 }
8 
10  files.clear();
12  rootNode = nullptr;
13 }
14 
16  if (node == nullptr) return;
17 
18  deleteTree(node->getLeftChild());
19  deleteTree(node->getRightChild());
20 
21  delete node;
22 }
23 
24 BinNode* Decompressor::readTree(std::ifstream& reader) {
25  char nodeType;
26  reader.get(nodeType);
27  if (!(nodeType == '1' || nodeType == '0')) {
28  throw std::runtime_error("Compressed file is corrupted.");
29  }
30 
31  if (nodeType == '1') {
32  char ch;
33  reader.get(ch);
34  BinNode* head = new BinNode(ch);
35  return head;
36  }
37 
39  head->setLeftChild(readTree(reader));
40  head->setRightChild(readTree(reader));
41  return head;
42 }
43 
44 void Decompressor::readHeader(const std::string& infileName, std::ifstream& infile) {
46 
48  uint16_t fileCount = 0;
49  infile.read(reinterpret_cast<char*>(&fileCount), sizeof(fileCount));
50 
52  std::filesystem::path p(infileName);
53  if (!std::filesystem::exists(p))
54  throw std::runtime_error("ERROR: Compressed file couldn't be found");
55  p = p.parent_path() / p.stem().concat(" (decompressed)");
56 
57  char ch;
58  unsigned int chars = 0;
59  std::string fileData;
60  for (int i = 0; i < fileCount; i++) {
61  infile.read(reinterpret_cast<char*>(&chars), sizeof(chars));
62 
63  while (infile.get(ch)) {
64  fileData += ch;
65  if (ch == FILE_NAME_SEPARATOR) {
66  fileData.pop_back();
67 
68  auto path = p / fileData;
69  if (!std::filesystem::exists(path.parent_path())) {
70  if (!std::filesystem::create_directories(path.parent_path())) {
71  throw std::runtime_error("ERROR : Couldn't create output directories");
72  }
73  }
74  files.enqueue(fileInfo(chars, path));
75 
76  fileData.clear();
77  break;
78  }
79  }
80  }
81 }
82 
83 void Decompressor::writeIntoFile(const std::string& infileName) {
84  fs::path outfilePath = files.getFront().filePath;
85  std::ofstream outfile(outfilePath, std::ios::out | std::ios::binary | std::ios::trunc);
86  if (!outfile)
87  throw std::runtime_error("Output Error : \'" + outfilePath.string() + "\' couldn't be created");
88  std::cout << "Writing into : " << outfilePath.filename() << std::endl;
89 
90  char ch;
91  unsigned int fileChars = 0;
92  BinNode* curr = rootNode;
93  while (infile.read(reinterpret_cast<char*>(&ch), sizeof(ch)) && !files.isEmpty()) {
94  for (auto&& binCode : std::bitset<8>(ch).to_string()) {
95  if (binCode == '0')
96  curr = curr->getLeftChild();
97  else if (binCode == '1')
98  curr = curr->getRightChild();
99  else
100  throw std::logic_error("Assertion error: Invalid binary code");
101 
102  if (curr->isLeaf()) {
103  outfile.put(curr->getCharacter());
104  curr = rootNode;
105 
106  fileChars++;
107  if (fileChars == files.getFront().fileSize) {
108  fileChars = 0;
109  files.dequeue();
110 
111  outfile.flush();
112  outfile.close();
113 
114  if (files.isEmpty()) break;
115 
116  outfilePath = files.getFront().filePath;
117  outfile.open(outfilePath, std::ios::out | std::ios::binary | std::ios::trunc);
118  if (!outfile)
119  throw std::runtime_error("Output Error : \'" + outfilePath.string() + "\' couldn't be created");
120  std::cout << "Writing into : " << outfilePath.filename() << std::endl;
121  }
122  }
123  }
124  }
125 
126  infile.close();
127  outfile.flush();
128  outfile.close();
129 
130  if (!fileChars && !files.isEmpty())
131  throw std::runtime_error("ERROR: Compressed file is corrupted");
132 }
133 
134 void Decompressor::decompressFile(const std::string& infileName) {
135  if (fs::path(infileName).extension().string() != ".huf") {
136  throw std::runtime_error("Enter compressed (.huf) file");
137  }
138 
139  std::cout << "Huffman Decompression\n";
140  std::cout << std::string(22, char(205));
141 
142  std::cout << "\nDecompressing ..." << std::endl;
143  auto start = std::chrono::steady_clock::now();
144 
145  infile.open(infileName, std::ios::in | std::ios::binary);
146  if (!infile)
147  throw std::runtime_error("Input Error : \'" + infileName + "\' couldn't be opened");
148 
149  std::cout << "Reading File Header ..." << std::endl;
150  std::cout << "Building decoding Tree ..." << std::endl;
151  readHeader(infileName, infile);
152  std::cout << files.size() << " file(s) to be obtained after decompression" << std::endl;
153 
154  std::cout << "Decoding Characters ..." << std::endl;
155  writeIntoFile(infileName);
156 
157  std::cout << "Cleaning Up ..." << std::endl;
158  clear();
159 
160  std::cout << "Success : Decompression Completed.\n" << std::endl;
161  std::cout << "Decompressed Folder : " << fs::path(infileName).parent_path().string() << std::endl;
162 
163  auto stop = std::chrono::steady_clock::now();
164  auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(stop - start);
165  std::cout << "Decompression Time : " << duration.count() << " seconds\n" << std::endl;
166 
167 }
constexpr auto INTERNAL_NODE_CHARACTER
Constants for Huffman Tree.
Definition: Constants.h:20
constexpr auto FILE_NAME_SEPARATOR
Constants for file Header.
Definition: Constants.h:23
This class models a node structure used for building Huffman Binary Tree.
Definition: BinNode.h:9
BinNode * getRightChild() const
Definition: BinNode.cpp:45
void setRightChild(BinNode *)
sets parameter node as left child of the caller node instance.
Definition: BinNode.cpp:37
bool isLeaf()
Definition: BinNode.cpp:49
void setLeftChild(BinNode *)
sets parameter node as left child of the caller node instance.
Definition: BinNode.cpp:33
BinNode * getLeftChild() const
Definition: BinNode.cpp:41
char getCharacter() const
Definition: BinNode.cpp:25
void clear()
Resets all the attributes for next decompression operation.
Definition: Decompressor.cpp:9
std::ifstream infile
Instance of ifstream class for reading encoded characters from compressed file.
Definition: Decompressor.h:45
Queue< fileInfo > files
Queue of input file(s) to be decompressed.
Definition: Decompressor.h:42
void readHeader(const std::string &infileName, std::ifstream &infile)
Reads the header section from compressed file.
void deleteTree(BinNode *node)
Frees all heap storage associated with the Huffman Tree.
void decompressFile(const std::string &infileName)
Decompresses the compressed(.huf) file to its original form.
BinNode * rootNode
Root node for Huffman tree.
Definition: Decompressor.h:48
void writeIntoFile(const std::string &infileName)
Decodes encoded characters using the tree obtained from header section.
BinNode * readTree(std::ifstream &reader)
Reads the entire Huffman tree in to the file header section using a pre-order traversal algorithm.
Structure to hold file metadata.
Definition: Decompressor.h:33