The final version has been comitted. It differs somewhat, so here's that
patch again.

2005-04-15  Sven de Marothy  <[EMAIL PROTECTED]>

        * gnu/java/nio/charset/EncodingHelper.java: Added method
        * java/io/InputStreamReader.java,
        * java/io/OutputStreamWriter.java,
        * java/lang/String.java: Move to NIO charsets.
        * java/io/PrintStream.java: Inline conversion using String.


Index: gnu/java/nio/charset/EncodingHelper.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/charset/EncodingHelper.java,v
retrieving revision 1.1
diff -u -r1.1 EncodingHelper.java
--- gnu/java/nio/charset/EncodingHelper.java	8 Apr 2005 21:46:05 -0000	1.1
+++ gnu/java/nio/charset/EncodingHelper.java	15 Apr 2005 15:54:44 -0000
@@ -116,6 +116,18 @@
 	return (oldCanonical != null)?oldCanonical : newCanonical;
     }
 
+    public static boolean isISOLatin1(String s)
+    {
+	if(s.equals("ISO-8859-1") ||
+	   s.equals("8859_1") ||
+	   s.equals("ISO_8859-1") ||
+	   s.equals("latin1") ||
+	   s.equals("ISO8859_1") || 
+	   s.equals("ISO_8859_1"))
+	    return true;
+	return false;
+    }
+
    /**
     * Gets a charset, throwing the java.io exception and not 
     * the java.nio exception if an error occurs.
Index: java/io/InputStreamReader.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/InputStreamReader.java,v
retrieving revision 1.21
diff -u -r1.21 InputStreamReader.java
--- java/io/InputStreamReader.java	10 Mar 2005 19:35:51 -0000	1.21
+++ java/io/InputStreamReader.java	15 Apr 2005 15:54:46 -0000
@@ -38,12 +38,16 @@
 
 package java.io;
 
-import java.nio.channels.Channels;
+import java.nio.charset.UnsupportedCharsetException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
-
-import gnu.java.io.EncodingManager;
-import gnu.java.io.decode.Decoder;
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import gnu.java.nio.charset.EncodingHelper;
 
 /**
  * This class reads characters from a byte input stream.   The characters
@@ -86,20 +90,50 @@
  * @see BufferedReader
  * @see InputStream
  *
+ * @author Robert Schuster
  * @author Aaron M. Renn ([EMAIL PROTECTED])
  * @author Per Bothner ([EMAIL PROTECTED])
  * @date April 22, 1998.  
  */
 public class InputStreamReader extends Reader
 {
-  /*
-   * This is the byte-character decoder class that does the reading and
-   * translation of bytes from the underlying stream.
+  /**
+   * The input stream.
+   */
+  private InputStream in;
+
+  /**
+   * The charset decoder.
+   */
+  private CharsetDecoder decoder;
+
+  /**
+   * End of stream reached.
+   */
+  private boolean isDone = false;
+
+  /**
+   * Need this.
    */
-  private Reader in;
+  private float maxBytesPerChar;
 
+  /**
+   * Buffer holding surplus loaded bytes (if any)
+   */
+  private ByteBuffer byteBuffer;
+
+  /**
+   * java.io canonical name of the encoding.
+   */
   private String encoding;
-  
+
+  /**
+   * We might decode to a 2-char UTF-16 surrogate, which won't fit in the
+   * output buffer. In this case we need to save the surrogate char.
+   */
+  private char savedSurrogate;
+  private boolean hasSavedSurrogate = false;
+
   /**
    * This method initializes a new instance of <code>InputStreamReader</code>
    * to read from the specified stream using the default encoding.
@@ -110,11 +144,38 @@
   {
     if (in == null)
       throw new NullPointerException();
-    
-    Decoder decoder =  EncodingManager.getDecoder(in);
-    encoding = decoder.getSchemeName();
-    
-    this.in = decoder;
+    this.in = in;
+    try 
+	{ 
+	  encoding = System.getProperty("file.encoding");
+	  // Don't use NIO if avoidable
+	  if(EncodingHelper.isISOLatin1(encoding))
+	    {
+	      encoding = "ISO8859_1";
+	      maxBytesPerChar = 1f;
+	      decoder = null;
+	      return;
+	    }
+	  Charset cs = EncodingHelper.getCharset(encoding);
+	  decoder = cs.newDecoder();
+	  encoding = EncodingHelper.getOldCanonical(cs.name());
+	  try {
+	      maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
+	  } catch(UnsupportedOperationException _){
+	      maxBytesPerChar = 1f;
+	  } 
+	  decoder.onMalformedInput(CodingErrorAction.REPLACE);
+	  decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	  decoder.reset();
+	} catch(RuntimeException e) {
+	  encoding = "ISO8859_1";
+	  maxBytesPerChar = 1f;
+	  decoder = null;
+	} catch(UnsupportedEncodingException e) {
+	  encoding = "ISO8859_1";
+	  maxBytesPerChar = 1f;
+	  decoder = null;
+	}
   }
 
   /**
@@ -136,41 +197,72 @@
         || encoding_name == null)
       throw new NullPointerException();
     
-    Decoder decoder = EncodingManager.getDecoder(in, encoding_name);
-    encoding = decoder.getSchemeName();
-    
-    this.in = decoder;
-    
+    this.in = in;
+    // Don't use NIO if avoidable
+    if(EncodingHelper.isISOLatin1(encoding_name))
+      {
+	encoding = "ISO8859_1";
+	maxBytesPerChar = 1f;
+	decoder = null;
+	return;
+      }
+    try {
+      Charset cs = EncodingHelper.getCharset(encoding_name);
+      try {
+        maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
+      } catch(UnsupportedOperationException _){
+	maxBytesPerChar = 1f;
+      } 
+
+      decoder = cs.newDecoder();
+      decoder.onMalformedInput(CodingErrorAction.REPLACE);
+      decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+      decoder.reset();
+
+      // The encoding should be the old name, if such exists.
+      encoding = EncodingHelper.getOldCanonical(cs.name());
+    } catch(RuntimeException e) {
+      encoding = "ISO8859_1";
+      maxBytesPerChar = 1f;
+      decoder = null;
+    }
   }
 
   /**
    * Creates an InputStreamReader that uses a decoder of the given
    * charset to decode the bytes in the InputStream into
    * characters.
-   * @since 1.4
    */
-  public InputStreamReader(InputStream in, Charset charset)
-  {
-    /* FIXME: InputStream is wrapped in Channel which is read by a
-     * Reader-implementation for channels. However to fix this we
-     * need to completely move to NIO-style character
-     * encoding/decoding.
-     */
-    this.in = Channels.newReader(Channels.newChannel(in), charset.newDecoder(),
-				 -1);
-    encoding = charset.name();
+  public InputStreamReader(InputStream in, Charset charset) {
+    this.in = in;
+    decoder = charset.newDecoder();
+
+    // JDK reports errors, so we do the same.
+    decoder.onMalformedInput(CodingErrorAction.REPORT);
+    decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+    decoder.reset();
+    encoding = EncodingHelper.getOldCanonical(charset.name());
   }
 
   /**
    * Creates an InputStreamReader that uses the given charset decoder
    * to decode the bytes in the InputStream into characters.
-   * @since 1.4
    */
-  public InputStreamReader(InputStream in, CharsetDecoder decoder)
-  {
-    // FIXME: see [EMAIL PROTECTED] InputStreamReader(InputStream, Charset)
-    this.in = Channels.newReader(Channels.newChannel(in), decoder, -1);
-    encoding = decoder.charset().name();
+  public InputStreamReader(InputStream in, CharsetDecoder decoder) {
+    this.in = in;
+    this.decoder = decoder;
+
+    try {
+	maxBytesPerChar = decoder.charset().newEncoder().maxBytesPerChar();
+    } catch(UnsupportedOperationException _){
+	maxBytesPerChar = 1f;
+    } 
+
+    // JDK reports errors, so we do the same.
+    decoder.onMalformedInput(CodingErrorAction.REPORT);
+    decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+    decoder.reset();
+    encoding = EncodingHelper.getOldCanonical(decoder.charset().name());      
   }
   
   /**
@@ -183,9 +275,14 @@
   {
     synchronized (lock)
       {
+	// Makes sure all intermediate data is released by the decoder.
+	if (decoder != null)
+	   decoder.reset();
 	if (in != null)
-	  in.close();
+	   in.close();
 	in = null;
+	isDone = true;
+	decoder = null;
       }
   }
 
@@ -202,7 +299,7 @@
   }
 
   /**
-   * This method checks to see if the stream is read to be read.  It
+   * This method checks to see if the stream is ready to be read.  It
    * will return <code>true</code> if is, or <code>false</code> if it is not.
    * If the stream is not ready to be read, it could (although is not required
    * to) block on the next read attempt.
@@ -217,7 +314,7 @@
     if (in == null)
       throw new IOException("Reader has been closed");
     
-    return in.ready();
+    return in.available() != 0;
   }
 
   /**
@@ -233,45 +330,108 @@
    *
    * @exception IOException If an error occurs
    */
-  public int read (char[] buf, int offset, int length) throws IOException
+  public int read(char[] buf, int offset, int length) throws IOException
   {
     if (in == null)
       throw new IOException("Reader has been closed");
-    
-    return in.read(buf, offset, length);
+    if (isDone)
+      return -1;
+
+    if(decoder != null){
+	int totalBytes = (int)((double)length * maxBytesPerChar);
+	byte[] bytes = new byte[totalBytes];
+
+	int remaining = 0;
+	if(byteBuffer != null)
+	{
+	    remaining = byteBuffer.remaining();
+	    byteBuffer.get(bytes, 0, remaining);
+	}
+	int read;
+	if(totalBytes - remaining > 0)
+	  {
+	    read = in.read(bytes, remaining, totalBytes - remaining);
+	    if(read == -1){
+	      read = remaining;
+	      isDone = true;
+	    } else
+	      read += remaining;
+	  } else 
+            read = remaining;
+	byteBuffer = ByteBuffer.wrap(bytes, 0, read);	
+	CharBuffer cb = CharBuffer.wrap(buf, offset, length);
+
+ 	if(hasSavedSurrogate){
+ 	    hasSavedSurrogate = false;
+ 	    cb.put(savedSurrogate);
+	    read++;
+ 	}
+
+	CoderResult cr = decoder.decode(byteBuffer, cb, isDone);
+	decoder.reset();
+
+	// 1 char remains which is the first half of a surrogate pair.
+	if(cr.isOverflow() && cb.hasRemaining()){
+	    CharBuffer overflowbuf = CharBuffer.allocate(2);
+	    cr = decoder.decode(byteBuffer, overflowbuf, isDone);
+	    overflowbuf.flip();
+	    cb.put(overflowbuf.get());
+ 	    savedSurrogate = overflowbuf.get();
+ 	    hasSavedSurrogate = true;	    
+	    isDone = false;
+	}
+
+	if(byteBuffer.hasRemaining()) {
+	    byteBuffer.compact();
+	    byteBuffer.flip();	  
+	    isDone = false;
+	} else
+	    byteBuffer = null;
+
+	return (read == 0)?-1:cb.position();
+    } else {
+	byte[] bytes = new byte[length];
+	int read = in.read(bytes);
+	for(int i=0;i<read;i++)
+          buf[offset+i] = (char)(bytes[i]&0xFF);
+	return read;
+    }
   }
 
   /**
-   * This method reads a single character of data from the stream.
+   * Reads an char from the input stream and returns it
+   * as an int in the range of 0-65535.  This method also will return -1 if
+   * the end of the stream has been reached.
+   * <p>
+   * This method will block until the char can be read.
    *
-   * @return The char read, as an int, or -1 if end of stream.
+   * @return The char read or -1 if end of stream
    *
    * @exception IOException If an error occurs
    */
   public int read() throws IOException
   {
-    if (in == null)
-      throw new IOException("Reader has been closed");
-    
-    return in.read();
+    char[] buf = new char[1];
+    int count = read(buf, 0, 1);
+    return count > 0 ? buf[0] : -1;
   }
 
-   /**
-    * Skips the specified number of chars in the stream.  It
-    * returns the actual number of chars skipped, which may be less than the
-    * requested amount.
-    *
-    * @param count The requested number of chars to skip
-    *
-    * @return The actual number of chars skipped.
-    *
-    * @exception IOException If an error occurs
-    */
+  /**
+   * Skips the specified number of chars in the stream.  It
+   * returns the actual number of chars skipped, which may be less than the
+   * requested amount.
+   *
+   * @param count The requested number of chars to skip
+   *
+   * @return The actual number of chars skipped.
+   *
+   * @exception IOException If an error occurs
+   */
    public long skip(long count) throws IOException
    {
      if (in == null)
        throw new IOException("Reader has been closed");
      
      return super.skip(count);
-  }
+   }
 }
Index: java/io/OutputStreamWriter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/OutputStreamWriter.java,v
retrieving revision 1.14
diff -u -r1.14 OutputStreamWriter.java
--- java/io/OutputStreamWriter.java	16 Feb 2005 11:18:37 -0000	1.14
+++ java/io/OutputStreamWriter.java	15 Apr 2005 15:54:46 -0000
@@ -38,8 +38,17 @@
 
 package java.io;
 
-import gnu.java.io.EncodingManager;
-import gnu.java.io.encode.Encoder;
+import gnu.java.nio.charset.EncodingHelper;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
 
 /**
  * This class writes characters to an output stream that is byte oriented
@@ -76,13 +85,26 @@
  */
 public class OutputStreamWriter extends Writer
 {
+  /**
+   * The output stream.
+   */
+  private OutputStream out;
 
   /**
-   * This is the byte-character encoder class that does the writing and
-   * translation of characters to bytes before writing to the underlying
-   * class.
+   * The charset encoder.
    */
-  private Encoder out;
+  private CharsetEncoder encoder;
+
+  /**
+   * java.io canonical name of the encoding.
+   */
+  private String encodingName;
+
+  /**
+   * Buffer output before character conversion as it has costly overhead.
+   */
+  private CharBuffer outputBuffer;
+  private final static int BUFFER_SIZE = 1024;
 
   /**
    * This method initializes a new instance of <code>OutputStreamWriter</code>
@@ -100,7 +122,54 @@
   public OutputStreamWriter (OutputStream out, String encoding_scheme) 
     throws UnsupportedEncodingException
   {
-    this.out = EncodingManager.getEncoder (out, encoding_scheme);
+    this.out = out;
+    try 
+    {
+      // Don't use NIO if avoidable
+      if(EncodingHelper.isISOLatin1(encoding_scheme))
+      {
+	encodingName = "ISO8859_1";
+	encoder = null;
+	return;
+      }
+
+      /*
+       * Workraround for encodings with a byte-order-mark.
+       * We only want to write it once per stream.
+       */
+      try {
+	if(encoding_scheme.equalsIgnoreCase("UnicodeBig") || 
+	   encoding_scheme.equalsIgnoreCase("UTF-16") ||
+	   encoding_scheme.equalsIgnoreCase("UTF16"))
+	{
+	  encoding_scheme = "UTF-16BE";	  
+	  out.write((byte)0xFE);
+	  out.write((byte)0xFF);
+	} else if(encoding_scheme.equalsIgnoreCase("UnicodeLittle")){
+	  encoding_scheme = "UTF-16LE";
+	  out.write((byte)0xFF);
+	  out.write((byte)0xFE);
+	}
+      } catch(IOException ioe){
+      }
+
+      outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+
+      Charset cs = EncodingHelper.getCharset(encoding_scheme);
+      if(cs == null)
+	throw new UnsupportedEncodingException("Encoding "+encoding_scheme+
+ 					       " unknown");
+      encoder = cs.newEncoder();
+      encodingName = EncodingHelper.getOldCanonical(cs.name());
+
+      encoder.onMalformedInput(CodingErrorAction.REPLACE);
+      encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+    } catch(RuntimeException e) {
+      // Default to ISO Latin-1, will happen if this is called, for instance,
+      //  before the NIO provider is loadable.
+      encoder = null; 
+      encodingName = "ISO8859_1";
+    }
   }
 
   /**
@@ -111,7 +180,24 @@
    */
   public OutputStreamWriter (OutputStream out)
   {
-    this.out = EncodingManager.getEncoder (out);
+    this.out = out;
+    outputBuffer = null;
+    try 
+    {
+      String encoding = System.getProperty("file.encoding");
+      Charset cs = Charset.forName(encoding);
+      encoder = cs.newEncoder();
+      encodingName =  EncodingHelper.getOldCanonical(cs.name());
+    } catch(RuntimeException e) {
+      encoder = null; 
+      encodingName = "ISO8859_1";
+    }
+    if(encoder != null)
+    {
+      encoder.onMalformedInput(CodingErrorAction.REPLACE);
+      encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+      outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+    }
   }
 
   /**
@@ -122,7 +208,11 @@
    */
   public void close () throws IOException
   {
+    if(out == null)
+      throw new IOException("Stream is closed.");
+    flush();
     out.close ();
+    out = null;
   }
 
   /**
@@ -134,7 +224,7 @@
    */
   public String getEncoding ()
   {
-    return out != null ? out.getSchemeName () : null;
+    return out != null ? encodingName : null;
   }
 
   /**
@@ -144,7 +234,18 @@
    */
   public void flush () throws IOException
   {
-    out.flush ();
+      if(out != null){	  
+	  if(outputBuffer != null){
+	      char[] buf = new char[outputBuffer.position()];
+	      if(buf.length > 0){
+		  outputBuffer.flip();
+		  outputBuffer.get(buf);
+		  writeConvert(buf, 0, buf.length);
+		  outputBuffer.clear();
+	      }
+	  }
+	  out.flush ();
+      }
   }
 
   /**
@@ -160,7 +261,64 @@
    */
   public void write (char[] buf, int offset, int count) throws IOException
   {
-    out.write (buf, offset, count);
+    if(out == null)
+      throw new IOException("Stream is closed.");
+    if(buf == null)
+      throw new IOException("Buffer is null.");
+
+    if(outputBuffer != null)
+	{
+	    if(count >= outputBuffer.remaining())
+		{
+		    int r = outputBuffer.remaining();
+		    outputBuffer.put(buf, offset, r);
+		    writeConvert(outputBuffer.array(), 0, BUFFER_SIZE);
+		    outputBuffer.clear();
+		    offset += r;
+		    count -= r;
+		    // if the remaining bytes is larger than the whole buffer, 
+		    // just don't buffer.
+		    if(count >= outputBuffer.remaining()){
+                      writeConvert(buf, offset, count);
+		      return;
+		    }
+		}
+	    outputBuffer.put(buf, offset, count);
+	} else writeConvert(buf, offset, count);
+  }
+
+ /**
+  * Converts and writes characters.
+  */
+  private void writeConvert (char[] buf, int offset, int count) 
+      throws IOException
+  {
+    if(encoder == null)
+    {
+      byte[] b = new byte[count];
+      for(int i=0;i<count;i++)
+	b[i] = (byte)((buf[offset+i] <= 0xFF)?buf[offset+i]:'?');
+      out.write(b);
+    } else {
+      try  {
+	ByteBuffer output = encoder.encode(CharBuffer.wrap(buf,offset,count));
+	encoder.reset();
+	if(output.hasArray())
+	  out.write(output.array());
+	else
+	  {
+	    byte[] outbytes = new byte[output.remaining()];
+	    output.get(outbytes);
+	    out.write(outbytes);
+	  }
+      } catch(IllegalStateException e) {
+	throw new IOException("Internal error.");
+      } catch(MalformedInputException e) {
+	throw new IOException("Invalid character sequence.");
+      } catch(CharacterCodingException e) {
+	throw new IOException("Unmappable character.");
+      }
+    }
   }
 
   /**
@@ -177,7 +335,10 @@
    */
   public void write (String str, int offset, int count) throws IOException
   {
-    out.write (str, offset, count);
+    if(str == null)
+      throw new IOException("String is null.");
+
+    write(str.toCharArray(), offset, count);
   }
 
   /**
@@ -189,8 +350,7 @@
    */
   public void write (int ch) throws IOException
   {
-    out.write (ch);
+    write(new char[]{ (char)ch }, 0, 1);
   }
