Невозможно накачать буфер, дефлированный с помощью java.util.zip.Deflater, используя фильтр сжатия Apache MINA. - PullRequest
0 голосов
/ 04 апреля 2011

Этот тест:

import java.util.zip.Deflater;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.filter.support.Zlib;
import org.junit.*;

public class ZlibTest {
    private Deflater deflater = null;

    private Zlib inflater = null;

    @Before
    public void setUp() throws Exception {
        deflater = new Deflater(Deflater.BEST_COMPRESSION);
        deflater.setStrategy(Deflater.DEFAULT_STRATEGY);
        inflater = new Zlib(Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER);
    }

    @Test
    public void testInflate() throws Exception {
        byte[] compressed = new byte[14];
        deflater.setInput(new byte[] {1});
        deflater.finish();
        int bytesCompressed = deflater.deflate(compressed);
        IoBuffer compressedBuffer = IoBuffer.wrap(compressed, 0, bytesCompressed);
        System.out.println(compressedBuffer);

        IoBuffer byteUncompressed = inflater.inflate(compressedBuffer);
    }
}

не проходит:

java.io.IOException: Unknown error. Error code : 1
    at org.apache.mina.filter.support.Zlib.inflate(Zlib.java:136)
    at ZlibTest.testInflate(ZlibTest.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
    at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Что здесь не так?

ОБНОВЛЕНИЕ: если я добавлю

        case JZlib.Z_STREAM_END:

до строки 139 в Zlib.java , отлично декодируется.

Ответы [ 3 ]

2 голосов
/ 04 апреля 2011

Вы выбрали «выбор дизайна» класса Java Deflater, который вызвал создание JZlib - вы не можете управлять параметром FLUSH для zlib.

Вывод из класса Deflater дляваш однобайтовый массив {1}:

[0] 120 
[1] -38 
[2] 99  
[3] 4   
[4] 0   
[5] 0   <<
[6] 2   <<
[7] 0   <<
[8] 2   <<

Выходные данные класса Zlib при дефляции для вашего однобайтового массива {1}:

[0] 120 
[1] -38 
[2] 98  
[3] 4   
[4] 0   
[5] 0   <<
[6] 0   <<
[7] -1  <<
[8] -1  <<

с Zlib manual

Если для параметра flush задано значение Z_SYNC_FLUSH, все ожидающие выходные данные сбрасываются в выходной буфер, а выходные данные выравниваются по границе байта, так что декомпрессор может получить всевходные данные доступны до сих пор.(В частности, util_in равен нулю после вызова, если перед вызовом было предоставлено достаточно места для вывода.) Сброс может ухудшить сжатие для некоторых алгоритмов сжатия, поэтому его следует использовать только при необходимости.Это завершает текущий блок дефляции и следует за ним с пустым сохраненным блоком, который составляет три бита плюс биты-заполнители до следующего байта, , за которым следуют четыре байта (00 00 и далее) .

С JZlib - Почему JZlib?

Java Platform API предоставляет пакеты 'java.util.zip. *' Для доступа к zlib, но эта поддержка очень ограничена, если вынужно использовать суть zlib.Например, нам нужен был полный доступ к zlib, чтобы добавить поддержку сжатия пакетов в чистую систему Java SSH, но они бесполезны для наших требований....

Для реализации этой функции необходимо использовать режим zlib Z_PARTIAL_FLUSH, однако JDK не позволяет нам это делать.Кажется, что эта проблема хорошо известна, и некоторые люди уже сообщили об этом в BugParade JavaSoft (например, BugId: 4255743), но ни один положительный ответ не был получен от JavaSoft, поэтому эта проблема не будет решена навсегда.Это наша мотивация взломать JZlib.

2 голосов
/ 05 июня 2012

Что касается http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4255743 (знаменитая 13-летняя ошибка - вскоре пойдет в старшую школу, если бы это был мой ребенок), исправление было доставлено в Java 7 (наконец); действительно, есть

public int deflate(byte[] b, int off, int len, int flush) {
    if (b == null) {
        throw new NullPointerException();
    }
    if (off < 0 || len < 0 || off > b.length - len) {
        throw new ArrayIndexOutOfBoundsException();
    }
    synchronized (zsRef) {
        ensureOpen();
        if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
            flush == FULL_FLUSH)
            return deflateBytes(zsRef.address(), b, off, len, flush);
        throw new IllegalArgumentException();
    }
}

часть кода, добавленная в класс Deflater. Итак, сегодня (2012) вы можете просто придерживаться java.util, если эта функциональность - это все, что вам нужно.

0 голосов
/ 04 апреля 2011

Я бы не предположил, что Zlib и Inflater / deflater используют один и тот же протокол данных для отправки данных. Они могут использовать одно и то же базовое сжатие, но я подозреваю, что Zlib ожидает, что поток будет содержать информацию для собственных нужд, а не только для необработанных данных.


Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
deflater.setStrategy(Deflater.DEFAULT_STRATEGY);

byte[] compressed = new byte[10];
deflater.setInput(new byte[]{1});
deflater.finish();
int bytesCompressed = deflater.deflate(compressed);
System.out.println("bytesCompressed=" + bytesCompressed + " " + Arrays.toString(compressed));

Inflater inflater = new Inflater();
inflater.setInput(compressed, 0, bytesCompressed);
byte[] decompressed = new byte[2];
int byteDecompressed = inflater.inflate(decompressed);

System.out.println("bytesInflated=" + byteDecompressed + " " + Arrays.toString(decompressed));

печать

bytesCompressed=9 [120, -38, 99, 4, 0, 0, 2, 0, 2, 0]
bytesInflated=1 [1, 0]
...