-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathutils.ts
138 lines (121 loc) · 3.98 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import fs from 'fs';
function readFile(filename: string): string {
if (fs.existsSync(filename)) {
return fs.readFileSync(filename, 'utf-8').toString();
}
console.error("Input file doesn't exists!");
process.exit(1);
}
/**
* Function to write compressed that along with header
*
* @param {string} filename - The output filename
* @param {string} headerText - relevant information need while decompression
* @param {Uint8Array} uint8Array - The compressed text
* @param {number} padding - The padding of the compressed text
*/
function writeToFile(
filename: string,
headerText: string,
uint8Array: Uint8Array,
padding: number
): void {
// Converting headerText to Uint8Array.
// When reading the file again for decompression, input is processed in Buffer
const headerUint8Array = new TextEncoder().encode(headerText);
// Creating new file and appending header length to it
fs.writeFileSync(filename, headerUint8Array.length.toString() + '\n');
// Follows by the 0 <= padding < 8
fs.appendFileSync(filename, padding.toString() + '\n');
// Followed by the headerText
fs.appendFileSync(filename, headerUint8Array);
// Finally the compressed data
fs.appendFileSync(filename, uint8Array);
}
/**
* Converts frequency table to relevant format for storing in file
*
* @param {Map<string, number>} freqTable
* @returns {string}
*/
function getHeaderSection(freqTable: Map<string, number>): string {
return JSON.stringify(Array.from(freqTable.entries()));
}
/**
* Reads compressed file from the given Buffer
*
* @param {Buffer} inputBuffer
* @returns {[Map<string, number>, Uint8Array, number]} - [Frequency Table, Compressed text, padding]
*/
function readOutputFile(
inputBuffer: Buffer
): [Map<string, number>, Uint8Array, number] {
// Retrieve Header length
let headerBufferStartIndex = 0;
while (inputBuffer[headerBufferStartIndex] !== '\n'.charCodeAt(0)) {
headerBufferStartIndex++;
}
const headerLength = parseInt(
inputBuffer.subarray(0, headerBufferStartIndex).toString()
);
headerBufferStartIndex++; // Move to next line
// Process padding
const padding = parseInt(
inputBuffer
.subarray(headerBufferStartIndex, headerBufferStartIndex + 1)
.toString()
);
headerBufferStartIndex += 2; // Move to next line
const headerBufferEndIndex = headerBufferStartIndex + headerLength;
// Process header
const headerBuffer = inputBuffer.subarray(
headerBufferStartIndex,
headerBufferEndIndex
);
const freqTable = new Map<string, number>(
JSON.parse(headerBuffer.toString())
);
// Process the compressed text
const compressedTextBuffer = inputBuffer.subarray(headerBufferEndIndex);
return [freqTable, compressedTextBuffer, padding];
}
/**
* Function to convert bits in string format to bytes in Uint8Array format
*
* @param {string} bitString - A string consisting of zeros and ones
* @returns {[Uint8Array, number]} - [Array of numbers after packing bits to bytes, padded zeros at the end]
*/
function packBitString(bitString: string): [Uint8Array, number] {
// Add padding if the length of bit string is not a multiple of 8;
let paddedBitString = bitString;
while (paddedBitString.length % 8 !== 0) {
paddedBitString += '0';
}
const padding = paddedBitString.length - bitString.length;
const byteCount = paddedBitString.length / 8;
const bytes = new Uint8Array(byteCount);
for (let i = 0; i < byteCount; i++) {
const start = i * 8;
const end = start + 8;
const byte = paddedBitString.slice(start, end);
bytes[i] = parseInt(byte, 2);
}
return [bytes, padding];
}
function unpack(uint8array: Uint8Array, padding: number): string {
let binaryString = '';
for (let i = 0; i < uint8array.length; i++) {
const byte = uint8array[i];
binaryString += byte.toString(2).padStart(8, '0');
}
// Remove padding
return binaryString.substring(0, binaryString.length - padding);
}
export {
readFile,
writeToFile,
getHeaderSection,
readOutputFile,
packBitString,
unpack
};