+2002-11-12 Michael Koch <konqueror@gmx.de>
+
+ * 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 <jmr@ugcs.caltech.edu>
* gnu/java/nio/charset/ISO_8859_1.java,
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 <konqueror@gmx.de>
* java/nio/charset/CharacterCodingException.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 \
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 \
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 \
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 \
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 \
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 \
.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 \
.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 \
.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 \
.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 \
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;
+ }
}
--- /dev/null
+/* 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 ' ';
+ }
+}
-/* AbstractChannel.java --
+/* InvalidMarkException.java --
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package java.nio.channels.spi;
+package java.nio;
-import java.io.IOException;
-import java.nio.channels.Channel;
-
-public abstract class AbstractChannel implements Channel
+/**
+ * @author Michael Koch
+ * @since 1.4
+ */
+public class InvalidMarkException extends IllegalStateException
{
- boolean opened;
-
- public boolean isOpen()
- {
- return opened;
- }
-
- public void close() throws IOException
+ /**
+ * Creates the exception
+ */
+ public InvalidMarkException ()
{
- if (! isOpen())
- return;
}
}
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;
+ }
}
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;
+ }
}
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);
}
-/* AbstractSelectableChannel.java --
+/* AbstractSelectableChannel.java
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
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;
+ }
+}
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
+ * <code>null</code> 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;
+ }
}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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);
+ }
+}