JavaScript Zlib解压缩

时间:2014-09-05 08:21:42

标签: javascript jquery google-chrome-extension bytearray zlib

我正在尝试解压缩zlib的XML,如下所示: https://drive.google.com/file/d/0B52P0MZLTdw8ZzQwQzVpZGZVZWc

上传到在线解压缩服务的工作原理,例如:http://i-tools.org/gzip

在PHP中,我正在使用此代码并且工作得很好,我得到了XML字符串:

$raw = file_get_contents("file_here");
$uncompressed = zlib_decode($raw);

但是,我想在JavaScript中执行此操作。

  • 该应用是客户端Chrome扩展程序,使用chrome.devtools.network从网络日志中读取
  • 读取二进制响应。顶部的Google云端硬盘链接示例
  • JS需要将该响应解压缩到其原始XML,然后解析为对象

我唯一的问题是zlib解压缩部分。

截至最新更新时,解压缩库可以正常工作,但解压缩不起作用。请跳至底部的更新9月16日。


我已经尝试过几个JavaScript库但仍无法使其工作:

Pako https://github.com/nodeca/pako

unpack()代码:https://codereview.stackexchange.com/questions/3569/pack-and-unpack-bytes-to-strings

function unpack(str) {
    var bytes = [];
    for(var i = 0, n = str.length; i < n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char >>> 8, char & 0xFF);
    }
    return bytes;
}

$.get("file_here", function(response){
    var charData    = unpack(response);
    var binData     = new Uint8Array(charData);
    var data        = pako.inflate(binData);
    var strData     = String.fromCharCode.apply(null, new Uint16Array(data));
    console.log(strData);
});

错误:Uncaught incorrect header check

即使将答案放在其他地方也是如此:

  • new Uint8Array(response);
  • pako.inflate(response);

Imaya的zlib https://github.com/imaya/zlib.js

$.get("file_here", function(response){
    var inflate = new Zlib.Inflate(response);
    var output = inflate.decompress();
    console.log(output);
});

错误:Uncaught Error: unsupported compression method inflate.js:60

仍在使用Imaya的zlib,结合此Stack Overflow问题: Decompress gzip and zlib string in javascript

$.get("file_here", function(response){
    var response = response.split('').map(function(e) {
        return e.charCodeAt(0);
    });
    var inflate = new Zlib.Inflate(response);
    var output = inflate.decompress();
    console.log(output);
});

错误:Uncaught Error: invalid fcheck flag:29 inflate.js:65


dankogai的js-deflate https://github.com/dankogai/js-deflate

console.log(RawDeflate.inflate(response));

输出:


augustl的js-inflate https://github.com/augustl/js-inflate

console.log(JSInflate.inflate(response));

输出:


zlib-browserify https://github.com/brianloveswords/zlib-browserify

错误:ReferenceError: exports is not defined

这只是Imaya的zlib的包装器。我认为这是requireJS?我甚至不确定如何使用它。它甚至可以在没有安装任何东西的情况下使用,只需jQuery / JS吗?提到的应用程序是可下载的Chrome扩展程序,只有HTML导入JS文件。


2014年9月16日更新

似乎问题出在 JavaScript unpack( )函数上。当我使用PHP生成的ByteArray:http://pastebin.com/uDWvK94B时,JavaScript解压缩功能可以正常工作。

PHP解包有效:

$unpacked = unpack("C*", $raw);

对于我使用的JavaScript unpack( )代码,该代码不起作用,请参阅 Pako 部分下的帖子顶部。

所以新问题是,为什么JavaScript会生成与PHP生成的值不同的ByteArray值。

  • unpack( )函数确实存在问题吗?
  • 或者当JS获取文件时,编码或任何更改因此字节变得混乱?
  • 最后,你建议的修复是什么?

更新于2014年9月20日

