lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nightowl...@apache.org
Subject [03/45] lucenenet git commit: Changed Lucene.Net.Analysis.Common.Analysis.Util.BufferedCharFilter to to the implementation from the Apache Harmony project
Date Sun, 30 Apr 2017 21:55:42 GMT
Changed Lucene.Net.Analysis.Common.Analysis.Util.BufferedCharFilter to to the implementation from the Apache Harmony project


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/f3ac940c
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/f3ac940c
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/f3ac940c

Branch: refs/heads/master
Commit: f3ac940c97d0e7ccdda707df11365fda4c89c197
Parents: b6b1d87
Author: Shad Storhaug <shad@shadstorhaug.com>
Authored: Thu Apr 27 12:54:48 2017 +0700
Committer: Shad Storhaug <shad@shadstorhaug.com>
Committed: Fri Apr 28 13:31:27 2017 +0700

----------------------------------------------------------------------
 LICENSE.txt                                     |  22 +
 .../Analysis/CharFilter/MappingCharFilter.cs    |   2 +-
 .../Analysis/Util/BufferedCharFilter.cs         | 752 +++++++++--------
 .../JavaCompatibility/SystemTypesHelpers.cs     |   2 +-
 .../Analysis/Util/TestBufferedCharFilter.cs     | 816 +++++++++++++++++++
 .../Lucene.Net.Tests.Analysis.Common.csproj     |   6 +-
 6 files changed, 1266 insertions(+), 334 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/LICENSE.txt
----------------------------------------------------------------------
diff --git a/LICENSE.txt b/LICENSE.txt
index 88346fd..617d392 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -758,6 +758,28 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 
+=============================
+
+Some code in 
+src/Lucene.Net.Analysis.Common/Util/BufferedCharFilter.cs
+src/Lucene.Net.Tests.Analysis.Common/Util/TestBufferedCharFilter.cs 
+was sourced from the Apache Harmony project, which falls under the 
+following license:
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
 
 =============================
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilter.cs b/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilter.cs
index 08ac354..de79d64 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilter.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilter.cs
@@ -58,7 +58,7 @@ namespace Lucene.Net.Analysis.CharFilters
         {
             //LUCENENET support to reset the reader.
             _input = GetBufferedReader(@in);
-            _input.Mark(BufferedCharFilter.defaultCharBufferSize);
+            _input.Mark(BufferedCharFilter.DEFAULT_CHAR_BUFFER_SIZE);
             buffer.Reset(_input);
             //buffer.Reset(@in);
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs b/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
index e1461a7..c475772 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Util/BufferedCharFilter.cs
@@ -1,27 +1,4 @@
-/*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
+// This class was sourced from the Apache Harmony project's BufferedReader
 
 using Lucene.Net.Analysis.CharFilters;
 using System;
@@ -31,38 +8,66 @@ using System.Threading.Tasks;
 
 namespace Lucene.Net.Analysis.Util
 {
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
     /// <summary>
     /// LUCENENET specific class to mimic Java's BufferedReader (that is, a reader that is seekable) 
     /// so it supports Mark() and Reset() (which are part of the Java Reader class), but also 
     /// provide the Correct() method of BaseCharFilter.
-    /// 
-    /// At some point we might be able to make some readers accept streams (that are seekable) 
-    /// so this functionality can be .NET-ified.
     /// </summary>
     public class BufferedCharFilter : BaseCharFilter
     {
-        private TextReader @in;
-
-        private char[] cb;
-        private int nChars, nextChar;
-
-        private static readonly int INVALIDATED = -2;
-        private static readonly int UNMARKED = -1;
-        private int markedChar = UNMARKED;
-        private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
+        public const int DEFAULT_CHAR_BUFFER_SIZE = 8192;
 
         /// <summary>
-        /// If the next character is a line feed, skip it
+        /// The object used to synchronize access to the reader.
         /// </summary>
-        private bool skipLF = false;
+        protected object m_lock = new object();
+
+        private TextReader @in;
 
         /// <summary>
-        /// The skipLF flag when the mark was set
+        /// The characters that can be read and refilled in bulk. We maintain three
+        /// indices into this buffer:
+        /// <code>
+        /// { X X X X X X X X X X X X - - }
+        /// ^     ^             ^
+        /// |     |             |
+        /// mark   pos end
+        /// </code>
+        /// Pos points to the next readable character.End is one greater than the
+        /// last readable character.When<c> pos == end</c>, the buffer is empty and
+        /// must be <see cref="FillBuf()"/> before characters can be read.
+        ///
+        /// <para/> Mark is the value pos will be set to on calls to 
+        /// <see cref="Reset()"/>. Its value is in the range <c>[0...pos]</c>. If the mark is <c>-1</c>, the
+        /// buffer cannot be reset.
+        /// 
+        /// <para/> MarkLimit limits the distance between the mark and the pos.When this
+        /// limit is exceeded, <see cref="Reset()"/> is permitted (but not required) to
+        /// throw an exception. For shorter distances, <see cref="Reset()"/> shall not throw
+        /// (unless the reader is closed).
         /// </summary>
-        private bool markedSkipLF = false;
-
-        internal static int defaultCharBufferSize = 8192;
-        private static int defaultExpectedLineLength = 80;
+        private char[] buf;
+        private int pos;
+        private int end;
+        private int mark = -1;
+        private int markLimit = -1;
 
 #if !NETSTANDARD
         /// <summary>
@@ -72,406 +77,497 @@ namespace Lucene.Net.Analysis.Util
 #endif
 
         /// <summary>
-        /// Creates a buffering character-input stream that uses an input buffer of the specified size.
+        /// Creates a buffering character-input stream that uses a default-sized input buffer.
         /// </summary>
         /// <param name="in">A TextReader</param>
-        /// <param name="sz">Input-buffer size</param>
-        public BufferedCharFilter(TextReader @in, int sz)
+        public BufferedCharFilter(TextReader @in)
             : base(@in)
         {
-            if (sz <= 0)
-                throw new ArgumentOutOfRangeException("Buffer size <= 0");
             this.@in = @in;
-            cb = new char[sz];
-            nextChar = nChars = 0;
+            buf = new char[DEFAULT_CHAR_BUFFER_SIZE];
         }
 
         /// <summary>
-        /// Creates a buffering character-input stream that uses a default-sized input buffer.
+        /// Creates a buffering character-input stream that uses an input buffer of the specified size.
         /// </summary>
         /// <param name="in">A TextReader</param>
-        public BufferedCharFilter(TextReader @in)
-            : this(@in, defaultCharBufferSize)
+        /// <param name="size">Input-buffer size</param>
+        public BufferedCharFilter(TextReader @in, int size)
+            : base(@in)
         {
+            if (size <= 0)
+            {
+                throw new ArgumentOutOfRangeException("Buffer size <= 0");
+            }
+            this.@in = @in;
+            buf = new char[size];
         }
 
         /// <summary>
-        /// Checks to make sure that the stream has not been closed
+        /// Disposes this reader. This implementation closes the buffered source reader
+        /// and releases the buffer. Nothing is done if this reader has already been
+        /// disposed.
         /// </summary>
-        private void EnsureOpen()
+        /// <param name="disposing"></param>
+        /// <exception cref="IOException">if an error occurs while closing this reader.</exception>
+        protected override void Dispose(bool disposing)
         {
-            if (@in == null)
-                throw new IOException("Stream closed");
+            if (disposing)
+            {
+#if !NETSTANDARD
+                this.isDisposing = true;
+#endif
+                lock (m_lock)
+                {
+                    if (!IsClosed)
+                    {
+                        @in.Dispose();
+                        @in = null;
+                        buf = null;
+                    }
+                }
+#if !NETSTANDARD
+                this.isDisposing = false;
+#endif
+            }
         }
 
         /// <summary>
-        /// Fills the input buffer, taking the mark into account if it is valid.
+        /// Populates the buffer with data. It is an error to call this method when
+        /// the buffer still contains data; ie. if <c>pos &lt; end</c>.
         /// </summary>
-        private void Fill()
+        /// <returns>
+        /// the number of bytes read into the buffer, or -1 if the end of the
+        /// source stream has been reached.
+        /// </returns>
+        private int FillBuf()
         {
-            int dst;
-            if (markedChar <= UNMARKED)
-            {
-                /* No mark */
-                dst = 0;
-            }
-            else
+            // assert(pos == end);
+
+            if (mark == -1 || (pos - mark >= markLimit))
             {
-                /* Marked */
-                int delta = nextChar - markedChar;
-                if (delta >= readAheadLimit)
+                /* mark isn't set or has exceeded its limit. use the whole buffer */
+                int result = @in.Read(buf, 0, buf.Length);
+                if (result > 0)
                 {
-                    /* Gone past read-ahead limit: Invalidate mark */
-                    markedChar = INVALIDATED;
-                    readAheadLimit = 0;
-                    dst = 0;
+                    mark = -1;
+                    pos = 0;
+                    end = result;
                 }
-                else
+                // LUCENENET specific: convert result to -1 to mimic java's reader
+                return result == 0 ? -1 : result;
+            }
+
+            if (mark == 0 && markLimit > buf.Length)
+            {
+                /* the only way to make room when mark=0 is by growing the buffer */
+                int newLength = buf.Length * 2;
+                if (newLength > markLimit)
                 {
-                    if (readAheadLimit <= cb.Length)
-                    {
-                        /* Shuffle in the current buffer */
-                        System.Array.Copy(cb, markedChar, cb, 0, delta);
-                        markedChar = 0;
-                        dst = delta;
-                    }
-                    else
-                    {
-                        /* Reallocate buffer to accommodate read-ahead limit */
-                        char[] ncb = new char[readAheadLimit];
-                        System.Array.Copy(cb, markedChar, ncb, 0, delta);
-                        cb = ncb;
-                        markedChar = 0;
-                        dst = delta;
-                    }
-                    nextChar = nChars = delta;
+                    newLength = markLimit;
                 }
+                char[] newbuf = new char[newLength];
+                System.Array.Copy(buf, 0, newbuf, 0, buf.Length);
+                buf = newbuf;
+            }
+            else if (mark > 0)
+            {
+                /* make room by shifting the buffered data to left mark positions */
+                System.Array.Copy(buf, mark, buf, 0, buf.Length - mark);
+                pos -= mark;
+                end -= mark;
+                mark = 0;
             }
 
