Initial revision
[gcc.git] / libjava / java / io / BufferedInputStream.java
1 /* Copyright (C) 1998, 1999 Cygnus Solutions
2
3 This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
7 details. */
8
9 package java.io;
10
11 /**
12 * @author Warren Levy <warrenl@cygnus.com>
13 * @date October 8, 1998.
14 */
15 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
16 * "The Java Language Specification", ISBN 0-201-63451-1
17 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
18 * Status: Believed complete and correct.
19 */
20
21 public class BufferedInputStream extends FilterInputStream
22 {
23 /* Internal buffer array for data. */
24 protected byte[] buf;
25
26 /* Index one greater than the last valid byte in the buffer. */
27 protected int count = 0;
28
29 /* The current position in the buffer. */
30 protected int pos = 0;
31
32 /* The value of pos the last time mark() was called. */
33 protected int markpos = -1;
34
35 /* The maximum read-ahead allowed before calls to reset() fail. */
36 protected int marklimit = 0;
37
38 public BufferedInputStream(InputStream in)
39 {
40 this(in, 2048);
41 }
42
43 public BufferedInputStream(InputStream in, int size)
44 {
45 super(in);
46 if (size <= 0)
47 throw new IllegalArgumentException();
48 buf = new byte[size];
49 }
50
51 public synchronized int available() throws IOException
52 {
53 return count - pos + super.available();
54 }
55
56 public void close() throws IOException
57 {
58 // Free up the array memory.
59 buf = null;
60 super.close();
61 }
62
63 public synchronized void mark(int readlimit)
64 {
65 marklimit = readlimit;
66 markpos = pos;
67 }
68
69 public boolean markSupported()
70 {
71 return true;
72 }
73
74 public synchronized int read() throws IOException
75 {
76 if (pos >= count && !refill())
77 return -1; // EOF
78
79 if (markpos >= 0 && pos - markpos > marklimit)
80 markpos = -1;
81
82 return ((int) buf[pos++]) & 0xFF;
83 }
84
85 public synchronized int read(byte[] b, int off, int len) throws IOException
86 {
87 if (off < 0 || len < 0 || off + len > b.length)
88 throw new ArrayIndexOutOfBoundsException();
89
90 if (pos >= count && !refill())
91 return -1; // No bytes were read before EOF.
92
93 int remain = Math.min(count - pos, len);
94 System.arraycopy(buf, pos, b, off, remain);
95 pos += remain;
96
97 if (markpos >= 0 && pos - markpos > marklimit)
98 markpos = -1;
99
100 return remain;
101 }
102
103 public synchronized void reset() throws IOException
104 {
105 if (markpos < 0)
106 throw new IOException();
107
108 pos = markpos;
109 }
110
111 public synchronized long skip(long n) throws IOException
112 {
113 final long origN = n;
114
115 while (n > 0L)
116 {
117 if (pos >= count && !refill())
118 if (n < origN)
119 break;
120 else
121 return -1; // No bytes were read before EOF.
122
123 int numread = (int) Math.min((long) (count - pos), n);
124 pos += numread;
125 n -= numread;
126
127 if (markpos >= 0 && pos - markpos > marklimit)
128 markpos = -1;
129 }
130
131 return origN - n;
132 }
133
134 private boolean refill() throws IOException
135 {
136 if (markpos < 0)
137 count = pos = 0;
138 else if (markpos > 0)
139 {
140 // Shift the marked bytes (if any) to the beginning of the array
141 // but don't grow it. This saves space in case a reset is done
142 // before we reach the max capacity of this array.
143 System.arraycopy(buf, markpos, buf, 0, count - markpos);
144 count -= markpos;
145 pos -= markpos;
146 markpos = 0;
147 }
148 else if (marklimit >= buf.length) // BTW, markpos == 0
149 {
150 // Need to grow the buffer now to have room for marklimit bytes.
151 // Note that the new buffer is one greater than marklimit.
152 // This is so that there will be one byte past marklimit to be read
153 // before having to call refill again, thus allowing marklimit to be
154 // invalidated. That way refill doesn't have to check marklimit.
155 byte[] newbuf = new byte[marklimit + 1];
156 System.arraycopy(buf, 0, newbuf, 0, count);
157 buf = newbuf;
158 }
159
160 int numread = super.read(buf, count, buf.length - count);
161
162 if (numread < 0) // EOF
163 return false;
164
165 count += numread;
166 return true;
167 }
168 }