package org.getopt.pcl5;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import org.getopt.pcl5.HPGLInterpreter.cmd.CmdUnknownHPGL;
import org.getopt.pcl5.HPGLInterpreter.cmd.CommandHPGL;
import org.getopt.pcl5.PCL5Interpreter.ControlCodes;
import org.getopt.pcl5.PCL5Interpreter.IInitialSetup;
import org.getopt.pcl5.PCL5Interpreter.IParse;
import org.getopt.pcl5.PCL5Interpreter.cmd.BaseCommandPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.CmdEscUnknownPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.CmdExtendedEscUnknownPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.CmdUnknownPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.CommandPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.EscCommandPCL5;
import org.getopt.pcl5.PCL5Interpreter.cmd.EscExtendedCommandPCL5;
import org.getopt.pcl5.PJLInterpreter.cmd.BaseCommandPJL;
import org.getopt.pcl5.PJLInterpreter.cmd.CmdEscUnknownPJL;
import org.getopt.pcl5.PJLInterpreter.cmd.CmdUnknownPJL;
import org.getopt.pcl5.PJLInterpreter.cmd.CommandPJL;
import org.getopt.pcl5.PJLInterpreter.cmd.EscCommandPJL;
/**
* This class is main class for printer parser, instance of this class will
* parse printer result stream
*/
public class Interpreter implements IParse, IInitialSetup {
PrinterState _printerState = new PrinterState();
/**
* Internal helper class to read integer from stream until non-digit We need
* class because of lack of pass-by-ref in java
*/
class ReadParameterFromStream {
String _parameter;
char _cmd;
char _subfamily;
void readParameter(InputStream in, char subfamily) throws IOException {
StringBuilder str = new StringBuilder();
// it's possible that we receive command without family
if (subfamily == '-' || subfamily == '+' || Character.isDigit(subfamily)) {
_subfamily = 0;
str.append(subfamily);
} else
_subfamily = subfamily;
char c = 0;
_parameter = null;
int data = in.read();
while (data != -1) {
c = (char) data;
if (c == '-' || Character.isDigit(c))
str.append(c);
else
break;
data = in.read();
}
_cmd = (char) data;
if (str.length() > 0)
_parameter = str.toString();
}
/**
* @return Returns the _cmd.
*/
public char getCmd() {
return _cmd;
}
/**
* @return Returns the _parameter.
*/
public String getParameter() {
return _parameter;
}
public char getSubfamily() {
return _subfamily;
}
}
interface IParser {
public void parse(int data, InputStream in) throws IOException;
}
/**
* Internal class that implements interpretation of printer commands. First
* loads all Cmd* classes and creates 3 collection for 3 different types of
* commands There are 2 collections for each type, hashed for often used
* collections and ArrayLists
*/
class PCL5Parser implements IParser {
private final static String RESOURCE_NAME = "res/commands.properties";
ArrayList _cmdParsers = new ArrayList();
HashMap _cmdParsersHash = new HashMap();
ArrayList _cmdEscParsers = new ArrayList();
HashMap _cmdEscParsersHash = new HashMap();
ArrayList _cmdExtendedEscParsers = new ArrayList();
HashMap _cmdExtendedEscParsersHash = new HashMap();
CmdUnknownPCL5 cmdUnknown = new CmdUnknownPCL5(_printerState);
CmdEscUnknownPCL5 cmdEscUnknown = new CmdEscUnknownPCL5(_printerState);
CmdExtendedEscUnknownPCL5 cmdExtendedEscUnknown = new CmdExtendedEscUnknownPCL5(
_printerState);
/**
* Very long contructor that creates Cmd* collections
*
* @throws IOException
*/
public PCL5Parser() throws IOException {
PackageLoader packageLoader = new PackageLoader(RESOURCE_NAME,
"PCL5Interpreter");
Class[] constructorParams = { PrinterState.class };
Object[] ps = { _printerState };
Iterator iter = packageLoader.getClassList().iterator();
while (iter.hasNext()) {
String clsName = (String) iter.next();
try {
Class cls = Class.forName(clsName);
BaseCommandPCL5 o;
if (cls.getSuperclass() == CommandPCL5.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (BaseCommandPCL5) constr.newInstance(ps);
char c = o.getCommandCode();
if (c != 0)
_cmdParsersHash.put(new Integer(c), o);
else
_cmdParsers.add(o);
} else if (cls.getSuperclass() == EscCommandPCL5.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (BaseCommandPCL5) constr.newInstance(ps);
char c = o.getCommandCode();
if (c != 0)
_cmdEscParsersHash.put(new Integer(c), o);
else
_cmdEscParsers.add(o);
} else if (cls.getSuperclass() == EscExtendedCommandPCL5.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (BaseCommandPCL5) constr.newInstance(ps);
char c = o.getCommandCode();
if (c != 0)
_cmdExtendedEscParsersHash.put(new Integer(c), o);
else
_cmdExtendedEscParsers.add(o);
} else if (cls.getSuperclass() == BaseCommandPCL5.class) {
// Unknown command classes
} else {
System.err.println("Incompatible class found: " + clsName);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
private boolean isExtendedCommand(char family) {
return family == '%' || family == '&' || family == '(' || family == ')'
|| family == '*';
}
/**
* Parser method for Esc commands, finds command that implements command and
* executes
*
* @param in
* stream to parse
*
* @throws IOException
*/
public void parse(int data, InputStream in) throws IOException {
char c = (char) data;
if (c >= ' ' && c != ControlCodes.DEL) {
_printerState.addText(c);
return;
}
if (c != ControlCodes.ESC) {
parse(c);
} else {
char family = (char) in.read();
if (isExtendedCommand(family)) // extended command
{
executeExtendedEscCommand(in, family);
} else {
executeEscCommand(in, family);
}
}
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executeExtendedEscCommand(InputStream in, char family)
throws IOException {
Iterator iter;
char subfamily = (char) in.read();
char command;
do {
_paramReader.readParameter(in, subfamily);
command = _paramReader.getCmd();
String parameter = _paramReader.getParameter();
subfamily = _paramReader.getSubfamily();
EscExtendedCommandPCL5 cmd;
// TODO: needs correct implementation
// cmd = (EscExtendedCommand)cmdExtendedEscParsersHash.get(new
// Integer(data));
// if (cmd != null)
// {
// cmd.execute(data, in);
// return;
// }
iter = _cmdExtendedEscParsers.iterator();
boolean found = false;
while (iter.hasNext()) {
cmd = (EscExtendedCommandPCL5) iter.next();
if (cmd.execute(family, subfamily, parameter,
Character.toUpperCase(command), in)) {
found = true;
break;
}
}
if (!found)
cmdExtendedEscUnknown.execute(family, subfamily, parameter, command,
in);
} while (Character.isLowerCase(command));
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executeEscCommand(InputStream in, char family)
throws IOException {
Iterator iter;
// this commands was tested
final String covered = "E";
if (covered.indexOf(family) == -1)
notCovered(family);
EscCommandPCL5 cmd = (EscCommandPCL5) _cmdEscParsersHash.get(new Integer(
family));
if (cmd != null) {
cmd.execute(family, in);
return;
}
iter = _cmdEscParsers.iterator();
while (iter.hasNext()) {
cmd = (EscCommandPCL5) iter.next();
if (cmd.execute(family, in))
return;
}
cmdEscUnknown.execute(family, in);
return;
}
/**
* Parser method for direct (non-Esc) commands
*
* @param data
* command to execute
*/
private void parse(int data) {
final String covered = "\r";
if (covered.indexOf(data) == -1)
notCovered(data);
CommandPCL5 cmd = (CommandPCL5) _cmdParsersHash.get(new Integer(data));
if (cmd != null) {
cmd.execute(data);
return;
}
Iterator iter = _cmdParsers.iterator();
while (iter.hasNext()) {
cmd = (CommandPCL5) iter.next();
if (cmd.execute(data))
return;
}
cmdUnknown.execute(data);
}
/**
* Not covered methods trace
*
* @param c
* printer command
*/
private void notCovered(int c) {
_printerState.trace(this, "Command not tested: " + c);
}
}
class PJLParser implements IParser {
private final static String RESOURCE_NAME = "res/pjlcommands.properties";
ArrayList _cmdParsers = new ArrayList();
HashMap _cmdParsersHash = new HashMap();
ArrayList _cmdEscParsers = new ArrayList();
CmdUnknownPJL _cmdUnknown = new CmdUnknownPJL(_printerState);
CmdEscUnknownPJL _cmdEscUnknown = new CmdEscUnknownPJL(_printerState);
/**
* Very long contructor that creates Cmd* collections
*
* @throws IOException
*/
public PJLParser() throws IOException {
PackageLoader packageLoader = new PackageLoader(RESOURCE_NAME,
"PJLInterpreter");
Class[] constructorParams = { PrinterState.class };
Object[] ps = { _printerState };
Iterator iter = packageLoader.getClassList().iterator();
while (iter.hasNext()) {
String clsName = (String) iter.next();
try {
Class cls = Class.forName(clsName);
BaseCommandPJL o;
if (cls.getSuperclass() == CommandPJL.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (BaseCommandPJL) constr.newInstance(ps);
String cmd = o.getCommandString();
if (cmd != null)
_cmdParsersHash.put(cmd, o);
else
_cmdParsers.add(o);
} else if (cls.getSuperclass() == EscCommandPJL.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (BaseCommandPJL) constr.newInstance(ps);
_cmdEscParsers.add(o);
} else {
System.err.println("Incompatible class found: " + clsName);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
/**
* Parser method for Esc commands, finds command that implements command and
* executes
*
* @param in
* stream to parse
*
* @throws IOException
*/
public void parse(int data, InputStream in) throws IOException {
char c = (char) data;
if (c == '@') // extended command
{
executePJLCommand(in);
} else if (c != ControlCodes.ESC) {
executeEscCommand(in);
} else {
_printerState.addText(c);
}
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executeEscCommand(InputStream in) throws IOException {
char family = (char) in.read();
Iterator iter;
// this commands was tested
iter = _cmdEscParsers.iterator();
while (iter.hasNext()) {
EscCommandPJL cmd = (EscCommandPJL) iter.next();
if (cmd.execute(family, in))
return;
}
_cmdEscUnknown.execute(family, in);
return;
}
String readLine(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
int n = in.read();
while (n != -1 && n != ControlCodes.LF) // EOF or LF
{
if (n != ControlCodes.CR)
sb.append((char) n);
n = in.read();
}
return sb.toString();
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executePJLCommand(InputStream in) throws IOException {
String expression = readLine(in);
String[] tokens = expression.split("\\p{Blank}+");
if (!tokens[0].equalsIgnoreCase("PJL"))
throw new RuntimeException("Error in PJL.");
CommandPJL cmd = (CommandPJL) _cmdParsersHash.get(tokens[1]);
if (cmd != null) {
cmd.execute(tokens);
return;
}
Iterator iter = _cmdParsers.iterator();
while (iter.hasNext()) {
cmd = (CommandPJL) iter.next();
if (cmd.execute(tokens))
return;
}
_cmdUnknown.execute(tokens);
return;
}
}
class HPGLParser implements IParser {
private final static String RESOURCE_NAME = "res/hpglcommands.properties";
ArrayList _cmdParsers = new ArrayList();
HashMap _cmdParsersHash = new HashMap();
CmdUnknownHPGL _cmdUnknown = new CmdUnknownHPGL(_printerState);
/**
* Very long contructor that creates Cmd* collections
*
* @throws IOException
*/
public HPGLParser() throws IOException {
PackageLoader packageLoader = new PackageLoader(RESOURCE_NAME,
"HPGLInterpreter");
Class[] constructorParams = { PrinterState.class };
Object[] ps = { _printerState };
Iterator iter = packageLoader.getClassList().iterator();
while (iter.hasNext()) {
String clsName = (String) iter.next();
try {
Class cls = Class.forName(clsName);
CommandHPGL o;
if (cls.getSuperclass() == CommandHPGL.class) {
Constructor constr = cls.getDeclaredConstructor(constructorParams);
o = (CommandHPGL) constr.newInstance(ps);
String cmd = o.getCommandString();
if (cmd != null)
_cmdParsersHash.put(cmd, o);
else
_cmdParsers.add(o);
} else {
System.err.println("Incompatible class found: " + clsName);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
public void parse(int data, InputStream in) throws IOException {
char c = (char) data;
while (data != -1 && (c == ' ' || c == ';')) {
data = in.read();
c = (char) data;
}
if (data == -1)
return;
else if (c == ControlCodes.ESC) {
executeEscCommand(in);
}
if (c <= ' ') // control command
{
executeControlCode(c, in);
} else {
String cmd = "";
cmd += c + (char) in.read();
executeHPGLCommand(cmd, in);
}
}
private void executeControlCode(char c, InputStream in) {
// TODO Auto-generated method stub
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executeEscCommand(InputStream in) throws IOException {
}
/**
* @param in
* @param family
* @throws IOException
*/
private void executeHPGLCommand(String command, InputStream in)
throws IOException {
CommandHPGL cmd = (CommandHPGL) _cmdParsersHash.get(command);
if (cmd != null) {
cmd.execute(command, in);
return;
}
Iterator iter = _cmdParsers.iterator();
while (iter.hasNext()) {
cmd = (CommandHPGL) iter.next();
if (cmd.execute(command, in))
return;
}
_cmdUnknown.execute(command, in);
return;
}
}
private PCL5Parser _pcl5Parser;
private PJLParser _pjlParser;
private HPGLParser _hpglParser;
private IParser _activeParser;
ReadParameterFromStream _paramReader;
public Interpreter() throws IOException {
_pcl5Parser = new PCL5Parser();
_pjlParser = new PJLParser();
_hpglParser = new HPGLParser();
_paramReader = new ReadParameterFromStream();
}
public void parse(InputStream in, IPrint print) throws IOException {
_activeParser = _pcl5Parser;
print.processingStart();
_printerState.setPrinter(print);
_printerState.reset();
int data = in.read();
while (data != -1) {
_activeParser = getActiveParser();
_activeParser.parse(data, in);
data = in.read();
}
print.processingEnd();
}
private IParser getActiveParser() {
switch (_printerState.getActiveLanguage()) {
case PrinterState.Language.PCL5:
return _pcl5Parser;
case PrinterState.Language.PJL:
return _pjlParser;
case PrinterState.Language.HPGL:
return _hpglParser;
}
return null;
}
public void setBoundBoxColor(boolean boudBox) {
_printerState.setBoundBoxColor(boudBox);
}
}