-            int n = @in.Read(cb, dst, cb.Length - dst);
-            // LUCENENET: .NET readers always return 0 when they are finished
-            // so there is nothing to do here but remove this loop.
-            //do
-            //{
-            //    n = @in.Read(cb, dst, cb.Length - dst);
-            //} while (n == 0);
-            if (n > 0)
+            /* Set the new position and mark position */
+            int count = @in.Read(buf, pos, buf.Length - pos);
+            if (count > 0)
             {
-                nChars = dst + n;
-                nextChar = dst;
+                end += count;
             }
+            // LUCENENET specific: convert result to -1 to mimic java's reader
+            return count == 0 ? -1 : count;
         }
 
         /// <summary>
-        /// Reads a single character.
+        /// Checks to make sure that the stream has not been closed
         /// </summary>
-        /// <returns>The character read, as an integer in the range 0 to 65535 (0x00-0xffff), or -1 if the end of the stream has been reached</returns>
-        /// <exception cref="IOException">If an I/O error occurs</exception>
-        public override int Read()
+        private void EnsureOpen()
         {
-            lock (this)
+            if (IsClosed)
+            {
+                throw new IOException("Reader already closed");
+            }
+        }
+
+        /// <summary>
+        /// Indicates whether or not this reader is closed.
+        /// </summary>
+        private bool IsClosed
+        {
+            get { return buf == null; }
+        }
+
+        /// <summary>
+        /// Sets a mark position in this reader. The parameter <paramref name="markLimit"/>
+        /// indicates how many characters can be read before the mark is invalidated.
+        /// Calling <see cref="Reset()"/> will reposition the reader back to the marked
+        /// position if <see cref="markLimit"/> has not been surpassed.
+        /// </summary>
+        /// <param name="markLimit">
+        /// the number of characters that can be read before the mark is
+        /// invalidated.
+        /// </param>
+        /// <exception cref="ArgumentOutOfRangeException">if <c>markLimit &lt; 0</c></exception>
+        /// <exception cref="IOException">if an error occurs while setting a mark in this reader.</exception>
+        public override void Mark(int markLimit)
+        {
+            if (markLimit < 0)
+            {
+                throw new ArgumentOutOfRangeException("Read-ahead limit < 0");
+            }
+            lock (m_lock)
             {
                 EnsureOpen();
-                for (;;)
-                {
-                    if (nextChar >= nChars)
-                    {
-                        Fill();
-                        if (nextChar >= nChars)
-                            return -1;
-                    }
-                    if (skipLF)
-                    {
-                        skipLF = false;
-                        if (cb[nextChar] == '\n')
-                        {
-                            nextChar++;
-                            continue;
-                        }
-                    }
-                    return cb[nextChar++];
-                }
+                this.markLimit = markLimit;
+                mark = pos;
             }
         }
 
         /// <summary>
-        /// Reads characters into a portion of an array.
-        /// This method implements the general contract of the corresponding read method of the TextReader class. 
-        /// As an additional convenience, it attempts to read as many characters as possible by repeatedly 
-        /// invoking the read method of the underlying stream.This iterated read continues until one of the 
-        /// following conditions becomes true:
-        /// 
-        /// <list type="bullet">
-        /// <item>The specified number of characters have been read,</item>
-        /// <item>The read method of the underlying stream returns -1, indicating end-of-file, or</item>
-        /// <item>The ready method of the underlying stream returns false, indicating that further input requests would block.</item>
-        /// </list>
-        /// If the first read on the underlying stream returns -1 to indicate end-of-file then this method returns -1. 
-        /// Otherwise this method returns the number of characters actually read.
-        /// Subclasses of this class are encouraged, but not required, to attempt to read as many characters 
-        /// as possible in the same fashion. Ordinarily this method takes characters from this stream's character 
-        /// buffer, filling it from the underlying stream as necessary. If, however, the buffer is empty, the mark 
-        /// is not valid, and the requested length is at least as large as the buffer, then this method will read 
-        /// characters directly from the underlying stream into the given array. Thus redundant BufferedReaders 
-        /// will not copy data unnecessarily.
+        /// Indicates whether this reader supports the <see cref="Mark(int)"/> and
+        /// <see cref="Reset()"/> methods. This implementation returns <c>true</c>.
         /// </summary>
