KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > HTTPClient > ExtBufferedInputStream


1 /*
2  * @(#)ExtBufferedInputStream.java 0.3-2 18/06/1999
3  *
4  * This file is part of the HTTPClient package
5  * Copyright (C) 1996-1999 Ronald Tschalär
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307, USA
21  *
22  * For questions, suggestions, bug-reports, enhancement-requests etc.
23  * I may be contacted at:
24  *
25  * ronald@innovation.ch
26  *
27  */

28
29 package HTTPClient;
30
31
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.FilterInputStream JavaDoc;
35
36
37 /**
38  * This class is a modified copy of java.io.BufferedInputStream which fixes
39  * the problem in fill when an InterrupedIOException occurs and which
40  * extends the class to allow searching for a string in the internal buffer
41  * (used for multipart content-types).
42  *
43  * @version 0.3-2 18/06/1999
44  * @author Ronald Tschalär
45  * @author Arthur van Hoff
46  */

47
48 /*
49  * @(#)BufferedInputStream.java 1.26 97/03/03
50  *
51  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
52  *
53  * This software is the confidential and proprietary information of Sun
54  * Microsystems, Inc. ("Confidential Information"). You shall not
55  * disclose such Confidential Information and shall use it only in
56  * accordance with the terms of the license agreement you entered into
57  * with Sun.
58  *
59  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
60  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
62  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
63  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
64  * THIS SOFTWARE OR ITS DERIVATIVES.
65  *
66  * CopyrightVersion 1.1_beta
67  *
68  */

