我的网页需要 JSZip 和 gzip,JSZip 拥有所有成分,但以我无法破解的方式隐藏它们
I need JSZip and gzip for my web page, and JSZip has all the ingredients, but hides them in ways I can't crack
JavaScript 中对 gzip 的支持出奇地弱。所有浏览器都实现它以支持 Content-encoding: gzip header,但没有标准访问浏览器的 gzip / gunzip 功能。因此,必须使用一种仅 javascript 的方法。周围有一些旧的 gzip-js 图书馆,但它们似乎 stream-enabled 并且已经停止维护 6 年了。
还有 pako,维护得更积极,但如果使用他们自己的发行版,也看不到启用流,因此您需要将整个二进制数组和 gzip 输出保存在内存中。我可能是错的,但这就是我正在收集的信息。
JSZip 是一款设计精良的工具,支持流 "Workers"。 JSZip 使用 pako。 ZIP 条目是 DEFLATEd 的,并且与 gzip 一样具有 CRC32 校验和,当然只是组织方式略有不同。仅从考虑 JSZip 源代码来看,将 pako 的 gzip 压缩选项公开到 JSZip 的流支持中似乎很容易。如果我同时使用 JSZip 并且还需要 gzip,为什么我要加载 pako 两次?
我希望我可以破解 JSZip 的内部机制,到达底层 Worker 并使用基于 pako 的 "Flate"(即 in-flate / de-flate)实现使用 pako 识别的 gzip 选项。用 Chrome javascript 控制台探索了它,但我无法通过。可分发的可加载 jszip.js 或 jszip-min.js 隐藏了所有内部结构,无法访问脚本。我打不开那个盒子。
所以我一直在查看 git 集线器源代码,看看我是否可以构建自己的 jszip.js 或 jszip-min.js 可加载模块,我可以在其中导出更多在我的页面中使用的内部资源,但是已经在这个领域工作了 20 年,UNIX make files,ant,一切,当谈到这些打包 javascript 模块的技巧时,我觉得自己完全是个新手,我看到了 bower 和"gruntfiles" 似乎都与 node.js 有关,我不需要(仅 client-side 浏览器)并且从未使用过,所以我不知道从哪里开始。
正如 Evert 所说,我应该先检查文档中的构建说明 https://stuk.github.io/jszip/documentation/contributing.html。
很明显,第一个需要 git 并制作一个本地克隆。然后需要设置grunt命令行,需要nodejs自带的npm。一旦 grunt 运行,还有其他依赖项需要 npm install-ed。这是常见的小事情,但无法正常工作,但谷歌搜索和暴力重试足以完成它。
现在jszip/lib/index.js 包含最终导出的资源。就是那个JSZipobject。所以只是为了玩弄内部的东西,我可以将它们添加到 JSZip object,例如,它已经包含:
JSZip.external = require("./external");
module.exports = JSZip;
因此我们可以轻松添加我们想要玩的其他资源:
JSZip.flate = require("./flate");
JSZip.DataWorker = require('./stream/DataWorker');
JSZip.DataLengthProbe = require('./stream/DataLengthProbe');
JSZip.Crc32Probe = require('./stream/Crc32Probe');
JSZip.StreamHelper = require('./stream/StreamHelper');
JSZip.pako = require("pako");
现在,我可以在 Chrome 调试器中创建概念证明:
(new JSZip.StreamHelper(
(new JSZip.DataWorker(Promise.resolve("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!")))
.pipe(new JSZip.DataLengthProbe("uncompressedSize"))
.pipe(new JSZip.Crc32Probe())
.pipe(JSZip.flate.compressWorker({}))
.pipe(new JSZip.DataLengthProbe("compressedSize"))
.on("end", function(event) { console.log("onEnd: ", this.streamInfo) }),
"uint8array", "")
).accumulate(function(data) { console.log("acc: ", data); })
.then(function(data) { console.log("then: ", data); })
这行得通。我一直在为自己制作一个带有 gzip header 和预告片的 GZipFileStream,正确创建所有内容。我放了一个jszip/lib/generate/GZipFileWorker.js 如下:
'use strict';
var external = require('../external');
var utils = require('../utils');
var flate = require('../flate');
var GenericWorker = require('../stream/GenericWorker');
var DataWorker = require('../stream/DataWorker');
var StreamHelper = require('../stream/StreamHelper');
var DataLengthProbe = require('../stream/DataLengthProbe');
var Crc32Probe = require('../stream/Crc32Probe');
function GZipFileWorker() {
GenericWorker.call(this, "GZipFileWorker");
this.virgin = true;
}
utils.inherits(GZipFileWorker, GenericWorker);
GZipFileWorker.prototype.processChunk = function(chunk) {
if(this.virgin) {
this.virgin = false;
var headerBuffer = new ArrayBuffer(10);
var headerView = new DataView(headerBuffer);
headerView.setUint16(0, 0x8b1f, true); // GZip magic
headerView.setUint8(2, 0x08); // compression algorithm DEFLATE
headerView.setUint8(3, 0x00); // flags
// bit 0 FTEXT
// bit 1 FHCRC
// bit 2 FEXTRA
// bit 3 FNAME
// bit 4 FCOMMENT
headerView.setUint32(4, (new Date()).getTime()/1000>>>0, true);
headerView.setUint8(8, 0x00); // no extension headers
headerView.setUint8(9, 0x03); // OS type UNIX
this.push({data: new Uint8Array(headerBuffer)});
}
this.push(chunk);
};
GZipFileWorker.prototype.flush = function() {
var trailerBuffer = new ArrayBuffer(8);
var trailerView = new DataView(trailerBuffer);
trailerView.setUint32(0, this.streamInfo["crc32"]>>>0, true);
trailerView.setUint32(4, this.streamInfo["originalSize"]>>>0 & 0xffffffff, true);
this.push({data: new Uint8Array(trailerBuffer)});
};
exports.gzip = function(data, inputFormat, outputFormat, compressionOptions, onUpdate) {
var mimeType = data.contentType || data.mimeType || "";
if(! (data instanceof GenericWorker)) {
inputFormat = (inputFormat || "").toLowerCase();
data = new DataWorker(
utils.prepareContent(data.name || "gzip source",
data,
inputFormat !== "string",
inputFormat === "binarystring",
inputFormat === "base64"));
}
return new StreamHelper(
data
.pipe(new DataLengthProbe("originalSize"))
.pipe(new Crc32Probe())
.pipe(flate.compressWorker( compressionOptions || {} ))
.pipe(new GZipFileWorker()),
outputFormat.toLowerCase(), mimeType).accumulate(onUpdate);
};
在 jszip/lib/index.js 中我只需要这个:
var gzip = require("./generate/GZipFileWorker");
JSZip.gzip = gzip.gzip;
这就是这样工作的:
JSZip.gzip("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!", "string", "base64", {level: 3}).then(function(result) { console.log(result); })
我可以像这样将结果粘贴到 UNIX 管道中:
$ echo -n "H4sIAOyR/VsAA/NIzcnJVwjPL8pJUVTwoJADAPCORolNAAAA" |base64 -d |zcat
并且正确 returns
Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!
它也可以与文件一起使用:
JSZip.gzip(file, "", "Blob").then(function(blob) {
xhr.setRequestProperty("Content-encoding", "gzip");
xhr.send(blob);
})
我可以将 blob 发送到我的网络服务器。我检查过大文件确实是按块处理的。
我唯一不喜欢的是最终的 blob 仍然组装成一个大 Blob,所以我假设它在内存中保存所有压缩数据。如果 Blow 是那个 Worker 管道的 end-point 会更好,这样当 xhr.send 从 Blob 中获取数据 chunk-wise 时,它只会消耗来自 Worker 管道的块。但是,考虑到它只包含压缩内容,并且可能(至少对我而言)大文件将是 multi-media 无论如何都不需要 gzip 压缩的文件,因此影响会大大减轻。
我没有写 gunzip 函数,因为坦率地说,我不需要,我不想创建一个无法正确解析 gzip headers 中的扩展 header ]s。一旦我将压缩内容上传到服务器(在我的例子中是 S3),当我再次获取它时,我假设浏览器会为我解压缩。我还没有检查过。如果它成为一个问题,我会回来结束编辑这个答案。
这是我在 github 上的分支:https://github.com/gschadow/jszip,已输入拉取请求。
JavaScript 中对 gzip 的支持出奇地弱。所有浏览器都实现它以支持 Content-encoding: gzip header,但没有标准访问浏览器的 gzip / gunzip 功能。因此,必须使用一种仅 javascript 的方法。周围有一些旧的 gzip-js 图书馆,但它们似乎 stream-enabled 并且已经停止维护 6 年了。
还有 pako,维护得更积极,但如果使用他们自己的发行版,也看不到启用流,因此您需要将整个二进制数组和 gzip 输出保存在内存中。我可能是错的,但这就是我正在收集的信息。
JSZip 是一款设计精良的工具,支持流 "Workers"。 JSZip 使用 pako。 ZIP 条目是 DEFLATEd 的,并且与 gzip 一样具有 CRC32 校验和,当然只是组织方式略有不同。仅从考虑 JSZip 源代码来看,将 pako 的 gzip 压缩选项公开到 JSZip 的流支持中似乎很容易。如果我同时使用 JSZip 并且还需要 gzip,为什么我要加载 pako 两次?
我希望我可以破解 JSZip 的内部机制,到达底层 Worker 并使用基于 pako 的 "Flate"(即 in-flate / de-flate)实现使用 pako 识别的 gzip 选项。用 Chrome javascript 控制台探索了它,但我无法通过。可分发的可加载 jszip.js 或 jszip-min.js 隐藏了所有内部结构,无法访问脚本。我打不开那个盒子。
所以我一直在查看 git 集线器源代码,看看我是否可以构建自己的 jszip.js 或 jszip-min.js 可加载模块,我可以在其中导出更多在我的页面中使用的内部资源,但是已经在这个领域工作了 20 年,UNIX make files,ant,一切,当谈到这些打包 javascript 模块的技巧时,我觉得自己完全是个新手,我看到了 bower 和"gruntfiles" 似乎都与 node.js 有关,我不需要(仅 client-side 浏览器)并且从未使用过,所以我不知道从哪里开始。
正如 Evert 所说,我应该先检查文档中的构建说明 https://stuk.github.io/jszip/documentation/contributing.html。
很明显,第一个需要 git 并制作一个本地克隆。然后需要设置grunt命令行,需要nodejs自带的npm。一旦 grunt 运行,还有其他依赖项需要 npm install-ed。这是常见的小事情,但无法正常工作,但谷歌搜索和暴力重试足以完成它。
现在jszip/lib/index.js 包含最终导出的资源。就是那个JSZipobject。所以只是为了玩弄内部的东西,我可以将它们添加到 JSZip object,例如,它已经包含:
JSZip.external = require("./external");
module.exports = JSZip;
因此我们可以轻松添加我们想要玩的其他资源:
JSZip.flate = require("./flate");
JSZip.DataWorker = require('./stream/DataWorker');
JSZip.DataLengthProbe = require('./stream/DataLengthProbe');
JSZip.Crc32Probe = require('./stream/Crc32Probe');
JSZip.StreamHelper = require('./stream/StreamHelper');
JSZip.pako = require("pako");
现在,我可以在 Chrome 调试器中创建概念证明:
(new JSZip.StreamHelper(
(new JSZip.DataWorker(Promise.resolve("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!")))
.pipe(new JSZip.DataLengthProbe("uncompressedSize"))
.pipe(new JSZip.Crc32Probe())
.pipe(JSZip.flate.compressWorker({}))
.pipe(new JSZip.DataLengthProbe("compressedSize"))
.on("end", function(event) { console.log("onEnd: ", this.streamInfo) }),
"uint8array", "")
).accumulate(function(data) { console.log("acc: ", data); })
.then(function(data) { console.log("then: ", data); })
这行得通。我一直在为自己制作一个带有 gzip header 和预告片的 GZipFileStream,正确创建所有内容。我放了一个jszip/lib/generate/GZipFileWorker.js 如下:
'use strict';
var external = require('../external');
var utils = require('../utils');
var flate = require('../flate');
var GenericWorker = require('../stream/GenericWorker');
var DataWorker = require('../stream/DataWorker');
var StreamHelper = require('../stream/StreamHelper');
var DataLengthProbe = require('../stream/DataLengthProbe');
var Crc32Probe = require('../stream/Crc32Probe');
function GZipFileWorker() {
GenericWorker.call(this, "GZipFileWorker");
this.virgin = true;
}
utils.inherits(GZipFileWorker, GenericWorker);
GZipFileWorker.prototype.processChunk = function(chunk) {
if(this.virgin) {
this.virgin = false;
var headerBuffer = new ArrayBuffer(10);
var headerView = new DataView(headerBuffer);
headerView.setUint16(0, 0x8b1f, true); // GZip magic
headerView.setUint8(2, 0x08); // compression algorithm DEFLATE
headerView.setUint8(3, 0x00); // flags
// bit 0 FTEXT
// bit 1 FHCRC
// bit 2 FEXTRA
// bit 3 FNAME
// bit 4 FCOMMENT
headerView.setUint32(4, (new Date()).getTime()/1000>>>0, true);
headerView.setUint8(8, 0x00); // no extension headers
headerView.setUint8(9, 0x03); // OS type UNIX
this.push({data: new Uint8Array(headerBuffer)});
}
this.push(chunk);
};
GZipFileWorker.prototype.flush = function() {
var trailerBuffer = new ArrayBuffer(8);
var trailerView = new DataView(trailerBuffer);
trailerView.setUint32(0, this.streamInfo["crc32"]>>>0, true);
trailerView.setUint32(4, this.streamInfo["originalSize"]>>>0 & 0xffffffff, true);
this.push({data: new Uint8Array(trailerBuffer)});
};
exports.gzip = function(data, inputFormat, outputFormat, compressionOptions, onUpdate) {
var mimeType = data.contentType || data.mimeType || "";
if(! (data instanceof GenericWorker)) {
inputFormat = (inputFormat || "").toLowerCase();
data = new DataWorker(
utils.prepareContent(data.name || "gzip source",
data,
inputFormat !== "string",
inputFormat === "binarystring",
inputFormat === "base64"));
}
return new StreamHelper(
data
.pipe(new DataLengthProbe("originalSize"))
.pipe(new Crc32Probe())
.pipe(flate.compressWorker( compressionOptions || {} ))
.pipe(new GZipFileWorker()),
outputFormat.toLowerCase(), mimeType).accumulate(onUpdate);
};
在 jszip/lib/index.js 中我只需要这个:
var gzip = require("./generate/GZipFileWorker");
JSZip.gzip = gzip.gzip;
这就是这样工作的:
JSZip.gzip("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!", "string", "base64", {level: 3}).then(function(result) { console.log(result); })
我可以像这样将结果粘贴到 UNIX 管道中:
$ echo -n "H4sIAOyR/VsAA/NIzcnJVwjPL8pJUVTwoJADAPCORolNAAAA" |base64 -d |zcat
并且正确 returns
Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!
它也可以与文件一起使用:
JSZip.gzip(file, "", "Blob").then(function(blob) {
xhr.setRequestProperty("Content-encoding", "gzip");
xhr.send(blob);
})
我可以将 blob 发送到我的网络服务器。我检查过大文件确实是按块处理的。
我唯一不喜欢的是最终的 blob 仍然组装成一个大 Blob,所以我假设它在内存中保存所有压缩数据。如果 Blow 是那个 Worker 管道的 end-point 会更好,这样当 xhr.send 从 Blob 中获取数据 chunk-wise 时,它只会消耗来自 Worker 管道的块。但是,考虑到它只包含压缩内容,并且可能(至少对我而言)大文件将是 multi-media 无论如何都不需要 gzip 压缩的文件,因此影响会大大减轻。
我没有写 gunzip 函数,因为坦率地说,我不需要,我不想创建一个无法正确解析 gzip headers 中的扩展 header ]s。一旦我将压缩内容上传到服务器(在我的例子中是 S3),当我再次获取它时,我假设浏览器会为我解压缩。我还没有检查过。如果它成为一个问题,我会回来结束编辑这个答案。
这是我在 github 上的分支:https://github.com/gschadow/jszip,已输入拉取请求。