-        /// <param name="buffer">Destination buffer</param>
-        /// <param name="index">Offset at which to start storing characters</param>
-        /// <param name="count">Maximum number of characters to read</param>
-        /// <returns></returns>
-        public override int Read(char[] buffer, int index, int count)
+        /// <seealso cref="Mark(int)"/>
+        /// <seealso cref="Reset()"/>
+        public override bool IsMarkSupported
         {
-            if (nextChar >= nChars)
+            get
             {
-                /* If the requested length is at least as large as the buffer, and
-               if there is no mark/reset activity, and if line feeds are not
-               being skipped, do not bother to copy the characters into the
-               local buffer.  In this way buffered streams will cascade
-               harmlessly. */
-                if (count >= cb.Length && markedChar <= UNMARKED && !skipLF)
-                {
-                    return @in.Read(buffer, index, count);
-                }
-                Fill();
+                return true;
             }
-            if (nextChar >= nChars) return -1;
-            if (skipLF)
+        }
+
+
+        /// <summary>
+        /// Reads a single character from this reader and returns it with the two
+        /// higher-order bytes set to 0. If possible, <see cref="BufferedCharFilter"/> returns a
+        /// character from the buffer. If there are no characters available in the
+        /// buffer, it fills the buffer and then returns a character. It returns -1
+        /// if there are no more characters in the source reader.
+        /// </summary>
+        /// <returns>The character read or -1 if the end of the source reader has been reached.</returns>
+        /// <exception cref="IOException">If this reader is disposed or some other I/O error occurs.</exception>
+        public override int Read()
+        {
+            lock (m_lock)
             {
-                skipLF = false;
-                if (cb[nextChar] == '\n')
+                EnsureOpen();
+                /* Are there buffered characters available? */
+                if (pos < end || FillBuf() != -1)
                 {
-                    nextChar++;
-                    if (nextChar >= nChars)
-                        Fill();
-                    if (nextChar >= nChars)
-                        return -1;
+                    return buf[pos++];
                 }
+                return -1;
             }
-            int n = Math.Min(count, nChars - nextChar);
-            System.Array.Copy(cb, nextChar, buffer, index, n);
-            nextChar += n;
-            return n;
         }
 
         /// <summary>
-        /// Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return 
-        /// ('\r'), or a carriage return followed immediately by a linefeed.
+        /// Reads at most <paramref name="length"/> characters from this reader and stores them
+        /// at <paramref name="offset"/> in the character array <paramref name="buffer"/>. Returns the
+        /// number of characters actually read or -1 if the end of the source reader
+        /// has been reached. If all the buffered characters have been used, a mark
+        /// has not been set and the requested number of characters is larger than
+        /// this readers buffer size, BufferedReader bypasses the buffer and simply
+        /// places the results directly into <paramref name="buffer"/>.
         /// </summary>