69
70 final class ExtBufferedInputStream extends FilterInputStream JavaDoc
71 {
72     /**
73      * The buffer where data is stored.
74      *
75      * @since JDK1.0
76      */

77     protected byte buf[];
78
79     /**
80      * The index one greater than the index of the last valid byte in
81      * the buffer.
82      *
83      * @since JDK1.0
84      */

85     protected int count;
86
87     /**
88      * The current position in the buffer. This is the index of the next
89      * character to be read from the <code>buf</code> array.
90      *
91      * @see java.io.BufferedInputStream#buf
92      * @since JDK1.0
93      */

94     protected int pos;
95     
96     /**
97      * The value of the <code>pos</code> field at the time the last
98      * <code>mark</code> method was called. The value of this field is
99      * <code>-1</code> if there is no current mark.
100      *
101      * @see java.io.BufferedInputStream#mark(int)
102      * @see java.io.BufferedInputStream#pos
103      * @since JDK1.0
104      */

105     protected int markpos = -1;
106
107     /**
108      * The maximum read ahead allowed after a call to the
109      * <code>mark</code> method before subsequent calls to the
110      * <code>reset</code> method fail.
111      *
112      * @see java.io.BufferedInputStream#mark(int)
113      * @see java.io.BufferedInputStream#reset()
114      * @since JDK1.0
115      */

116     protected int marklimit;
117
118     /**
119      * Creates a new buffered input stream to read data from the
120      * specified input stream with a default 512-byte buffer size.
121      *
122      * @param in the underlying input stream.
123      * @since JDK1.0
124      */

125     public ExtBufferedInputStream(InputStream JavaDoc in)
126     {
127     this(in, 2048);
128     }
129
130     /**
131      * Creates a new buffered input stream to read data from the
132      * specified input stream with the specified buffer size.
133      *
134      * @param in the underlying input stream.
135      * @param size the buffer size.
136      * @since JDK1.0
137      */

138     public ExtBufferedInputStream(InputStream JavaDoc in, int size)
139     {
140     super(in);
141     buf = new byte[size];
142     }
143
144     /**
145      * Fills the buffer with more data, taking into account
146      * shuffling and other tricks for dealing with marks.
147      * Assumes that it is being called by a synchronized method.
148      * This method also assumes that all data has already been read in,
149      * hence pos > count.
150      */

151     private void fill() throws IOException JavaDoc
152     {
153     if (markpos < 0)
154         pos = 0; /* no mark: throw away the buffer */
155     else if (pos >= buf.length) /* no room left in buffer */
156     {
157         if (markpos > 0) /* can throw away early part of the buffer */
158         {
159         int sz = pos - markpos;
160         System.arraycopy(buf, markpos, buf, 0, sz);
161         pos = sz;
162         markpos = 0;
163         }
164         else if (buf.length >= marklimit)
165         {
166         markpos = -1; /* buffer got too big, invalidate mark */
167         pos = 0; /* drop buffer contents */
168         }
169         else /* grow buffer */
170         {
171         int nsz = pos * 2;
172         if (nsz > marklimit)
173             nsz = marklimit;
174         byte nbuf[] = new byte[nsz];
175         System.arraycopy(buf, 0, nbuf, 0, pos);
176         buf = nbuf;
177         }
178     }
179     count = pos; // in case read() throws InterruptedIOException
180
int n = in.read(buf, pos, buf.length - pos);
181     count = n <= 0 ? pos : n + pos;
182     }
183
184     /**
185      * Reads the next byte of data from this buffered input stream. The
186      * value byte is returned as an <code>int</code> in the range
187      * <code>0</code> to <code>255</code>. If no byte is available
188      * because the end of the stream has been reached, the value
189      * <code>-1</code> is returned. This method blocks until input data
190      * is available, the end of the stream is detected, or an exception
191      * is thrown.
192      * <p>
193      * The <code>read</code> method of <code>BufferedInputStream</code>
194      * returns the next byte of data from its buffer if the buffer is not
195      * empty. Otherwise, it refills the buffer from the underlying input
196      * stream and returns the next character, if the underlying stream
197      * has not returned an end-of-stream indicator.
198      *
199      * @return the next byte of data, or <code>-1</code> if the end of the
200      * stream is reached.
201      * @exception IOException if an I/O error occurs.
202      * @see java.io.FilterInputStream#in
203      * @since JDK1.0
204      */

205     public synchronized int read() throws IOException JavaDoc
206     {
207     if (pos >= count)
208     {
209         fill();
210         if (pos >= count)
211         return -1;
212     }
213     return buf[pos++] & 0xff;
214     }
215
216     /**
217      * Reads bytes into a portion of an array. This method will block until
218      * some input is available, an I/O error occurs, or the end of the stream
219      * is reached.
220      *
221      * <p> If this stream's buffer is not empty, bytes are copied from it into
222      * the array argument. Otherwise, the buffer is refilled from the
223      * underlying input stream and, unless the stream returns an end-of-stream
224      * indication, the array argument is filled with characters from the
225      * newly-filled buffer.
226      *
227      * <p> As an optimization, if the buffer is empty, the mark is not valid,
228      * and <code>len</code> is at least as large as the buffer, then this
229      * method will read directly from the underlying stream into the given
230      * array. Thus redundant <code>BufferedInputStream</code>s will not copy
231      * data unnecessarily.
232      *
233      * @param b destination buffer.
234      * @param off offset at which to start storing bytes.
235      * @param len maximum number of bytes to read.
236      * @return the number of bytes read, or <code>-1</code> if the end of
237      * the stream has been reached.
238      * @exception IOException if an I/O error occurs.
239      */

240     public synchronized int read(byte b[], int off, int len) throws IOException JavaDoc
241     {
242     int avail = count - pos;
243     if (avail <= 0)
244     {
245         /* If the requested length is larger than the buffer, and if there
246            is no mark/reset activity, do not bother to copy the bytes into
247            the local buffer. In this way buffered streams will cascade
248            harmlessly. */

249         if (len >= buf.length && markpos < 0)
250         return in.read(b, off, len);
251
252         fill();
253         avail = count - pos;
254         if (avail <= 0)
255         return -1;
256     }
257     int cnt = (avail < len) ? avail : len;
258     System.arraycopy(buf, pos, b, off, cnt);
259     pos += cnt;
260     return cnt;
261     }
262
263     /**
264      * Skips over and discards <code>n</code> bytes of data from the
265      * input stream. The <code>skip</code> method may, for a variety of
266      * reasons, end up skipping over some smaller number of bytes,
267      * possibly zero. The actual number of bytes skipped is returned.
268      * <p>
269      * The <code>skip</code> method of <code>BufferedInputStream</code>
270      * compares the number of bytes it has available in its buffer,
271      * <i>k</i>, where <i>k</i>&nbsp;= <code>count&nbsp;- pos</code>,
272      * with <code>n</code>. If <code>n</code>&nbsp;&le;&nbsp;<i>k</i>,
273      * then the <code>pos</code> field is incremented by <code>n</code>.
274      * Otherwise, the <code>pos</code> field is incremented to have the
275      * value <code>count</code>, and the remaining bytes are skipped by
276      * calling the <code>skip</code> method on the underlying input
277      * stream, supplying the argument <code>n&nbsp;-</code>&nbsp;<i>k</i>.
278      *
279      * @param n the number of bytes to be skipped.
280      * @return the actual number of bytes skipped.
281      * @exception IOException if an I/O error occurs.
282      * @since JDK1.0
283      */

284     public synchronized long skip(long n) throws IOException JavaDoc
285     {
286     if (n < 0)
287         return 0;
288
289     long avail = count - pos;
290
291     if (avail >= n)
292     {
293         pos += n;
294         return n;
295     }
296
297     pos += avail;
298     return avail + in.skip(n - avail);
299     }
300
301     /**
302      * Returns the number of bytes that can be read from this input
303      * stream without blocking.
304      * <p>
305      * The <code>available</code> method of
306      * <code>BufferedInputStream</code> returns the sum of the the number
307      * of bytes remaining to be read in the buffer
308      * (<code>count&nbsp;- pos</code>)
309      * and the result of calling the <code>available</code> method of the
310      * underlying input stream.
311      *
312      * @return the number of bytes that can be read from this input
313      * stream without blocking.
314      * @exception IOException if an I/O error occurs.
315      * @see java.io.FilterInputStream#in
316      * @since JDK1.0
317      */

318     public synchronized int available() throws IOException JavaDoc
319     {
320     return (count - pos) + in.available();
321     }
322
323     /**
324      * Marks the current position in this input stream. A subsequent
325      * call to the <code>reset</code> method repositions the stream at
326      * the last marked position so that subsequent reads re-read the same
327      * bytes.
328      * <p>
329      * The <code>readlimit</code> argument tells the input stream to
330      * allow that many bytes to be read before the mark position gets
331      * invalidated.
332      *
333      * @param readlimit the maximum limit of bytes that can be read before
334      * the mark position becomes invalid.
335      * @see java.io.BufferedInputStream#reset()
336      * @since JDK1.0
337      */

338     public synchronized void mark(int readlimit)
339     {
340     marklimit = readlimit;
341     markpos = pos;
342     }
343
344     /**
345      * Repositions this stream to the position at the time the
346      * <code>mark</code> method was last called on this input stream.
347      * <p>
348      * If the stream has not been marked, or if the mark has been invalidated,
349      * an IOException is thrown. Stream marks are intended to be used in
350      * situations where you need to read ahead a little to see what's in
351      * the stream. Often this is most easily done by invoking some
352      * general parser. If the stream is of the type handled by the
353      * parser, it just chugs along happily. If the stream is not of
354      * that type, the parser should toss an exception when it fails. If an
355      * exception gets tossed within readlimit bytes, the parser will allow the
356      * outer code to reset the stream and to try another parser.
357      *
358      * @exception IOException if this stream has not been marked or
359      * if the mark has been invalidated.
360      * @see java.io.BufferedInputStream#mark(int)
361      * @since JDK1.0
362      */

363     public synchronized void reset() throws IOException JavaDoc
364     {
365     if (markpos < 0)
366         throw new IOException JavaDoc("Resetting to invalid mark");
367     pos = markpos;
368     }
369
370     /**
371      * Tests if this input stream supports the <code>mark</code>
372      * and <code>reset</code> methods. The <code>markSupported</code>
373      * method of <code>BufferedInputStream</code> returns
374      * <code>true</code>.
375      *
376      * @return a <code>boolean</code> indicating if this stream type supports
377      * the <code>mark</code> and <code>reset</code> methods.
378      * @see java.io.InputStream#mark(int)
379      * @see java.io.InputStream#reset()
380      * @since JDK1.0
381
382      */

383     public boolean markSupported()
384     {
385     return true;
386     }
387
388
389     /**
390      * Figures out how many bytes past the end of the multipart we read.
391      * It then resets the markpos to either just past the end boundary
392      * if we found it, or back enough from the current position so we
393      * can always be sure to find the boundary.
394      *
395      * @param search the search string (end boundary)
396      * @param search_cmp the compiled info of the search string
397      * @return how many bytes past the end of the boundary we went.
398      */

399     int pastEnd(byte[] search, int[] search_cmp)
400     {
401     int idx = Util.findStr(search, search_cmp, buf, markpos, pos);
402     if (idx == -1)
403         markpos = pos - search.length;
404     else
405     {
406         markpos = idx + search.length;
407         idx = pos - markpos;
408     }
409
410     return idx;
411     }
412
413
414     /**
415      * Initialises the mark and sets the marklimit to the buffer length.
416      */

417     void initMark()
418     {
419     mark(buf.length);
420     }
421 }
422
Popular Tags