KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > utils > ChunkyByteArray


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.enhydra.apache.xerces.utils;
59
60 import java.io.IOException JavaDoc;
61 import java.io.InputStream JavaDoc;
62
63 /**
64  * This class is used for accessing the data provided by an InputStream.
65  *
66  * There are two ways in which this class is used. The first occurs
67  * when we are prescanning the start of the stream to determine the
68  * encoding being used. Since we do not require that the stream be
69  * positionable, we wrap it with an instance of this class. The first
70  * "chunk" of the file is read and the data may be accessed directly
71  * using the byteAt(offset) method. After we have determined the
72  * encoding of the byte stream, the instance of this class is passed
73  * on to the EntityReader that will process the data for the scanner.
74  *
75  * At this point, the reader may continue to access this instance using
76  * the byteAt method, which will continue to read the contents into
77  * chunks as required until end of input. An example of this is the
78  * UCSReader.
79  *
80  * Alternatively, the reader may access this instance as an InputStream
81  * which will first return any data that has been reading into the
82  * chunks, and will then return the remaining data from the original
83  * InputStream directly.
84  *
85  * @version
86  */

87 public final class ChunkyByteArray extends InputStream JavaDoc {
88
89     /**
90      * Constructor
91      *
92      * Reads the first chunk.
93      *
94      * @param is The input stream containing the data of the entity.
95      */

96     public ChunkyByteArray(InputStream JavaDoc is) throws IOException JavaDoc {
97         fInputStream = is;
98         fill();
99     }
100
101     /**
102      * Read a byte.
103      *
104      * @return The next byte of the input data or -1 if there is no more data.
105      */

106     public int read() throws IOException JavaDoc {
107         if (fData == null)
108             return fInputStream == null ? -1 : fInputStream.read();
109         int b = (int)(fData[0][fOffset]);
110         if (++fOffset == fLength) {
111             fData = null;
112             if (fLength < CHUNK_SIZE)
113                 fInputStream = null;
114         }
115         return b;
116     }
117
118     /**
119      * Read bytes.
120      *
121      * @param buffer The destination for the bytes returned. If null, then
122      * the data will discarded instead of returned.
123      * @param offset The offset within the buffer where the first returned
124      * byte should be placed.
125      * @param length The maximum number of bytes to place in the buffer or discard.
126      * @return The number of bytes actually placed in the buffer or discarded.
127      */

128     public int read(byte buffer[], int offset, int length) throws IOException JavaDoc {
129         int bytesLeft = fLength - fOffset;
130         if (bytesLeft == 0)
131             return fInputStream == null ? -1 : fInputStream.read(buffer, offset, length);
132         if (length <= 0)
133             return 0;
134         byte[] chunk = fData[0];
135         if (length >= bytesLeft) {
136             length = bytesLeft;
137             if (fLength < CHUNK_SIZE)
138                 fInputStream = null;
139         }
140         if (buffer == null) {
141             fOffset += length;
142             return length;
143         }
144         int stop = offset + length;
145         do {
146             buffer[offset++] = chunk[fOffset++];
147         } while (offset < stop);
148         return length;
149     }
150
151     /**
152      * Reset position within the data stream back to
153      * the very beginning.
154      */

155     public void rewind() {
156         fOffset = 0;
157     }
158
159     /**
160      * Return a byte of input data at the given offset.
161      *
162      * @param offset The offset in the data stream.
163      * @return The byte at the specified position within the data stream.
164      */

165     public byte byteAt(int offset) throws IOException JavaDoc {
166         int chunk = offset >> CHUNK_SHIFT;
167         int index = offset & CHUNK_MASK;
168         try {
169             return fData[chunk][index];
170         } catch (NullPointerException JavaDoc ex) {
171             // ignore -- let fill create new chunk
172
} catch (ArrayIndexOutOfBoundsException JavaDoc e) {
173             // current chunk array is not big enough; resize
174
byte newdata[][] = new byte[fData.length * 2][];
175             System.arraycopy(fData, 0, newdata, 0, fData.length);
176             fData = newdata;
177         }
178         if (index == 0) {
179             fill();
180             return fData[chunk][index];
181         }
182         return 0;
183     }
184
185     /**
186      * Test to see if an offset is at the end of the input data.
187      *
188      * @param offset A position in the data stream.
189      * @return <code>true</code> if the position is at the end of the data stream;
190      * <code>false</code> otherwise.
191      */

192     public boolean atEOF(int offset) {
193         return(offset > fLength);
194     }
195
196
197
198     /**
199      * Closes this input Stream
200      *
201      * @exception IOException
202      */

203     public void close() throws IOException JavaDoc {
204         if ( fInputStream != null ) {
205              fInputStream.close();
206              fInputStream = null; // Null it
207
}
208     }
209
210
211     //
212
// Fill in the next chunk with additional data.
213
//
214
private void fill() throws IOException JavaDoc {
215         int bufnum = fLength >> CHUNK_SHIFT;
216         byte[] data = new byte[CHUNK_SIZE];
217         fData[bufnum] = data;
218         int offset = 0;
219         int capacity = CHUNK_SIZE;
220         int result = 0;
221         do {
222             result = fInputStream.read(data, offset, capacity);
223             if (result == -1) {
224                 data[offset] = (byte)0xff;
225                 fInputStream.close();
226                 fInputStream = null;
227                 break;
228             }
229             if (result > 0) {
230                 fLength += result;
231                 offset += result;
232                 capacity -= result;
233             }
234         } while (capacity > 0);
235     }
236     //
237
// Chunk size constants
238
//
239
private static final int CHUNK_SHIFT = 14; // 2^14 = 16k
240
private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
241     private static final int CHUNK_MASK = CHUNK_SIZE - 1;
242     private static final int INITIAL_CHUNK_COUNT = (1 << (20 - CHUNK_SHIFT)); // 2^20 = 1m
243
//
244
// Instance variables
245
//
246
private InputStream JavaDoc fInputStream = null;
247     private byte[][] fData = new byte[INITIAL_CHUNK_COUNT][];
248     private int fLength = 0;
249     private int fOffset = 0; // for read methods
250
}
251
Popular Tags