Advertisement
esimran

Untitled

Apr 23rd, 2017
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.53 KB | None | 0 0
  1. import java.util.PriorityQueue;
  2.  
  3. /**
  4. * Interface that all compression suites must implement. That is they must be
  5. * able to compress a file and also reverse/decompress that process.
  6. *
  7. * @author Brian Lavallee
  8. * @since 5 November 2015
  9. * @author Owen Atrachan
  10. * @since December 1, 2016
  11. */
  12. public class HuffProcessor {
  13.  
  14. public static final int BITS_PER_WORD = 8;
  15. public static final int BITS_PER_INT = 32;
  16. public static final int ALPH_SIZE = (1 << BITS_PER_WORD); // or 256
  17. public static final int PSEUDO_EOF = ALPH_SIZE;
  18. public static final int HUFF_NUMBER = 0xface8200;
  19. public static final int HUFF_TREE = HUFF_NUMBER | 1;
  20. public static final int HUFF_COUNTS = HUFF_NUMBER | 2;
  21.  
  22. public enum Header {
  23. TREE_HEADER, COUNT_HEADER
  24. };
  25.  
  26. public Header myHeader = Header.TREE_HEADER;
  27.  
  28. /**
  29. * Compresses a file. Process must be reversible and loss-less.
  30. *
  31. * @param in
  32. * Buffered bit stream of the file to be compressed.
  33. * @param out
  34. * Buffered bit stream writing to the output file.
  35. */
  36. public void compress(BitInputStream in, BitOutputStream out) {
  37. int[] counts = readForCounts(in); // creates frequency array
  38. HuffNode root = makeTreeFromCounts(counts); //creates tree with root
  39. String[] codings = makeCodingsFromTree(root, "", new String[257]); //create array where index is value and String is path
  40. out.writeBits(BITS_PER_INT, HUFF_TREE); //beginning code
  41. writeHeader(root, out); //writing header
  42. in.reset(); //reset to write compression after reading stream for counts
  43. writeCompressedBits(in, codings, out);
  44. }
  45.  
  46. public int[] readForCounts(BitInputStream in){
  47. int[] ans = new int[257]; //257 is for PSEUDO_EOF
  48. while (true) { //reads each bit value and adds one to frequency count
  49. int val = in.readBits(BITS_PER_WORD);
  50. if (val == -1)
  51. break;
  52. ans[val]++;
  53. }
  54. ans[256] = 1;
  55. return ans;
  56. }
  57.  
  58. public HuffNode makeTreeFromCounts(int[] counts){
  59. PriorityQueue<HuffNode> pq = new PriorityQueue<HuffNode>();
  60. for(int i = 0; i<counts.length; i++){ //adds all letters than are present as node with frequency as weight
  61. if(counts[i] != 0)
  62. pq.add(new HuffNode(i, counts[i]));
  63. }
  64. while(pq.size() > 1){
  65. HuffNode left = pq.remove();
  66. HuffNode right = pq.remove();
  67. HuffNode t = new HuffNode(-1, left.weight()+right.weight(), left, right); //creates node from left and right
  68. pq.add(t);
  69. }
  70. return pq.remove(); //root
  71. }
  72.  
  73. public String[] makeCodingsFromTree(HuffNode node, String current, String[] codings){
  74. if((node.left() == null) && (node.right() == null)){ //base case if leaf, then this is correct path
  75. codings[node.value()] = current;
  76. }
  77. //search left and right, add 0 to path if left, 1 if right, continue until you get all leaves
  78. if(node.left() != null){
  79. codings = makeCodingsFromTree(node.left(), current + "0", codings);
  80. }
  81. if(node.right() != null){
  82. codings = makeCodingsFromTree(node.right(), current + "1", codings);
  83. }
  84. return codings;
  85. }
  86.  
  87. public void writeHeader(HuffNode node, BitOutputStream out){
  88. if(node.value() != -1){ //if its a leaf, then add signal for leaf and write 9 bit value
  89. out.writeBits(1, 1);
  90. out.writeBits(9, node.value());
  91. } else out.writeBits(1, 0);
  92. //go let and right if its an intermediary node
  93. if(node.left() != null){
  94. writeHeader(node.left(), out);
  95. }
  96. if(node.right() != null){
  97. writeHeader(node.right(), out);
  98. }
  99. }
  100.  
  101. public void writeCompressedBits(BitInputStream in, String[] codings, BitOutputStream out){
  102. //read 8 bits at a time and replace them with encoded values
  103. int val = in.readBits(8);
  104. String encode;
  105. while(val != -1){
  106. encode = codings[val];
  107. out.writeBits(encode.length(), Integer.parseInt(encode, 2));
  108. val = in.readBits(8);
  109. }
  110. //add PSEUDO_EOF
  111. encode = codings[256];
  112. out.writeBits(encode.length(), Integer.parseInt(encode, 2));
  113. }
  114.  
  115. /**
  116. * Decompresses a file. Output file must be identical bit-by-bit to the
  117. * original.
  118. *
  119. * @param in
  120. * Buffered bit stream of the file to be decompressed.
  121. * @param out
  122. * Buffered bit stream writing to the output file.
  123. */
  124.  
  125. public void decompress(BitInputStream in, BitOutputStream out) {
  126. int val = in.readBits(BITS_PER_INT);
  127. if (!(val == HUFF_TREE || val == HUFF_COUNTS)) //checks for code that says I can decompress it
  128. throw new HuffException("Give valid input!");
  129. HuffNode root = readTreeHeader(in); //create tree
  130. readCompressedBits(root, in, out); //read the bits with new tree
  131. }
  132.  
  133. public HuffNode readTreeHeader(BitInputStream in) {
  134. int val = in.readBits(1);
  135. if (val == 0) { //if intermediary node
  136. return new HuffNode(0, 0, readTreeHeader(in), readTreeHeader(in));
  137. } else //leaf node
  138. return new HuffNode(in.readBits(9), 1);
  139. }
  140.  
  141. public void readCompressedBits(HuffNode root, BitInputStream in, BitOutputStream out) {
  142. HuffNode temp = root;
  143. while (true) {
  144. int val = in.readBits(1);
  145. //check which way down the tree to go for a specific bit
  146. if (val == 1) {
  147. temp = temp.right();
  148. } else
  149. temp = temp.left();
  150. if (temp.weight() == 1) { //if it is a character, otherwise, keep searching
  151. int value = temp.value();
  152. if (value == PSEUDO_EOF) { //if End of File, break
  153. break;
  154. } else
  155. out.write(value); //found a letter, write the new letter in 8 bit
  156. temp = root; //restart new letter at the beginning of the root again
  157. }
  158. }
  159. }
  160.  
  161. public void setHeader(Header header) {
  162. myHeader = header;
  163. System.out.println("header set to " + myHeader);
  164. }
  165. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement