filesqueeze
Version:
A file compression tool that uses Huffman coding
122 lines (99 loc) • 3.44 kB
JavaScript
const msgpack5 = require("msgpack5")();
const path = require('path');
const fs = require('fs');
const Node = require("./Node");
const { formatFileSize } = require("./util");
const bufferToBinaryString = (buffer) => {
return buffer
.toString('binary') // Convert to binary string
.split('')
.map((char) => char.charCodeAt(0).toString(2).padStart(8, '0')) // Each char -> binary
.join('');
};
const decodeData = (encoded, tree) => {
let decodedData = '';
let currentNode = tree;
if (tree.left === null && tree.right === null) {
for (let bit of encoded) {
decodedData += tree.char;
}
return decodedData;
}
for (let bit of encoded) {
currentNode = bit === '0' ? currentNode.left : currentNode.right;
if (currentNode.char !== null) {
decodedData += currentNode.char;
currentNode = tree;
}
}
// console.log("decoded data: ", decodedData);
return decodedData;
}
const deserializedBinaryToTree = (buffer) => {
const deserializeNode = (data) => {
if (!data) return null;
if (data.marker === 0x01) {
// Leaf node
return new Node(data.char, data.freq);
}
// Internal node
return new Node(
null,
data.freq,
deserializeNode(data.left),
deserializeNode(data.right)
);
};
const metaData = msgpack5.decode(buffer);
const tree = deserializeNode(metaData.tree);
const fileExtension = metaData.fileExtension;
return {
tree,
fileExtension
}
};
const deserializeTree = (tree) => {
if (!tree) return null;
const root = new Node(tree.char, tree.freq);
const queue = [{ node: root, tree }];
while (queue.length > 0) {
const { node, tree } = queue.shift();
if (tree?.left) {
node.left = new Node(tree.left.char, tree.left.freq);
queue.push({ node: node.left, data: tree.left });
}
if (tree?.right) {
node.right = new Node(tree.right.char, tree.right.freq);
queue.push({ node: node.right, data: tree.right });
}
}
// console.log("deserialized tree: ", root);
return root;
}
const saveDecodedOutput = async (fileName, data, outputDir) => {
try {
// Create the directory if it doesn't exist
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Define the decoded file path
const decodedFile = path.join(outputDir, fileName);
// Write the decoded data to the file
await fs.promises.writeFile(decodedFile, data);
// Fetch file size and return it along with the file path
const fileSize = fs.statSync(decodedFile).size;
console.log(`✅ Decoded file saved at: ${decodedFile}`);
console.log(`📏 Decoded file size: ${formatFileSize(fileSize)}`);
return fileSize;
} catch (err) {
console.error('❌ Error saving decoded file:', err.message);
throw err; // Re-throw for upstream error handling
}
};
module.exports = {
bufferToBinaryString,
decodeData,
deserializeTree,
deserializedBinaryToTree,
saveDecodedOutput
}