为了账号安全,请及时绑定邮箱和手机立即绑定

这是 Java 的 Inflater 中的错误还是什么?

这是 Java 的 Inflater 中的错误还是什么?

鸿蒙传说 2023-08-16 09:46:35
我在一些单元测试中就被这个问题困扰了。我想使用Inflater解压缩一些 ZLIB 压缩的数据,其中原始数据长度是预先知道的。这(简单)按预期工作   /*       * Decompresses a zlib compressed buffer, with given size of raw data.     * All data is fed and inflated in full (one step)      */    public static byte[] decompressFull(byte[] comp, int len) throws Exception {        byte[] res = new byte[len]; // result (uncompressed)        Inflater inf = new Inflater();        inf.setInput(comp);        int n = inf.inflate(res, 0, len);        if (n != len)            throw new RuntimeException("didn't inflate all data");        System.out.println("Data done (full). bytes in :"  + inf.getBytesRead()                 + " out=" + inf.getBytesWritten()                + " finished: " + inf.finished());        // done - the next is not needed, just for checking...         //try a final inflate just in case (might trigger ZLIB crc check)        byte[] buf2 = new byte[6];        int nx = inf.inflate(buf2);//should give 0        if (nx != 0)            throw new RuntimeException("nx=" + nx + " " + Arrays.toString(buf2));        if (!inf.finished())            throw new RuntimeException("not finished?");        inf.end();        return res;    }现在,压缩输入可以是任意大小的块。下面的代码模拟了这样一种情况:除了最后 4 个字节之外,压缩输入被全部馈送,然后一次馈送一个剩余字节。(据我了解,解压缩完整数据不需要 zlib 流的最后 4 个或 5 个字节,但需要它们来检查完整性 - Adler-32 CRC)。    public static byte[] decompressBytexByte(byte[] comp, int len) throws Exception {            byte[] res = new byte[len]; // result (uncompressed)            Inflater inf = new Inflater();            inf.setInput(comp, 0, comp.length - 4);            int n = inf.inflate(res, 0, len);            if (n != len)        }嗯,这对我不起作用(Java 1.8.0_181)。充气机还没有完成,Adler CRC 检查还没有完成,看起来;更多:似乎字节没有送入充气机。更奇怪的是:如果在一次调用中输入尾部 4 个字节,它就会起作用。您可以在这里尝试: https: //repl.it/@HernanJJ/Inflater-Test当我一次输入一个字节的整个输入时,甚至会发生更奇怪的事情:有时该行 int nx= inf.inflate(buf2);//should give 0返回非零(当所有数据已经被夸大时)。这是预期的行为吗?我错过了什么吗?
查看完整描述

1 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

正如@SeanBright已经注意到的,你应该只在Inflater.needsInput()返回 true 时为其提供新的输入。

顺序调用setInput将覆盖您之前传递的输入。

Javadoc of Inflater.needsInput():

如果输入缓冲区中没有数据,则返回 true。这可用于确定是否应调用 #setInput 以提供更多输入。

只要你逐字节地输入它,情况总是如此,所以你可能可以跳过检查本身。

您可以用此替换该方法的输入设置部分decompressBytexByte(用于完整的逐字节馈送):

byte[] res = new byte[len];

Inflater inf = new Inflater();


int a = 0; // number of bytes that have already been obtained

for (int p = 0; p < comp.length; p++) {         

    inf.setInput(comp, p, 1);

    a += inf.inflate(res, a, len - a);

}


查看完整回答
反对 回复 2023-08-16
  • 1 回答
  • 0 关注
  • 102 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信