Skip to content

Commit da39456

Browse files
committed
test message
1 parent 48ed35b commit da39456

File tree

9 files changed

+4835
-242
lines changed

9 files changed

+4835
-242
lines changed

logs/file-compression.log

Lines changed: 4785 additions & 0 deletions
Large diffs are not rendered by default.

src/main/java/prog/compression/Compressor.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,6 @@ public interface Compressor {
2424
*/
2525
void compress();
2626

27-
/**
28-
* Compresses the file to a specific output path.
29-
* Allows the caller to specify exactly where the compressed file should be saved.
30-
*
31-
* @param outputFilePath The absolute path where the compressed file will be saved
32-
* @throws RuntimeException if compression fails
33-
* @throws IllegalArgumentException if outputFilePath is null or invalid
34-
*/
35-
void compress(String outputFilePath);
36-
3727
/**
3828
* Cleans up any resources used by the compressor.
3929
* Should be called after compression is complete.

src/main/java/prog/compression/Decompressor.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,4 @@ public interface Decompressor {
2222
* @throws RuntimeException if decompression fails
2323
*/
2424
void decompress();
25-
26-
/**
27-
* Decompresses the file to a specific output path.
28-
* Allows the caller to specify exactly where the decompressed file should be saved.
29-
*
30-
* @param outputFilePath The absolute path where the decompressed file will be saved
31-
* @throws RuntimeException if decompression fails
32-
* @throws IllegalArgumentException if outputFilePath is null or invalid
33-
*/
34-
void decompress(String outputFilePath);
3525
}

