@@ -31,14 +31,41 @@ public class HuffmanDecompressor implements Decompressor {
3131 */
3232 private final Map <String , Integer > huffmancodeToByteMap ;
3333
34+ /**
35+ * Path to the output file after decompression
36+ */
37+ private final String outputFilePath ;
38+
39+ /**
40+ * Byte reader for the compressed file
41+ */
42+ private ByteReader byteReader ;
43+
44+ /**
45+ * Byte writer for the decompressed output file
46+ */
47+ private ByteWriter byteWriter ;
48+
3449 /**
3550 * Constructor that takes a compressed file path and generates the Huffman code mapping
3651 * @param compressedFilePath The path to the compressed file to be decompressed
3752 */
3853 public HuffmanDecompressor (String compressedFilePath ) {
3954 logger .debug ("Initializing HuffmanDecompressor for file: {}" , compressedFilePath );
4055 this .compressedFilePath = compressedFilePath ;
56+ // Remove the .huffz extension to get the output file path
57+ this .outputFilePath = FileUtils .getUniqueFilePath (compressedFilePath .substring (0 ,
58+ compressedFilePath .length () - Constants .HUFFMAN_FILE_EXTENSION .length ()));
4159 this .huffmancodeToByteMap = generateHuffmanCodesFromZipFile (compressedFilePath );
60+
61+ try {
62+ this .byteReader = new ByteReader (compressedFilePath );
63+ this .byteWriter = new ByteWriter (outputFilePath );
64+ } catch (IOException e ) {
65+ logger .error ("Failed to initialize byte reader and writer: {}" , e .getMessage ());
66+ throw new RuntimeException ("Failed to initialize byte reader and writer: " + e .getMessage ());
67+ }
68+
4269 logger .debug ("Huffman code mapping generated successfully" );
4370 }
4471 /*******************************************************************************
@@ -72,12 +99,11 @@ private Map<String, Integer> generateHuffmanCodesFromZipFile(String compressedFi
7299 /**
73100 * Step 1: Read the number of unique characters from the compressed file header.
74101 *
75- * @param byteReader The byte reader for the compressed file
76102 * @return The number of unique byte values in the original file
77103 * @throws IOException If reading fails
78104 */
79- private int getUniqueCharCount (ByteReader byteReader ) throws IOException {
80- return byteReader .readInt ();
105+ private int getUniqueCharCount () throws IOException {
106+ return this . byteReader .readInt ();
81107 }
82108
83109 /**
@@ -87,17 +113,16 @@ private int getUniqueCharCount(ByteReader byteReader) throws IOException {
87113 * that indicates how many bits were added to make the compressed data byte-aligned.
88114 *
89115 * @param uniqueCharCount Number of unique characters to skip in the frequency table
90- * @param byteReader The byte reader for the compressed file
91116 * @return The number of padding bits (0-7) used in compression
92117 * @throws IOException If reading fails
93118 */
94- private int getExtraBits (int uniqueCharCount , ByteReader byteReader ) throws IOException {
119+ private int getExtraBits (int uniqueCharCount ) throws IOException {
95120 int i ;
96121 for (i = 0 ; i < uniqueCharCount ; i ++) {
97- byteReader .readNextByte ();
98- byteReader .readInt ();
122+ this . byteReader .readNextByte ();
123+ this . byteReader .readInt ();
99124 }
100- return byteReader .readInt ();
125+ return this . byteReader .readInt ();
101126 }
102127
103128 /**
@@ -106,16 +131,13 @@ private int getExtraBits(int uniqueCharCount, ByteReader byteReader) throws IOEx
106131 * This method reads compressed bytes, converts them to bits, and decodes them
107132 * using the Huffman code mapping to reconstruct the original data.
108133 *
109- * @param byteReader Reader for the compressed file
110- * @param byteWriter Writer for the decompressed output
111134 * @param bitReader Buffer for accumulating and processing bits
112- * @param huffmancodeToByteMap Mapping from Huffman codes to original byte values
113135 * @throws IOException If reading or writing fails
114136 */
115- private void processCompressedBytes (ByteReader byteReader , ByteWriter byteWriter , BitReader bitReader , Map < String , Integer > huffmancodeToByteMap ) throws IOException {
137+ private void processCompressedBytes (BitReader bitReader ) throws IOException {
116138 String [] byteToBinaryStrings = HuffmanUtils .createBinaryStringsForBytes ();
117139 while (true ) {
118- Byte currentByte = byteReader .readNextByte ();
140+ Byte currentByte = this . byteReader .readNextByte ();
119141 if (currentByte == null ) break ;
120142
121143 int byteAsInt = CommonUtil .byteToUnsignedInt (currentByte );
@@ -128,9 +150,9 @@ private void processCompressedBytes(ByteReader byteReader, ByteWriter byteWriter
128150 for (i = 0 ; i < bitReader .getAvailableBits (); i ++) {
129151 codeBuilder .append (bitReader .charAt (i ));
130152 String currentCode = codeBuilder .toString ();
131- Integer decodedByte = huffmancodeToByteMap .get (currentCode );
153+ Integer decodedByte = this . huffmancodeToByteMap .get (currentCode );
132154 if (decodedByte != null ) {
133- byteWriter .writeByte (decodedByte );
155+ this . byteWriter .writeByte (decodedByte );
134156 codeFound = true ;
135157 bitReader .consume (currentCode .length ());
136158 break ;
@@ -144,19 +166,18 @@ private void processCompressedBytes(ByteReader byteReader, ByteWriter byteWriter
144166 /***********************************************************************************
145167 * Decompresses file using Huffman codes
146168 **************************************************************************************/
147- private void decompressFile (String compressedFilePath , String outputFilePath , Map < String , Integer > huffmancodeToByteMap ) {
169+ private void decompressFile () {
148170 logger .info ("Decompressing file: {} -> {}" , compressedFilePath , outputFilePath );
149- try (ByteReader byteReader = new ByteReader (compressedFilePath );
150- ByteWriter byteWriter = new ByteWriter (outputFilePath )) {
171+ try {
151172 // Step1: Read the unique char count
152173 logger .debug ("Reading frequency table" );
153- int uniqueCharCount = getUniqueCharCount (byteReader );
174+ int uniqueCharCount = getUniqueCharCount ();
154175 // Step2: Read the extra padding bits
155- int extraBits = getExtraBits (uniqueCharCount , byteReader );
176+ int extraBits = getExtraBits (uniqueCharCount );
156177 BitReader bitReader = new BitReader (extraBits );
157178 // Step3: Process the compressed bytes
158179 logger .debug ("Decoding compressed content" );
159- processCompressedBytes (byteReader , byteWriter , bitReader , huffmancodeToByteMap );
180+ processCompressedBytes (bitReader );
160181 logger .info ("Decompression completed successfully" );
161182 } catch (IOException e ) {
162183 logger .error ("Failed to decompress file: {}" , compressedFilePath , e );
@@ -173,24 +194,6 @@ private void decompressFile(String compressedFilePath, String outputFilePath, Ma
173194 */
174195 @ Override
175196 public void decompress () {
176- // Remove the .huffz extension to get the output file path
177- String outputFilePath = compressedFilePath .substring (0 ,
178- compressedFilePath .length () - Constants .HUFFMAN_FILE_EXTENSION .length ());
179- // Get a unique file path if the file already exists
180- outputFilePath = FileUtils .getUniqueFilePath (outputFilePath );
181- decompressFile (compressedFilePath , outputFilePath , huffmancodeToByteMap );
182- }
183-
184- /**
185- * Decompresses the file to a specific output path
186- *
187- * @param outputFilePath The path where the decompressed file will be saved
188- * @throws RuntimeException if decompression fails
189- * @throws IllegalArgumentException if outputFilePath is null or invalid
190- */
191- @ Override
192- public void decompress (String outputFilePath ) {
193- FileUtils .validateOutputFilePath (outputFilePath );
194- decompressFile (compressedFilePath , outputFilePath , huffmancodeToByteMap );
197+ decompressFile ();
195198 }
196199}
0 commit comments