Converted ReaderGuacamoleReader to real parser of new instruction format (should be more efficient, and no more chance of invalid reads due to semicolons).

This commit is contained in:
Michael Jumper
2011-12-05 18:20:58 -08:00
parent 70b522cacd
commit e0b1427e59

View File

@@ -65,31 +65,88 @@ public class ReaderGuacamoleReader implements GuacamoleReader {
this.input = input; this.input = input;
} }
private int usedLength = 0; private int parseStart;
private char[] buffer = new char[20000];
private int instructionStart; private char[] buffer = new char[20480];
private char[] instructionBuffer; private int usedLength = 0;
@Override @Override
public char[] read() throws GuacamoleException { public char[] read() throws GuacamoleException {
// If data was previously read via readInstruction(), return remaining
// data instead of reading more.
if (instructionBuffer != null) {
char[] chunk = new char[instructionBuffer.length - instructionStart];
System.arraycopy(instructionBuffer, instructionStart, chunk, 0, chunk.length);
instructionBuffer = null;
return chunk;
}
try { try {
// While we're blocking, or input is available // While we're blocking, or input is available
for (;;) { for (;;) {
// Length of element
int elementLength = 0;
// Resume where we left off
int i = parseStart;
// Parse instruction in buffer
while (i < usedLength) {
// Read character
char readChar = buffer[i++];
// If digit, update length
if (readChar >= '0' && readChar <= '9')
elementLength = elementLength * 10 + readChar - '0';
// If not digit, check for end-of-length character
else if (readChar == '.') {
// Check if element present in buffer
if (i + elementLength < usedLength) {
// Get terminator
char terminator = buffer[i + elementLength];
// Move to character after terminator
i += elementLength + 1;
// Reset length
elementLength = 0;
// Continue here if necessary
parseStart = i;
// If terminator is semicolon, we have a full
// instruction.
if (terminator == ';') {
// Copy instruction data
char[] instruction = new char[i];
System.arraycopy(buffer, 0, instruction, 0, i);
// Update buffer
usedLength -= i;
parseStart = 0;
System.arraycopy(buffer, i, buffer, 0, usedLength);
return instruction;
}
// Handle invalid terminator characters
else if (terminator != ',')
throw new GuacamoleException("Element terminator of instruction was not ';' nor ','");
}
// Otherwise, read more data
else
break;
}
// Otherwise, parse error
else
throw new GuacamoleException("Non-numeric character in element length.");
}
// If past threshold, resize buffer before reading // If past threshold, resize buffer before reading
if (usedLength > buffer.length/2) { if (usedLength > buffer.length/2) {
char[] biggerBuffer = new char[buffer.length*2]; char[] biggerBuffer = new char[buffer.length*2];
@@ -102,30 +159,9 @@ public class ReaderGuacamoleReader implements GuacamoleReader {
if (numRead == -1) if (numRead == -1)
return null; return null;
int prevLength = usedLength; // Update used length
usedLength += numRead; usedLength += numRead;
for (int i=usedLength-1; i>=prevLength; i--) {
char readChar = buffer[i];
// If end of instruction, return it.
if (readChar == ';') {
// Get instruction
char[] chunk = new char[i+1];
System.arraycopy(buffer, 0, chunk, 0, i+1);
// Reset buffer
usedLength -= i+1;
System.arraycopy(buffer, i+1, buffer, 0, usedLength);
// Return instruction string
return chunk;
}
}
} // End read loop } // End read loop
} }
@@ -138,35 +174,35 @@ public class ReaderGuacamoleReader implements GuacamoleReader {
@Override @Override
public GuacamoleInstruction readInstruction() throws GuacamoleException { public GuacamoleInstruction readInstruction() throws GuacamoleException {
// Fill instructionBuffer if not already filled // Get instruction
if (instructionBuffer == null) { char[] instructionBuffer = read();
instructionBuffer = read();
instructionStart = 0;
}
// If EOF, return EOF // If EOF, return EOF
if (instructionBuffer == null) if (instructionBuffer == null)
return null; return null;
// Start of element
int elementStart = 0;
// Build list of elements // Build list of elements
LinkedList<String> elements = new LinkedList<String>(); LinkedList<String> elements = new LinkedList<String>();
while (instructionStart < instructionBuffer.length) { while (elementStart < instructionBuffer.length) {
// Find end of length // Find end of length
int lengthEnd = ArrayUtils.indexOf(instructionBuffer, '.', instructionStart); int lengthEnd = ArrayUtils.indexOf(instructionBuffer, '.', elementStart);
// Parse length // Parse length
int length = Integer.parseInt(new String( int length = Integer.parseInt(new String(
instructionBuffer, instructionBuffer,
instructionStart, elementStart,
lengthEnd - instructionStart lengthEnd - elementStart
)); ));
// Parse element from just after period // Parse element from just after period
instructionStart = lengthEnd + 1; elementStart = lengthEnd + 1;
String element = new String( String element = new String(
instructionBuffer, instructionBuffer,
instructionStart, elementStart,
length length
); );
@@ -174,11 +210,11 @@ public class ReaderGuacamoleReader implements GuacamoleReader {
elements.addLast(element); elements.addLast(element);
// Read terminator after element // Read terminator after element
instructionStart += length; elementStart += length;
char terminator = instructionBuffer[instructionStart]; char terminator = instructionBuffer[elementStart];
// Continue reading instructions after terminator // Continue reading instructions after terminator
instructionStart++; elementStart++;
// If we've reached the end of the instruction // If we've reached the end of the instruction
if (terminator == ';') if (terminator == ';')
@@ -195,10 +231,6 @@ public class ReaderGuacamoleReader implements GuacamoleReader {
elements.toArray(new String[elements.size()]) elements.toArray(new String[elements.size()])
); );
// Detect end of buffer
if (instructionStart >= instructionBuffer.length)
instructionBuffer = null;
// Return parsed instruction // Return parsed instruction
return instruction; return instruction;