1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.nio.CharBuffer;
  29 import java.nio.charset.Charset;
  30 import java.nio.charset.CharsetEncoder;
  31 import sun.nio.cs.StreamEncoder;
  32 
  33 
  34 /**
  35  * An OutputStreamWriter is a bridge from character streams to byte streams:
  36  * Characters written to it are encoded into bytes using a specified {@link
  37  * java.nio.charset.Charset charset}.  The charset that it uses
  38  * may be specified by name or may be given explicitly, or the platform's
  39  * default charset may be accepted.
  40  *
  41  * <p> Each invocation of a write() method causes the encoding converter to be
  42  * invoked on the given character(s).  The resulting bytes are accumulated in a
  43  * buffer before being written to the underlying output stream.  The size of
  44  * this buffer may be specified, but by default it is large enough for most
  45  * purposes.  Note that the characters passed to the write() methods are not
  46  * buffered.
  47  *
  48  * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
  49  * BufferedWriter so as to avoid frequent converter invocations.  For example:
  50  *
  51  * <pre>
  52  * Writer out
  53  *   = new BufferedWriter(new OutputStreamWriter(System.out));
  54  * </pre>
  55  *
  56  * <p> A <i>surrogate pair</i> is a character represented by a sequence of two
  57  * {@code char} values: A <i>high</i> surrogate in the range '\uD800' to
  58  * '\uDBFF' followed by a <i>low</i> surrogate in the range '\uDC00' to
  59  * '\uDFFF'.
  60  *
  61  * <p> A <i>malformed surrogate element</i> is a high surrogate that is not
  62  * followed by a low surrogate or a low surrogate that is not preceded by a
  63  * high surrogate.
  64  *
  65  * <p> This class always replaces malformed surrogate elements and unmappable
  66  * character sequences with the charset's default <i>substitution sequence</i>.
  67  * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
  68  * control over the encoding process is required.
  69  *
  70  * @see BufferedWriter
  71  * @see OutputStream
  72  * @see java.nio.charset.Charset
  73  *
  74  * @author      Mark Reinhold
  75  * @since       1.1
  76  */
  77 
  78 public class OutputStreamWriter extends Writer {
  79 
  80     private final StreamEncoder se;
  81 
  82     /**
  83      * Creates an OutputStreamWriter that uses the named charset.
  84      *
  85      * @param  out
  86      *         An OutputStream
  87      *
  88      * @param  charsetName
  89      *         The name of a supported
  90      *         {@link java.nio.charset.Charset charset}
  91      *
  92      * @exception  UnsupportedEncodingException
  93      *             If the named encoding is not supported
  94      */
  95     public OutputStreamWriter(OutputStream out, String charsetName)
  96         throws UnsupportedEncodingException
  97     {
  98         super(out);
  99         if (charsetName == null)
 100             throw new NullPointerException("charsetName");
 101         se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
 102     }
 103 
 104     /**
 105      * Creates an OutputStreamWriter that uses the default character encoding.
 106      *
 107      * @param  out  An OutputStream
 108      */
 109     public OutputStreamWriter(OutputStream out) {
 110         super(out);
 111         try {
 112             se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
 113         } catch (UnsupportedEncodingException e) {
 114             throw new Error(e);
 115         }
 116     }
 117 
 118     /**
 119      * Creates an OutputStreamWriter that uses the given charset.
 120      *
 121      * @param  out
 122      *         An OutputStream
 123      *
 124      * @param  cs
 125      *         A charset
 126      *
 127      * @since 1.4
 128      * @spec JSR-51
 129      */
 130     public OutputStreamWriter(OutputStream out, Charset cs) {
 131         super(out);
 132         if (cs == null)
 133             throw new NullPointerException("charset");
 134         se = StreamEncoder.forOutputStreamWriter(out, this, cs);
 135     }
 136 
 137     /**
 138      * Creates an OutputStreamWriter that uses the given charset encoder.
 139      *
 140      * @param  out
 141      *         An OutputStream
 142      *
 143      * @param  enc
 144      *         A charset encoder
 145      *
 146      * @since 1.4
 147      * @spec JSR-51
 148      */
 149     public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
 150         super(out);
 151         if (enc == null)
 152             throw new NullPointerException("charset encoder");
 153         se = StreamEncoder.forOutputStreamWriter(out, this, enc);
 154     }
 155 
 156     /**
 157      * Returns the name of the character encoding being used by this stream.
 158      *
 159      * <p> If the encoding has an historical name then that name is returned;
 160      * otherwise the encoding's canonical name is returned.
 161      *
 162      * <p> If this instance was created with the {@link
 163      * #OutputStreamWriter(OutputStream, String)} constructor then the returned
 164      * name, being unique for the encoding, may differ from the name passed to
 165      * the constructor.  This method may return {@code null} if the stream has
 166      * been closed. </p>
 167      *
 168      * @return The historical name of this encoding, or possibly
 169      *         <code>null</code> if the stream has been closed
 170      *
 171      * @see java.nio.charset.Charset
 172      *
 173      * @revised 1.4
 174      * @spec JSR-51
 175      */
 176     public String getEncoding() {
 177         return se.getEncoding();
 178     }
 179 
 180     /**
 181      * Flushes the output buffer to the underlying byte stream, without flushing
 182      * the byte stream itself.  This method is non-private only so that it may
 183      * be invoked by PrintStream.
 184      */
 185     void flushBuffer() throws IOException {
 186         se.flushBuffer();
 187     }
 188 
 189     /**
 190      * Writes a single character.
 191      *
 192      * @exception  IOException  If an I/O error occurs
 193      */
 194     public void write(int c) throws IOException {
 195         se.write(c);
 196     }
 197 
 198     /**
 199      * Writes a portion of an array of characters.
 200      *
 201      * @param  cbuf  Buffer of characters
 202      * @param  off   Offset from which to start writing characters
 203      * @param  len   Number of characters to write
 204      *
 205      * @throws  IndexOutOfBoundsException
 206      *          If {@code off} is negative, or {@code len} is negative,
 207      *          or {@code off + len} is negative or greater than the length
 208      *          of the given array
 209      *
 210      * @throws  IOException  If an I/O error occurs
 211      */
 212     public void write(char cbuf[], int off, int len) throws IOException {
 213         se.write(cbuf, off, len);
 214     }
 215 
 216     /**
 217      * Writes a portion of a string.
 218      *
 219      * @param  str  A String
 220      * @param  off  Offset from which to start writing characters
 221      * @param  len  Number of characters to write
 222      *
 223      * @throws  IndexOutOfBoundsException
 224      *          If {@code off} is negative, or {@code len} is negative,
 225      *          or {@code off + len} is negative or greater than the length
 226      *          of the given string
 227      *
 228      * @throws  IOException  If an I/O error occurs
 229      */
 230     public void write(String str, int off, int len) throws IOException {
 231         se.write(str, off, len);
 232     }
 233 
 234     @Override
 235     public Writer append(CharSequence csq, int start, int end) throws IOException {
 236         if (csq == null) csq = "null";
 237         write(csq.subSequence(start, end).toString());
 238         return this;
 239     }
 240 
 241     @Override
 242     public Writer append(CharSequence csq) throws IOException {
 243         if (csq instanceof CharBuffer) {
 244             se.write((CharBuffer) csq);
 245         } else {
 246             se.write(String.valueOf(csq));
 247         }
 248         return this;
 249     }
 250 
 251     /**
 252      * Flushes the stream.
 253      *
 254      * @exception  IOException  If an I/O error occurs
 255      */
 256     public void flush() throws IOException {
 257         se.flush();
 258     }
 259 
 260     public void close() throws IOException {
 261         se.close();
 262     }
 263 }