001: /*
002: Derby - Class org.apache.derby.client.net.EncodedInputStream
003:
004: Licensed to the Apache Software Foundation (ASF) under one
005: or more contributor license agreements. See the NOTICE file
006: distributed with this work for additional information
007: regarding copyright ownership. The ASF licenses this file
008: to you under the Apache License, Version 2.0 (the
009: "License"); you may not use this file except in compliance
010: with the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing,
015: software distributed under the License is distributed on an
016: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: KIND, either express or implied. See the License for the
018: specific language governing permissions and limitations
019: under the License.
020: */
021: package org.apache.derby.client.net;
022:
023: import java.io.InputStream;
024: import java.io.Reader;
025: import java.io.OutputStreamWriter;
026: import java.io.ByteArrayOutputStream;
027: import java.io.ByteArrayInputStream;
028:
029: import java.io.IOException;
030: import java.io.UnsupportedEncodingException;
031:
032: import org.apache.derby.iapi.services.sanity.SanityManager;
033:
034: /**
035: * Create an encoded stream from a <code>Reader</code>.
036: *
037: * This is an internal class, used to pass readers of characters as streams of
038: * bytes. The characters will be represented according to the specified
039: * encoding. It is up to the caller to ensure the specified encoding is
040: * available, and in general only encodings available as default from Java 1.3
041: * and up should be used.
042: *
043: * Currently, the encodings 'UTF8' and 'UTF-16BE' are used.
044: * Streams are obtained by calling the static methods of this class,
045: * for instance <code>createUTF8Stream</code>.
046: */
047: public final class EncodedInputStream extends InputStream {
048:
049: /**
050: * Create a UTF-8 encoded stream from the given <code>Reader</code>.
051: *
052: * @param reader the <code>Reader</code> to read characters from.
053: * @return a byte-stream with UTF-8 encoded characters
054: */
055: public static EncodedInputStream createUTF8Stream(Reader reader) {
056: return new EncodedInputStream(reader, "UTF8",
057: BUFFERED_CHAR_LEN, BUFFERED_CHAR_LEN * 3);
058: }
059:
060: /**
061: * Create a UTF-16BE encoded stream from the given <code>Reader</code>.
062: *
063: * @param reader the <code>Reader</code> to read characters from.
064: * @return a byte-stream with UTF-16BE encoded characters
065: */
066: static EncodedInputStream createUTF16BEStream(Reader reader) {
067: return new EncodedInputStream(reader, "UTF-16BE",
068: BUFFERED_CHAR_LEN, BUFFERED_CHAR_LEN * 2);
069: }
070:
071: private static final int BUFFERED_CHAR_LEN = 1024;
072: private static final ByteArrayInputStream suspendMarker = new ByteArrayInputStream(
073: new byte[0]);
074:
075: private Reader reader_;
076: private final char[] decodedBuffer_;
077:
078: private OutputStreamWriter encodedStreamWriter_;
079: private PublicBufferOutputStream encodedOutputStream_;
080:
081: private ByteArrayInputStream encodedInputStream_;
082:
083: /**
084: * Create an encoded stream for the specified <code>Reader</code>.
085: *
086: * @param reader the <code>Reader</code> to read characters from
087: * @param encoding the encoding to use in the encoded stream
088: * @param charBufferSize the size of the char buffer. This is the number
089: * of characters read at once from the <code>Reader</code>.
090: * @param initialByteBufferSize the initial size of the byte buffer.
091: * holding the encoded bytes
092: */
093: private EncodedInputStream(Reader reader, String encoding,
094: int charBufferSize, int initialByteBufferSize) {
095:
096: reader_ = reader;
097: decodedBuffer_ = new char[charBufferSize];
098:
099: encodedOutputStream_ = new PublicBufferOutputStream(
100: initialByteBufferSize);
101:
102: try {
103: encodedStreamWriter_ = new OutputStreamWriter(
104: encodedOutputStream_, encoding);
105:
106: } catch (UnsupportedEncodingException e) {
107: // Should never happen. It is up to the caller to ensure the
108: // specified encoding is available.
109: if (SanityManager.DEBUG) {
110: SanityManager.THROWASSERT(
111: "Unavailable encoding specified: " + encoding,
112: e);
113: }
114: }
115:
116: encodedInputStream_ = suspendMarker;
117:
118: }
119:
120: private ByteArrayInputStream reEncode(Reader reader)
121: throws IOException {
122:
123: int count;
124: do {
125: count = reader.read(decodedBuffer_, 0,
126: decodedBuffer_.length);
127:
128: } while (count == 0);
129:
130: if (count < 0)
131: return null;
132:
133: encodedOutputStream_.reset();
134: encodedStreamWriter_.write(decodedBuffer_, 0, count);
135: encodedStreamWriter_.flush();
136:
137: int encodedLength = encodedOutputStream_.size();
138:
139: return new ByteArrayInputStream(encodedOutputStream_
140: .getBuffer(), 0, encodedLength);
141: }
142:
143: public int available() throws IOException {
144:
145: if (encodedInputStream_ == suspendMarker)
146: encodedInputStream_ = reEncode(reader_);
147:
148: if (encodedInputStream_ == null) {
149: return 0;
150: }
151:
152: return encodedInputStream_.available();
153:
154: }
155:
156: public void close() throws IOException {
157:
158: if (encodedInputStream_ != null) {
159: encodedInputStream_.close();
160: encodedInputStream_ = null;
161: }
162:
163: if (reader_ != null) {
164: reader_.close();
165: reader_ = null;
166: }
167:
168: if (encodedStreamWriter_ != null) {
169: encodedStreamWriter_.close();
170: encodedStreamWriter_ = null;
171: }
172:
173: }
174:
175: public int read() throws IOException {
176:
177: if (encodedInputStream_ == suspendMarker)
178: encodedInputStream_ = reEncode(reader_);
179:
180: if (encodedInputStream_ == null) {
181: return -1;
182: }
183:
184: int c = encodedInputStream_.read();
185:
186: if (c > -1) {
187: return c;
188:
189: } else {
190: encodedInputStream_ = reEncode(reader_);
191:
192: if (encodedInputStream_ == null) {
193: return -1;
194: }
195:
196: return encodedInputStream_.read();
197:
198: }
199:
200: }
201:
202: protected void finalize() throws IOException {
203: close();
204: }
205:
206: static class PublicBufferOutputStream extends ByteArrayOutputStream {
207:
208: PublicBufferOutputStream(int size) {
209: super (size);
210: }
211:
212: public byte[] getBuffer() {
213: return buf;
214: }
215:
216: }
217: }
|