aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io/BufferedInputStream.java
blob: 698abf608af5c68e3b0bd84a40eca1276da9ebb6 (plain)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Copyright (C) 1998, 1999  Cygnus Solutions

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */
 
package java.io;

/**
 * @author Warren Levy <warrenl@cygnus.com>
 * @date October 8, 1998.
 */
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
 * "The Java Language Specification", ISBN 0-201-63451-1
 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
 * Status:  Believed complete and correct.
 */
 
public class BufferedInputStream extends FilterInputStream
{
  /* Internal buffer array for data. */
  protected byte[] buf;

  /* Index one greater than the last valid byte in the buffer. */
  protected int count = 0;

  /* The current position in the buffer. */
  protected int pos = 0;

  /* The value of pos the last time mark() was called. */
  protected int markpos = -1;

  /* The maximum read-ahead allowed before calls to reset() fail. */
  protected int marklimit = 0;

  public BufferedInputStream(InputStream in)
  {
    this(in, 2048);
  }

  public BufferedInputStream(InputStream in, int size)
  {
    super(in);
    if (size <= 0)
      throw new IllegalArgumentException();
    buf = new byte[size];
  }

  public synchronized int available() throws IOException
  {
    return count - pos + super.available();
  }

  public void close() throws IOException
  {
    // Free up the array memory.
    buf = null;
    super.close();
  }

  public synchronized void mark(int readlimit)
  {
    marklimit = readlimit;
    markpos = pos;
  }

  public boolean markSupported()
  {
    return true;
  }

  public synchronized int read() throws IOException
  {
    if (pos >= count && !refill())
      return -1;	// EOF

    if (markpos >= 0 && pos - markpos > marklimit)
      markpos = -1;

    return ((int) buf[pos++]) & 0xFF;
  }

  public synchronized int read(byte[] b, int off, int len) throws IOException
  {
    if (off < 0 || len < 0 || off + len > b.length)
      throw new ArrayIndexOutOfBoundsException();

    if (pos >= count && !refill())
      return -1;		// No bytes were read before EOF.

    int remain = Math.min(count - pos, len);
    System.arraycopy(buf, pos, b, off, remain);
    pos += remain;

    if (markpos >= 0 && pos - markpos > marklimit)
      markpos = -1;

    return remain;
  }

  public synchronized void reset() throws IOException
  {
    if (markpos < 0)
      throw new IOException();

    pos = markpos;
  }

  public synchronized long skip(long n) throws IOException
  {
    final long origN = n;

    while (n > 0L)
      {
	if (pos >= count && !refill())
	  if (n < origN)
	    break;
	  else
	    return -1;	// No bytes were read before EOF.

	int numread = (int) Math.min((long) (count - pos), n);
	pos += numread;
	n -= numread;

        if (markpos >= 0 && pos - markpos > marklimit)
          markpos = -1;
      }

    return origN - n;
  }

  private boolean refill() throws IOException
  {
    if (markpos < 0)
      count = pos = 0;
    else if (markpos > 0)
      {
        // Shift the marked bytes (if any) to the beginning of the array
	// but don't grow it.  This saves space in case a reset is done
	// before we reach the max capacity of this array.
        System.arraycopy(buf, markpos, buf, 0, count - markpos);
	count -= markpos;
	pos -= markpos;
	markpos = 0;
      }
    else if (marklimit >= buf.length)	// BTW, markpos == 0
      {
	// Need to grow the buffer now to have room for marklimit bytes.
	// Note that the new buffer is one greater than marklimit.
	// This is so that there will be one byte past marklimit to be read
	// before having to call refill again, thus allowing marklimit to be
	// invalidated.  That way refill doesn't have to check marklimit.
	byte[] newbuf = new byte[marklimit + 1];
	System.arraycopy(buf, 0, newbuf, 0, count);
	buf = newbuf;
      }

    int numread = super.read(buf, count, buf.length - count);

    if (numread < 0)	// EOF
      return false;

    count += numread;
    return true;
  }
}