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