1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.client;
30
31 import java.io.InputStream;
32 import java.io.IOException;
33
34 import org.apache.mina.common.ByteBuffer;
35
36 import uk.ac.rdg.resc.jstyx.StyxException;
37
38 /***
39 * InputStream for reading from a file on a Styx server
40 * @todo Implement read(byte[]), read(byte[], off, len), skip() in most
41 * efficient way possible
42 * @todo Also make into a Channel?
43 *
44 * @author Jon Blower
45 * $Revision: 385 $
46 * $Date: 2005-09-01 18:12:11 +0100 (Thu, 01 Sep 2005) $
47 * $Log$
48 * Revision 1.2 2005/09/01 17:12:09 jonblower
49 * Changes to Input and Output stream code
50 *
51 * Revision 1.1 2005/08/31 17:03:18 jonblower
52 * Renamed "StyxFile*putStream*" to "CStyxFile*putStream*" for consistency with CStyxFile class
53 *
54 * Revision 1.8 2005/06/22 17:07:29 jonblower
55 * Added read(byte[]) method
56 *
57 * Revision 1.7 2005/05/12 07:40:52 jonblower
58 * CStyxFile.close() no longer throws a StyxException
59 *
60 * Revision 1.6 2005/05/05 07:09:06 jonblower
61 * Improved comments
62 *
63 * Revision 1.5 2005/05/04 16:25:49 jonblower
64 * Improved parameter naming in constructor
65 *
66 * Revision 1.4 2005/03/22 10:19:52 jonblower
67 * Fixed problem with ByteBuffer leak in StyxMessageDecoder and CStyxFileInputStream
68 *
69 * Revision 1.3 2005/03/19 21:46:58 jonblower
70 * Further fixes relating to releasing ByteBuffers
71 *
72 * Revision 1.2 2005/03/16 17:55:53 jonblower
73 * Replaced use of java.nio.ByteBuffer with MINA's ByteBuffer to minimise copying of buffers
74 *
75 * Revision 1.1.1.1 2005/02/16 18:58:19 jonblower
76 * Initial import
77 */
78 public class CStyxFileInputStream extends InputStream
79 {
80
81 private CStyxFile file;
82 private ByteBuffer buf;
83 private long offset;
84 private boolean eof;
85 private boolean closeConnectionWhenCloseStream;
86
87
88
89 /***
90 * Creates a CStyxFileInputStream for reading the given file.
91 * @param file The file to read from
92 * @param closeConnectionWhenCloseStream If this is true, we shall close the underlying
93 * StyxConnection when this stream is closed (this is normally set when
94 * getting an input stream through the StyxURLConnection class)
95 */
96 public CStyxFileInputStream(CStyxFile file, boolean closeConnectionWhenCloseStream)
97 {
98 if (file == null)
99 {
100 throw new NullPointerException("file cannot be null");
101 }
102 this.file = file;
103 this.buf = null;
104 this.offset = 0;
105 this.eof = false;
106 this.closeConnectionWhenCloseStream = closeConnectionWhenCloseStream;
107 }
108
109 public CStyxFileInputStream(CStyxFile file)
110 {
111 this(file, false);
112 }
113
114 public int read() throws IOException
115 {
116 if (this.eof)
117 {
118 return -1;
119 }
120
121 if (this.buf != null && this.buf.hasRemaining())
122 {
123 return buf.get() & 0xff;
124 }
125 else
126 {
127
128
129 try
130 {
131
132 if (this.buf != null)
133 {
134 this.buf.release();
135 }
136
137 this.buf = this.file.read(this.offset);
138 if (this.buf.remaining() > 0)
139 {
140
141 this.offset += this.buf.remaining();
142
143 return buf.get() & 0xff;
144 }
145 else
146 {
147
148 this.eof = true;
149
150 this.buf.release();
151 return -1;
152 }
153 }
154 catch(StyxException e)
155 {
156 throw new IOException(e.getMessage());
157 }
158 }
159 }
160
161 public int read(byte b[], int off, int len) throws IOException
162 {
163 if (b == null)
164 {
165 throw new NullPointerException();
166 }
167 else if ((off < 0) || (off > b.length) || (len < 0) ||
168 ((off + len) > b.length) || ((off + len) < 0))
169 {
170 throw new IndexOutOfBoundsException();
171 }
172 else if (len == 0)
173 {
174 return 0;
175 }
176
177 if (this.eof)
178 {
179 return -1;
180 }
181
182
183 if (this.buf != null && this.buf.hasRemaining())
184 {
185
186 int bytesToGet = Math.min(this.buf.remaining(), len);
187 this.buf.get(b, off, bytesToGet);
188 return bytesToGet;
189 }
190 else
191 {
192
193
194 try
195 {
196
197 if (this.buf != null)
198 {
199 this.buf.release();
200 }
201
202 this.buf = this.file.read(this.offset);
203 if (this.buf.remaining() > 0)
204 {
205
206 this.offset += this.buf.remaining();
207
208 int bytesToGet = Math.min(this.buf.remaining(), len);
209 this.buf.get(b, off, bytesToGet);
210 return bytesToGet;
211 }
212 else
213 {
214
215 this.eof = true;
216
217 this.buf.release();
218 return -1;
219 }
220 }
221 catch(StyxException e)
222 {
223 throw new IOException(e.getMessage());
224 }
225 }
226 }
227
228 /***
229 * @return the number of bytes that can be read without blocking
230 */
231 public int available() throws IOException
232 {
233 return (this.buf == null) ? 0 : this.buf.remaining();
234 }
235
236 /***
237 * Closes the stream (clunks the underlying file). If this InputStream was
238 * created with <code>closeConnectionWhenCloseStream = true</code>, this will
239 * also close the StyxConnection.
240 */
241 public void close() throws IOException
242 {
243 this.file.close();
244 this.offset = 0;
245 this.eof = false;
246 if (this.closeConnectionWhenCloseStream)
247 {
248 this.file.getConnection().close();
249 }
250 this.buf = null;
251 }
252 }