View Javadoc

1   /*
2    * Trip Tracker, a real-time position tracking system for the Internet.
3    * Copyright (C) 2006  Team Trip Tracker
4    *
5    * This program is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License as published by the
7    * Free Software Foundation; either version 2 of the License, or (at your
8    * option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful, but
11   * WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13   * General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License along
16   * with this program; if not, write to the Free Software Foundation, Inc.,
17   * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18   */
19  
20  package triptracker.testing.compress;
21  
22  /***
23   * Input stream that decompresses data. 
24   * 
25   * Copyright 2005 - Philip Isenhour - http://javatechniques.com/
26   * 
27   * This software is provided 'as-is', without any express or 
28   * implied warranty. In no event will the authors be held liable 
29   * for any damages arising from the use of this software.
30   *
31   * Permission is granted to anyone to use this software for any 
32   * purpose, including commercial applications, and to alter it and 
33   * redistribute it freely, subject to the following restrictions:
34   *
35   *  1. The origin of this software must not be misrepresented; you 
36   *     must not claim that you wrote the original software. If you 
37   *     use this software in a product, an acknowledgment in the 
38   *     product documentation would be appreciated but is not required.
39   *
40   *  2. Altered source versions must be plainly marked as such, and 
41   *     must not be misrepresented as being the original software.
42   *
43   *  3. This notice may not be removed or altered from any source 
44   *     distribution.
45   *
46   * $Id:  1.2 2005/10/26 17:40:19 isenhour Exp $
47   */
48  import java.io.EOFException;
49  import java.io.FilterInputStream;
50  import java.io.IOException;
51  import java.io.InputStream;
52  import java.util.zip.DataFormatException;
53  import java.util.zip.Inflater;
54  
55  public class CompressedBlockInputStream extends FilterInputStream {
56  	/***
57  	 * Buffer of compressed data read from the stream
58  	 */
59  	private byte[] inBuf = null;
60  
61  	/***
62  	 * Length of data in the input data
63  	 */
64  	private int inLength = 0;
65  
66  	/***
67  	 * Buffer of uncompressed data
68  	 */
69  	private byte[] outBuf = null;
70  
71  	/***
72  	 * Offset and length of uncompressed data
73  	 */
74  	private int outOffs = 0;
75  
76  	private int outLength = 0;
77  
78  	/***
79  	 * Inflater for decompressing
80  	 */
81  	private Inflater inflater = null;
82  
83  	public CompressedBlockInputStream(InputStream is) throws IOException {
84  		super(is);
85  		inflater = new Inflater();
86  	}
87  
88  	private void readAndDecompress() throws IOException {
89  		// Read the length of the compressed block
90  		int ch1 = in.read();
91  		int ch2 = in.read();
92  		int ch3 = in.read();
93  		int ch4 = in.read();
94  		if ((ch1 | ch2 | ch3 | ch4) < 0)
95  			throw new EOFException();
96  		inLength = ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
97  
98  		ch1 = in.read();
99  		ch2 = in.read();
100 		ch3 = in.read();
101 		ch4 = in.read();
102 		if ((ch1 | ch2 | ch3 | ch4) < 0)
103 			throw new EOFException();
104 		outLength = ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
105 
106 		// Make sure we've got enough space to read the block
107 		if ((inBuf == null) || (inLength > inBuf.length)) {
108 			inBuf = new byte[inLength];
109 		}
110 
111 		if ((outBuf == null) || (outLength > outBuf.length)) {
112 			outBuf = new byte[outLength];
113 		}
114 
115 		// Read until we're got the entire compressed buffer.
116 		// read(...) will not necessarily block until all
117 		// requested data has been read, so we loop until
118 		// we're done.
119 		int inOffs = 0;
120 		while (inOffs < inLength) {
121 			int inCount = in.read(inBuf, inOffs, inLength - inOffs);
122 			if (inCount == -1) {
123 				throw new EOFException();
124 			}
125 			inOffs += inCount;
126 		}
127 
128 		inflater.setInput(inBuf, 0, inLength);
129 		try {
130 			inflater.inflate(outBuf);
131 		} catch (DataFormatException dfe) {
132 			throw new IOException("Data format exception - "
133 					+ dfe.getMessage());
134 		}
135 
136 		// Reset the inflator so we can re-use it for the
137 		// next block
138 		inflater.reset();
139 
140 		outOffs = 0;
141 	}
142 
143 	@Override
144 	public int read() throws IOException {
145 		if (outOffs >= outLength) {
146 			try {
147 				readAndDecompress();
148 			} catch (EOFException eof) {
149 				return -1;
150 			}
151 		}
152 
153 		return outBuf[outOffs++] & 0xff;
154 	}
155 	
156 //	@Override
157 //	public int read(byte[] b) throws IOException {
158 //		return read(b, 0, b.length);
159 //	}
160 
161 	@Override
162 	public int read(byte[] b, int off, int len) throws IOException {
163 		int count = 0;
164 		while (count < len) {
165 			if (outOffs >= outLength) {
166 				try {
167 					// If we've read at least one decompressed
168 					// byte and further decompression would
169 					// require blocking, return the count.
170 					if ((count > 0) && (in.available() == 0))
171 						return count;
172 					else
173 						readAndDecompress();
174 				} catch (EOFException eof) {
175 					if (count == 0)
176 						count = -1;
177 					return count;
178 				}
179 			}
180 
181 			int toCopy = Math.min(outLength - outOffs, len - count);
182 			System.arraycopy(outBuf, outOffs, b, off + count, toCopy);
183 			outOffs += toCopy;
184 			count += toCopy;
185 		}
186 
187 		return count;
188 	}
189 
190 	@Override
191 	public int available() throws IOException {
192 		// This isn't precise, but should be an adequate
193 		// lower bound on the actual amount of available data
194 		return (outLength - outOffs) + in.available();
195 	}
196 
197 }