-
 } // class OutputStreamWriter
 
Index: java/io/PrintStream.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/PrintStream.java,v
retrieving revision 1.23
diff -u -r1.23 PrintStream.java
--- java/io/PrintStream.java	16 Feb 2005 11:18:37 -0000	1.23
+++ java/io/PrintStream.java	15 Apr 2005 15:54:46 -0000
@@ -58,6 +58,19 @@
  */
 public class PrintStream extends FilterOutputStream
 {
+  /* Notice the implementation is quite similar to OutputStreamWriter.
+   * This leads to some minor duplication, because neither inherits
+   * from the other, and we want to maximize performance. */
+
+  // Line separator string.
+  private static final char[] line_separator
+    = System.getProperty("line.separator").toCharArray();
+
+  /**
+   *  Encoding name
+   */
+  private String encoding;
+
   /**
    * This boolean indicates whether or not an error has ever occurred
    * on this stream.
@@ -71,54 +84,6 @@
   private boolean auto_flush;
 
   /**
-   * The PrintWriter instance this object writes to
-   */
-  private PrintWriter pw;
-
-  /**
-   * Lets us know if the stream is closed
-   */
-  private boolean closed;
-
-  /**
-   * This class exists to forward the write calls from the PrintWriter back
-   * to us. This is required to make subclassing of PrintStream work
-   * correctly.
-   */
-  private class ForwardStream extends OutputStream
-  {
-    // This is package-private to avoid a trampoline constructor.
-    ForwardStream ()
-    {
-    }
-
-    public void close () throws IOException
-    {
-      out.close ();
-    }
-
-    public void flush () throws IOException
-    {
-      out.flush ();
-    }
-
-    public void write (byte[] b) throws IOException
-    {
-	PrintStream.this.write (b);
-    }
-
-    public void write (byte[] b, int off, int len) throws IOException
-    {
-	PrintStream.this.write (b, off, len);
-    }
-
-    public void write (int b) throws IOException
-    {
-	PrintStream.this.write (b);
-    }
-  }
-
-  /**
    * This method intializes a new <code>PrintStream</code> object to write
    * to the specified output sink.
    *
@@ -146,10 +111,15 @@
   {
     super (out);
 
-    // FIXME Instead of using PrintWriter and ForwardStream we
-    // should inline the character conversion (see libgcj's version
-    // of this class)
-    pw = new PrintWriter (new ForwardStream (), auto_flush);
+    try {
+	this.encoding = System.getProperty("file.encoding");
+    } catch (SecurityException e){
+	this.encoding = "ISO8859_1";
+    } catch (IllegalArgumentException e){
+	this.encoding = "ISO8859_1";
+    } catch (NullPointerException e){
+	this.encoding = "ISO8859_1";
+    }
     this.auto_flush = auto_flush;
   }
 
@@ -173,12 +143,8 @@
   {
     super (out);
 
-    // FIXME Instead of using PrintWriter and ForwardStream we
-    // should inline the character conversion (see libgcj's version
-    // of this class)
-    pw = new PrintWriter (
-	    new OutputStreamWriter (
-		new ForwardStream (), encoding), auto_flush);
+    new String(new byte[]{0}, encoding);    // check if encoding is supported
+    this.encoding = encoding;
     this.auto_flush = auto_flush;
   }
 
@@ -193,10 +159,8 @@
    */
   public boolean checkError ()
   {
-    if (!closed)
-      flush ();
-
-    return error_occurred | pw.checkError ();
+    flush ();
+    return error_occurred;
   }
 
   /**
@@ -213,8 +177,19 @@
    */
   public void close ()
   {
-    pw.close ();
-    closed = true;
+    try
+      {
+	flush();
+	out.close();
+      }
+    catch (InterruptedIOException iioe)
+      {
+	Thread.currentThread().interrupt();
+      }
+    catch (IOException e)
+      {
+	setError ();
+      }
   }
 
   /**
@@ -223,7 +198,73 @@
    */
   public void flush ()
   {
-    pw.flush();
+    try
+      {
+	out.flush();
+      }
+    catch (InterruptedIOException iioe)
+      {
+	Thread.currentThread().interrupt();
+      }
+    catch (IOException e)
+      {
+	setError ();
+      }
+  }
+
+  private synchronized void print (String str, boolean println)
+  {
+    try
+      {
+        writeChars(str, 0, str.length());
+	if (println)
+	  writeChars(line_separator, 0, line_separator.length);
+	if (auto_flush)
+	  flush();
+      }
+    catch (InterruptedIOException iioe)
+      {
+	Thread.currentThread().interrupt();
+      }
+    catch (IOException e)
+      {
+	setError ();
+      }
+  }
+
+  private synchronized void print (char[] chars, int pos, int len,
+				   boolean println)
+  {
+    try
+      {
+        writeChars(chars, pos, len);
+	if (println)
+	  writeChars(line_separator, 0, line_separator.length);
+	if (auto_flush)
+	  flush();
+      }
+    catch (InterruptedIOException iioe)
+      {
+	Thread.currentThread().interrupt();
+      }
+    catch (IOException e)
+      {
+	setError ();
+      }
+  }
+
+  private void writeChars(char[] buf, int offset, int count)
+    throws IOException
+  {
+      byte[] bytes = (new String(buf, offset, count)).getBytes(encoding);
+      out.write(bytes, 0, bytes.length);
+  }
+
+  private void writeChars(String str, int offset, int count)
+    throws IOException
+  {
+      byte[] bytes = str.substring(offset, offset+count).getBytes(encoding);
+      out.write(bytes, 0, bytes.length);
   }
 
   /**
@@ -235,7 +276,7 @@
    */
   public void print (boolean bool)
   {
-    print (String.valueOf (bool));
+    print(String.valueOf(bool), false);
   }
 
   /**
@@ -246,7 +287,7 @@
    */
   public void print (int inum)
   {
-    print (String.valueOf (inum));
+    print(String.valueOf(inum), false);
   }
 
   /**
@@ -257,7 +298,7 @@
    */
   public void print (long lnum)
   {
-    print (String.valueOf (lnum));
+    print(String.valueOf(lnum), false);
   }
 
   /**
@@ -268,7 +309,7 @@
    */
   public void print (float fnum)
   {
-    print (String.valueOf (fnum));
+    print(String.valueOf(fnum), false);
   }
 
   /**
@@ -279,7 +320,7 @@
    */
   public void print (double dnum)
   {
-    print (String.valueOf (dnum));
+    print(String.valueOf(dnum), false);
   }
 
   /**
@@ -291,9 +332,7 @@
    */
   public void print (Object obj)
   {
-    // Don't call pw directly.  Convert to String so we scan for newline
-    // characters on auto-flush;
-    print (String.valueOf (obj));
+    print(obj == null ? "null" : obj.toString(), false);
   }
 
   /**
@@ -304,10 +343,7 @@
    */
   public void print (String str)
   {
-    pw.print (str);
-
-    if (auto_flush)
-      flush ();
+    print(str == null ? "null" : str, false);
   }
 
   /**
@@ -316,9 +352,9 @@
    *
    * @param ch The <code>char</code> value to be printed
    */
-  public void print (char ch)
+  public synchronized void print (char ch)
   {
-    print (String.valueOf (ch));
+    print(new char[]{ch}, 0, 1, false);
   }
 
   /**
@@ -329,7 +365,7 @@
    */
   public void print (char[] charArray)
   {
-    pw.print (charArray);
+    print(charArray, 0, charArray.length, false);
   }
 
   /**
@@ -339,7 +375,7 @@
    */
   public void println ()
   {
-    pw.println();
+    print(line_separator, 0, line_separator.length, false);
   }
 
   /**
@@ -353,7 +389,7 @@
    */
   public void println (boolean bool)
   {
-    println (String.valueOf (bool));
+    print(String.valueOf(bool), true);
   }
 
   /**
@@ -366,7 +402,7 @@
    */
   public void println (int inum)
   {
-    println (String.valueOf (inum));
+    print(String.valueOf(inum), true);
   }
 
   /**
@@ -379,7 +415,7 @@
    */
   public void println (long lnum)
   {
-    println (String.valueOf (lnum));
+    print(String.valueOf(lnum), true);
   }
 
   /**
@@ -392,7 +428,7 @@
    */
   public void println (float fnum)
   {
-    println (String.valueOf (fnum));
+    print(String.valueOf(fnum), true);
   }
 
   /**
@@ -405,7 +441,7 @@
    */
   public void println (double dnum)
   {
-    println (String.valueOf (dnum));
+    print(String.valueOf(dnum), true);
   }
 
   /**
@@ -419,7 +455,7 @@
    */
   public void println (Object obj)
   {
-    println (String.valueOf (obj));
+    print(obj == null ? "null" : obj.toString(), true);
   }
 
   /**
@@ -432,7 +468,7 @@
    */
   public void println (String str)
   {
-    pw.println (str);
+    print (str == null ? "null" : str, true);
   }
 
   /**
@@ -443,9 +479,9 @@
    *
    * @param ch The <code>char</code> value to be printed
    */
-  public void println (char ch)
+  public synchronized void println (char ch)
   {
-    println (String.valueOf (ch));
+    print(new char[]{ch}, 0, 1, true);
   }
 
   /**
@@ -458,7 +494,7 @@
    */
   public void println (char[] charArray)
   {
-    pw.println (charArray);
+    print(charArray, 0, charArray.length, true);
   }
 
   /**
@@ -470,10 +506,6 @@
    */
   public void write (int oneByte)
   {
-    // We actually have to implement this method. Flush first so that
-    // things get written in the right order.
-    flush();
-
     try
       {
         out.write (oneByte & 0xff);
@@ -501,10 +533,6 @@
    */
   public void write (byte[] buffer, int offset, int len)
   {
-    // We actually have to implement this method too. Flush first so that
-    // things get written in the right order.
-    flush();
-
     try
       {
         out.write (buffer, offset, len);
@@ -522,3 +550,4 @@
       }
   }
 } // class PrintStream
+
Index: java/lang/String.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/String.java,v
retrieving revision 1.61
diff -u -r1.61 String.java
--- java/lang/String.java	19 Jan 2005 19:26:54 -0000	1.61
+++ java/lang/String.java	15 Apr 2005 15:54:46 -0000
@@ -39,9 +39,16 @@
 
 package java.lang;
 
-import gnu.java.io.EncodingManager;
 import gnu.java.lang.CharData;
-
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.util.Comparator;
@@ -105,14 +112,14 @@
    * Characters which make up the String.
    * Package access is granted for use by StringBuffer.
    */
-  final char[] value;
+  public final char[] value;
 
   /**
    * Holds the number of characters in value.  This number is generally
    * the same as value.length, but can be smaller because substrings and
    * StringBuffers can share arrays. Package visible for use by trusted code.
    */
-  final int count;
+  public final int count;
 
   /**
    * Caches the result of hashCode().  If this value is zero, the hashcode
@@ -125,7 +132,7 @@
    * substring()'s are common, the use of offset allows the operation
    * to perform in O(1). Package access is granted for use by StringBuffer.
    */
-  final int offset;
+  public final int offset;
 
   /**
    * An implementation for [EMAIL PROTECTED] CASE_INSENSITIVE_ORDER}.
@@ -304,7 +311,7 @@
    *
    * @param data byte array to copy
    * @param offset the offset to start at
-   * @param count the number of characters in the array to use
+   * @param count the number of bytes in the array to use
    * @param encoding the name of the encoding to use
    * @throws NullPointerException if data or encoding is null
    * @throws IndexOutOfBoundsException if offset or count is incorrect
@@ -318,11 +325,34 @@
   {
     if (offset < 0 || count < 0 || offset + count > data.length)
       throw new StringIndexOutOfBoundsException();
-    // XXX Consider using java.nio here.
-    value = EncodingManager.getDecoder(encoding)
-        .convertToChars(data, offset, count);
-    this.offset = 0;
-    this.count = value.length;
+    try 
+      {
+        CharsetDecoder csd = Charset.forName(encoding).newDecoder();
+	csd.onMalformedInput(CodingErrorAction.REPLACE);
+	csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
+ 	if(cbuf.hasArray())
+ 	  {
+ 	    value = cbuf.array();
+	    this.offset = cbuf.position();
+	    this.count = cbuf.remaining();
+ 	  } else {
+	    // Doubt this will happen. But just in case.
+	    value = new char[cbuf.remaining()];
+	    cbuf.get(value);
+	    this.offset = 0;
+	    this.count = value.length;
+	  }
+      } catch(CharacterCodingException e){
+	  throw new UnsupportedEncodingException("Encoding: "+encoding+
+						 " not found.");	  
+      } catch(IllegalCharsetNameException e){
+	  throw new UnsupportedEncodingException("Encoding: "+encoding+
+						 " not found.");
+      } catch(UnsupportedCharsetException e){
+	  throw new UnsupportedEncodingException("Encoding: "+encoding+
+						 " not found.");
+      }    
   }
 
   /**
@@ -359,7 +389,7 @@
    *
    * @param data byte array to copy
    * @param offset the offset to start at
-   * @param count the number of characters in the array to use
+   * @param count the number of bytes in the array to use
    * @throws NullPointerException if data is null
    * @throws IndexOutOfBoundsException if offset or count is incorrect
    * @throws Error if the decoding fails
@@ -370,11 +400,41 @@
   {
     if (offset < 0 || count < 0 || offset + count > data.length)
       throw new StringIndexOutOfBoundsException();
-    // XXX Consider using java.nio here.
-    value = EncodingManager.getDecoder()
-        .convertToChars(data, offset, count);
-    this.offset = 0;
-    this.count = value.length;
+    int o, c;
+    char[] v;
+    String encoding;
+    try 
+	{
+	  encoding = System.getProperty("file.encoding");
+	  CharsetDecoder csd = Charset.forName(encoding).newDecoder();
+	  csd.onMalformedInput(CodingErrorAction.REPLACE);
+	  csd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	  CharBuffer cbuf = csd.decode(ByteBuffer.wrap(data, offset, count));
+	  if(cbuf.hasArray())
+	    {
+              v = cbuf.array();
+	      o = cbuf.position();
+	      c = cbuf.remaining();
+	    } else {
+	      // Doubt this will happen. But just in case.
+	      v = new char[cbuf.remaining()];
+	      cbuf.get(v);
+	      o = 0;
+	      c = v.length;
+	    }
+	} catch(Exception ex){
+	    // If anything goes wrong (System property not set,
+	    // NIO provider not available, etc)
+	    // Default to the 'safe' encoding ISO8859_1
+	    v = new char[count];
+	    o = 0;
+	    c = count;
+	    for (int i=0;i<count;i++)
+	      v[i] = (char)data[offset+i];
+	}
+    this.value = v;
+    this.offset = o;
+    this.count = c;
   }
 
   /**
@@ -556,9 +616,30 @@
    */
   public byte[] getBytes(String enc) throws UnsupportedEncodingException
   {
-    // XXX Consider using java.nio here.
-    return EncodingManager.getEncoder(enc)
-        .convertToBytes(value, offset, count);
+    try 
+      {
+	CharsetEncoder cse = Charset.forName(enc).newEncoder();
+	cse.onMalformedInput(CodingErrorAction.REPLACE);
+	cse.onUnmappableCharacter(CodingErrorAction.REPLACE);
+	ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count));
+	if(bbuf.hasArray())
+	  return bbuf.array();
+
+	// Doubt this will happen. But just in case.
+	byte[] bytes = new byte[bbuf.remaining()];
+	bbuf.get(bytes);
+	return bytes;
+
+      } catch(IllegalCharsetNameException e){
+	  throw new UnsupportedEncodingException("Encoding: "+enc+
+						 " not found.");
+      } catch(UnsupportedCharsetException e){
+	  throw new UnsupportedEncodingException("Encoding: "+enc+
+						 " not found.");
+      } catch(CharacterCodingException e){
+	  // XXX - Ignore coding exceptions? They shouldn't really happen.
+	  return null;
+      }	  
   }
 
   /**
@@ -572,10 +653,19 @@
    * @since 1.1
    */
   public byte[] getBytes()
-  {
-    // XXX Consider using java.nio here.
-    return EncodingManager.getEncoder()
-        .convertToBytes(value, offset, count);
+  { 
+      try 
+	  {
+	      return getBytes(System.getProperty("file.encoding"));
+	  } catch(Exception e) {
+	      // XXX - Throw an error here? 
+	      // For now, default to the 'safe' encoding.
+	      byte[] bytes = new byte[count];
+	      for(int i=0;i<count;i++)
+		  bytes[i] = (byte)((value[offset+i] <= 0xFF)?
+				    value[offset+i]:'?');
+	      return bytes;
+      }
   }
 
   /**
_______________________________________________
Classpath-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/classpath-patches

Reply via email to