1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.isBinaryFileSync = exports.isBinaryFile = void 0;
|
4 | const fs = require("fs");
|
5 | const util_1 = require("util");
|
6 | const statAsync = (0, util_1.promisify)(fs.stat);
|
7 | const openAsync = (0, util_1.promisify)(fs.open);
|
8 | const closeAsync = (0, util_1.promisify)(fs.close);
|
9 | const MAX_BYTES = 512;
|
10 |
|
11 |
|
12 | class Reader {
|
13 | fileBuffer;
|
14 | size;
|
15 | offset;
|
16 | error;
|
17 | constructor(fileBuffer, size) {
|
18 | this.fileBuffer = fileBuffer;
|
19 | this.size = size;
|
20 | this.offset = 0;
|
21 | this.error = false;
|
22 | }
|
23 | hasError() {
|
24 | return this.error;
|
25 | }
|
26 | nextByte() {
|
27 | if (this.offset === this.size || this.hasError()) {
|
28 | this.error = true;
|
29 | return 0xff;
|
30 | }
|
31 | return this.fileBuffer[this.offset++];
|
32 | }
|
33 | next(len) {
|
34 | const n = new Array();
|
35 | for (let i = 0; i < len; i++) {
|
36 | n[i] = this.nextByte();
|
37 | }
|
38 | return n;
|
39 | }
|
40 | }
|
41 |
|
42 | function readProtoVarInt(reader) {
|
43 | let idx = 0;
|
44 | let varInt = 0;
|
45 | while (!reader.hasError()) {
|
46 | const b = reader.nextByte();
|
47 | varInt = varInt | ((b & 0x7f) << (7 * idx));
|
48 | if ((b & 0x80) === 0) {
|
49 | break;
|
50 | }
|
51 | idx++;
|
52 | }
|
53 | return varInt;
|
54 | }
|
55 |
|
56 | function readProtoMessage(reader) {
|
57 | const varInt = readProtoVarInt(reader);
|
58 | const wireType = varInt & 0x7;
|
59 | switch (wireType) {
|
60 | case 0:
|
61 | readProtoVarInt(reader);
|
62 | return true;
|
63 | case 1:
|
64 | reader.next(8);
|
65 | return true;
|
66 | case 2:
|
67 | const len = readProtoVarInt(reader);
|
68 | reader.next(len);
|
69 | return true;
|
70 | case 5:
|
71 | reader.next(4);
|
72 | return true;
|
73 | }
|
74 | return false;
|
75 | }
|
76 |
|
77 | function isBinaryProto(fileBuffer, totalBytes) {
|
78 | const reader = new Reader(fileBuffer, totalBytes);
|
79 | let numMessages = 0;
|
80 | while (true) {
|
81 |
|
82 | if (!readProtoMessage(reader) && !reader.hasError()) {
|
83 | return false;
|
84 | }
|
85 |
|
86 | if (reader.hasError()) {
|
87 | break;
|
88 | }
|
89 | numMessages++;
|
90 | }
|
91 | return numMessages > 0;
|
92 | }
|
93 | async function isBinaryFile(file, size) {
|
94 | if (isString(file)) {
|
95 | const stat = await statAsync(file);
|
96 | isStatFile(stat);
|
97 | const fileDescriptor = await openAsync(file, 'r');
|
98 | const allocBuffer = Buffer.alloc(MAX_BYTES);
|
99 |
|
100 |
|
101 | return new Promise((fulfill, reject) => {
|
102 | fs.read(fileDescriptor, allocBuffer, 0, MAX_BYTES, 0, (err, bytesRead, _) => {
|
103 | closeAsync(fileDescriptor);
|
104 | if (err) {
|
105 | reject(err);
|
106 | }
|
107 | else {
|
108 | fulfill(isBinaryCheck(allocBuffer, bytesRead));
|
109 | }
|
110 | });
|
111 | });
|
112 | }
|
113 | else {
|
114 | if (size === undefined) {
|
115 | size = file.length;
|
116 | }
|
117 | return isBinaryCheck(file, size);
|
118 | }
|
119 | }
|
120 | exports.isBinaryFile = isBinaryFile;
|
121 | function isBinaryFileSync(file, size) {
|
122 | if (isString(file)) {
|
123 | const stat = fs.statSync(file);
|
124 | isStatFile(stat);
|
125 | const fileDescriptor = fs.openSync(file, 'r');
|
126 | const allocBuffer = Buffer.alloc(MAX_BYTES);
|
127 | const bytesRead = fs.readSync(fileDescriptor, allocBuffer, 0, MAX_BYTES, 0);
|
128 | fs.closeSync(fileDescriptor);
|
129 | return isBinaryCheck(allocBuffer, bytesRead);
|
130 | }
|
131 | else {
|
132 | if (size === undefined) {
|
133 | size = file.length;
|
134 | }
|
135 | return isBinaryCheck(file, size);
|
136 | }
|
137 | }
|
138 | exports.isBinaryFileSync = isBinaryFileSync;
|
139 | function isBinaryCheck(fileBuffer, bytesRead) {
|
140 |
|
141 | if (bytesRead === 0) {
|
142 | return false;
|
143 | }
|
144 | let suspiciousBytes = 0;
|
145 | const totalBytes = Math.min(bytesRead, MAX_BYTES);
|
146 |
|
147 | if (bytesRead >= 3 && fileBuffer[0] === 0xef && fileBuffer[1] === 0xbb && fileBuffer[2] === 0xbf) {
|
148 | return false;
|
149 | }
|
150 |
|
151 | if (bytesRead >= 4 &&
|
152 | fileBuffer[0] === 0x00 &&
|
153 | fileBuffer[1] === 0x00 &&
|
154 | fileBuffer[2] === 0xfe &&
|
155 | fileBuffer[3] === 0xff) {
|
156 | return false;
|
157 | }
|
158 |
|
159 | if (bytesRead >= 4 &&
|
160 | fileBuffer[0] === 0xff &&
|
161 | fileBuffer[1] === 0xfe &&
|
162 | fileBuffer[2] === 0x00 &&
|
163 | fileBuffer[3] === 0x00) {
|
164 | return false;
|
165 | }
|
166 |
|
167 | if (bytesRead >= 4 &&
|
168 | fileBuffer[0] === 0x84 &&
|
169 | fileBuffer[1] === 0x31 &&
|
170 | fileBuffer[2] === 0x95 &&
|
171 | fileBuffer[3] === 0x33) {
|
172 | return false;
|
173 | }
|
174 | if (totalBytes >= 5 && fileBuffer.slice(0, 5).toString() === '%PDF-') {
|
175 |
|
176 | return true;
|
177 | }
|
178 |
|
179 | if (bytesRead >= 2 && fileBuffer[0] === 0xfe && fileBuffer[1] === 0xff) {
|
180 | return false;
|
181 | }
|
182 |
|
183 | if (bytesRead >= 2 && fileBuffer[0] === 0xff && fileBuffer[1] === 0xfe) {
|
184 | return false;
|
185 | }
|
186 | for (let i = 0; i < totalBytes; i++) {
|
187 | if (fileBuffer[i] === 0) {
|
188 |
|
189 | return true;
|
190 | }
|
191 | else if ((fileBuffer[i] < 7 || fileBuffer[i] > 14) && (fileBuffer[i] < 32 || fileBuffer[i] > 127)) {
|
192 |
|
193 | if (fileBuffer[i] >= 0xc0 && fileBuffer[i] <= 0xdf && i + 1 < totalBytes) {
|
194 | i++;
|
195 | if (fileBuffer[i] >= 0x80 && fileBuffer[i] <= 0xbf) {
|
196 | continue;
|
197 | }
|
198 | }
|
199 | else if (fileBuffer[i] >= 0xe0 && fileBuffer[i] <= 0xef && i + 2 < totalBytes) {
|
200 | i++;
|
201 | if (fileBuffer[i] >= 0x80 && fileBuffer[i] <= 0xbf && fileBuffer[i + 1] >= 0x80 && fileBuffer[i + 1] <= 0xbf) {
|
202 | i++;
|
203 | continue;
|
204 | }
|
205 | }
|
206 | else if (fileBuffer[i] >= 0xf0 && fileBuffer[i] <= 0xf7 && i + 3 < totalBytes) {
|
207 | i++;
|
208 | if (fileBuffer[i] >= 0x80 &&
|
209 | fileBuffer[i] <= 0xbf &&
|
210 | fileBuffer[i + 1] >= 0x80 &&
|
211 | fileBuffer[i + 1] <= 0xbf &&
|
212 | fileBuffer[i + 2] >= 0x80 &&
|
213 | fileBuffer[i + 2] <= 0xbf) {
|
214 | i += 2;
|
215 | continue;
|
216 | }
|
217 | }
|
218 | suspiciousBytes++;
|
219 |
|
220 | if (i >= 32 && (suspiciousBytes * 100) / totalBytes > 10) {
|
221 | return true;
|
222 | }
|
223 | }
|
224 | }
|
225 | if ((suspiciousBytes * 100) / totalBytes > 10) {
|
226 | return true;
|
227 | }
|
228 | if (suspiciousBytes > 1 && isBinaryProto(fileBuffer, totalBytes)) {
|
229 | return true;
|
230 | }
|
231 | return false;
|
232 | }
|
233 | function isString(x) {
|
234 | return typeof x === 'string';
|
235 | }
|
236 | function isStatFile(stat) {
|
237 | if (!stat.isFile()) {
|
238 | throw new Error(`Path provided was not a file!`);
|
239 | }
|
240 | }
|