mortified_penguin

huff_code.cpp

Dec 29th, 2012
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.92 KB | None | 0 0
  1. #include "code.hpp"
  2. #include "tree.hpp"
  3.  
  4. #include <cstdio>
  5. #include <map>
  6. #include <stdexcept>
  7.  
  8.  
  9. // Helper functions for compressor
  10. std::string generate_code(std::string plaintext, const tree &t);
  11. void search(node *r, const char c, bool &found, std::string &plaincode);
  12.  
  13.  
  14. compr::compr(std::string &infile_, const opentype opentype_)
  15. {
  16.    if (opentype_ == opentype::BINARY)
  17.       infile.open(infile_, std::ios::binary);
  18.    if (opentype_ == opentype::PLAIN)
  19.       infile.open(infile_);
  20.  
  21.    if (!(infile.is_open()))
  22.       throw std::runtime_error("Error opening file\n");
  23. }
  24.  
  25. compr::~compr()
  26. {
  27.    infile.close();
  28. }
  29.  
  30.  
  31. compress::compress(std::string infile_): compr(infile_, opentype::PLAIN)
  32. {}
  33.  
  34. void compress::write(const std::string outfile_)
  35. {
  36.    std::ofstream outfile(outfile_, std::ios::binary | std::ios::trunc);
  37.    if (!(outfile.is_open()))
  38.        throw std::runtime_error("Error opening file\n");
  39.  
  40.    //  create a histogram
  41.    std::string plaintext;
  42.    for (std::string line; std::getline(infile, line); ) {
  43.       line += '\n';
  44.       for (unsigned i = 0; i<=line.size(); histog[line[i++]]++);
  45.       plaintext += line;
  46.    }
  47.  
  48.  
  49.    tree hcode(histog);
  50.    std::string plaincode = generate_code(plaintext, hcode);
  51.  
  52.    //  write huffman-code to file
  53.    uint16_t streamOffset = (sizeof(int)+sizeof(char))*histog.size()+sizeof(uint16_t);
  54.    outfile.write(reinterpret_cast<char*>(&streamOffset), 2);
  55.  
  56.    //  write chars and their weights into the binary file
  57.    for (auto it = histog.begin(); it != histog.end(); ++it) {
  58.       outfile.put(it->first);
  59.       outfile.write(reinterpret_cast<char*>(&(it->second)), sizeof(int));
  60.    }
  61.  
  62.    //  write length of last byte
  63.    std::string pcode = plaincode;
  64.    outfile.put(pcode.length() %8);
  65.  
  66.    //  since only full bytes are written to file, pad last byte
  67.    while (pcode.length() %8 != 0)
  68.       pcode.push_back('0');
  69.  
  70.    for (; !(pcode.empty()); pcode = pcode.substr(8)) {
  71.       unsigned char byte = 0;
  72.       for (int j=0; j<8; ++j) {
  73.          if (pcode.at(j) == '1')
  74.             byte |= 0x01;
  75.          else
  76.             byte &= ~(0x01);
  77.          if (j < 7) byte<<=1;
  78.       }
  79.       outfile.put(byte);
  80.    }
  81.    outfile.close();
  82. }
  83.  
  84.  
  85. std::string generate_code(std::string plaintext, const tree &t)
  86. {
  87.    std::string plaincode;
  88.    while (!(plaintext.empty())) {
  89.       node *p = t.rootnode();
  90.       bool found = false;
  91.  
  92.       search(p, plaintext[0], found, plaincode);
  93.  
  94.       plaintext = plaintext.substr(1, plaintext.length()-1);
  95.    }
  96.    return plaincode;
  97. }
  98. void search(node *r, const char c, bool &found, std::string &plaincode)
  99. {
  100.    if (r->left->type() == nodetype::LEAF && dynamic_cast<leaf*>(r->left)->payload == c) {
  101.       found = true;
  102.       plaincode.append("0");
  103.       return;
  104.    }
  105.    if (r->right->type() == nodetype::LEAF && dynamic_cast<leaf*>(r->right)->payload == c) {
  106.       found = true;
  107.       plaincode.append("1");
  108.       return;
  109.    }
  110.  
  111.    if (!found && !(r->left->type() == nodetype::LEAF)) {
  112.       plaincode.append("0");
  113.       search(r->left, c, found, plaincode);
  114.       //  We went the wrong way; pop the last char successively
  115.       if (!found)
  116.          plaincode = plaincode.substr(0, plaincode.length()-1);
  117.    }
  118.    if (!found && !(r->right->type() == nodetype::LEAF)) {
  119.       plaincode.append("1");
  120.       search(r->right, c, found, plaincode);
  121.       if (!found)
  122.          plaincode = plaincode.substr(0, plaincode.length()-1);
  123.    }
  124. }
  125.  
  126.  
  127.  
  128. decompress::decompress(std::string infile_): compr(infile_, opentype::BINARY)
  129. {
  130.    //  first byte in the file denotes the offset to the bitstream
  131.    infile.read(reinterpret_cast<char*>(&stream_offset), 2);
  132.  
  133.    for (int i=2; i<stream_offset; i += sizeof(int)+sizeof(char)) {
  134.       char ch = infile.get();
  135.       int weight;
  136.       infile.read(reinterpret_cast<char*>(&weight), sizeof(int));
  137.       histog[ch] = weight;
  138.    }
  139.  
  140.    tree hcode(histog);
  141.  
  142.    getplain(hcode);
  143. }
  144.  
  145. std::string decompress::plaintext() const
  146. {
  147.    return ptext;
  148. }
  149.  
  150.  
  151. void decompress::getplain(const tree &hc)
  152. {
  153.    infile.seekg(stream_offset, std::ios_base::beg);
  154.    unsigned char length_last_byte = infile.get();
  155.  
  156.    node *traverser = hc.rootnode();
  157.    bool found = false;
  158.    unsigned char stream;
  159.    for (stream = infile.get(); infile.peek() != EOF; stream = infile.get()) {
  160.       for (int j=0; j<8; ++j) {
  161.          //  go back to the root when we have found a character
  162.          if (found) {
  163.             traverser = hc.rootnode();
  164.             found = false;
  165.          }
  166.  
  167.          if (stream & 0x80) {
  168.             if (traverser->right->type() == nodetype::LEAF) {
  169.                leaf *right = dynamic_cast<leaf*>(traverser->right);
  170.                ptext.push_back(right->payload);
  171.                found = true;
  172.             } else {
  173.                traverser = traverser->right;
  174.             }
  175.          } else {
  176.             if (traverser->left->type() == nodetype::LEAF) {
  177.                leaf *left = dynamic_cast<leaf*>(traverser->left);
  178.                ptext.push_back(left->payload);
  179.                found = true;
  180.             } else {
  181.                traverser = traverser->left;
  182.             }
  183.          }
  184.          stream <<= 1;
  185.       }
  186.    }
  187.  
  188.    //  handle the last byte
  189.    for (int i=0; i<length_last_byte; ++i) {
  190.       if (found) {
  191.          traverser = hc.rootnode();
  192.          found = false;
  193.       }
  194.       if (stream & 0x80) {
  195.          if (traverser->right->type() == nodetype::LEAF) {
  196.             leaf *right = dynamic_cast<leaf*>(traverser->right);
  197.             ptext.push_back(right->payload);
  198.             found = true;
  199.          } else {
  200.             traverser = traverser->right;
  201.          }
  202.       } else {
  203.          if (traverser->left->type() == nodetype::LEAF) {
  204.             leaf *left = dynamic_cast<leaf*>(traverser->left);
  205.             ptext.push_back(left->payload);
  206.             found = true;
  207.          } else {
  208.             traverser = traverser->left;
  209.          }
  210.       }
  211.       stream <<= 1;
  212.    }
  213. }
Advertisement
Add Comment
Please, Sign In to add comment