#ifndef HUFFMAN_H #define HUFFMAN_H // Oldham, Jeffrey D. // 2000Apr26 // CS1321 // Huffman Codes // This class encapsulates use of Huffman trees for encoding and // decoding files. The two important (static) functions are // // 1) encode <- filename // -> ostream // 2) decode <- istream // -> ostream // // All interesting functions are static. It is not intended for // Huffman objects to be created. Use the functions like: // Huffman::encode(...) and Huffman::decode(...). // (Perhaps, not using a class would have been better.) // ASSUMPTIONS: // Use of ASCII encoding. // CHAR_BIT bits on both machine to encode and machine to decode. // The encoded document consists of // 1) the number of characters in the document (followed by one space), // 2) a Huffman tree, and // 3) the encoded characters. #include #include // has EXIT_SUCCESS #include "tree.h" #include "bitstream.h" #include "HuffmanTree.h" #include #include #include class Huffman { public: // Encode the document, sending to the specified stream. // Returns true if it succeeds. static bool encode(const string & filename, ostream& encoded) { // Record the characters' frequencies. ifstream in(filename.c_str()); if (!in) { cerr << "unable to open " << filename << endl; return false; } char c; unsigned long count = 0; map freq; while (in.get(c)) { ++count; ++freq[c]; } if (count > 0) { encoded << count << ' '; // Create the Huffman encoding tree. vector< HuffmanTree::freqChar > v; for (map::const_iterator pos = freq.begin(); pos != freq.end(); ++pos) v.push_back(HuffmanTree::freqChar(pos->second, pos->first)); HuffmanTree t(v); encoded << t; // Print the tree. // For faster encoding, convert the tree into a map from // characters to vectors of bools. mcb translation; convertTreeToMap(translation, vector(), t.getTree()); // Encode the characters. in.close(); // Move to the file's beginning. in.open(filename.c_str()); if (!in) { cerr << "unable to reopen " << filename << endl; return false; } bitostream b(encoded); while (in.get(c)) b.nextBits(translation[c]); } in.close(); return true; } // Decode the encoded document, sending it to the specified stream. static istream& decode(istream& encoded, ostream& decoded) { // Read the number of encoded characters. unsigned long nuEncodedChars; if (encoded >> nuEncodedChars && encoded.ignore()) { // Read the Huffman tree. HuffmanTree t; if (!(encoded >> t)) { cerr << "problem reading tree in encoded document\n"; throw "bad tree in encoded document"; } // Read the encoded characters. bitistream b(encoded); while (nuEncodedChars > 0) { decoded << readChar(b, t.getTree()); --nuEncodedChars; } } return encoded; } private: typedef map > mcb; // lazy programmer typedef unsigned long ul; // lazy programmer // Prevent creating Huffman objects. Huffman(void) {}; Huffman(const Huffman &) {}; Huffman(Huffman &) {}; // Return the next character from the encoded document. // This is a recursively defined function. Call the function // providing the Huffman tree. static char readChar(bitistream & b, const HuffmanTree::tfc & t) { if (HuffmanTree::leafp(t)) return t.item().second; else { bool bit; if (!b.nextBit(bit)) { cerr << "premature file end\n"; throw "premature file end"; } return readChar(b, bit==false ? t.left() : t.right()); } } // Convert a Huffman tree into a map from a character to a vector of // booleans. // vector encodes the path from the entire tree's root to // t's root. static void convertTreeToMap(mcb & m, vector v, const HuffmanTree::tfc & t) { if (HuffmanTree::leafp(t)) { m[t.item().second] = v; return; } else { vector v1(v); v1.push_back(false); convertTreeToMap(m, v1, t.left()); vector v2(v); v2.push_back(true); convertTreeToMap(m, v2, t.right()); return; } } }; #endif // HUFFMAN_H