KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > XmlInputStream


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.xml;
10
11 import j2me.lang.IllegalStateException;
12 import j2me.io.CharConversionException;
13 import javolution.lang.Reusable;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.Reader;
18
19 /**
20  * <p> This class represents an object input stream using {@link ObjectReader}
21  * for object deserialization.</p>
22  *
23  * <p> Instances of this class embed their own data buffer, wrapping using
24  * a <code>java.io.BufferedInputStream</code> is therefore unnescessary.</p>
25  *
26  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
27  * @version 2.2, January 8, 2005
28  * @see XmlOutputStream
29  */

30 public class XmlInputStream/*<T>*/ extends InputStream implements Reusable {
31
32     /**
33      * Holds the object reader.
34      */

35     private final ObjectReader/*<T>*/ _objectReader = new ObjectReader/*<T>*/();
36
37     /**
38      * Holds the xml reader used for parsing.
39      */

40     private final XmlReader _xmlReader = new XmlReader();
41
42     /**
43      * Default constructor.
44      */

45     public XmlInputStream() {
46     }
47     
48     /**
49      * Sets the underlying input source for this stream.
50      *
51      * @param in the input source.
52      * @return <code>this</code>
53      * @throws IllegalStateException if this stream is being reused and
54      * it has not been {@link #close closed} or {@link #reset reset}.
55      */

56     public XmlInputStream setInputStream(InputStream in) {
57         if (_xmlReader._inputStream != null)
58             throw new IllegalStateException("Stream not closed or reset");
59         _xmlReader._inputStream = in;
60         return this;
61     }
62
63     /**
64      * Reads an object from the underlying stream using an {@link ObjectReader}.
65      *
66      * @return the object read from its xml representation.
67      * @throws IOException if an I/O error occurs.
68      */

69     public Object/*T*/ readObject() throws IOException {
70         try {
71             return _objectReader.read(_xmlReader);
72         } finally {
73            _xmlReader.resume();
74         }
75     }
76
77     /**
78      * Closes and {@link #reset resets} this stream for reuse.
79      *
80      * @throws IOException if an I/O error occurs.
81      */

82     public void close() throws IOException {
83         if (_xmlReader._inputStream != null) {
84             _xmlReader._inputStream.close();
85             reset();
86         }
87     }
88     
89     /**
90      * Reads the next byte of data from the input stream.
91      *
92      * @return the next byte of data, or -1 if the end of the stream is reached.
93      * @throws IOException if an I/O error occurs.
94      */

95     public int read() throws IOException {
96         if (_xmlReader._start < _xmlReader._end) {
97             return _xmlReader._bytes[_xmlReader._start++];
98         } else { // Use the reader buffer.
99
return _xmlReader.fillBuffer() ?
100                  _xmlReader._bytes[_xmlReader._start++] : -1;
101         }
102     }
103     
104     /**
105      * Reads up to len bytes of data from the input stream into an array of
106      * bytes.
107      *
108      * @param b the buffer into which the data is read.
109      * @param off the start offset in array b at which the data is written.
110      * @param len the maximum number of bytes to read.
111      * @return the total number of bytes read into the buffer, or -1 if there
112      * is no more data because the end of the stream has been reached.
113      * @throws IOException if an I/O error occurs.
114      */

115     public int read(byte b[], int off, int len) throws IOException {
116         int rem = _xmlReader._end - _xmlReader._start;
117         if (rem == 0) { // Buffer empty, go straight to the source.
118
return _xmlReader._inputStream.read(b, off, len);
119         }
120         // Returns bytes from buffer.
121
int count = (len < rem) ? len : rem;
122         System.arraycopy(_xmlReader._bytes, _xmlReader._start, b, off, count);
123         _xmlReader._start += count;
124         return count;
125     }
126     
127     // Implements Reusable interface.
128
public void reset() {
129         _objectReader.reset();
130         _xmlReader.reset();
131     }
132     
133     /**
134      * This inner class represents a custom reader for reading the xml
135      * data when parsing. It stops reading when the
136      * {@link XmlOutputStream#END_XML} byte is encountered, it then returns
137      * the code <code>-1</code> (end of stream) until {@link #resume resumed}.
138      */

139     private static final class XmlReader extends Reader implements Reusable {
140         private InputStream _inputStream;
141         private int _code;
142         private int _moreBytes;
143         private int _start;
144         private int _end;
145         private final byte[] _bytes = new byte[2048];
146         private boolean _isHalted;
147         
148
149         /**
150          * Resumes reading after an {@link XmlOutputStream#END_UTF8} byte
151          * is encountered.
152          */

153         public void resume() {
154             _isHalted = false;
155         }
156         
157         /**
158          * Fills buffer.
159          *
160          * @return <code>true</code> if at least one more byte has been read;
161          * <code>false</code> otherwise.
162          * @throws IOException if an I/O error occurs.
163          */

164         public boolean fillBuffer() throws IOException {
165             if (_inputStream == null) throw new IOException("Stream closed");
166             _start = 0;
167             _end = _inputStream.read(_bytes, 0, _bytes.length);
168             return _end > 0;
169         }
170         
171         // Implements abstract method.
172
public int read(char[] cbuf, int off, int len) throws IOException {
173             if (_isHalted) {
174                 return -1;
175             } else if (_start >= _end) {
176                 if (!fillBuffer()) {
177                     return - 1;
178                 }
179             }
180             final int off_plus_len = off + len;
181             for (int i = off; i < off_plus_len;) {
182                 // assert(_start < _end)
183
byte b = _bytes[_start];
184                 if ((b >= 0) && (++_start < _end)) {
185                     cbuf[i++] = (char) b; // Most common case.
186
} else if (b < 0) {
187                     if (b == XmlOutputStream.END_XML) {
188                         ++_start;
189                         _isHalted = true;
190                         return i - off;
191                     } else if (i < off_plus_len - 1) { // Up to two 'char' can be read.
192
int code = read2();
193                         if (code < 0x10000) {
194                             cbuf[i++] = (char) code;
195                         } else if (code <= 0x10ffff) { // Surrogates.
196
cbuf[i++] = (char) (((code - 0x10000) >> 10) + 0xd800);
197                             cbuf[i++] = (char) (((code - 0x10000) & 0x3ff) + 0xdc00);
198                         } else {
199                             throw new CharConversionException(
200                                     "Cannot convert U+"
201                                             + Integer.toHexString(code)
202                                             + " to char (code greater than U+10FFFF)");
203                         }
204                         if (_start < _end) {
205                             continue;
206                         }
207                     }
208                     return i - off;
209                 } else { // End of buffer (_start >= _end).
210
cbuf[i++] = (char) b;
211                     return i - off;
212                 }
213             }
214             return len;
215         }
216
217         // Implements abstract method.
218
public void close() throws IOException {
219             // Do nothing (we don't want the object reader to close
220
// the input stream).
221
}
222
223         // Reads one full character, blocks if necessary.
224
private int read2() throws IOException {
225             if (_start < _end) {
226                 byte b = _bytes[_start++];
227
228                 // Decodes UTF-8.
229
if ((b >= 0) && (_moreBytes == 0)) {
230                     // 0xxxxxxx
231
return b;
232                 } else if (((b & 0xc0) == 0x80) && (_moreBytes != 0)) {
233                     // 10xxxxxx (continuation byte)
234
_code = (_code << 6) | (b & 0x3f); // Adds 6 bits to code.
235
if (--_moreBytes == 0) {
236                         return _code;
237                     } else {
238                         return read2();
239                     }
240                 } else if (((b & 0xe0) == 0xc0) && (_moreBytes == 0)) {
241                     // 110xxxxx
242
_code = b & 0x1f;
243                     _moreBytes = 1;
244                     return read2();
245                 } else if (((b & 0xf0) == 0xe0) && (_moreBytes == 0)) {
246                     // 1110xxxx
247
_code = b & 0x0f;
248                     _moreBytes = 2;
249                     return read2();
250                 } else if (((b & 0xf8) == 0xf0) && (_moreBytes == 0)) {
251                     // 11110xxx
252
_code = b & 0x07;
253                     _moreBytes = 3;
254                     return read2();
255                 } else {
256                     throw new CharConversionException("Invalid UTF-8 Encoding");
257                 }
258             } else { // No more bytes in buffer.
259
if (fillBuffer()) {
260                     return read2(); // Continues.
261
} else { // Done.
262
if (_moreBytes == 0) {
263                         return -1;
264                     } else { // Incomplete sequence.
265
throw new CharConversionException(
266                                 "Unexpected end of stream");
267                     }
268                 }
269             }
270         }
271
272         // Implements Reusable interface.
273
public void reset() {
274             _code = 0;
275             _end = 0;
276             _inputStream = null;
277             _moreBytes = 0;
278             _start = 0;
279         }
280     }
281 }
Popular Tags