我的网页需要JSZip和gzip,JSZip拥有所有成分,但以我无法破解的方式隐藏它们



JavaScript中对gzip的支持非常弱。所有浏览器都实现了它,以支持Contentencoding:gzip标头,但没有对浏览器的gzip/gunzip功能的标准访问权限。因此,必须使用仅使用javascript的方法。有一些旧的gzip js库,但它们似乎没有启用流,而且已经6年没有维护了。

然后是pako,它得到了更积极的维护,但如果使用它们自己的分布,也不会看到流被启用,所以你需要在内存中保存整个二进制数组和gzip输出。我可能错了,但这就是我所收集的。

JSZip是一个设计良好的工具,支持流"Workers"。JSZip使用pako。ZIP条目是DEFLATEd的,具有CRC32校验和,就像gzip一样,当然只是组织方式略有不同。仅从JSZip的来源来看,将pako的gzip压缩选项公开到JSZip流支持中似乎很容易。如果我既使用JSZip又需要gzip,为什么我要加载两次pako?

我希望我能破解JSZip的内部结构,找到底层Workers,并使用基于pako的"Flate"(即在Flate/de-Flate中(实现,并使用pako认可的gzip选项。使用Chrome javascript控制台进行了探索,但我无法接通。可分发的可加载jszip.js或jszip-min.js隐藏了所有内部内容,不允许访问脚本。我打不开那个盒子。

因此,我一直在查看github源代码,看看我是否可以构建自己的jszip.js或jszip-min.js可加载模块,在那里我可以导出更多的内部资源用于我的页面,但在这方面已经工作了20年,UNIX生成文件,ant,一切,当谈到这些打包javascript模块的技巧时,我觉得自己完全是个新手,我看到了bower和"gruntfiles",它们似乎都与node.js有关,我不需要(只有客户端浏览器(,也从未使用过,所以我不知道从哪里开始。

正如Evert所说,我应该先检查文档中的构建说明https://stuk.github.io/jszip/documentation/contributing.html.

由此可以清楚地看出,第一个需要git并进行本地克隆。然后需要设置grunt命令行,该命令行需要nodejs附带的npm。一旦grunt运行,还有其他依赖项需要npm install-ed。这是通常的小事,但不起作用,但足够的谷歌搜索和蛮力尝试来完成它。

现在jszip/lib/index.js包含最终导出的资源。就是那个JSZip对象。因此,为了处理内部内容,我可以将这些内容添加到JSZip对象中,例如,它已经包含:

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头和尾部的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

并且它正确地返回

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发送到我的web服务器。我已经检查过这个大文件确实是分块处理的。

我唯一不喜欢的是,最后一个blob仍然被组装成一个大blob,所以我假设它在内存中保存所有压缩数据。如果Blow是Worker管道的终点,那么当xhr.send从Blob中获取数据块时,它只会消耗Worker管道中的块,这会更好。然而,考虑到它只保存压缩的内容,这种影响减轻了很多,而且(至少对我来说(大文件可能是多媒体文件,无论如何都不需要gzip压缩。

我没有写一个gunzip函数,因为坦率地说,我不需要一个,也不想制作一个无法正确解析gzip标头中扩展标头的函数。一旦我将压缩内容上传到服务器(在我的情况下是S3(,当我再次获取它时,我认为浏览器会为我进行解压缩。不过我还没有检查。如果它成为一个问题,我会回来编辑这个答案更多。

这是我在github上的分叉:https://github.com/gschadow/jszip,已输入拉取请求。

相关内容

  • 没有找到相关文章

最新更新