UNPKG

typesxml

Version:

Open source XML library written in TypeScript

123 lines 4.42 kB
"use strict"; /******************************************************************************* * Copyright (c) 2023-2026 Maxprograms. * * This program and the accompanying materials * are made available under the terms of the Eclipse License 1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-v10.html * * Contributors: * Maxprograms - initial API and implementation *******************************************************************************/ Object.defineProperty(exports, "__esModule", { value: true }); exports.FileReader = void 0; const node_fs_1 = require("node:fs"); const node_util_1 = require("node:util"); class FileReader { fileHandle; encoding; blockSize; fileSize; position; firstRead; decoder; filePath; constructor(path, encoding) { this.filePath = path; let stats = (0, node_fs_1.statSync)(path, { bigint: false, throwIfNoEntry: true }); this.fileSize = stats.size; this.blockSize = stats.blksize && stats.blksize > 0 ? stats.blksize : 8192; this.fileHandle = (0, node_fs_1.openSync)(path, 'r'); if (encoding) { this.encoding = encoding; } else { this.encoding = FileReader.detectEncoding(path); } this.position = 0; this.firstRead = true; this.initializeDecoder(); } static detectEncoding(path) { const fd = (0, node_fs_1.openSync)(path, 'r'); const buffer = Buffer.alloc(3); const bytesRead = (0, node_fs_1.readSync)(fd, buffer, 0, 3, 0); (0, node_fs_1.closeSync)(fd); if (bytesRead === 0) { return 'utf8'; } const slice = buffer.subarray(0, bytesRead); const UTF8 = Buffer.from([0xEF, 0xBB, 0xBF]); const UTF16LE = Buffer.from([0xFF, 0xFE]); const UTF16BE = Buffer.from([0xFE, 0xFF]); if (slice.length >= UTF8.length && slice.compare(UTF8, 0, UTF8.length, 0, UTF8.length) === 0) { return 'utf8'; } if (slice.length >= UTF16LE.length && slice.compare(UTF16LE, 0, UTF16LE.length, 0, UTF16LE.length) === 0) { return 'utf16le'; } if (slice.length >= UTF16BE.length && slice.compare(UTF16BE, 0, UTF16BE.length, 0, UTF16BE.length) === 0) { return 'utf16le'; } return 'utf8'; } getEncoding() { return this.encoding; } setEncoding(encoding) { this.encoding = encoding; this.initializeDecoder(); this.firstRead = true; } read() { let buffer = Buffer.alloc(this.blockSize); let amount = this.blockSize <= this.fileSize - this.position ? this.blockSize : this.fileSize - this.position; let bytesRead = (0, node_fs_1.readSync)(this.fileHandle, buffer, 0, amount, this.position); this.position += bytesRead; let decoded; try { if (this.decoder) { const stream = this.position < this.fileSize; decoded = this.decoder.decode(buffer.subarray(0, bytesRead), { stream }); } else { decoded = buffer.toString(this.encoding, 0, bytesRead); } } catch (error) { const message = error.message || 'invalid byte sequence'; throw new Error(`Invalid ${this.encoding} data in "${this.filePath}": ${message}`); } return this.firstRead ? this.handleInitialChunk(decoded) : decoded; } handleInitialChunk(text) { this.firstRead = false; if (!this.decoder && text.length > 0 && text.codePointAt(0) === 0xFEFF) { return text.substring(1); } return text; } dataAvailable() { return this.position < this.fileSize; } getFileSize() { return this.fileSize; } closeFile() { (0, node_fs_1.closeSync)(this.fileHandle); } initializeDecoder() { if (this.encoding === 'utf8') { this.decoder = new node_util_1.TextDecoder('utf-8', { fatal: true }); } else if (this.encoding === 'utf16le') { this.decoder = new node_util_1.TextDecoder('utf-16le', { fatal: true }); } else { this.decoder = undefined; } } } exports.FileReader = FileReader; //# sourceMappingURL=FileReader.js.map