151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
22c87ad3a45cecf9e344487cad1abfdebe79f2c7cNarayan Kamath * Copyright (C) 2014 The Android Open Source Project
31a91deb15b7cc44851ebe9efbd935fc92b65a8dbShubham Ajmera * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.nio.cs;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.*;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.*;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.channels.*;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.charset.*;
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class StreamDecoder extends Reader
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski{
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int MIN_BYTE_BUFFER_SIZE = 32;
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private volatile boolean isOpen = true;
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void ensureOpen() throws IOException {
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!isOpen)
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IOException("Stream closed");
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // In order to handle surrogates properly we must never try to produce
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // fewer than two characters at a time.  If we're only asked to return one
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // character then the other is saved here to be returned later.
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    //
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean haveLeftoverChar = false;
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private char leftoverChar;
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
578bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath    private boolean needsFlush = false;
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Factories for java.io.InputStreamReader
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamDecoder forInputStreamReader(InputStream in,
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     Object lock,
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     String charsetName)
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws UnsupportedEncodingException
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String csn = charsetName;
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (csn == null)
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            csn = Charset.defaultCharset().name();
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (Charset.isSupported(csn))
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return new StreamDecoder(in, lock, Charset.forName(csn));
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IllegalCharsetNameException x) { }
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throw new UnsupportedEncodingException (csn);
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamDecoder forInputStreamReader(InputStream in,
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     Object lock,
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     Charset cs)
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamDecoder(in, lock, cs);
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamDecoder forInputStreamReader(InputStream in,
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     Object lock,
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                     CharsetDecoder dec)
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamDecoder(in, lock, dec);
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Factory for java.nio.channels.Channels.newReader
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static StreamDecoder forDecoder(ReadableByteChannel ch,
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                           CharsetDecoder dec,
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                           int minBufferCap)
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new StreamDecoder(ch, dec, minBufferCap);
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // -- Public methods corresponding to those in InputStreamReader --
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // All synchronization and state/argument checking is done in these public
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // methods; the concrete stream-decoder subclasses defined below need not
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // do any such checking.
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getEncoding() {
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isOpen())
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return encodingName();
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int read() throws IOException {
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return read0();
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
1171a91deb15b7cc44851ebe9efbd935fc92b65a8dbShubham Ajmera    @SuppressWarnings("fallthrough")
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int read0() throws IOException {
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Return the leftover char, if there is one
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (haveLeftoverChar) {
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                haveLeftoverChar = false;
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return leftoverChar;
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Convert more bytes
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char cb[] = new char[2];
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int n = read(cb, 0, 2);
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            switch (n) {
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case -1:
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return -1;
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case 2:
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                leftoverChar = cb[1];
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                haveLeftoverChar = true;
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // FALL THROUGH
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case 1:
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return cb[0];
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            default:
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                assert false : n;
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return -1;
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int read(char cbuf[], int offset, int length) throws IOException {
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int off = offset;
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int len = length;
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ensureOpen();
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ((off + len) > cbuf.length) || ((off + len) < 0)) {
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IndexOutOfBoundsException();
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (len == 0)
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return 0;
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int n = 0;
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (haveLeftoverChar) {
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // Copy the leftover char into the buffer
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                cbuf[off] = leftoverChar;
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                off++; len--;
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                haveLeftoverChar = false;
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                n = 1;
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((len == 0) || !implReady())
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Return now if this is all we can produce w/o blocking
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return n;
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (len == 1) {
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // Treat single-character array reads just like read()
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int c = read0();
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (c == -1)
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return (n == 0) ? -1 : n;
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                cbuf[off] = (char)c;
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return n + 1;
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return n + implRead(cbuf, off, off + len);
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean ready() throws IOException {
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ensureOpen();
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return haveLeftoverChar || implReady();
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void close() throws IOException {
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (lock) {
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!isOpen)
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return;
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            implClose();
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            isOpen = false;
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean isOpen() {
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return isOpen;
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // -- Charset-based stream decoder impl --
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // In the early stages of the build we haven't yet built the NIO native
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // code, so guard against that by catching the first UnsatisfiedLinkError
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // and setting this flag so that later attempts fail quickly.
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    //
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static volatile boolean channelsAvailable = true;
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static FileChannel getChannel(FileInputStream in) {
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!channelsAvailable)
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return in.getChannel();
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (UnsatisfiedLinkError x) {
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            channelsAvailable = false;
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Charset cs;
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private CharsetDecoder decoder;
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ByteBuffer bb;
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Exactly one of these is non-null
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private InputStream in;
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ReadableByteChannel ch;
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    StreamDecoder(InputStream in, Object lock, Charset cs) {
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this(in, lock,
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         cs.newDecoder()
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         .onMalformedInput(CodingErrorAction.REPLACE)
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         .onUnmappableCharacter(CodingErrorAction.REPLACE));
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        super(lock);
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.cs = dec.charset();
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.decoder = dec;
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // This path disabled until direct buffers are faster
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (false && in instanceof FileInputStream) {
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ch = getChannel((FileInputStream)in);
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch != null)
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch == null) {
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.in = in;
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.ch = null;
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.flip();                      // So that bb is initially empty
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    StreamDecoder(ReadableByteChannel ch, CharsetDecoder dec, int mbc) {
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.in = null;
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.ch = ch;
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.decoder = dec;
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.cs = dec.charset();
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.bb = ByteBuffer.allocate(mbc < 0
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  ? DEFAULT_BYTE_BUFFER_SIZE
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                  : (mbc < MIN_BYTE_BUFFER_SIZE
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                     ? MIN_BYTE_BUFFER_SIZE
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                     : mbc));
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.flip();
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int readBytes() throws IOException {
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.compact();
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch != null) {
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Read from the channel
2766975f84c2ed72e1e26d20190b6f318718c849008Tobias Thierer            // Android-changed: Use ChannelInputStream.read to make sure we throw
2770319995669db3d4cd8fcb73e01f9beaa1106bf2fNarayan Kamath            // the right exception for non-blocking channels.
2780319995669db3d4cd8fcb73e01f9beaa1106bf2fNarayan Kamath            int n = sun.nio.ch.ChannelInputStream.read(ch, bb);
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (n < 0)
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return n;
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Read from the input stream, and then update the buffer
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int lim = bb.limit();
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int pos = bb.position();
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert (pos <= lim);
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int rem = (pos <= lim ? lim - pos : 0);
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert rem > 0;
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (n < 0)
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return n;
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (n == 0)
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IOException("Underlying input stream returned zero bytes");
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert (n <= rem) : "n = " + n + ", rem = " + rem;
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bb.position(pos + n);
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } finally {
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Flip even when an IOException is thrown,
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // otherwise the stream will stutter
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        bb.flip();
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int rem = bb.remaining();
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert (rem != 0) : rem;
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return rem;
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int implRead(char[] cbuf, int off, int end) throws IOException {
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // In order to handle surrogate pairs, this method requires that
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // the invoker attempt to read at least two characters.  Saving the
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // extra character, if any, at a higher level is easier than trying
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // to deal with it here.
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert (end - off > 1);
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cb.position() != 0)
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Ensure that cb[0] == cbuf[off]
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cb = cb.slice();
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3206975f84c2ed72e1e26d20190b6f318718c849008Tobias Thierer        // Android-changed: Support flushing the buffer properly.
3218bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath        if (needsFlush) {
3228bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            CoderResult cr = decoder.flush(cb);
3238bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            if (cr.isOverflow()) {
3248bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                // We've overflowed, we'll have to come back round and ask for more data.
3258bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                return cb.position();
3268bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            }
3278bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath
3288bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            // By definition, we're at the end of the stream here.
3298bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            if (cr.isUnderflow()) {
3308bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                if (cb.position() == 0) {
3318bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                    return -1;
3328bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                }
3338bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath
3348bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                return cb.position();
3358bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            }
3368bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath
3378bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            cr.throwException();
3388bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            // Unreachable.
3398bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath        }
3408bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean eof = false;
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (;;) {
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CoderResult cr = decoder.decode(bb, cb, eof);
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cr.isUnderflow()) {
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (eof)
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!cb.hasRemaining())
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((cb.position() > 0) && !inReady())
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;          // Block at most once
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int n = readBytes();
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (n < 0) {
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                eof = true;
3546975f84c2ed72e1e26d20190b6f318718c849008Tobias Thierer                // Android-changed: We want to go 'round the loop one more time
3558bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                // with "eof = true". We also don't want to reset the decoder here
3568bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                // because we might potentially need to flush it later.
3578bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                //
3588bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                // if ((cb.position() == 0) && (!bb.hasRemaining()))
3598bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                //     break;
3608bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                //  decoder.reset();
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            continue;
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cr.isOverflow()) {
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert cb.position() > 0;
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cr.throwException();
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (eof) {
3728bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            CoderResult cr = decoder.flush(cb);
3738bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            if (cr.isOverflow()) {
3748bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                needsFlush = true;
3758bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                return cb.position();
3768bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            }
3778bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath
3788bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            decoder.reset();
3798bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            if (!cr.isUnderflow()) {
3808bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath                cr.throwException();
3818bc68f626c8c28fa3bc2a277b52aed3c80ede701Narayan Kamath            }
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (cb.position() == 0) {
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (eof)
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return -1;
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert false;
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return cb.position();
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    String encodingName() {
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return ((cs instanceof HistoricallyNamedCharset)
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ? ((HistoricallyNamedCharset)cs).historicalName()
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            : cs.name());
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean inReady() {
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (((in != null) && (in.available() > 0))
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                || (ch instanceof FileChannel)); // ## RBC.available()?
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IOException x) {
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return false;
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    boolean implReady() {
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return bb.hasRemaining() || inReady();
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    void implClose() throws IOException {
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ch != null)
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ch.close();
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        in.close();
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
419