Initial import
[jpf-core.git] / src / main / gov / nasa / jpf / util / AvailableBufferedInputStream.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18
19 package gov.nasa.jpf.util;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.Arrays;
24
25 public class AvailableBufferedInputStream extends InputStream
26 {
27    private static final boolean CLEAN               = false;
28            static final int     DEFAULT_BUFFER_SIZE = 16 * 1024;        // Not private for testing purposes
29    
30    private final InputStream m_input;
31    private final byte        m_buffer[];
32    private       int         m_read;
33    private       int         m_end;
34    
35    public AvailableBufferedInputStream(InputStream input)
36    {
37       this(input, DEFAULT_BUFFER_SIZE);
38    }
39    
40    public AvailableBufferedInputStream(InputStream input, int bufferSize)
41    {
42       m_input  = input;
43       m_buffer = new byte[bufferSize];
44       
45       if (input == null)
46          throw new NullPointerException("input == null");
47    }
48    
49    public int getBufferSize()
50    {
51       return(m_buffer.length);
52    }
53    
54    @Override
55   public int read() throws IOException
56    {
57       if (m_read >= m_end)
58       {
59          fill();
60       
61          if (m_read >= m_end)
62             return(m_input.read());
63       }
64       
65       return(m_buffer[m_read++] & 0x00FF);
66    }
67
68    @Override
69   public int read(byte buffer[], int offset, int length) throws IOException
70    {
71       if (m_read >= m_end)
72       {
73          fill();
74          
75          if (m_read >= m_end)
76             return(m_input.read(buffer, offset, length));
77       }
78       
79       length  = Math.min(length, m_end - m_read);
80       System.arraycopy(m_buffer, m_read, buffer, offset, length);
81       m_read += length;
82          
83       return(length);
84    }
85
86    public int peek() throws IOException   // Returns -1 if there is nothing to read.
87    {
88       if (m_read >= m_end)
89       {
90          fill();
91          
92          if (m_read >= m_end)
93             return(-1);
94       }
95       
96       return(m_buffer[m_read] & 0x00FF);
97    }
98
99    @Override
100   public int available() throws IOException
101    {
102       if (m_read >= m_end)
103          fill();
104       
105       return(m_end - m_read);
106    }
107    
108    public void unread(int data) throws IOException
109    {
110       if (m_read <= 0)
111       {
112          if (m_end >= m_buffer.length)
113             throw new IOException("Internal buffer overflow");
114          
115          System.arraycopy(m_buffer, m_read, m_buffer, m_buffer.length - m_end, m_end);
116          m_read = m_buffer.length - m_end;
117          m_end  = m_buffer.length;
118       }
119       
120       m_buffer[--m_read] = (byte) data;
121    }
122    
123    private void fill() throws IOException
124    {
125       if (CLEAN)
126          Arrays.fill(m_buffer, 0, m_buffer.length, (byte) 0);
127
128       m_read = 0;
129       m_end  = m_input.available();
130       m_end  = Math.max(m_end, 0);
131
132       if (m_end <= 0)                              // m_input.read(m_buffer, 0, 0) can be expensive.  Don't waste time.
133          return;
134
135       m_end  = Math.min(m_end, m_buffer.length);
136       m_end  = m_input.read(m_buffer, 0, m_end);
137       m_end  = Math.max(m_end, 0);                 // Defend against a bug where m_input.available() returning > 0 and m_input.read() returning -1
138    }
139
140    @Override
141   public String toString()  // For debugging purposes
142    {
143       return(new String(m_buffer, m_read, m_end - m_read));
144    }
145 }