KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > io > ByteArrayPushBackInputStream


1 /**
2  * Copyright (c) 2004, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.io;
32
33 import java.io.ByteArrayInputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36
37 /**
38  * PushBackInputStream for byte arrays.
39  *
40  * The inheritance from PushBackInputStream is only to avoid the
41  * introduction of an interface with all PushBackInputStream
42  * methods. The parent PushBackInputStream is not used in any way and
43  * all methods are overridden. (Thus when adding new methods to PushBackInputStream
44  * override them in this class as well!)
45  * unread() is limited to the number of bytes already read from this stream (i.e.
46  * the current position in the array). This limitation usually poses no problem
47  * to a parser, but allows for some optimization since only one array has to
48  * be dealt with.
49  *
50  * Note: This class is not thread safe. Clients must provide synchronization
51  * if needed.
52  *
53  * Note: Calling unread() after mark() will cause (part of) the unread data to be
54  * read again after reset(). Thus do not call unread() between mark() and reset().
55  *
56  * @author Andreas Weiss (andreas.weiss@switzerland.org)
57  * @version $Revision: 1.2 $
58  */

59 public class ByteArrayPushBackInputStream extends PushBackInputStream
60 {
61     private byte[] data;
62     private int datapos;
63     private int datalen;
64     private int save;
65     
66     // dummy for base class constructor
67
private static final InputStream JavaDoc DUMMY = new ByteArrayInputStream JavaDoc("".getBytes());
68     
69     /**
70      * Constructor.
71      * @param input Data to read from. Note that calls to unread() will
72      * modify this array! If this is not desired, pass a copy.
73      *
74      * @throws IOException If there is an IO error.
75      */

76     public ByteArrayPushBackInputStream(byte[] input) throws IOException JavaDoc
77     {
78         super(DUMMY, 1);
79         data = input;
80         datapos = 0;
81         save = datapos;
82         datalen = input != null ? input.length : 0;
83     }
84     
85     /**
86      * This will peek at the next byte.
87      *
88      * @return The next byte on the stream, leaving it as available to read.
89      */

90     public int peek()
91     {
92         try
93         {
94             // convert negative values to 128..255
95
return (data[datapos] + 0x100) & 0xff;
96         }
97         catch (ArrayIndexOutOfBoundsException JavaDoc ex)
98         {
99             // could check this before, but this is a rare case
100
// and this method is called sufficiently often to justify this
101
// optimization
102
return -1;
103         }
104     }
105
106     /**
107      * A simple test to see if we are at the end of the stream.
108      *
109      * @return true if we are at the end of the stream.
110      */

111     public boolean isEOF()
112     {
113         return datapos >= datalen;
114     }
115     
116     /**
117      * Save the state of this stream.
118      * @param readlimit Has no effect.
119      * @see InputStream#mark(int)
120      */

121     public void mark(int readlimit)
122     {
123         if (false)
124         {
125             ++readlimit; // avoid unused param warning
126
}
127         save = datapos;
128     }
129     
130     /**
131      * Check if mark is supported.
132      * @return Always true.
133      * @see InputStream#markSupported()
134      */

135     public boolean markSupported()
136     {
137         return true;
138     }
139     
140     /**
141      * Restore the state of this stream to the last saveState call.
142      * @see InputStream#reset()
143      */

144     public void reset()
145     {
146         datapos = save;
147     }
148     
149     /** Available bytes.
150      * @see InputStream#available()
151      * @return Available bytes.
152      */

153     public int available()
154     {
155         int av = datalen - datapos;
156         return av > 0 ? av : 0;
157     }
158     
159     /** Totally available bytes in the underlying array.
160      * @return Available bytes.
161      */

162     public int size()
163     {
164         return datalen;
165     }
166     
167     /**
168      * Pushes back a byte.
169      * After this method returns, the next byte to be read will have the value (byte)by.
170      * @param by the int value whose low-order byte is to be pushed back.
171      * @throws IOException - If there is not enough room in the buffer for the byte.
172      * @see java.io.PushbackInputStream#unread(int)
173      */

174     public void unread(int by) throws IOException JavaDoc
175     {
176         if (datapos == 0)
177         {
178             throw new IOException JavaDoc("ByteArrayParserInputStream.unread(int): " +
179                                   "cannot unread 1 byte at buffer position " + datapos);
180         }
181         --datapos;
182         data[datapos] = (byte)by;
183     }
184
185     /**
186      * Pushes back a portion of an array of bytes by copying it to the
187      * front of the pushback buffer. After this method returns, the next byte
188      * to be read will have the value b[off], the byte after that will have
189      * the value b[off+1], and so forth.
190      * @param buffer the byte array to push back.
191      * @param off the start offset of the data.
192      * @param len the number of bytes to push back.
193      * @throws IOException If there is not enough room in the pushback buffer
194      * for the specified number of bytes.
195      * @see java.io.PushbackInputStream#unread(byte[], int, int)
196      */

197     public void unread(byte[] buffer, int off, int len) throws IOException JavaDoc
198     {
199         if (len <= 0 || off >= buffer.length)
200         {
201             return;
202         }
203         if (off < 0)
204         {
205             off = 0;
206         }
207         if (len > buffer.length)
208         {
209             len = buffer.length;
210         }
211         localUnread(buffer, off, len);
212     }
213     
214     /**
215      * Pushes back a portion of an array of bytes by copying it to the
216      * front of the pushback buffer. After this method returns, the next byte
217      * to be read will have the value buffer[0], the byte after that will have
218      * the value buffer[1], and so forth.
219      * @param buffer the byte array to push back.
220      * @throws IOException If there is not enough room in the pushback buffer
221      * for the specified number of bytes.
222      * @see java.io.PushbackInputStream#unread(byte[])
223      */

224     public void unread(byte[] buffer) throws IOException JavaDoc
225     {
226         localUnread(buffer, 0, buffer.length);
227     }
228  
229     /**
230      * Pushes back a portion of an array of bytes by copying it to the
231      * front of the pushback buffer. After this method returns, the next byte
232      * to be read will have the value buffer[off], the byte after that will have
233      * the value buffer[off+1], and so forth.
234      * Internal method that assumes off and len to be valid.
235      * @param buffer the byte array to push back.
236      * @param off the start offset of the data.
237      * @param len the number of bytes to push back.
238      * @throws IOException If there is not enough room in the pushback buffer
239      * for the specified number of bytes.
240      * @see java.io.PushbackInputStream#unread(byte[], int, int)
241      */

242     private void localUnread(byte[] buffer, int off, int len) throws IOException JavaDoc
243     {
244         if (datapos < len)
245         {
246             throw new IOException JavaDoc("ByteArrayParserInputStream.unread(int): " +
247                                   "cannot unread " + len +
248                                   " bytes at buffer position " + datapos);
249         }
250         datapos -= len;
251         System.arraycopy(buffer, off, data, datapos, len);
252     }
253        
254     /**
255      * Read a byte.
256      * @see InputStream#read()
257      * @return Byte read or -1 if no more bytes are available.
258      */

259     public int read()
260     {
261         try
262         {
263             // convert negative values to 128..255
264
return (data[datapos++] + 0x100) & 0xff;
265         }
266         catch (ArrayIndexOutOfBoundsException JavaDoc ex)
267         {
268             // could check this before, but this is a rare case
269
// and this method is called sufficiently often to justify this
270
// optimization
271
datapos = datalen;
272             return -1;
273         }
274     }
275     
276     /**
277      * Read a number of bytes.
278      * @see InputStream#read(byte[])
279      * @param buffer the buffer into which the data is read.
280      * @return the total number of bytes read into the buffer, or -1 if there
281      * is no more data because the end of the stream has been reached.
282      */

283     public int read(byte[] buffer)
284     {
285         return localRead(buffer, 0, buffer.length);
286     }
287     
288     /**
289      * Read a number of bytes.
290      * @see InputStream#read(byte[], int, int)
291      * @param buffer the buffer into which the data is read.
292      * @param off the start offset in array buffer at which the data is written.
293      * @param len the maximum number of bytes to read.
294      * @return the total number of bytes read into the buffer, or -1 if there
295      * is no more data because the end of the stream has been reached.
296      */

297     public int read(byte[] buffer, int off, int len)
298     {
299         if (len <= 0 || off >= buffer.length)
300         {
301             return 0;
302         }
303         if (off < 0)
304         {
305             off = 0;
306         }
307         if (len > buffer.length)
308         {
309             len = buffer.length;
310         }
311         return localRead(buffer, off, len);
312     }
313     
314     
315     /**
316      * Read a number of bytes. Internal method that assumes off and len to be
317      * valid.
318      * @see InputStream#read(byte[], int, int)
319      * @param buffer the buffer into which the data is read.
320      * @param off the start offset in array buffer at which the data is written.
321      * @param len the maximum number of bytes to read.
322      * @return the total number of bytes read into the buffer, or -1 if there
323      * is no more data because the end of the stream has been reached.
324      */

325     public int localRead(byte[] buffer, int off, int len)
326     {
327         if (len == 0)
328         {
329             return 0; // must return 0 even if at end!
330
}
331         else if (datapos >= datalen)
332         {
333             return -1;
334         }
335         else
336         {
337             int newpos = datapos + len;
338             if (newpos > datalen)
339             {
340                 newpos = datalen;
341                 len = newpos - datapos;
342             }
343             System.arraycopy(data, datapos, buffer, off, len);
344             datapos = newpos;
345             return len;
346         }
347     }
348     
349     /**
350      * Skips over and discards n bytes of data from this input stream.
351      * The skip method may, for a variety of reasons, end up skipping over some
352      * smaller number of bytes, possibly 0. This may result from any of a number
353      * of conditions; reaching end of file before n bytes have been skipped is
354      * only one possibility. The actual number of bytes skipped is returned.
355      * If n is negative, no bytes are skipped.
356      * @param num the number of bytes to be skipped.
357      * @return the actual number of bytes skipped.
358      * @see InputStream#skip(long)
359      */

360     public long skip(long num)
361     {
362         if (num <= 0)
363         {
364             return 0;
365         }
366         else
367         {
368             long newpos = datapos + num;
369             if (newpos >= datalen)
370             {
371                 num = datalen - datapos;
372                 datapos = datalen;
373             }
374             else
375             {
376                 datapos = (int)newpos;
377             }
378             return num;
379         }
380     }
381     
382     /** Position the stream at a given index. Positioning the stream
383      * at position size() will cause the next call to read() to return -1.
384      *
385      * @param newpos Position in the underlying array. A negative value will be
386      * interpreted as 0, a value greater than size() as size().
387      * @return old position.
388      */

389     public int seek(int newpos)
390     {
391         if (newpos < 0)
392         {
393             newpos = 0;
394         }
395         else if (newpos > datalen)
396         {
397             newpos = datalen;
398         }
399         int oldpos = pos;
400         pos = newpos;
401         return oldpos;
402     }
403
404 }
405
Popular Tags