001    /*
002    Copyright (c) 1996-2011, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    package org.hd.d.pg2k.svrCore;
030    
031    import java.io.ByteArrayInputStream;
032    import java.io.IOException;
033    import java.io.InputStream;
034    import java.io.SequenceInputStream;
035    import java.util.zip.Inflater;
036    import java.util.zip.InflaterInputStream;
037    
038    /**Like GZIPInputStream but no GZIP or ZLIB header or checksum.
039     * This is meant to give maximum compression and assumes error
040     * checking/recovery is done elsewhere.
041     */
042    public final class DefInputStream extends InflaterInputStream
043        {
044        /**Indicates end of input stream. */
045        private boolean eos;
046    
047        /**Is the stream already closed? */
048        private boolean closed = false;
049    
050        /**Check to make sure that this stream has not been closed.
051         */
052        private synchronized void ensureOpen()
053            throws IOException
054            { if(closed) { throw new IOException("already closed"); } }
055    
056        /**Creates a new input stream with the specified buffer size.
057         * In cases where we know that the input stream has one or more
058         * trailing bytes that we don't care about
059         * then the hasDummyTrailingData arg can be true
060         * to save us having to wrap the input stream.
061         *
062         * @param in     the input stream
063         * @param hasDummyTrailingByte  if true then the input stream has
064         *     one or more bytes of trailing data that ZLIB can eat harmlessly
065         * @exception    IOException if an I/O error has occurred
066         */
067        public DefInputStream(final InputStream in,
068                              final boolean hasDummyTrailingByte)
069            throws IOException
070            {
071            super(hasDummyTrailingByte ? in : new SequenceInputStream(in, new ByteArrayInputStream(new byte[1])),
072                  new Inflater(true),
073                  512); // Standard deflater buffer size is fine...
074            }
075    
076        /**Creates a new input stream with a default buffer size.
077         * @param in   the input stream
078         * @exception  IOException if an I/O error has occurred
079         */
080        public DefInputStream(final InputStream in)
081            throws IOException
082            { this(in, false); }
083    
084        /**Reads uncompressed data into an array of bytes.
085         * Blocks until enough input is available for decompression.
086         *
087         * @return  the actual number of bytes read, or -1 if the end of the
088         *          compressed input stream is reached
089         * @exception IOException  if an I/O error has occurred or the compressed
090         *     input data is corrupt
091         */
092        @Override
093        public synchronized int read(final byte[] buf, final int off, int len)
094            throws IOException
095            {
096            ensureOpen();
097            if(eos) { return(-1); }
098            len = super.read(buf, off, len);
099            if(len == -1) { eos = true; }
100            return(len);
101            }
102    
103        /**Closes the input stream and releases non-Java resources.
104         * @exception IOException  if an I/O error has occurred
105         */
106        @Override
107        public synchronized void close()
108            throws IOException
109            {
110            inf.end();
111            in.close();
112            eos = true;
113            closed = true;
114            }
115        }