first commit

This commit is contained in:
2025-10-10 18:00:07 -04:00
commit 06b59a3a99
3786 changed files with 571590 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
export type SeekMethod = 'CUR' | 'SET' | 'END';
declare const ERROR_CODE: {
readonly 0: "ERAR_SUCCESS";
readonly 10: "ERAR_END_ARCHIVE";
readonly 11: "ERAR_NO_MEMORY";
readonly 12: "ERAR_BAD_DATA";
readonly 13: "ERAR_BAD_ARCHIVE";
readonly 14: "ERAR_UNKNOWN_FORMAT";
readonly 15: "ERAR_EOPEN";
readonly 16: "ERAR_ECREATE";
readonly 17: "ERAR_ECLOSE";
readonly 18: "ERAR_EREAD";
readonly 19: "ERAR_EWRITE";
readonly 20: "ERAR_SMALL_BUF";
readonly 21: "ERAR_UNKNOWN";
readonly 22: "ERAR_MISSING_PASSWORD";
readonly 23: "ERAR_EREFERENCE";
readonly 24: "ERAR_BAD_PASSWORD";
};
export type FailReason = Exclude<(typeof ERROR_CODE)[keyof typeof ERROR_CODE], 'ERAR_SUCCESS' | 'ERAR_END_ARCHIVE'>;
export declare class UnrarError extends Error {
reason: FailReason;
file?: string | undefined;
constructor(reason: FailReason, message: string, file?: string | undefined);
}
export type CompressMethod = 'Storing' | 'Fastest' | 'Fast' | 'Normal' | 'Good' | 'Best' | 'Unknown';
export interface FileHeader {
name: string;
flags: {
encrypted: boolean;
solid: boolean;
directory: boolean;
};
packSize: number;
unpSize: number;
crc: number;
time: string;
unpVer: string;
method: CompressMethod;
comment: string;
}
export interface ArcHeader {
comment: string;
flags: {
volume: boolean;
lock: boolean;
solid: boolean;
authInfo: boolean;
recoveryRecord: boolean;
headerEncrypted: boolean;
};
}
export interface ArcList {
arcHeader: ArcHeader;
fileHeaders: Generator<FileHeader>;
}
export type ArcFile<withContent = never> = {
fileHeader: FileHeader;
extraction?: withContent;
};
export interface ArcFiles<withContent = never> {
arcHeader: ArcHeader;
files: Generator<ArcFile<withContent>>;
}
export interface ExtractOptions {
files?: string[] | ((fileHeader: FileHeader) => boolean);
password?: string;
}
export declare abstract class Extractor<withContent = never> {
protected unrar: any;
protected abstract _filePath: string;
private _password;
private _archive;
constructor(unrar: any, password?: string);
getFileList(): ArcList;
extract({ files, password }?: ExtractOptions): ArcFiles<withContent>;
protected fileCreated(filename: string): void;
protected abstract open(filename: string): number;
protected abstract create(filename: string): number;
protected abstract read(fd: number, buf: number, size: number): number;
protected abstract write(fd: number, buf: number, size: number): boolean;
protected abstract tell(fd: number): number;
protected abstract seek(fd: number, pos: number, method: SeekMethod): boolean;
protected abstract closeFile(fd: number): void;
protected close(fd: number): void;
private openArc;
private processNextFile;
private closeArc;
private getFailException;
}
export {};
+191
View File
@@ -0,0 +1,191 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Extractor = exports.UnrarError = void 0;
const ERROR_CODE = {
0: 'ERAR_SUCCESS',
10: 'ERAR_END_ARCHIVE',
11: 'ERAR_NO_MEMORY',
12: 'ERAR_BAD_DATA',
13: 'ERAR_BAD_ARCHIVE',
14: 'ERAR_UNKNOWN_FORMAT',
15: 'ERAR_EOPEN',
16: 'ERAR_ECREATE',
17: 'ERAR_ECLOSE',
18: 'ERAR_EREAD',
19: 'ERAR_EWRITE',
20: 'ERAR_SMALL_BUF',
21: 'ERAR_UNKNOWN',
22: 'ERAR_MISSING_PASSWORD',
23: 'ERAR_EREFERENCE',
24: 'ERAR_BAD_PASSWORD',
};
const ERROR_MSG = {
ERAR_NO_MEMORY: 'Not enough memory',
ERAR_BAD_DATA: 'Archive header or data are damaged',
ERAR_BAD_ARCHIVE: 'File is not RAR archive',
ERAR_UNKNOWN_FORMAT: 'Unknown archive format',
ERAR_EOPEN: 'File open error',
ERAR_ECREATE: 'File create error',
ERAR_ECLOSE: 'File close error',
ERAR_EREAD: 'File read error',
ERAR_EWRITE: 'File write error',
ERAR_SMALL_BUF: 'Buffer for archive comment is too small, comment truncated',
ERAR_UNKNOWN: 'Unknown error',
ERAR_MISSING_PASSWORD: 'Password for encrypted file or header is not specified',
ERAR_EREFERENCE: 'Cannot open file source for reference record',
ERAR_BAD_PASSWORD: 'Wrong password is specified',
};
class UnrarError extends Error {
constructor(reason, message, file) {
super(message);
this.reason = reason;
this.file = file;
}
}
exports.UnrarError = UnrarError;
class Extractor {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
constructor(unrar, password = '') {
this.unrar = unrar;
this._password = password;
this._archive = null;
}
getFileList() {
const arcHeader = this.openArc(true);
function* getFileHeaders() {
while (true) {
const arcFile = this.processNextFile(() => true);
if (arcFile === 'ERAR_END_ARCHIVE') {
break;
}
yield arcFile.fileHeader;
}
this.closeArc();
}
return { arcHeader, fileHeaders: getFileHeaders.call(this) };
}
extract({ files, password } = {}) {
const arcHeader = this.openArc(false, password);
function* getFiles() {
let count = 0;
while (true) {
let shouldSkip = () => false;
if (Array.isArray(files)) {
if (count === files.length) {
break;
}
shouldSkip = ({ name }) => !files.includes(name);
}
else if (files) {
shouldSkip = (fileHeader) => !files(fileHeader);
}
const arcFile = this.processNextFile(shouldSkip);
if (arcFile === 'ERAR_END_ARCHIVE') {
break;
}
if (arcFile.extraction === 'skipped') {
continue;
}
count++;
yield {
fileHeader: arcFile.fileHeader,
};
}
this.closeArc();
}
return { arcHeader, files: getFiles.call(this) };
}
fileCreated(filename) {
return;
}
close(fd) {
this.closeFile(fd);
}
openArc(listOnly, password) {
this._archive = new this.unrar.RarArchive();
const header = this._archive.open(this._filePath, password ? password : this._password, listOnly);
if (header.state.errCode !== 0) {
throw this.getFailException(header.state.errCode, header.state.errType);
}
return {
comment: header.comment,
flags: {
volume: (header.flags & 0x0001) !== 0,
lock: (header.flags & 0x0004) !== 0,
solid: (header.flags & 0x0008) !== 0,
authInfo: (header.flags & 0x0020) !== 0,
recoveryRecord: (header.flags & 0x0040) !== 0,
headerEncrypted: (header.flags & 0x0080) !== 0,
},
};
}
processNextFile(shouldSkip) {
function getDateString(dosTime) {
const bitLen = [5, 6, 5, 5, 4, 7];
let parts = [];
for (const len of bitLen) {
parts.push(dosTime & ((1 << len) - 1));
dosTime >>= len;
}
parts = parts.reverse();
const pad = (num) => (num < 10 ? '0' + num : '' + num);
return (`${1980 + parts[0]}-${pad(parts[1])}-${pad(parts[2])}` +
`T${pad(parts[3])}:${pad(parts[4])}:${pad(parts[5] * 2)}.000`);
}
function getMethod(method) {
const methodMap = {
0x30: 'Storing',
0x31: 'Fastest',
0x32: 'Fast',
0x33: 'Normal',
0x34: 'Good',
0x35: 'Best',
};
return methodMap[method] || 'Unknown';
}
const arcFileHeader = this._archive.getFileHeader();
if (arcFileHeader.state.errCode === 10) {
return 'ERAR_END_ARCHIVE';
}
if (arcFileHeader.state.errCode !== 0) {
throw this.getFailException(arcFileHeader.state.errCode, arcFileHeader.state.errType);
}
const fileHeader = {
name: arcFileHeader.name,
flags: {
encrypted: (arcFileHeader.flags & 0x04) !== 0,
solid: (arcFileHeader.flags & 0x10) !== 0,
directory: (arcFileHeader.flags & 0x20) !== 0,
},
packSize: arcFileHeader.packSize,
unpSize: arcFileHeader.unpSize,
// hostOS: arcFileHeader.hostOS
crc: arcFileHeader.crc,
time: getDateString(arcFileHeader.time),
unpVer: `${Math.floor(arcFileHeader.unpVer / 10)}.${arcFileHeader.unpVer % 10}`,
method: getMethod(arcFileHeader.method),
comment: arcFileHeader.comment,
// // fileAttr: arcFileHeader.fileAttr,
};
const skip = shouldSkip(fileHeader);
const fileState = this._archive.readFile(skip);
if (fileState.errCode !== 0) {
throw this.getFailException(fileState.errCode, fileState.errType, fileHeader.name);
}
return {
fileHeader,
extraction: skip ? 'skipped' : 'extracted',
};
}
closeArc() {
this._archive.delete();
this._archive = null;
}
getFailException(errCode, _errType, file) {
const reason = ERROR_CODE[errCode];
this.closeArc();
return new UnrarError(reason, ERROR_MSG[reason], file);
}
}
exports.Extractor = Extractor;
//# sourceMappingURL=Extractor.js.map
@@ -0,0 +1,17 @@
import { ArcFiles, ExtractOptions, Extractor, SeekMethod } from './Extractor';
export declare class ExtractorData extends Extractor<Uint8Array> {
protected _filePath: string;
private dataFiles;
private dataFileMap;
private currentFd;
constructor(unrar: any, data: ArrayBuffer, password: string);
extract(options?: ExtractOptions): ArcFiles<Uint8Array>;
private getExtractedFileName;
protected open(filename: string): number;
protected create(filename: string): number;
protected closeFile(fd: number): void;
protected read(fd: number, buf: number, size: number): number;
protected write(fd: number, buf: number, size: number): boolean;
protected tell(fd: number): number;
protected seek(fd: number, pos: number, method: SeekMethod): boolean;
}
@@ -0,0 +1,13 @@
import { SeekMethod } from './Extractor';
export declare class DataFile {
private buffers;
private size;
private pos;
constructor(data?: Uint8Array);
read(size: number): Uint8Array | null;
readAll(): Uint8Array;
write(data: Uint8Array): boolean;
tell(): number;
seek(pos: number, method: SeekMethod): boolean;
private flatten;
}
@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataFile = void 0;
class DataFile {
constructor(data) {
this.buffers = [];
this.pos = 0;
this.size = 0;
if (data) {
this.buffers.push(data);
this.size = data.byteLength;
this.pos = 0;
}
}
read(size) {
this.flatten();
if (size + this.pos > this.size) {
// size = this.size - this.pos;
return null;
}
const oldPos = this.pos;
this.pos += size;
// return this.buffers[0].subarray(oldPos, this.pos);
return this.buffers[0].slice(oldPos, this.pos);
}
readAll() {
this.flatten();
return this.buffers[0] || new Uint8Array();
}
write(data) {
this.buffers.push(data);
this.size += data.byteLength;
this.pos += data.byteLength;
return true;
}
tell() {
return this.pos;
}
seek(pos, method) {
let newPos = this.pos;
if (method === 'SET') {
newPos = pos;
}
else if (method === 'CUR') {
newPos += pos;
}
else {
newPos = this.size - pos;
}
if (newPos < 0 || newPos > this.size) {
return false;
}
this.pos = newPos;
return true;
}
flatten() {
if (this.buffers.length <= 1) {
return;
}
const newBuffer = new Uint8Array(this.size);
let offset = 0;
for (const buffer of this.buffers) {
newBuffer.set(buffer, offset);
offset += buffer.byteLength;
}
this.buffers = [newBuffer];
}
}
exports.DataFile = DataFile;
//# sourceMappingURL=ExtractorData.helper.js.map
+96
View File
@@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtractorData = void 0;
const ExtractorData_helper_1 = require("./ExtractorData.helper");
const Extractor_1 = require("./Extractor");
class ExtractorData extends Extractor_1.Extractor {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any
constructor(unrar, data, password) {
super(unrar, password);
this.dataFiles = {};
this.dataFileMap = {};
this.currentFd = 1;
const rarFile = {
file: new ExtractorData_helper_1.DataFile(new Uint8Array(data)),
fd: this.currentFd++,
};
this._filePath = '_defaultUnrarJS_.rar';
this.dataFiles[this._filePath] = rarFile;
this.dataFileMap[rarFile.fd] = this._filePath;
}
extract(options = {}) {
const { arcHeader, files } = super.extract(options);
function* getFiles() {
for (const file of files) {
if (!file.fileHeader.flags.directory) {
file.extraction =
this.dataFiles[this.getExtractedFileName(file.fileHeader.name)].file.readAll();
}
yield file;
}
}
return { arcHeader, files: getFiles.call(this) };
}
getExtractedFileName(filename) {
return `*Extracted*/${filename}`;
}
open(filename) {
const dataFile = this.dataFiles[filename];
if (!dataFile) {
return 0;
}
return dataFile.fd;
}
create(filename) {
const fd = this.currentFd++;
this.dataFiles[this.getExtractedFileName(filename)] = {
file: new ExtractorData_helper_1.DataFile(),
fd: this.currentFd++,
};
this.dataFileMap[fd] = this.getExtractedFileName(filename);
return fd;
}
closeFile(fd) {
const fileData = this.dataFiles[this.dataFileMap[fd]];
if (!fileData) {
return;
}
fileData.file.seek(0, 'SET');
}
read(fd, buf, size) {
const fileData = this.dataFiles[this.dataFileMap[fd]];
if (!fileData) {
return -1;
}
const data = fileData.file.read(size);
if (data === null) {
return -1;
}
this.unrar.HEAPU8.set(data, buf);
return data.byteLength;
}
write(fd, buf, size) {
const fileData = this.dataFiles[this.dataFileMap[fd]];
if (!fileData) {
return false;
}
fileData.file.write(this.unrar.HEAPU8.slice(buf, buf + size));
return true;
}
tell(fd) {
const fileData = this.dataFiles[this.dataFileMap[fd]];
if (!fileData) {
return -1;
}
return fileData.file.tell();
}
seek(fd, pos, method) {
const fileData = this.dataFiles[this.dataFileMap[fd]];
if (!fileData) {
return false;
}
return fileData.file.seek(pos, method);
}
}
exports.ExtractorData = ExtractorData;
//# sourceMappingURL=ExtractorData.js.map
@@ -0,0 +1,15 @@
import { Extractor, SeekMethod } from './Extractor';
export declare class ExtractorFile extends Extractor {
private filenameTransform;
protected _filePath: string;
private _target;
private fileMap;
constructor(unrar: any, filepath: string, targetPath: string, password: string, filenameTransform: (filename: string) => string);
protected open(filename: string): number;
protected create(filename: string): number;
protected closeFile(fd: number): void;
protected read(fd: number, buf: number, size: number): number;
protected write(fd: number, buf: number, size: number): boolean;
protected tell(fd: number): number;
protected seek(fd: number, pos: number, method: SeekMethod): boolean;
}
+104
View File
@@ -0,0 +1,104 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtractorFile = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const Extractor_1 = require("./Extractor");
class ExtractorFile extends Extractor_1.Extractor {
constructor(
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any
unrar, filepath, targetPath, password, filenameTransform) {
super(unrar, password);
this.filenameTransform = filenameTransform;
this._filePath = filepath;
this.fileMap = {};
this._target = targetPath;
}
open(filename) {
const fd = fs.openSync(filename, 'r');
this.fileMap[fd] = {
size: fs.fstatSync(fd).size,
pos: 0,
name: filename,
};
return fd;
}
create(filename) {
const fullpath = path.join(this._target, this.filenameTransform(filename));
const dir = path.parse(fullpath).dir;
// Skip if directory is the current directory
if (dir !== '') {
fs.mkdirSync(dir, { recursive: true });
}
const fd = fs.openSync(fullpath, 'w');
this.fileMap[fd] = {
size: 0,
pos: 0,
name: filename,
};
return fd;
}
closeFile(fd) {
delete this.fileMap[fd];
fs.closeSync(fd);
}
read(fd, buf, size) {
const file = this.fileMap[fd];
const buffer = Buffer.allocUnsafe(size);
const readed = fs.readSync(fd, buffer, 0, size, file.pos);
this.unrar.HEAPU8.set(buffer, buf);
file.pos += readed;
return readed;
}
write(fd, buf, size) {
const file = this.fileMap[fd];
const writeNum = fs.writeSync(fd, Buffer.from(this.unrar.HEAPU8.subarray(buf, buf + size)), 0, size);
file.pos += writeNum;
file.size += writeNum;
return writeNum === size;
}
tell(fd) {
return this.fileMap[fd].pos;
}
seek(fd, pos, method) {
const file = this.fileMap[fd];
let newPos = file.pos;
if (method === 'SET') {
newPos = 0;
}
else if (method === 'END') {
newPos = file.size;
}
newPos += pos;
if (newPos < 0 || newPos > file.size) {
return false;
}
file.pos = newPos;
return true;
}
}
exports.ExtractorFile = ExtractorFile;
//# sourceMappingURL=ExtractorFile.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
export declare function getUnrar(options?: {
wasmBinary?: ArrayBuffer;
}): Promise<any>;
@@ -0,0 +1,17 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUnrar = void 0;
/* eslint-disable @typescript-eslint/no-explicit-any */
const unrar_1 = __importDefault(require("./unrar"));
let unrar;
async function getUnrar(options) {
if (!unrar) {
unrar = await (0, unrar_1.default)(options);
}
return unrar;
}
exports.getUnrar = getUnrar;
//# sourceMappingURL=unrar.singleton.js.map
Binary file not shown.