From: <cr...@us...> - 2008-09-03 10:43:57
|
Revision: 4535 http://jnode.svn.sourceforge.net/jnode/?rev=4535&view=rev Author: crawley Date: 2008-09-03 10:43:53 +0000 (Wed, 03 Sep 2008) Log Message: ----------- Bug fixes + extended unit tests for ReaderInputStream Modified Paths: -------------- trunk/shell/src/shell/org/jnode/shell/io/ReaderInputStream.java trunk/shell/src/test/org/jnode/test/shell/io/ReaderInputStreamTest.java Modified: trunk/shell/src/shell/org/jnode/shell/io/ReaderInputStream.java =================================================================== --- trunk/shell/src/shell/org/jnode/shell/io/ReaderInputStream.java 2008-09-03 10:42:12 UTC (rev 4534) +++ trunk/shell/src/shell/org/jnode/shell/io/ReaderInputStream.java 2008-09-03 10:43:53 UTC (rev 4535) @@ -1,3 +1,23 @@ +/* + * $Id: ThreadCommandInvoker.java 3374 2007-08-02 18:15:27Z lsantha $ + * + * JNode.org + * Copyright (C) 2007 JNode.org + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ package org.jnode.shell.io; import java.io.IOException; @@ -27,7 +47,7 @@ @Override public synchronized int read() throws IOException { if (bytes.remaining() == 0) { - if (!fillBuffer(true)) { + if (fillBuffer(true) == -1) { return -1; } } @@ -42,19 +62,19 @@ // This implementation is simple-minded. I'm sure we could recode it to avoid // the 'bytes.get' copying step if we thought about it. int count = 0; - while (count < len) { + do { if (bytes.remaining() == 0) { - if (!fillBuffer(count == 0)) { - return count == 0 ? -1 : count; + int nosRead = fillBuffer(count == 0); + if (nosRead <= 0) { + return count > 0 ? count : -1; } } - int copied = Math.min(bytes.remaining(), len); - bytes.get(b, off, copied); - System.err.println("Copied " + copied); - count += copied; - len -= copied; - off += copied; - } + int toCopy = Math.min(bytes.remaining(), len); + bytes.get(b, off, toCopy); + count += toCopy; + len -= toCopy; + off += toCopy; + } while (count < len); return count; } @@ -69,33 +89,39 @@ * would have blocked or because it returned <code>-1</code>. * * @param wait if <code>true</code> allow the reader to block. - * @return <code>true</code> if we've added some data to 'bytes'. + * @return the number of bytes added; <code>-1</code> if none were added + * and the reader is at the EOF. * @throws IOException */ - private boolean fillBuffer(boolean wait) throws IOException { + private int fillBuffer(boolean wait) throws IOException { bytes.clear(); // The loop is necessary because the way that the encoder has to deal - // with UTF-16 surrogate pairs. If the one and only character returned - // by the reader is the first char of a surrogate pair, the encoder won't - // (can't) put anything into the 'bytes' buffer. So if 'wait' is true, - // we must go around a second time to get the second character of the - // surrogate pair. + // with UTF-16 surrogate pairs. + CoderResult cr = null; + int count; do { - CoderResult cr; - if (chars.remaining() == 0) { - chars.clear(); - if (!reader.ready() && !wait) { - bytes.flip(); - return false; + if (chars.remaining() == 0 || cr == CoderResult.UNDERFLOW) { + if (chars.remaining() == 0) { + if (!reader.ready() && !wait) { + bytes.flip(); + return 0; + } + chars.clear(); + } else { + char[] tmp = new char[chars.remaining()]; + chars.get(tmp); + chars.clear(); + chars.put(tmp); } if (reader.read(chars) == -1) { - System.err.println("Reached EOF"); - bytes.flip(); + chars.flip(); cr = encoder.encode(chars, bytes, true); if (cr.isError()) { cr.throwException(); } - return bytes.remaining() > 0; + count = bytes.position(); + bytes.flip(); + return count > 0 ? count : -1; } chars.flip(); } @@ -103,8 +129,9 @@ if (cr.isError()) { cr.throwException(); } - } while (wait && bytes.position() == 0); + count = bytes.position(); + } while (wait && count == 0); bytes.flip(); - return true; + return count; } } Modified: trunk/shell/src/test/org/jnode/test/shell/io/ReaderInputStreamTest.java =================================================================== --- trunk/shell/src/test/org/jnode/test/shell/io/ReaderInputStreamTest.java 2008-09-03 10:42:12 UTC (rev 4534) +++ trunk/shell/src/test/org/jnode/test/shell/io/ReaderInputStreamTest.java 2008-09-03 10:43:53 UTC (rev 4535) @@ -1,9 +1,31 @@ +/* + * $Id: ThreadCommandInvoker.java 3374 2007-08-02 18:15:27Z lsantha $ + * + * JNode.org + * Copyright (C) 2007 JNode.org + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ package org.jnode.test.shell.io; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.nio.charset.MalformedInputException; import java.nio.charset.UnmappableCharacterException; import org.jnode.shell.io.ReaderInputStream; @@ -93,7 +115,7 @@ assertEquals((byte) i, buffer[i]); } } - + public void testBadLatin1All() throws Exception { char[] chars = new char[257]; for (int i = 0; i < 257; i++) { @@ -110,4 +132,161 @@ // expected } } + + public void testUnicode() throws Exception { + char[] chars = new char[1024]; + for (int i = 0; i < 1024; i++) { + chars[i] = (char) i; + } + final String LINE = new String(chars); + Reader r = new StringReader(LINE); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + char[] buffer = new char[1024]; + isr.read(buffer); + for (int i = 0; i < 1024; i++) { + assertEquals(chars[i], buffer[i]); + } + } + + public void testUnicode2() throws Exception { + char[] chars = new char[]{'\ud800', '\udc00'}; + final String LINE = new String(chars); + Reader r = new StringReader(LINE); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + assertEquals(chars[0], isr.read()); + assertEquals(chars[1], isr.read()); + } + + public void testBadUnicode() throws Exception { + char[] chars = new char[]{'\ud800'}; + final String LINE = new String(chars); + Reader r = new StringReader(LINE); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + public void testBadUnicode2() throws Exception { + char[] chars = new char[]{'a', '\ud800'}; + final String LINE = new String(chars); + Reader r = new StringReader(LINE); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + assertEquals(chars[0], isr.read()); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + public void testBadUnicode3() throws Exception { + char[] chars = new char[]{'\udc00'}; + final String LINE = new String(chars); + Reader r = new StringReader(LINE); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + public void testUnicode3() throws Exception { + char[] chars = new char[]{'\ud800', '\udc00'}; + final String LINE = new String(chars); + Reader r = new OneCharAtATimeReader(new StringReader(LINE)); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + assertEquals(chars[0], isr.read()); + assertEquals(chars[1], isr.read()); + } + + public void testBadUnicode4() throws Exception { + char[] chars = new char[]{'\ud800'}; + final String LINE = new String(chars); + Reader r = new OneCharAtATimeReader(new StringReader(LINE)); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + public void testBadUnicode5() throws Exception { + char[] chars = new char[]{'a', '\ud800'}; + final String LINE = new String(chars); + Reader r = new OneCharAtATimeReader(new StringReader(LINE)); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + assertEquals(chars[0], isr.read()); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + public void testBadUnicode6() throws Exception { + char[] chars = new char[]{'\udc00'}; + final String LINE = new String(chars); + Reader r = new OneCharAtATimeReader(new StringReader(LINE)); + ReaderInputStream ris = new ReaderInputStream(r, "UTF-8"); + InputStreamReader isr = new InputStreamReader(ris); + try { + isr.read(); + fail("No exception raised"); + } catch (MalformedInputException ex) { + // expected + } + } + + /** + * This wrapper class delivers characters from a Reader one at a time, no matter + * what the client asks for. + */ + private class OneCharAtATimeReader extends Reader { + + private Reader reader; + + public OneCharAtATimeReader(Reader reader) { + this.reader = reader; + } + + @Override + public void close() throws IOException { + this.reader.close(); + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + if (off < 0 || off > cbuf.length || len < 0 || off + len > cbuf.length || off + len < 0) { + throw new IndexOutOfBoundsException(); + } + if (len == 0) { + return 0; + } + int ch = reader.read(); + if (ch == -1) { + return -1; + } else { + cbuf[off] = (char) ch; + return 1; + } + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |