Skip to content

Commit d5b05f3

Browse files
committed
updated the ByteBufferPclCommandReader to properly break up compound commands; updated the PclUtil to be more performant when trying to determine if an escape sequence expecting binary data
1 parent 263b6fd commit d5b05f3

8 files changed

+245
-332
lines changed

src/main/java/pcl4j/io/ByteBufferPclCommandReader.java

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import java.io.ByteArrayOutputStream;
1919
import java.nio.ByteBuffer;
20+
import java.util.LinkedList;
21+
import java.util.Queue;
2022

2123
/**
2224
* A PclCommandReader implementation using the java.nio.ByteBuffer
@@ -26,6 +28,7 @@ public class ByteBufferPclCommandReader implements PclCommandReader {
2628
private PclUtil pclUtil = new PclUtil();
2729
protected ByteBuffer buffer;
2830
private long filePosition = 0;
31+
private Queue<PclCommand> queuedCommands = new LinkedList<PclCommand>();
2932

3033
public ByteBufferPclCommandReader(byte[] entirePclFileContents) {
3134
this(ByteBuffer.wrap(entirePclFileContents));
@@ -45,56 +48,107 @@ public void skip(long numberOfBytesToSkip) throws PclCommandReaderException {
4548
}
4649

4750
public PclCommand nextCommand() throws PclCommandReaderException {
51+
if (commandsAreQueued()) {
52+
return queuedCommands.remove();
53+
}
54+
4855
if (isFileEmpty() || isEOF()) {
4956
return null;
5057
}
5158

5259
long commandPosition = filePosition;
5360
byte currentByte = readNextByte();
5461
if (pclUtil.isEscape(currentByte)) {
55-
return pclCommand(commandPosition);
62+
pclCommand(commandPosition);
63+
return queuedCommands.remove();
5664
} else {
5765
return textCommand(commandPosition, currentByte);
5866
}
5967
}
6068

61-
private PclCommand pclCommand(long commandPosition) {
62-
PclCommand command = null;
69+
private void pclCommand(long initialCommandPosition) {
70+
long commandPosition = initialCommandPosition;
71+
ByteArrayOutputStream commandPrefixBytes = new ByteArrayOutputStream();
72+
commandPrefixBytes.write(PclUtil.ESCAPE);
6373
ByteArrayOutputStream commandData = new ByteArrayOutputStream();
6474
commandData.write(PclUtil.ESCAPE);
75+
6576
boolean isFirstRead = true;
77+
boolean captureByte = true;
78+
boolean escapeSequenceComplete = false;
79+
boolean groupByteFound = false;
80+
boolean parameterByteFound = false;
6681
boolean commandCompleted = false;
82+
boolean compressedCommand = false;
6783

68-
while (!commandCompleted && isNotEOF()) {
84+
while (!escapeSequenceComplete && isNotEOF()) {
6985
byte currentByte = readNextByte();
70-
commandData.write(currentByte);
7186

72-
if (isFirstRead && pclUtil.is2ByteCommandOperator(currentByte)) {
87+
if (!groupByteFound) {
88+
commandPrefixBytes.write(currentByte);
89+
}
90+
91+
92+
if (isTwoByteCommand(isFirstRead, currentByte)) {
93+
escapeSequenceComplete = true;
94+
} else if (!parameterByteFound) {
95+
parameterByteFound = pclUtil.isParameterizedCharacter(currentByte);
96+
} else if (!groupByteFound) {
97+
groupByteFound = pclUtil.isGroupCharacter(currentByte);
98+
} else if (groupByteFound && pclUtil.isParameterCharacter(currentByte) && isNextByteNotAnEscapeByte()) {
7399
commandCompleted = true;
100+
compressedCommand = true;
101+
currentByte = pclUtil.changeParameterToTerminator(currentByte);
74102
} else if (pclUtil.isTermination(currentByte)) {
75-
if (pclUtil.isCommandExpectingData(commandData.toByteArray())) {
103+
escapeSequenceComplete = true;
104+
} else if (pclUtil.isEscape(currentByte)) {
105+
undoRead();
106+
escapeSequenceComplete = true;
107+
captureByte = false;
108+
}
109+
110+
if (captureByte) {
111+
commandData.write(currentByte);
112+
}
113+
114+
if (escapeSequenceComplete || commandCompleted || isLastByteInFile()) {
115+
if (!isFirstRead && pclUtil.isCommandExpectingData(commandData.toByteArray())) {
76116
captureBinaryData(commandData);
77117
}
78-
commandCompleted = true;
118+
119+
queuedCommands.add(pclCommandFactory.build(commandPosition, commandData.toByteArray()));
120+
commandPosition = filePosition;
121+
122+
if (compressedCommand) {
123+
commandData.reset();
124+
commandData.write(commandPrefixBytes.toByteArray(), 0, 3);
125+
commandCompleted = false;
126+
}
79127
}
80128

81129
isFirstRead = false;
82130
}
131+
}
83132

133+
private boolean isLastByteInFile() {
84134
if (isEOF()) {
85-
commandCompleted = true;
135+
return true;
86136
}
87137

88-
if (commandCompleted) {
89-
command = pclCommandFactory.build(commandPosition, commandData.toByteArray());
90-
}
138+
return buffer.position() == buffer.capacity();
139+
}
91140

92-
return command;
141+
private boolean isNextByteNotAnEscapeByte() {
142+
return !isNextByteAnEscapeByte();
143+
}
144+
145+
private boolean isTwoByteCommand(boolean firstRead, byte currentByte) {
146+
return firstRead && pclUtil.is2ByteCommandOperator(currentByte);
93147
}
94148

95149
private void captureBinaryData(ByteArrayOutputStream commandData) {
96-
String valueAsString = new String(pclUtil.getValue(commandData.toByteArray())).replaceAll("\\.[0-9]*", "");
97-
Integer numberOfBytesToRead = Integer.valueOf(valueAsString);
150+
String valueAsString = new String(pclUtil.getValue(commandData.toByteArray())).replaceAll("\\+|\\.[0-9]*|\\s+", "");
151+
Integer numberOfBytesToRead = valueAsString.length() == 0 ? 0 : Integer.valueOf(valueAsString);
98152
int count = 0;
99153
while (isNotEOF() && count < numberOfBytesToRead) {
100154
commandData.write(readNextByte());
@@ -149,7 +203,12 @@ private boolean isFileEmpty() {
149203
return buffer.capacity() == 0;
150204
}
151205

206+
private boolean commandsAreQueued() {
207+
return queuedCommands.size() > 0;
208+
}
209+
152210
public void close() {
153211

154212
}
213+
155214
}

src/main/java/pcl4j/io/PclCommandBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public PclCommandBuilder copy() {
132132
child.value = value;
133133
child.terminator = terminator;
134134
child.binaryData = binaryData;
135+
child.validate = validate;
135136
return child;
136137
}
137138

src/main/java/pcl4j/io/PclUtil.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616

1717
import java.io.ByteArrayOutputStream;
1818
import java.util.Arrays;
19-
import java.util.List;
2019

2120
/**
2221
* Utility class for checking for the magic PCL bytes
2322
*/
2423
public class PclUtil {
25-
private static final List<String> BINARY_DATA_COMMANDS = Arrays.asList(
26-
"*c#E", ")s#W", "(s#W", "(f#W", "&n#W", "*b#W", "*g#W", "*b#Y", "*b#V", "*v#W", "*l#W", "*o#W", "*m#W", "&p#X"
27-
);
24+
private static final String[] BINARY_DATA_COMMANDS = {"*c#E", ")s#W", "(s#W", "(f#W", "&n#W", "*b#W", "*g#W", "*b#Y", "*b#V", "*v#W", "*l#W", "*o#W", "*m#W", "&p#X"};
25+
private static final int[] BINARY_DATA_COMMANDS_HASHES = initializeBinaryDataHashes();
2826

2927
public static final int PARAMETERIZED_BYTE_POSITION = 1;
3028
public static final int GROUP_BYTE_POSITION = 2;
@@ -246,7 +244,7 @@ public byte[] getValue(byte[] commandBytes) {
246244
} else {
247245
for (int i = VALUE_BYTE_START_POSITION; i < commandBytes.length; i++) {
248246
byte currentByte = commandBytes[i];
249-
if (isTermination(currentByte)) {
247+
if (currentByte == getTerminatorByte(commandBytes)) {
250248
break;
251249
} else if (isParameterCharacter(currentByte)) {
252250
output.reset();
@@ -266,12 +264,13 @@ public byte[] getValue(byte[] commandBytes) {
266264
* false - is not expecting binary data
267265
*/
268266
public boolean isCommandExpectingData(byte[] commandBytes) {
269-
StringBuilder pattern = new StringBuilder();
270-
pattern.append((char) commandBytes[PARAMETERIZED_BYTE_POSITION]);
271-
pattern.append((char) commandBytes[GROUP_BYTE_POSITION]);
272-
pattern.append("#");
273-
pattern.append((char) getTerminatorByte(commandBytes));
274-
return BINARY_DATA_COMMANDS.contains(pattern.toString());
267+
byte[] commandId = {
268+
commandBytes[PARAMETERIZED_BYTE_POSITION],
269+
commandBytes[GROUP_BYTE_POSITION],
270+
'#',
271+
(byte) Character.toUpperCase((char) getTerminatorByte(commandBytes))
272+
};
273+
return Arrays.binarySearch(BINARY_DATA_COMMANDS_HASHES, Arrays.hashCode(commandId)) > -1;
275274
}
276275

277276
private void requiresParameterizedCommand(PclCommand command) {
@@ -287,4 +286,13 @@ private boolean is2ByteCommand(PclCommand command) {
287286
private byte getTerminatorByte(byte[] commandBytes) {
288287
return commandBytes[commandBytes.length - 1];
289288
}
289+
290+
private static int[] initializeBinaryDataHashes() {
291+
int[] hashes = new int[BINARY_DATA_COMMANDS.length];
292+
for (int i = 0; i < hashes.length; i++) {
293+
hashes[i] = Arrays.hashCode(BINARY_DATA_COMMANDS[i].getBytes());
294+
}
295+
Arrays.sort(hashes);
296+
return hashes;
297+
}
290298
}

src/main/java/pcl4j/io/UncompressedPclCommandReader.java

Lines changed: 0 additions & 160 deletions
This file was deleted.

0 commit comments

Comments
 (0)