有更多的研究和一些答案在这里给出了潜在客户

  • Sebastian S 宣布问题是以检索数据的方式,而且与文本编码有关
  • user3995789 提供一个示例,即使没有unpack( )功能,它也可以使用,但不在Chrome扩展程序的上下文中
  • Isaac 在Chrome扩展程序环境中提供示例,但仍然无效

有了这个,我研究了进一步结合所有线索,这引出了一个理论,这背后的原因是Chrome无法通过其request.getContent函数获得“原始”数据。 See here用于上述功能的Chrome文档。

截至目前,我已将问题发送给Chrome,see here

2015年3月24日更新

虽然问题没有完全解决,但我认为对我来说最有用的答案来自@Sebastian S,他提出“我采取或接收数据的方式”是错误的,转换错误是原因,就像问题一样。

3 个答案:

答案 0 :(得分:2)

Jquery以utf8格式读取,你必须读取原始文件,这个函数才有效。

function readTextFile(file)
{
    var rawFile = new XMLHttpRequest();
    rawFile.open('GET', file, true);  
    rawFile.responseType = 'arraybuffer';
    rawFile.onload = function (response)
    {
      var words = new Uint8Array(rawFile.response);
       console.log(words[1]);
      console.log(pako.ungzip(words));

    };
    rawFile.send();
}

有关详细信息,请参阅此answer

答案 1 :(得分:1)

我知道你想在Chrome扩展程序中使用zlib解压缩,同时从网络日志中读取响应主体。

首先需要检索要解压缩的base64。您可以在使用getContent方法时实现此目的。

function zlibDecompress(base64Content){
    // var base64Content        = base64Content.split(',')[1]; // Not sure if need to keep it

    // Decode base64 (convert ascii to binary)
    var strData     = atob(base64Content);

    // Convert binary string to character-number array
    var charData    = strData.split('').map(function(x){return x.charCodeAt(0);});

    // Turn number array into byte-array
    var binData     = new Uint8Array(charData);

    // Pako inflate
    var data        = pako.inflate(binData, { to: 'string' });

    return data;

}

chrome.devtools.network.onRequestFinished.addListener(
    function(request) {
        request.getContent(
            function(content, encoding){
                if(encoding == 'base64'){
                    var output = zlibDecompress(content);
                }
            }
        );
    }
);

https://developer.chrome.com/extensions/devtools_network#type-Request

使用XMLHttpRequest:

<script type="text/javascript" src="pako.js"></script>
<script type="text/javascript">

function zlibDecompress(url){
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';

    xhr.onload = function(oEvent) {
        // Base64 encode
        var reader = new window.FileReader();
        reader.readAsDataURL(xhr.response); 
        reader.onloadend = function() {
            base64data      = reader.result;  
            var base64      = base64data.split(',')[1];

            // Decode base64 (convert ascii to binary)
            var strData     = atob(base64);

            // Convert binary string to character-number array
            var charData    = strData.split('').map(function(x){return x.charCodeAt(0);});

            // Turn number array into byte-array
            var binData     = new Uint8Array(charData);

            // Pako inflate
            var data        = pako.inflate(binData, { to: 'string' });

            console.log(data);
        }
    };

    xhr.send();
}
zlibDecompress('fileurl');
</script>

如果您想使用带有chrome扩展名的XMLHttpRequest

{
  "name": "My extension",
  ...
  "permissions": [
    "http://www.domain.com/", // The domain that hold the file
    "http://*/" // Or every domain
  ],
  ...
}

https://developer.chrome.com/extensions/xhr

随时问你是否有任何问题;)

答案 2 :(得分:0)

在我看来,您应该问的问题是: 如何检索压缩数据?一旦它成为UTF-16字符串,麻烦就开始了。如果从原始字节数据到javascript字符串的转换是无损的,我甚至不确定。

当你写一些关于php的东西时,我假设你正在与某种后端进行通信。如果这是真的,可以使用本机方法处理二进制数据。也许这可以帮到你:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data