if (ch == 'x') {
hexChars = "";
} else if (ch == ' ' || ch == '\'' || ch == '"' || ch == '\\') {
token[tokenLength++] = inputBytes[i];
} else {
throw new BadArgumentException("can only escape single quotes, double quotes, the space character, the backslash, and hex input", input, i);
}
}
// in a hex escape sequence
else if (hexChars != null) {
final int digit = Character.digit(ch, 16);
if (digit < 0) {
throw new BadArgumentException("expected hex character", input, i);
}
hexChars += ch;
if (hexChars.length() == 2) {
byte b;
try {
b = (byte) (0xff & Short.parseShort(hexChars, 16));
if (!Character.isValidCodePoint(0xff & b))
throw new NumberFormatException();
} catch (NumberFormatException e) {
throw new BadArgumentException("unsupported non-ascii character", input, i);
}
token[tokenLength++] = b;
hexChars = null;
}
}
// in a quote, either end the quote, start escape, or continue a token
else if (inQuote) {
if (ch == inQuoteChar) {
inQuote = false;
tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
tokenLength = 0;
} else if (ch == '\\') {
inEscapeSequence = true;
} else {
token[tokenLength++] = inputBytes[i];
}
}
// not in a quote, either enter a quote, end a token, start escape, or continue a token
else {
if (ch == '\'' || ch == '"') {
if (tokenLength > 0) {
tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
tokenLength = 0;
}
inQuote = true;
inQuoteChar = ch;
} else if (ch == ' ' && tokenLength > 0) {
tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
tokenLength = 0;
} else if (ch == '\\') {
inEscapeSequence = true;
} else if (ch != ' ') {
token[tokenLength++] = inputBytes[i];
}
}
}
if (inQuote) {
throw new BadArgumentException("missing terminating quote", input, input.length());
} else if (inEscapeSequence || hexChars != null) {
throw new BadArgumentException("escape sequence not complete", input, input.length());
}
if (tokenLength > 0) {
tokens.add(new String(token, 0, tokenLength, Shell.CHARSET));
}
}