/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine 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. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.util.zip;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import totalcross.io.IOException;
import totalcross.io.Stream;
/**
* Base class for stream filters that perform data compression and decompression.<br>
*
* @since TotalCross 1.12
*/
public abstract class CompressedStream extends Stream
{
protected Object compressedStream;
protected int mode;
/**
* Used to create a stream that will be used for data compression. In this mode, you may NOT use the method
* readBytes.
*/
public static final int DEFLATE = 1;
/**
* Used to create a stream that will be used for data decompression. In this mode, you may NOT use the method
* writeBytes.
*/
public static final int INFLATE = 2;
protected CompressedStream()
{
}
/**
* Creates a CompressedStream object that may be used to read compressed data from the given stream, or to write
* compressed data to the given stream.<br>
*
* @param stream
* input stream.
* @param mode
* its value must be either DEFLATE or INFLATE.
*
* @since TotalCross 1.12
*/
protected CompressedStream(Stream stream, int mode)
{
if (stream == null)
throw new NullPointerException("Argument stream cannot have a null value.");
this.mode = mode;
switch (mode)
{
case DEFLATE:
compressedStream = createDeflate(stream);
break;
case INFLATE:
compressedStream = createInflate(stream);
break;
default:
throw new IllegalArgumentException("Argument mode must be either DEFLATE or INFLATE.");
}
}
protected abstract Object createDeflate(Stream stream);
protected abstract Object createInflate(Stream stream);
/**
* Attempts to read count bytes to the given byte array, starting from offset start.<br>
* This method can be used only with CompressedStreams created in INFLATE mode, and should be used only for reading
* compressed data from the original stream, returning uncompressed data on the give byte array.
*
* @since TotalCross 1.12
*/
public int readBytes(byte[] buf, int start, int count) throws IOException, ZipException
{
if (mode != INFLATE)
throw new IOException("This operation can only be performed in INFLATE mode.");
try
{
int r = 0;
do
{
int l = ((InflaterInputStream) compressedStream).read(buf, start, count); // guich@tc125_28
if (l <= 0)
break;
r += l;
start += l;
count -= l;
} while (count > 0);
return r;
}
catch (java.io.EOFException e)
{
return -1;
}
catch (java.io.IOException e)
{
throw new IOException(e.getMessage());
}
}
/**
* Attempts to write count bytes from the given byte array, starting from offset start.<br>
* This method can be used only with CompressedStreams created in DEFLATE mode, and should be used only for
* compressing the contents of the given byte array, and writing the compressed data to the original stream.
*
* @since TotalCross 1.12
*/
public int writeBytes(byte[] buf, int start, int count) throws IOException
{
if (mode != DEFLATE)
throw new IOException("This operation can only be performed in DEFLATE mode.");
try
{
((DeflaterOutputStream) compressedStream).write(buf, start, count);
return count;
}
catch (java.io.IOException e)
{
throw new IOException(e.getMessage());
}
}
/**
* Closes this stream WITHOUT closing the underlying stream, which must be explicitly closed by the user.<br>
*
* @since TotalCross 1.12
*/
public void close() throws IOException
{
try
{
switch (mode)
{
case DEFLATE:
((DeflaterOutputStream) compressedStream).close();
break;
case INFLATE:
((InflaterInputStream) compressedStream).close();
break;
default:
throw new IOException("Invalid object.");
}
}
catch (java.io.IOException e)
{
throw new IOException(e.getMessage());
}
finally
{
mode = 0;
}
}
protected void finalize()
{
try
{
if (mode != 0)
this.close();
}
catch (Throwable t)
{
}
}
}