/*
* JLibs: Common Utilities for Java
* Copyright (C) 2009 Santhosh Kumar T <santhosh.tekuri@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package jlibs.nio.filters;
import jlibs.nio.Input;
import jlibs.nio.InputFilter;
import jlibs.nio.Reactor;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
/**
* @author Santhosh Kumar Tekuri
*/
public class InflaterInput extends InputFilter{
protected Inflater inflater;
protected ByteBuffer buffer;
private ByteBuffer tmpBuffer;
public InflaterInput(Input peer){
this(new Inflater(false), peer);
}
protected InflaterInput(Inflater inflater, Input in){
super(in);
buffer = Reactor.current().allocator.allocateHeap();
this.inflater = inflater;
}
@Override
protected boolean readReady(){
return inflater==null || !inflater.needsInput();
}
protected int inflate(byte bytes[], int offset, int len) throws DataFormatException{
return inflater.inflate(bytes, offset, len);
}
@Override
public int read(ByteBuffer dst) throws IOException{
if(inflater==null)
return -1;
if(inflater.needsInput()){
buffer.clear();
int read = peer.read(buffer);
if(read==0)
return 0;
else if(read==-1)
throw new EOFException();
else
inflater.setInput(buffer.array(), 0, read);
}
int pos = dst.position();
try{
if(dst.hasArray()){
int uncompressed = inflate(dst.array(), dst.arrayOffset()+dst.position(), dst.remaining());
dst.position(dst.position()+uncompressed);
}else{
if(tmpBuffer==null)
tmpBuffer = Reactor.current().allocator.allocateHeap();
int min = Math.min(dst.remaining(), tmpBuffer.remaining());
int uncompressed = inflate(tmpBuffer.array(), 0, min);
tmpBuffer.position(0);
tmpBuffer.limit(uncompressed);
dst.put(tmpBuffer);
}
if(inflater.finished() || inflater.needsDictionary())
endInflater();
}catch(DataFormatException ex){
String s = ex.getMessage();
throw (ZipException)new ZipException(s!=null ? s : "Invalid ZLIB data format").initCause(ex);
}
int read = dst.position()-pos;
if(read==0 && inflater==null){
eof = true;
return -1;
}
return read;
}
protected void endInflater(){
if(tmpBuffer!=null){
Reactor.current().allocator.free(tmpBuffer);
tmpBuffer = null;
}
if(inflater.getRemaining()>0){
buffer.limit(buffer.position());
buffer.position(buffer.position()-inflater.getRemaining());
}else{
Reactor.current().allocator.free(buffer);
buffer = null;
}
inflater.end();
inflater = null;
}
@Override
protected ByteBuffer detached(){
if(tmpBuffer!=null){
Reactor.current().allocator.free(tmpBuffer);
tmpBuffer = null;
}
if(inflater!=null){
inflater.end();
inflater = null;
if(buffer!=null){
Reactor.current().allocator.free(buffer);
buffer = null;
}
}
return buffer;
}
@Override
public long available(){
return 0;
}
}