KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > readers > CharReader


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.readers;
59
60 import java.io.Reader JavaDoc;
61
62 import org.enhydra.apache.xerces.framework.XMLErrorReporter;
63 import org.enhydra.apache.xerces.utils.CharDataChunk;
64 import org.enhydra.apache.xerces.utils.StringPool;
65
66 /**
67  * General purpose character stream reader.
68  *
69  * This class is used when the input source for the document entity is
70  * specified using a character stream, when the input source is specified
71  * using a byte stream with an explicit encoding, or when a recognizer
72  * scans the encoding decl from the byte stream and chooses to use this
73  * reader class for that encoding. For the latter two cases, the byte
74  * stream is wrapped in the appropriate InputStreamReader using the
75  * desired encoding.
76  *
77  * @version
78  */

79 final class CharReader extends AbstractCharReader {
80     //
81
//
82
//
83
CharReader(XMLEntityHandler entityHandler, XMLErrorReporter errorReporter, boolean sendCharDataAsCharArray, Reader JavaDoc reader, StringPool stringPool) throws Exception JavaDoc {
84         super(entityHandler, errorReporter, sendCharDataAsCharArray, stringPool);
85         fCharacterStream = reader;
86         fillCurrentChunk();
87     }
88     //
89
//
90
//
91
private Reader JavaDoc fCharacterStream = null;
92     //
93
// When we fill a chunk there may be data that was read from the
94
// input stream that has not been "processed". We need to save
95
// that data, and any in-progress state, between the calls to
96
// fillCurrentChunk() in these instance variables.
97
//
98
private boolean fCheckOverflow = false;
99     private char[] fOverflow = null;
100     private int fOverflowOffset = 0;
101     private int fOverflowEnd = 0;
102     private int fOutputOffset = 0;
103     private boolean fSkipLinefeed = false;
104     //
105
//
106
//
107
protected int fillCurrentChunk() throws Exception JavaDoc {
108         //
109
// See if we can find a way to reuse the buffer that may have been returned
110
// with a recyled data chunk.
111
//
112
char[] recycledData = fCurrentChunk.toCharArray();
113         //
114
// If we have overflow from the last call, normalize from where
115
// we left off, copying into the front of the output buffer.
116
//
117
fOutputOffset = 0;
118         if (fCheckOverflow) {
119             //
120
// The fOverflowEnd should always be equal to CHUNK_SIZE, unless we hit
121
// EOF during the previous call. Copy the remaining data to the front
122
// of the buffer and return it as the final chunk.
123
//
124
fMostRecentData = recycledData;
125             if (fOverflowEnd < CharDataChunk.CHUNK_SIZE) {
126                 recycledData = null;
127                 if (fOverflowEnd > 0) {
128                     if (fMostRecentData == null || fMostRecentData.length < 1 + fOverflowEnd - fOverflowOffset)
129                         fMostRecentData = new char[1 + fOverflowEnd - fOverflowOffset];
130                     copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
131                 } else {
132                     if (fMostRecentData == null)
133                         fMostRecentData = new char[1];
134                 }
135                 fMostRecentData[fOutputOffset] = 0;
136                 //
137
// Update our instance variables
138
//
139
fOverflow = null;
140                 fLength += fOutputOffset;
141                 fCurrentIndex = 0;
142                 fCurrentChunk.setCharArray(fMostRecentData);
143                 return (fMostRecentChar = fMostRecentData[0]);
144             }
145             if (fMostRecentData == null || fMostRecentData.length < CharDataChunk.CHUNK_SIZE)
146                 fMostRecentData = new char[CharDataChunk.CHUNK_SIZE];
147             else
148                 recycledData = null;
149             copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
150             fCheckOverflow = false;
151         } else {
152             if (fOverflow == null) {
153                 fOverflow = recycledData;
154                 if (fOverflow == null || fOverflow.length < CharDataChunk.CHUNK_SIZE)
155                     fOverflow = new char[CharDataChunk.CHUNK_SIZE];
156                 else
157                     recycledData = null;
158             }
159             fMostRecentData = null;
160         }
161         while (true) {
162             fOverflowOffset = 0;
163             fOverflowEnd = 0;
164             int capacity = CharDataChunk.CHUNK_SIZE;
165             int result = 0;
166             do {
167                 try {
168                     result = fCharacterStream.read(fOverflow, fOverflowEnd, capacity);
169                 } catch (java.io.IOException JavaDoc ex) {
170                     result = -1;
171                 }
172                 if (result == -1) {
173                     //
174
// We have reached the end of the stream.
175
//
176
fCharacterStream.close();
177                     fCharacterStream = null;
178                     if (fMostRecentData == null) {
179                         //
180
// There is no previous output data, so we know that all of the
181
// new input data will fit.
182
//
183
fMostRecentData = recycledData;
184                         if (fMostRecentData == null || fMostRecentData.length < 1 + fOverflowEnd)
185                             fMostRecentData = new char[1 + fOverflowEnd];
186                         else
187                             recycledData = null;
188                         copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
189                         fOverflow = null;
190                         fMostRecentData[fOutputOffset] = 0;
191                     } else {
192                         //
193
// Copy the input data to the end of the output buffer.
194
//
195
boolean alldone = copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
196                         if (alldone) {
197                             if (fOutputOffset == CharDataChunk.CHUNK_SIZE) {
198                                 //
199
// Special case - everything fit into the overflow buffer,
200
// except that there is no room for the nul char we use to
201
// indicate EOF. Set the overflow buffer length to zero.
202
// On the next call to this method, we will detect this
203
// case and which we will handle above .
204
//
205
fCheckOverflow = true;
206                                 fOverflowOffset = 0;
207                                 fOverflowEnd = 0;
208                             } else {
209                                 //
210
// It all fit into the output buffer.
211
//
212
fOverflow = null;
213                                 fMostRecentData[fOutputOffset] = 0;
214                             }
215                         } else {
216                             //
217
// There is still input data left over, save the remaining data as
218
// the overflow buffer for the next call.
219
//
220
fCheckOverflow = true;
221                         }
222                     }
223                     break;
224                 }
225                 if (result > 0) {
226                     fOverflowEnd += result;
227                     capacity -= result;
228                 }
229             } while (capacity > 0);
230             //
231
//
232
//
233
if (result == -1)
234                 break;
235             if (fMostRecentData != null) {
236                 boolean alldone = copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
237                 if (fOutputOffset == CharDataChunk.CHUNK_SIZE) {
238                     //
239
// We filled the output buffer.
240
//
241
if (!alldone) {
242                         //
243
// The input buffer will become the next overflow buffer.
244
//
245
fCheckOverflow = true;
246                     }
247                     break;
248                 }
249             } else {
250                 //
251
// Now normalize the end-of-line characters and see if we need to read more
252
// chars to fill up the buffer.
253
//
254
fMostRecentData = recycledData;
255                 if (fMostRecentData == null || fMostRecentData.length < CharDataChunk.CHUNK_SIZE)
256                     fMostRecentData = new char[CharDataChunk.CHUNK_SIZE];
257                 else
258                     recycledData = null;
259                 copyNormalize(fOverflow, fOverflowOffset, fMostRecentData, fOutputOffset);
260                 if (fOutputOffset == CharDataChunk.CHUNK_SIZE) {
261                     //
262
// The output buffer is full. We can return now.
263
//
264
break;
265                 }
266             }
267             //
268
// We will need to get another intput buffer to be able to fill the
269
// overflow buffer completely.
270
//
271
}
272         //
273
// Update our instance variables
274
//
275
fLength += fOutputOffset;
276         fCurrentIndex = 0;
277         fCurrentChunk.setCharArray(fMostRecentData);
278         return (fMostRecentChar = fMostRecentData[0]);
279     }
280     //
281
// Copy and normalize chars from the overflow buffer into chars in our data buffer.
282
//
283
private boolean copyNormalize(char[] in, int inOffset, char[] out, int outOffset) throws Exception JavaDoc {
284         //
285
// Handle all edge cases before dropping into the inner loop.
286
//
287
int inEnd = fOverflowEnd;
288         int outEnd = out.length;
289         if (inOffset == inEnd)
290             return true;
291         char b = in[inOffset];
292         if (fSkipLinefeed) {
293             fSkipLinefeed = false;
294             if (b == 0x0A) {
295                 if (++inOffset == inEnd)
296                     return exitNormalize(inOffset, outOffset, true);
297                 b = in[inOffset];
298             }
299         }
300         while (outOffset < outEnd) {
301             //
302
// Find the longest run that we can guarantee will not exceed the
303
// bounds of the outer loop.
304
//
305
int inCount = inEnd - inOffset;
306             int outCount = outEnd - outOffset;
307             if (inCount > outCount)
308                 inCount = outCount;
309             inOffset++;
310             while (true) {
311                 while (b == 0x0D) {
312                     out[outOffset++] = 0x0A;
313                     if (inOffset == inEnd) {
314                         fSkipLinefeed = true;
315                         return exitNormalize(inOffset, outOffset, true);
316                     }
317                     b = in[inOffset];
318                     if (b == 0x0A) {
319                         if (++inOffset == inEnd)
320                             return exitNormalize(inOffset, outOffset, true);
321                         b = in[inOffset];
322                     }
323                     if (outOffset == outEnd)
324                         return exitNormalize(inOffset, outOffset, false);
325                     inCount = inEnd - inOffset;
326                     outCount = outEnd - outOffset;
327                     if (inCount > outCount)
328                         inCount = outCount;
329                     inOffset++;
330                 }
331                 while (true) {
332                     out[outOffset++] = b;
333                     if (--inCount == 0)
334                         break;
335                     b = in[inOffset++];
336                     if (b == 0x0D)
337                         break;
338                 }
339                 if (inCount == 0)
340                     break;
341             }
342             if (inOffset == inEnd)
343                 break;
344         }
345         return exitNormalize(inOffset, outOffset, inOffset == inEnd);
346     }
347     //
348
//
349
//
350
private boolean exitNormalize(int inOffset, int outOffset, boolean result) {
351         fOverflowOffset = inOffset;
352         fOutputOffset = outOffset;
353         return result;
354     }
355 }
356
Popular Tags