-        /// <returns>A String containing the contents of the line, not including any line-termination characters, 
-        /// or null if the end of the stream has been reached</returns>
-        /// <exception cref="IOException">If an I/O error occurs</exception>
-        public override string ReadLine()
+        /// <param name="buffer">the character array to store the characters read.</param>
+        /// <param name="offset">the initial position in <paramref name="buffer"/> to store the bytes read from this reader.</param>
+        /// <param name="length">the maximum number of characters to read, must be non-negative.</param>
+        /// <returns>number of characters read or -1 if the end of the source reader has been reached.</returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// if <c>offset &lt; 0</c> or <c>length &lt; 0</c>, or if
+        /// <c>offset + length</c> is greater than the size of
+        /// <paramref name="buffer"/>.
+        /// </exception>
+        /// <exception cref="IOException">if this reader is disposed or some other I/O error occurs.</exception>
+        public override int Read(char[] buffer, int offset, int length)
         {
-            StringBuilder s = null;
-            int startChar;
-
-            lock (this)
+            lock(m_lock)
             {
                 EnsureOpen();
-                bool omitLF = skipLF;
-
-                for (;;)
+                if (offset < 0 || offset > buffer.Length - length || length < 0)
+                {
+                    throw new ArgumentOutOfRangeException();
+                }
+                int outstanding = length;
+                while (outstanding > 0)
                 {
-                    if (nextChar >= nChars)
+
+                    /*
+                     * If there are bytes in the buffer, grab those first.
+                     */
+                    int available = end - pos;
+                    if (available > 0)
                     {
-                        Fill();
+                        int count2 = available >= outstanding ? outstanding : available;
+                        System.Array.Copy(buf, pos, buffer, offset, count2);
+                        pos += count2;
+                        offset += count2;
+                        outstanding -= count2;
                     }
-                    if (nextChar >= nChars)
-                    { /* EOF */
-                        if (s != null && s.Length > 0)
-                            return s.ToString();
-                        else
-                            return null;
+
+                    /*
+                     * Before attempting to read from the underlying stream, make
+                     * sure we really, really want to. We won't bother if we're
+                     * done, or if we've already got some bytes and reading from the
+                     * underlying stream would block.
+                     */
+                    if (outstanding == 0 /*|| (outstanding < length && !@in.ready())*/) {
+                        break;
                     }
-                    bool eol = false;
-                    char c = (char)0;
-                    int i;
 
-                    /* Skip a leftover '\n', if necessary */
-                    if (omitLF && (cb[nextChar] == '\n'))
-                        nextChar++;
-                    skipLF = false;
-                    omitLF = false;
+                    // assert(pos == end);
 
-                    for (i = nextChar; i < nChars; i++)
+                    /*
+                     * If we're unmarked and the requested size is greater than our
+                     * buffer, read the bytes directly into the caller's buffer. We
+                     * don't read into smaller buffers because that could result in
+                     * a many reads.
+                     */
+                    if ((mark == -1 || (pos - mark >= markLimit))
+                            && outstanding >= buf.Length)
                     {
-                        c = cb[i];
-                        if ((c == '\n') || (c == '\r'))
+                        int count3 = @in.Read(buffer, offset, outstanding);
+                        if (count3 > 0)
                         {
-                            eol = true;
-                            break;
+                            offset += count3;
+                            outstanding -= count3;
+                            mark = -1;
                         }
+
+                        break; // assume the source stream gave us all that it could
                     }
 
-                    startChar = nextChar;
-                    nextChar = i;
-                    if (eol)
+                    if (FillBuf() == -1)
                     {
-                        string str;
-                        if (s == null)
-                        {
-                            str = new string(cb, startChar, i - startChar);
-                        }
-                        else
-                        {
-                            s.Append(cb, startChar, i - startChar);
-                            str = s.ToString();
-                        }
-                        nextChar++;
-                        if (c == '\r')
-                        {
-                            skipLF = true;
-                        }
-                        return str;
+                        break; // source is exhausted
                     }
-
-                    if (s == null)
-                        s = new StringBuilder(defaultExpectedLineLength);
-                    s.Append(cb, startChar, i - startChar);
                 }
+
+                int count = length - outstanding;
+                return (count > 0 || count == length) ? count : 0 /*-1*/;
             }
         }
 
-        public override long Skip(int n)
+        /// <summary>
+        /// Peeks at the next input character, refilling the buffer if necessary. If
+        /// this character is a newline character ("\n"), it is discarded.
+        /// </summary>
+        private void ChompNewline()
         {
-            if (n < 0L)
+            if ((pos != end || FillBuf() != -1)
+                && buf[pos] == '\n')
             {
-                throw new ArgumentOutOfRangeException("skip value is negative");
+                pos++;
             }
-            lock (this)
+        }
+
+        /// <summary>
+        /// Returns the next line of text available from this reader. A line is
+        /// represented by zero or more characters followed by <c>'\n'</c>,
+        /// <c>'\r'</c>, <c>"\r\n"</c> or the end of the reader. The string does
+        /// not include the newline sequence.
+        /// </summary>
+        /// <returns>The contents of the line or <c>null</c> if no characters were 
+        /// read before the end of the reader has been reached.</returns>
+        /// <exception cref="IOException">if this reader is disposed or some other I/O error occurs.</exception>
+        public override string ReadLine()
+        {
+            lock(m_lock)
             {
                 EnsureOpen();
-                int r = n;
-                while (r > 0)
+                /* has the underlying stream been exhausted? */
+                if (pos == end && FillBuf() == -1)
                 {
-                    if (nextChar >= nChars)
-                        Fill();
-                    if (nextChar >= nChars) /* EOF */
-                        break;
-                    if (skipLF)
+                    return null;
+                }
+                for (int charPos = pos; charPos < end; charPos++)
+                {
+                    char ch = buf[charPos];
+                    if (ch > '\r')
                     {
-                        skipLF = false;
-                        if (cb[nextChar] == '\n')
-                        {
-                            nextChar++;
-                        }
+                        continue;
                     }
-                    int d = nChars - nextChar;
-                    if (r <= d)
+                    if (ch == '\n')
                     {
-                        nextChar += r;
-                        r = 0;
-                        break;
+                        string res = new string(buf, pos, charPos - pos);
+                        pos = charPos + 1;
+                        return res;
                     }
-                    else
+                    else if (ch == '\r')
                     {
-                        r -= d;
-                        nextChar = nChars;
+                        string res = new string(buf, pos, charPos - pos);
+                        pos = charPos + 1;
+                        if (((pos < end) || (FillBuf() != -1))
+                                && (buf[pos] == '\n'))
+                        {
+                            pos++;
+                        }
+                        return res;
                     }
                 }
-                return n - r;
-            }
-        }
 
-        /// <summary>
-        /// Tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.
-        /// </summary>
-        /// <returns></returns>
-        public override bool Ready()
-        {
-            lock (this)
-            {
-                EnsureOpen();
+                char eol = '\0';
+                StringBuilder result = new StringBuilder(80);
+                /* Typical Line Length */
 
-                // If newline needs to be skipped and the next char to be read
-                // is a newline character, then just skip it right away.
-                if (skipLF)
+                result.Append(buf, pos, end - pos);
+                while (true)
                 {
-                    // Note that in.ready() will return true if and only if the next
-                    // read on the stream will not block.
-                    if (nextChar >= nChars /* && @in.Ready() */)
+                    pos = end;
+
+                    /* Are there buffered characters available? */
+                    if (eol == '\n')
+                    {
+                        return result.ToString();
+                    }
+                    // attempt to fill buffer
+                    if (FillBuf() == -1)
+                    {
+                        // characters or null.
+                        return result.Length > 0 || eol != '\0'
+                                ? result.ToString()
+                                : null;
+                    }
+                    for (int charPos = pos; charPos < end; charPos++)
+                    {
+                        char c = buf[charPos];
+                        if (eol == '\0')
+                        {
+                            if ((c == '\n' || c == '\r'))
+                            {
+                                eol = c;
+                            }
+                        }
+                        else if (eol == '\r' && c == '\n')
+                        {
+                            if (charPos > pos)
+                            {
+                                result.Append(buf, pos, charPos - pos - 1);
+                            }
+                            pos = charPos + 1;
+                            return result.ToString();
+                        }
+                        else
+                        {
+                            if (charPos > pos)
+                            {
+                                result.Append(buf, pos, charPos - pos - 1);
+                            }
+                            pos = charPos;
+                            return result.ToString();
+                        }
+                    }
+                    if (eol == '\0')
                     {
-                        Fill();
+                        result.Append(buf, pos, end - pos);
                     }
-                    if (nextChar < nChars)
+                    else
                     {
-                        if (cb[nextChar] == '\n')
-                            nextChar++;
-                        skipLF = false;
+                        result.Append(buf, pos, end - pos - 1);
                     }
                 }
-                return (nextChar < nChars) /* || @in.Ready() */;
             }
         }
 
         /// <summary>
-        /// Tells whether this stream supports the mark() operation, which it does.
+        /// Indicates whether this reader is ready to be read without blocking.
         /// </summary>
-        public override bool IsMarkSupported
+        /// <returns>
+        /// <c>true</c> if this reader will not block when <see cref="Read"/> is
+        /// called, <c>false</c> if unknown or blocking will occur.
+        /// </returns>
+        public override bool Ready()
         {
-            get
+            lock (m_lock)
             {
-                return true;
+                EnsureOpen();
+                return ((end - pos) > 0) /*|| in.ready()*/;
             }
         }
 
         /// <summary>
-        /// Marks the present position in the stream. Subsequent calls to reset() will attempt to reposition the stream to this point.
+        /// Resets this reader's position to the last <see cref="Mark(int)"/> location.
+        /// Invocations of <see cref="Read()"/> and <see cref="Skip(int)"/> will occur from this new
+        /// location.
         /// </summary>
-        /// <param name="readAheadLimit">Limit on the number of characters that may be read while still preserving the mark. An attempt 
-        /// to reset the stream after reading characters up to this limit or beyond may fail. A limit value larger than the size of the 
-        /// input buffer will cause a new buffer to be allocated whose size is no smaller than limit. Therefore large values should be 
-        /// used with care.</param>
-        public override void Mark(int readAheadLimit)
+        /// <exception cref="IOException">If this reader is disposed or no mark has been set.</exception>
+        /// <seealso cref="Mark(int)"/>
+        /// <seealso cref="IsMarkSupported"/>
+        public override void Reset()
         {
-            if (readAheadLimit < 0)
-            {
-                throw new ArgumentOutOfRangeException("Read-ahead limit < 0");
-            }
-            lock (this)
+            lock (m_lock)
             {
                 EnsureOpen();
-                this.readAheadLimit = readAheadLimit;
-                markedChar = nextChar;
-                markedSkipLF = skipLF;
+                if (mark < 0)
+                {
+                    throw new IOException("Reader not marked");
+                }
+                pos = mark;
             }
         }
 
         /// <summary>
-        /// Resets the stream to the most recent mark.
+        /// Skips <paramref name="amount"/> characters in this reader. Subsequent
+        /// <see cref="Read()"/>s will not return these characters unless <see cref="Reset()"/>
+        /// is used. Skipping characters may invalidate a mark if <see cref="markLimit"/>
+        /// is surpassed.
         /// </summary>
-        /// <exception cref="IOException">If the stream has never been marked, or if the mark has been invalidated</exception>
-        public override void Reset()
+        /// <param name="amount">the maximum number of characters to skip.</param>
+        /// <returns>the number of characters actually skipped.</returns>
+        /// <exception cref="ArgumentOutOfRangeException">if <c>amount &lt; 0</c>.</exception>
+        /// <exception cref="IOException">If this reader is disposed or some other I/O error occurs.</exception>
+        /// <seealso cref="Mark(int)"/>
+        /// <seealso cref="IsMarkSupported"/>
+        /// <seealso cref="Reset()"/>
+        public override long Skip(int amount)
         {
-            lock (this)
+            if (amount < 0L)
             {
-                EnsureOpen();
-                if (markedChar < 0)
-                    throw new IOException((markedChar == INVALIDATED) ? "Mark invalid" : "Stream not marked");
-                nextChar = markedChar;
-                skipLF = markedSkipLF;
+                throw new ArgumentOutOfRangeException("skip value is negative");
             }
-        }
-
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
+            lock (m_lock)
             {
-#if !NETSTANDARD
-                this.isDisposing = true;
-#endif
-                lock (this)
+                EnsureOpen();
+                if (amount < 1)
+                {
+                    return 0;
+                }
+                if (end - pos >= amount)
+                {
+                    pos += amount;
+                    return amount;
+                }
+
+                int read = end - pos;
+                pos = end;
+                while (read < amount)
                 {
-                    if (@in != null)
+                    if (FillBuf() == -1)
                     {
-                        @in.Dispose();
-                        @in = null;
+                        return read;
                     }
-                    cb = null;
+                    if (end - pos >= amount - read)
+                    {
+                        pos += amount - read;
+                        return amount;
+                    }
+                    // Couldn't get all the characters, skip what we read
+                    read += (end - pos);
+                    pos = end;
                 }
-#if !NETSTANDARD
-                this.isDisposing = false;
-#endif
+                return amount;
             }
         }
 
