From 93f93f9f2865f06a0929d5311101c5bc4b6565bc Mon Sep 17 00:00:00 2001 From: Michael Koch Date: Wed, 13 Nov 2002 12:21:26 +0000 Subject: Buffer.java: Implemented. 2002-11-13 Michael Koch * java/nio/Buffer.java: Implemented. * java/nio/CharBuffer.java: New file. * java/nio/InvalidMarkException.java: New file. * java/nio/channels/DatagramChannel.java: Implemented. * java/nio/channels/ServerSocketChannel.java: Implemented. * java/nio/channels/SocketChannel.java: Implemented. * java/nio/channels/spi/AbstractChannel.java: Removed. * java/nio/channels/spi/AbstractSelectableChannel.java: Implemented. * java/nio/charset/Charset.java: Merge from Classpath. * java/nio/charset/CharsetDecoder.java: New file. * java/nio/charset/CharsetEncoder.java: New file. * java/nio/charset/CoderResult.java: New file. * Makefile.am (ordinary_java_source_files): Added new files. * Makefile.in: Regenerated. From-SVN: r59075 --- libjava/ChangeLog | 24 +- libjava/Makefile.am | 15 +- libjava/Makefile.in | 32 +- libjava/java/nio/Buffer.java | 151 +++++++++ libjava/java/nio/CharBuffer.java | 291 +++++++++++++++++ libjava/java/nio/InvalidMarkException.java | 52 +++ libjava/java/nio/channels/DatagramChannel.java | 105 +++++- libjava/java/nio/channels/ServerSocketChannel.java | 37 +++ libjava/java/nio/channels/SocketChannel.java | 121 ++++++- libjava/java/nio/channels/spi/AbstractChannel.java | 57 ---- .../channels/spi/AbstractSelectableChannel.java | 163 +++++++++- libjava/java/nio/charset/Charset.java | 257 ++++++++++++--- libjava/java/nio/charset/CharsetDecoder.java | 312 ++++++++++++++++++ libjava/java/nio/charset/CharsetEncoder.java | 360 +++++++++++++++++++++ libjava/java/nio/charset/CoderResult.java | 193 +++++++++++ 15 files changed, 2047 insertions(+), 123 deletions(-) create mode 100644 libjava/java/nio/CharBuffer.java create mode 100644 libjava/java/nio/InvalidMarkException.java delete mode 100644 libjava/java/nio/channels/spi/AbstractChannel.java create mode 100644 libjava/java/nio/charset/CharsetDecoder.java create mode 100644 libjava/java/nio/charset/CharsetEncoder.java create mode 100644 libjava/java/nio/charset/CoderResult.java diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 0732a56..54c9e04 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,22 @@ +2002-11-12 Michael Koch + + * java/nio/Buffer.java: Implemented. + * java/nio/CharBuffer.java: New file. + * java/nio/InvalidMarkException.java: New file. + * java/nio/channels/DatagramChannel.java: Implemented. + * java/nio/channels/ServerSocketChannel.java: Implemented. + * java/nio/channels/SocketChannel.java: Implemented. + * java/nio/channels/spi/AbstractChannel.java: Removed. + * java/nio/channels/spi/AbstractSelectableChannel.java: + Implemented. + * java/nio/charset/Charset.java: + Merge from Classpath. + * java/nio/charset/CharsetDecoder.java: New file. + * java/nio/charset/CharsetEncoder.java: New file. + * java/nio/charset/CoderResult.java: New file. + * Makefile.am (ordinary_java_source_files): Added new files. + * Makefile.in: Regenerated. + 2002-11-11 Jesse Rosenstock * gnu/java/nio/charset/ISO_8859_1.java, @@ -9,10 +28,7 @@ gnu/java/nio/charset/UTF_16Encoder.java, gnu/java/nio/charset/UTF_16LE.java, gnu/java/nio/charset/UTF_8.java: New files. - * Makefile.am (): - Added new files. - * Makefile.in: Regenerated. - + 2002-11-11 Michael Koch * java/nio/charset/CharacterCodingException.java: diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 17ac03a..d07aa82 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -1871,6 +1871,15 @@ gnu/java/locale/LocaleInformation_zh_HK.java \ gnu/java/locale/LocaleInformation_zh_SG.java \ gnu/java/locale/LocaleInformation_zh_TW.java \ gnu/java/math/MPN.java \ +gnu/java/nio/charset/ISO_8859_1.java \ +gnu/java/nio/charset/Provider.java \ +gnu/java/nio/charset/US_ASCII.java \ +gnu/java/nio/charset/UTF_16.java \ +gnu/java/nio/charset/UTF_16BE.java \ +gnu/java/nio/charset/UTF_16Decoder.java \ +gnu/java/nio/charset/UTF_16Encoder.java \ +gnu/java/nio/charset/UTF_16LE.java \ +gnu/java/nio/charset/UTF_8.java \ gnu/java/security/der/DEREncodingException.java \ gnu/java/security/provider/DERReader.java \ gnu/java/security/provider/DERWriter.java \ @@ -1963,6 +1972,8 @@ java/nio/BufferOverflowException.java \ java/nio/BufferUnderflowException.java \ java/nio/ByteBuffer.java \ java/nio/ByteOrder.java \ +java/nio/CharBuffer.java \ +java/nio/InvalidMarkException.java \ java/nio/MappedByteBuffer.java \ java/nio/channels/AlreadyConnectedException.java \ java/nio/channels/ByteChannel.java \ @@ -1982,14 +1993,16 @@ java/nio/channels/ServerSocketChannel.java \ java/nio/channels/SocketChannel.java \ java/nio/channels/WritableByteChannel.java \ java/nio/channels/spi/AbstractSelectableChannel.java \ -java/nio/channels/spi/AbstractChannel.java \ java/nio/channels/spi/AbstractInterruptibleChannel.java \ java/nio/channels/spi/AbstractSelectionKey.java \ java/nio/channels/spi/AbstractSelector.java \ java/nio/channels/spi/SelectorProvider.java \ java/nio/charset/Charset.java \ java/nio/charset/CharacterCodingException.java \ +java/nio/charset/CharsetDecoder.java \ +java/nio/charset/CharsetEncoder.java \ java/nio/charset/CoderMalfunctionError.java \ +java/nio/charset/CoderResult.java \ java/nio/charset/CodingErrorAction.java \ java/nio/charset/IllegalCharsetNameException.java \ java/nio/charset/MalformedInputException.java \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index c440076..4ece78c 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -1621,6 +1621,15 @@ gnu/java/locale/LocaleInformation_zh_HK.java \ gnu/java/locale/LocaleInformation_zh_SG.java \ gnu/java/locale/LocaleInformation_zh_TW.java \ gnu/java/math/MPN.java \ +gnu/java/nio/charset/ISO_8859_1.java \ +gnu/java/nio/charset/Provider.java \ +gnu/java/nio/charset/US_ASCII.java \ +gnu/java/nio/charset/UTF_16.java \ +gnu/java/nio/charset/UTF_16BE.java \ +gnu/java/nio/charset/UTF_16Decoder.java \ +gnu/java/nio/charset/UTF_16Encoder.java \ +gnu/java/nio/charset/UTF_16LE.java \ +gnu/java/nio/charset/UTF_8.java \ gnu/java/security/der/DEREncodingException.java \ gnu/java/security/provider/DERReader.java \ gnu/java/security/provider/DERWriter.java \ @@ -1713,6 +1722,8 @@ java/nio/BufferOverflowException.java \ java/nio/BufferUnderflowException.java \ java/nio/ByteBuffer.java \ java/nio/ByteOrder.java \ +java/nio/CharBuffer.java \ +java/nio/InvalidMarkException.java \ java/nio/MappedByteBuffer.java \ java/nio/channels/AlreadyConnectedException.java \ java/nio/channels/ByteChannel.java \ @@ -1732,14 +1743,16 @@ java/nio/channels/ServerSocketChannel.java \ java/nio/channels/SocketChannel.java \ java/nio/channels/WritableByteChannel.java \ java/nio/channels/spi/AbstractSelectableChannel.java \ -java/nio/channels/spi/AbstractChannel.java \ java/nio/channels/spi/AbstractInterruptibleChannel.java \ java/nio/channels/spi/AbstractSelectionKey.java \ java/nio/channels/spi/AbstractSelector.java \ java/nio/channels/spi/SelectorProvider.java \ java/nio/charset/Charset.java \ java/nio/charset/CharacterCodingException.java \ +java/nio/charset/CharsetDecoder.java \ +java/nio/charset/CharsetEncoder.java \ java/nio/charset/CoderMalfunctionError.java \ +java/nio/charset/CoderResult.java \ java/nio/charset/CodingErrorAction.java \ java/nio/charset/IllegalCharsetNameException.java \ java/nio/charset/MalformedInputException.java \ @@ -2514,7 +2527,15 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/gnu/java/locale/LocaleInformation_zh_HK.P \ .deps/gnu/java/locale/LocaleInformation_zh_SG.P \ .deps/gnu/java/locale/LocaleInformation_zh_TW.P \ -.deps/gnu/java/math/MPN.P \ +.deps/gnu/java/math/MPN.P .deps/gnu/java/nio/charset/ISO_8859_1.P \ +.deps/gnu/java/nio/charset/Provider.P \ +.deps/gnu/java/nio/charset/US_ASCII.P \ +.deps/gnu/java/nio/charset/UTF_16.P \ +.deps/gnu/java/nio/charset/UTF_16BE.P \ +.deps/gnu/java/nio/charset/UTF_16Decoder.P \ +.deps/gnu/java/nio/charset/UTF_16Encoder.P \ +.deps/gnu/java/nio/charset/UTF_16LE.P \ +.deps/gnu/java/nio/charset/UTF_8.P \ .deps/gnu/java/rmi/RMIMarshalledObjectInputStream.P \ .deps/gnu/java/rmi/RMIMarshalledObjectOutputStream.P \ .deps/gnu/java/rmi/dgc/DGCImpl.P .deps/gnu/java/rmi/dgc/DGCImpl_Skel.P \ @@ -2981,7 +3002,8 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/net/natPlainSocketImpl.P .deps/java/nio/Buffer.P \ .deps/java/nio/BufferOverflowException.P \ .deps/java/nio/BufferUnderflowException.P .deps/java/nio/ByteBuffer.P \ -.deps/java/nio/ByteOrder.P .deps/java/nio/MappedByteBuffer.P \ +.deps/java/nio/ByteOrder.P .deps/java/nio/CharBuffer.P \ +.deps/java/nio/InvalidMarkException.P .deps/java/nio/MappedByteBuffer.P \ .deps/java/nio/channels/AlreadyConnectedException.P \ .deps/java/nio/channels/ByteChannel.P .deps/java/nio/channels/Channel.P \ .deps/java/nio/channels/ClosedChannelException.P \ @@ -2998,7 +3020,6 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/nio/channels/ServerSocketChannel.P \ .deps/java/nio/channels/SocketChannel.P \ .deps/java/nio/channels/WritableByteChannel.P \ -.deps/java/nio/channels/spi/AbstractChannel.P \ .deps/java/nio/channels/spi/AbstractInterruptibleChannel.P \ .deps/java/nio/channels/spi/AbstractSelectableChannel.P \ .deps/java/nio/channels/spi/AbstractSelectionKey.P \ @@ -3006,7 +3027,10 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/nio/channels/spi/SelectorProvider.P \ .deps/java/nio/charset/CharacterCodingException.P \ .deps/java/nio/charset/Charset.P \ +.deps/java/nio/charset/CharsetDecoder.P \ +.deps/java/nio/charset/CharsetEncoder.P \ .deps/java/nio/charset/CoderMalfunctionError.P \ +.deps/java/nio/charset/CoderResult.P \ .deps/java/nio/charset/CodingErrorAction.P \ .deps/java/nio/charset/IllegalCharsetNameException.P \ .deps/java/nio/charset/MalformedInputException.P \ diff --git a/libjava/java/nio/Buffer.java b/libjava/java/nio/Buffer.java index 4e18cbd..9474fb4 100644 --- a/libjava/java/nio/Buffer.java +++ b/libjava/java/nio/Buffer.java @@ -39,4 +39,155 @@ package java.nio; public abstract class Buffer { + int cap = 0; + int limit = 0; + int pos = 0; + int mark = -1; + + /** + * Retrieves the capacity of the buffer. + */ + public final int capacity () + { + return cap; + } + + /** + * Clears the buffer. + */ + public final Buffer clear () + { + limit = cap; + pos = 0; + mark = -1; + return this; + } + + /** + * Flips the buffer. + */ + public final Buffer flip () + { + limit = pos; + pos = 0; + mark = -1; + return this; + } + + /** + * Tells whether the buffer has remaining data to read or not. + */ + public final boolean hasRemaining () + { + return limit > pos; + } + + /** + * Tells whether this buffer is read only or not. + */ + public abstract boolean isReadOnly (); + + /** + * Retrieves the current limit of the buffer. + */ + public final int limit () + { + return limit; + } + + /** + * Sets this buffer's limit. + * + * @param newLimit The new limit value; must be non-negative and no larger + * than this buffer's capacity. + * + * @exception IllegalArgumentException If the preconditions on newLimit + * do not hold. + */ + public final Buffer limit (int newLimit) + { + if ((newLimit < 0) || (newLimit > cap)) + throw new IllegalArgumentException (); + + if (newLimit <= mark) + mark = -1; + + if (pos > newLimit) + pos = newLimit - 1; + + limit = newLimit; + return this; + } + + /** + * Sets this buffer's mark at its position. + */ + public final Buffer mark () + { + mark = pos; + return this; + } + + /** + * Retrieves the current position of this buffer. + */ + public final int position () + { + return pos; + } + + /** + * Sets this buffer's position. If the mark is defined and larger than the + * new position then it is discarded. + * + * @param newPosition The new position value; must be non-negative and no + * larger than the current limit. + * + * @exception IllegalArgumentException If the preconditions on newPosition + * do not hold + */ + public final Buffer position (int newPosition) + { + if ((newPosition < 0) || (newPosition > limit)) + throw new IllegalArgumentException (); + + if (newPosition <= mark) + mark = -1; + + pos = newPosition; + return this; + } + + /** + * Returns the number of elements between the current position and the limit. + */ + public final int remaining() + { + return limit - pos; + } + + /** + * Resets this buffer's position to the previously-marked position. + * + * @exception InvalidMarkException If the mark has not been set. + */ + public final Buffer reset() + { + if (mark == -1) + throw new InvalidMarkException (); + + pos = mark; + return this; + } + + /** + * Rewinds this buffer. The position is set to zero and the mark + * is discarded. + */ + public final Buffer rewind() + { + pos = 0; + mark = -1; + return this; + } } diff --git a/libjava/java/nio/CharBuffer.java b/libjava/java/nio/CharBuffer.java new file mode 100644 index 0000000..2a21ef9 --- /dev/null +++ b/libjava/java/nio/CharBuffer.java @@ -0,0 +1,291 @@ +/* CharBuffer.java -- + Copyright (C) 2002 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 java.nio; + +public abstract class CharBuffer extends Buffer +{ + private ByteOrder endian = ByteOrder.BIG_ENDIAN; + + protected char [] backing_buffer; + + public static CharBuffer allocate (int capacity) + { + return null; + } + + /** + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + final public static CharBuffer wrap (char[] array, int offset, int length) + { + if ((offset < 0) || + (offset > array.length) || + (length < 0) || + (length > (array.length - offset))) + throw new IndexOutOfBoundsException (); + + return null; + } + + final public static CharBuffer wrap (CharSequence a) + { + return wrap (a, 0, a.length ()); + } + + /** + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + final public static CharBuffer wrap (CharSequence a, int offset, int length) + { + char [] buffer = new char [length]; + + for (int i = offset; i < length; i++) + { + buffer [i] = a.charAt (i); + } + + return wrap (buffer, 0, length); + } + + final public static CharBuffer wrap (char[] array) + { + return wrap (array, 0, array.length); + } + + /** + * @exception BufferUnderflowException FIXME + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + final public CharBuffer get (char[] dst, int offset, int length) + { + for (int i = offset; i < offset + length; i++) + { + dst [i] = get (); + } + return this; + } + + /** + * @exception BufferUnderflowException FIXME + */ + final public CharBuffer get (char[] dst) + { + return get (dst, 0, dst.length); + } + + /** + * @exception BufferOverflowException FIXME + * @exception IllegalArgumentException FIXME + * @exception ReadOnlyBufferException FIXME + */ + final public CharBuffer put (CharBuffer src) + { + while (src.hasRemaining ()) + put (src.get ()); + + return this; + } + + /** + * @exception BufferOverflowException FIXME + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + * @exception ReadOnlyBufferException FIXME + */ + final public CharBuffer put (char[] src, int offset, int length) + { + for (int i = offset; i < offset + length; i++) + put (src [i]); + + return this; + } + + /** + * @exception BufferOverflowException FIXME + * @exception ReadOnlyBufferException FIXME + */ + public final CharBuffer put (char[] src) + { + return put (src, 0, src.length); + } + + public final boolean hasArray () + { + return backing_buffer != null; + } + + /** + * @exception ReadOnlyBufferException FIXME + * @exception UnsupportedOperationException FIXME + */ + public final char[] array () + { + return backing_buffer; + } + + /** + * @exception ReadOnlyBufferException FIXME + * @exception UnsupportedOperationException FIXME + */ + public final int arrayOffset () + { + return 0; + } + + public int hashCode () + { + return super.hashCode (); + } + + public boolean equals (Object obj) + { + if (obj instanceof CharBuffer) + return compareTo (obj) == 0; + + return false; + } + + /** + * @exception ClassCastException FIXME + */ + public int compareTo(Object obj) + { + CharBuffer a = (CharBuffer) obj; + + if (a.remaining () != remaining ()) + return 1; + + if (! hasArray () || ! a.hasArray ()) + return 1; + + int r = remaining (); + int i1 = pos; + int i2 = a.pos; + + for (int i = 0; i < r; i++) + { + int t = (int) (get (i1)- a.get (i2)); + + if (t != 0) + return (int) t; + } + return 0; + } + + /** + * @exception BufferUnderflowException FIXME + */ + public abstract char get (); + + /** + * @exception BufferOverflowException FIXME + * @exception ReadOnlyBufferException FIXME + */ + public abstract CharBuffer put (char b); + + /** + * @exception IndexOutOfBoundsException FIXME + */ + public abstract char get (int index); + + /** + * @exception IndexOutOfBoundsException FIXME + * @exception ReadOnlyBufferException FIXME + */ + public abstract CharBuffer put (int index, char b); + + /** + * @exception ReadOnlyBufferException FIXME + */ + public abstract CharBuffer compact (); + + public abstract boolean isDirect (); + + public abstract CharBuffer slice (); + + public abstract CharBuffer duplicate (); + + public abstract CharBuffer asReadOnlyBuffer (); + + public String toString () + { + return ""; + } + + public final int length () + { + return 0; + } + + public abstract ByteOrder order (); + + /** + * @exception IndexOutOfBoundsException FIXME + */ + public abstract CharSequence subSequence (int start, int length); + + /** + * @exception BufferOverflowException FIXME + * @exception IndexOutOfBoundsException FIXME + * @exception ReadOnlyBufferException FIXME + */ + public CharBuffer put (String str, int start, int length) + { + return null; + } + + /** + * @exception BufferOverflowException FIXME + * @exception ReadOnlyBufferException FIXME + */ + public final CharBuffer put (String str) + { + return null; + } + + /** + * @exception IndexOutOfBoundsException FIXME + */ + public final char charAt (int index) + { + return ' '; + } +} diff --git a/libjava/java/nio/InvalidMarkException.java b/libjava/java/nio/InvalidMarkException.java new file mode 100644 index 0000000..5917855 --- /dev/null +++ b/libjava/java/nio/InvalidMarkException.java @@ -0,0 +1,52 @@ +/* InvalidMarkException.java -- + Copyright (C) 2002 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 java.nio; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class InvalidMarkException extends IllegalStateException +{ + /** + * Creates the exception + */ + public InvalidMarkException () + { + } +} diff --git a/libjava/java/nio/channels/DatagramChannel.java b/libjava/java/nio/channels/DatagramChannel.java index 301f33e..eefa443 100644 --- a/libjava/java/nio/channels/DatagramChannel.java +++ b/libjava/java/nio/channels/DatagramChannel.java @@ -37,14 +37,117 @@ exception statement from your version. */ package java.nio.channels; +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; +/** + * @since 1.4 + */ public abstract class DatagramChannel extends AbstractSelectableChannel + implements ByteChannel, ScatteringByteChannel, GatheringByteChannel { - public DatagramChannel (SelectorProvider provider) + /** + * Initializes the channel. + */ + protected DatagramChannel (SelectorProvider provider) { super (provider); } + + /** + * Opens a datagram channel. + */ + public static DatagramChannel open () throws IOException + { + return SelectorProvider.provider ().openDatagramChannel (); + } + + /** + * Reads data from this channel. + */ + public final long read (ByteBuffer[] dsts) throws IOException + { + long b = 0; + + for (int i = 0; i < dsts.length; i++) + b += read (dsts[i]); + + return b; + } + + /** + * Writes data to this channel. + */ + public final long write (ByteBuffer[] srcs) + { + long b = 0; + + for (int i = 0;i < srcs.length; i++) + b += write (srcs[i]); + + return b; + } + + /** + * Connects this channel's socket. + */ + public abstract DatagramChannel connect (SocketAddress remote); + + /** + * Disonnects this channel's socket. + */ + public abstract DatagramChannel disconnect (); + + /** + * Tells whether or not this channel's socket is connected. + */ + public abstract boolean isConnected (); + + /** + * Reads data from this channel. + */ + public abstract int read (ByteBuffer dst); + + /** + * Reads data from this channel. + */ + public abstract long read (ByteBuffer[] dsts, int offset, int length); + + /** + * Receives a datagram via this channel. + */ + public abstract SocketAddress receive (ByteBuffer dst); + + /** + * Sends a datagram via this channel. + */ + public abstract int send (ByteBuffer src, SocketAddress target); + + /** + * Retrieves the channel's socket. + */ + public abstract DatagramSocket socket (); + + /** + * Writes data to this channel. + */ + public abstract int write (ByteBuffer src); + + /** + * Writes data to this channel. + */ + public abstract long write (ByteBuffer[] srcs, int offset, int length); + + /** + * Retrieves the valid operations for this channel. + */ + public final int validOps () + { + return SelectionKey.OP_READ | SelectionKey.OP_WRITE; + } } diff --git a/libjava/java/nio/channels/ServerSocketChannel.java b/libjava/java/nio/channels/ServerSocketChannel.java index e423bd1..ed8d392 100644 --- a/libjava/java/nio/channels/ServerSocketChannel.java +++ b/libjava/java/nio/channels/ServerSocketChannel.java @@ -39,12 +39,49 @@ package java.nio.channels; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; +import java.nio.ByteOrder; +import java.nio.ByteBuffer; +import java.io.IOException; +import java.net.ServerSocket; +/** + * @author Michael Koch + * @since 1.4 + */ public abstract class ServerSocketChannel extends AbstractSelectableChannel { + /** + * Initializes this channel. + */ public ServerSocketChannel (SelectorProvider provider) { super (provider); } + + /** + * Accepts a connection made to this channel's socket. + */ + public abstract SocketChannel accept (); + + /** + * Retrieves the channels socket. + */ + public abstract ServerSocket socket (); + + /** + * Opens a server socker channel. + */ + public static ServerSocketChannel open () throws IOException + { + return SelectorProvider.provider ().openServerSocketChannel (); + } + + /** + * Retrieves the valid operations for this channel. + */ + public final int validOps () + { + return SelectionKey.OP_ACCEPT; + } } diff --git a/libjava/java/nio/channels/SocketChannel.java b/libjava/java/nio/channels/SocketChannel.java index dc6e1d2..1d93430 100644 --- a/libjava/java/nio/channels/SocketChannel.java +++ b/libjava/java/nio/channels/SocketChannel.java @@ -39,12 +39,127 @@ package java.nio.channels; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; +import java.nio.ByteBuffer; +import java.io.IOException; +import java.net.Socket; +import java.net.SocketAddress; -public abstract class SocketChannel - extends AbstractSelectableChannel +/** + * @author Michael Koch + * @since 1.4 + */ +abstract public class SocketChannel extends AbstractSelectableChannel { - public SocketChannel (SelectorProvider provider) + /** + * Initializes this socket. + */ + protected SocketChannel (SelectorProvider provider) { super (provider); } + + /** + * Opens a socket channel. + */ + public static SocketChannel open () throws IOException + { + return SelectorProvider.provider ().openSocketChannel (); + } + + /** + * Opens a channel and connects it to a remote address. + */ + public static SocketChannel open (SocketAddress remote) throws IOException + { + SocketChannel ch = open (); + + if (ch.connect (remote)) + { + } + + return ch; + } + + /** + * Reads data from the channel. + */ + public final long read (ByteBuffer[] dsts) + { + long b = 0; + + for (int i = 0; i < dsts.length; i++) + { + b += read (dsts [i]); + } + + return b; + } + + /** + * Writes data to the channel. + */ + public final long write (ByteBuffer[] dsts) + { + long b = 0; + + for (int i= 0; i < dsts.length; i++) + { + b += write (dsts [i]); + } + + return b; + } + + /** + * Retrieves the valid operations for this channel. + */ + public final int validOps () + { + return SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE; + } + + /** + * Reads data from the channel. + */ + public abstract int read (ByteBuffer dst); + + /** + * Connects the channel's socket to the remote address. + */ + public abstract boolean connect (SocketAddress remote) throws IOException; + + /** + * Finishes the process of connecting a socket channel. + */ + public abstract boolean finishConnect (); + + /** + * Tells whether or not the channel's socket is connected. + */ + public abstract boolean isConnected (); + + /** + * Tells whether or not a connection operation is in progress on this channel. + */ + public abstract boolean isConnectionPending (); + + /** + * Reads data from the channel. + */ + public abstract long read (ByteBuffer[] dsts, int offset, int length); + + /** + * Retrieves the channel's socket. + */ + public abstract Socket socket (); + + /** + * Writes data to the channel. + */ + public abstract int write (ByteBuffer src); + + /** + * Writes data to the channel. + */ + public abstract long write (ByteBuffer[] srcs, int offset, int length); } diff --git a/libjava/java/nio/channels/spi/AbstractChannel.java b/libjava/java/nio/channels/spi/AbstractChannel.java deleted file mode 100644 index 3d7fe7a..0000000 --- a/libjava/java/nio/channels/spi/AbstractChannel.java +++ /dev/null @@ -1,57 +0,0 @@ -/* AbstractChannel.java -- - Copyright (C) 2002 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 java.nio.channels.spi; - -import java.io.IOException; -import java.nio.channels.Channel; - -public abstract class AbstractChannel implements Channel -{ - boolean opened; - - public boolean isOpen() - { - return opened; - } - - public void close() throws IOException - { - if (! isOpen()) - return; - } -} diff --git a/libjava/java/nio/channels/spi/AbstractSelectableChannel.java b/libjava/java/nio/channels/spi/AbstractSelectableChannel.java index 42bb1f2..433b729 100644 --- a/libjava/java/nio/channels/spi/AbstractSelectableChannel.java +++ b/libjava/java/nio/channels/spi/AbstractSelectableChannel.java @@ -1,4 +1,4 @@ -/* AbstractSelectableChannel.java -- +/* AbstractSelectableChannel.java Copyright (C) 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,18 +37,171 @@ exception statement from your version. */ package java.nio.channels.spi; +import java.io.IOException; +import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; -public abstract class AbstractSelectableChannel - extends SelectableChannel +public abstract class AbstractSelectableChannel extends SelectableChannel { + int registered; + boolean blocking = true; + Object LOCK = new Object (); + SelectorProvider provider; + List keys; + + /** + * Initializes the channel + */ protected AbstractSelectableChannel (SelectorProvider provider) { + this.provider = provider; + } + + /** + * Retrieves the object upon which the configureBlocking and register + * methods synchronize. + */ + public final Object blockingLock () + { + return LOCK; + } + + /** + * Adjusts this channel's blocking mode. + */ + public final SelectableChannel configureBlocking (boolean block) + { + synchronized (LOCK) + { + blocking = true; + implConfigureBlocking (block); + } + + return this; + } + + /** + * Closes this channel. + */ + protected final void implCloseChannel () + { + implCloseSelectableChannel (); } + + /** + * Closes this selectable channel. + */ + protected abstract void implCloseSelectableChannel (); + /** + * Adjusts this channel's blocking mode. + */ + protected abstract void implConfigureBlocking (boolean block); + + /** + * Tells whether or not every I/O operation on this channel will block + * until it completes. + */ public final boolean isBlocking() { - return true; + return blocking; + } + + /** + * Tells whether or not this channel is currently registered with + * any selectors. + */ + public final boolean isRegistered() + { + return registered > 0; + } + + /** + * Retrieves the key representing the channel's registration with the + * given selector. + */ + public final SelectionKey keyFor(Selector selector) + { + try + { + return register (selector, 0, null); + } + catch (Exception e) + { + return null; + } } -} + /** + * Returns the provider that created this channel. + */ + public final SelectorProvider provider () + { + return provider; + } + + private SelectionKey locate (Selector selector) + { + if (keys == null) + return null; + + SelectionKey k = null; + ListIterator it = keys.listIterator (); + + while (it.hasNext ()) + { + k = (SelectionKey) it.next (); + if (k.selector () == selector) + { + return k; + } + } + + return k; + } + + private void add (SelectionKey key) + { + if (keys == null) + keys = new LinkedList (); + + keys.add (key); + } + + /** + * Registers this channel with the given selector, returning a selection key. + */ + public final SelectionKey register (Selector selin, int ops, Object att) + throws ClosedChannelException + { + if (!isOpen ()) + throw new ClosedChannelException(); + + SelectionKey k = null; + AbstractSelector selector = (AbstractSelector) selin; + + synchronized (LOCK) + { + k = locate (selector); + + if (k != null) + { + k.attach (att); + } + else + { + k = selector.register (this, ops, att); + + if (k != null) + add (k); + } + } + + return k; + } +} diff --git a/libjava/java/nio/charset/Charset.java b/libjava/java/nio/charset/Charset.java index 2a1338f..5d96daf 100644 --- a/libjava/java/nio/charset/Charset.java +++ b/libjava/java/nio/charset/Charset.java @@ -37,54 +37,215 @@ exception statement from your version. */ package java.nio.charset; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.spi.CharsetProvider; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import gnu.java.nio.charset.Provider; -import java.nio.*; - -public class Charset -{ - public static Charset forName(String name) - { - return new Charset(); - } - -/* - public CharsetDecoder newDecoder() - { - return new CharsetDecoder(this,2,2) - { - protected CoderResult decodeLoop(ByteBuffer in, - CharBuffer out) - { - while (in.hasRemaining()) - { - char a = (char) in.get(); - out.put(a); - } - return null; - } - }; - } - - public CharsetEncoder newEncoder() - { - return new CharsetEncoder(this,2,2) - { - protected CoderResult encodeLoop(CharBuffer in, - ByteBuffer out) - { - //System.out.println("in encode loop:"+in.hasRemaining()); - - while (in.hasRemaining()) - { - char a = in.get(); - out.put((byte)a); - - //int len = out.position(); - //System.out.println("pos="+len + ","+a); - } - return null; - } - }; - } +/** + * @author Jesse Rosenstock + * @since 1.4 */ +public abstract class Charset implements Comparable +{ + private final String canonicalName; + private final String[] aliases; + + protected Charset (String canonicalName, String[] aliases) + { + checkName (canonicalName); + if (aliases != null) + { + int n = aliases.length; + for (int i = 0; i < n; ++i) + checkName (aliases[i]); + } + + this.canonicalName = canonicalName; + this.aliases = aliases; + } + + /** + * @throws IllegalCharsetNameException if the name is illegal + */ + private static void checkName (String name) + { + int n = name.length (); + + if (n == 0) + throw new IllegalCharsetNameException (name); + + char ch = name.charAt (0); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9'))) + throw new IllegalCharsetNameException (name); + + for (int i = 1; i < n; ++i) + { + ch = name.charAt (i); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9') + || ch == '-' || ch == '.' || ch == ':' || ch == '_')) + throw new IllegalCharsetNameException (name); + } + } + + public static boolean isSupported (String charsetName) + { + return charsetForName (charsetName) != null; + } + + public static Charset forName (String charsetName) + { + Charset cs = charsetForName (charsetName); + if (cs == null) + throw new UnsupportedCharsetException (charsetName); + return cs; + } + + /** + * Retrieves a charset for the given charset name. + * + * @return A charset object for the charset with the specified name, or + * null if no such charset exists. + * + * @throws IllegalCharsetNameException if the name is illegal + */ + private static Charset charsetForName (String charsetName) + { + checkName (charsetName); + return provider ().charsetForName (charsetName); + } + + public static SortedMap availableCharsets () + { + TreeMap charsets = new TreeMap (String.CASE_INSENSITIVE_ORDER); + + for (Iterator i = provider ().charsets (); i.hasNext (); ) + { + Charset cs = (Charset) i.next (); + charsets.put (cs.name (), cs); + } + + return Collections.unmodifiableSortedMap (charsets); + } + + // XXX: we need to support multiple providers, reading them from + // java.nio.charset.spi.CharsetProvider in the resource directory + // META-INF/services + private static final CharsetProvider provider () + { + return Provider.provider (); + } + + public final String name () + { + return canonicalName; + } + + public final Set aliases () + { + if (aliases == null) + return Collections.EMPTY_SET; + + // should we cache the aliasSet instead? + int n = aliases.length; + HashSet aliasSet = new HashSet (n); + for (int i = 0; i < n; ++i) + aliasSet.add (aliases[i]); + return Collections.unmodifiableSet (aliasSet); + } + + public String displayName () + { + return canonicalName; + } + + public String displayName (Locale locale) + { + return canonicalName; + } + + public final boolean isRegistered (String name) + { + return !name.startsWith ("x-") && !name.startsWith ("X-"); + } + + public abstract boolean contains (Charset cs); + + public abstract CharsetDecoder newDecoder (); + + public abstract CharsetEncoder newEncoder (); + + public boolean canEncode () + { + return true; + } + + public final ByteBuffer encode (CharBuffer cb) + { + try + { + // TODO: cache encoders between sucessive invocations + return newEncoder ().onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE) + .encode (cb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final ByteBuffer encode (String str) + { + return encode (CharBuffer.wrap (str)); + } + + public CharBuffer decode (ByteBuffer bb) + { + try + { + // TODO: cache encoders between sucessive invocations + return newDecoder ().onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE) + .decode (bb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final int compareTo (Object ob) + { + return canonicalName.compareToIgnoreCase (((Charset) ob).canonicalName); + } + + public final int hashCode () + { + return canonicalName.hashCode (); + } + + public final boolean equals (Object ob) + { + if (ob instanceof Charset) + return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName); + else + return false; + } + + public final String toString () + { + return canonicalName; + } } diff --git a/libjava/java/nio/charset/CharsetDecoder.java b/libjava/java/nio/charset/CharsetDecoder.java new file mode 100644 index 0000000..185de14 --- /dev/null +++ b/libjava/java/nio/charset/CharsetDecoder.java @@ -0,0 +1,312 @@ +/* CharsetDecoder.java -- + Copyright (C) 2002 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 java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public abstract class CharsetDecoder +{ + private static final int STATE_RESET = 0; + private static final int STATE_CODING = 1; + private static final int STATE_END = 2; + private static final int STATE_FLUSHED = 3; + + private static final String DEFAULT_REPLACEMENT = "\uFFFD"; + + private final Charset charset; + private final float averageCharsPerByte; + private final float maxCharsPerByte; + private String replacement; + + private int state = STATE_RESET; + + private CodingErrorAction malformedInputAction + = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction + = CodingErrorAction.REPORT; + + private CharsetDecoder (Charset cs, float averageCharsPerByte, + float maxCharsPerByte, String replacement) + { + if (averageCharsPerByte <= 0.0f) + throw new IllegalArgumentException ("Non-positive averageCharsPerByte"); + if (maxCharsPerByte <= 0.0f) + throw new IllegalArgumentException ("Non-positive maxCharsPerByte"); + + this.charset = cs; + this.averageCharsPerByte + = averageCharsPerByte; + this.maxCharsPerByte + = maxCharsPerByte; + this.replacement = replacement; + implReplaceWith (replacement); + } + + protected CharsetDecoder (Charset cs, float averageCharsPerByte, + float maxCharsPerByte) + { + this (cs, averageCharsPerByte, maxCharsPerByte, DEFAULT_REPLACEMENT); + } + + public final float averageCharsPerByte () + { + return averageCharsPerByte; + } + + public final Charset charset () + { + return charset; + } + + public final CharBuffer decode (ByteBuffer in) + throws CharacterCodingException + { + // XXX: Sun's Javadoc seems to contradict itself saying an + // IllegalStateException is thrown "if a decoding operation is already + // in progress" and also that "it resets this Decoder". + // Should we check to see that the state is reset, or should we + // call reset()? + if (state != STATE_RESET) + throw new IllegalStateException (); + + // REVIEW: Using max instead of average may allocate a very large + // buffer. Maybe we should do something more efficient? + int remaining = in.remaining (); + int n = (int) (remaining * maxCharsPerByte ()); + CharBuffer out = CharBuffer.allocate (n); + + if (remaining == 0) + { + state = STATE_FLUSHED; + return out; + } + + CoderResult cr = decode (in, out, true); + if (cr.isError ()) + cr.throwException (); + + cr = flush (out); + if (cr.isError ()) + cr.throwException (); + + out.flip (); + return out; + } + + public final CoderResult decode (ByteBuffer in, CharBuffer out, + boolean endOfInput) + { + int newState = endOfInput ? STATE_END : STATE_CODING; + // XXX: Need to check for "previous step was an invocation [not] of + // this method with a value of true for the endOfInput parameter but + // a return value indicating an incomplete decoding operation" + // XXX: We will not check the previous return value, just + // that the previous call passed true for endOfInput + if (state != STATE_RESET && state != STATE_CODING + && !(endOfInput && state == STATE_END)) + throw new IllegalStateException (); + state = newState; + + for (;;) + { + CoderResult cr; + try + { + cr = decodeLoop (in, out); + } + catch (RuntimeException e) + { + throw new CoderMalfunctionError (e); + } + + if (cr.isOverflow ()) + return cr; + + if (cr.isUnderflow ()) + { + if (endOfInput && in.hasRemaining ()) + cr = CoderResult.malformedForLength (in.remaining ()); + else + return cr; + } + + CodingErrorAction action = cr.isMalformed () + ? malformedInputAction + : unmappableCharacterAction; + + if (action == CodingErrorAction.REPORT) + return cr; + + if (action == CodingErrorAction.REPLACE) + { + if (out.remaining () < replacement.length ()) + return CoderResult.OVERFLOW; + out.put (replacement); + } + + in.position (in.position () + cr.length ()); + } + } + + protected abstract CoderResult decodeLoop (ByteBuffer in, CharBuffer out); + + public Charset detectedCharset () + { + throw new UnsupportedOperationException (); + } + + public final CoderResult flush (CharBuffer out) + { + // It seems weird that you can flush after reset, but Sun's javadoc + // says an IllegalStateException is thrown "If the previous step of the + // current decoding operation was an invocation neither of the reset + // method nor ... of the three-argument decode method with a value of + // true for the endOfInput parameter." + // Further note that flush() only requires that there not be + // an IllegalStateException if the previous step was a call to + // decode with true as the last argument. It does not require + // that the call succeeded. decode() does require that it succeeded. + // XXX: test this to see if reality matches javadoc + if (state != STATE_RESET && state != STATE_END) + throw new IllegalStateException (); + + state = STATE_FLUSHED; + return implFlush (out); + } + + protected CoderResult implFlush (CharBuffer out) + { + return CoderResult.UNDERFLOW; + } + + public final CharsetDecoder onMalformedInput (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + malformedInputAction = newAction; + implOnMalformedInput (newAction); + return this; + } + + protected void implOnMalformedInput (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implOnUnmappableCharacter (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implReplaceWith (String newReplacement) + { + // default implementation does nothing + } + + protected void implReset () + { + // default implementation does nothing + } + + public boolean isAutoDetecting () + { + return false; + } + + public boolean isCharsetDetected () + { + throw new UnsupportedOperationException (); + } + + public CodingErrorAction malformedInputAction () + { + return malformedInputAction; + } + + public final float maxCharsPerByte () + { + return maxCharsPerByte; + } + + public final CharsetDecoder onUnmappableCharacter + (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + unmappableCharacterAction = newAction; + implOnUnmappableCharacter (newAction); + return this; + } + + public final String replacement () + { + return replacement; + } + + public final CharsetDecoder replaceWith (String newReplacement) + { + if (newReplacement == null) + throw new IllegalArgumentException ("Null replacement"); + if (newReplacement.length () == 0) + throw new IllegalArgumentException ("Empty replacement"); + // XXX: what about maxCharsPerByte? + + this.replacement = newReplacement; + implReplaceWith (newReplacement); + return this; + } + + public final CharsetDecoder reset () + { + state = STATE_RESET; + implReset (); + return this; + } + + public CodingErrorAction unmappableCharacterAction () + { + return unmappableCharacterAction; + } +} diff --git a/libjava/java/nio/charset/CharsetEncoder.java b/libjava/java/nio/charset/CharsetEncoder.java new file mode 100644 index 0000000..dd434a7 --- /dev/null +++ b/libjava/java/nio/charset/CharsetEncoder.java @@ -0,0 +1,360 @@ +/* CharsetEncoder.java -- + Copyright (C) 2002 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 java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public abstract class CharsetEncoder +{ + private static final int STATE_RESET = 0; + private static final int STATE_CODING = 1; + private static final int STATE_END = 2; + private static final int STATE_FLUSHED = 3; + + private static final byte[] DEFAULT_REPLACEMENT = {(byte)'?'}; + + private final Charset charset; + private final float averageBytesPerChar; + private final float maxBytesPerChar; + private byte[] replacement; + + private int state = STATE_RESET; + + private CodingErrorAction malformedInputAction + = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction + = CodingErrorAction.REPORT; + + protected CharsetEncoder (Charset cs, float averageBytesPerChar, + float maxBytesPerChar) + { + this (cs, averageBytesPerChar, maxBytesPerChar, DEFAULT_REPLACEMENT); + } + + protected CharsetEncoder (Charset cs, float averageBytesPerChar, + float maxBytesPerChar, byte[] replacement) + { + if (averageBytesPerChar <= 0.0f) + throw new IllegalArgumentException ("Non-positive averageBytesPerChar"); + if (maxBytesPerChar <= 0.0f) + throw new IllegalArgumentException ("Non-positive maxBytesPerChar"); + + this.charset = cs; + this.averageBytesPerChar + = averageBytesPerChar; + this.maxBytesPerChar + = maxBytesPerChar; + this.replacement = replacement; + implReplaceWith (replacement); + } + + public final float averageBytesPerChar () + { + return averageBytesPerChar; + } + + public boolean canEncode (char c) + { + CharBuffer cb = CharBuffer.allocate (1).put (c); + cb.flip (); + return canEncode (cb); + } + + public boolean canEncode (CharSequence cs) + { + CharBuffer cb; + if (cs instanceof CharBuffer) + cb = ((CharBuffer) cs).duplicate (); + else + cb = CharBuffer.wrap (cs); + return canEncode (cb); + } + + private boolean canEncode (CharBuffer cb) + { + // It is an error if a coding operation is "in progress" + // I take that to mean the state is not reset or flushed. + // XXX: check "in progress" everywhere + if (state == STATE_FLUSHED) + reset (); + else if (state != STATE_RESET) + throw new IllegalStateException (); + + CodingErrorAction oldMalformedInputAction = malformedInputAction; + CodingErrorAction oldUnmappableCharacterAction + = unmappableCharacterAction; + + try + { + if (oldMalformedInputAction != CodingErrorAction.REPORT) + onMalformedInput (CodingErrorAction.REPORT); + if (oldUnmappableCharacterAction != CodingErrorAction.REPORT) + onUnmappableCharacter (CodingErrorAction.REPORT); + } + catch (Exception e) + { + return false; + } + finally + { + if (oldMalformedInputAction != CodingErrorAction.REPORT) + onMalformedInput (oldMalformedInputAction); + if (oldUnmappableCharacterAction != CodingErrorAction.REPORT) + onUnmappableCharacter (oldUnmappableCharacterAction); + } + + return true; + } + + public final Charset charset () + { + return charset; + } + + public final ByteBuffer encode (CharBuffer in) + throws CharacterCodingException + { + // XXX: Sun's Javadoc seems to contradict itself saying an + // IllegalStateException is thrown "if a decoding operation is already + // in progress" and also that "it resets this Encoder". + // Should we check to see that the state is reset, or should we + // call reset()? + if (state != STATE_RESET) + throw new IllegalStateException (); + + // REVIEW: Using max instead of average may allocate a very large + // buffer. Maybe we should do something more efficient? + int remaining = in.remaining (); + int n = (int) (remaining * maxBytesPerChar ()); + ByteBuffer out = ByteBuffer.allocate (n); + + if (remaining == 0) + { + state = STATE_FLUSHED; + return out; + } + + CoderResult cr = encode (in, out, true); + if (cr.isError ()) + cr.throwException (); + + cr = flush (out); + if (cr.isError ()) + cr.throwException (); + + out.flip (); + return out; + } + + public final CoderResult encode (CharBuffer in, ByteBuffer out, + boolean endOfInput) + { + int newState = endOfInput ? STATE_END : STATE_CODING; + // XXX: Need to check for "previous step was an invocation [not] of + // this method with a value of true for the endOfInput parameter but + // a return value indicating an incomplete decoding operation" + // XXX: We will not check the previous return value, just + // that the previous call passed true for endOfInput + if (state != STATE_RESET && state != STATE_CODING + && !(endOfInput && state == STATE_END)) + throw new IllegalStateException (); + state = newState; + + for (;;) + { + CoderResult cr; + try + { + cr = encodeLoop (in, out); + } + catch (RuntimeException e) + { + throw new CoderMalfunctionError (e); + } + + if (cr.isOverflow ()) + return cr; + + if (cr.isUnderflow ()) + { + if (endOfInput && in.hasRemaining ()) + cr = CoderResult.malformedForLength (in.remaining ()); + else + return cr; + } + + CodingErrorAction action = cr.isMalformed () + ? malformedInputAction + : unmappableCharacterAction; + + if (action == CodingErrorAction.REPORT) + return cr; + + if (action == CodingErrorAction.REPLACE) + { + if (out.remaining () < replacement.length) + return CoderResult.OVERFLOW; + out.put (replacement); + } + + in.position (in.position () + cr.length ()); + } + } + + protected abstract CoderResult encodeLoop (CharBuffer in, ByteBuffer out); + + public final CoderResult flush (ByteBuffer out) + { + // It seems weird that you can flush after reset, but Sun's javadoc + // says an IllegalStateException is thrown "If the previous step of the + // current decoding operation was an invocation neither of the reset + // method nor ... of the three-argument encode method with a value of + // true for the endOfInput parameter." + // Further note that flush() only requires that there not be + // an IllegalStateException if the previous step was a call to + // encode with true as the last argument. It does not require + // that the call succeeded. encode() does require that it succeeded. + // XXX: test this to see if reality matches javadoc + if (state != STATE_RESET && state != STATE_END) + throw new IllegalStateException (); + + state = STATE_FLUSHED; + return implFlush (out); + } + + protected CoderResult implFlush (ByteBuffer out) + { + return CoderResult.UNDERFLOW; + } + + protected void implOnMalformedInput (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implOnUnmappableCharacter (CodingErrorAction newAction) + { + // default implementation does nothing + } + + protected void implReplaceWith (byte[] newReplacement) + { + // default implementation does nothing + } + + protected void implReset () + { + // default implementation does nothing + } + + public boolean isLegalReplacement (byte[] replacement) + { + // TODO: cache the decoder + // error actions will be REPORT after construction + CharsetDecoder decoder = charset.newDecoder (); + ByteBuffer bb = ByteBuffer.wrap (replacement); + CharBuffer cb + = CharBuffer.allocate ((int) (replacement.length + * decoder.maxCharsPerByte ())); + return !decoder.decode (bb, cb, true).isError (); + } + + public CodingErrorAction malformedInputAction () + { + return malformedInputAction; + } + + public final float maxBytesPerChar () + { + return maxBytesPerChar; + } + + public final CharsetEncoder onMalformedInput (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + malformedInputAction = newAction; + implOnMalformedInput (newAction); + return this; + } + + public final CharsetEncoder onUnmappableCharacter + (CodingErrorAction newAction) + { + if (newAction == null) + throw new IllegalArgumentException ("Null action"); + + unmappableCharacterAction = newAction; + implOnUnmappableCharacter (newAction); + return this; + } + + public final byte[] replacement () + { + return replacement; + } + + public final CharsetEncoder replaceWith (byte[] newReplacement) + { + if (newReplacement == null) + throw new IllegalArgumentException ("Null replacement"); + if (newReplacement.length == 0) + throw new IllegalArgumentException ("Empty replacement"); + // XXX: what about maxBytesPerChar? + + if (!isLegalReplacement (newReplacement)) + throw new IllegalArgumentException ("Illegal replacement"); + + this.replacement = newReplacement; + implReplaceWith (newReplacement); + return this; + } + + public final CharsetEncoder reset () + { + state = STATE_RESET; + implReset (); + return this; + } +} diff --git a/libjava/java/nio/charset/CoderResult.java b/libjava/java/nio/charset/CoderResult.java new file mode 100644 index 0000000..69deadc --- /dev/null +++ b/libjava/java/nio/charset/CoderResult.java @@ -0,0 +1,193 @@ +/* CoderResult.java -- + Copyright (C) 2002 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 java.nio.charset; + +import java.lang.ref.WeakReference; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.util.HashMap; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public class CoderResult +{ + private static final int TYPE_MALFORMED = 0; + private static final int TYPE_OVERFLOW = 1; + private static final int TYPE_UNDERFLOW = 2; + private static final int TYPE_UNMAPPABLE = 3; + + public static final CoderResult OVERFLOW + = new CoderResult (TYPE_OVERFLOW, 0); + public static final CoderResult UNDERFLOW + = new CoderResult (TYPE_UNDERFLOW, 0); + + private static final String[] names + = { "MALFORMED", "OVERFLOW", "UNDERFLOW", "UNMAPPABLE" }; + + private static final Cache malformedCache + = new Cache () + { + protected CoderResult make (int length) + { + return new CoderResult (TYPE_MALFORMED, length); + } + }; + + private static final Cache unmappableCache + = new Cache () + { + protected CoderResult make (int length) + { + return new CoderResult (TYPE_UNMAPPABLE, length); + } + }; + + private final int type; + private final int length; + + private CoderResult (int type, int length) + { + this.type = type; + this.length = length; + } + + public boolean isError () + { + return length > 0; + } + + public boolean isMalformed () + { + return type == TYPE_MALFORMED; + } + + public boolean isOverflow () + { + return type == TYPE_OVERFLOW; + } + + public boolean isUnderflow () + { + return type == TYPE_UNDERFLOW; + } + + public boolean isUnmappable () + { + return type == TYPE_UNMAPPABLE; + } + + public int length () + { + if (length <= 0) + throw new UnsupportedOperationException (); + else + return length; + } + + public static CoderResult malformedForLength (int length) + { + return malformedCache.get (length); + } + + public void throwException () + throws CharacterCodingException + { + switch (type) + { + case TYPE_MALFORMED: + throw new MalformedInputException (length); + case TYPE_OVERFLOW: + throw new BufferOverflowException (); + case TYPE_UNDERFLOW: + throw new BufferUnderflowException (); + case TYPE_UNMAPPABLE: + throw new UnmappableCharacterException (length); + } + } + + public String toString () + { + String name = names[type]; + return (length > 0) ? name + '[' + length + ']' : name; + } + + public static CoderResult unmappableForLength (int length) + { + return unmappableCache.get (length); + } + + private abstract static class Cache + { + private final HashMap cache; + + private Cache () + { + // If we didn't synchronize on this, then cache would be initialized + // without holding a lock. Undefined behavior would occur if the + // first thread to call get(int) was not the same as the one that + // called the constructor. + synchronized (this) + { + cache = new HashMap (); + } + } + + private synchronized CoderResult get (int length) + { + if (length <= 0) + throw new IllegalArgumentException ("Non-positive length"); + + Integer len = new Integer (length); + CoderResult cr = null; + Object o; + if ((o = cache.get (len)) != null) + cr = (CoderResult) ((WeakReference) o).get (); + if (cr == null) + { + cr = make (length); + cache.put (len, cr); + } + + return cr; + } + + protected abstract CoderResult make (int length); + } +} -- cgit v1.1