blob: dc8d5a45a4dfaf9c03f67d0f7e9ec33a1a18dec4 [file] [log] [blame]
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.entity;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipException;
/**
* Deflate input stream. This class includes logic needed for various Rfc's in order
* to reasonably implement the "deflate" compression style.
*/
public class DeflateInputStream extends InputStream {
private final InputStream sourceStream;
public DeflateInputStream(final InputStream wrapped) throws IOException {
final PushbackInputStream pushback = new PushbackInputStream(wrapped, 2);
final int i1 = pushback.read();
final int i2 = pushback.read();
if (i1 == -1 || i2 == -1) {
throw new ZipException("Unexpected end of stream");
}
pushback.unread(i2);
pushback.unread(i1);
boolean nowrap = true;
final int b1 = i1 & 0xFF;
final int compressionMethod = b1 & 0xF;
final int compressionInfo = b1 >> 4 & 0xF;
final int b2 = i2 & 0xFF;
if (compressionMethod == 8 && compressionInfo <= 7 && ((b1 << 8) | b2) % 31 == 0) {
nowrap = false;
}
sourceStream = new DeflateStream(pushback, new Inflater(nowrap));
}
/**
* Read a byte.
*/
@Override
public int read() throws IOException {
return sourceStream.read();
}
/**
* Read lots of bytes.
*/
@Override
public int read(final byte[] b) throws IOException {
return sourceStream.read(b);
}
/**
* Read lots of specific bytes.
*/
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
return sourceStream.read(b, off, len);
}
/**
* Skip
*/
@Override
public long skip(final long n) throws IOException {
return sourceStream.skip(n);
}
/**
* Get available.
*/
@Override
public int available() throws IOException {
return sourceStream.available();
}
/**
* Mark.
*/
@Override
public void mark(final int readLimit) {
sourceStream.mark(readLimit);
}
/**
* Reset.
*/
@Override
public void reset() throws IOException {
sourceStream.reset();
}
/**
* Check if mark is supported.
*/
@Override
public boolean markSupported() {
return sourceStream.markSupported();
}
/**
* Close.
*/
@Override
public void close() throws IOException {
sourceStream.close();
}
static class DeflateStream extends InflaterInputStream {
private boolean closed = false;
public DeflateStream(final InputStream in, final Inflater inflater) {
super(in, inflater);
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
closed = true;
inf.end();
super.close();
}
}
}