Save This Page
Home » openjdk-7 » sun » nio » cs » [javadoc | source]
    1   /*
    2    * Copyright (c) 2001, 2005, 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   /*
   27    */
   28   
   29   package sun.nio.cs;
   30   
   31   import java.io;
   32   import java.nio;
   33   import java.nio.channels;
   34   import java.nio.charset;
   35   
   36   public class StreamEncoder extends Writer
   37   {
   38   
   39       private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
   40   
   41       private volatile boolean isOpen = true;
   42   
   43       private void ensureOpen() throws IOException {
   44           if (!isOpen)
   45               throw new IOException("Stream closed");
   46       }
   47   
   48       // Factories for java.io.OutputStreamWriter
   49       public static StreamEncoder forOutputStreamWriter(OutputStream out,
   50                                                         Object lock,
   51                                                         String charsetName)
   52           throws UnsupportedEncodingException
   53       {
   54           String csn = charsetName;
   55           if (csn == null)
   56               csn = Charset.defaultCharset().name();
   57           try {
   58               if (Charset.isSupported(csn))
   59                   return new StreamEncoder(out, lock, Charset.forName(csn));
   60           } catch (IllegalCharsetNameException x) { }
   61           throw new UnsupportedEncodingException (csn);
   62       }
   63   
   64       public static StreamEncoder forOutputStreamWriter(OutputStream out,
   65                                                         Object lock,
   66                                                         Charset cs)
   67       {
   68           return new StreamEncoder(out, lock, cs);
   69       }
   70   
   71       public static StreamEncoder forOutputStreamWriter(OutputStream out,
   72                                                         Object lock,
   73                                                         CharsetEncoder enc)
   74       {
   75           return new StreamEncoder(out, lock, enc);
   76       }
   77   
   78   
   79       // Factory for java.nio.channels.Channels.newWriter
   80   
   81       public static StreamEncoder forEncoder(WritableByteChannel ch,
   82                                              CharsetEncoder enc,
   83                                              int minBufferCap)
   84       {
   85           return new StreamEncoder(ch, enc, minBufferCap);
   86       }
   87   
   88   
   89       // -- Public methods corresponding to those in OutputStreamWriter --
   90   
   91       // All synchronization and state/argument checking is done in these public
   92       // methods; the concrete stream-encoder subclasses defined below need not
   93       // do any such checking.
   94   
   95       public String getEncoding() {
   96           if (isOpen())
   97               return encodingName();
   98           return null;
   99       }
  100   
  101       public void flushBuffer() throws IOException {
  102           synchronized (lock) {
  103               if (isOpen())
  104                   implFlushBuffer();
  105               else
  106                   throw new IOException("Stream closed");
  107           }
  108       }
  109   
  110       public void write(int c) throws IOException {
  111           char cbuf[] = new char[1];
  112           cbuf[0] = (char) c;
  113           write(cbuf, 0, 1);
  114       }
  115   
  116       public void write(char cbuf[], int off, int len) throws IOException {
  117           synchronized (lock) {
  118               ensureOpen();
  119               if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  120                   ((off + len) > cbuf.length) || ((off + len) < 0)) {
  121                   throw new IndexOutOfBoundsException();
  122               } else if (len == 0) {
  123                   return;
  124               }
  125               implWrite(cbuf, off, len);
  126           }
  127       }
  128   
  129       public void write(String str, int off, int len) throws IOException {
  130           /* Check the len before creating a char buffer */
  131           if (len < 0)
  132               throw new IndexOutOfBoundsException();
  133           char cbuf[] = new char[len];
  134           str.getChars(off, off + len, cbuf, 0);
  135           write(cbuf, 0, len);
  136       }
  137   
  138       public void flush() throws IOException {
  139           synchronized (lock) {
  140               ensureOpen();
  141               implFlush();
  142           }
  143       }
  144   
  145       public void close() throws IOException {
  146           synchronized (lock) {
  147               if (!isOpen)
  148                   return;
  149               implClose();
  150               isOpen = false;
  151           }
  152       }
  153   
  154       private boolean isOpen() {
  155           return isOpen;
  156       }
  157   
  158   
  159       // -- Charset-based stream encoder impl --
  160   
  161       private Charset cs;
  162       private CharsetEncoder encoder;
  163       private ByteBuffer bb;
  164   
  165       // Exactly one of these is non-null
  166       private final OutputStream out;
  167       private WritableByteChannel ch;
  168   
  169       // Leftover first char in a surrogate pair
  170       private boolean haveLeftoverChar = false;
  171       private char leftoverChar;
  172       private CharBuffer lcb = null;
  173   
  174       private StreamEncoder(OutputStream out, Object lock, Charset cs) {
  175           this(out, lock,
  176            cs.newEncoder()
  177            .onMalformedInput(CodingErrorAction.REPLACE)
  178            .onUnmappableCharacter(CodingErrorAction.REPLACE));
  179       }
  180   
  181       private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
  182           super(lock);
  183           this.out = out;
  184           this.ch = null;
  185           this.cs = enc.charset();
  186           this.encoder = enc;
  187   
  188           // This path disabled until direct buffers are faster
  189           if (false && out instanceof FileOutputStream) {
  190                   ch = ((FileOutputStream)out).getChannel();
  191           if (ch != null)
  192                       bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
  193           }
  194               if (ch == null) {
  195           bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
  196           }
  197       }
  198   
  199       private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
  200           this.out = null;
  201           this.ch = ch;
  202           this.cs = enc.charset();
  203           this.encoder = enc;
  204           this.bb = ByteBuffer.allocate(mbc < 0
  205                                     ? DEFAULT_BYTE_BUFFER_SIZE
  206                                     : mbc);
  207       }
  208   
  209       private void writeBytes() throws IOException {
  210           bb.flip();
  211           int lim = bb.limit();
  212           int pos = bb.position();
  213           assert (pos <= lim);
  214           int rem = (pos <= lim ? lim - pos : 0);
  215   
  216               if (rem > 0) {
  217           if (ch != null) {
  218               if (ch.write(bb) != rem)
  219                   assert false : rem;
  220           } else {
  221               out.write(bb.array(), bb.arrayOffset() + pos, rem);
  222           }
  223           }
  224           bb.clear();
  225           }
  226   
  227       private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
  228           throws IOException
  229       {
  230           if (!haveLeftoverChar && !endOfInput)
  231               return;
  232           if (lcb == null)
  233               lcb = CharBuffer.allocate(2);
  234           else
  235               lcb.clear();
  236           if (haveLeftoverChar)
  237               lcb.put(leftoverChar);
  238           if ((cb != null) && cb.hasRemaining())
  239               lcb.put(cb.get());
  240           lcb.flip();
  241           while (lcb.hasRemaining() || endOfInput) {
  242               CoderResult cr = encoder.encode(lcb, bb, endOfInput);
  243               if (cr.isUnderflow()) {
  244                   if (lcb.hasRemaining()) {
  245                       leftoverChar = lcb.get();
  246                       if (cb != null && cb.hasRemaining())
  247                           flushLeftoverChar(cb, endOfInput);
  248                       return;
  249                   }
  250                   break;
  251               }
  252               if (cr.isOverflow()) {
  253                   assert bb.position() > 0;
  254                   writeBytes();
  255                   continue;
  256               }
  257               cr.throwException();
  258           }
  259           haveLeftoverChar = false;
  260       }
  261   
  262       void implWrite(char cbuf[], int off, int len)
  263           throws IOException
  264       {
  265           CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
  266   
  267           if (haveLeftoverChar)
  268           flushLeftoverChar(cb, false);
  269   
  270           while (cb.hasRemaining()) {
  271           CoderResult cr = encoder.encode(cb, bb, false);
  272           if (cr.isUnderflow()) {
  273              assert (cb.remaining() <= 1) : cb.remaining();
  274              if (cb.remaining() == 1) {
  275                   haveLeftoverChar = true;
  276                   leftoverChar = cb.get();
  277               }
  278               break;
  279           }
  280           if (cr.isOverflow()) {
  281               assert bb.position() > 0;
  282               writeBytes();
  283               continue;
  284           }
  285           cr.throwException();
  286           }
  287       }
  288   
  289       void implFlushBuffer() throws IOException {
  290           if (bb.position() > 0)
  291           writeBytes();
  292       }
  293   
  294       void implFlush() throws IOException {
  295           implFlushBuffer();
  296           if (out != null)
  297           out.flush();
  298       }
  299   
  300       void implClose() throws IOException {
  301           flushLeftoverChar(null, true);
  302           try {
  303               for (;;) {
  304                   CoderResult cr = encoder.flush(bb);
  305                   if (cr.isUnderflow())
  306                       break;
  307                   if (cr.isOverflow()) {
  308                       assert bb.position() > 0;
  309                       writeBytes();
  310                       continue;
  311                   }
  312                   cr.throwException();
  313               }
  314   
  315               if (bb.position() > 0)
  316                   writeBytes();
  317               if (ch != null)
  318                   ch.close();
  319               else
  320                   out.close();
  321           } catch (IOException x) {
  322               encoder.reset();
  323               throw x;
  324           }
  325       }
  326   
  327       String encodingName() {
  328           return ((cs instanceof HistoricallyNamedCharset)
  329               ? ((HistoricallyNamedCharset)cs).historicalName()
  330               : cs.name());
  331       }
  332   }

Save This Page
Home » openjdk-7 » sun » nio » cs » [javadoc | source]