151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.nio.cs;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.*;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.*;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.channels.*;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.charset.*;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class StreamEncoder extends Writer
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski{
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private volatile boolean isOpen = true;
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void ensureOpen() throws IOException {
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!isOpen)
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Stream closed");
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Factories for java.io.OutputStreamWriter
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamEncoder forOutputStreamWriter(OutputStream out,
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      Object lock,
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      String charsetName)
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws UnsupportedEncodingException
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String csn = charsetName;
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (csn == null)
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            csn = Charset.defaultCharset().name();
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (Charset.isSupported(csn))
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return new StreamEncoder(out, lock, Charset.forName(csn));
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IllegalCharsetNameException x) { }
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throw new UnsupportedEncodingException (csn);
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamEncoder forOutputStreamWriter(OutputStream out,
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      Object lock,
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      Charset cs)
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamEncoder(out, lock, cs);
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamEncoder forOutputStreamWriter(OutputStream out,
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      Object lock,
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                      CharsetEncoder enc)
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamEncoder(out, lock, enc);
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Factory for java.nio.channels.Channels.newWriter
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamEncoder forEncoder(WritableByteChannel ch,
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                           CharsetEncoder enc,
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                           int minBufferCap)
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamEncoder(ch, enc, minBufferCap);
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // -- Public methods corresponding to those in OutputStreamWriter --
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // All synchronization and state/argument checking is done in these public
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // methods; the concrete stream-encoder subclasses defined below need not
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // do any such checking.
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getEncoding() {
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isOpen())
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return encodingName();
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void flushBuffer() throws IOException {
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (isOpen())
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                implFlushBuffer();
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Stream closed");
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void write(int c) throws IOException {
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char cbuf[] = new char[1];
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cbuf[0] = (char) c;
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        write(cbuf, 0, 1);
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void write(char cbuf[], int off, int len) throws IOException {
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ensureOpen();
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ((off + len) > cbuf.length) || ((off + len) < 0)) {
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IndexOutOfBoundsException();
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else if (len == 0) {
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return;
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            implWrite(cbuf, off, len);
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void write(String str, int off, int len) throws IOException {
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /* Check the len before creating a char buffer */
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len < 0)
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IndexOutOfBoundsException();
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char cbuf[] = new char[len];
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        str.getChars(off, off + len, cbuf, 0);
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        write(cbuf, 0, len);
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void flush() throws IOException {
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ensureOpen();
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            implFlush();
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void close() throws IOException {
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!isOpen)
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return;
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            implClose();
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            isOpen = false;
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean isOpen() {
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return isOpen;
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // -- Charset-based stream encoder impl --
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Charset cs;
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private CharsetEncoder encoder;
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ByteBuffer bb;
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Exactly one of these is non-null
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final OutputStream out;
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private WritableByteChannel ch;
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Leftover first char in a surrogate pair
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean haveLeftoverChar = false;
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private char leftoverChar;
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private CharBuffer lcb = null;
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private StreamEncoder(OutputStream out, Object lock, Charset cs) {
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this(out, lock,
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         cs.newEncoder()
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         .onMalformedInput(CodingErrorAction.REPLACE)
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         .onUnmappableCharacter(CodingErrorAction.REPLACE));
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        super(lock);
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.out = out;
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.ch = null;
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.cs = enc.charset();
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.encoder = enc;
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // This path disabled until direct buffers are faster
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (false && out instanceof FileOutputStream) {
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ch = ((FileOutputStream)out).getChannel();
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch != null)
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (ch == null) {
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.out = null;
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.ch = ch;
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.cs = enc.charset();
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.encoder = enc;
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.bb = ByteBuffer.allocate(mbc < 0
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  ? DEFAULT_BYTE_BUFFER_SIZE
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  : mbc);
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void writeBytes() throws IOException {
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.flip();
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int lim = bb.limit();
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int pos = bb.position();
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert (pos <= lim);
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int rem = (pos <= lim ? lim - pos : 0);
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (rem > 0) {
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch != null) {
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (ch.write(bb) != rem)
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                assert false : rem;
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            out.write(bb.array(), bb.arrayOffset() + pos, rem);
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.clear();
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws IOException
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!haveLeftoverChar && !endOfInput)
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return;
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (lcb == null)
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lcb = CharBuffer.allocate(2);
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lcb.clear();
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (haveLeftoverChar)
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lcb.put(leftoverChar);
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((cb != null) && cb.hasRemaining())
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lcb.put(cb.get());
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        lcb.flip();
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (lcb.hasRemaining() || endOfInput) {
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            CoderResult cr = encoder.encode(lcb, bb, endOfInput);
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (cr.isUnderflow()) {
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (lcb.hasRemaining()) {
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    leftoverChar = lcb.get();
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (cb != null && cb.hasRemaining())
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        flushLeftoverChar(cb, endOfInput);
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return;
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (cr.isOverflow()) {
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                assert bb.position() > 0;
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                writeBytes();
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            cr.throwException();
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        haveLeftoverChar = false;
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void implWrite(char cbuf[], int off, int len)
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws IOException
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (haveLeftoverChar)
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        flushLeftoverChar(cb, false);
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (cb.hasRemaining()) {
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CoderResult cr = encoder.encode(cb, bb, false);
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cr.isUnderflow()) {
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           assert (cb.remaining() <= 1) : cb.remaining();
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           if (cb.remaining() == 1) {
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                haveLeftoverChar = true;
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                leftoverChar = cb.get();
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cr.isOverflow()) {
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert bb.position() > 0;
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            writeBytes();
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            continue;
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cr.throwException();
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void implFlushBuffer() throws IOException {
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (bb.position() > 0)
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        writeBytes();
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void implFlush() throws IOException {
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        implFlushBuffer();
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (out != null)
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        out.flush();
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void implClose() throws IOException {
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        flushLeftoverChar(null, true);
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (;;) {
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                CoderResult cr = encoder.flush(bb);
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (cr.isUnderflow())
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (cr.isOverflow()) {
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    assert bb.position() > 0;
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    writeBytes();
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    continue;
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                cr.throwException();
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (bb.position() > 0)
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                writeBytes();
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (ch != null)
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ch.close();
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                out.close();
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IOException x) {
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            encoder.reset();
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw x;
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    String encodingName() {
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ((cs instanceof HistoricallyNamedCharset)
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ? ((HistoricallyNamedCharset)cs).historicalName()
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            : cs.name());
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
333