I'm writing an app to let me interact and debug my android over USB using the android SDK and the ADB command. I create a Process with redirected input and output streams and basically run "ADB shell", and I want to be able to wait for the prompt, enter commands and parse the results.
Here's a sample running ps
and getting the results:
CreateProcess("shell");
string data = await ReadToPrompt(":/ $ ");
_Process.StandardInput.WriteLine("ps");
string echo = await ReadLine(); // my command echoed back
string dataAndPrompt = await ReadToPrompt(":/ $ ");
It works (although I'm getting extra CR in the byte stream, CR/LF is coming as CR/CF/LF), but I can't help but wonder if there's a better way than what I have:
Process _Process;
MemoryStream _Remaining; // bytes left after ReadToPrompt
byte[] _Buffer = new byte[0x10000];
public async Task<string> ReadLine()
{
return await ReadToPrompt("\r\n");
}
public async Task<string> ReadToPrompt(string prompt)
{
MemoryStream ms = _Remaining == null ? new MemoryStream() : _Remaining;
int promptSize = prompt.Length;
int pos = 0;
while (true)
{
// read what we can from the process's standard output
int count = await _Process.StandardOutput.BaseStream.ReadAsync(_Buffer, 0, _Buffer.Length);
ms.Write(_Buffer, 0, count); // write new data to memory stream
// convert all new bytes to check for prompt
string testString = Encoding.ASCII.GetString(ms.GetBuffer(), pos, (int)(ms.Position - pos));
int promptPos = testString.IndexOf(prompt);
if (promptPos > 0)
{
// we found it, result is up to and including prompt
int stripLength = pos + promptPos + promptSize;
string result = Encoding.ASCII.GetString(ms.GetBuffer(), 0, stripLength);
// store remaining data in a MemoryStream for the next call
_Remaining = new MemoryStream();
_Remaining.Write(ms.GetBuffer(), stripLength, (int)(ms.Position - stripLength));
return result.Replace("\r\r", "\r");
}
// we didn't find it but we know it isn't in what we got, so move first position
// to check to the position - promptSize
pos = (int)(ms.Position - promptSize);
pos = (pos < 0) ? 0 : pos;
}
}
Is there something I can reliably do to keep from creating new MemoryStream
s? For instance, could I do an array copy on MemoryStream.GetBuffer()
to itself and use MemoryStream.SetLength()
? Is there an entirely better way to do it than using async and await?