Add Reader and StringReader emulation.
Change-Id: Ib382e5d1605e56a37b6dca6703016591f5a06c63
Review-Link: https://gwt-review.googlesource.com/#/c/20680/
diff --git a/user/super/com/google/gwt/emul/java/io/Reader.java b/user/super/com/google/gwt/emul/java/io/Reader.java
new file mode 100644
index 0000000..5413799
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/io/Reader.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Licensed 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.
+ */
+package java.io;
+
+/**
+ * Reads a stream of characters.
+ */
+public abstract class Reader {
+ /**
+ * The maximum buffer size to incrementally read in {@link #skip}.
+ */
+ private static final int MAX_SKIP_BUFFER_SIZE = 1024;
+
+ /**
+ * Closes the reader, and releases any associated resources.
+ */
+ public abstract void close() throws IOException;
+
+ /**
+ * Marks the present position in the stream. Until {@code readAheadLimit} more
+ * characters have been read, the current point in the stream will be stored
+ * as the mark. Calls to {@link #reset} will reposition the point in the
+ * stream to the mark.
+ *
+ * @throws IOException If the stream does not support mark().
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException("Not supported");
+ }
+
+ /**
+ * Returns whether {@link #mark} is implemented.
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+ /**
+ * Reads a single character, or -1 if we are at the end of the stream.
+ */
+ public int read() throws IOException {
+ char chr[] = new char[1];
+ return (read(chr) == -1) ? -1 : chr[0];
+ }
+
+ /**
+ * Attempts to fill {@code buf} with characters up to the size of the array.
+ */
+ public int read(char[] buf) {
+ return read(buf, 0, buf.length);
+ }
+
+ /**
+ * Attempts to fill {@code buf} with up to {@code len} characters. Characters
+ * will be stored in {@code buf} starting at index {@code off}.
+ */
+ public abstract int read(char[] buf, int off, int len);
+
+ /**
+ * Returns whether the stream is ready for reading characters.
+ */
+ public boolean ready() throws IOException {
+ return false;
+ }
+
+ /**
+ * Attempts to reset the stream to the previous mark.
+ */
+ public void reset() throws IOException {
+ throw new IOException("Not supported");
+ }
+
+ /**
+ * Skips {@code n} characters, returning the number of characters that were actually skipped.
+ */
+ public long skip(long n) throws IOException {
+ long remaining = n;
+ int bufferSize = Math.min((int) n, MAX_SKIP_BUFFER_SIZE);
+ char[] skipBuffer = new char[bufferSize];
+ while (remaining > 0) {
+ long numRead = read(skipBuffer, 0, (int) remaining);
+ if (numRead < 0) {
+ break;
+ }
+ remaining -= numRead;
+ }
+ return n - remaining;
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/io/StringReader.java b/user/super/com/google/gwt/emul/java/io/StringReader.java
new file mode 100644
index 0000000..08d3241
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/io/StringReader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Licensed 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.
+ */
+package java.io;
+
+/**
+ * Reads characters from a string.
+ */
+public class StringReader extends Reader {
+ private final String text;
+ private int position;
+
+ /**
+ * Constructs a reader which will read from the given string.
+ */
+ public StringReader(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public void close() throws IOException { }
+
+ /**
+ * Reads up to the specified number of characters from the string.
+ */
+ @Override
+ public int read(char[] buf, int off, int readLength) {
+ if (position >= text.length()) {
+ return -1;
+ }
+ int length = Math.min(text.length() - position, readLength);
+ text.getChars(position, position + length, buf, off);
+ position += length;
+ return length;
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/io/StringReaderTest.java b/user/test/com/google/gwt/emultest/java/io/StringReaderTest.java
new file mode 100644
index 0000000..c9d79de
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/io/StringReaderTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Licensed 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.
+ */
+package com.google.gwt.emultest.java.io;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.io.StringReader;
+import java.util.Arrays;
+
+/**
+ * Unit test for the {@link java.io.StringReader} emulated class.
+ */
+public class StringReaderTest extends GWTTestCase {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ public void testEmptyString() throws Exception {
+ StringReader reader = new StringReader("");
+ assertEquals(-1, reader.read());
+ char[] buf = new char[5];
+ assertEquals(-1, reader.read(buf));
+ assertEquals(-1, reader.read(buf, 2, 0));
+ }
+
+ public void testString() throws Exception {
+ StringReader reader = new StringReader("The q\u00DCuick brown fox jumped over the lazy dog");
+ assertEquals('T', reader.read());
+
+ char[] buf = new char[10];
+ assertEquals(6, reader.read(buf, 3, 6));
+ assertEquals("\u0000\u0000\u0000he q\u00DCi\u0000", String.valueOf(buf));
+
+ assertEquals('k', reader.read());
+ assertEquals(' ', reader.read());
+
+ assertEquals(2, reader.read(buf, 0, 2));
+ // First 2 characters now filled.
+ assertEquals("br\u0000he q\u00DCi\u0000", String.valueOf(buf));
+
+ assertEquals(10, reader.read(buf));
+ assertEquals("own fox ju", String.valueOf(buf));
+
+ char[] four = new char[4];
+ assertEquals(4, reader.read(four));
+ assertEquals("mped", String.valueOf(four));
+
+ char[] emptyBuf = new char[0];
+ assertEquals(0, reader.read(emptyBuf));
+
+ assertEquals(10, reader.read(buf));
+ assertEquals(" over the ", String.valueOf(buf));
+
+ char[] eight = new char[8];
+ assertEquals(7, reader.read(eight));
+ assertEquals("lazy dog\u0000", String.valueOf(eight));
+
+ assertEquals(-1, reader.read());
+ assertEquals(-1, reader.read(eight));
+ assertEquals(-1, reader.read(eight, 0, 0));
+ assertEquals(-1, reader.read(eight, 0, 1));
+ }
+
+ public void testSkip_stringOverBufferSize() throws Exception {
+ StringReader reader = new StringReader(repeat('x', 1025));
+
+ assertEquals(1025, reader.skip(2000));
+
+ assertEquals(-1, reader.read());
+ }
+
+ public void testSkip_longString() throws Exception {
+ int n = 10000;
+ char[] arr = new char[n];
+ for (char i = 0; i < n; i++) {
+ arr[i] = i;
+ }
+
+ StringReader reader = new StringReader(String.valueOf(arr));
+ assertEquals(5000, reader.skip(5000));
+ assertEquals(5000, reader.read());
+ assertEquals(5001, reader.read());
+
+ assertEquals(4000, reader.skip(4000));
+ assertEquals(9002, reader.read());
+
+ assertEquals(997, reader.skip(4000));
+ assertEquals(-1, reader.read());
+ }
+
+ private static String repeat(char c, int count) {
+ char[] arr = new char[count];
+ Arrays.fill(arr, c);
+ return String.valueOf(arr);
+ }
+}