typesxml
Version:
Open source XML library written in TypeScript
123 lines • 4.42 kB
JavaScript
"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