|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { |
|
|
DEFAULT_BINARY_DETECTION_OPTIONS, |
|
|
type BinaryDetectionOptions |
|
|
} from '$lib/constants/binary-detection'; |
|
|
import { FileExtensionText } from '$lib/enums/files'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function isTextFileByName(filename: string): boolean { |
|
|
const textExtensions = Object.values(FileExtensionText); |
|
|
|
|
|
return textExtensions.some((ext: FileExtensionText) => filename.toLowerCase().endsWith(ext)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function readFileAsText(file: File): Promise<string> { |
|
|
return new Promise((resolve, reject) => { |
|
|
const reader = new FileReader(); |
|
|
|
|
|
reader.onload = (event) => { |
|
|
if (event.target?.result !== null && event.target?.result !== undefined) { |
|
|
resolve(event.target.result as string); |
|
|
} else { |
|
|
reject(new Error('Failed to read file')); |
|
|
} |
|
|
}; |
|
|
|
|
|
reader.onerror = () => reject(new Error('File reading error')); |
|
|
|
|
|
reader.readAsText(file); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function isLikelyTextFile( |
|
|
content: string, |
|
|
options: Partial<BinaryDetectionOptions> = {} |
|
|
): boolean { |
|
|
if (!content) return true; |
|
|
|
|
|
const config = { ...DEFAULT_BINARY_DETECTION_OPTIONS, ...options }; |
|
|
const sample = content.substring(0, config.prefixLength); |
|
|
|
|
|
let nullCount = 0; |
|
|
let suspiciousControlCount = 0; |
|
|
|
|
|
for (let i = 0; i < sample.length; i++) { |
|
|
const charCode = sample.charCodeAt(i); |
|
|
|
|
|
|
|
|
if (charCode === 0) { |
|
|
nullCount++; |
|
|
|
|
|
continue; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13) { |
|
|
|
|
|
if (charCode < 8 || (charCode > 13 && charCode < 27)) { |
|
|
suspiciousControlCount++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (charCode === 0xfffd) { |
|
|
suspiciousControlCount++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (nullCount > config.maxAbsoluteNullBytes) return false; |
|
|
|
|
|
|
|
|
if (suspiciousControlCount / sample.length > config.suspiciousCharThresholdRatio) return false; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|