feat: 实现供水运营专题大屏BI可视化
- 新增OperationDashboard.vue全屏大屏组件 - 添加6个核心KPI指标卡片: 进水总量/出水总量/产销差率/营收额/平均水质/报警次数 - 实现6个ECharts图表: 供水趋势/水质分布/报警统计/管网空间/设备状态/营收分析 - 创建静态HTML版本operation-dashboard.html,使用CDN加载Vue3/ECharts/Element Plus - 更新路由配置,添加/operation路径支持 - 修复nextTick导入问题,优化build脚本 🚧 开发者: bot_dev1 📝 任务: #38 [BI] 运营仪表盘 + 供水专题大屏
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
# .github/workflows/publish.yml
|
||||
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
publish_jsr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: npx jsr publish
|
||||
|
||||
publish_npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm publish
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2023, Gildas Lormeau
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
# Introduction
|
||||
|
||||
zip.js is a JavaScript open-source library (BSD-3-Clause license) for
|
||||
compressing and decompressing zip files. It has been designed to handle large amounts
|
||||
of data. It supports notably multi-core compression, native compression with
|
||||
compression streams, archives larger than 4GB with Zip64, split zip files, data
|
||||
encryption, and Deflate64 decompression.
|
||||
|
||||
# Demo
|
||||
|
||||
See https://gildas-lormeau.github.io/zip-manager
|
||||
|
||||
# Documentation
|
||||
|
||||
See here for more info: https://gildas-lormeau.github.io/zip.js/
|
||||
|
||||
# Examples
|
||||
|
||||
## Hello world
|
||||
|
||||
```js
|
||||
import {
|
||||
BlobReader,
|
||||
BlobWriter,
|
||||
TextReader,
|
||||
TextWriter,
|
||||
ZipReader,
|
||||
ZipWriter
|
||||
} from "@zip-js/zip-js";
|
||||
// Prefix "@zip-js/zip-js" with "jsr:" for Deno
|
||||
|
||||
// ----
|
||||
// Write the zip file
|
||||
// ----
|
||||
|
||||
// Creates a BlobWriter object where the zip content will be written.
|
||||
const zipFileWriter = new BlobWriter();
|
||||
// Creates a TextReader object storing the text of the entry to add in the zip
|
||||
// (i.e. "Hello world!").
|
||||
const helloWorldReader = new TextReader("Hello world!");
|
||||
|
||||
// Creates a ZipWriter object writing data via `zipFileWriter`, adds the entry
|
||||
// "hello.txt" containing the text "Hello world!" via `helloWorldReader`, and
|
||||
// closes the writer.
|
||||
const zipWriter = new ZipWriter(zipFileWriter);
|
||||
await zipWriter.add("hello.txt", helloWorldReader);
|
||||
await zipWriter.close();
|
||||
|
||||
// Retrieves the Blob object containing the zip content into `zipFileBlob`. It
|
||||
// is also returned by zipWriter.close() for more convenience.
|
||||
const zipFileBlob = await zipFileWriter.getData();
|
||||
|
||||
// ----
|
||||
// Read the zip file
|
||||
// ----
|
||||
|
||||
// Creates a BlobReader object used to read `zipFileBlob`.
|
||||
const zipFileReader = new BlobReader(zipFileBlob);
|
||||
// Creates a TextWriter object where the content of the first entry in the zip
|
||||
// will be written.
|
||||
const helloWorldWriter = new TextWriter();
|
||||
|
||||
// Creates a ZipReader object reading the zip content via `zipFileReader`,
|
||||
// retrieves metadata (name, dates, etc.) of the first entry, retrieves its
|
||||
// content via `helloWorldWriter`, and closes the reader.
|
||||
const zipReader = new ZipReader(zipFileReader);
|
||||
const firstEntry = (await zipReader.getEntries()).shift();
|
||||
const helloWorldText = await firstEntry.getData(helloWorldWriter);
|
||||
await zipReader.close();
|
||||
|
||||
// Displays "Hello world!".
|
||||
console.log(helloWorldText);
|
||||
```
|
||||
|
||||
Run the code on JSFiddle: https://jsfiddle.net/tm9fhvab/
|
||||
|
||||
## Hello world with Streams
|
||||
|
||||
```js
|
||||
import {
|
||||
BlobReader,
|
||||
ZipReader,
|
||||
ZipWriter
|
||||
} from "@zip-js/zip-js";
|
||||
// Prefix "@zip-js/zip-js" with "jsr:" for Deno
|
||||
|
||||
// ----
|
||||
// Write the zip file
|
||||
// ----
|
||||
|
||||
// Creates a TransformStream object, the zip content will be written in the
|
||||
// `writable` property.
|
||||
const zipFileStream = new TransformStream();
|
||||
// Creates a Promise object resolved to the zip content returned as a Blob
|
||||
// object retrieved from `zipFileStream.readable`.
|
||||
const zipFileBlobPromise = new Response(zipFileStream.readable).blob();
|
||||
// Creates a ReadableStream object storing the text of the entry to add in the
|
||||
// zip (i.e. "Hello world!").
|
||||
const helloWorldReadable = new Blob(["Hello world!"]).stream();
|
||||
|
||||
// Creates a ZipWriter object writing data into `zipFileStream.writable`, adds
|
||||
// the entry "hello.txt" containing the text "Hello world!" retrieved from
|
||||
// `helloWorldReadable`, and closes the writer.
|
||||
const zipWriter = new ZipWriter(zipFileStream.writable);
|
||||
await zipWriter.add("hello.txt", helloWorldReadable);
|
||||
await zipWriter.close();
|
||||
|
||||
// Retrieves the Blob object containing the zip content into `zipFileBlob`.
|
||||
const zipFileBlob = await zipFileBlobPromise;
|
||||
|
||||
// ----
|
||||
// Read the zip file
|
||||
// ----
|
||||
|
||||
// Creates a BlobReader object used to read `zipFileBlob`.
|
||||
const zipFileReader = new BlobReader(zipFileBlob);
|
||||
// Creates a TransformStream object, the content of the first entry in the zip
|
||||
// will be written in the `writable` property.
|
||||
const helloWorldStream = new TransformStream();
|
||||
// Creates a Promise object resolved to the content of the first entry returned
|
||||
// as text from `helloWorldStream.readable`.
|
||||
const helloWorldTextPromise = new Response(helloWorldStream.readable).text();
|
||||
|
||||
// Creates a ZipReader object reading the zip content via `zipFileReader`,
|
||||
// retrieves metadata (name, dates, etc.) of the first entry, retrieves its
|
||||
// content into `helloWorldStream.writable`, and closes the reader.
|
||||
const zipReader = new ZipReader(zipFileReader);
|
||||
const firstEntry = (await zipReader.getEntries()).shift();
|
||||
await firstEntry.getData(helloWorldStream.writable);
|
||||
await zipReader.close();
|
||||
|
||||
// Displays "Hello world!".
|
||||
const helloWorldText = await helloWorldTextPromise;
|
||||
console.log(helloWorldText);
|
||||
```
|
||||
|
||||
Run the code on JSFiddle: https://jsfiddle.net/aw3d6f4o/
|
||||
|
||||
## Adding concurrently multiple entries in a zip file
|
||||
|
||||
```js
|
||||
import {
|
||||
BlobWriter,
|
||||
HttpReader,
|
||||
TextReader,
|
||||
ZipWriter,
|
||||
} from "@zip-js/zip-js";
|
||||
// Prefix "@zip-js/zip-js" with "jsr:" for Deno
|
||||
|
||||
const README_URL = "https://unpkg.com/@zip.js/zip.js/README.md";
|
||||
getZipFileBlob()
|
||||
.then(downloadFile);
|
||||
|
||||
async function getZipFileBlob() {
|
||||
const zipWriter = new ZipWriter(new BlobWriter("application/zip"));
|
||||
await Promise.all([
|
||||
zipWriter.add("hello.txt", new TextReader("Hello world!")),
|
||||
zipWriter.add("README.md", new HttpReader(README_URL)),
|
||||
]);
|
||||
return zipWriter.close();
|
||||
}
|
||||
|
||||
function downloadFile(blob) {
|
||||
document.body.appendChild(Object.assign(document.createElement("a"), {
|
||||
download: "hello.zip",
|
||||
href: URL.createObjectURL(blob),
|
||||
textContent: "Download zip file",
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
Run the code on Plunker: https://plnkr.co/edit/4sVljNIpqSUE9HCA?preview
|
||||
|
||||
## Tests
|
||||
|
||||
See https://github.com/gildas-lormeau/zip.js/tree/master/tests/all
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@zip-js/zip-js",
|
||||
"version": "2.8.26",
|
||||
"exports": {
|
||||
".": "./index.js"
|
||||
},
|
||||
"lint": {
|
||||
"exclude": [
|
||||
"dist/*.js",
|
||||
"*-inline.js",
|
||||
"tests/vendor/*.js",
|
||||
"index.cjs",
|
||||
"index.min.js"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"rollup*",
|
||||
"tsconfig.json",
|
||||
".vscode",
|
||||
".eslintrc.json",
|
||||
"docs"
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
# Prebuilt zip.js bundles
|
||||
|
||||
**Note**: These bundles are not ES module compatible (you cannot `import` them directly). Use `index.js` at the project root or one of the `zip-*.js` files in [`/lib`](../lib) (e.g. `/lib/zip-core.js`) for ESM usage.
|
||||
|
||||
Contents:
|
||||
|
||||
- `zip.js` / `zip.min.js`: Full `ZipWriter` / `ZipReader` bundles with embedded Web Worker code and WASM.
|
||||
- `zip-fs.js` / `zip-fs.min.js`: Full `ZipWriter` / `ZipReader` plus virtual file system (`fs`), with embedded Web Worker code and WASM.
|
||||
- `zip-core.js` / `zip-core.min.js`: Minimal `ZipWriter` / `ZipReader`.
|
||||
- `zip-fs-core.js` / `zip-fs-core.min.js`: Minimal `ZipWriter` / `ZipReader` plus virtual file system (`fs`).
|
||||
|
||||
Online builder:
|
||||
|
||||
Alternatively, you can build your own version of zip.js with the online builder, see https://gildas-lormeau.github.io/zip.js/builder.
|
||||
|
||||
Notes:
|
||||
- Files suffixed with `-native` rely on a pure JavaScript implementation of Compression Streams instead of a WASM module.
|
||||
- `zip-legacy.min.js` is the equivalent of `zip.min.js` before the version `2.8`, it relies on a JavaScript implementation of Compression Streams (if used) but only in web workers. Alternatively `zip-native.min.js` includes the Compression Streams implementation in the main environment and the web workers.
|
||||
+6027
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+6675
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+8599
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+8890
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+6060
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
+6098
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+6389
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+49
@@ -0,0 +1,49 @@
|
||||
import js from "@eslint/js";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
"**/node_modules/",
|
||||
".git/",
|
||||
"dist/",
|
||||
"**/*-inline.js",
|
||||
"tests/vendor/*.js",
|
||||
"index.cjs",
|
||||
"index.min.js"
|
||||
]
|
||||
},
|
||||
js.configs.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
sourceType: "module",
|
||||
globals: {
|
||||
console: "readonly"
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
"indent": [
|
||||
"error",
|
||||
"tab",
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"double"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-console": [
|
||||
"warn"
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
+8591
File diff suppressed because one or more lines are too long
+31
@@ -0,0 +1,31 @@
|
||||
/// <reference types="./index.d.ts" />
|
||||
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./lib/zip-fs-native.js";
|
||||
+1
File diff suppressed because one or more lines are too long
+8882
File diff suppressed because one or more lines are too long
+2355
File diff suppressed because it is too large
Load Diff
+31
@@ -0,0 +1,31 @@
|
||||
/// <reference types="./index.d.ts" />
|
||||
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./lib/zip-fs-wasm.js";
|
||||
+1
File diff suppressed because one or more lines are too long
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global setTimeout, clearTimeout */
|
||||
|
||||
import { UNDEFINED_VALUE } from "./constants.js";
|
||||
import {
|
||||
CODEC_INFLATE,
|
||||
CODEC_DEFLATE,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_ABORT_CHECK_PASSWORD
|
||||
} from "./streams/codec-stream.js";
|
||||
import { CodecWorker } from "./codec-worker.js";
|
||||
|
||||
let pool = [];
|
||||
const pendingRequests = [];
|
||||
|
||||
export {
|
||||
runWorker,
|
||||
terminateWorkers,
|
||||
CODEC_DEFLATE,
|
||||
CODEC_INFLATE,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_ABORT_CHECK_PASSWORD
|
||||
};
|
||||
|
||||
let indexWorker = 0;
|
||||
|
||||
async function runWorker(stream, workerOptions) {
|
||||
const { options, config } = workerOptions;
|
||||
const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted } = options;
|
||||
const { workerURI, maxWorkers } = config;
|
||||
workerOptions.transferStreams = transferStreams || transferStreams === UNDEFINED_VALUE;
|
||||
const streamCopy = !compressed && !signed && !encrypted && !workerOptions.transferStreams;
|
||||
workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
|
||||
workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
|
||||
options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
|
||||
return (await getWorker()).run();
|
||||
|
||||
// deno-lint-ignore require-await
|
||||
async function getWorker() {
|
||||
const workerData = pool.find(workerData => !workerData.busy);
|
||||
if (workerData) {
|
||||
clearTerminateTimeout(workerData);
|
||||
return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
||||
} else if (pool.length < maxWorkers) {
|
||||
const workerData = { indexWorker };
|
||||
indexWorker++;
|
||||
pool.push(workerData);
|
||||
return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
||||
} else {
|
||||
return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
|
||||
}
|
||||
}
|
||||
|
||||
function onTaskFinished(workerData) {
|
||||
if (pendingRequests.length) {
|
||||
const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
|
||||
resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
|
||||
} else if (workerData.worker) {
|
||||
clearTerminateTimeout(workerData);
|
||||
terminateWorker(workerData, workerOptions);
|
||||
} else {
|
||||
pool = pool.filter(data => data != workerData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function terminateWorker(workerData, workerOptions) {
|
||||
const { config } = workerOptions;
|
||||
const { terminateWorkerTimeout } = config;
|
||||
if (Number.isFinite(terminateWorkerTimeout) && terminateWorkerTimeout >= 0) {
|
||||
if (workerData.terminated) {
|
||||
workerData.terminated = false;
|
||||
} else {
|
||||
workerData.terminateTimeout = setTimeout(async () => {
|
||||
pool = pool.filter(data => data != workerData);
|
||||
try {
|
||||
await workerData.terminate();
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
}, terminateWorkerTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearTerminateTimeout(workerData) {
|
||||
const { terminateTimeout } = workerData;
|
||||
if (terminateTimeout) {
|
||||
clearTimeout(terminateTimeout);
|
||||
workerData.terminateTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function terminateWorkers() {
|
||||
await Promise.allSettled(pool.map(workerData => {
|
||||
clearTerminateTimeout(workerData);
|
||||
return workerData.terminate();
|
||||
}));
|
||||
}
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global Worker, URL, TransformStream, WritableStream */
|
||||
|
||||
import {
|
||||
UNDEFINED_VALUE,
|
||||
UNDEFINED_TYPE,
|
||||
FUNCTION_TYPE
|
||||
} from "./constants.js";
|
||||
import {
|
||||
CodecStream,
|
||||
ChunkStream,
|
||||
MESSAGE_EVENT_TYPE,
|
||||
MESSAGE_START,
|
||||
MESSAGE_PULL,
|
||||
MESSAGE_DATA,
|
||||
MESSAGE_ACK_DATA,
|
||||
MESSAGE_CLOSE
|
||||
} from "./streams/codec-stream.js";
|
||||
|
||||
const MODULE_WORKER_OPTIONS = { type: "module" };
|
||||
|
||||
let webWorkerSupported, webWorkerURI, webWorkerOptions;
|
||||
let transferStreamsSupported = true;
|
||||
try {
|
||||
transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
let initModule = () => { };
|
||||
|
||||
export {
|
||||
CodecWorker,
|
||||
configureWorker
|
||||
};
|
||||
|
||||
function configureWorker({ initModule: initModuleFunction }) {
|
||||
initModule = initModuleFunction;
|
||||
}
|
||||
|
||||
class CodecWorker {
|
||||
|
||||
constructor(workerData, { readable, writable }, { options, config, streamOptions, useWebWorkers, transferStreams, workerURI }, onTaskFinished) {
|
||||
const { signal } = streamOptions;
|
||||
Object.assign(workerData, {
|
||||
busy: true,
|
||||
readable: readable
|
||||
.pipeThrough(new ChunkStream(config.chunkSize))
|
||||
.pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
|
||||
writable,
|
||||
options: Object.assign({}, options),
|
||||
workerURI,
|
||||
transferStreams,
|
||||
terminate() {
|
||||
return new Promise(resolve => {
|
||||
const { worker, busy } = workerData;
|
||||
if (worker) {
|
||||
if (busy) {
|
||||
workerData.resolveTerminated = resolve;
|
||||
} else {
|
||||
worker.terminate();
|
||||
resolve();
|
||||
}
|
||||
workerData.interface = null;
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
},
|
||||
onTaskFinished() {
|
||||
const { resolveTerminated } = workerData;
|
||||
if (resolveTerminated) {
|
||||
workerData.resolveTerminated = null;
|
||||
workerData.terminated = true;
|
||||
workerData.worker.terminate();
|
||||
resolveTerminated();
|
||||
}
|
||||
workerData.busy = false;
|
||||
onTaskFinished(workerData);
|
||||
}
|
||||
});
|
||||
if (webWorkerSupported === UNDEFINED_VALUE) {
|
||||
// deno-lint-ignore valid-typeof
|
||||
webWorkerSupported = typeof Worker != UNDEFINED_TYPE;
|
||||
}
|
||||
return (useWebWorkers && webWorkerSupported ? createWebWorkerInterface : createWorkerInterface)(workerData, config);
|
||||
}
|
||||
}
|
||||
|
||||
class ProgressWatcherStream extends TransformStream {
|
||||
|
||||
constructor({ onstart, onprogress, size, onend }) {
|
||||
let chunkOffset = 0;
|
||||
super({
|
||||
async start() {
|
||||
if (onstart) {
|
||||
await callHandler(onstart, size);
|
||||
}
|
||||
},
|
||||
async transform(chunk, controller) {
|
||||
chunkOffset += chunk.length;
|
||||
if (onprogress) {
|
||||
await callHandler(onprogress, chunkOffset, size);
|
||||
}
|
||||
controller.enqueue(chunk);
|
||||
},
|
||||
async flush() {
|
||||
if (onend) {
|
||||
await callHandler(onend, chunkOffset);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function callHandler(handler, ...parameters) {
|
||||
try {
|
||||
await handler(...parameters);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
function createWorkerInterface(workerData, config) {
|
||||
return {
|
||||
run: () => runWorker(workerData, config)
|
||||
};
|
||||
}
|
||||
|
||||
function createWebWorkerInterface(workerData, config) {
|
||||
const { baseURI, chunkSize } = config;
|
||||
let { wasmURI } = config;
|
||||
|
||||
if (!workerData.interface) {
|
||||
// deno-lint-ignore valid-typeof
|
||||
if (typeof wasmURI == FUNCTION_TYPE) {
|
||||
wasmURI = wasmURI();
|
||||
}
|
||||
let worker;
|
||||
try {
|
||||
worker = getWebWorker(workerData.workerURI, baseURI, workerData);
|
||||
} catch {
|
||||
webWorkerSupported = false;
|
||||
return createWorkerInterface(workerData, config);
|
||||
}
|
||||
Object.assign(workerData, {
|
||||
worker,
|
||||
interface: {
|
||||
run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
|
||||
}
|
||||
});
|
||||
}
|
||||
return workerData.interface;
|
||||
}
|
||||
|
||||
async function runWorker({ options, readable, writable, onTaskFinished }, config) {
|
||||
let codecStream;
|
||||
try {
|
||||
if (!options.useCompressionStream) {
|
||||
try {
|
||||
await initModule(config);
|
||||
} catch {
|
||||
options.useCompressionStream = true;
|
||||
}
|
||||
}
|
||||
codecStream = new CodecStream(options, config);
|
||||
await readable.pipeThrough(codecStream).pipeTo(writable, { preventClose: true, preventAbort: true });
|
||||
const {
|
||||
signature,
|
||||
inputSize,
|
||||
outputSize
|
||||
} = codecStream;
|
||||
return {
|
||||
signature,
|
||||
inputSize,
|
||||
outputSize
|
||||
};
|
||||
} catch (error) {
|
||||
if (codecStream) {
|
||||
error.outputSize = codecStream.outputSize;
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
onTaskFinished();
|
||||
}
|
||||
}
|
||||
|
||||
async function runWebWorker(workerData, config) {
|
||||
let resolveResult, rejectResult;
|
||||
const result = new Promise((resolve, reject) => {
|
||||
resolveResult = resolve;
|
||||
rejectResult = reject;
|
||||
});
|
||||
Object.assign(workerData, {
|
||||
reader: null,
|
||||
writer: null,
|
||||
resolveResult,
|
||||
rejectResult,
|
||||
result
|
||||
});
|
||||
const { readable, options } = workerData;
|
||||
const { writable, closed } = watchClosedStream(workerData.writable);
|
||||
const streamsTransferred = sendMessage({
|
||||
type: MESSAGE_START,
|
||||
options,
|
||||
config,
|
||||
readable,
|
||||
writable
|
||||
}, workerData);
|
||||
if (!streamsTransferred) {
|
||||
Object.assign(workerData, {
|
||||
reader: readable.getReader(),
|
||||
writer: writable.getWriter()
|
||||
});
|
||||
}
|
||||
const resultValue = await result;
|
||||
if (!streamsTransferred) {
|
||||
await writable.getWriter().close();
|
||||
}
|
||||
await closed;
|
||||
return resultValue;
|
||||
}
|
||||
|
||||
function watchClosedStream(writableSource) {
|
||||
const { writable, readable } = new TransformStream();
|
||||
const closed = readable.pipeTo(writableSource, { preventClose: true });
|
||||
return { writable, closed };
|
||||
}
|
||||
|
||||
function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true) {
|
||||
let worker, resolvedURI, resolvedOptions;
|
||||
if (webWorkerURI === UNDEFINED_VALUE) {
|
||||
// deno-lint-ignore valid-typeof
|
||||
const isFunctionURI = typeof url == FUNCTION_TYPE;
|
||||
if (isFunctionURI) {
|
||||
resolvedURI = url(useBlobURI);
|
||||
} else {
|
||||
resolvedURI = url;
|
||||
}
|
||||
const isDataURI = resolvedURI.startsWith("data:");
|
||||
const isBlobURI = resolvedURI.startsWith("blob:");
|
||||
if (isDataURI || isBlobURI) {
|
||||
if (isModuleType === UNDEFINED_VALUE) {
|
||||
isModuleType = false;
|
||||
}
|
||||
if (isModuleType) {
|
||||
resolvedOptions = MODULE_WORKER_OPTIONS;
|
||||
}
|
||||
try {
|
||||
worker = new Worker(resolvedURI, resolvedOptions);
|
||||
} catch (error) {
|
||||
if (isBlobURI) {
|
||||
try {
|
||||
URL.revokeObjectURL(resolvedURI);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
if (isFunctionURI && isBlobURI) {
|
||||
return getWebWorker(url, baseURI, workerData, isModuleType, false);
|
||||
} else if (!isModuleType) {
|
||||
return getWebWorker(url, baseURI, workerData, true, false);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isModuleType === UNDEFINED_VALUE) {
|
||||
isModuleType = true;
|
||||
}
|
||||
if (isModuleType) {
|
||||
resolvedOptions = MODULE_WORKER_OPTIONS;
|
||||
}
|
||||
try {
|
||||
resolvedURI = new URL(resolvedURI, baseURI);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
try {
|
||||
worker = new Worker(resolvedURI, resolvedOptions);
|
||||
} catch (error) {
|
||||
if (!isModuleType) {
|
||||
return getWebWorker(url, baseURI, workerData, false, useBlobURI);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
webWorkerURI = resolvedURI;
|
||||
webWorkerOptions = resolvedOptions;
|
||||
} else {
|
||||
worker = new Worker(webWorkerURI, webWorkerOptions);
|
||||
}
|
||||
worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
|
||||
return worker;
|
||||
}
|
||||
|
||||
function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
|
||||
try {
|
||||
const { value, readable, writable } = message;
|
||||
const transferables = [];
|
||||
if (value) {
|
||||
message.value = value;
|
||||
transferables.push(message.value.buffer);
|
||||
}
|
||||
if (transferStreams && transferStreamsSupported) {
|
||||
if (readable) {
|
||||
transferables.push(readable);
|
||||
}
|
||||
if (writable) {
|
||||
transferables.push(writable);
|
||||
}
|
||||
} else {
|
||||
message.readable = message.writable = null;
|
||||
}
|
||||
if (transferables.length) {
|
||||
try {
|
||||
worker.postMessage(message, transferables);
|
||||
return true;
|
||||
} catch {
|
||||
transferStreamsSupported = false;
|
||||
message.readable = message.writable = null;
|
||||
worker.postMessage(message);
|
||||
}
|
||||
} else {
|
||||
worker.postMessage(message);
|
||||
}
|
||||
} catch (error) {
|
||||
if (writer) {
|
||||
writer.releaseLock();
|
||||
}
|
||||
onTaskFinished();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function onMessage({ data }, workerData) {
|
||||
const { type, value, messageId, result, error } = data;
|
||||
const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
|
||||
try {
|
||||
if (error) {
|
||||
const { message, stack, code, name, outputSize } = error;
|
||||
const responseError = new Error(message);
|
||||
Object.assign(responseError, { stack, code, name, outputSize });
|
||||
close(responseError);
|
||||
} else {
|
||||
if (type == MESSAGE_PULL) {
|
||||
const { value, done } = await reader.read();
|
||||
sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
|
||||
}
|
||||
if (type == MESSAGE_DATA) {
|
||||
await writer.ready;
|
||||
await writer.write(new Uint8Array(value));
|
||||
sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
|
||||
}
|
||||
if (type == MESSAGE_CLOSE) {
|
||||
close(null, result);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
|
||||
close(error);
|
||||
}
|
||||
|
||||
function close(error, result) {
|
||||
if (error) {
|
||||
rejectResult(error);
|
||||
} else {
|
||||
resolveResult(result);
|
||||
}
|
||||
if (writer) {
|
||||
writer.releaseLock();
|
||||
}
|
||||
onTaskFinished();
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global navigator, CompressionStream, DecompressionStream */
|
||||
|
||||
import {
|
||||
UNDEFINED_VALUE,
|
||||
UNDEFINED_TYPE
|
||||
} from "./constants.js";
|
||||
|
||||
const MINIMUM_CHUNK_SIZE = 64;
|
||||
let maxWorkers = 2;
|
||||
try {
|
||||
if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
|
||||
maxWorkers = navigator.hardwareConcurrency;
|
||||
}
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
const DEFAULT_CONFIGURATION = {
|
||||
workerURI: "./core/web-worker-wasm.js",
|
||||
wasmURI: "./core/streams/zlib-wasm/zlib-streams.wasm",
|
||||
chunkSize: 64 * 1024,
|
||||
maxWorkers,
|
||||
terminateWorkerTimeout: 5000,
|
||||
useWebWorkers: true,
|
||||
useCompressionStream: true,
|
||||
CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
|
||||
DecompressionStream: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
|
||||
};
|
||||
|
||||
const config = Object.assign({}, DEFAULT_CONFIGURATION);
|
||||
|
||||
export {
|
||||
configure,
|
||||
getConfiguration,
|
||||
getChunkSize
|
||||
};
|
||||
|
||||
function getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
function getChunkSize(config) {
|
||||
return Math.max(config.chunkSize, MINIMUM_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
function configure(configuration) {
|
||||
const {
|
||||
baseURI,
|
||||
chunkSize,
|
||||
maxWorkers,
|
||||
terminateWorkerTimeout,
|
||||
useCompressionStream,
|
||||
useWebWorkers,
|
||||
CompressionStream,
|
||||
DecompressionStream,
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib,
|
||||
workerURI,
|
||||
wasmURI
|
||||
} = configuration;
|
||||
setIfDefined("baseURI", baseURI);
|
||||
setIfDefined("wasmURI", wasmURI);
|
||||
setIfDefined("workerURI", workerURI);
|
||||
setIfDefined("chunkSize", chunkSize);
|
||||
setIfDefined("maxWorkers", maxWorkers);
|
||||
setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
|
||||
setIfDefined("useCompressionStream", useCompressionStream);
|
||||
setIfDefined("useWebWorkers", useWebWorkers);
|
||||
setIfDefined("CompressionStream", CompressionStream);
|
||||
setIfDefined("DecompressionStream", DecompressionStream);
|
||||
setIfDefined("CompressionStreamZlib", CompressionStreamZlib);
|
||||
setIfDefined("DecompressionStreamZlib", DecompressionStreamZlib);
|
||||
}
|
||||
|
||||
function setIfDefined(propertyName, propertyValue) {
|
||||
if (propertyValue !== UNDEFINED_VALUE) {
|
||||
config[propertyName] = propertyValue;
|
||||
}
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const MAX_32_BITS = 0xffffffff;
|
||||
const MAX_16_BITS = 0xffff;
|
||||
const MAX_8_BITS = 0xff;
|
||||
const COMPRESSION_METHOD_DEFLATE = 0x08;
|
||||
const COMPRESSION_METHOD_DEFLATE_64 = 0x09;
|
||||
const COMPRESSION_METHOD_STORE = 0x00;
|
||||
const COMPRESSION_METHOD_AES = 0x63;
|
||||
|
||||
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
||||
const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
|
||||
const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
|
||||
const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
|
||||
const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
|
||||
const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
|
||||
const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
|
||||
const END_OF_CENTRAL_DIR_LENGTH = 22;
|
||||
const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
|
||||
const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
|
||||
const ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH = END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LENGTH;
|
||||
|
||||
const DATA_DESCRIPTOR_RECORD_LENGTH = 12;
|
||||
const DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH = 20;
|
||||
const DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH = 4;
|
||||
|
||||
const EXTRAFIELD_TYPE_ZIP64 = 0x0001;
|
||||
const EXTRAFIELD_TYPE_AES = 0x9901;
|
||||
const EXTRAFIELD_TYPE_NTFS = 0x000a;
|
||||
const EXTRAFIELD_TYPE_NTFS_TAG1 = 0x0001;
|
||||
const EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP = 0x5455;
|
||||
const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075;
|
||||
const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375;
|
||||
const EXTRAFIELD_TYPE_USDZ = 0x1986;
|
||||
const EXTRAFIELD_TYPE_INFOZIP = 0x7875;
|
||||
const EXTRAFIELD_TYPE_UNIX = 0x7855;
|
||||
|
||||
const BITFLAG_ENCRYPTED = 0b1;
|
||||
const BITFLAG_LEVEL = 0b0110;
|
||||
const BITFLAG_LEVEL_MAX_MASK = 0b010;
|
||||
const BITFLAG_LEVEL_FAST_MASK = 0b100;
|
||||
const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
|
||||
const BITFLAG_DATA_DESCRIPTOR = 0b1000;
|
||||
const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
|
||||
const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
|
||||
const FILE_ATTR_MSDOS_READONLY_MASK = 0x01;
|
||||
const FILE_ATTR_MSDOS_HIDDEN_MASK = 0x02;
|
||||
const FILE_ATTR_MSDOS_SYSTEM_MASK = 0x04;
|
||||
const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
|
||||
const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
|
||||
const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
|
||||
const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
|
||||
const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
|
||||
const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
|
||||
const FILE_ATTR_UNIX_SETGID_MASK = 0o2000;
|
||||
const FILE_ATTR_UNIX_STICKY_MASK = 0o1000;
|
||||
|
||||
const VERSION_DEFLATE = 0x14;
|
||||
const VERSION_ZIP64 = 0x2D;
|
||||
const VERSION_AES = 0x33;
|
||||
|
||||
const DIRECTORY_SIGNATURE = "/";
|
||||
|
||||
const HEADER_SIZE = 30;
|
||||
const HEADER_OFFSET_SIGNATURE = 10;
|
||||
const HEADER_OFFSET_COMPRESSED_SIZE = 14;
|
||||
const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
|
||||
|
||||
const MAX_DATE = new Date(2107, 11, 31);
|
||||
const MIN_DATE = new Date(1980, 0, 1);
|
||||
|
||||
const UNDEFINED_VALUE = undefined;
|
||||
const INFINITY_VALUE = Infinity;
|
||||
const UNDEFINED_TYPE = "undefined";
|
||||
const FUNCTION_TYPE = "function";
|
||||
const OBJECT_TYPE = "object";
|
||||
|
||||
export {
|
||||
MAX_32_BITS,
|
||||
MAX_16_BITS,
|
||||
MAX_8_BITS,
|
||||
COMPRESSION_METHOD_DEFLATE,
|
||||
COMPRESSION_METHOD_DEFLATE_64,
|
||||
COMPRESSION_METHOD_STORE,
|
||||
COMPRESSION_METHOD_AES,
|
||||
SPLIT_ZIP_FILE_SIGNATURE,
|
||||
LOCAL_FILE_HEADER_SIGNATURE,
|
||||
DATA_DESCRIPTOR_RECORD_SIGNATURE,
|
||||
CENTRAL_FILE_HEADER_SIGNATURE,
|
||||
END_OF_CENTRAL_DIR_SIGNATURE,
|
||||
ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE,
|
||||
ZIP64_END_OF_CENTRAL_DIR_SIGNATURE,
|
||||
DATA_DESCRIPTOR_RECORD_LENGTH,
|
||||
DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH,
|
||||
DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH,
|
||||
EXTRAFIELD_TYPE_ZIP64,
|
||||
EXTRAFIELD_TYPE_AES,
|
||||
EXTRAFIELD_TYPE_NTFS,
|
||||
EXTRAFIELD_TYPE_NTFS_TAG1,
|
||||
EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
|
||||
EXTRAFIELD_TYPE_UNICODE_PATH,
|
||||
EXTRAFIELD_TYPE_UNICODE_COMMENT,
|
||||
EXTRAFIELD_TYPE_USDZ,
|
||||
EXTRAFIELD_TYPE_INFOZIP,
|
||||
EXTRAFIELD_TYPE_UNIX,
|
||||
END_OF_CENTRAL_DIR_LENGTH,
|
||||
ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH,
|
||||
ZIP64_END_OF_CENTRAL_DIR_LENGTH,
|
||||
ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH,
|
||||
BITFLAG_ENCRYPTED,
|
||||
BITFLAG_LEVEL,
|
||||
BITFLAG_LEVEL_MAX_MASK,
|
||||
BITFLAG_LEVEL_FAST_MASK,
|
||||
BITFLAG_LEVEL_SUPER_FAST_MASK,
|
||||
BITFLAG_DATA_DESCRIPTOR,
|
||||
BITFLAG_LANG_ENCODING_FLAG,
|
||||
FILE_ATTR_MSDOS_DIR_MASK,
|
||||
FILE_ATTR_MSDOS_READONLY_MASK,
|
||||
FILE_ATTR_MSDOS_HIDDEN_MASK,
|
||||
FILE_ATTR_MSDOS_SYSTEM_MASK,
|
||||
FILE_ATTR_MSDOS_ARCHIVE_MASK,
|
||||
FILE_ATTR_UNIX_TYPE_MASK,
|
||||
FILE_ATTR_UNIX_TYPE_DIR,
|
||||
FILE_ATTR_UNIX_EXECUTABLE_MASK,
|
||||
FILE_ATTR_UNIX_DEFAULT_MASK,
|
||||
FILE_ATTR_UNIX_SETUID_MASK,
|
||||
FILE_ATTR_UNIX_SETGID_MASK,
|
||||
FILE_ATTR_UNIX_STICKY_MASK,
|
||||
VERSION_DEFLATE,
|
||||
VERSION_ZIP64,
|
||||
VERSION_AES,
|
||||
HEADER_SIZE,
|
||||
HEADER_OFFSET_SIGNATURE,
|
||||
HEADER_OFFSET_COMPRESSED_SIZE,
|
||||
HEADER_OFFSET_UNCOMPRESSED_SIZE,
|
||||
DIRECTORY_SIGNATURE,
|
||||
MIN_DATE,
|
||||
MAX_DATE,
|
||||
UNDEFINED_VALUE,
|
||||
INFINITY_VALUE,
|
||||
UNDEFINED_TYPE,
|
||||
FUNCTION_TYPE,
|
||||
OBJECT_TYPE
|
||||
};
|
||||
+797
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global Blob, atob, btoa, XMLHttpRequest, URL, fetch, ReadableStream, WritableStream, FileReader, TransformStream, Response */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import {
|
||||
UNDEFINED_VALUE,
|
||||
INFINITY_VALUE,
|
||||
FUNCTION_TYPE,
|
||||
END_OF_CENTRAL_DIR_LENGTH
|
||||
} from "./constants.js";
|
||||
import { getConfiguration } from "./configuration.js";
|
||||
|
||||
const ERR_HTTP_STATUS = "HTTP error ";
|
||||
const ERR_HTTP_RANGE = "HTTP Range not supported";
|
||||
const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
|
||||
const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
|
||||
|
||||
const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
|
||||
const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
|
||||
const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
|
||||
const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
|
||||
const HTTP_HEADER_RANGE = "Range";
|
||||
const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
|
||||
const HTTP_METHOD_HEAD = "HEAD";
|
||||
const HTTP_METHOD_GET = "GET";
|
||||
const HTTP_RANGE_UNIT = "bytes";
|
||||
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
||||
const DEFAULT_BUFFER_SIZE = 256 * 1024;
|
||||
|
||||
const PROPERTY_NAME_WRITABLE = "writable";
|
||||
|
||||
class Stream {
|
||||
|
||||
constructor() {
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
class Reader extends Stream {
|
||||
|
||||
get readable() {
|
||||
const reader = this;
|
||||
const { chunkSize = DEFAULT_CHUNK_SIZE } = reader;
|
||||
const readable = new ReadableStream({
|
||||
start() {
|
||||
this.chunkOffset = 0;
|
||||
},
|
||||
async pull(controller) {
|
||||
const { offset = 0, size, diskNumberStart } = readable;
|
||||
const { chunkOffset } = this;
|
||||
const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
|
||||
const data = await readUint8Array(reader, offset + chunkOffset, dataSize, diskNumberStart);
|
||||
controller.enqueue(data);
|
||||
if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
|
||||
controller.close();
|
||||
} else {
|
||||
this.chunkOffset += chunkSize;
|
||||
}
|
||||
}
|
||||
});
|
||||
return readable;
|
||||
}
|
||||
}
|
||||
|
||||
class Writer extends Stream {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const writer = this;
|
||||
const writable = new WritableStream({
|
||||
write(chunk) {
|
||||
if (!writer.initialized) {
|
||||
throw new Error(ERR_WRITER_NOT_INITIALIZED);
|
||||
}
|
||||
return writer.writeUint8Array(chunk);
|
||||
}
|
||||
});
|
||||
Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
|
||||
get() {
|
||||
return writable;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
writeUint8Array() {
|
||||
// abstract
|
||||
}
|
||||
}
|
||||
|
||||
class Data64URIReader extends Reader {
|
||||
|
||||
constructor(dataURI) {
|
||||
super();
|
||||
let dataEnd = dataURI.length;
|
||||
while (dataURI.charAt(dataEnd - 1) == "=") {
|
||||
dataEnd--;
|
||||
}
|
||||
const dataStart = dataURI.indexOf(",") + 1;
|
||||
Object.assign(this, {
|
||||
dataURI,
|
||||
dataStart,
|
||||
size: Math.floor((dataEnd - dataStart) * 0.75)
|
||||
});
|
||||
}
|
||||
|
||||
readUint8Array(offset, length) {
|
||||
const {
|
||||
dataStart,
|
||||
dataURI
|
||||
} = this;
|
||||
const dataArray = new Uint8Array(length);
|
||||
const start = Math.floor(offset / 3) * 4;
|
||||
const bytes = atob(dataURI.substring(start + dataStart, Math.ceil((offset + length) / 3) * 4 + dataStart));
|
||||
const delta = offset - Math.floor(start / 4) * 3;
|
||||
let effectiveLength = 0;
|
||||
for (let indexByte = delta; indexByte < delta + length && indexByte < bytes.length; indexByte++) {
|
||||
dataArray[indexByte - delta] = bytes.charCodeAt(indexByte);
|
||||
effectiveLength++;
|
||||
}
|
||||
if (effectiveLength < dataArray.length) {
|
||||
return dataArray.subarray(0, effectiveLength);
|
||||
} else {
|
||||
return dataArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Data64URIWriter extends Writer {
|
||||
|
||||
constructor(contentType) {
|
||||
super();
|
||||
Object.assign(this, {
|
||||
data: "data:" + (contentType || "") + ";base64,",
|
||||
pending: []
|
||||
});
|
||||
}
|
||||
|
||||
writeUint8Array(array) {
|
||||
const writer = this;
|
||||
let indexArray = 0;
|
||||
let dataString = writer.pending;
|
||||
const delta = writer.pending.length;
|
||||
writer.pending = "";
|
||||
for (indexArray = 0; indexArray < (Math.floor((delta + array.length) / 3) * 3) - delta; indexArray++) {
|
||||
dataString += String.fromCharCode(array[indexArray]);
|
||||
}
|
||||
for (; indexArray < array.length; indexArray++) {
|
||||
writer.pending += String.fromCharCode(array[indexArray]);
|
||||
}
|
||||
if (dataString.length) {
|
||||
if (dataString.length > 2) {
|
||||
writer.data += btoa(dataString);
|
||||
} else {
|
||||
writer.pending += dataString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.data + btoa(this.pending);
|
||||
}
|
||||
}
|
||||
|
||||
class BlobReader extends Reader {
|
||||
|
||||
constructor(blob) {
|
||||
super();
|
||||
Object.assign(this, {
|
||||
blob,
|
||||
size: blob.size
|
||||
});
|
||||
}
|
||||
|
||||
async readUint8Array(offset, length) {
|
||||
const reader = this;
|
||||
const offsetEnd = offset + length;
|
||||
const blob = offset || offsetEnd < reader.size ? reader.blob.slice(offset, offsetEnd) : reader.blob;
|
||||
let arrayBuffer = await blob.arrayBuffer();
|
||||
if (arrayBuffer.byteLength > length) {
|
||||
arrayBuffer = arrayBuffer.slice(offset, offsetEnd);
|
||||
}
|
||||
return new Uint8Array(arrayBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
class BlobWriter extends Stream {
|
||||
|
||||
constructor(contentType) {
|
||||
super();
|
||||
const writer = this;
|
||||
const transformStream = new TransformStream();
|
||||
const headers = [];
|
||||
if (contentType) {
|
||||
headers.push([HTTP_HEADER_CONTENT_TYPE, contentType]);
|
||||
}
|
||||
Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
|
||||
get() {
|
||||
return transformStream.writable;
|
||||
}
|
||||
});
|
||||
writer.blob = new Response(transformStream.readable, { headers }).blob();
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.blob;
|
||||
}
|
||||
}
|
||||
|
||||
class TextReader extends BlobReader {
|
||||
|
||||
constructor(text) {
|
||||
super(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN }));
|
||||
}
|
||||
}
|
||||
|
||||
class TextWriter extends BlobWriter {
|
||||
|
||||
constructor(encoding) {
|
||||
super(encoding);
|
||||
Object.assign(this, {
|
||||
encoding,
|
||||
utf8: !encoding || encoding.toLowerCase() == "utf-8"
|
||||
});
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const {
|
||||
encoding,
|
||||
utf8
|
||||
} = this;
|
||||
const blob = await super.getData();
|
||||
if (blob.text && utf8) {
|
||||
return blob.text();
|
||||
} else {
|
||||
const reader = new FileReader();
|
||||
return new Promise((resolve, reject) => {
|
||||
Object.assign(reader, {
|
||||
onload: ({ target }) => resolve(target.result),
|
||||
onerror: () => reject(reader.error)
|
||||
});
|
||||
reader.readAsText(blob, encoding);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FetchReader extends Reader {
|
||||
|
||||
constructor(url, options) {
|
||||
super();
|
||||
createHttpReader(this, url, options);
|
||||
}
|
||||
|
||||
async init() {
|
||||
await initHttpReader(this, sendFetchRequest, getFetchRequestData);
|
||||
super.init();
|
||||
}
|
||||
|
||||
readUint8Array(index, length) {
|
||||
return readUint8ArrayHttpReader(this, index, length, sendFetchRequest, getFetchRequestData);
|
||||
}
|
||||
}
|
||||
|
||||
class XHRReader extends Reader {
|
||||
|
||||
constructor(url, options) {
|
||||
super();
|
||||
createHttpReader(this, url, options);
|
||||
}
|
||||
|
||||
async init() {
|
||||
await initHttpReader(this, sendXMLHttpRequest, getXMLHttpRequestData);
|
||||
super.init();
|
||||
}
|
||||
|
||||
readUint8Array(index, length) {
|
||||
return readUint8ArrayHttpReader(this, index, length, sendXMLHttpRequest, getXMLHttpRequestData);
|
||||
}
|
||||
}
|
||||
|
||||
function createHttpReader(httpReader, url, options) {
|
||||
const {
|
||||
preventHeadRequest,
|
||||
useRangeHeader,
|
||||
forceRangeRequests,
|
||||
combineSizeEocd
|
||||
} = options;
|
||||
options = Object.assign({}, options);
|
||||
delete options.preventHeadRequest;
|
||||
delete options.useRangeHeader;
|
||||
delete options.forceRangeRequests;
|
||||
delete options.combineSizeEocd;
|
||||
delete options.useXHR;
|
||||
Object.assign(httpReader, {
|
||||
url,
|
||||
options,
|
||||
preventHeadRequest,
|
||||
useRangeHeader,
|
||||
forceRangeRequests,
|
||||
combineSizeEocd
|
||||
});
|
||||
}
|
||||
|
||||
async function initHttpReader(httpReader, sendRequest, getRequestData) {
|
||||
const {
|
||||
url,
|
||||
preventHeadRequest,
|
||||
useRangeHeader,
|
||||
forceRangeRequests,
|
||||
combineSizeEocd
|
||||
} = httpReader;
|
||||
if (isHttpFamily(url) && (useRangeHeader || forceRangeRequests) && (typeof preventHeadRequest == "undefined" || preventHeadRequest)) {
|
||||
const response = await sendRequest(HTTP_METHOD_GET, httpReader, getRangeHeaders(httpReader, combineSizeEocd ? -END_OF_CENTRAL_DIR_LENGTH : undefined));
|
||||
const acceptRanges = response.headers.get(HTTP_HEADER_ACCEPT_RANGES);
|
||||
if (!forceRangeRequests && (!acceptRanges || acceptRanges.toLowerCase() != HTTP_RANGE_UNIT)) {
|
||||
throw new Error(ERR_HTTP_RANGE);
|
||||
} else {
|
||||
if (combineSizeEocd) {
|
||||
httpReader.eocdCache = new Uint8Array(await response.arrayBuffer());
|
||||
}
|
||||
let contentSize;
|
||||
const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
|
||||
if (contentRangeHeader) {
|
||||
const splitHeader = contentRangeHeader.trim().split(/\s*\/\s*/);
|
||||
if (splitHeader.length) {
|
||||
const headerValue = splitHeader[1];
|
||||
if (headerValue && headerValue != "*") {
|
||||
contentSize = Number(headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contentSize === UNDEFINED_VALUE) {
|
||||
await getContentLength(httpReader, sendRequest, getRequestData);
|
||||
} else {
|
||||
httpReader.size = contentSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await getContentLength(httpReader, sendRequest, getRequestData);
|
||||
}
|
||||
}
|
||||
|
||||
async function readUint8ArrayHttpReader(httpReader, index, length, sendRequest, getRequestData) {
|
||||
const {
|
||||
useRangeHeader,
|
||||
forceRangeRequests,
|
||||
eocdCache,
|
||||
size,
|
||||
options
|
||||
} = httpReader;
|
||||
if (useRangeHeader || forceRangeRequests) {
|
||||
if (eocdCache && index == size - END_OF_CENTRAL_DIR_LENGTH && length == END_OF_CENTRAL_DIR_LENGTH) {
|
||||
return eocdCache;
|
||||
}
|
||||
if (index >= size || length === 0) {
|
||||
return new Uint8Array();
|
||||
} else {
|
||||
if (index + length > size) {
|
||||
length = size - index;
|
||||
}
|
||||
const response = await sendRequest(HTTP_METHOD_GET, httpReader, getRangeHeaders(httpReader, index, length));
|
||||
if (response.status != 206) {
|
||||
throw new Error(ERR_HTTP_RANGE);
|
||||
}
|
||||
return new Uint8Array(await response.arrayBuffer());
|
||||
}
|
||||
} else {
|
||||
const { data } = httpReader;
|
||||
if (!data) {
|
||||
await getRequestData(httpReader, options);
|
||||
}
|
||||
return new Uint8Array(httpReader.data.subarray(index, index + length));
|
||||
}
|
||||
}
|
||||
|
||||
function getRangeHeaders(httpReader, index = 0, length = 1) {
|
||||
return Object.assign({}, getHeaders(httpReader), { [HTTP_HEADER_RANGE]: HTTP_RANGE_UNIT + "=" + (index < 0 ? index : index + "-" + (index + length - 1)) });
|
||||
}
|
||||
|
||||
function getHeaders({ options }) {
|
||||
const { headers } = options;
|
||||
if (headers) {
|
||||
if (Symbol.iterator in headers) {
|
||||
return Object.fromEntries(headers);
|
||||
} else {
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getFetchRequestData(httpReader) {
|
||||
await getRequestData(httpReader, sendFetchRequest);
|
||||
}
|
||||
|
||||
async function getXMLHttpRequestData(httpReader) {
|
||||
await getRequestData(httpReader, sendXMLHttpRequest);
|
||||
}
|
||||
|
||||
async function getRequestData(httpReader, sendRequest) {
|
||||
const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
|
||||
httpReader.data = new Uint8Array(await response.arrayBuffer());
|
||||
if (!httpReader.size) {
|
||||
httpReader.size = httpReader.data.length;
|
||||
}
|
||||
}
|
||||
|
||||
async function getContentLength(httpReader, sendRequest, getRequestData) {
|
||||
if (httpReader.preventHeadRequest) {
|
||||
await getRequestData(httpReader, httpReader.options);
|
||||
} else {
|
||||
const response = await sendRequest(HTTP_METHOD_HEAD, httpReader, getHeaders(httpReader));
|
||||
const contentLength = response.headers.get(HTTP_HEADER_CONTENT_LENGTH);
|
||||
if (contentLength) {
|
||||
httpReader.size = Number(contentLength);
|
||||
} else {
|
||||
await getRequestData(httpReader, httpReader.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function sendFetchRequest(method, { options, url }, headers) {
|
||||
const response = await fetch(url, Object.assign({}, options, { method, headers }));
|
||||
if (response.status < 400) {
|
||||
return response;
|
||||
} else {
|
||||
throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
|
||||
}
|
||||
}
|
||||
|
||||
function sendXMLHttpRequest(method, { url }, headers) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = new XMLHttpRequest();
|
||||
request.addEventListener("load", () => {
|
||||
if (request.status < 400) {
|
||||
const headers = [];
|
||||
request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
|
||||
const splitHeader = header.trim().split(/\s*:\s*/);
|
||||
splitHeader[0] = splitHeader[0].trim().replace(/^[a-z]|-[a-z]/g, value => value.toUpperCase());
|
||||
headers.push(splitHeader);
|
||||
});
|
||||
resolve({
|
||||
status: request.status,
|
||||
arrayBuffer: () => request.response,
|
||||
headers: new Map(headers)
|
||||
});
|
||||
} else {
|
||||
reject(request.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (request.statusText || request.status)));
|
||||
}
|
||||
}, false);
|
||||
request.addEventListener("error", event => reject(event.detail ? event.detail.error : new Error("Network error")), false);
|
||||
request.open(method, url);
|
||||
if (headers) {
|
||||
for (const entry of Object.entries(headers)) {
|
||||
request.setRequestHeader(entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
request.responseType = "arraybuffer";
|
||||
request.send();
|
||||
});
|
||||
}
|
||||
|
||||
class HttpReader extends Reader {
|
||||
|
||||
constructor(url, options = {}) {
|
||||
super();
|
||||
Object.assign(this, {
|
||||
url,
|
||||
reader: options.useXHR ? new XHRReader(url, options) : new FetchReader(url, options)
|
||||
});
|
||||
}
|
||||
|
||||
set size(value) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.reader.size;
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.reader.init();
|
||||
super.init();
|
||||
}
|
||||
|
||||
readUint8Array(index, length) {
|
||||
return this.reader.readUint8Array(index, length);
|
||||
}
|
||||
}
|
||||
|
||||
class HttpRangeReader extends HttpReader {
|
||||
|
||||
constructor(url, options = {}) {
|
||||
options.useRangeHeader = true;
|
||||
super(url, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Uint8ArrayReader extends Reader {
|
||||
|
||||
constructor(array) {
|
||||
super();
|
||||
array = new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
||||
Object.assign(this, {
|
||||
array,
|
||||
size: array.length
|
||||
});
|
||||
}
|
||||
|
||||
readUint8Array(index, length) {
|
||||
return this.array.slice(index, index + length);
|
||||
}
|
||||
}
|
||||
|
||||
class Uint8ArrayWriter extends Writer {
|
||||
|
||||
constructor(defaultBufferSize) {
|
||||
super();
|
||||
this.defaultBufferSize = defaultBufferSize || DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
init(initSize = 0) {
|
||||
Object.assign(this, {
|
||||
offset: 0,
|
||||
array: new Uint8Array(initSize > 0 ? initSize : this.defaultBufferSize)
|
||||
});
|
||||
super.init();
|
||||
}
|
||||
|
||||
writeUint8Array(array) {
|
||||
const writer = this;
|
||||
const requiredLength = writer.offset + array.length;
|
||||
if (requiredLength > writer.array.length) {
|
||||
let newLength = writer.array.length ? writer.array.length * 2 : writer.defaultBufferSize;
|
||||
while (newLength < requiredLength) {
|
||||
newLength *= 2;
|
||||
}
|
||||
const previousArray = writer.array;
|
||||
writer.array = new Uint8Array(newLength);
|
||||
writer.array.set(previousArray);
|
||||
}
|
||||
writer.array.set(array, writer.offset);
|
||||
writer.offset += array.length;
|
||||
}
|
||||
|
||||
getData() {
|
||||
if (this.offset === this.array.length) {
|
||||
return this.array;
|
||||
} else {
|
||||
return this.array.slice(0, this.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SplitDataReader extends Reader {
|
||||
|
||||
constructor(readers) {
|
||||
super();
|
||||
this.readers = readers;
|
||||
}
|
||||
|
||||
async init() {
|
||||
const reader = this;
|
||||
const { readers } = reader;
|
||||
reader.lastDiskNumber = 0;
|
||||
reader.lastDiskOffset = 0;
|
||||
await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
|
||||
await diskReader.init();
|
||||
if (indexDiskReader != readers.length - 1) {
|
||||
reader.lastDiskOffset += diskReader.size;
|
||||
}
|
||||
reader.size += diskReader.size;
|
||||
}));
|
||||
super.init();
|
||||
}
|
||||
|
||||
async readUint8Array(offset, length, diskNumber = 0) {
|
||||
const reader = this;
|
||||
const { readers } = this;
|
||||
let result;
|
||||
let currentDiskNumber = diskNumber;
|
||||
if (currentDiskNumber == -1) {
|
||||
currentDiskNumber = readers.length - 1;
|
||||
}
|
||||
let currentReaderOffset = offset;
|
||||
while (readers[currentDiskNumber] && currentReaderOffset >= readers[currentDiskNumber].size) {
|
||||
currentReaderOffset -= readers[currentDiskNumber].size;
|
||||
currentDiskNumber++;
|
||||
}
|
||||
const currentReader = readers[currentDiskNumber];
|
||||
if (currentReader) {
|
||||
const currentReaderSize = currentReader.size;
|
||||
if (currentReaderOffset + length <= currentReaderSize) {
|
||||
result = await readUint8Array(currentReader, currentReaderOffset, length);
|
||||
} else {
|
||||
const chunkLength = currentReaderSize - currentReaderOffset;
|
||||
result = new Uint8Array(length);
|
||||
const firstPart = await readUint8Array(currentReader, currentReaderOffset, chunkLength);
|
||||
result.set(firstPart, 0);
|
||||
const secondPart = await reader.readUint8Array(offset + chunkLength, length - chunkLength, diskNumber);
|
||||
result.set(secondPart, chunkLength);
|
||||
if (firstPart.length + secondPart.length < length) {
|
||||
result = result.subarray(0, firstPart.length + secondPart.length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = new Uint8Array();
|
||||
}
|
||||
reader.lastDiskNumber = Math.max(currentDiskNumber, reader.lastDiskNumber);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class SplitDataWriter extends Stream {
|
||||
|
||||
constructor(writerGenerator, maxSize = 4294967295) {
|
||||
super();
|
||||
const writer = this;
|
||||
Object.assign(writer, {
|
||||
diskNumber: 0,
|
||||
diskOffset: 0,
|
||||
size: 0,
|
||||
maxSize,
|
||||
availableSize: maxSize
|
||||
});
|
||||
let diskSourceWriter, diskWritable, diskWriter;
|
||||
const writable = new WritableStream({
|
||||
async write(chunk) {
|
||||
const { availableSize } = writer;
|
||||
if (!diskWriter) {
|
||||
const { value, done } = await writerGenerator.next();
|
||||
if (done && !value) {
|
||||
throw new Error(ERR_ITERATOR_COMPLETED_TOO_SOON);
|
||||
} else {
|
||||
diskSourceWriter = value;
|
||||
diskSourceWriter.size = 0;
|
||||
if (diskSourceWriter.maxSize) {
|
||||
writer.maxSize = diskSourceWriter.maxSize;
|
||||
}
|
||||
writer.availableSize = writer.maxSize;
|
||||
await initStream(diskSourceWriter);
|
||||
diskWritable = value.writable;
|
||||
diskWriter = diskWritable.getWriter();
|
||||
}
|
||||
await this.write(chunk);
|
||||
} else if (chunk.length >= availableSize) {
|
||||
await writeChunk(chunk.subarray(0, availableSize));
|
||||
await closeDisk();
|
||||
writer.diskOffset += diskSourceWriter.size;
|
||||
writer.diskNumber++;
|
||||
diskWriter = null;
|
||||
await this.write(chunk.subarray(availableSize));
|
||||
} else {
|
||||
await writeChunk(chunk);
|
||||
}
|
||||
},
|
||||
async close() {
|
||||
await diskWriter.ready;
|
||||
await closeDisk();
|
||||
}
|
||||
});
|
||||
Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
|
||||
get() {
|
||||
return writable;
|
||||
}
|
||||
});
|
||||
|
||||
async function writeChunk(chunk) {
|
||||
const chunkLength = chunk.length;
|
||||
if (chunkLength) {
|
||||
await diskWriter.ready;
|
||||
await diskWriter.write(chunk);
|
||||
diskSourceWriter.size += chunkLength;
|
||||
writer.size += chunkLength;
|
||||
writer.availableSize -= chunkLength;
|
||||
}
|
||||
}
|
||||
|
||||
async function closeDisk() {
|
||||
await diskWriter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GenericReader {
|
||||
|
||||
constructor(reader) {
|
||||
if (Array.isArray(reader)) {
|
||||
reader = new SplitDataReader(reader);
|
||||
}
|
||||
if (reader instanceof ReadableStream) {
|
||||
reader = {
|
||||
readable: reader
|
||||
};
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
class GenericWriter {
|
||||
|
||||
constructor(writer) {
|
||||
if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
|
||||
writer = new SplitDataWriter(writer);
|
||||
}
|
||||
if (writer instanceof WritableStream) {
|
||||
writer = {
|
||||
writable: writer
|
||||
};
|
||||
}
|
||||
if (writer.size === UNDEFINED_VALUE) {
|
||||
writer.size = 0;
|
||||
}
|
||||
if (!(writer instanceof SplitDataWriter)) {
|
||||
Object.assign(writer, {
|
||||
diskNumber: 0,
|
||||
diskOffset: 0,
|
||||
availableSize: INFINITY_VALUE,
|
||||
maxSize: INFINITY_VALUE
|
||||
});
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
|
||||
function isHttpFamily(url) {
|
||||
const { baseURI } = getConfiguration();
|
||||
const { protocol } = new URL(url, baseURI);
|
||||
return protocol == "http:" || protocol == "https:";
|
||||
}
|
||||
|
||||
async function initStream(stream, initSize) {
|
||||
if (stream.init && !stream.initialized) {
|
||||
await stream.init(initSize);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function readUint8Array(reader, offset, size, diskNumber) {
|
||||
return reader.readUint8Array(offset, size, diskNumber);
|
||||
}
|
||||
|
||||
export {
|
||||
initStream,
|
||||
GenericReader,
|
||||
GenericWriter,
|
||||
readUint8Array,
|
||||
Reader,
|
||||
Writer,
|
||||
TextReader,
|
||||
TextWriter,
|
||||
Data64URIReader,
|
||||
Data64URIWriter,
|
||||
BlobReader,
|
||||
BlobWriter,
|
||||
Uint8ArrayReader,
|
||||
Uint8ArrayWriter,
|
||||
HttpReader,
|
||||
HttpRangeReader,
|
||||
SplitDataReader,
|
||||
SplitDataWriter,
|
||||
ERR_HTTP_RANGE,
|
||||
ERR_ITERATOR_COMPLETED_TOO_SOON,
|
||||
ERR_WRITER_NOT_INITIALIZED
|
||||
};
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const OPTION_FILENAME_ENCODING = "filenameEncoding";
|
||||
const OPTION_COMMENT_ENCODING = "commentEncoding";
|
||||
const OPTION_DECODE_TEXT = "decodeText";
|
||||
const OPTION_EXTRACT_PREPENDED_DATA = "extractPrependedData";
|
||||
const OPTION_EXTRACT_APPENDED_DATA = "extractAppendedData";
|
||||
const OPTION_PASSWORD = "password";
|
||||
const OPTION_RAW_PASSWORD = "rawPassword";
|
||||
const OPTION_PASS_THROUGH = "passThrough";
|
||||
const OPTION_SIGNAL = "signal";
|
||||
const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
|
||||
const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
|
||||
const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
|
||||
const OPTION_CHECK_SIGNATURE = "checkSignature";
|
||||
const OPTION_USE_WEB_WORKERS = "useWebWorkers";
|
||||
const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
|
||||
const OPTION_TRANSFER_STREAMS = "transferStreams";
|
||||
const OPTION_PREVENT_CLOSE = "preventClose";
|
||||
const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
|
||||
const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
|
||||
const OPTION_KEEP_ORDER = "keepOrder";
|
||||
const OPTION_LEVEL = "level";
|
||||
const OPTION_BUFFERED_WRITE = "bufferedWrite";
|
||||
const OPTION_CREATE_TEMP_STREAM = "createTempStream";
|
||||
const OPTION_DATA_DESCRIPTOR_SIGNATURE = "dataDescriptorSignature";
|
||||
const OPTION_USE_UNICODE_FILE_NAMES = "useUnicodeFileNames";
|
||||
const OPTION_DATA_DESCRIPTOR = "dataDescriptor";
|
||||
const OPTION_SUPPORT_ZIP64_SPLIT_FILE = "supportZip64SplitFile";
|
||||
const OPTION_ENCODE_TEXT = "encodeText";
|
||||
const OPTION_OFFSET = "offset";
|
||||
const OPTION_USDZ = "usdz";
|
||||
const OPTION_UNIX_EXTRA_FIELD_TYPE = "unixExtraFieldType";
|
||||
|
||||
export {
|
||||
OPTION_FILENAME_ENCODING,
|
||||
OPTION_COMMENT_ENCODING,
|
||||
OPTION_DECODE_TEXT,
|
||||
OPTION_EXTRACT_PREPENDED_DATA,
|
||||
OPTION_EXTRACT_APPENDED_DATA,
|
||||
OPTION_PASSWORD,
|
||||
OPTION_RAW_PASSWORD,
|
||||
OPTION_PASS_THROUGH,
|
||||
OPTION_SIGNAL,
|
||||
OPTION_CHECK_PASSWORD_ONLY,
|
||||
OPTION_CHECK_OVERLAPPING_ENTRY_ONLY,
|
||||
OPTION_CHECK_OVERLAPPING_ENTRY,
|
||||
OPTION_CHECK_SIGNATURE,
|
||||
OPTION_USE_WEB_WORKERS,
|
||||
OPTION_USE_COMPRESSION_STREAM,
|
||||
OPTION_TRANSFER_STREAMS,
|
||||
OPTION_PREVENT_CLOSE,
|
||||
OPTION_ENCRYPTION_STRENGTH,
|
||||
OPTION_EXTENDED_TIMESTAMP,
|
||||
OPTION_KEEP_ORDER,
|
||||
OPTION_LEVEL,
|
||||
OPTION_BUFFERED_WRITE,
|
||||
OPTION_CREATE_TEMP_STREAM,
|
||||
OPTION_DATA_DESCRIPTOR_SIGNATURE,
|
||||
OPTION_USE_UNICODE_FILE_NAMES,
|
||||
OPTION_DATA_DESCRIPTOR,
|
||||
OPTION_SUPPORT_ZIP64_SPLIT_FILE,
|
||||
OPTION_ENCODE_TEXT,
|
||||
OPTION_OFFSET,
|
||||
OPTION_USDZ,
|
||||
OPTION_UNIX_EXTRA_FIELD_TYPE
|
||||
};
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global crypto, TransformStream */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import { UNDEFINED_VALUE, UNDEFINED_TYPE, FUNCTION_TYPE } from "../constants.js";
|
||||
import { encodeText } from "./../util/encode-text.js";
|
||||
import {
|
||||
cipher,
|
||||
codec,
|
||||
misc,
|
||||
mode
|
||||
} from "./codecs/sjcl.js";
|
||||
import {
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_ABORT_CHECK_PASSWORD,
|
||||
getRandomValues
|
||||
} from "./common-crypto.js";
|
||||
|
||||
const BLOCK_LENGTH = 16;
|
||||
const RAW_FORMAT = "raw";
|
||||
const PBKDF2_ALGORITHM = { name: "PBKDF2" };
|
||||
const HASH_ALGORITHM = { name: "HMAC" };
|
||||
const HASH_FUNCTION = "SHA-1";
|
||||
const BASE_KEY_ALGORITHM = Object.assign({ hash: HASH_ALGORITHM }, PBKDF2_ALGORITHM);
|
||||
const DERIVED_BITS_ALGORITHM = Object.assign({ iterations: 1000, hash: { name: HASH_FUNCTION } }, PBKDF2_ALGORITHM);
|
||||
const DERIVED_BITS_USAGE = ["deriveBits"];
|
||||
const SALT_LENGTH = [8, 12, 16];
|
||||
const KEY_LENGTH = [16, 24, 32];
|
||||
const SIGNATURE_LENGTH = 10;
|
||||
const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0];
|
||||
// deno-lint-ignore valid-typeof
|
||||
const CRYPTO_API_SUPPORTED = typeof crypto != UNDEFINED_TYPE;
|
||||
const subtle = CRYPTO_API_SUPPORTED && crypto.subtle;
|
||||
const SUBTLE_API_SUPPORTED = CRYPTO_API_SUPPORTED && typeof subtle != UNDEFINED_TYPE;
|
||||
const codecBytes = codec.bytes;
|
||||
const Aes = cipher.aes;
|
||||
const CtrGladman = mode.ctrGladman;
|
||||
const HmacSha1 = misc.hmacSha1;
|
||||
|
||||
let IMPORT_KEY_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.importKey == FUNCTION_TYPE;
|
||||
let DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.deriveBits == FUNCTION_TYPE;
|
||||
|
||||
class AESDecryptionStream extends TransformStream {
|
||||
|
||||
constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
|
||||
super({
|
||||
start() {
|
||||
Object.assign(this, {
|
||||
ready: new Promise(resolve => this.resolveReady = resolve),
|
||||
password: encodePassword(password, rawPassword),
|
||||
signed,
|
||||
strength: encryptionStrength - 1,
|
||||
pending: new Uint8Array()
|
||||
});
|
||||
},
|
||||
async transform(chunk, controller) {
|
||||
const aesCrypto = this;
|
||||
const {
|
||||
password,
|
||||
strength,
|
||||
resolveReady,
|
||||
ready
|
||||
} = aesCrypto;
|
||||
if (password) {
|
||||
await createDecryptionKeys(aesCrypto, strength, password, subarray(chunk, 0, SALT_LENGTH[strength] + 2));
|
||||
chunk = subarray(chunk, SALT_LENGTH[strength] + 2);
|
||||
if (checkPasswordOnly) {
|
||||
controller.error(new Error(ERR_ABORT_CHECK_PASSWORD));
|
||||
} else {
|
||||
resolveReady();
|
||||
}
|
||||
} else {
|
||||
await ready;
|
||||
}
|
||||
const output = new Uint8Array(chunk.length - SIGNATURE_LENGTH - ((chunk.length - SIGNATURE_LENGTH) % BLOCK_LENGTH));
|
||||
controller.enqueue(append(aesCrypto, chunk, output, 0, SIGNATURE_LENGTH, true));
|
||||
},
|
||||
async flush(controller) {
|
||||
const {
|
||||
signed,
|
||||
ctr,
|
||||
hmac,
|
||||
pending,
|
||||
ready
|
||||
} = this;
|
||||
if (hmac && ctr) {
|
||||
await ready;
|
||||
const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
|
||||
const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
|
||||
let decryptedChunkArray = new Uint8Array();
|
||||
if (chunkToDecrypt.length) {
|
||||
const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
|
||||
hmac.update(encryptedChunk);
|
||||
const decryptedChunk = ctr.update(encryptedChunk);
|
||||
decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
|
||||
}
|
||||
if (signed) {
|
||||
const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
|
||||
for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
|
||||
if (signature[indexSignature] != originalSignature[indexSignature]) {
|
||||
throw new Error(ERR_INVALID_SIGNATURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.enqueue(decryptedChunkArray);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AESEncryptionStream extends TransformStream {
|
||||
|
||||
constructor({ password, rawPassword, encryptionStrength }) {
|
||||
// deno-lint-ignore prefer-const
|
||||
let stream;
|
||||
super({
|
||||
start() {
|
||||
Object.assign(this, {
|
||||
ready: new Promise(resolve => this.resolveReady = resolve),
|
||||
password: encodePassword(password, rawPassword),
|
||||
strength: encryptionStrength - 1,
|
||||
pending: new Uint8Array()
|
||||
});
|
||||
},
|
||||
async transform(chunk, controller) {
|
||||
const aesCrypto = this;
|
||||
const {
|
||||
password,
|
||||
strength,
|
||||
resolveReady,
|
||||
ready
|
||||
} = aesCrypto;
|
||||
let preamble = new Uint8Array();
|
||||
if (password) {
|
||||
preamble = await createEncryptionKeys(aesCrypto, strength, password);
|
||||
resolveReady();
|
||||
} else {
|
||||
await ready;
|
||||
}
|
||||
const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
|
||||
output.set(preamble, 0);
|
||||
controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0));
|
||||
},
|
||||
async flush(controller) {
|
||||
const {
|
||||
ctr,
|
||||
hmac,
|
||||
pending,
|
||||
ready
|
||||
} = this;
|
||||
if (hmac && ctr) {
|
||||
await ready;
|
||||
let encryptedChunkArray = new Uint8Array();
|
||||
if (pending.length) {
|
||||
const encryptedChunk = ctr.update(toBits(codecBytes, pending));
|
||||
hmac.update(encryptedChunk);
|
||||
encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
|
||||
}
|
||||
stream.signature = fromBits(codecBytes, hmac.digest()).slice(0, SIGNATURE_LENGTH);
|
||||
controller.enqueue(concat(encryptedChunkArray, stream.signature));
|
||||
}
|
||||
}
|
||||
});
|
||||
stream = this;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
AESDecryptionStream,
|
||||
AESEncryptionStream,
|
||||
ERR_INVALID_PASSWORD
|
||||
};
|
||||
|
||||
function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
|
||||
const {
|
||||
ctr,
|
||||
hmac,
|
||||
pending
|
||||
} = aesCrypto;
|
||||
const inputLength = input.length - paddingEnd;
|
||||
if (pending.length) {
|
||||
input = concat(pending, input);
|
||||
output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
|
||||
}
|
||||
let offset;
|
||||
for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
|
||||
const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
|
||||
if (verifySignature) {
|
||||
hmac.update(inputChunk);
|
||||
}
|
||||
const outputChunk = ctr.update(inputChunk);
|
||||
if (!verifySignature) {
|
||||
hmac.update(outputChunk);
|
||||
}
|
||||
output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
|
||||
}
|
||||
aesCrypto.pending = subarray(input, offset);
|
||||
return output;
|
||||
}
|
||||
|
||||
async function createDecryptionKeys(decrypt, strength, password, preamble) {
|
||||
const passwordVerificationKey = await createKeys(decrypt, strength, password, subarray(preamble, 0, SALT_LENGTH[strength]));
|
||||
const passwordVerification = subarray(preamble, SALT_LENGTH[strength]);
|
||||
if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) {
|
||||
throw new Error(ERR_INVALID_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
async function createEncryptionKeys(encrypt, strength, password) {
|
||||
const salt = getRandomValues(new Uint8Array(SALT_LENGTH[strength]));
|
||||
const passwordVerification = await createKeys(encrypt, strength, password, salt);
|
||||
return concat(salt, passwordVerification);
|
||||
}
|
||||
|
||||
async function createKeys(aesCrypto, strength, password, salt) {
|
||||
aesCrypto.password = null;
|
||||
const baseKey = await importKey(RAW_FORMAT, password, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE);
|
||||
const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), baseKey, 8 * ((KEY_LENGTH[strength] * 2) + 2));
|
||||
const compositeKey = new Uint8Array(derivedBits);
|
||||
const key = toBits(codecBytes, subarray(compositeKey, 0, KEY_LENGTH[strength]));
|
||||
const authentication = toBits(codecBytes, subarray(compositeKey, KEY_LENGTH[strength], KEY_LENGTH[strength] * 2));
|
||||
const passwordVerification = subarray(compositeKey, KEY_LENGTH[strength] * 2);
|
||||
Object.assign(aesCrypto, {
|
||||
keys: {
|
||||
key,
|
||||
authentication,
|
||||
passwordVerification
|
||||
},
|
||||
ctr: new CtrGladman(new Aes(key), Array.from(COUNTER_DEFAULT_VALUE)),
|
||||
hmac: new HmacSha1(authentication)
|
||||
});
|
||||
return passwordVerification;
|
||||
}
|
||||
|
||||
async function importKey(format, password, algorithm, extractable, keyUsages) {
|
||||
if (IMPORT_KEY_SUPPORTED) {
|
||||
try {
|
||||
return await subtle.importKey(format, password, algorithm, extractable, keyUsages);
|
||||
} catch {
|
||||
IMPORT_KEY_SUPPORTED = false;
|
||||
return misc.importKey(password);
|
||||
}
|
||||
} else {
|
||||
return misc.importKey(password);
|
||||
}
|
||||
}
|
||||
|
||||
async function deriveBits(algorithm, baseKey, length) {
|
||||
if (DERIVE_BITS_SUPPORTED) {
|
||||
try {
|
||||
return await subtle.deriveBits(algorithm, baseKey, length);
|
||||
} catch {
|
||||
DERIVE_BITS_SUPPORTED = false;
|
||||
return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
|
||||
}
|
||||
} else {
|
||||
return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
|
||||
}
|
||||
}
|
||||
|
||||
function encodePassword(password, rawPassword) {
|
||||
if (rawPassword === UNDEFINED_VALUE) {
|
||||
return encodeText(password);
|
||||
} else {
|
||||
return rawPassword;
|
||||
}
|
||||
}
|
||||
|
||||
function concat(leftArray, rightArray) {
|
||||
let array = leftArray;
|
||||
if (leftArray.length + rightArray.length) {
|
||||
array = new Uint8Array(leftArray.length + rightArray.length);
|
||||
array.set(leftArray, 0);
|
||||
array.set(rightArray, leftArray.length);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
function expand(inputArray, length) {
|
||||
if (length && length > inputArray.length) {
|
||||
const array = inputArray;
|
||||
inputArray = new Uint8Array(length);
|
||||
inputArray.set(array, 0);
|
||||
}
|
||||
return inputArray;
|
||||
}
|
||||
|
||||
function subarray(array, begin, end) {
|
||||
return array.subarray(begin, end);
|
||||
}
|
||||
|
||||
function fromBits(codecBytes, chunk) {
|
||||
return codecBytes.fromBits(chunk);
|
||||
}
|
||||
function toBits(codecBytes, chunk) {
|
||||
return codecBytes.toBits(chunk);
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
|
||||
* JZlib is based on zlib-1.1.3, so all credit should go authors
|
||||
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
* and contributors of zlib.
|
||||
*/
|
||||
|
||||
/* global TransformStream */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import { UNDEFINED_VALUE } from "../constants.js";
|
||||
import {
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_ABORT_CHECK_PASSWORD,
|
||||
InflateStream,
|
||||
DeflateStream
|
||||
} from "./zip-entry-stream.js";
|
||||
|
||||
const MESSAGE_EVENT_TYPE = "message";
|
||||
const MESSAGE_START = "start";
|
||||
const MESSAGE_PULL = "pull";
|
||||
const MESSAGE_DATA = "data";
|
||||
const MESSAGE_ACK_DATA = "ack";
|
||||
const MESSAGE_CLOSE = "close";
|
||||
const CODEC_DEFLATE = "deflate";
|
||||
const CODEC_INFLATE = "inflate";
|
||||
|
||||
export {
|
||||
CODEC_DEFLATE,
|
||||
CODEC_INFLATE,
|
||||
MESSAGE_EVENT_TYPE,
|
||||
MESSAGE_START,
|
||||
MESSAGE_PULL,
|
||||
MESSAGE_DATA,
|
||||
MESSAGE_ACK_DATA,
|
||||
MESSAGE_CLOSE,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_ABORT_CHECK_PASSWORD,
|
||||
CodecStream,
|
||||
ChunkStream
|
||||
};
|
||||
|
||||
class CodecStream extends TransformStream {
|
||||
|
||||
constructor(options, config) {
|
||||
super({});
|
||||
const codec = this;
|
||||
const { codecType } = options;
|
||||
let Stream;
|
||||
if (codecType.startsWith(CODEC_DEFLATE)) {
|
||||
Stream = DeflateStream;
|
||||
} else if (codecType.startsWith(CODEC_INFLATE)) {
|
||||
Stream = InflateStream;
|
||||
}
|
||||
codec.outputSize = 0;
|
||||
let inputSize = 0;
|
||||
const stream = new Stream(options, config);
|
||||
const readable = super.readable;
|
||||
const inputSizeStream = new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
if (chunk && chunk.length) {
|
||||
inputSize += chunk.length;
|
||||
controller.enqueue(chunk);
|
||||
}
|
||||
},
|
||||
flush() {
|
||||
Object.assign(codec, {
|
||||
inputSize
|
||||
});
|
||||
}
|
||||
});
|
||||
const outputSizeStream = new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
if (chunk && chunk.length) {
|
||||
controller.enqueue(chunk);
|
||||
codec.outputSize += chunk.length;
|
||||
if (options.outputSize !== UNDEFINED_VALUE && codec.outputSize > options.outputSize) {
|
||||
throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
||||
}
|
||||
}
|
||||
},
|
||||
flush() {
|
||||
const { signature } = stream;
|
||||
Object.assign(codec, {
|
||||
signature,
|
||||
inputSize
|
||||
});
|
||||
}
|
||||
});
|
||||
Object.defineProperty(codec, "readable", {
|
||||
get() {
|
||||
return readable.pipeThrough(inputSizeStream).pipeThrough(stream).pipeThrough(outputSizeStream);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ChunkStream extends TransformStream {
|
||||
|
||||
constructor(chunkSize) {
|
||||
let pendingChunk;
|
||||
super({
|
||||
transform,
|
||||
flush(controller) {
|
||||
if (pendingChunk && pendingChunk.length) {
|
||||
controller.enqueue(pendingChunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function transform(chunk, controller) {
|
||||
if (pendingChunk) {
|
||||
const newChunk = new Uint8Array(pendingChunk.length + chunk.length);
|
||||
newChunk.set(pendingChunk);
|
||||
newChunk.set(chunk, pendingChunk.length);
|
||||
chunk = newChunk;
|
||||
pendingChunk = null;
|
||||
}
|
||||
if (chunk.length > chunkSize) {
|
||||
controller.enqueue(chunk.slice(0, chunkSize));
|
||||
transform(chunk.slice(chunkSize), controller);
|
||||
} else {
|
||||
pendingChunk = chunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const table = [];
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let t = i;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
if (t & 1) {
|
||||
t = (t >>> 1) ^ 0xEDB88320;
|
||||
} else {
|
||||
t = t >>> 1;
|
||||
}
|
||||
}
|
||||
table[i] = t;
|
||||
}
|
||||
|
||||
class Crc32 {
|
||||
|
||||
constructor(crc) {
|
||||
this.crc = crc || -1;
|
||||
}
|
||||
|
||||
append(data) {
|
||||
let crc = this.crc | 0;
|
||||
for (let offset = 0, length = data.length | 0; offset < length; offset++) {
|
||||
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
||||
}
|
||||
this.crc = crc;
|
||||
}
|
||||
|
||||
get() {
|
||||
return ~this.crc;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Crc32
|
||||
};
|
||||
+827
@@ -0,0 +1,827 @@
|
||||
// Derived from https://github.com/xqdoo00o/jszip/blob/master/lib/sjcl.js and https://github.com/bitwiseshiftleft/sjcl
|
||||
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
/*
|
||||
* SJCL is open. You can use, modify and redistribute it under a BSD
|
||||
* license or under the GNU GPL, version 2.0.
|
||||
*/
|
||||
|
||||
/** @fileOverview Javascript cryptography implementation.
|
||||
*
|
||||
* Crush to remove comments, shorten variable names and
|
||||
* generally reduce transmission size.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
|
||||
|
||||
/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arrays of bits, encoded as arrays of Numbers.
|
||||
* @namespace
|
||||
* @description
|
||||
* <p>
|
||||
* These objects are the currency accepted by SJCL's crypto functions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Most of our crypto primitives operate on arrays of 4-byte words internally,
|
||||
* but many of them can take arguments that are not a multiple of 4 bytes.
|
||||
* This library encodes arrays of bits (whose size need not be a multiple of 8
|
||||
* bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
|
||||
* array of words, 32 bits at a time. Since the words are double-precision
|
||||
* floating point numbers, they fit some extra data. We use this (in a private,
|
||||
* possibly-changing manner) to encode the number of bits actually present
|
||||
* in the last word of the array.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Because bitwise ops clear this out-of-band data, these arrays can be passed
|
||||
* to ciphers like AES which want arrays of words.
|
||||
* </p>
|
||||
*/
|
||||
const bitArray = {
|
||||
/**
|
||||
* Concatenate two bit arrays.
|
||||
* @param {bitArray} a1 The first array.
|
||||
* @param {bitArray} a2 The second array.
|
||||
* @return {bitArray} The concatenation of a1 and a2.
|
||||
*/
|
||||
concat(a1, a2) {
|
||||
if (a1.length === 0 || a2.length === 0) {
|
||||
return a1.concat(a2);
|
||||
}
|
||||
|
||||
const last = a1[a1.length - 1], shift = bitArray.getPartial(last);
|
||||
if (shift === 32) {
|
||||
return a1.concat(a2);
|
||||
} else {
|
||||
return bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the length of an array of bits.
|
||||
* @param {bitArray} a The array.
|
||||
* @return {Number} The length of a, in bits.
|
||||
*/
|
||||
bitLength(a) {
|
||||
const l = a.length;
|
||||
if (l === 0) {
|
||||
return 0;
|
||||
}
|
||||
const x = a[l - 1];
|
||||
return (l - 1) * 32 + bitArray.getPartial(x);
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate an array.
|
||||
* @param {bitArray} a The array.
|
||||
* @param {Number} len The length to truncate to, in bits.
|
||||
* @return {bitArray} A new array, truncated to len bits.
|
||||
*/
|
||||
clamp(a, len) {
|
||||
if (a.length * 32 < len) {
|
||||
return a;
|
||||
}
|
||||
a = a.slice(0, Math.ceil(len / 32));
|
||||
const l = a.length;
|
||||
len = len & 31;
|
||||
if (l > 0 && len) {
|
||||
a[l - 1] = bitArray.partial(len, a[l - 1] & 0x80000000 >> (len - 1), 1);
|
||||
}
|
||||
return a;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a partial word for a bit array.
|
||||
* @param {Number} len The number of bits in the word.
|
||||
* @param {Number} x The bits.
|
||||
* @param {Number} [_end=0] Pass 1 if x has already been shifted to the high side.
|
||||
* @return {Number} The partial word.
|
||||
*/
|
||||
partial(len, x, _end) {
|
||||
if (len === 32) {
|
||||
return x;
|
||||
}
|
||||
return (_end ? x | 0 : x << (32 - len)) + len * 0x10000000000;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of bits used by a partial word.
|
||||
* @param {Number} x The partial word.
|
||||
* @return {Number} The number of bits used by the partial word.
|
||||
*/
|
||||
getPartial(x) {
|
||||
return Math.round(x / 0x10000000000) || 32;
|
||||
},
|
||||
|
||||
/** Shift an array right.
|
||||
* @param {bitArray} a The array to shift.
|
||||
* @param {Number} shift The number of bits to shift.
|
||||
* @param {Number} [carry=0] A byte to carry in
|
||||
* @param {bitArray} [out=[]] An array to prepend to the output.
|
||||
* @private
|
||||
*/
|
||||
_shiftRight(a, shift, carry, out) {
|
||||
if (out === undefined) {
|
||||
out = [];
|
||||
}
|
||||
|
||||
for (; shift >= 32; shift -= 32) {
|
||||
out.push(carry);
|
||||
carry = 0;
|
||||
}
|
||||
if (shift === 0) {
|
||||
return out.concat(a);
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
out.push(carry | a[i] >>> shift);
|
||||
carry = a[i] << (32 - shift);
|
||||
}
|
||||
const last2 = a.length ? a[a.length - 1] : 0;
|
||||
const shift2 = bitArray.getPartial(last2);
|
||||
out.push(bitArray.partial(shift + shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(), 1));
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arrays of bytes
|
||||
* @namespace
|
||||
*/
|
||||
const codec = {
|
||||
bytes: {
|
||||
/** Convert from a bitArray to an array of bytes. */
|
||||
fromBits(arr) {
|
||||
const bl = bitArray.bitLength(arr);
|
||||
const byteLength = bl / 8;
|
||||
const out = new Uint8Array(byteLength);
|
||||
let tmp;
|
||||
for (let i = 0; i < byteLength; i++) {
|
||||
if ((i & 3) === 0) {
|
||||
tmp = arr[i / 4];
|
||||
}
|
||||
out[i] = tmp >>> 24;
|
||||
tmp <<= 8;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
/** Convert from an array of bytes to a bitArray. */
|
||||
toBits(bytes) {
|
||||
const out = [];
|
||||
let i;
|
||||
let tmp = 0;
|
||||
for (i = 0; i < bytes.length; i++) {
|
||||
tmp = tmp << 8 | bytes[i];
|
||||
if ((i & 3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i & 3) {
|
||||
out.push(bitArray.partial(8 * (i & 3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const hash = {};
|
||||
|
||||
/**
|
||||
* Context for a SHA-1 operation in progress.
|
||||
* @constructor
|
||||
*/
|
||||
hash.sha1 = class {
|
||||
constructor(hash) {
|
||||
const sha1 = this;
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
sha1.blockSize = 512;
|
||||
/**
|
||||
* The SHA-1 initialization vector.
|
||||
* @private
|
||||
*/
|
||||
sha1._init = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
|
||||
/**
|
||||
* The SHA-1 hash key.
|
||||
* @private
|
||||
*/
|
||||
sha1._key = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6];
|
||||
if (hash) {
|
||||
sha1._h = hash._h.slice(0);
|
||||
sha1._buffer = hash._buffer.slice(0);
|
||||
sha1._length = hash._length;
|
||||
} else {
|
||||
sha1.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset() {
|
||||
const sha1 = this;
|
||||
sha1._h = sha1._init.slice(0);
|
||||
sha1._buffer = [];
|
||||
sha1._length = 0;
|
||||
return sha1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update(data) {
|
||||
const sha1 = this;
|
||||
if (typeof data === "string") {
|
||||
data = codec.utf8String.toBits(data);
|
||||
}
|
||||
const b = sha1._buffer = bitArray.concat(sha1._buffer, data);
|
||||
const ol = sha1._length;
|
||||
const nl = sha1._length = ol + bitArray.bitLength(data);
|
||||
if (nl > 9007199254740991) {
|
||||
throw new Error("Cannot hash more than 2^53 - 1 bits");
|
||||
}
|
||||
const c = new Uint32Array(b);
|
||||
let j = 0;
|
||||
for (let i = sha1.blockSize + ol - ((sha1.blockSize + ol) & (sha1.blockSize - 1)); i <= nl;
|
||||
i += sha1.blockSize) {
|
||||
sha1._block(c.subarray(16 * j, 16 * (j + 1)));
|
||||
j += 1;
|
||||
}
|
||||
b.splice(0, 16 * j);
|
||||
return sha1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete hashing and output the hash value.
|
||||
* @return {bitArray} The hash value, an array of 5 big-endian words. TODO
|
||||
*/
|
||||
finalize() {
|
||||
const sha1 = this;
|
||||
let b = sha1._buffer;
|
||||
const h = sha1._h;
|
||||
|
||||
// Round out and push the buffer
|
||||
b = bitArray.concat(b, [bitArray.partial(1, 1)]);
|
||||
// Round out the buffer to a multiple of 16 words, less the 2 length words.
|
||||
for (let i = b.length + 2; i & 15; i++) {
|
||||
b.push(0);
|
||||
}
|
||||
|
||||
// append the length
|
||||
b.push(Math.floor(sha1._length / 0x100000000));
|
||||
b.push(sha1._length | 0);
|
||||
|
||||
while (b.length) {
|
||||
sha1._block(b.splice(0, 16));
|
||||
}
|
||||
|
||||
sha1.reset();
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SHA-1 logical functions f(0), f(1), ..., f(79).
|
||||
* @private
|
||||
*/
|
||||
_f(t, b, c, d) {
|
||||
if (t <= 19) {
|
||||
return (b & c) | (~b & d);
|
||||
} else if (t <= 39) {
|
||||
return b ^ c ^ d;
|
||||
} else if (t <= 59) {
|
||||
return (b & c) | (b & d) | (c & d);
|
||||
} else if (t <= 79) {
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Circular left-shift operator.
|
||||
* @private
|
||||
*/
|
||||
_S(n, x) {
|
||||
return (x << n) | (x >>> 32 - n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform one cycle of SHA-1.
|
||||
* @param {Uint32Array|bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block(words) {
|
||||
const sha1 = this;
|
||||
const h = sha1._h;
|
||||
// When words is passed to _block, it has 16 elements. SHA1 _block
|
||||
// function extends words with new elements (at the end there are 80 elements).
|
||||
// The problem is that if we use Uint32Array instead of Array,
|
||||
// the length of Uint32Array cannot be changed. Thus, we replace words with a
|
||||
// normal Array here.
|
||||
const w = Array(80); // do not use Uint32Array here as the instantiation is slower
|
||||
for (let j = 0; j < 16; j++) {
|
||||
w[j] = words[j];
|
||||
}
|
||||
|
||||
let a = h[0];
|
||||
let b = h[1];
|
||||
let c = h[2];
|
||||
let d = h[3];
|
||||
let e = h[4];
|
||||
|
||||
for (let t = 0; t <= 79; t++) {
|
||||
if (t >= 16) {
|
||||
w[t] = sha1._S(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
|
||||
}
|
||||
const tmp = (sha1._S(5, a) + sha1._f(t, b, c, d) + e + w[t] +
|
||||
sha1._key[Math.floor(t / 20)]) | 0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = sha1._S(30, b);
|
||||
b = a;
|
||||
a = tmp;
|
||||
}
|
||||
|
||||
h[0] = (h[0] + a) | 0;
|
||||
h[1] = (h[1] + b) | 0;
|
||||
h[2] = (h[2] + c) | 0;
|
||||
h[3] = (h[3] + d) | 0;
|
||||
h[4] = (h[4] + e) | 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** @fileOverview Low-level AES implementation.
|
||||
*
|
||||
* This file contains a low-level implementation of AES, optimized for
|
||||
* size and for efficiency on several browsers. It is based on
|
||||
* OpenSSL's aes_core.c, a public-domain implementation by Vincent
|
||||
* Rijmen, Antoon Bosselaers and Paulo Barreto.
|
||||
*
|
||||
* An older version of this implementation is available in the public
|
||||
* domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
|
||||
* Stanford University 2008-2010 and BSD-licensed for liability
|
||||
* reasons.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
const cipher = {};
|
||||
|
||||
/**
|
||||
* Schedule out an AES key for both encryption and decryption. This
|
||||
* is a low-level class. Use a cipher mode to do bulk encryption.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Array} key The key as an array of 4, 6 or 8 words.
|
||||
*/
|
||||
cipher.aes = class {
|
||||
constructor(key) {
|
||||
/**
|
||||
* The expanded S-box and inverse S-box tables. These will be computed
|
||||
* on the client so that we don't have to send them down the wire.
|
||||
*
|
||||
* There are two tables, _tables[0] is for encryption and
|
||||
* _tables[1] is for decryption.
|
||||
*
|
||||
* The first 4 sub-tables are the expanded S-box with MixColumns. The
|
||||
* last (_tables[01][4]) is the S-box itself.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const aes = this;
|
||||
aes._tables = [[[], [], [], [], []], [[], [], [], [], []]];
|
||||
|
||||
if (!aes._tables[0][0][0]) {
|
||||
aes._precompute();
|
||||
}
|
||||
|
||||
const sbox = aes._tables[0][4];
|
||||
const decTable = aes._tables[1];
|
||||
const keyLen = key.length;
|
||||
|
||||
let i, encKey, decKey, rcon = 1;
|
||||
|
||||
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
|
||||
throw new Error("invalid aes key size");
|
||||
}
|
||||
|
||||
aes._key = [encKey = key.slice(0), decKey = []];
|
||||
|
||||
// schedule encryption keys
|
||||
for (i = keyLen; i < 4 * keyLen + 28; i++) {
|
||||
let tmp = encKey[i - 1];
|
||||
|
||||
// apply sbox
|
||||
if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
|
||||
tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
|
||||
|
||||
// shift rows and add rcon
|
||||
if (i % keyLen === 0) {
|
||||
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
|
||||
rcon = rcon << 1 ^ (rcon >> 7) * 283;
|
||||
}
|
||||
}
|
||||
|
||||
encKey[i] = encKey[i - keyLen] ^ tmp;
|
||||
}
|
||||
|
||||
// schedule decryption keys
|
||||
for (let j = 0; i; j++, i--) {
|
||||
const tmp = encKey[j & 3 ? i : i - 4];
|
||||
if (i <= 4 || j < 4) {
|
||||
decKey[j] = tmp;
|
||||
} else {
|
||||
decKey[j] = decTable[0][sbox[tmp >>> 24]] ^
|
||||
decTable[1][sbox[tmp >> 16 & 255]] ^
|
||||
decTable[2][sbox[tmp >> 8 & 255]] ^
|
||||
decTable[3][sbox[tmp & 255]];
|
||||
}
|
||||
}
|
||||
}
|
||||
// public
|
||||
/* Something like this might appear here eventually
|
||||
name: "AES",
|
||||
blockSize: 4,
|
||||
keySizes: [4,6,8],
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The plaintext.
|
||||
* @return {Array} The ciphertext.
|
||||
*/
|
||||
encrypt(data) {
|
||||
return this._crypt(data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt an array of 4 big-endian words.
|
||||
* @param {Array} data The ciphertext.
|
||||
* @return {Array} The plaintext.
|
||||
*/
|
||||
decrypt(data) {
|
||||
return this._crypt(data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the S-box tables.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_precompute() {
|
||||
const encTable = this._tables[0];
|
||||
const decTable = this._tables[1];
|
||||
const sbox = encTable[4];
|
||||
const sboxInv = decTable[4];
|
||||
const d = [];
|
||||
const th = [];
|
||||
let xInv, x2, x4, x8;
|
||||
|
||||
// Compute double and third tables
|
||||
for (let i = 0; i < 256; i++) {
|
||||
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
|
||||
}
|
||||
|
||||
for (let x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
|
||||
// Compute sbox
|
||||
let s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
|
||||
s = s >> 8 ^ s & 255 ^ 99;
|
||||
sbox[x] = s;
|
||||
sboxInv[s] = x;
|
||||
|
||||
// Compute MixColumns
|
||||
x8 = d[x4 = d[x2 = d[x]]];
|
||||
let tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
|
||||
let tEnc = d[s] * 0x101 ^ s * 0x1010100;
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
|
||||
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Compactify. Considerable speedup on Firefox.
|
||||
for (let i = 0; i < 5; i++) {
|
||||
encTable[i] = encTable[i].slice(0);
|
||||
decTable[i] = decTable[i].slice(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encryption and decryption core.
|
||||
* @param {Array} input Four words to be encrypted or decrypted.
|
||||
* @param dir The direction, 0 for encrypt and 1 for decrypt.
|
||||
* @return {Array} The four encrypted or decrypted words.
|
||||
* @private
|
||||
*/
|
||||
_crypt(input, dir) {
|
||||
if (input.length !== 4) {
|
||||
throw new Error("invalid aes block size");
|
||||
}
|
||||
|
||||
const key = this._key[dir];
|
||||
|
||||
const nInnerRounds = key.length / 4 - 2;
|
||||
const out = [0, 0, 0, 0];
|
||||
const table = this._tables[dir];
|
||||
|
||||
// load up the tables
|
||||
const t0 = table[0];
|
||||
const t1 = table[1];
|
||||
const t2 = table[2];
|
||||
const t3 = table[3];
|
||||
const sbox = table[4];
|
||||
|
||||
// state variables a,b,c,d are loaded with pre-whitened data
|
||||
let a = input[0] ^ key[0];
|
||||
let b = input[dir ? 3 : 1] ^ key[1];
|
||||
let c = input[2] ^ key[2];
|
||||
let d = input[dir ? 1 : 3] ^ key[3];
|
||||
let kIndex = 4;
|
||||
let a2, b2, c2;
|
||||
|
||||
// Inner rounds. Cribbed from OpenSSL.
|
||||
for (let i = 0; i < nInnerRounds; i++) {
|
||||
a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex];
|
||||
b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
|
||||
c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
|
||||
d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
|
||||
kIndex += 4;
|
||||
a = a2; b = b2; c = c2;
|
||||
}
|
||||
|
||||
// Last round.
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out[dir ? 3 & -i : i] =
|
||||
sbox[a >>> 24] << 24 ^
|
||||
sbox[b >> 16 & 255] << 16 ^
|
||||
sbox[c >> 8 & 255] << 8 ^
|
||||
sbox[d & 255] ^
|
||||
key[kIndex++];
|
||||
a2 = a; a = b; b = c; c = d; d = a2;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Random values
|
||||
* @namespace
|
||||
*/
|
||||
const random = {
|
||||
/**
|
||||
* Generate random words with pure js, cryptographically not as strong & safe as native implementation.
|
||||
* @param {TypedArray} typedArray The array to fill.
|
||||
* @return {TypedArray} The random values.
|
||||
*/
|
||||
getRandomValues(typedArray) {
|
||||
const words = new Uint32Array(typedArray.buffer);
|
||||
const r = (m_w) => {
|
||||
let m_z = 0x3ade68b1;
|
||||
const mask = 0xffffffff;
|
||||
return function () {
|
||||
m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
|
||||
m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
|
||||
const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
|
||||
return result * (Math.random() > .5 ? 1 : -1);
|
||||
};
|
||||
};
|
||||
for (let i = 0, rcache; i < typedArray.length; i += 4) {
|
||||
const _r = r((rcache || Math.random()) * 0x100000000);
|
||||
rcache = _r() * 0x3ade67b7;
|
||||
words[i / 4] = (_r() * 0x100000000) | 0;
|
||||
}
|
||||
return typedArray;
|
||||
}
|
||||
};
|
||||
|
||||
/** @fileOverview CTR mode implementation.
|
||||
*
|
||||
* Special thanks to Roy Nicholson for pointing out a bug in our
|
||||
* implementation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** Brian Gladman's CTR Mode.
|
||||
* @constructor
|
||||
* @param {Object} _prf The aes instance to generate key.
|
||||
* @param {bitArray} _iv The iv for ctr mode, it must be 128 bits.
|
||||
*/
|
||||
|
||||
const mode = {};
|
||||
|
||||
/**
|
||||
* Brian Gladman's CTR Mode.
|
||||
* @namespace
|
||||
*/
|
||||
mode.ctrGladman = class {
|
||||
constructor(prf, iv) {
|
||||
this._prf = prf;
|
||||
this._initIv = iv;
|
||||
this._iv = iv;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this._iv = this._initIv;
|
||||
}
|
||||
|
||||
/** Input some data to calculate.
|
||||
* @param {bitArray} data the data to process, it must be intergral multiple of 128 bits unless it's the last.
|
||||
*/
|
||||
update(data) {
|
||||
return this.calculate(this._prf, data, this._iv);
|
||||
}
|
||||
|
||||
incWord(word) {
|
||||
if (((word >> 24) & 0xff) === 0xff) { //overflow
|
||||
let b1 = (word >> 16) & 0xff;
|
||||
let b2 = (word >> 8) & 0xff;
|
||||
let b3 = word & 0xff;
|
||||
|
||||
if (b1 === 0xff) { // overflow b1
|
||||
b1 = 0;
|
||||
if (b2 === 0xff) {
|
||||
b2 = 0;
|
||||
if (b3 === 0xff) {
|
||||
b3 = 0;
|
||||
} else {
|
||||
++b3;
|
||||
}
|
||||
} else {
|
||||
++b2;
|
||||
}
|
||||
} else {
|
||||
++b1;
|
||||
}
|
||||
|
||||
word = 0;
|
||||
word += (b1 << 16);
|
||||
word += (b2 << 8);
|
||||
word += b3;
|
||||
} else {
|
||||
word += (0x01 << 24);
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
incCounter(counter) {
|
||||
if ((counter[0] = this.incWord(counter[0])) === 0) {
|
||||
// encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8
|
||||
counter[1] = this.incWord(counter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
calculate(prf, data, iv) {
|
||||
let l;
|
||||
if (!(l = data.length)) {
|
||||
return [];
|
||||
}
|
||||
const bl = bitArray.bitLength(data);
|
||||
for (let i = 0; i < l; i += 4) {
|
||||
this.incCounter(iv);
|
||||
const e = prf.encrypt(iv);
|
||||
data[i] ^= e[0];
|
||||
data[i + 1] ^= e[1];
|
||||
data[i + 2] ^= e[2];
|
||||
data[i + 3] ^= e[3];
|
||||
}
|
||||
return bitArray.clamp(data, bl);
|
||||
}
|
||||
};
|
||||
|
||||
const misc = {
|
||||
importKey(password) {
|
||||
return new misc.hmacSha1(codec.bytes.toBits(password));
|
||||
},
|
||||
pbkdf2(prf, salt, count, length) {
|
||||
count = count || 10000;
|
||||
if (length < 0 || count < 0) {
|
||||
throw new Error("invalid params to pbkdf2");
|
||||
}
|
||||
const byteLength = ((length >> 5) + 1) << 2;
|
||||
let u, ui, i, j, k;
|
||||
const arrayBuffer = new ArrayBuffer(byteLength);
|
||||
const out = new DataView(arrayBuffer);
|
||||
let outLength = 0;
|
||||
const b = bitArray;
|
||||
salt = codec.bytes.toBits(salt);
|
||||
for (k = 1; outLength < (byteLength || 1); k++) {
|
||||
u = ui = prf.encrypt(b.concat(salt, [k]));
|
||||
for (i = 1; i < count; i++) {
|
||||
ui = prf.encrypt(ui);
|
||||
for (j = 0; j < ui.length; j++) {
|
||||
u[j] ^= ui[j];
|
||||
}
|
||||
}
|
||||
for (i = 0; outLength < (byteLength || 1) && i < u.length; i++) {
|
||||
out.setInt32(outLength, u[i]);
|
||||
outLength += 4;
|
||||
}
|
||||
}
|
||||
return arrayBuffer.slice(0, length / 8);
|
||||
}
|
||||
};
|
||||
|
||||
/** @fileOverview HMAC implementation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** HMAC with the specified hash function.
|
||||
* @constructor
|
||||
* @param {bitArray} key the key for HMAC.
|
||||
* @param {Object} [Hash=hash.sha1] The hash function to use.
|
||||
*/
|
||||
misc.hmacSha1 = class {
|
||||
|
||||
constructor(key) {
|
||||
const hmac = this;
|
||||
const Hash = hmac._hash = hash.sha1;
|
||||
const exKey = [[], []];
|
||||
hmac._baseHash = [new Hash(), new Hash()];
|
||||
const bs = hmac._baseHash[0].blockSize / 32;
|
||||
|
||||
if (key.length > bs) {
|
||||
key = new Hash().update(key).finalize();
|
||||
}
|
||||
|
||||
for (let i = 0; i < bs; i++) {
|
||||
exKey[0][i] = key[i] ^ 0x36363636;
|
||||
exKey[1][i] = key[i] ^ 0x5C5C5C5C;
|
||||
}
|
||||
|
||||
hmac._baseHash[0].update(exKey[0]);
|
||||
hmac._baseHash[1].update(exKey[1]);
|
||||
hmac._resultHash = new Hash(hmac._baseHash[0]);
|
||||
}
|
||||
reset() {
|
||||
const hmac = this;
|
||||
hmac._resultHash = new hmac._hash(hmac._baseHash[0]);
|
||||
hmac._updated = false;
|
||||
}
|
||||
|
||||
update(data) {
|
||||
const hmac = this;
|
||||
hmac._updated = true;
|
||||
hmac._resultHash.update(data);
|
||||
}
|
||||
|
||||
digest() {
|
||||
const hmac = this;
|
||||
const w = hmac._resultHash.finalize();
|
||||
const result = new (hmac._hash)(hmac._baseHash[1]).update(w).finalize();
|
||||
|
||||
hmac.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
encrypt(data) {
|
||||
if (!this._updated) {
|
||||
this.update(data);
|
||||
return this.digest(data);
|
||||
} else {
|
||||
throw new Error("encrypt on already updated hmac called!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
cipher,
|
||||
codec,
|
||||
misc,
|
||||
mode,
|
||||
random
|
||||
};
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global crypto */
|
||||
|
||||
import { FUNCTION_TYPE, UNDEFINED_TYPE } from "../constants.js";
|
||||
import {
|
||||
random
|
||||
} from "./codecs/sjcl.js";
|
||||
|
||||
const GET_RANDOM_VALUES_SUPPORTED = typeof crypto != UNDEFINED_TYPE && typeof crypto.getRandomValues == FUNCTION_TYPE;
|
||||
|
||||
const ERR_INVALID_PASSWORD = "Invalid password";
|
||||
const ERR_INVALID_SIGNATURE = "Invalid signature";
|
||||
const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
|
||||
|
||||
export {
|
||||
getRandomValues,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_ABORT_CHECK_PASSWORD
|
||||
};
|
||||
|
||||
function getRandomValues(array) {
|
||||
if (GET_RANDOM_VALUES_SUPPORTED) {
|
||||
return crypto.getRandomValues(array);
|
||||
} else {
|
||||
return random.getRandomValues(array);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TransformStream */
|
||||
|
||||
import { Crc32 } from "./codecs/crc32.js";
|
||||
|
||||
class Crc32Stream extends TransformStream {
|
||||
|
||||
constructor() {
|
||||
// deno-lint-ignore prefer-const
|
||||
let stream;
|
||||
const crc32 = new Crc32();
|
||||
super({
|
||||
transform(chunk, controller) {
|
||||
crc32.append(chunk);
|
||||
controller.enqueue(chunk);
|
||||
},
|
||||
flush() {
|
||||
const value = new Uint8Array(4);
|
||||
const dataView = new DataView(value.buffer);
|
||||
dataView.setUint32(0, crc32.get());
|
||||
stream.value = value;
|
||||
}
|
||||
});
|
||||
stream = this;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
Crc32Stream
|
||||
};
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TransformStream */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import { Crc32 } from "./codecs/crc32.js";
|
||||
import {
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_ABORT_CHECK_PASSWORD,
|
||||
getRandomValues
|
||||
} from "./common-crypto.js";
|
||||
|
||||
const HEADER_LENGTH = 12;
|
||||
|
||||
class ZipCryptoDecryptionStream extends TransformStream {
|
||||
|
||||
constructor({ password, passwordVerification, checkPasswordOnly }) {
|
||||
super({
|
||||
start() {
|
||||
Object.assign(this, {
|
||||
password,
|
||||
passwordVerification
|
||||
});
|
||||
createKeys(this, password);
|
||||
},
|
||||
transform(chunk, controller) {
|
||||
const zipCrypto = this;
|
||||
if (zipCrypto.password) {
|
||||
const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
|
||||
zipCrypto.password = null;
|
||||
if (decryptedHeader.at(-1) != zipCrypto.passwordVerification) {
|
||||
throw new Error(ERR_INVALID_PASSWORD);
|
||||
}
|
||||
chunk = chunk.subarray(HEADER_LENGTH);
|
||||
}
|
||||
if (checkPasswordOnly) {
|
||||
controller.error(new Error(ERR_ABORT_CHECK_PASSWORD));
|
||||
} else {
|
||||
controller.enqueue(decrypt(zipCrypto, chunk));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ZipCryptoEncryptionStream extends TransformStream {
|
||||
|
||||
constructor({ password, passwordVerification }) {
|
||||
super({
|
||||
start() {
|
||||
Object.assign(this, {
|
||||
password,
|
||||
passwordVerification
|
||||
});
|
||||
createKeys(this, password);
|
||||
},
|
||||
transform(chunk, controller) {
|
||||
const zipCrypto = this;
|
||||
let output;
|
||||
let offset;
|
||||
if (zipCrypto.password) {
|
||||
zipCrypto.password = null;
|
||||
const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
|
||||
header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
|
||||
output = new Uint8Array(chunk.length + header.length);
|
||||
output.set(encrypt(zipCrypto, header), 0);
|
||||
offset = HEADER_LENGTH;
|
||||
} else {
|
||||
output = new Uint8Array(chunk.length);
|
||||
offset = 0;
|
||||
}
|
||||
output.set(encrypt(zipCrypto, chunk), offset);
|
||||
controller.enqueue(output);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ZipCryptoDecryptionStream,
|
||||
ZipCryptoEncryptionStream,
|
||||
ERR_INVALID_PASSWORD
|
||||
};
|
||||
|
||||
function decrypt(target, input) {
|
||||
const output = new Uint8Array(input.length);
|
||||
for (let index = 0; index < input.length; index++) {
|
||||
output[index] = getByte(target) ^ input[index];
|
||||
updateKeys(target, output[index]);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function encrypt(target, input) {
|
||||
const output = new Uint8Array(input.length);
|
||||
for (let index = 0; index < input.length; index++) {
|
||||
output[index] = getByte(target) ^ input[index];
|
||||
updateKeys(target, input[index]);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function createKeys(target, password) {
|
||||
const keys = [0x12345678, 0x23456789, 0x34567890];
|
||||
Object.assign(target, {
|
||||
keys,
|
||||
crcKey0: new Crc32(keys[0]),
|
||||
crcKey2: new Crc32(keys[2])
|
||||
});
|
||||
for (let index = 0; index < password.length; index++) {
|
||||
updateKeys(target, password.charCodeAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
function updateKeys(target, byte) {
|
||||
let [key0, key1, key2] = target.keys;
|
||||
target.crcKey0.append([byte]);
|
||||
key0 = ~target.crcKey0.get();
|
||||
key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
|
||||
target.crcKey2.append([key1 >>> 24]);
|
||||
key2 = ~target.crcKey2.get();
|
||||
target.keys = [key0, key1, key2];
|
||||
}
|
||||
|
||||
function getByte(target) {
|
||||
const temp = target.keys[2] | 2;
|
||||
return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8);
|
||||
}
|
||||
|
||||
function getInt8(number) {
|
||||
return number & 0xFF;
|
||||
}
|
||||
|
||||
function getInt32(number) {
|
||||
return number & 0xFFFFFFFF;
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TransformStream */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import { Crc32Stream } from "./crc32-stream.js";
|
||||
import {
|
||||
AESEncryptionStream,
|
||||
AESDecryptionStream
|
||||
} from "./aes-crypto-stream.js";
|
||||
import {
|
||||
ZipCryptoEncryptionStream,
|
||||
ZipCryptoDecryptionStream
|
||||
} from "./zip-crypto-stream.js";
|
||||
import {
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_ABORT_CHECK_PASSWORD
|
||||
} from "./common-crypto.js";
|
||||
|
||||
const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
|
||||
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
||||
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
||||
|
||||
class DeflateStream extends TransformStream {
|
||||
|
||||
constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
|
||||
super({});
|
||||
const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level } = options;
|
||||
const stream = this;
|
||||
let crc32Stream, encryptionStream;
|
||||
let readable = super.readable;
|
||||
if ((!encrypted || zipCrypto) && signed) {
|
||||
crc32Stream = new Crc32Stream();
|
||||
readable = pipeThrough(readable, crc32Stream);
|
||||
}
|
||||
if (compressed) {
|
||||
readable = pipeThroughCommpressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamZlib, CompressionStream);
|
||||
}
|
||||
if (encrypted) {
|
||||
if (zipCrypto) {
|
||||
readable = pipeThrough(readable, new ZipCryptoEncryptionStream(options));
|
||||
} else {
|
||||
encryptionStream = new AESEncryptionStream(options);
|
||||
readable = pipeThrough(readable, encryptionStream);
|
||||
}
|
||||
}
|
||||
setReadable(stream, readable, () => {
|
||||
let signature;
|
||||
if (encrypted && !zipCrypto) {
|
||||
signature = encryptionStream.signature;
|
||||
}
|
||||
if ((!encrypted || zipCrypto) && signed) {
|
||||
signature = new DataView(crc32Stream.value.buffer).getUint32(0);
|
||||
}
|
||||
stream.signature = signature;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class InflateStream extends TransformStream {
|
||||
|
||||
constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
|
||||
super({});
|
||||
const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64 } = options;
|
||||
let crc32Stream, decryptionStream;
|
||||
let readable = super.readable;
|
||||
if (encrypted) {
|
||||
if (zipCrypto) {
|
||||
readable = pipeThrough(readable, new ZipCryptoDecryptionStream(options));
|
||||
} else {
|
||||
decryptionStream = new AESDecryptionStream(options);
|
||||
readable = pipeThrough(readable, decryptionStream);
|
||||
}
|
||||
}
|
||||
if (compressed) {
|
||||
readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
|
||||
}
|
||||
if ((!encrypted || zipCrypto) && signed) {
|
||||
crc32Stream = new Crc32Stream();
|
||||
readable = pipeThrough(readable, crc32Stream);
|
||||
}
|
||||
setReadable(this, readable, () => {
|
||||
if ((!encrypted || zipCrypto) && signed) {
|
||||
const dataViewSignature = new DataView(crc32Stream.value.buffer);
|
||||
if (signature != dataViewSignature.getUint32(0, false)) {
|
||||
throw new Error(ERR_INVALID_SIGNATURE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DeflateStream,
|
||||
InflateStream,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_ABORT_CHECK_PASSWORD
|
||||
};
|
||||
|
||||
function setReadable(stream, readable, flush) {
|
||||
readable = pipeThrough(readable, new TransformStream({ flush }));
|
||||
Object.defineProperty(stream, "readable", {
|
||||
get() {
|
||||
return readable;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
|
||||
const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
|
||||
const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
|
||||
try {
|
||||
readable = pipeThrough(readable, new Stream(format, options));
|
||||
} catch (error) {
|
||||
if (useCompressionStream) {
|
||||
if (CompressionStreamZlib) {
|
||||
readable = pipeThrough(readable, new CompressionStreamZlib(format, options));
|
||||
} else if (CompressionStream) {
|
||||
readable = pipeThrough(readable, new CompressionStream(format, options));
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return readable;
|
||||
}
|
||||
|
||||
function pipeThrough(readable, transformStream) {
|
||||
return readable.pipeThrough(transformStream);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
See https://github.com/gildas-lormeau/zlib-streams-ts/tree/main/dist
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
See https://github.com/gildas-lormeau/zlib-streams/tree/main/dist
|
||||
Generated
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global WebAssembly, URL, fetch, atob */
|
||||
|
||||
import { setWasmExports } from "./zlib-streams.js";
|
||||
|
||||
let initializedModule = false;
|
||||
|
||||
async function initModule(wasmURI, { baseURI }) {
|
||||
if (!initializedModule) {
|
||||
let arrayBuffer, uri;
|
||||
try {
|
||||
try {
|
||||
uri = new URL(wasmURI, baseURI);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
const response = await fetch(uri);
|
||||
arrayBuffer = await response.arrayBuffer();
|
||||
} catch (error) {
|
||||
if (wasmURI.startsWith("data:application/wasm;base64,")) {
|
||||
arrayBuffer = arrayBufferFromDataURI(wasmURI);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const wasmInstance = await WebAssembly.instantiate(arrayBuffer);
|
||||
setWasmExports(wasmInstance.instance.exports);
|
||||
initializedModule = true;
|
||||
}
|
||||
}
|
||||
|
||||
function resetWasmModule() {
|
||||
initializedModule = false;
|
||||
}
|
||||
|
||||
function arrayBufferFromDataURI(dataURI) {
|
||||
const base64 = dataURI.split(",")[1];
|
||||
const binary = atob(base64);
|
||||
const len = binary.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
export {
|
||||
setWasmExports,
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib
|
||||
} from "./zlib-streams.js";
|
||||
export {
|
||||
initModule,
|
||||
resetWasmModule,
|
||||
initializedModule
|
||||
};
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TransformStream */
|
||||
|
||||
let wasm, malloc, free, memory;
|
||||
|
||||
export function setWasmExports(wasmAPI) {
|
||||
wasm = wasmAPI;
|
||||
({ malloc, free, memory } = wasm);
|
||||
if (typeof malloc !== "function" || typeof free !== "function" || !memory) {
|
||||
wasm = malloc = free = memory = null;
|
||||
throw new Error("Invalid WASM module");
|
||||
}
|
||||
}
|
||||
|
||||
function _make(isCompress, type, options = {}) {
|
||||
const level = (typeof options.level === "number") ? options.level : -1;
|
||||
const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
|
||||
const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
|
||||
|
||||
return new TransformStream({
|
||||
start() {
|
||||
let result;
|
||||
this.out = malloc(outBufferSize);
|
||||
this.in = malloc(inBufferSize);
|
||||
this.inBufferSize = inBufferSize;
|
||||
this._scratch = new Uint8Array(outBufferSize);
|
||||
if (isCompress) {
|
||||
this._process = wasm.deflate_process;
|
||||
this._last_consumed = wasm.deflate_last_consumed;
|
||||
this._end = wasm.deflate_end;
|
||||
this.streamHandle = wasm.deflate_new();
|
||||
if (type === "gzip") {
|
||||
result = wasm.deflate_init_gzip(this.streamHandle, level);
|
||||
} else if (type === "deflate-raw") {
|
||||
result = wasm.deflate_init_raw(this.streamHandle, level);
|
||||
} else {
|
||||
result = wasm.deflate_init(this.streamHandle, level);
|
||||
}
|
||||
} else {
|
||||
if (type === "deflate64-raw") {
|
||||
this._process = wasm.inflate9_process;
|
||||
this._last_consumed = wasm.inflate9_last_consumed;
|
||||
this._end = wasm.inflate9_end;
|
||||
this.streamHandle = wasm.inflate9_new();
|
||||
result = wasm.inflate9_init_raw(this.streamHandle);
|
||||
} else {
|
||||
this._process = wasm.inflate_process;
|
||||
this._last_consumed = wasm.inflate_last_consumed;
|
||||
this._end = wasm.inflate_end;
|
||||
this.streamHandle = wasm.inflate_new();
|
||||
if (type === "deflate-raw") {
|
||||
result = wasm.inflate_init_raw(this.streamHandle);
|
||||
} else if (type === "gzip") {
|
||||
result = wasm.inflate_init_gzip(this.streamHandle);
|
||||
} else {
|
||||
result = wasm.inflate_init(this.streamHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result !== 0) {
|
||||
throw new Error("init failed:" + result);
|
||||
}
|
||||
},
|
||||
transform(chunk, controller) {
|
||||
try {
|
||||
const buffer = chunk;
|
||||
const heap = new Uint8Array(memory.buffer);
|
||||
const process = this._process;
|
||||
const last_consumed = this._last_consumed;
|
||||
const out = this.out;
|
||||
const scratch = this._scratch;
|
||||
let offset = 0;
|
||||
while (offset < buffer.length) {
|
||||
const toRead = Math.min(buffer.length - offset, 32 * 1024);
|
||||
if (!this.in || this.inBufferSize < toRead) {
|
||||
if (this.in && free) {
|
||||
free(this.in);
|
||||
}
|
||||
this.in = malloc(toRead);
|
||||
this.inBufferSize = toRead;
|
||||
}
|
||||
heap.set(buffer.subarray(offset, offset + toRead), this.in);
|
||||
const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
|
||||
const prod = result & 0x00ffffff;
|
||||
if (prod) {
|
||||
scratch.set(heap.subarray(out, out + prod), 0);
|
||||
controller.enqueue(scratch.slice(0, prod));
|
||||
}
|
||||
if (!isCompress) {
|
||||
const code = (result >> 24) & 0xff;
|
||||
const signedCode = (code & 0x80) ? code - 256 : code;
|
||||
if (signedCode < 0) {
|
||||
throw new Error("process error:" + signedCode);
|
||||
}
|
||||
}
|
||||
const consumed = last_consumed(this.streamHandle);
|
||||
if (consumed === 0) {
|
||||
break;
|
||||
}
|
||||
offset += consumed;
|
||||
}
|
||||
} catch (error) {
|
||||
if (this._end && this.streamHandle) {
|
||||
this._end(this.streamHandle);
|
||||
}
|
||||
if (this.in && free) {
|
||||
free(this.in);
|
||||
}
|
||||
if (this.out && free) {
|
||||
free(this.out);
|
||||
}
|
||||
controller.error(error);
|
||||
}
|
||||
},
|
||||
flush(controller) {
|
||||
try {
|
||||
const heap = new Uint8Array(memory.buffer);
|
||||
const process = this._process;
|
||||
const out = this.out;
|
||||
const scratch = this._scratch;
|
||||
while (true) {
|
||||
const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
|
||||
const produced = result & 0x00ffffff;
|
||||
const code = (result >> 24) & 0xff;
|
||||
if (!isCompress) {
|
||||
const signedCode = (code & 0x80) ? code - 256 : code;
|
||||
if (signedCode < 0) {
|
||||
throw new Error("process error:" + signedCode);
|
||||
}
|
||||
}
|
||||
if (produced) {
|
||||
scratch.set(heap.subarray(out, out + produced), 0);
|
||||
controller.enqueue(scratch.slice(0, produced));
|
||||
}
|
||||
if (code === 1 || produced === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
} finally {
|
||||
if (this._end && this.streamHandle) {
|
||||
const result = this._end(this.streamHandle);
|
||||
if (result !== 0) {
|
||||
controller.error(new Error("end error:" + result));
|
||||
}
|
||||
}
|
||||
if (this.in && free) {
|
||||
free(this.in);
|
||||
}
|
||||
if (this.out && free) {
|
||||
free(this.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export class CompressionStreamZlib {
|
||||
constructor(type = "deflate", options) {
|
||||
return _make(true, type, options);
|
||||
}
|
||||
}
|
||||
export class DecompressionStreamZlib {
|
||||
constructor(type = "deflate", options) {
|
||||
return _make(false, type, options);
|
||||
}
|
||||
}
|
||||
Generated
Vendored
Executable
BIN
Binary file not shown.
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TextDecoder */
|
||||
|
||||
const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
|
||||
const VALID_CP437 = CP437.length == 256;
|
||||
|
||||
export {
|
||||
decodeCP437
|
||||
};
|
||||
|
||||
function decodeCP437(stringValue) {
|
||||
if (VALID_CP437) {
|
||||
let result = "";
|
||||
for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) {
|
||||
result += CP437[stringValue[indexCharacter]];
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return new TextDecoder().decode(stringValue);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TextDecoder */
|
||||
|
||||
import { decodeCP437 } from "./decode-cp437.js";
|
||||
|
||||
export {
|
||||
decodeText
|
||||
};
|
||||
|
||||
function decodeText(value, encoding) {
|
||||
if (encoding && encoding.trim().toLowerCase() == "cp437") {
|
||||
return decodeCP437(value);
|
||||
} else {
|
||||
return new TextDecoder(encoding).decode(value);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const mimeTypes = {};
|
||||
|
||||
export {
|
||||
mimeTypes,
|
||||
getMimeType
|
||||
};
|
||||
|
||||
function getMimeType() {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global TextEncoder */
|
||||
|
||||
import { UNDEFINED_TYPE } from "../constants.js";
|
||||
|
||||
export {
|
||||
encodeText
|
||||
};
|
||||
|
||||
function encodeText(value) {
|
||||
// deno-lint-ignore valid-typeof
|
||||
if (typeof TextEncoder == UNDEFINED_TYPE) {
|
||||
value = unescape(encodeURIComponent(value));
|
||||
const result = new Uint8Array(value.length);
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
result[i] = value.charCodeAt(i);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return new TextEncoder().encode(value);
|
||||
}
|
||||
}
|
||||
+1637
File diff suppressed because it is too large
Load Diff
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const BASE64_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
export function base64Decode(b64) {
|
||||
b64 = String(b64).replace(/[^A-Za-z0-9+/=]/g, "");
|
||||
const len = b64.length;
|
||||
const out = [];
|
||||
for (let i = 0; i < len; i += 4) {
|
||||
const a = BASE64_TABLE.indexOf(b64[i]);
|
||||
const b = BASE64_TABLE.indexOf(b64[i + 1]);
|
||||
const c = BASE64_TABLE.indexOf(b64[i + 2]);
|
||||
const d = BASE64_TABLE.indexOf(b64[i + 3]);
|
||||
const n = (a << 18) | (b << 12) | ((c & 63) << 6) | (d & 63);
|
||||
out.push((n >> 16) & 0xff);
|
||||
if (b64[i + 2] !== "=") {
|
||||
out.push((n >> 8) & 0xff);
|
||||
}
|
||||
if (b64[i + 3] !== "=") {
|
||||
out.push(n & 0xff);
|
||||
}
|
||||
}
|
||||
return new Uint8Array(out);
|
||||
}
|
||||
|
||||
export function base64Encode(bytes) {
|
||||
let out = "";
|
||||
const len = bytes.length;
|
||||
let i = 0;
|
||||
for (; i + 2 < len; i += 3) {
|
||||
const n = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||
out += BASE64_TABLE[(n >> 18) & 63] + BASE64_TABLE[(n >> 12) & 63] + BASE64_TABLE[(n >> 6) & 63] + BASE64_TABLE[n & 63];
|
||||
}
|
||||
const rem = len - i;
|
||||
if (rem === 1) {
|
||||
const n = bytes[i] << 16;
|
||||
out += BASE64_TABLE[(n >> 18) & 63] + BASE64_TABLE[(n >> 12) & 63] + "==";
|
||||
} else if (rem === 2) {
|
||||
const n = (bytes[i] << 16) | (bytes[i + 1] << 8);
|
||||
out += BASE64_TABLE[(n >> 18) & 63] + BASE64_TABLE[(n >> 12) & 63] + BASE64_TABLE[(n >> 6) & 63] + "=";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export function decompress(src) {
|
||||
src = base64Decode(src);
|
||||
let out = new Uint8Array(1024);
|
||||
let outLen = 0;
|
||||
for (let i = 0; i < src.length;) {
|
||||
const ctrl = src[i++];
|
||||
if ((ctrl & 0x80) === 0) {
|
||||
const L = ctrl;
|
||||
ensure(outLen + L);
|
||||
for (let j = 0; j < L && i < src.length; j++) {
|
||||
out[outLen++] = src[i++];
|
||||
}
|
||||
} else {
|
||||
const L = (ctrl & 0x7f) + 3;
|
||||
const off = (src[i++] << 8) | src[i++];
|
||||
const start = outLen - off;
|
||||
ensure(outLen + L);
|
||||
for (let k = 0; k < L; k++) {
|
||||
out[outLen++] = out[start + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
const data = new Uint8Array(out.buffer.slice(0, outLen));
|
||||
return base64Encode(data);
|
||||
|
||||
function ensure(n) {
|
||||
if (out.length < n) {
|
||||
let nl = out.length * 2;
|
||||
while (nl < n) {
|
||||
nl *= 2;
|
||||
}
|
||||
const nbuf = new Uint8Array(nl);
|
||||
nbuf.set(out.subarray(0, outLen));
|
||||
out = nbuf;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function compress(input) {
|
||||
const src = new Uint8Array(input);
|
||||
const N = src.length;
|
||||
const out = [];
|
||||
const litBuf = [];
|
||||
const MAX_OFFSET = 0xffff;
|
||||
const MAX_MATCH = 130;
|
||||
const MAX_CANDIDATES = 64;
|
||||
const map = new Map();
|
||||
let i = 0;
|
||||
while (i < N) {
|
||||
let bestLen = 0, bestOff = 0;
|
||||
if (i + 2 < N) {
|
||||
const key = (src[i] << 16) | (src[i + 1] << 8) | src[i + 2];
|
||||
const cand = map.get(key) || [];
|
||||
for (let c = cand.length - 1; c >= 0; c--) {
|
||||
const j = cand[c];
|
||||
const off = i - j;
|
||||
if (off <= 0 || off > MAX_OFFSET) {
|
||||
continue;
|
||||
}
|
||||
let k = 0;
|
||||
while (k < MAX_MATCH && i + k < N && src[j + k] === src[i + k]) {
|
||||
k++;
|
||||
}
|
||||
if (k > bestLen && k >= 3) {
|
||||
bestLen = k; bestOff = off;
|
||||
if (bestLen === MAX_MATCH) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestLen >= 3) {
|
||||
if (litBuf.length) {
|
||||
flushLiterals();
|
||||
}
|
||||
let remain = bestLen;
|
||||
let produced = 0;
|
||||
while (remain > 0) {
|
||||
const take = Math.min(remain, MAX_MATCH);
|
||||
out.push(0x80 | ((take - 3) & 0x7f));
|
||||
out.push((bestOff >> 8) & 0xff);
|
||||
out.push(bestOff & 0xff);
|
||||
remain -= take;
|
||||
produced += take;
|
||||
}
|
||||
const start = i;
|
||||
for (let p = start; p < start + produced; p++) {
|
||||
addPos(p);
|
||||
}
|
||||
i += produced;
|
||||
} else {
|
||||
litBuf.push(src[i]);
|
||||
addPos(i);
|
||||
i++;
|
||||
if (litBuf.length === 127) {
|
||||
flushLiterals();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (litBuf.length) {
|
||||
flushLiterals();
|
||||
}
|
||||
const u8 = new Uint8Array(out);
|
||||
return base64Encode(u8);
|
||||
|
||||
function flushLiterals() {
|
||||
while (litBuf.length) {
|
||||
const take = Math.min(127, litBuf.length);
|
||||
out.push(take);
|
||||
for (let t = 0; t < take; t++) {
|
||||
out.push(litBuf.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPos(pos) {
|
||||
if (pos + 2 < N) {
|
||||
const key = (src[pos] << 16) | (src[pos + 1] << 8) | src[pos + 2];
|
||||
const arr = map.get(key) || [];
|
||||
arr.push(pos);
|
||||
if (arr.length > MAX_CANDIDATES) {
|
||||
arr.shift();
|
||||
}
|
||||
map.set(key, arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global self, addEventListener, postMessage, ReadableStream, WritableStream, AbortController */
|
||||
|
||||
import {
|
||||
CodecStream,
|
||||
ChunkStream,
|
||||
MESSAGE_EVENT_TYPE,
|
||||
MESSAGE_START,
|
||||
MESSAGE_PULL,
|
||||
MESSAGE_DATA,
|
||||
MESSAGE_ACK_DATA,
|
||||
MESSAGE_CLOSE
|
||||
} from "./streams/codec-stream.js";
|
||||
|
||||
const pendingPullMessages = new Map();
|
||||
const pendingDataMessages = new Map();
|
||||
|
||||
let abortController, messageId = 0;
|
||||
|
||||
addEventListener(MESSAGE_EVENT_TYPE, ({ data }) => {
|
||||
const { type, messageId, value, done } = data;
|
||||
try {
|
||||
if (type == MESSAGE_START) {
|
||||
init(data);
|
||||
}
|
||||
if (type == MESSAGE_DATA) {
|
||||
const resolve = pendingPullMessages.get(messageId);
|
||||
pendingPullMessages.delete(messageId);
|
||||
resolve({ value: new Uint8Array(value), done });
|
||||
}
|
||||
if (type == MESSAGE_ACK_DATA) {
|
||||
const resolve = pendingDataMessages.get(messageId);
|
||||
pendingDataMessages.delete(messageId);
|
||||
resolve();
|
||||
}
|
||||
if (type == MESSAGE_CLOSE) {
|
||||
abortController.abort();
|
||||
}
|
||||
} catch (error) {
|
||||
sendErrorMessage(error);
|
||||
}
|
||||
});
|
||||
|
||||
async function init(message) {
|
||||
let codecStream;
|
||||
try {
|
||||
const { options, config } = message;
|
||||
if (!options.useCompressionStream) {
|
||||
try {
|
||||
await self.initModule(message.config);
|
||||
} catch {
|
||||
options.useCompressionStream = true;
|
||||
}
|
||||
}
|
||||
config.CompressionStream = self.CompressionStream;
|
||||
config.DecompressionStream = self.DecompressionStream;
|
||||
const strategy = { highWaterMark: 1 };
|
||||
const readable = message.readable || new ReadableStream({
|
||||
async pull(controller) {
|
||||
const result = new Promise(resolve => pendingPullMessages.set(messageId, resolve));
|
||||
sendMessage({ type: MESSAGE_PULL, messageId });
|
||||
messageId = (messageId + 1) % Number.MAX_SAFE_INTEGER;
|
||||
const { value, done } = await result;
|
||||
controller.enqueue(value);
|
||||
if (done) {
|
||||
controller.close();
|
||||
}
|
||||
}
|
||||
}, strategy);
|
||||
const writable = message.writable || new WritableStream({
|
||||
async write(value) {
|
||||
let resolveAckData;
|
||||
const ackData = new Promise(resolve => resolveAckData = resolve);
|
||||
pendingDataMessages.set(messageId, resolveAckData);
|
||||
sendMessage({ type: MESSAGE_DATA, value, messageId });
|
||||
messageId = (messageId + 1) % Number.MAX_SAFE_INTEGER;
|
||||
await ackData;
|
||||
}
|
||||
}, strategy);
|
||||
const codecStream = new CodecStream(options, config);
|
||||
abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
await readable
|
||||
.pipeThrough(codecStream)
|
||||
.pipeThrough(new ChunkStream(config.chunkSize))
|
||||
.pipeTo(writable, { signal, preventClose: true, preventAbort: true });
|
||||
await writable.getWriter().close();
|
||||
const {
|
||||
signature,
|
||||
inputSize,
|
||||
outputSize
|
||||
} = codecStream;
|
||||
sendMessage({
|
||||
type: MESSAGE_CLOSE,
|
||||
result: {
|
||||
signature,
|
||||
inputSize,
|
||||
outputSize
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
error.outputSize = codecStream ? codecStream.outputSize : 0;
|
||||
sendErrorMessage(error);
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage(message) {
|
||||
let { value } = message;
|
||||
if (value) {
|
||||
if (value.length) {
|
||||
try {
|
||||
value = new Uint8Array(value);
|
||||
message.value = value.buffer;
|
||||
postMessage(message, [message.value]);
|
||||
} catch {
|
||||
postMessage(message);
|
||||
}
|
||||
} else {
|
||||
postMessage(message);
|
||||
}
|
||||
} else {
|
||||
postMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
function sendErrorMessage(error = new Error("Unknown error")) {
|
||||
const { message, stack, code, name, outputSize } = error;
|
||||
postMessage({ error: { message, stack, code, name, outputSize } });
|
||||
}
|
||||
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global Blob, URL, atob */
|
||||
/* eslint-disable quotes */
|
||||
import { decompress } from "./util/mini-lz.js";
|
||||
|
||||
export function configureWebWorker(configure) {
|
||||
const code = `__workerCode__`;
|
||||
configure({
|
||||
workerURI: (useBlobURI) => {
|
||||
const type = "text/javascript";
|
||||
const base64Source = decompress(code);
|
||||
if (useBlobURI) {
|
||||
const source = atob(base64Source);
|
||||
const blob = new Blob([source], { type });
|
||||
return URL.createObjectURL(blob);
|
||||
} else {
|
||||
return "data:" + type + ";base64," + base64Source;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global Blob, URL */
|
||||
/* eslint-disable quotes */
|
||||
|
||||
export function configureWebWorker(configure) {
|
||||
const code = `__workerCode__`;
|
||||
|
||||
configure({
|
||||
workerURI: (useBlobURI) => {
|
||||
const type = "text/javascript";
|
||||
if (useBlobURI) {
|
||||
const blob = new Blob([code], { type });
|
||||
return URL.createObjectURL(blob);
|
||||
} else {
|
||||
return "data:" + type + "," + encodeURIComponent(code);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
+1
File diff suppressed because one or more lines are too long
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global self */
|
||||
|
||||
import "./web-worker-base.js";
|
||||
import {
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib,
|
||||
} from "./streams/zlib-js/zlib-streams.min.js";
|
||||
|
||||
self.initModule = config => {
|
||||
config.CompressionStreamZlib = CompressionStreamZlib;
|
||||
config.DecompressionStreamZlib = DecompressionStreamZlib;
|
||||
};
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global self */
|
||||
|
||||
import "./web-worker-base.js";
|
||||
import {
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib,
|
||||
initModule as init
|
||||
} from "./streams/zlib-wasm/zlib-streams-loader.js";
|
||||
|
||||
self.initModule = async config => {
|
||||
try {
|
||||
const result = await init(config.wasmURI, config);
|
||||
config.CompressionStreamZlib = CompressionStreamZlib;
|
||||
config.DecompressionStreamZlib = DecompressionStreamZlib;
|
||||
return result;
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
};
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const PROPERTY_NAME_FILENAME = "filename";
|
||||
const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
|
||||
const PROPERTY_NAME_COMMENT = "comment";
|
||||
const PROPERTY_NAME_RAW_COMMENT = "rawComment";
|
||||
const PROPERTY_NAME_UNCOMPRESSED_SIZE = "uncompressedSize";
|
||||
const PROPERTY_NAME_COMPRESSED_SIZE = "compressedSize";
|
||||
const PROPERTY_NAME_OFFSET = "offset";
|
||||
const PROPERTY_NAME_DISK_NUMBER_START = "diskNumberStart";
|
||||
const PROPERTY_NAME_LAST_MODIFICATION_DATE = "lastModDate";
|
||||
const PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE = "rawLastModDate";
|
||||
const PROPERTY_NAME_LAST_ACCESS_DATE = "lastAccessDate";
|
||||
const PROPERTY_NAME_RAW_LAST_ACCESS_DATE = "rawLastAccessDate";
|
||||
const PROPERTY_NAME_CREATION_DATE = "creationDate";
|
||||
const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
|
||||
const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
|
||||
const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
|
||||
const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
|
||||
const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
|
||||
const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
|
||||
const PROPERTY_NAME_ZIP64 = "zip64";
|
||||
const PROPERTY_NAME_ENCRYPTED = "encrypted";
|
||||
const PROPERTY_NAME_VERSION = "version";
|
||||
const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
|
||||
const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
|
||||
const PROPERTY_NAME_DIRECTORY = "directory";
|
||||
const PROPERTY_NAME_EXECUTABLE = "executable";
|
||||
const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
|
||||
const PROPERTY_NAME_SIGNATURE = "signature";
|
||||
const PROPERTY_NAME_EXTRA_FIELD = "extraField";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_INFOZIP = "extraFieldInfoZip";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_UNIX = "extraFieldUnix";
|
||||
const PROPERTY_NAME_UID = "uid";
|
||||
const PROPERTY_NAME_GID = "gid";
|
||||
const PROPERTY_NAME_UNIX_MODE = "unixMode";
|
||||
const PROPERTY_NAME_SETUID = "setuid";
|
||||
const PROPERTY_NAME_SETGID = "setgid";
|
||||
const PROPERTY_NAME_STICKY = "sticky";
|
||||
const PROPERTY_NAME_BITFLAG = "bitFlag";
|
||||
const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
|
||||
const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
|
||||
const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_ZIP64 = "extraFieldZip64";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_UNICODE_PATH = "extraFieldUnicodePath";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_UNICODE_COMMENT = "extraFieldUnicodeComment";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_AES = "extraFieldAES";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_NTFS = "extraFieldNTFS";
|
||||
const PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP = "extraFieldExtendedTimestamp";
|
||||
|
||||
const PROPERTY_NAMES = [
|
||||
PROPERTY_NAME_FILENAME,
|
||||
PROPERTY_NAME_RAW_FILENAME,
|
||||
PROPERTY_NAME_UNCOMPRESSED_SIZE,
|
||||
PROPERTY_NAME_COMPRESSED_SIZE,
|
||||
PROPERTY_NAME_LAST_MODIFICATION_DATE,
|
||||
PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE,
|
||||
PROPERTY_NAME_COMMENT,
|
||||
PROPERTY_NAME_RAW_COMMENT,
|
||||
PROPERTY_NAME_LAST_ACCESS_DATE,
|
||||
PROPERTY_NAME_CREATION_DATE,
|
||||
PROPERTY_NAME_RAW_CREATION_DATE,
|
||||
PROPERTY_NAME_OFFSET,
|
||||
PROPERTY_NAME_DISK_NUMBER_START,
|
||||
PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
|
||||
PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
|
||||
PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
|
||||
PROPERTY_NAME_MSDOS_ATTRIBUTES,
|
||||
PROPERTY_NAME_MS_DOS_COMPATIBLE,
|
||||
PROPERTY_NAME_ZIP64,
|
||||
PROPERTY_NAME_ENCRYPTED,
|
||||
PROPERTY_NAME_VERSION,
|
||||
PROPERTY_NAME_VERSION_MADE_BY,
|
||||
PROPERTY_NAME_ZIPCRYPTO,
|
||||
PROPERTY_NAME_DIRECTORY,
|
||||
PROPERTY_NAME_EXECUTABLE,
|
||||
PROPERTY_NAME_COMPRESSION_METHOD,
|
||||
PROPERTY_NAME_SIGNATURE,
|
||||
PROPERTY_NAME_EXTRA_FIELD,
|
||||
PROPERTY_NAME_EXTRA_FIELD_UNIX,
|
||||
PROPERTY_NAME_EXTRA_FIELD_INFOZIP,
|
||||
PROPERTY_NAME_UID,
|
||||
PROPERTY_NAME_GID,
|
||||
PROPERTY_NAME_UNIX_MODE,
|
||||
PROPERTY_NAME_SETUID,
|
||||
PROPERTY_NAME_SETGID,
|
||||
PROPERTY_NAME_STICKY,
|
||||
PROPERTY_NAME_BITFLAG,
|
||||
PROPERTY_NAME_FILENAME_UTF8,
|
||||
PROPERTY_NAME_COMMENT_UTF8,
|
||||
PROPERTY_NAME_RAW_EXTRA_FIELD,
|
||||
PROPERTY_NAME_EXTRA_FIELD_ZIP64,
|
||||
PROPERTY_NAME_EXTRA_FIELD_UNICODE_PATH,
|
||||
PROPERTY_NAME_EXTRA_FIELD_UNICODE_COMMENT,
|
||||
PROPERTY_NAME_EXTRA_FIELD_AES,
|
||||
PROPERTY_NAME_EXTRA_FIELD_NTFS,
|
||||
PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP
|
||||
];
|
||||
|
||||
class Entry {
|
||||
|
||||
constructor(data) {
|
||||
PROPERTY_NAMES.forEach(name => this[name] = data[name]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
PROPERTY_NAME_FILENAME,
|
||||
PROPERTY_NAME_RAW_FILENAME,
|
||||
PROPERTY_NAME_COMMENT,
|
||||
PROPERTY_NAME_RAW_COMMENT,
|
||||
PROPERTY_NAME_UNCOMPRESSED_SIZE,
|
||||
PROPERTY_NAME_COMPRESSED_SIZE,
|
||||
PROPERTY_NAME_OFFSET,
|
||||
PROPERTY_NAME_DISK_NUMBER_START,
|
||||
PROPERTY_NAME_LAST_MODIFICATION_DATE,
|
||||
PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE,
|
||||
PROPERTY_NAME_LAST_ACCESS_DATE,
|
||||
PROPERTY_NAME_RAW_LAST_ACCESS_DATE,
|
||||
PROPERTY_NAME_CREATION_DATE,
|
||||
PROPERTY_NAME_RAW_CREATION_DATE,
|
||||
PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
|
||||
PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
|
||||
PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
|
||||
PROPERTY_NAME_MSDOS_ATTRIBUTES,
|
||||
PROPERTY_NAME_MS_DOS_COMPATIBLE,
|
||||
PROPERTY_NAME_ZIP64,
|
||||
PROPERTY_NAME_ENCRYPTED,
|
||||
PROPERTY_NAME_VERSION,
|
||||
PROPERTY_NAME_VERSION_MADE_BY,
|
||||
PROPERTY_NAME_ZIPCRYPTO,
|
||||
PROPERTY_NAME_DIRECTORY,
|
||||
PROPERTY_NAME_EXECUTABLE,
|
||||
PROPERTY_NAME_COMPRESSION_METHOD,
|
||||
PROPERTY_NAME_SIGNATURE,
|
||||
PROPERTY_NAME_EXTRA_FIELD,
|
||||
PROPERTY_NAME_GID,
|
||||
PROPERTY_NAME_UID,
|
||||
PROPERTY_NAME_UNIX_MODE,
|
||||
PROPERTY_NAME_SETUID,
|
||||
PROPERTY_NAME_SETGID,
|
||||
PROPERTY_NAME_STICKY,
|
||||
Entry
|
||||
};
|
||||
+895
@@ -0,0 +1,895 @@
|
||||
/*
|
||||
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* global WritableStream */
|
||||
// deno-lint-ignore-file no-this-alias
|
||||
|
||||
import {
|
||||
initStream,
|
||||
Reader,
|
||||
TextReader,
|
||||
TextWriter,
|
||||
Data64URIReader,
|
||||
Data64URIWriter,
|
||||
Uint8ArrayReader,
|
||||
Uint8ArrayWriter,
|
||||
BlobReader,
|
||||
BlobWriter,
|
||||
HttpReader
|
||||
} from "./io.js";
|
||||
import {
|
||||
ZipReader,
|
||||
ERR_INVALID_PASSWORD
|
||||
} from "./zip-reader.js";
|
||||
import {
|
||||
ZipWriter
|
||||
} from "./zip-writer.js";
|
||||
import {
|
||||
Entry
|
||||
} from "./zip-entry.js";
|
||||
import { UNDEFINED_VALUE } from "./constants.js";
|
||||
|
||||
class ZipEntry {
|
||||
|
||||
constructor(fs, name, params, parent) {
|
||||
const zipEntry = this;
|
||||
if (fs.root && parent && parent.getChildByName(name)) {
|
||||
throw new Error("Entry filename already exists");
|
||||
}
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
Object.assign(zipEntry, {
|
||||
fs,
|
||||
name,
|
||||
data: params.data,
|
||||
options: params.options,
|
||||
id: fs.entries.length,
|
||||
parent,
|
||||
children: [],
|
||||
uncompressedSize: params.uncompressedSize || 0,
|
||||
passThrough: params.passThrough
|
||||
});
|
||||
fs.entries.push(zipEntry);
|
||||
if (parent) {
|
||||
zipEntry.parent.children.push(zipEntry);
|
||||
}
|
||||
}
|
||||
|
||||
moveTo(target) {
|
||||
// deprecated
|
||||
const zipEntry = this;
|
||||
zipEntry.fs.move(zipEntry, target);
|
||||
}
|
||||
|
||||
getFullname() {
|
||||
return this.getRelativeName();
|
||||
}
|
||||
|
||||
getRelativeName(ancestor = this.fs.root) {
|
||||
const zipEntry = this;
|
||||
let relativeName = zipEntry.name;
|
||||
let entry = zipEntry.parent;
|
||||
while (entry && entry != ancestor) {
|
||||
relativeName = (entry.name ? entry.name + "/" : "") + relativeName;
|
||||
entry = entry.parent;
|
||||
}
|
||||
return relativeName;
|
||||
}
|
||||
|
||||
isDescendantOf(ancestor) {
|
||||
let entry = this.parent;
|
||||
while (entry && entry.id != ancestor.id) {
|
||||
entry = entry.parent;
|
||||
}
|
||||
return Boolean(entry);
|
||||
}
|
||||
|
||||
rename(name) {
|
||||
const parent = this.parent;
|
||||
if (parent && parent.getChildByName(name)) {
|
||||
throw new Error("Entry filename already exists");
|
||||
} else {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ZipFileEntry extends ZipEntry {
|
||||
|
||||
constructor(fs, name, params, parent) {
|
||||
super(fs, name, params, parent);
|
||||
const zipEntry = this;
|
||||
zipEntry.Reader = params.Reader;
|
||||
zipEntry.Writer = params.Writer;
|
||||
if (params.getData) {
|
||||
zipEntry.getData = params.getData;
|
||||
}
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new ZipFileEntry(this.fs, this.name, this);
|
||||
}
|
||||
|
||||
async getData(writer, options = {}) {
|
||||
const zipEntry = this;
|
||||
if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
|
||||
return zipEntry.data;
|
||||
} else {
|
||||
const reader = zipEntry.reader = new zipEntry.Reader(zipEntry.data, options);
|
||||
const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
|
||||
await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
|
||||
const { readable } = reader;
|
||||
zipEntry.uncompressedSize = reader.size;
|
||||
await readable.pipeTo(writer.writable);
|
||||
return writer.getData ? writer.getData() : writer.writable;
|
||||
}
|
||||
}
|
||||
|
||||
isPasswordProtected() {
|
||||
return this.data.encrypted;
|
||||
}
|
||||
|
||||
async checkPassword(password, options = {}) {
|
||||
const zipEntry = this;
|
||||
if (zipEntry.isPasswordProtected()) {
|
||||
options.password = password;
|
||||
options.checkPasswordOnly = true;
|
||||
try {
|
||||
await zipEntry.data.getData(null, options);
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error.message == ERR_INVALID_PASSWORD) {
|
||||
return false;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
getText(encoding, options) {
|
||||
return this.getData(new TextWriter(encoding), options);
|
||||
}
|
||||
|
||||
getBlob(mimeType, options) {
|
||||
return this.getData(new BlobWriter(mimeType), options);
|
||||
}
|
||||
|
||||
getData64URI(mimeType, options) {
|
||||
return this.getData(new Data64URIWriter(mimeType), options);
|
||||
}
|
||||
|
||||
getUint8Array(options) {
|
||||
return this.getData(new Uint8ArrayWriter(), options);
|
||||
}
|
||||
|
||||
getWritable(writable = new WritableStream(), options) {
|
||||
return this.getData({ writable }, options);
|
||||
}
|
||||
|
||||
getArrayBuffer(options) {
|
||||
return this.data.arrayBuffer(options);
|
||||
}
|
||||
|
||||
replaceBlob(blob) {
|
||||
Object.assign(this, {
|
||||
data: blob,
|
||||
Reader: BlobReader,
|
||||
Writer: BlobWriter,
|
||||
reader: null
|
||||
});
|
||||
}
|
||||
|
||||
replaceText(text) {
|
||||
Object.assign(this, {
|
||||
data: text,
|
||||
Reader: TextReader,
|
||||
Writer: TextWriter,
|
||||
reader: null
|
||||
});
|
||||
}
|
||||
|
||||
replaceData64URI(dataURI) {
|
||||
Object.assign(this, {
|
||||
data: dataURI,
|
||||
Reader: Data64URIReader,
|
||||
Writer: Data64URIWriter,
|
||||
reader: null
|
||||
});
|
||||
}
|
||||
|
||||
replaceUint8Array(array) {
|
||||
Object.assign(this, {
|
||||
data: array,
|
||||
Reader: Uint8ArrayReader,
|
||||
Writer: Uint8ArrayWriter,
|
||||
reader: null
|
||||
});
|
||||
}
|
||||
|
||||
replaceReadable(readable) {
|
||||
Object.assign(this, {
|
||||
data: null,
|
||||
Reader: function () { return { readable }; },
|
||||
Writer: null,
|
||||
reader: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ZipDirectoryEntry extends ZipEntry {
|
||||
|
||||
constructor(fs, name, params, parent) {
|
||||
super(fs, name, params, parent);
|
||||
this.directory = true;
|
||||
}
|
||||
|
||||
clone(deepClone) {
|
||||
const zipEntry = this;
|
||||
const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name);
|
||||
if (deepClone) {
|
||||
clonedEntry.children = zipEntry.children.map(child => {
|
||||
const childClone = child.clone(deepClone);
|
||||
childClone.parent = clonedEntry;
|
||||
return childClone;
|
||||
});
|
||||
}
|
||||
return clonedEntry;
|
||||
}
|
||||
|
||||
addDirectory(name, options) {
|
||||
return addChild(this, name, { options }, true);
|
||||
}
|
||||
|
||||
addText(name, text, options = {}) {
|
||||
return addChild(this, name, {
|
||||
data: text,
|
||||
Reader: TextReader,
|
||||
Writer: TextWriter,
|
||||
options,
|
||||
uncompressedSize: text.length
|
||||
});
|
||||
}
|
||||
|
||||
addBlob(name, blob, options = {}) {
|
||||
return addChild(this, name, {
|
||||
data: blob,
|
||||
Reader: BlobReader,
|
||||
Writer: BlobWriter,
|
||||
options,
|
||||
uncompressedSize: blob.size
|
||||
});
|
||||
}
|
||||
|
||||
addData64URI(name, dataURI, options = {}) {
|
||||
let dataEnd = dataURI.length;
|
||||
while (dataURI.charAt(dataEnd - 1) == "=") {
|
||||
dataEnd--;
|
||||
}
|
||||
const dataStart = dataURI.indexOf(",") + 1;
|
||||
return addChild(this, name, {
|
||||
data: dataURI,
|
||||
Reader: Data64URIReader,
|
||||
Writer: Data64URIWriter,
|
||||
options,
|
||||
uncompressedSize: Math.floor((dataEnd - dataStart) * 0.75)
|
||||
});
|
||||
}
|
||||
|
||||
addUint8Array(name, array, options = {}) {
|
||||
return addChild(this, name, {
|
||||
data: array,
|
||||
Reader: Uint8ArrayReader,
|
||||
Writer: Uint8ArrayWriter,
|
||||
options,
|
||||
uncompressedSize: array.length
|
||||
});
|
||||
}
|
||||
|
||||
addHttpContent(name, url, options = {}) {
|
||||
return addChild(this, name, {
|
||||
data: url,
|
||||
Reader: class extends HttpReader {
|
||||
constructor(url) {
|
||||
super(url, options);
|
||||
}
|
||||
},
|
||||
options
|
||||
});
|
||||
}
|
||||
|
||||
addReadable(name, readable, options = {}) {
|
||||
return addChild(this, name, {
|
||||
Reader: function () { return { readable }; },
|
||||
options
|
||||
});
|
||||
}
|
||||
|
||||
addFileSystemEntry(fileSystemEntry, options = {}) {
|
||||
return addFileSystemHandle(this, fileSystemEntry, options);
|
||||
}
|
||||
|
||||
addFileSystemHandle(handle, options = {}) {
|
||||
return addFileSystemHandle(this, handle, options);
|
||||
}
|
||||
|
||||
addFile(file, options = {}) {
|
||||
if (!options.lastModDate) {
|
||||
options.lastModDate = new Date(file.lastModified);
|
||||
}
|
||||
return addChild(this, file.name, {
|
||||
data: file,
|
||||
Reader: function () {
|
||||
const readable = file.stream();
|
||||
const size = file.size;
|
||||
return { readable, size };
|
||||
},
|
||||
options,
|
||||
uncompressedSize: file.size
|
||||
});
|
||||
}
|
||||
|
||||
addData(name, params) {
|
||||
return addChild(this, name, params);
|
||||
}
|
||||
|
||||
importBlob(blob, options) {
|
||||
return this.importZip(new BlobReader(blob), options);
|
||||
}
|
||||
|
||||
importData64URI(dataURI, options) {
|
||||
return this.importZip(new Data64URIReader(dataURI), options);
|
||||
}
|
||||
|
||||
importUint8Array(array, options) {
|
||||
return this.importZip(new Uint8ArrayReader(array), options);
|
||||
}
|
||||
|
||||
importHttpContent(url, options) {
|
||||
return this.importZip(new HttpReader(url, options), options);
|
||||
}
|
||||
|
||||
importReadable(readable, options) {
|
||||
return this.importZip({ readable }, options);
|
||||
}
|
||||
|
||||
exportBlob(options = {}) {
|
||||
return this.exportZip(new BlobWriter(options.mimeType || "application/zip"), options);
|
||||
}
|
||||
|
||||
exportData64URI(options = {}) {
|
||||
return this.exportZip(new Data64URIWriter(options.mimeType || "application/zip"), options);
|
||||
}
|
||||
|
||||
exportUint8Array(options = {}) {
|
||||
return this.exportZip(new Uint8ArrayWriter(), options);
|
||||
}
|
||||
|
||||
async exportWritable(writable = new WritableStream(), options = {}) {
|
||||
await this.exportZip({ writable }, options);
|
||||
return writable;
|
||||
}
|
||||
|
||||
async importZip(reader, options = {}) {
|
||||
await initStream(reader);
|
||||
const zipReader = new ZipReader(reader, options);
|
||||
const importedEntries = [];
|
||||
const entries = await zipReader.getEntries();
|
||||
for (const entry of entries) {
|
||||
let parent = this;
|
||||
try {
|
||||
const path = entry.filename.split("/");
|
||||
const name = path.pop();
|
||||
path.forEach((pathPart, pathIndex) => {
|
||||
const previousParent = parent;
|
||||
parent = parent.getChildByName(pathPart);
|
||||
if (!parent) {
|
||||
parent = new ZipDirectoryEntry(this.fs, pathPart, { data: pathIndex == path.length - 1 ? entry : null }, previousParent);
|
||||
importedEntries.push(parent);
|
||||
}
|
||||
});
|
||||
if (!entry.directory) {
|
||||
importedEntries.push(addChild(parent, name, {
|
||||
data: entry,
|
||||
Reader: getZipBlobReader(Object.assign({}, options)),
|
||||
uncompressedSize: entry.uncompressedSize,
|
||||
passThrough: options.passThrough
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
error.cause = {
|
||||
entry
|
||||
};
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return importedEntries;
|
||||
}
|
||||
|
||||
async exportZip(writer, options) {
|
||||
const zipEntry = this;
|
||||
if (options.bufferedWrite === UNDEFINED_VALUE) {
|
||||
options.bufferedWrite = true;
|
||||
}
|
||||
await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
|
||||
const zipWriter = new ZipWriter(writer, options);
|
||||
await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
|
||||
await zipWriter.close();
|
||||
return writer.getData ? writer.getData() : writer.writable;
|
||||
}
|
||||
|
||||
getChildByName(name) {
|
||||
const children = this.children;
|
||||
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
||||
const child = children[childIndex];
|
||||
if (child.name == name) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isPasswordProtected() {
|
||||
const children = this.children;
|
||||
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
||||
const child = children[childIndex];
|
||||
if (child.isPasswordProtected()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async checkPassword(password, options = {}) {
|
||||
const children = this.children;
|
||||
const result = await Promise.all(children.map(child => child.checkPassword(password, options)));
|
||||
return !result.includes(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FS {
|
||||
|
||||
constructor() {
|
||||
resetFS(this);
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this.root.children;
|
||||
}
|
||||
|
||||
remove(entry) {
|
||||
detach(entry);
|
||||
this.entries[entry.id] = null;
|
||||
}
|
||||
|
||||
move(entry, destination) {
|
||||
if (entry == this.root) {
|
||||
throw new Error("Root directory cannot be moved");
|
||||
} else {
|
||||
if (destination.directory) {
|
||||
if (!destination.isDescendantOf(entry)) {
|
||||
if (entry != destination) {
|
||||
if (destination.getChildByName(entry.name)) {
|
||||
throw new Error("Entry filename already exists");
|
||||
}
|
||||
detach(entry);
|
||||
entry.parent = destination;
|
||||
destination.children.push(entry);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Entry is a ancestor of target entry");
|
||||
}
|
||||
} else {
|
||||
throw new Error("Target entry is not a directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
find(fullname) {
|
||||
const path = fullname.split("/");
|
||||
let node = this.root;
|
||||
for (let index = 0; node && index < path.length; index++) {
|
||||
node = node.getChildByName(path[index]);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
getById(id) {
|
||||
return this.entries[id];
|
||||
}
|
||||
|
||||
getChildByName(name) {
|
||||
return this.root.getChildByName(name);
|
||||
}
|
||||
|
||||
addDirectory(name, options) {
|
||||
return this.root.addDirectory(name, options);
|
||||
}
|
||||
|
||||
addText(name, text, options) {
|
||||
return this.root.addText(name, text, options);
|
||||
}
|
||||
|
||||
addBlob(name, blob, options) {
|
||||
return this.root.addBlob(name, blob, options);
|
||||
}
|
||||
|
||||
addData64URI(name, dataURI, options) {
|
||||
return this.root.addData64URI(name, dataURI, options);
|
||||
}
|
||||
|
||||
addUint8Array(name, array, options) {
|
||||
return this.root.addUint8Array(name, array, options);
|
||||
}
|
||||
|
||||
addHttpContent(name, url, options) {
|
||||
return this.root.addHttpContent(name, url, options);
|
||||
}
|
||||
|
||||
addReadable(name, readable, options) {
|
||||
return this.root.addReadable(name, readable, options);
|
||||
}
|
||||
|
||||
addFileSystemEntry(fileSystemEntry, options) {
|
||||
return this.root.addFileSystemEntry(fileSystemEntry, options);
|
||||
}
|
||||
|
||||
addFileSystemHandle(handle, options) {
|
||||
return this.root.addFileSystemHandle(handle, options);
|
||||
}
|
||||
|
||||
addFile(file, options) {
|
||||
return this.root.addFile(file, options);
|
||||
}
|
||||
|
||||
addData(name, params) {
|
||||
return this.root.addData(name, params);
|
||||
}
|
||||
|
||||
importBlob(blob, options) {
|
||||
resetFS(this);
|
||||
return this.root.importBlob(blob, options);
|
||||
}
|
||||
|
||||
importData64URI(dataURI, options) {
|
||||
resetFS(this);
|
||||
return this.root.importData64URI(dataURI, options);
|
||||
}
|
||||
|
||||
importUint8Array(array, options) {
|
||||
resetFS(this);
|
||||
return this.root.importUint8Array(array, options);
|
||||
}
|
||||
|
||||
importHttpContent(url, options) {
|
||||
resetFS(this);
|
||||
return this.root.importHttpContent(url, options);
|
||||
}
|
||||
|
||||
importReadable(readable, options) {
|
||||
resetFS(this);
|
||||
return this.root.importReadable(readable, options);
|
||||
}
|
||||
|
||||
importZip(reader, options) {
|
||||
return this.root.importZip(reader, options);
|
||||
}
|
||||
|
||||
exportBlob(options) {
|
||||
return this.root.exportBlob(options);
|
||||
}
|
||||
|
||||
exportData64URI(options) {
|
||||
return this.root.exportData64URI(options);
|
||||
}
|
||||
|
||||
exportUint8Array(options) {
|
||||
return this.root.exportUint8Array(options);
|
||||
}
|
||||
|
||||
exportWritable(writable, options) {
|
||||
return this.root.exportWritable(writable, options);
|
||||
}
|
||||
|
||||
isPasswordProtected() {
|
||||
return this.root.isPasswordProtected();
|
||||
}
|
||||
|
||||
checkPassword(password, options) {
|
||||
return this.root.checkPassword(password, options);
|
||||
}
|
||||
}
|
||||
|
||||
const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
|
||||
export { fs };
|
||||
|
||||
function getTotalSize(entries, propertyName) {
|
||||
let size = 0;
|
||||
entries.forEach(process);
|
||||
return size;
|
||||
|
||||
function process(entry) {
|
||||
size += entry[propertyName];
|
||||
if (entry.children) {
|
||||
entry.children.forEach(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getZipBlobReader(options) {
|
||||
return class extends Reader {
|
||||
|
||||
constructor(entry, options = {}) {
|
||||
super();
|
||||
this.entry = entry;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
async init() {
|
||||
const zipBlobReader = this;
|
||||
zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
|
||||
const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
|
||||
zipBlobReader.data = data;
|
||||
zipBlobReader.blobReader = new BlobReader(data);
|
||||
super.init();
|
||||
}
|
||||
|
||||
readUint8Array(index, length) {
|
||||
return this.blobReader.readUint8Array(index, length);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function initReaders(entry, options) {
|
||||
if (entry.children.length) {
|
||||
await Promise.all(entry.children.map(async child => {
|
||||
if (child.directory) {
|
||||
await initReaders(child, options);
|
||||
} else {
|
||||
const reader = child.reader = new child.Reader(child.data, options);
|
||||
try {
|
||||
await initStream(reader);
|
||||
} catch (error) {
|
||||
try {
|
||||
error.entryId = child.id;
|
||||
error.cause = {
|
||||
entry: child
|
||||
};
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
child.uncompressedSize = reader.size;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function detach(entry) {
|
||||
if (entry.parent) {
|
||||
const children = entry.parent.children;
|
||||
children.forEach((child, index) => {
|
||||
if (child.id == entry.id) {
|
||||
children.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function exportZip(zipWriter, entry, totalSize, options) {
|
||||
const selectedEntry = entry;
|
||||
const entryOffsets = new Map();
|
||||
await process(zipWriter, entry);
|
||||
|
||||
async function process(zipWriter, entry) {
|
||||
await exportChild();
|
||||
|
||||
async function exportChild() {
|
||||
if (options.bufferedWrite) {
|
||||
await Promise.allSettled(entry.children.map(processChild));
|
||||
} else {
|
||||
for (const child of entry.children) {
|
||||
await processChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processChild(child) {
|
||||
const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
|
||||
const childOptions = child.options || {};
|
||||
let zipEntryOptions = {};
|
||||
if (child.data instanceof Entry) {
|
||||
const {
|
||||
externalFileAttributes,
|
||||
versionMadeBy,
|
||||
comment,
|
||||
lastModDate,
|
||||
creationDate,
|
||||
lastAccessDate,
|
||||
uncompressedSize,
|
||||
encrypted,
|
||||
zipCrypto,
|
||||
signature,
|
||||
compressionMethod,
|
||||
extraFieldAES
|
||||
} = child.data;
|
||||
zipEntryOptions = {
|
||||
externalFileAttributes,
|
||||
versionMadeBy,
|
||||
comment,
|
||||
lastModDate,
|
||||
creationDate,
|
||||
lastAccessDate
|
||||
};
|
||||
if (child.passThrough) {
|
||||
let level, encryptionStrength;
|
||||
if (compressionMethod === 0) {
|
||||
level = 0;
|
||||
}
|
||||
if (extraFieldAES) {
|
||||
encryptionStrength = extraFieldAES.strength;
|
||||
}
|
||||
zipEntryOptions = Object.assign(zipEntryOptions, {
|
||||
passThrough: true,
|
||||
encrypted,
|
||||
zipCrypto,
|
||||
signature,
|
||||
uncompressedSize,
|
||||
level,
|
||||
encryptionStrength,
|
||||
compressionMethod
|
||||
});
|
||||
}
|
||||
}
|
||||
await zipWriter.add(name, child.reader, Object.assign({}, options, zipEntryOptions, childOptions, {
|
||||
directory: child.directory,
|
||||
onprogress: async indexProgress => {
|
||||
if (options.onprogress) {
|
||||
entryOffsets.set(name, indexProgress);
|
||||
try {
|
||||
await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
await process(zipWriter, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addFileSystemHandle(zipEntry, handle, options) {
|
||||
return addFile(zipEntry, handle, []);
|
||||
|
||||
async function addFile(parentEntry, handle, addedEntries) {
|
||||
if (handle) {
|
||||
try {
|
||||
if (handle.isFile || handle.isDirectory) {
|
||||
handle = await transformToFileSystemhandle(handle);
|
||||
}
|
||||
if (handle.kind == "file") {
|
||||
const file = await handle.getFile();
|
||||
addedEntries.push(
|
||||
parentEntry.addData(file.name, {
|
||||
Reader: function () {
|
||||
const readable = file.stream();
|
||||
const size = file.size;
|
||||
return { readable, size };
|
||||
},
|
||||
options: Object.assign({}, { lastModDate: new Date(file.lastModified) }, options),
|
||||
uncompressedSize: file.size
|
||||
})
|
||||
);
|
||||
} else if (handle.kind == "directory") {
|
||||
const directoryEntry = parentEntry.addDirectory(handle.name);
|
||||
addedEntries.push(directoryEntry);
|
||||
for await (const childHandle of handle.values()) {
|
||||
await addFile(directoryEntry, childHandle, addedEntries);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error.message + (handle ? " (" + handle.name + ")" : "");
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
return addedEntries;
|
||||
}
|
||||
}
|
||||
|
||||
async function transformToFileSystemhandle(entry) {
|
||||
const handle = {
|
||||
name: entry.name
|
||||
};
|
||||
if (entry.isFile) {
|
||||
handle.kind = "file";
|
||||
handle.getFile = () =>
|
||||
new Promise((resolve, reject) => entry.file(resolve, reject));
|
||||
}
|
||||
if (entry.isDirectory) {
|
||||
handle.kind = "directory";
|
||||
const handles = await transformToFileSystemhandles(entry);
|
||||
handle.values = () => handles;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
async function transformToFileSystemhandles(entry) {
|
||||
const entries = [];
|
||||
function readEntries(directoryReader, resolve, reject) {
|
||||
directoryReader.readEntries(async (entriesPart) => {
|
||||
if (!entriesPart.length) {
|
||||
resolve(entries);
|
||||
} else {
|
||||
for (const entry of entriesPart) {
|
||||
entries.push(await transformToFileSystemhandle(entry));
|
||||
}
|
||||
readEntries(directoryReader, resolve, reject);
|
||||
}
|
||||
}, reject);
|
||||
}
|
||||
await new Promise((resolve, reject) =>
|
||||
readEntries(entry.createReader(), resolve, reject)
|
||||
);
|
||||
return {
|
||||
[Symbol.iterator]() {
|
||||
let entryIndex = 0;
|
||||
return {
|
||||
next() {
|
||||
const result = {
|
||||
value: entries[entryIndex],
|
||||
done: entryIndex == entries.length
|
||||
};
|
||||
entryIndex++;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function resetFS(fs) {
|
||||
fs.entries = [];
|
||||
fs.root = new ZipDirectoryEntry(fs);
|
||||
}
|
||||
|
||||
function addChild(parent, name, params, directory) {
|
||||
if (parent.directory) {
|
||||
return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
|
||||
} else {
|
||||
throw new Error("Parent entry is not a directory");
|
||||
}
|
||||
}
|
||||
+1009
File diff suppressed because it is too large
Load Diff
+1722
File diff suppressed because it is too large
Load Diff
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* eslint-disable quotes */
|
||||
|
||||
import { decompress } from "./util/mini-lz.js";
|
||||
|
||||
export function configureZlibModule(configure) {
|
||||
const data = `__wasmBinary__`;
|
||||
let dataURI;
|
||||
configure({
|
||||
wasmURI: () => {
|
||||
if (!dataURI) {
|
||||
dataURI = "data:application/wasm;base64," + decompress(data);
|
||||
}
|
||||
return dataURI;
|
||||
}
|
||||
});
|
||||
}
|
||||
+1
File diff suppressed because one or more lines are too long
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
|
||||
try {
|
||||
configure({ baseURI: import.meta.url });
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
|
||||
export * from "./zip-core-reader.js";
|
||||
export * from "./zip-core-writer.js";
|
||||
export {
|
||||
Reader,
|
||||
Writer,
|
||||
TextReader,
|
||||
TextWriter,
|
||||
Data64URIReader,
|
||||
Data64URIWriter,
|
||||
BlobReader,
|
||||
BlobWriter,
|
||||
HttpReader,
|
||||
HttpRangeReader,
|
||||
Uint8ArrayWriter,
|
||||
Uint8ArrayReader,
|
||||
SplitDataReader,
|
||||
SplitDataWriter,
|
||||
ERR_HTTP_RANGE
|
||||
} from "./core/io.js";
|
||||
export {
|
||||
getMimeType
|
||||
} from "./core/util/default-mime-type.js";
|
||||
export {
|
||||
configure
|
||||
} from "./core/configuration.js";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./zip-core-base.js";
|
||||
export * from "./zip-module-native.js";
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export {
|
||||
ZipReader,
|
||||
ZipReaderStream,
|
||||
ERR_BAD_FORMAT,
|
||||
ERR_EOCDR_NOT_FOUND,
|
||||
ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND,
|
||||
ERR_CENTRAL_DIRECTORY_NOT_FOUND,
|
||||
ERR_LOCAL_FILE_HEADER_NOT_FOUND,
|
||||
ERR_EXTRAFIELD_ZIP64_NOT_FOUND,
|
||||
ERR_ENCRYPTED,
|
||||
ERR_UNSUPPORTED_ENCRYPTION,
|
||||
ERR_UNSUPPORTED_COMPRESSION,
|
||||
ERR_INVALID_SIGNATURE,
|
||||
ERR_INVALID_UNCOMPRESSED_SIZE,
|
||||
ERR_INVALID_PASSWORD,
|
||||
ERR_SPLIT_ZIP_FILE,
|
||||
ERR_OVERLAPPING_ENTRY
|
||||
} from "./core/zip-reader.js";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./zip-core-base.js";
|
||||
export * from "./zip-module-wasm.js";
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export {
|
||||
ZipWriter,
|
||||
ZipWriterStream,
|
||||
ERR_DUPLICATED_NAME,
|
||||
ERR_INVALID_COMMENT,
|
||||
ERR_INVALID_ENTRY_NAME,
|
||||
ERR_INVALID_ENTRY_COMMENT,
|
||||
ERR_INVALID_VERSION,
|
||||
ERR_INVALID_EXTRAFIELD_TYPE,
|
||||
ERR_INVALID_EXTRAFIELD_DATA,
|
||||
ERR_INVALID_ENCRYPTION_STRENGTH,
|
||||
ERR_UNSUPPORTED_FORMAT,
|
||||
ERR_UNDEFINED_UNCOMPRESSED_SIZE,
|
||||
ERR_ZIP_NOT_EMPTY
|
||||
} from "./core/zip-writer.js";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./zip-core-base.js";
|
||||
export { terminateWorkers } from "./core/codec-pool.js";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./zip-core-native.js";
|
||||
export * from "./core/zip-fs.js";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
export * from "./zip-core-wasm.js";
|
||||
export * from "./core/zip-fs.js";
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureWebWorker } from "./core/web-worker-inline-native.js";
|
||||
|
||||
configureWebWorker(configure);
|
||||
|
||||
export * from "./zip-fs-core-native.js";
|
||||
export { getMimeType } from "./core/util/mime-type.js";
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureWebWorker } from "./core/web-worker-inline-wasm.js";
|
||||
|
||||
configureWebWorker(configure);
|
||||
|
||||
export * from "./zip-fs-core-wasm.js";
|
||||
export { getMimeType } from "./core/util/mime-type.js";
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureWebWorker } from "./core/web-worker-inline-native.js";
|
||||
|
||||
configureWebWorker(configure);
|
||||
|
||||
export * from "./zip-core-base.js";
|
||||
export { terminateWorkers } from "./core/codec-pool.js";
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { CompressionStreamZlib, DecompressionStreamZlib } from "./core/streams/zlib-js/zlib-streams.min.js";
|
||||
|
||||
configure({
|
||||
workerURI: "./core/web-worker-native.js",
|
||||
wasmURI: null,
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib
|
||||
});
|
||||
|
||||
export { terminateWorkers } from "./core/codec-pool.js";
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { FUNCTION_TYPE } from "./core/constants.js";
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureZlibModule } from "./core/zlib-streams-inline.js";
|
||||
import { configureWorker } from "./core/codec-worker.js";
|
||||
import { terminateWorkers } from "./core/codec-pool.js";
|
||||
import { initModule, resetWasmModule, CompressionStreamZlib, DecompressionStreamZlib } from "./core/streams/zlib-wasm/zlib-streams-loader.js";
|
||||
|
||||
let modulePromise;
|
||||
|
||||
configureZlibModule(configure);
|
||||
configureWorker({
|
||||
initModule: config => {
|
||||
if (!modulePromise) {
|
||||
let { wasmURI } = config;
|
||||
// deno-lint-ignore valid-typeof
|
||||
if (typeof wasmURI == FUNCTION_TYPE) {
|
||||
wasmURI = wasmURI();
|
||||
}
|
||||
modulePromise = initModule(wasmURI, config);
|
||||
|
||||
}
|
||||
return modulePromise;
|
||||
}
|
||||
});
|
||||
configure({
|
||||
CompressionStreamZlib,
|
||||
DecompressionStreamZlib
|
||||
});
|
||||
|
||||
export { terminateWorkersAndModule as terminateWorkers };
|
||||
|
||||
function terminateWorkersAndModule() {
|
||||
modulePromise = null;
|
||||
terminateWorkers();
|
||||
resetWasmModule();
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureWebWorker } from "./core/web-worker-inline-native.js";
|
||||
|
||||
configureWebWorker(configure);
|
||||
|
||||
export * from "./zip-core-native.js";
|
||||
export * from "./zip-module-native.js";
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import { configure } from "./core/configuration.js";
|
||||
import { configureWebWorker } from "./core/web-worker-inline-wasm.js";
|
||||
|
||||
configureWebWorker(configure);
|
||||
|
||||
export * from "./zip-core-wasm.js";
|
||||
export * from "./zip-module-wasm.js";
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"name": "@zip.js/zip.js",
|
||||
"description": "A JavaScript library to zip and unzip files in the browser, Deno and Node.js",
|
||||
"author": "Gildas Lormeau",
|
||||
"license": "BSD-3-Clause",
|
||||
"version": "2.8.26",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"zip",
|
||||
"unzip",
|
||||
"browser",
|
||||
"web",
|
||||
"aes-256",
|
||||
"aes-192",
|
||||
"aes-128",
|
||||
"zip-crypto",
|
||||
"encryption",
|
||||
"zip64",
|
||||
"web-streams",
|
||||
"compression-streams",
|
||||
"web-crypto",
|
||||
"web-workers",
|
||||
"deno",
|
||||
"node.js",
|
||||
"multi-core",
|
||||
"split-zip",
|
||||
"usdz",
|
||||
"deflate64",
|
||||
"wasm"
|
||||
],
|
||||
"engines": {
|
||||
"deno": ">=1.0.0",
|
||||
"node": ">=18.0.0",
|
||||
"bun": ">=0.7.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npx rollup -c",
|
||||
"build-dev": "npx rollup -c rollup.config.dev.js",
|
||||
"build-doc-api": "npx typedoc",
|
||||
"build-doc-markdown": "npx typedoc --plugin typedoc-plugin-markdown --out ./docs",
|
||||
"test-deno": "cd ./tests && deno test --allow-read ./deno-runner.js",
|
||||
"test-node": "cd ./tests && node ./node-runner.js",
|
||||
"test-bun": "cd ./tests && bun test ./bun-runner.js",
|
||||
"test-firefox": "firefox http://localhost:8081/tests/ & npx http-server -p=8081 & wait $!",
|
||||
"test-chrome": "google-chrome http://localhost:8081/tests/ & npx http-server -p=8081 & wait $!"
|
||||
},
|
||||
"main": "./index.cjs",
|
||||
"module": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
"./dist/zip-web-worker.js": "./dist/zip-web-worker.js",
|
||||
"./dist/zip-web-worker-native.js": "./dist/zip-web-worker-native.js",
|
||||
"./dist/zip-module.wasm": "./dist/zip-module.wasm",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.cjs"
|
||||
}
|
||||
},
|
||||
"./index-native.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index-native.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index-native.cjs"
|
||||
}
|
||||
},
|
||||
"./index.min.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.min.js"
|
||||
}
|
||||
},
|
||||
"./index-native.min.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index-native.min.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-core-reader.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-core-reader.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-core-writer.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-core-writer.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-fs.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-fs-wasm.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-fs-native.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-fs-native.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-core.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-core-wasm.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-core-native.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-core-native.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-fs-core.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-fs-core-wasm.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-fs-core-native.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-fs-core-native.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-wasm.js"
|
||||
}
|
||||
},
|
||||
"./lib/zip-native.js": {
|
||||
"import": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./lib/zip-native.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/gildas-lormeau/zip.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/gildas-lormeau/zip.js/issues"
|
||||
},
|
||||
"homepage": "https://gildas-lormeau.github.io/zip.js",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "^6.0.3",
|
||||
"@rollup/plugin-terser": "^1.0.0",
|
||||
"eslint": "^10.1.0",
|
||||
"http-server": "^14.1.1",
|
||||
"rollup": "^4.60.1",
|
||||
"typedoc": "^0.28.18",
|
||||
"typedoc-plugin-markdown": "^4.11.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user