first commit
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
## [2.0.2](https://github.com/YuJianrong/node-unrar.js/compare/v2.0.1...v2.0.2) (2023-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove the postinstall script which should not be executed when installed on user side ([#329](https://github.com/YuJianrong/node-unrar.js/issues/329)) ([16b4e3c](https://github.com/YuJianrong/node-unrar.js/commit/16b4e3c0fca8602392d7f492830867b05e762f4a)), closes [#324](https://github.com/YuJianrong/node-unrar.js/issues/324)
|
||||
|
||||
## [2.0.1](https://github.com/YuJianrong/node-unrar.js/compare/v2.0.0...v2.0.1) (2023-11-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix husky blocker on semantic-release ([88cd80c](https://github.com/YuJianrong/node-unrar.js/commit/88cd80cd60cb5dd054235e4a0376d2ad2b745213))
|
||||
* fix the case when file size is greater than 2G ([#323](https://github.com/YuJianrong/node-unrar.js/issues/323)) ([f81cacd](https://github.com/YuJianrong/node-unrar.js/commit/f81cacde37e4725a453563e9faa58e7932c23dcb))
|
||||
|
||||
#### 2.0.0 (2022-06-15)
|
||||
|
||||
- Add support for NodeJs v18
|
||||
- **(Breaking change)**: `ArcFile.extraction` is optional for `createExtractorFromData` now. If `ArcFile.fileHeader.flags.directory` is `true`, this field will be `undefined`.
|
||||
|
||||
#### 1.0.6 (2022-03-16)
|
||||
|
||||
- Add `createExtractorFromFile` support in Webpack
|
||||
|
||||
#### 1.0.5 (2022-02-28)
|
||||
|
||||
- Fix an issue on file extracting to current working directory ('./')
|
||||
|
||||
#### 1.0.4 (2022-02-15)
|
||||
|
||||
- Fix folder creation issue on Windows.
|
||||
|
||||
#### 1.0.3 (2021-05-10)
|
||||
|
||||
- Fix for Security Vulnerability on dependencies
|
||||
|
||||
#### 1.0.2 (2021-04-01)
|
||||
|
||||
- Fix for Security Vulnerability on dependencies
|
||||
|
||||
#### 1.0.1 (2021-02-18)
|
||||
|
||||
- Add new option `filenameTransform` for `ExtractorFromFileOptions`.
|
||||
|
||||
#### 1.0.0 (2020-12-29)
|
||||
|
||||
- Refactory by the latest EMScripten and UnRar DLL source. Since both of them changed a lot, there are many breaking changes in this update
|
||||
- **(Breaking change)**: Use Javascript Exception instead of tuple `[state, result]` for error handling.
|
||||
- **(Breaking change)**: The extractor object return by `createExtractorFromData` and `createExtractorFromFile` are now promise object. Since loading the wasm object in the latest EMScriten is asynchronized.
|
||||
- **(Breaking change)**: The `fileHeaders` and `files` returned by the extractions api are changed from array to iterator, make the extraction lazy.
|
||||
|
||||
#### 0.8.0
|
||||
|
||||
- First release
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2017 Jianrong Yu.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
# node-unrar-js
|
||||
|
||||
[](https://github.com/YuJianrong/node-unrar.js/actions?query=workflow%3ABuild)
|
||||
[](https://badge.fury.io/js/node-unrar-js)
|
||||
[](https://opensource.org/licenses/mit-license.php)
|
||||
[](https://www.typescriptlang.org/)
|
||||
|
||||
`node-unrar.js` is a npm module to extract rar archive in pure JavaScript. It's combined by a Javascript adoption layer and JavaScript unRar library compiled by [Emscripten](http://emscripten.org/) from the [C++ unrar library](http://www.rarlab.com/rar/unrarsrc-6.1.7.tar.gz) which hosted on <http://www.rarlab.com/rar_add.htm> .
|
||||
|
||||
## Installation
|
||||
|
||||
You can install the module via `npm`:
|
||||
|
||||
```bash
|
||||
npm install node-unrar-js
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Fully support for RAR archive, because it comes from the official source code.
|
||||
- Unicode support, for both comment and file path/name.
|
||||
- API for Extraction to both memory and file system.
|
||||
- Both Commonjs module (for nodejs) and ES2015 module (for webpack) are supported.
|
||||
|
||||
## Unsupported Features
|
||||
|
||||
- Volume archives are not supported.
|
||||
- Synchronize File System IO functions are used in File Extraction.
|
||||
|
||||
## API to create the extractor
|
||||
|
||||
- `async function createExtractorFromData(options: ExtractorFromDataOptions): Promise<Extractor<Uint8Array>>` - Create the in Memory Extractor
|
||||
|
||||
Options `ExtractorFromDataOptions`:
|
||||
|
||||
- `data: ArrayBuffer` : ArrayBuffer object of the RAR archive file
|
||||
- `password?: string` : _Optional_ password
|
||||
- `wasmBinary? ArrayBuffer;` : _Optional_ Use in browser/webpack, the wasm binary must be loaded in the code and send to this function to load the wasm code
|
||||
|
||||
- `async function createExtractorFromFile(options: ExtractorFromFileOptions): Promise<Extractor>` - Get the File Extractor
|
||||
|
||||
Options `ExtractorFromFileOptions`:
|
||||
|
||||
- `filepath: string` : File path of the RAR archive file
|
||||
- `targetPath?: string` : _Optional_ target folder
|
||||
- `password?: string` : _Optional_ password
|
||||
- `filenameTransform?: (filename: string) => string`: _Optional_ transform the file name before it's created on file system
|
||||
- `wasmBinary? ArrayBuffer;` : _Optional_ Use in nodejs/webpack, the wasm binary must be loaded in the code and send to this function to load the wasm code in webpack based nodejs project (please read [Used in Webpack-bundled NodeJS Project](#use-in-webpack-bundled-nodejs-project) for more details).
|
||||
|
||||
_Node_: This function is not available in EM2015 Module since the EM2015 Module is used for webpack in Browser.
|
||||
|
||||
## API of the extractor
|
||||
|
||||
- `getFileList(): ArcList` : Get the file header and file list of the archive.
|
||||
|
||||
Members in `ArcList`:
|
||||
|
||||
- `arcHeader: ArcHeader` : The header of the archive
|
||||
- `fileHeaders: Generator<FileHeader>` : The iterator of the `FileHeader` objects
|
||||
|
||||
```js
|
||||
{
|
||||
arcHeader: {
|
||||
comment: "",
|
||||
flags: {
|
||||
authInfo: false,
|
||||
headerEncrypted: false,
|
||||
lock: false,
|
||||
recoveryRecord: false,
|
||||
solid: false,
|
||||
volume: false,
|
||||
},
|
||||
}, fileHeaders: (Iterator)
|
||||
{
|
||||
crc: 0,
|
||||
flags: {
|
||||
directory: false,
|
||||
encrypted: false,
|
||||
solid: false,
|
||||
},
|
||||
method: "Storing",
|
||||
name: "FileName",
|
||||
packSize: 0,
|
||||
time: "2017-04-03T10:41:42.000",
|
||||
unpSize: 0,
|
||||
unpVer: "2.9",
|
||||
comment: "",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
- `extract(options: ExtractOptions)`: Extract the files.
|
||||
- Options `ExtractOptions`:
|
||||
- `files?: string[] | ((fileHeader: FileHeader) => boolean)` _Optional_ Extract all the files if `files` is empty
|
||||
- `string[]`: Extract the specific files only
|
||||
- `(fileHeader: FileHeader) => boolean`: Extract only the filtered file (_eg. extract only the files without password_).
|
||||
- `password?: string`: _Optional_ password for the extracted files only (Different password can be applied to any single file in RAR archive).
|
||||
- The return values are different for `createExtractorFromData` and `createExtractorFromFile`:
|
||||
- `ArcFiles<Uint8Array>` for `createExtractorFromData`
|
||||
- `ArcFiles` for `createExtractorFromFile`
|
||||
- Members in `ArcFiles`:
|
||||
- `arcHeader: ArcHeader` : The header of the archive
|
||||
- `files: Generator<ArcFile>` : The iterator of the `ArcFile` objects
|
||||
- Members in `ArcFile`:
|
||||
- `fileHeader: FileHeader` : The header of the extracted file
|
||||
- `extraction?: Uint8Array` : The extracted content of the file (`createExtractorFromData` only). If the `ArcFile` is a folder (`ArcFile.fileHeader.flags.directory` is `true`), the `extraction` will be undefined, otherwise it will be the content of the file (in `Uint8Array).
|
||||
|
||||
```js
|
||||
{
|
||||
arcHeader: {...} // Same as the arcHeader above
|
||||
files: (Iterator)
|
||||
{
|
||||
fileHeader: {...} // Same as the fileHeader above
|
||||
extraction?: Uint8Array // createExtractorFromData only
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Note: The returned iterators from the two apis are lazy, it means the file header/content will not be parsed/extracted if any file is not iterated yet.**
|
||||
|
||||
## Exception
|
||||
|
||||
The customized Error Object `UnrarError` will be thrown for any exception in extracting. The definition of the Object is:
|
||||
|
||||
```Typescript
|
||||
class UnrarError extends Error {
|
||||
reason: FailReason;
|
||||
file?: string | undefined; // Will be filled for any exception in extraction of a file
|
||||
}
|
||||
```
|
||||
|
||||
The following code is used in the `FailReason`:
|
||||
|
||||
| FailReason | Message |
|
||||
| --------------------- | ---------------------------------------------------------- |
|
||||
| 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 |
|
||||
|
||||
## Memory Leak
|
||||
|
||||
Note: although the return value `fileHeaders` and `files` are iterators, they must be traversed to the end! Otherwise the C++ object for archive extraction will not be destructed and cause memory leak.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const fs = require("fs");
|
||||
const unrar = require("node-unrar-js");
|
||||
|
||||
async function main() {
|
||||
// Read the archive file into a typedArray
|
||||
const buf = Uint8Array.from(fs.readFileSync("a.rar")).buffer;
|
||||
const extractor = await unrar.createExtractorFromData({ data: buf });
|
||||
|
||||
const list = extractor.getFileList();
|
||||
const listArcHeader = list.arcHeader; // archive header
|
||||
const fileHeaders = [...list.fileHeaders]; // load the file headers
|
||||
|
||||
const extracted = extractor.extract({ files: ["1.txt"] });
|
||||
// extracted.arcHeader : archive header
|
||||
const files = [...extracted.files]; //load the files
|
||||
files[0].fileHeader; // file header
|
||||
files[0].extraction; // Uint8Array content, createExtractorFromData only
|
||||
}
|
||||
main();
|
||||
```
|
||||
|
||||
## Demo in Webpack
|
||||
|
||||
This package can also be used in browser by Webpack, please visit the [demo project](https://github.com/YuJianrong/node-unrar.js/tree/master/demo/web) to see how to use it in webpack.
|
||||
|
||||
## Use in Webpack-bundled NodeJS Project
|
||||
|
||||
In most cases the exported ESModule is used in browser by Webpack, but in case if the NodeJs project (or an Electron project) is bundled by Webpack, the `wasmBinary` data must be loaded manually just like the browser by Webpack, it can be loaded like this:
|
||||
|
||||
```Typescript
|
||||
import fs from 'fs';
|
||||
import { createExtractorFromFile } from 'node-unrar-js/esm';
|
||||
|
||||
const wasmBinary = fs.readFileSync(require.resolve('node-unrar-js/esm/js/unrar.wasm'));
|
||||
|
||||
const extractor = await createExtractorFromFile({ wasmBinary, filepath: './WithComment.rar' });
|
||||
|
||||
// const list = extractor.getFileList();
|
||||
```
|
||||
|
||||
Note: the package must be loaded from `'node-unrar-js/esm'` instead of `'node-unrar-js'` to enable the function `createExtractorFromFile` in ES Module.
|
||||
|
||||
## TypeScript
|
||||
|
||||
This module is written in [TypeScript](https://www.typescriptlang.org/), you can import it directly in TypeScript and get the benefit of static type checking and auto-complete of IDE.
|
||||
|
||||
## Development and Contribution
|
||||
|
||||
If you want to compile the module by yourself, please follow the steps below:
|
||||
|
||||
- Install the [docker](https://www.docker.com/)
|
||||
|
||||
- Download the c++ source of unRar library by:
|
||||
|
||||
`npm run downloadUnrarSrc`
|
||||
|
||||
- Build for debug:
|
||||
|
||||
`npm run build:debug`
|
||||
|
||||
- Build for release
|
||||
|
||||
`npm run build:release`
|
||||
|
||||
- Run Test
|
||||
|
||||
`npm run test`
|
||||
|
||||
## License
|
||||
|
||||
This module is licensed under MIT.
|
||||
|
||||
### [Changelog](https://github.com/YuJianrong/node-unrar.js/blob/master/CHANGELOG.md)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { Extractor } from './js/Extractor';
|
||||
export * from './index.esm';
|
||||
export interface ExtractorFromFileOptions {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
filepath: string;
|
||||
targetPath?: string;
|
||||
password?: string;
|
||||
filenameTransform?: (filename: string) => string;
|
||||
}
|
||||
export declare function createExtractorFromFile({ wasmBinary, filepath, targetPath, password, filenameTransform, }: ExtractorFromFileOptions): Promise<Extractor>;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { Extractor } from './js/Extractor';
|
||||
export * from './js/Extractor';
|
||||
export interface ExtractorFromDataOptions {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
data: ArrayBuffer;
|
||||
password?: string;
|
||||
}
|
||||
export declare function createExtractorFromData({ wasmBinary, data, password, }: ExtractorFromDataOptions): Promise<Extractor<Uint8Array>>;
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
"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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createExtractorFromData = void 0;
|
||||
const ExtractorData_1 = require("./js/ExtractorData");
|
||||
const unrar_singleton_1 = require("./js/unrar.singleton");
|
||||
__exportStar(require("./js/Extractor"), exports);
|
||||
async function createExtractorFromData({ wasmBinary, data, password = '', }) {
|
||||
const unrar = await (0, unrar_singleton_1.getUnrar)(wasmBinary && { wasmBinary });
|
||||
const extractor = new ExtractorData_1.ExtractorData(unrar, data, password);
|
||||
unrar.extractor = extractor;
|
||||
return extractor;
|
||||
}
|
||||
exports.createExtractorFromData = createExtractorFromData;
|
||||
//# sourceMappingURL=index.esm.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.esm.js","sourceRoot":"","sources":["../src/index.esm.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AACA,sDAAmD;AACnD,0DAAgD;AAChD,iDAA+B;AAQxB,KAAK,UAAU,uBAAuB,CAAC,EAC5C,UAAU,EACV,IAAI,EACJ,QAAQ,GAAG,EAAE,GACY;IACzB,MAAM,KAAK,GAAG,MAAM,IAAA,0BAAQ,EAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,6BAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3D,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,OAAO,SAAS,CAAC;AACnB,CAAC;AATD,0DASC"}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
"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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createExtractorFromFile = void 0;
|
||||
const ExtractorFile_1 = require("./js/ExtractorFile");
|
||||
const unrar_singleton_1 = require("./js/unrar.singleton");
|
||||
__exportStar(require("./index.esm"), exports);
|
||||
async function createExtractorFromFile({ wasmBinary, filepath, targetPath = '', password = '', filenameTransform = (filename) => filename, }) {
|
||||
const unrar = await (0, unrar_singleton_1.getUnrar)(wasmBinary && { wasmBinary });
|
||||
const extractor = new ExtractorFile_1.ExtractorFile(unrar, filepath, targetPath, password, filenameTransform);
|
||||
unrar.extractor = extractor;
|
||||
return extractor;
|
||||
}
|
||||
exports.createExtractorFromFile = createExtractorFromFile;
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AACA,sDAAmD;AACnD,0DAAgD;AAChD,8CAA4B;AAUrB,KAAK,UAAU,uBAAuB,CAAC,EAC5C,UAAU,EACV,QAAQ,EACR,UAAU,GAAG,EAAE,EACf,QAAQ,GAAG,EAAE,EACb,iBAAiB,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,GACzB;IACzB,MAAM,KAAK,GAAG,MAAM,IAAA,0BAAQ,EAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,6BAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAC9F,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,OAAO,SAAS,CAAC;AACnB,CAAC;AAXD,0DAWC"}
|
||||
+91
@@ -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
@@ -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
|
||||
+17
@@ -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;
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
+70
@@ -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
@@ -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
|
||||
+15
@@ -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
@@ -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
|
||||
+21
File diff suppressed because one or more lines are too long
+3
@@ -0,0 +1,3 @@
|
||||
export declare function getUnrar(options?: {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
}): Promise<any>;
|
||||
+17
@@ -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
|
||||
BIN
Binary file not shown.
+10
@@ -0,0 +1,10 @@
|
||||
import { Extractor } from './js/Extractor';
|
||||
export * from './index.esm';
|
||||
export interface ExtractorFromFileOptions {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
filepath: string;
|
||||
targetPath?: string;
|
||||
password?: string;
|
||||
filenameTransform?: (filename: string) => string;
|
||||
}
|
||||
export declare function createExtractorFromFile({ wasmBinary, filepath, targetPath, password, filenameTransform, }: ExtractorFromFileOptions): Promise<Extractor>;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { Extractor } from './js/Extractor';
|
||||
export * from './js/Extractor';
|
||||
export interface ExtractorFromDataOptions {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
data: ArrayBuffer;
|
||||
password?: string;
|
||||
}
|
||||
export declare function createExtractorFromData({ wasmBinary, data, password, }: ExtractorFromDataOptions): Promise<Extractor<Uint8Array>>;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { ExtractorData } from './js/ExtractorData';
|
||||
import { getUnrar } from './js/unrar.singleton';
|
||||
export * from './js/Extractor';
|
||||
export async function createExtractorFromData({ wasmBinary, data, password = '', }) {
|
||||
const unrar = await getUnrar(wasmBinary && { wasmBinary });
|
||||
const extractor = new ExtractorData(unrar, data, password);
|
||||
unrar.extractor = extractor;
|
||||
return extractor;
|
||||
}
|
||||
//# sourceMappingURL=index.esm.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.esm.js","sourceRoot":"","sources":["../src/index.esm.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,cAAc,gBAAgB,CAAC;AAQ/B,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAC5C,UAAU,EACV,IAAI,EACJ,QAAQ,GAAG,EAAE,GACY;IACzB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3D,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { ExtractorFile } from './js/ExtractorFile';
|
||||
import { getUnrar } from './js/unrar.singleton';
|
||||
export * from './index.esm';
|
||||
export async function createExtractorFromFile({ wasmBinary, filepath, targetPath = '', password = '', filenameTransform = (filename) => filename, }) {
|
||||
const unrar = await getUnrar(wasmBinary && { wasmBinary });
|
||||
const extractor = new ExtractorFile(unrar, filepath, targetPath, password, filenameTransform);
|
||||
unrar.extractor = extractor;
|
||||
return extractor;
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,cAAc,aAAa,CAAC;AAU5B,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAC5C,UAAU,EACV,QAAQ,EACR,UAAU,GAAG,EAAE,EACf,QAAQ,GAAG,EAAE,EACb,iBAAiB,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,GACzB;IACzB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAC9F,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
||||
+91
@@ -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 {};
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
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',
|
||||
};
|
||||
export class UnrarError extends Error {
|
||||
constructor(reason, message, file) {
|
||||
super(message);
|
||||
this.reason = reason;
|
||||
this.file = file;
|
||||
}
|
||||
}
|
||||
export 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);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=Extractor.js.map
|
||||
+17
@@ -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;
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
export 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];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ExtractorData.helper.js.map
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import { DataFile } from './ExtractorData.helper';
|
||||
import { Extractor } from './Extractor';
|
||||
export class ExtractorData extends 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 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 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);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ExtractorData.js.map
|
||||
+15
@@ -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;
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Extractor } from './Extractor';
|
||||
export class ExtractorFile extends 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;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ExtractorFile.js.map
|
||||
+16
File diff suppressed because one or more lines are too long
+3
@@ -0,0 +1,3 @@
|
||||
export declare function getUnrar(options?: {
|
||||
wasmBinary?: ArrayBuffer;
|
||||
}): Promise<any>;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import unrarFactory from './unrar';
|
||||
let unrar;
|
||||
export async function getUnrar(options) {
|
||||
if (!unrar) {
|
||||
unrar = await unrarFactory(options);
|
||||
}
|
||||
return unrar;
|
||||
}
|
||||
//# sourceMappingURL=unrar.singleton.js.map
|
||||
BIN
Binary file not shown.
+74
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "node-unrar-js",
|
||||
"version": "2.0.2",
|
||||
"description": "Pure JavaScript RAR archive extractor by compile the official unrar lib by Emscripten.",
|
||||
"homepage": "https://github.com/YuJianrong/node-unrar.js",
|
||||
"bugs": {
|
||||
"url": "https://github.com/YuJianrong/node-unrar.js/issues"
|
||||
},
|
||||
"repository": "YuJianrong/node-unrar.js",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./esm/index.esm.js",
|
||||
"scripts": {
|
||||
"prepare": "husky install",
|
||||
"downloadUnrarSrc": "wget https://www.rarlab.com/rar/unrarsrc-6.1.7.tar.gz && tar -xf unrarsrc-6.1.7.tar.gz -C src/cpp && rm -rf unrarsrc-6.1.7.tar.gz && husky install",
|
||||
"clean": "rm -rf dist coverage dist_map esm",
|
||||
"clean:test": "rm -rf dist/test dist/build esm/test esm/build dist/**/*.map esm/**/*.map",
|
||||
"commit": "cz",
|
||||
"lint": "eslint './src/**/*.ts' --max-warnings 0",
|
||||
"tsc": "tsc",
|
||||
"build:debug": "tsc && node ./dist/build/make.js",
|
||||
"prebuild:release": "npm run lint",
|
||||
"build:release": "npm run clean && tsc && node ./dist/build/make.js release && tsc -p tsconfig-esm.json && node ./dist/build/make.js release esm",
|
||||
"test": "mocha dist/test/*.spec.js",
|
||||
"test:debug": "npm run test -- --inspect-brk"
|
||||
},
|
||||
"keywords": [
|
||||
"unrar"
|
||||
],
|
||||
"author": "Jianrong Yu <yujianrong@gmail.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.4.3",
|
||||
"@commitlint/config-conventional": "^18.4.3",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@types/eslint": "^8.44.7",
|
||||
"@types/mocha": "^10.0.5",
|
||||
"@types/shelljs": "^0.8.15",
|
||||
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
||||
"@typescript-eslint/parser": "^6.12.0",
|
||||
"commitizen": "^4.3.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^15.1.0",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^3.1.0",
|
||||
"shelljs": "^0.8.5",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{json,md,less,yaml,yml}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{ts,tsx}": [
|
||||
"eslint --fix --max-warnings 0"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"esm",
|
||||
"*.md"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user