import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* An implementation of a {@link Console} based in the execution of shell commands.<br/>
ByteArrayOutputStream mSbErr = null;
private final SecureRandom mRandom;
- private String mStartControlPattern;
- private String mEndControlPattern;
+
+ private ControlPatternInfo mControlPattern = new ControlPatternInfo();
+ private static class ControlPatternInfo {
+ String mStartId1, mStartId2;
+ String mEndId1, mEndId2;
+ byte[] mStartControlBytes;
+ int mEndControlLength;
+
+ public void setNewPattern(String s1, String s2, String e1, String e2) {
+ mStartId1 = s1;
+ mStartId2 = s2;
+ mEndId1 = e1;
+ mEndId2 = e2;
+ mStartControlBytes = (mStartId1 + "0" + mStartId2).getBytes();
+ mEndControlLength = mEndId1.length() + mEndId2.length() + 3; // leave 3 for exit code;
+ }
+
+ public byte[] getStartControlPatternBytes() {
+ return mStartControlBytes;
+ }
+
+ public int getEndControlPatternLength() {
+ return mEndControlLength;
+ }
+
+ public int[] getEndControlMatch(byte[] bytes) {
+ return getEndControlMatch(bytes, false);
+ }
+
+ /**
+ * Find end control pattern indices
+ * @param bytes byte array to check against
+ * @param getExitIndices if true, this method will return the indices of the values
+ * in between the end control pattern (e.g. exit code), otherwise
+ * it will return the start and end indices of the whole end pattern
+ * @return if {@code getExitIndices} is false, See {@link #findControlPattern(byte[], byte[])}
+ * otherwise it will return values as described in {@code getExitIndices}
+ */
+ public int[] getEndControlMatch(byte[] bytes, boolean getExitIndices) {
+ // in the end control pattern, we check for endId1, 1-3 chars for exit code, endId2
+ int start, end;
+
+ final int[] end1PatternResult = findControlPattern(bytes, mEndId1.getBytes());
+ if (end1PatternResult != null) {
+ start = end1PatternResult[0];
+
+ final int[] end2PatternResult = findControlPattern(bytes, mEndId2.getBytes());
+ if (end2PatternResult != null) {
+ if (getExitIndices) {
+ return new int[]{end1PatternResult[1], end2PatternResult[0]};
+ }
+
+ end = end2PatternResult[1];
+ return new int[]{start, end};
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find the start control pattern indices
+ * @param bytes to check against
+ * @return See {@link #findControlPattern(byte[], byte[])}
+ */
+ public int[] getStartControlMatch(byte[] bytes) {
+ return findControlPattern(bytes, getStartControlPatternBytes());
+ }
+
+ /**
+ * Checks whether {@code controlBytes} exists inside of {@code bytes} and returns the start
+ * and end indices if it does. Returns null otherwise.
+ *
+ * @param bytes where to look for the pattern
+ * @param controlBytes the pattern to search for
+ * @return if {@code controlBytes} was found inside of {@code bytes} then this method will
+ * return an int[] array of length 2:
+ * <ul>
+ * <li>[0] the starting index of the control pattern
+ * <li>[1] the ending index of the control pattern + 1 (like {{@link java.lang.String#substring(int, int)})
+ * </ul>
+ */
+ private int[] findControlPattern(byte[] bytes, byte[] controlBytes) {
+ if (bytes.length >= controlBytes.length) {
+ for (int i = 0; i < bytes.length; i++) {
+ boolean foundControlBytePattern = true;
+ int patternEnd = -1;
+ if (bytes[i] == controlBytes[0]) {
+ int start = i;
+ for (int j = start; j < controlBytes.length + start; j++) {
+ if (j > bytes.length - 1) {
+ foundControlBytePattern = false;
+ break;
+ }
+ if (bytes[j] != controlBytes[j - start]) {
+ foundControlBytePattern = false;
+ break;
+ } else {
+ patternEnd = j;
+ }
+ }
+ if (foundControlBytePattern) {
+ return new int[]{start, patternEnd+1};
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
/**
* @hide
boolean hasEndControl = (!(program instanceof AsyncResultProgram) ||
(program instanceof AsyncResultProgram &&
((AsyncResultProgram)program).isExpectEnd()));
+ mControlPattern.setNewPattern(startId1, startId2, endId1, endId2);
- this.mStartControlPattern = startId1 + "\\d{1,3}" + startId2; //$NON-NLS-1$
- this.mEndControlPattern = endId1 + "\\d{1,3}" + endId2; //$NON-NLS-1$
String startCmd =
Command.getStartCodeCommandInfo(
FileManagerApplication.getInstance().getResources());
AsyncResultProgram program =
((AsyncResultProgram)shell.mActiveCommand);
String partial = sb.toString();
- int cc = shell.mEndControlPattern.length();
- if (partial.length() >= cc) {
+ if (partial.length() >= shell.mControlPattern
+ .getEndControlPatternLength()) {
program.onRequestParsePartialResult(sb.toByteArray());
shell.toStdIn(partial);
if (async) {
AsyncResultProgram program = ((AsyncResultProgram)shell.mActiveCommand);
String partial = sb.toString();
- int cc = shell.mEndControlPattern.length();
- if (partial.length() >= cc) {
+ if (partial.length() >= shell.mControlPattern
+ .getEndControlPatternLength()) {
if (program != null) {
program.onRequestParsePartialResult(sb.toByteArray());
}
*/
boolean isCommandStarted(ByteArrayOutputStream stdin) {
if (stdin == null) return false;
- final String str = stdin.toString();
- Pattern pattern = Pattern.compile(this.mStartControlPattern);
- Matcher matcher = pattern.matcher(str);
byte[] data = stdin.toByteArray();
- if (matcher.find()) {
+ final int[] match = mControlPattern.getStartControlMatch(data);
+ if (match != null) {
stdin.reset();
- stdin.write(data, matcher.end(), data.length - matcher.end());
+ stdin.write(data, match[1], data.length - match[1]);
return true;
}
return false;
* @hide
*/
boolean isCommandFinished(ByteArrayOutputStream stdin, ByteArrayOutputStream partial) {
- Pattern pattern = Pattern.compile(this.mEndControlPattern);
if (stdin == null) return false;
- Matcher matcher = pattern.matcher(stdin.toString());
- boolean ret = matcher.find();
+
+ int[] match = mControlPattern.getEndControlMatch(stdin.toByteArray());
+ boolean ret = match != null;
// Remove partial
if (ret && partial != null) {
- matcher = pattern.matcher(partial.toString());
- if (matcher.find()) {
- byte[] data = partial.toByteArray();
+
+ byte[] bytes = partial.toByteArray();
+ match = mControlPattern.getEndControlMatch(bytes);
+
+ if (match != null) {
partial.reset();
- partial.write(data, 0, matcher.start());
+ partial.write(bytes, match[0], match[1]);
}
}
return ret;
return 143;
}
- // Parse the stdin seeking exit code pattern
- Pattern pattern = Pattern.compile(this.mEndControlPattern);
- Matcher matcher = pattern.matcher(stdin.toString());
- if (matcher.find()) {
+ byte[] bytes = stdin.toByteArray();
+ int[] match = mControlPattern.getEndControlMatch(bytes);
+
+ if (match != null) {
if (!async) {
- byte[] data = stdin.toByteArray();
mSbIn.reset();
- mSbIn.write(data, 0, matcher.start());
+ mSbIn.write(bytes, 0, match[0]);
}
- String exitTxt = matcher.group();
- return Integer.parseInt(
- exitTxt.substring(
- exitTxt.indexOf("#/") + 2, //$NON-NLS-1$
- exitTxt.indexOf("/#", 2))); //$NON-NLS-1$
+ // find the indices of the exit code and extract it
+ match = mControlPattern.getEndControlMatch(bytes, true);
+ return Integer.parseInt(new String(bytes, match[0], match[1] - match[0]));
}
return 255;
}
* @hide
*/
@SuppressWarnings("static-method") void trimBuffer(ByteArrayOutputStream sb) {
- final int bufferSize = mEndControlPattern.length();
+ final int bufferSize = mControlPattern
+ .getEndControlPatternLength();
if (sb.size() > bufferSize) {
byte[] data = sb.toByteArray();
sb.reset();