src/main/java/prog/huffman/HuffmanCompressor.java

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ public class HuffmanCompressor implements Compressor {
2121
*/
2222
private final String inputFilePath;
2323

24+
/**
25+
* Path to the output file that will be compressed
26+
* Example: "/home/user/document.txt.huffz"
27+
*/
28+
private final String outputFilePath;
29+
2430
/**
2531
* Array storing the frequency of each byte value (0-255) in the input file
2632
* Index represents the byte value, value represents the count
@@ -51,6 +57,7 @@ public class HuffmanCompressor implements Compressor {
5157
public HuffmanCompressor(String inputFilePath) {
5258
logger.debug("Initializing HuffmanCompressor for file: {}", inputFilePath);
5359
this.inputFilePath = inputFilePath;
60+
this.outputFilePath = inputFilePath + Constants.HUFFMAN_FILE_EXTENSION;
5461
this.frequency = HuffmanUtils.calculateFrequencyOfBytesInFile(inputFilePath);
5562

5663
if (HuffmanUtils.isEmptyFile(frequency)) {
@@ -68,31 +75,31 @@ public HuffmanCompressor(String inputFilePath) {
6875
/**
6976
* Step 1: Write the table size
7077
*/
71-
private void writeTableSize(ByteWriter writer, int[] frequency) throws IOException {
72-
writer.writeInt(HuffmanUtils.calculateUniqueByteCount(frequency));
78+
private void writeTableSize(ByteWriter writer) throws IOException {
79+
writer.writeInt(HuffmanUtils.calculateUniqueByteCount(this.frequency));
7380
}
7481

7582
/**
7683
* Step 2: Write the frequency table
7784
*/
78-
private void writeFrequencyTable(ByteWriter writer, int[] frequency) throws IOException {
85+
private void writeFrequencyTable(ByteWriter writer) throws IOException {
7986
for (int i = 0; i < Constants.BYTE_VALUES_COUNT; i++) {
80-
if (frequency[i] != 0) {
87+
if (this.frequency[i] != 0) {
8188
byte currentByte = (byte) i;
8289
writer.writeByte(currentByte);
83-
writer.writeInt(frequency[i]);
90+
writer.writeInt(this.frequency[i]);
8491
}
8592
}
8693
}
8794

8895
/**
8996
* Step 3: Calculate and write extra bits needed for padding
9097
*/
91-
private void writeExtraBits(ByteWriter writer, int[] frequency, String[] huffmanCodes) throws IOException {
98+
private void writeExtraBits(ByteWriter writer) throws IOException {
9299
int totalBinaryDigitsMod8 = 0;
93100
for(int i = 0; i < Constants.BYTE_VALUES_COUNT; i++) {
94-
if (huffmanCodes[i] != null) {
95-
totalBinaryDigitsMod8 += huffmanCodes[i].length() * frequency[i];
101+
if (this.huffmanCodes[i] != null) {
102+
totalBinaryDigitsMod8 += this.huffmanCodes[i].length() * this.frequency[i];
96103
totalBinaryDigitsMod8 %= Constants.BITS_PER_BYTE;
97104
}
98105
}
@@ -104,12 +111,12 @@ private void writeExtraBits(ByteWriter writer, int[] frequency, String[] huffman
104111
* Step 4: Encode and write the compressed content using Huffman codes
105112
* Reads each byte from input, converts to its Huffman code, and writes compressed output
106113
*/
107-
private void encodeAndWriteContent(ByteReader reader, ByteWriter writer, String[] huffmanCodes) throws IOException {
114+
private void encodeAndWriteContent(ByteReader reader, ByteWriter writer) throws IOException {
108115
StringBuilder bitBuffer = new StringBuilder();
109116
Byte currentByte;
110117

111118
while ((currentByte = reader.readNextByte()) != null) {
112-
String huffmanCodeOfCurrentByte = huffmanCodes[CommonUtil.byteToUnsignedInt(currentByte)];
119+
String huffmanCodeOfCurrentByte = this.huffmanCodes[CommonUtil.byteToUnsignedInt(currentByte)];
113120
bitBuffer.append(huffmanCodeOfCurrentByte);
114121

115122
while(bitBuffer.length() >= Constants.BITS_PER_BYTE) {
@@ -123,25 +130,25 @@ private void encodeAndWriteContent(ByteReader reader, ByteWriter writer, String[
123130
}
124131
}
125132

126-
private void compressFile(String inputFilePath, String outputFilePath, int[] frequency, String[] huffmanCodes) {
133+
private void compressFile() {
127134
logger.info("Compressing file: {} -> {}", inputFilePath, outputFilePath);
128135
try (ByteReader reader = new ByteReader(inputFilePath);
129136
ByteWriter writer = new ByteWriter(outputFilePath)) {
130137

131138
// Step1: Write the table size
132139
logger.debug("Writing frequency table");
133-
writeTableSize(writer, frequency);
140+
writeTableSize(writer);
134141

135142
// Step2: Write the table
136-
writeFrequencyTable(writer, frequency);
143+
writeFrequencyTable(writer);
137144

138145
// Step3: Write extra bits needed for padding
139146
logger.debug("Writing padding information");
140-
writeExtraBits(writer, frequency, huffmanCodes);
147+
writeExtraBits(writer);
141148

142149
// Step4: Encode and write the compressed content
143150
logger.debug("Encoding and writing compressed content");
144-
encodeAndWriteContent(reader, writer, huffmanCodes);
151+
encodeAndWriteContent(reader, writer);
145152

146153
logger.info("Compression completed successfully");
147154
} catch (IOException e) {
@@ -158,21 +165,7 @@ private void compressFile(String inputFilePath, String outputFilePath, int[] fre
158165
*/
159166
@Override
160167
public void compress() {
161-
String outputFilePath = inputFilePath + Constants.HUFFMAN_FILE_EXTENSION;
162-
compressFile(inputFilePath, outputFilePath, frequency, huffmanCodes);
163-
}
164-
165-
/**
166-
* Compresses the file to a specific output path
167-
*
168-
* @param outputFilePath The path where the compressed file will be saved
169-
* @throws RuntimeException if compression fails
170-
* @throws IllegalArgumentException if outputFilePath is null or invalid
171-
*/
172-
@Override
173-
public void compress(String outputFilePath) {
174-
CommonUtil.validateOutputFilePath(outputFilePath);
175-
compressFile(inputFilePath, outputFilePath, frequency, huffmanCodes);
168+
compressFile();
176169
}
177170

178171
/**

src/main/java/prog/lzw/LzwCompressor.java

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import prog.util.ByteWriter;
99
import prog.util.CommonUtil;
1010
import prog.util.Constants;
11+
import prog.util.FileUtils;
12+
1113
import java.io.IOException;
1214
import java.util.Map;
1315

@@ -20,6 +22,13 @@ public class LzwCompressor implements Compressor {
2022
*/
2123
private final String inputFilePath;
2224

25+
26+
/**
27+
* Path to the output file that will be compressed
28+
* Example: "/home/user/document.txt.LmZWp"
29+
*/
30+
private final String outputFilePath;
31+
2332
/**
2433
* Number of bits required to encode dictionary entries
2534
* Calculated based on the final dictionary size after a preliminary scan
@@ -38,12 +47,13 @@ public class LzwCompressor implements Compressor {
3847
* @param inputFilePath The path to the file to be compressed
3948
*/
4049
public LzwCompressor(String inputFilePath) {
50+
this.inputFilePath = inputFilePath;
51+
this.outputFilePath = inputFilePath + Constants.LZW_FILE_EXTENSION;
4152
logger.debug("Initializing LzwCompressor for file: {}", inputFilePath);
42-
if (CommonUtil.isEmptyFile(inputFilePath)) {
53+
if (FileUtils.isEmptyFile(inputFilePath)) {
4354
logger.error("Attempted to compress empty file: {}", inputFilePath);
4455
throw new IllegalArgumentException("Cannot compress empty file: " + inputFilePath);
4556
}
46-
this.inputFilePath = inputFilePath;
4757
this.bitSize = 0;
4858
this.bitBuffer = "";
4959
calculateBitSize();
@@ -119,19 +129,18 @@ private void calculateBitSize() {
119129
* Output: codes for ['A', 'B', 256, 'A']
120130
* </pre>
121131
*
122-
* @param outputFilePath The path where the compressed file will be saved
123132
* @throws RuntimeException if an IO error occurs during compression
124133
*/
125-
private void compressFile(String outputFilePath) {
134+
private void compressFile() {
126135
Map<String, Integer> dictionary = LzwUtils.initializeCompressionDictionary();
127136
int dictionarySize = Constants.BYTE_VALUES_COUNT;
128137
bitBuffer = "";
129138
int dictionaryMemorySize = Constants.BYTE_VALUES_COUNT;
130139
String currentSequence = "";
131140

132-
logger.info("Compressing file: {} -> {}", inputFilePath, outputFilePath);
133-
try (ByteReader reader = new ByteReader(inputFilePath);
134-
ByteWriter writer = new ByteWriter(outputFilePath)) {
141+
logger.info("Compressing file: {} -> {}", this.inputFilePath, this.outputFilePath);
142+
try (ByteReader reader = new ByteReader(this.inputFilePath);
143+
ByteWriter writer = new ByteWriter(this.outputFilePath)) {
135144

136145
logger.debug("Writing bit size: {}", bitSize);
137146
writer.writeInt(bitSize);
@@ -189,20 +198,6 @@ private void flushCompleteBytesFromBuffer(ByteWriter writer) throws IOException
189198
*/
190199
@Override
191200
public void compress() {
192-
String outputFilePath = inputFilePath + Constants.LZW_FILE_EXTENSION;
193-
compressFile(outputFilePath);
194-
}
195-
196-
/**
197-
* Compresses the file to a specific output path
198-
*
199-
* @param outputFilePath The path where the compressed file will be saved
200-
* @throws RuntimeException if compression fails
201-
* @throws IllegalArgumentException if outputFilePath is null or invalid
202-
*/
203-
@Override
204-
public void compress(String outputFilePath) {
205-
CommonUtil.validateOutputFilePath(outputFilePath);
206-
compressFile(outputFilePath);
201+
compressFile();
207202
}
208203
}

src/main/java/prog/lzw/LzwDecompressor.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ public class LzwDecompressor implements Decompressor {
2121
*/
2222
private final String compressedFilePath;
2323

24+
/**
25+
* Path to the output file that will be decompressed
26+
* Example: "/home/user/document.txt"
27+
*/
28+
private final String outputFilePath;
29+
2430
/**
2531
* Number of bits used to encode dictionary entries
2632
* Read from the compressed file header
@@ -47,6 +53,8 @@ public class LzwDecompressor implements Decompressor {
4753
public LzwDecompressor(String compressedFilePath) {
4854
logger.debug("Initializing LzwDecompressor for file: {}", compressedFilePath);
4955
this.compressedFilePath = compressedFilePath;
56+
this.outputFilePath = FileUtils.getUniqueFilePath(compressedFilePath.substring(0,
57+
compressedFilePath.length() - Constants.LZW_FILE_EXTENSION.length()));
5058
this.bitSize = 0;
5159
this.bitBuffer = "";
5260
this.byteToBinaryLookup = CommonUtil.createByteToBinaryLookupTable();
@@ -109,10 +117,9 @@ private void writeString(ByteWriter writer, String text) throws IOException {
109117
* added is the one we're currently processing. In this case, the sequence is:
110118
* previous sequence + first character of previous sequence.</p>
111119
*
112-
* @param outputFilePath The path where the decompressed file will be saved
113120
* @throws RuntimeException if an IO error occurs during decompression
114121
*/
115-
private void decompressFile(String outputFilePath) {
122+
private void decompressFile() {
116123
logger.info("Decompressing file: {} -> {}", compressedFilePath, outputFilePath);
117124
int code;
118125
int dictionarySize = Constants.BYTE_VALUES_COUNT;
@@ -191,23 +198,6 @@ private void decompressFile(String outputFilePath) {
191198
*/
192199
@Override
193200
public void decompress() {
194-
String outputFilePath = compressedFilePath.substring(0,
195-
compressedFilePath.length() - Constants.LZW_FILE_EXTENSION.length());
196-
// Get a unique file path if the file already exists
197-
outputFilePath = FileUtils.getUniqueFilePath(outputFilePath);
198-
decompressFile(outputFilePath);
199-
}
200-
201-
/**
202-
* Decompresses the file to a specific output path
203-
*
204-
* @param outputFilePath The path where the decompressed file will be saved
205-
* @throws RuntimeException if decompression fails
206-
* @throws IllegalArgumentException if outputFilePath is null or invalid
207-
*/
208-
@Override
209-
public void decompress(String outputFilePath) {
210-
FileUtils.validateOutputFilePath(outputFilePath);
211-
decompressFile(outputFilePath);
201+
decompressFile();
212202
}
213203
}

src/main/java/prog/util/CommonUtil.java

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -220,28 +220,4 @@ public static String[] createByteToBinaryLookupTable() {
220220
}
221221
return lookupTable;
222222
}
223-
224-
/**
225-
* Checks if a file is empty by checking its length.
226-
*
227-
* @deprecated Use {@link FileUtils#isEmptyFile(String)} instead.
228-
* @param filePath Path to the file to check
229-
* @return true if file is empty (length = 0), false otherwise
230-
*/
231-
@Deprecated
232-
public static boolean isEmptyFile(String filePath) {
233-
return FileUtils.isEmptyFile(filePath);
234-
}
235-
236-
/**
237-
* Validates that an output file path is not null or empty.
238-
*
239-
* @deprecated Use {@link FileUtils#validateOutputFilePath(String)} instead.
240-
* @param outputFilePath The output file path to validate
241-
* @throws IllegalArgumentException if outputFilePath is null or empty/whitespace
242-
*/
243-
@Deprecated
244-
public static void validateOutputFilePath(String outputFilePath) {
245-
FileUtils.validateOutputFilePath(outputFilePath);
246-
}
247223
}

0 commit comments

Comments
 (0)