Merge pull request #112 from phantamanta44/master

Allow multi-byte characters in payload
This commit is contained in:
Samuel Carlsson 2018-12-25 19:15:22 +01:00 committed by GitHub
commit 4546c0583f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 4 deletions

View File

@ -19,8 +19,9 @@ public class SyncTransport {
public void send(String syncCommand, String name) throws IOException {
if (syncCommand.length() != 4) throw new IllegalArgumentException("sync commands must have length 4");
output.writeBytes(syncCommand);
output.writeInt(Integer.reverseBytes(name.length()));
output.writeBytes(name);
byte[] data = name.getBytes(StandardCharsets.UTF_8);
output.writeInt(Integer.reverseBytes(data.length));
output.write(data);
}
public void sendStatus(String statusCode, int length) throws IOException {
@ -50,6 +51,21 @@ public class SyncTransport {
return new String(buffer, StandardCharsets.UTF_8);
}
public void sendDirectoryEntry(RemoteFile file) throws IOException {
output.writeBytes("DENT");
output.writeInt(Integer.reverseBytes(0666 | (file.isDirectory() ? (1 << 14) : 0)));
output.writeInt(Integer.reverseBytes(file.getSize()));
output.writeInt(Integer.reverseBytes(Long.valueOf(file.getLastModified()).intValue()));
byte[] pathChars = file.getPath().getBytes(StandardCharsets.UTF_8);
output.writeInt(Integer.reverseBytes(pathChars.length));
output.write(pathChars);
}
public void sendDirectoryEntryDone() throws IOException {
output.writeBytes("DONE");
output.writeBytes("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); // equivalent to the length of a "normal" dent
}
public RemoteFileRecord readDirectoryEntry() throws IOException {
String id = readString(4);
int mode = readInt();

View File

@ -7,6 +7,7 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
/**
* Created by vidstige on 20/03/14.
@ -19,4 +20,6 @@ public interface AdbDeviceResponder {
void filePulled(RemoteFile path, ByteArrayOutputStream buffer) throws JadbException, IOException;
void shell(String command, DataOutputStream stdout, DataInput stdin) throws IOException;
List<RemoteFile> list(String path) throws IOException;
}

View File

@ -175,6 +175,8 @@ class AdbProtocolHandler implements Runnable {
syncSend(output, input, length);
} else if ("RECV".equals(id)) {
syncRecv(output, input, length);
} else if ("LIST".equals(id)) {
syncList(output, input, length);
} else throw new JadbException("Unknown sync id " + id);
} catch (JadbException e) { // sync response with a different type of fail message
SyncTransport sync = getSyncTransport(output, input);
@ -207,6 +209,15 @@ class AdbProtocolHandler implements Runnable {
transport.sendStatus("OKAY", 0); // 0 = ignored
}
private void syncList(DataOutput output, DataInput input, int length) throws IOException, JadbException {
String remotePath = readString(input, length);
SyncTransport transport = getSyncTransport(output, input);
for (RemoteFile file : selected.list(remotePath)) {
transport.sendDirectoryEntry(file);
}
transport.sendDirectoryEntryDone();
}
private String getCommandLength(String command) {
return String.format("%04x", command.length());
}

View File

@ -13,6 +13,7 @@ import java.io.IOException;
import java.net.ProtocolException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -86,6 +87,10 @@ public class FakeAdbServer implements AdbResponder {
return findBySerial(serial).expectShell(commands);
}
public DeviceResponder.ListExpectation expectList(String serial, String remotePath) {
return findBySerial(serial).expectList(remotePath);
}
@Override
public List<AdbDeviceResponder> getDevices() {
return new ArrayList<AdbDeviceResponder>(devices);
@ -96,6 +101,7 @@ public class FakeAdbServer implements AdbResponder {
private final String type;
private List<FileExpectation> fileExpectations = new ArrayList<>();
private List<ShellExpectation> shellExpectations = new ArrayList<>();
private List<ListExpectation> listExpectations = new ArrayList<>();
private DeviceResponder(String serial, String type) {
this.serial = serial;
@ -150,9 +156,21 @@ public class FakeAdbServer implements AdbResponder {
throw new ProtocolException("Unexpected shell to device " + serial + ": " + command);
}
@Override
public List<RemoteFile> list(String path) throws IOException {
for (ListExpectation le : listExpectations) {
if (le.matches(path)) {
listExpectations.remove(le);
return le.getFiles();
}
}
throw new ProtocolException("Unexpected list of device " + serial + " in dir " + path);
}
public void verifyExpectations() {
org.junit.Assert.assertEquals(0, fileExpectations.size());
org.junit.Assert.assertEquals(0, shellExpectations.size());
org.junit.Assert.assertEquals(0, listExpectations.size());
}
private static class FileExpectation implements ExpectationBuilder {
@ -161,7 +179,6 @@ public class FakeAdbServer implements AdbResponder {
private String failMessage;
public FileExpectation(RemoteFile path) {
this.path = path;
content = null;
failMessage = null;
@ -220,6 +237,62 @@ public class FakeAdbServer implements AdbResponder {
}
}
public static class ListExpectation {
private final String remotePath;
private final List<RemoteFile> files = new ArrayList<>();
public ListExpectation(String remotePath) {
this.remotePath = remotePath;
}
public boolean matches(String remotePath) {
return remotePath.equals(this.remotePath);
}
public ListExpectation withFile(String path, int size, long modifyTime) {
files.add(new MockFileEntry(path, size, modifyTime, false));
return this;
}
public ListExpectation withDir(String path, long modifyTime) {
files.add(new MockFileEntry(path, -1, modifyTime, true));
return this;
}
public List<RemoteFile> getFiles() {
return Collections.unmodifiableList(files);
}
private static class MockFileEntry extends RemoteFile {
private final int size;
private final long modifyTime;
private final boolean dir;
MockFileEntry(String path, int size, long modifyTime, boolean dir) {
super(path);
this.size = size;
this.modifyTime = modifyTime;
this.dir = dir;
}
public int getSize() {
return size;
}
public long getLastModified() {
return modifyTime;
}
public boolean isDirectory() {
return dir;
}
}
}
public ExpectationBuilder expectPush(RemoteFile path) {
FileExpectation expectation = new FileExpectation(path);
fileExpectations.add(expectation);
@ -237,5 +310,11 @@ public class FakeAdbServer implements AdbResponder {
shellExpectations.add(expectation);
return expectation;
}
public ListExpectation expectList(String remotePath) {
ListExpectation expectation = new ListExpectation(remotePath);
listExpectations.add(expectation);
return expectation;
}
}
}

View File

@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
public class MockedTestCases {
@ -117,8 +118,59 @@ public class MockedTestCases {
device.executeShell("echo", "newline2\r\nstring");
}
private long parseDate(String date) throws ParseException {
@Test
public void testFileList() throws Exception {
server.add("serial-123");
server.expectList("serial-123", "/sdcard/Documents")
.withDir("school", 123456789L)
.withDir("finances", 7070707L)
.withDir("\u904A\u6232", 528491L)
.withFile("user_manual.pdf", 3000, 648649L)
.withFile("effective java vol. 7.epub", 0xCAFE, 0xBABEL)
.withFile("\uB9AC\uADF8 \uC624\uBE0C \uB808\uC804\uB4DC", 240, 9001L);
JadbDevice device = connection.getDevices().get(0);
List<RemoteFile> files = device.list("/sdcard/Documents");
Assert.assertEquals(6, files.size());
assertHasDir("school", 123456789L, files);
assertHasDir("finances", 7070707L, files);
assertHasDir("\u904A\u6232", 528491L, files);
assertHasFile("user_manual.pdf", 3000, 648649L, files);
assertHasFile("effective java vol. 7.epub", 0xCAFE, 0xBABEL, files);
assertHasFile("\uB9AC\uADF8 \uC624\uBE0C \uB808\uC804\uB4DC", 240, 9001L, files);
}
private static long parseDate(String date) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
return dateFormat.parse(date).getTime();
}
private static void assertHasFile(String expPath, int expSize, long expModifyTime, List<RemoteFile> actualFiles) {
for (RemoteFile file : actualFiles) {
if (expPath.equals(file.getPath())) {
if (file.isDirectory()) {
Assert.fail("File " + expPath + " was listed as a dir!");
} else if (expSize != file.getSize() || expModifyTime != file.getLastModified()) {
Assert.fail("File " + expPath + " exists but has incorrect properties!");
} else {
return;
}
}
}
Assert.fail("File " + expPath + " could not be found!");
}
private static void assertHasDir(String expPath, long expModifyTime, List<RemoteFile> actualFiles) {
for (RemoteFile file : actualFiles) {
if (expPath.equals(file.getPath())) {
if (!file.isDirectory()) {
Assert.fail("Dir " + expPath + " was listed as a file!");
} else if (expModifyTime != file.getLastModified()) {
Assert.fail("Dir " + expPath + " exists but has incorrect properties!");
} else {
return;
}
}
}
Assert.fail("Dir " + expPath + " could not be found!");
}
}