From c34fdf0b7d1e046a50934c10011753d04be8e8b7 Mon Sep 17 00:00:00 2001 From: Robert Schuster Date: Wed, 23 Feb 2005 08:26:36 +0000 Subject: [PATCH] ChannelReader: Fixed comments. 2005-02-23 Robert Schuster * gnu/java/nio/ChannelReader: Fixed comments. 2005-02-23 Robert Schuster * java/nio/channels/Channels: Added FIXMEs about stub method implementation. (newReader): Implemented. * gnu/java/nio/ChannelReader: New class. From-SVN: r95444 --- libjava/ChangeLog | 11 ++ libjava/gnu/java/nio/ChannelReader.java | 211 ++++++++++++++++++++++++++++++++ libjava/java/nio/channels/Channels.java | 4 +- 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 libjava/gnu/java/nio/ChannelReader.java diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 3b0699e..2aded18 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,14 @@ +2005-02-23 Robert Schuster + + * gnu/java/nio/ChannelReader: Fixed comments. + +2005-02-23 Robert Schuster + + * java/nio/channels/Channels: Added FIXMEs about + stub method implementation. + (newReader): Implemented. + * gnu/java/nio/ChannelReader: New class. + 2005-02-23 Michael Koch * java/text/SimpleDateFormat.java: diff --git a/libjava/gnu/java/nio/ChannelReader.java b/libjava/gnu/java/nio/ChannelReader.java new file mode 100644 index 0000000..11e66a7 --- /dev/null +++ b/libjava/gnu/java/nio/ChannelReader.java @@ -0,0 +1,211 @@ +/* ChannelReader.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.nio; + +import java.io.IOException; +import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +/** + * A Reader implementation that works using a ReadableByteChannel and a + * CharsetDecoder. + * + *

+ * This is a bridge between NIO <-> IO character decoding. + *

+ * + * @author Robert Schuster + */ +public class ChannelReader extends Reader +{ + + private static final int DEFAULT_BUFFER_CAP = 8192; + + private ReadableByteChannel channel; + + private CharsetDecoder decoder; + + private ByteBuffer byteBuffer; + + private CharBuffer charBuffer; + + public ChannelReader(ReadableByteChannel channel, CharsetDecoder decoder, + int minBufferCap) + { + this.channel = channel; + this.decoder = decoder; + + // JDK reports errors, so we do the same. + decoder.onMalformedInput(CodingErrorAction.REPORT); + decoder.onUnmappableCharacter(CodingErrorAction.REPORT); + decoder.reset(); + + int size = (minBufferCap == -1) ? DEFAULT_BUFFER_CAP : minBufferCap; + + // Allocates the buffers and prepares them for reading, because that is the + // first operation being done on them. + byteBuffer = ByteBuffer.allocate(size); + byteBuffer.flip(); + charBuffer = CharBuffer.allocate((int) (size * decoder.averageCharsPerByte())); + } + + public int read(char[] buf, int offset, int count) throws IOException + { + // I declared channel being null meaning that the reader is closed. + if (!channel.isOpen()) + throw new IOException("Reader was already closed."); + + // I declared decoder being null meaning that there is no more data to read + // and convert. + if (decoder == null) + return -1; + + // Stores the amount of character being read. It -1 so that if no conversion + // occured the caller will see this as an 'end of file'. + int sum = -1; + + // Copies any characters which may be left from the last invocation into the + // destination array. + if (charBuffer.remaining() > 0) + { + sum = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, sum); + + // Updates the control variables according to the latest copy operation. + offset += sum; + count -= sum; + } + + // Copies the character which have not been put in the destination array to + // the beginning. If data is actually copied count will be 0. If no data is + // copied count is >0 and we can now convert some more characters. + charBuffer.compact(); + + int converted = 0; + boolean last = false; + + while (count != 0) + { + // Tries to convert some bytes (Which will intentionally fail in the + // first place because we have not read any bytes yet.) + CoderResult result = decoder.decode(byteBuffer, charBuffer, last); + if (result.isMalformed() || result.isUnmappable()) + { + // JDK throws exception when bytes are malformed for sure. + // FIXME: Unsure what happens when a character is simply + // unmappable. + result.throwException(); + } + + // Marks that we should end this loop regardless whether the caller + // wants more chars or not, when this was the last conversion. + if (last) + { + decoder = null; + } + else if (result.isUnderflow()) + { + // We need more bytes to do the conversion. + + // Copies the not yet converted bytes to the beginning making it + // being able to receive more bytes. + byteBuffer.compact(); + + // Reads in another bunch of bytes for being converted. + if (channel.read(byteBuffer) == -1) + { + // If there is no more data available in the channel we mark + // that state for the final character conversion run which is + // done in the next loop iteration. + last = true; + } + + // Prepares the byteBuffer for the next character conversion run. + byteBuffer.flip(); + } + + // Prepares the charBuffer for being drained. + charBuffer.flip(); + + converted = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, converted); + + // Copies characters which have not yet being copied into the char-Array + // to the beginning making it possible to read them later (If data is + // really copied here, then the caller has received enough characters so + // far.). + charBuffer.compact(); + + // Updates the control variables according to the latest copy operation. + offset += converted; + count -= converted; + + // Updates the amount of transferred characters. + sum += converted; + + if (decoder == null) + { + break; + } + + // Now that more characters have been transfered we let the loop decide + // what to do next. + } + + // Makes the charBuffer ready for reading on the next invocation. + charBuffer.flip(); + + return sum; + } + + public void close() throws IOException + { + channel.close(); + + // Makes sure all intermediate data is released by the decoder. + if (decoder != null) + decoder.reset(); + } + +} diff --git a/libjava/java/nio/channels/Channels.java b/libjava/java/nio/channels/Channels.java index 4c86cc9..1da5d13 100644 --- a/libjava/java/nio/channels/Channels.java +++ b/libjava/java/nio/channels/Channels.java @@ -40,6 +40,7 @@ package java.nio.channels; import gnu.java.nio.ChannelInputStream; import gnu.java.nio.ChannelOutputStream; +import gnu.java.nio.ChannelReader; import gnu.java.nio.InputStreamChannel; import gnu.java.nio.OutputStreamChannel; import gnu.java.nio.channels.FileChannelImpl; @@ -115,7 +116,7 @@ public final class Channels public static Reader newReader(ReadableByteChannel ch, CharsetDecoder dec, int minBufferCap) { - throw new Error("not implemented"); + return new ChannelReader(ch, dec, minBufferCap); } /** @@ -137,6 +138,7 @@ public final class Channels public static Writer newWriter(WritableByteChannel ch, CharsetEncoder enc, int minBufferCap) { + // FIXME: implement java.nio.channels.Channel.newWriter(WritableByteChannel, CharsetEncoder, int) throw new Error("not implemented"); } -- 2.7.4