diff --git a/src/se/vidstige/jadb/AdbFilterInputStream.java b/src/se/vidstige/jadb/AdbFilterInputStream.java new file mode 100644 index 0000000..49ced53 --- /dev/null +++ b/src/se/vidstige/jadb/AdbFilterInputStream.java @@ -0,0 +1,42 @@ +package se.vidstige.jadb; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class AdbFilterInputStream extends FilterInputStream { + public AdbFilterInputStream(InputStream inputStream) { + super(inputStream); + } + + @Override + public int read() throws IOException { + int b1 = in.read(); + if (b1 == 0x0d) { + in.mark(1); + int b2 = in.read(); + if (b2 == 0x0a) { + return b2; + } + in.reset(); + } + return b1; + } + + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + int n = 0; + for (int i = 0; i < length; i++) { + int b = read(); + if (b == -1) return n == 0 ? -1 : n; + buffer[offset + n] = (byte) b; + n++; + } + return n; + } + + @Override + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } +} diff --git a/src/se/vidstige/jadb/JadbDevice.java b/src/se/vidstige/jadb/JadbDevice.java index d86d3ae..823c4eb 100644 --- a/src/se/vidstige/jadb/JadbDevice.java +++ b/src/se/vidstige/jadb/JadbDevice.java @@ -45,11 +45,7 @@ public class JadbDevice { return transport.readString(); } - public void executeShell(String command, String... args) throws IOException, JadbException { - executeShell(null, command, args); - } - - public void executeShell(OutputStream stdout, String command, String... args) throws IOException, JadbException { + public InputStream executeShell(String command, String... args) throws IOException, JadbException { Transport transport = getTransport(); StringBuilder shellLine = new StringBuilder(command); for (String arg : args) { @@ -59,9 +55,23 @@ public class JadbDevice { shellLine.append(arg); } send(transport, "shell:" + shellLine.toString()); - if (stdout != null) { - transport.readResponseTo(new AdbFilterOutputStream(stdout)); + return new AdbFilterInputStream(new BufferedInputStream(transport.getInputStream())); + } + + public void executeShell(OutputStream output, String command, String... args) throws IOException, JadbException { + Transport transport = getTransport(); + StringBuilder shellLine = new StringBuilder(command); + for (String arg : args) { + shellLine.append(" "); + // TODO: throw if arg contains double quote + // TODO: quote arg if it contains space + shellLine.append(arg); } + send(transport, "shell:" + shellLine.toString()); + if (output != null) { + transport.readResponseTo(new AdbFilterOutputStream(output)); + } + //return AdbFilterInputStream(transport.getInputStream()); } public List list(String remotePath) throws IOException, JadbException { diff --git a/src/se/vidstige/jadb/Stream.java b/src/se/vidstige/jadb/Stream.java new file mode 100644 index 0000000..db807db --- /dev/null +++ b/src/se/vidstige/jadb/Stream.java @@ -0,0 +1,16 @@ +package se.vidstige.jadb; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class Stream { + public static void copy(InputStream in, OutputStream out) throws IOException { + byte[] buffer = new byte[1024 * 10]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + } + +} diff --git a/src/se/vidstige/jadb/Transport.java b/src/se/vidstige/jadb/Transport.java index f7d0dfb..701c9de 100644 --- a/src/se/vidstige/jadb/Transport.java +++ b/src/se/vidstige/jadb/Transport.java @@ -24,17 +24,12 @@ class Transport { return readString(length); } - - private static void copy(InputStream in, OutputStream out) throws IOException { - byte[] buffer = new byte[1024 * 10]; - int len; - while ((len = in.read(buffer)) != -1) { - out.write(buffer, 0, len); - } + public void readResponseTo(OutputStream output) throws IOException { + Stream.copy(inputStream, output); } - public void readResponseTo(OutputStream output) throws IOException { - copy(inputStream, output); + public InputStream getInputStream() { + return inputStream; } public void verifyResponse() throws IOException, JadbException { diff --git a/test/se/vidstige/jadb/test/AdbInputStreamFixture.java b/test/se/vidstige/jadb/test/AdbInputStreamFixture.java new file mode 100644 index 0000000..37aa4b2 --- /dev/null +++ b/test/se/vidstige/jadb/test/AdbInputStreamFixture.java @@ -0,0 +1,46 @@ +package se.vidstige.jadb.test; + +import org.junit.Assert; +import org.junit.Test; +import se.vidstige.jadb.AdbFilterInputStream; +import se.vidstige.jadb.Stream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class AdbInputStreamFixture { + + private byte[] passthrough(byte[] input) throws IOException { + ByteArrayInputStream inputStream = new ByteArrayInputStream(input); + InputStream sut = new AdbFilterInputStream(inputStream); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Stream.copy(sut, output); + return output.toByteArray(); + } + + @Test + public void testSimple() throws Exception { + byte[] actual = passthrough(new byte[]{ 1, 2, 3}); + Assert.assertArrayEquals(new byte[]{ 1, 2, 3}, actual); + } + + @Test + public void testEmpty() throws Exception { + byte[] actual = passthrough(new byte[]{}); + Assert.assertArrayEquals(new byte[]{}, actual); + } + + @Test + public void testSimpleRemoval() throws Exception { + byte[] actual = passthrough(new byte[]{0x0d, 0x0a}); + Assert.assertArrayEquals(new byte[]{0x0a}, actual); + } + + @Test + public void testDoubleRemoval() throws Exception { + byte[] actual = passthrough(new byte[]{0x0d, 0x0a, 0x0d, 0x0a}); + Assert.assertArrayEquals(new byte[]{0x0a, 0x0a}, actual); + } +} diff --git a/test/se/vidstige/jadb/test/RealDeviceTestCases.java b/test/se/vidstige/jadb/test/RealDeviceTestCases.java index f36c746..64687a7 100644 --- a/test/se/vidstige/jadb/test/RealDeviceTestCases.java +++ b/test/se/vidstige/jadb/test/RealDeviceTestCases.java @@ -8,6 +8,7 @@ import se.vidstige.jadb.*; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.List; public class RealDeviceTestCases { @@ -96,7 +97,13 @@ public class RealDeviceTestCases { @Test public void testScreenshot() throws Exception { JadbDevice any = jadb.getAnyDevice(); - FileOutputStream outputStream = new FileOutputStream(new File("screenshot.png")); - any.executeShell(outputStream, "screencap", "-p"); + FileOutputStream outputStream = null; + try { + outputStream = new FileOutputStream(new File("screenshot.png")); + InputStream stdout = any.executeShell("screencap", "-p"); + Stream.copy(stdout, outputStream); + } finally { + if (outputStream != null) outputStream.close(); + } } }