@@ -511,8 +607,11 @@ namespace Lucene.Net.Analysis.Util
         {
             throw new NotImplementedException();
         }
-
 #if !NETSTANDARD
+        public override object InitializeLifetimeService()
+        {
+            throw new NotImplementedException();
+        }
 
         public override void Close()
         {
@@ -521,12 +620,7 @@ namespace Lucene.Net.Analysis.Util
                 throw new NotSupportedException("Close() is not supported. Call Dispose() instead.");
             }
         }
-
-        public override object InitializeLifetimeService()
-        {
-            throw new NotImplementedException();
-        }
 #endif
-#endregion
+        #endregion
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs b/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
index 9fd0444..c0f2462 100644
--- a/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
+++ b/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
@@ -282,7 +282,7 @@ namespace Lucene.Net
 
         public static int read(this TextReader reader, char[] buffer)
         {
-            int bytesRead = reader.Read(buffer, 0, buffer.Length - 1);
+            int bytesRead = reader.Read(buffer, 0, buffer.Length);
             // Convert the .NET 0 based bytes to the Java -1 behavior when reading is done.
             return bytesRead == 0 ? -1 : bytesRead;
         }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/src/Lucene.Net.Tests.Analysis.Common/Analysis/Util/TestBufferedCharFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Analysis.Common/Analysis/Util/TestBufferedCharFilter.cs b/src/Lucene.Net.Tests.Analysis.Common/Analysis/Util/TestBufferedCharFilter.cs
