/// <summary>
        /// Read characters into a portion of an array, reading from the underlying
        /// stream at most once if necessary.
        /// </summary>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private int read1(byte[] b, int off, int len) throws IOException
        private int Read1(sbyte[] b, int off, int len)
        {
            int avail = Count - Pos;

            if (avail <= 0)
            {
                /* If the requested length is at least as large as the buffer, and
                 * if there is no mark/reset activity, do not bother to copy the
                 * bytes into the local buffer.  In this way buffered streams will
                 * cascade harmlessly. */
                if (len >= BufIfOpen.Length && Markpos < 0)
                {
                    return(InIfOpen.Read(b, off, len));
                }
                Fill();
                avail = Count - Pos;
                if (avail <= 0)
                {
                    return(-1);
                }
            }
            int cnt = (avail < len) ? avail : len;

            System.Array.Copy(BufIfOpen, Pos, b, off, cnt);
            Pos += cnt;
            return(cnt);
        }
        /// <summary>
        /// See the general contract of the <code>skip</code>
        /// method of <code>InputStream</code>.
        /// </summary>
        /// <exception cref="IOException">  if the stream does not support seek,
        ///                          or if this input stream has been closed by
        ///                          invoking its <seealso cref="#close()"/> method, or an
        ///                          I/O error occurs. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public synchronized long skip(long n) throws IOException
        public override long Skip(long n)
        {
            lock (this)
            {
                BufIfOpen;                 // Check for closed stream
                if (n <= 0)
                {
                    return(0);
                }
                long avail = Count - Pos;

                if (avail <= 0)
                {
                    // If no mark position set then don't keep in buffer
                    if (Markpos < 0)
                    {
                        return(InIfOpen.Skip(n));
                    }

                    // Fill in buffer to save bytes for reset
                    Fill();
                    avail = Count - Pos;
                    if (avail <= 0)
                    {
                        return(0);
                    }
                }

                long skipped = (avail < n) ? avail : n;
                Pos += (int)skipped;
                return(skipped);
            }
        }
        /// <summary>
        /// Returns an estimate of the number of bytes that can be read (or
        /// skipped over) from this input stream without blocking by the next
        /// invocation of a method for this input stream. The next invocation might be
        /// the same thread or another thread.  A single read or skip of this
        /// many bytes will not block, but may read or skip fewer bytes.
        /// <para>
        /// This method returns the sum of the number of bytes remaining to be read in
        /// the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
        /// <seealso cref="java.io.FilterInputStream#in in"/>.available().
        ///
        /// </para>
        /// </summary>
        /// <returns>     an estimate of the number of bytes that can be read (or skipped
        ///             over) from this input stream without blocking. </returns>
        /// <exception cref="IOException">  if this input stream has been closed by
        ///                          invoking its <seealso cref="#close()"/> method,
        ///                          or an I/O error occurs. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public synchronized int available() throws IOException
        public override int Available()
        {
            lock (this)
            {
                int n     = Count - Pos;
                int avail = InIfOpen.Available();
                return(n > (Integer.MaxValue - avail) ? Integer.MaxValue : n + avail);
            }
        }
        /// <summary>
        /// Fills the buffer with more data, taking into account
        /// shuffling and other tricks for dealing with marks.
        /// Assumes that it is being called by a synchronized method.
        /// This method also assumes that all data has already been read in,
        /// hence pos > count.
        /// </summary>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: private void fill() throws IOException
        private void Fill()
        {
            sbyte[] buffer = BufIfOpen;
            if (Markpos < 0)
            {
                Pos = 0;                   // no mark: throw away the buffer
            }
            else if (Pos >= buffer.Length) // no room left in buffer
            {
                if (Markpos > 0)           // can throw away early part of the buffer
                {
                    int sz = Pos - Markpos;
                    System.Array.Copy(buffer, Markpos, buffer, 0, sz);
                    Pos     = sz;
                    Markpos = 0;
                }
                else if (buffer.Length >= Marklimit)
                {
                    Markpos = -1;                // buffer got too big, invalidate mark
                    Pos     = 0;                 // drop buffer contents
                }
                else if (buffer.Length >= MAX_BUFFER_SIZE)
                {
                    throw new OutOfMemoryError("Required array size too large");
                }                 // grow buffer
                else
                {
                    int nsz = (Pos <= MAX_BUFFER_SIZE - Pos) ? Pos * 2 : MAX_BUFFER_SIZE;
                    if (nsz > Marklimit)
                    {
                        nsz = Marklimit;
                    }
                    sbyte[] nbuf = new sbyte[nsz];
                    System.Array.Copy(buffer, 0, nbuf, 0, Pos);
                    if (!BufUpdater.CompareAndSet(this, buffer, nbuf))
                    {
                        // Can't replace buf if there was an async close.
                        // Note: This would need to be changed if fill()
                        // is ever made accessible to multiple threads.
                        // But for now, the only way CAS can fail is via close.
                        // assert buf == null;
                        throw new IOException("Stream closed");
                    }
                    buffer = nbuf;
                }
            }
            Count = Pos;
            int n = InIfOpen.Read(buffer, Pos, buffer.Length - Pos);

            if (n > 0)
            {
                Count = n + Pos;
            }
        }