new file mode 100644
index 0000000..887a7df
--- /dev/null
+++ b/src/Lucene.Net.Tests.Analysis.Common/Analysis/Util/TestBufferedCharFilter.cs
@@ -0,0 +1,816 @@
+// This class was sourced from the Apache Harmony project
+
+using Lucene.Net.Attributes;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace Lucene.Net.Analysis.Util
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class TestBufferedCharFilter : LuceneTestCase
+    {
+        BufferedCharFilter br;
+
+        String testString = "Test_All_Tests\nTest_java_io_BufferedInputStream\nTest_java_io_BufferedOutputStream\nTest_java_io_ByteArrayInputStream\nTest_java_io_ByteArrayOutputStream\nTest_java_io_DataInputStream\nTest_java_io_File\nTest_java_io_FileDescriptor\nTest_java_io_FileInputStream\nTest_java_io_FileNotFoundException\nTest_java_io_FileOutputStream\nTest_java_io_FilterInputStream\nTest_java_io_FilterOutputStream\nTest_java_io_InputStream\nTest_java_io_IOException\nTest_java_io_OutputStream\nTest_java_io_PrintStream\nTest_java_io_RandomAccessFile\nTest_java_io_SyncFailedException\nTest_java_lang_AbstractMethodError\nTest_java_lang_ArithmeticException\nTest_java_lang_ArrayIndexOutOfBoundsException\nTest_java_lang_ArrayStoreException\nTest_java_lang_Boolean\nTest_java_lang_Byte\nTest_java_lang_Character\nTest_java_lang_Class\nTest_java_lang_ClassCastException\nTest_java_lang_ClassCircularityError\nTest_java_lang_ClassFormatError\nTest_java_lang_ClassLoader\nTest_java_lang_Class
 NotFoundException\nTest_java_lang_CloneNotSupportedException\nTest_java_lang_Double\nTest_java_lang_Error\nTest_java_lang_Exception\nTest_java_lang_ExceptionInInitializerError\nTest_java_lang_Float\nTest_java_lang_IllegalAccessError\nTest_java_lang_IllegalAccessException\nTest_java_lang_IllegalArgumentException\nTest_java_lang_IllegalMonitorStateException\nTest_java_lang_IllegalThreadStateException\nTest_java_lang_IncompatibleClassChangeError\nTest_java_lang_IndexOutOfBoundsException\nTest_java_lang_InstantiationError\nTest_java_lang_InstantiationException\nTest_java_lang_Integer\nTest_java_lang_InternalError\nTest_java_lang_InterruptedException\nTest_java_lang_LinkageError\nTest_java_lang_Long\nTest_java_lang_Math\nTest_java_lang_NegativeArraySizeException\nTest_java_lang_NoClassDefFoundError\nTest_java_lang_NoSuchFieldError\nTest_java_lang_NoSuchMethodError\nTest_java_lang_NullPointerException\nTest_java_lang_Number\nTest_java_lang_NumberFormatException\nTest_java_lang_Object\nTes
 t_java_lang_OutOfMemoryError\nTest_java_lang_RuntimeException\nTest_java_lang_SecurityManager\nTest_java_lang_Short\nTest_java_lang_StackOverflowError\nTest_java_lang_String\nTest_java_lang_StringBuffer\nTest_java_lang_StringIndexOutOfBoundsException\nTest_java_lang_System\nTest_java_lang_Thread\nTest_java_lang_ThreadDeath\nTest_java_lang_ThreadGroup\nTest_java_lang_Throwable\nTest_java_lang_UnknownError\nTest_java_lang_UnsatisfiedLinkError\nTest_java_lang_VerifyError\nTest_java_lang_VirtualMachineError\nTest_java_lang_vm_Image\nTest_java_lang_vm_MemorySegment\nTest_java_lang_vm_ROMStoreException\nTest_java_lang_vm_VM\nTest_java_lang_Void\nTest_java_net_BindException\nTest_java_net_ConnectException\nTest_java_net_DatagramPacket\nTest_java_net_DatagramSocket\nTest_java_net_DatagramSocketImpl\nTest_java_net_InetAddress\nTest_java_net_NoRouteToHostException\nTest_java_net_PlainDatagramSocketImpl\nTest_java_net_PlainSocketImpl\nTest_java_net_Socket\nTest_java_net_SocketException\nTest_j
 ava_net_SocketImpl\nTest_java_net_SocketInputStream\nTest_java_net_SocketOutputStream\nTest_java_net_UnknownHostException\nTest_java_util_ArrayEnumerator\nTest_java_util_Date\nTest_java_util_EventObject\nTest_java_util_HashEnumerator\nTest_java_util_Hashtable\nTest_java_util_Properties\nTest_java_util_ResourceBundle\nTest_java_util_tm\nTest_java_util_Vector\n";
+
+        /**
+         * The spec says that BufferedReader.readLine() considers only "\r", "\n"
+         * and "\r\n" to be line separators. We must not permit additional separator
+         * characters.
+        */
+        [Test, LuceneNetSpecific]
+        public void Test_ReadLine_IgnoresEbcdic85Characters()
+        {
+            assertLines("A\u0085B", "A\u0085B");
+        }
+
+        [Test, LuceneNetSpecific]
+        public void Test_ReadLine_Separators()
+        {
+            assertLines("A\nB\nC", "A", "B", "C");
+            assertLines("A\rB\rC", "A", "B", "C");
+            assertLines("A\r\nB\r\nC", "A", "B", "C");
+            assertLines("A\n\rB\n\rC", "A", "", "B", "", "C");
+            assertLines("A\n\nB\n\nC", "A", "", "B", "", "C");
+            assertLines("A\r\rB\r\rC", "A", "", "B", "", "C");
+            assertLines("A\n\n", "A", "");
+            assertLines("A\n\r", "A", "");
+            assertLines("A\r\r", "A", "");
+            assertLines("A\r\n", "A");
+            assertLines("A\r\n\r\n", "A", "");
+        }
+
+        private void assertLines(string @in, params string[] lines)
+        {
+            BufferedCharFilter bufferedReader
+                = new BufferedCharFilter(new StringReader(@in));
+            foreach (String line in lines)
+            {
+                assertEquals(line, bufferedReader.ReadLine());
+            }
+            assertNull(bufferedReader.ReadLine());
+        }
+
+        /**
+         * @tests java.io.BufferedReader#BufferedReader(java.io.Reader)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ConstructorLjava_io_Reader()
+        {
+            // Test for method java.io.BufferedReader(java.io.Reader)
+            assertTrue("Used in tests", true);
+        }
+
+        /**
+         * @tests java.io.BufferedReader#BufferedReader(java.io.Reader, int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ConstructorLjava_io_ReaderI()
+        {
+            // Test for method java.io.BufferedReader(java.io.Reader, int)
+            assertTrue("Used in tests", true);
+        }
+
+        /**
+         * @tests java.io.BufferedReader#close()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_Close()
+        {
+            // Test for method void java.io.BufferedReader.close()
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                br.Dispose();
+                br.Read();
+                fail("Read on closed stream");
+            }
+            catch (IOException x)
+            {
+                return;
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#mark(int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_MarkI()
+        {
+            // Test for method void java.io.BufferedReader.mark(int)
+            char[] buf = null;
+            br = new BufferedCharFilter(new StringReader(testString));
+            br.Skip(500);
+            br.Mark(1000);
+            br.Skip(250);
+            br.Reset();
+            buf = new char[testString.Length];
+            br.Read(buf, 0, 500);
+
+            assertTrue("Failed to set mark properly", testString.Substring(500,
+                    1000 - 500).equals(new string(buf, 0, 500)));
+
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString), 800);
+                br.Skip(500);
+                br.Mark(250);
+                br.Read(buf, 0, 1000);
+                br.Reset();
+
+                fail("Failed to invalidate mark properly");
+            }
+            catch (IOException x)
+            {
+                // Expected
+            }
+
+            char[] chars = new char[256];
+            for (int i = 0; i < 256; i++)
+                chars[i] = (char)i;
+            BufferedCharFilter @in = new BufferedCharFilter(new StringReader(new String(
+                    chars)), 12);
+
+            @in.Skip(6);
+            @in.Mark(14);
+            @in.Read(new char[14], 0, 14);
+            @in.Reset();
+
+            assertTrue("Wrong chars", @in.Read() == (char)6
+                    && @in.Read() == (char)7);
+
+            @in = new BufferedCharFilter(new StringReader(new String(chars)), 12);
+            @in.Skip(6);
+            @in.Mark(8);
+            @in.Skip(7);
+            @in.Reset();
+
+            assertTrue("Wrong chars 2", @in.Read() == (char)6
+                    && @in.Read() == (char)7);
+
+            BufferedCharFilter br2 = new BufferedCharFilter(new StringReader("01234"), 2);
+            br2.Mark(3);
+            char[] carray = new char[3];
+            int result = br2.read(carray);
+            assertEquals(3, result);
+            assertEquals("Assert 0:", '0', carray[0]);
+            assertEquals("Assert 1:", '1', carray[1]);
+            assertEquals("Assert 2:", '2', carray[2]);
+            assertEquals("Assert 3:", '3', br2.Read());
+
+            br2 = new BufferedCharFilter(new StringReader("01234"), 2);
+            br2.Mark(3);
+            carray = new char[4];
+            result = br2.read(carray);
+            assertEquals("Assert 4:", 4, result);
+            assertEquals("Assert 5:", '0', carray[0]);
+            assertEquals("Assert 6:", '1', carray[1]);
+            assertEquals("Assert 7:", '2', carray[2]);
+            assertEquals("Assert 8:", '3', carray[3]);
+            assertEquals("Assert 9:", '4', br2.Read());
+            assertEquals("Assert 10:", -1, br2.Read());
+
+            BufferedCharFilter reader = new BufferedCharFilter(new StringReader("01234"));
+            reader.Mark(int.MaxValue);
+            reader.Read();
+            reader.Dispose();
+        }
+
+        /**
+         * @tests java.io.BufferedReader#markSupported()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_IsMarkSupported()
+        {
+            // Test for method boolean java.io.BufferedReader.markSupported()
+            br = new BufferedCharFilter(new StringReader(testString));
+            assertTrue("markSupported returned false", br.IsMarkSupported);
+        }
+
+        /**
+         * @tests java.io.BufferedReader#read()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_Read()
+        {
+            // Test for method int java.io.BufferedReader.read()
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                int r = br.Read();
+                assertTrue("Char read improperly", testString[0] == r);
+                br = new BufferedCharFilter(new StringReader(new String(
+                        new char[] { '\u8765' })));
+                assertTrue("Wrong double byte character", br.Read() == '\u8765');
+            }
+            catch (IOException e)
+            {
+                fail("Exception during read test");
+            }
+
+            char[] chars = new char[256];
+            for (int i = 0; i < 256; i++)
+                chars[i] = (char)i;
+            BufferedCharFilter @in = new BufferedCharFilter(new StringReader(new String(
+                chars)), 12);
+            try
+            {
+
+                assertEquals("Wrong initial char", 0, @in.Read()); // Fill the
+                                                                   // buffer
+                char[] buf = new char[14];
+                @in.Read(buf, 0, 14); // Read greater than the buffer
+
+                assertTrue("Wrong block read data", new String(buf)
+                        .equals(new String(chars, 1, 14)));
+
+                assertEquals("Wrong chars", 15, @in.Read()); // Check next byte
+            }
+            catch (IOException e)
+            {
+
+                fail("Exception during read test 2:" + e);
+            }
+
+            // regression test for HARMONY-841
+            assertTrue(new BufferedCharFilter(new StringReader(new string(new char[5], 1, 0)), 2).Read() == -1);
+        }
+
+        private class ReaderAnonymousInnerClassHelper : TextReader
+        {
+            private const int SIZE = 2;
+            private int size = SIZE, pos = 0;
+
+            private readonly char[] contents = new char[SIZE];
+
+            public override int Read()
+            {
+                if (pos >= size)
+                    throw new IOException("Read past end of data");
+                return contents[pos++];
+            }
+
+            public override int Read(char[] buf, int off, int len)
+            {
+                if (pos >= size)
+                    throw new IOException("Read past end of data");
+                int toRead = len;
+                if (toRead > (size - pos))
+                    toRead = size - pos;
+                System.Array.Copy(contents, pos, buf, off, toRead);
+                pos += toRead;
+                return toRead;
+            }
+
+            public bool Ready()
+            {
+                return size - pos > 0;
+            }
+
+#if !NETSTANDARD
+            public override void Close()
+            {
+            }
+#endif
+
+            protected override void Dispose(bool disposing)
+            {
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#read(char[], int, int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ReadCII()
+        {
+            char[] ca = new char[2];
+            BufferedCharFilter toRet = new BufferedCharFilter(new StreamReader(
+                new MemoryStream(new byte[0])));
+
+            /* Null buffer should throw NPE even when len == 0 */
+            try
+            {
+                toRet.Read(null, 1, 0);
+
+                fail("null buffer reading zero bytes should throw NPE");
+            }
+            catch (NullReferenceException e)
+            {
+                //expected
+            }
+
+            try
+            {
+                toRet.Dispose();
+            }
+            catch (IOException e)
+            {
+
+                fail("unexpected 1: " + e);
+            }
+
+            try
+            {
+                toRet.Read(null, 1, 0);
+
+                fail("null buffer reading zero bytes on closed stream should throw IOException");
+            }
+            catch (IOException e)
+            {
+                //expected
+            }
+
+            /* Closed reader should throw IOException reading zero bytes */
+            try
+            {
+                toRet.Read(ca, 0, 0);
+
+                fail("Reading zero bytes on a closed reader should not work");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+
+            /*
+             * Closed reader should throw IOException in preference to index out of
+             * bounds
+             */
+            try
+            {
+                // Read should throw IOException before
+                // ArrayIndexOutOfBoundException
+                toRet.Read(ca, 1, 5);
+
+                fail("IOException should have been thrown");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+
+            // Test to ensure that a drained stream returns 0 at EOF
+            toRet = new BufferedCharFilter(new StreamReader(
+
+                    new MemoryStream(new byte[2])));
+            try
+            {
+
+                assertEquals("Emptying the reader should return two bytes", 2,
+                        toRet.Read(ca, 0, 2));
+
+                // LUCENENET specific: end of stream should be 0 in .NET
+                assertEquals("EOF on a reader should be 0", 0, toRet.Read(ca, 0,
+                        2));
+                //assertEquals("EOF on a reader should be -1", -1, toRet.Read(ca, 0,
+                //        2));
+
+                assertEquals("Reading zero bytes at EOF should work", 0, toRet
+                        .Read(ca, 0, 0));
+            }
+            catch (IOException ex)
+            {
+
+                fail("Unexpected IOException : " + ex.ToString());
+            }
+
+            // Test for method int java.io.BufferedReader.read(char [], int, int)
+            try
+            {
+                char[] buf = new char[testString.Length];
+                br = new BufferedCharFilter(new StringReader(testString));
+                br.Read(buf, 50, 500);
+
+                assertTrue("Chars read improperly", new String(buf, 50, 500)
+                        .equals(testString.Substring(0, 500 - 0)));
+            }
+            catch (IOException e)
+            {
+
+                fail("Exception during read test");
+            }
+
+            BufferedCharFilter bufin = new BufferedCharFilter(new ReaderAnonymousInnerClassHelper());
+
+            //BufferedCharFilter bufin = new BufferedCharFilter(new Reader() {
+            //            int size = 2, pos = 0;
+
+            //char[] contents = new char[size];
+
+            //public int read() 
+            //{
+            //				if (pos >= size)
+            //					throw new IOException("Read past end of data");
+            //				return contents[pos++];
+            //			}
+
+            //			public int read(char[] buf, int off, int len) throws IOException
+            //{
+            //				if (pos >= size)
+            //					throw new IOException("Read past end of data");
+            //int toRead = len;
+            //				if (toRead > (size - pos))
+            //					toRead = size - pos;
+            //				System.arraycopy(contents, pos, buf, off, toRead);
+            //				pos += toRead;
+            //				return toRead;
+            //			}
+
+            //			public boolean ready() throws IOException
+            //{
+            //				return size - pos > 0;
+            //}
+
+            //public void close() 
+            //{
+            //}
+            //		});
+            try
+            {
+                bufin.Read();
+                int result = bufin.Read(new char[2], 0, 2);
+
+                assertTrue("Incorrect result: " + result, result == 1);
+            }
+            catch (IOException e)
+            {
+
+                fail("Unexpected: " + e);
+            }
+
+            //regression for HARMONY-831
+            try
+            {
+                new BufferedCharFilter(new StringReader(""), 9).Read(new char[] { }, 7, 0);
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+            }
+
+            // Regression for HARMONY-54
+            char[] ch = { };
+            BufferedCharFilter reader = new BufferedCharFilter(new StringReader(new string(ch)));
+            try
+            {
+                // Check exception thrown when the reader is open.
+                reader.Read(null, 1, 0);
+                fail("Assert 0: NullPointerException expected");
+            }
+            catch (NullReferenceException e)
+            {
+                // Expected
+            }
+
+            // Now check IOException is thrown in preference to
+            // NullPointerexception when the reader is closed.
+            reader.Dispose();
+            try
+            {
+                reader.Read(null, 1, 0);
+                fail("Assert 1: IOException expected");
+            }
+            catch (IOException e)
+            {
+                // Expected
+            }
+
+            try
+            {
+                // And check that the IOException is thrown before
+                // ArrayIndexOutOfBoundException
+                reader.Read(ch, 0, 42);
+                fail("Assert 2: IOException expected");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#read(char[], int, int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_Read_CII_Exception()
+        {
+            br = new BufferedCharFilter(new StringReader(testString));
+            char[] nullCharArray = null;
+            char[] charArray = testString.toCharArray();
+
+            try
+            {
+                br.Read(nullCharArray, -1, -1);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(nullCharArray, -1, 0);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(nullCharArray, 0, -1);
+
+                fail("should throw NullPointerException");
+            }
+            catch (NullReferenceException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(nullCharArray, 0, 0);
+
+                fail("should throw NullPointerException");
+            }
+            catch (NullReferenceException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(nullCharArray, 0, 1);
+
+                fail("should throw NullPointerException");
+            }
+            catch (NullReferenceException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(charArray, -1, -1);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(charArray, -1, 0);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                // expected
+            }
+
+            br.Read(charArray, 0, 0);
+            br.Read(charArray, 0, charArray.Length);
+            br.Read(charArray, charArray.Length, 0);
+
+            try
+            {
+                br.Read(charArray, charArray.Length + 1, 0);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                //expected
+            }
+
+            try
+            {
+                br.Read(charArray, charArray.Length + 1, 1);
+
+                fail("should throw IndexOutOfBoundsException");
+            }
+            catch (ArgumentOutOfRangeException e)
+            {
+                //expected
+            }
+
+            br.Dispose();
+
+            try
+            {
+                br.Read(nullCharArray, -1, -1);
+
+                fail("should throw IOException");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(charArray, -1, 0);
+
+                fail("should throw IOException");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+
+            try
+            {
+                br.Read(charArray, 0, -1);
+
+                fail("should throw IOException");
+            }
+            catch (IOException e)
+            {
+                // expected
+            }
+        }
+        /**
+         * @tests java.io.BufferedReader#readLine()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ReadLine()
+        {
+            // Test for method java.lang.String java.io.BufferedReader.readLine()
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                String r = br.ReadLine();
+                assertEquals("readLine returned incorrect string", "Test_All_Tests", r
+                        );
+            }
+            catch (IOException e)
+            {
+                fail("Exception during readLine test");
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#ready()
+         */
+        public void Test_Ready()
+        {
+            // Test for method boolean java.io.BufferedReader.ready()
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                assertTrue("ready returned false", br.Ready());
+            }
+            catch (IOException e)
+            {
+                fail("Exception during ready test" + e.toString());
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#reset()
+         */
+        public void Test_Reset()
+        {
+            // Test for method void java.io.BufferedReader.reset()
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                br.Skip(500);
+                br.Mark(900);
+                br.Skip(500);
+                br.Reset();
+                char[] buf = new char[testString.Length];
+                br.Read(buf, 0, 500);
+                assertTrue("Failed to reset properly", testString.Substring(500,
+                        1000 - 500).equals(new String(buf, 0, 500)));
+            }
+            catch (IOException e)
+            {
+                fail("Exception during reset test");
+            }
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                br.Skip(500);
+                br.Reset();
+                fail("Reset succeeded on unmarked stream");
+            }
+            catch (IOException x)
+            {
+                return;
+
+            }
+        }
+
+        [Test, LuceneNetSpecific]
+        public void Test_Reset_IOException()
+        {
+            int[]
+        expected = new int[] { '1', '2', '3', '4', '5', '6', '7', '8',
+                '9', '0', -1 };
+            br = new BufferedCharFilter(new StringReader("1234567890"), 9);
+            br.Mark(9);
+            for (int i = 0; i < 11; i++)
+            {
+                assertEquals(expected[i], br.Read());
+            }
+            try
+            {
+                br.Reset();
+                fail("should throw IOException");
+            }
+            catch (IOException e)
+            {
+                // Expected
+            }
+            for (int i = 0; i < 11; i++)
+            {
+                assertEquals(-1, br.Read());
+            }
+
+            br = new BufferedCharFilter(new StringReader("1234567890"));
+            br.Mark(10);
+            for (int i = 0; i < 10; i++)
+            {
+                assertEquals(expected[i], br.Read());
+            }
+            br.Reset();
+            for (int i = 0; i < 11; i++)
+            {
+                assertEquals(expected[i], br.Read());
+            }
+        }
+
+        /**
+         * @tests java.io.BufferedReader#skip(long)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_SkipJ()
+        {
+            // Test for method long java.io.BufferedReader.skip(long)
+            try
+            {
+                br = new BufferedCharFilter(new StringReader(testString));
+                br.Skip(500);
+                char[] buf = new char[testString.Length];
+                br.Read(buf, 0, 500);
+                assertTrue("Failed to set skip properly", testString.Substring(500,
+                        1000 - 500).equals(new String(buf, 0, 500)));
+            }
+            catch (IOException e)
+            {
+                fail("Exception during skip test");
+            }
+
+        }
+
+        /**
+         * Sets up the fixture, for example, open a network connection. This method
+         * is called before a test is executed.
+         */
+        public override void SetUp()
+        {
+        }
+
+        /**
+         * Tears down the fixture, for example, close a network connection. This
+         * method is called after a test is executed.
+         */
+        public override void TearDown()
+        {
+            try
+            {
+                br.Dispose();
+            }
+            catch (Exception e)
+            {
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f3ac940c/src/Lucene.Net.Tests.Analysis.Common/Lucene.Net.Tests.Analysis.Common.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Analysis.Common/Lucene.Net.Tests.Analysis.Common.csproj b/src/Lucene.Net.Tests.Analysis.Common/Lucene.Net.Tests.Analysis.Common.csproj
index 06ff0c5..0c6f911 100644
--- a/src/Lucene.Net.Tests.Analysis.Common/Lucene.Net.Tests.Analysis.Common.csproj
+++ b/src/Lucene.Net.Tests.Analysis.Common/Lucene.Net.Tests.Analysis.Common.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 
  Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,6 @@
  under the License.
 
 -->
-
 <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
@@ -322,6 +321,7 @@
     <Compile Include="Analysis\Util\BaseTokenStreamFactoryTestCase.cs" />
     <Compile Include="Analysis\Util\StringMockResourceLoader.cs" />
     <Compile Include="Analysis\Util\TestAnalysisSPILoader.cs" />
+    <Compile Include="Analysis\Util\TestBufferedCharFilter.cs" />
     <Compile Include="Analysis\Util\TestCharacterUtils.cs" />
     <Compile Include="Analysis\Util\TestCharArrayIterator.cs" />
     <Compile Include="Analysis\Util\TestCharArrayMap.cs" />
@@ -487,4 +487,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>
\ No newline at end of file


Mime
View raw message