// Copyright 2001, FreeHEP.
package org.freehep.postscript;
import java.io.IOException;
import org.freehep.util.io.EEXECDecryption;
/**
* Control Operators for PostScript Processor
*
* @author Mark Donszelmann
* @version $Id: ControlOperator.java 10178 2006-12-08 09:03:07Z duns $
*/
public class ControlOperator extends PSOperator {
public static Class[] operators = {
Exec.class, If.class, IfElse.class,
For.class, Repeat.class, Loop.class,
Exit.class, Stop.class, Stopped.class,
CountExecStack.class, ExecStack.class,
Quit.class, Start.class,
EExec.class
};
public boolean execute(OperandStack os) {
throw new RuntimeException("Cannot execute class: "+getClass());
}
}
class Exec extends ControlOperator {
{ operandTypes = new Class[] {PSObject.class}; }
public boolean execute(OperandStack os) {
os.execStack().pop();
os.execStack().push(os.popObject());
return false;
}
}
class If extends ControlOperator {
{ operandTypes = new Class[] {PSBoolean.class, PSPackedArray.class}; }
public boolean execute(OperandStack os) {
PSPackedArray p = os.popPackedArray();
PSBoolean b = os.popBoolean();
if (b.getValue()) {
os.execStack().pop();
os.execStack().push(p);
return false;
}
return true;
}
}
class IfElse extends ControlOperator {
{ operandTypes = new Class[] {PSBoolean.class,
PSPackedArray.class,
PSPackedArray.class}; }
public boolean execute(OperandStack os) {
PSPackedArray p2 = os.popPackedArray();
PSPackedArray p1 = os.popPackedArray();
PSBoolean b = os.popBoolean();
os.execStack().pop();
if (b.getValue()) {
os.execStack().push(p1);
} else {
os.execStack().push(p2);
}
return false;
}
}
class For extends ControlOperator implements LoopingContext {
private PSPackedArray procedure = null;
private int iLimit = 0;
private int iIncrement = 0;
private int iCount = 0;
private double rLimit = 0.0;
private double rIncrement = 0.0;
private double rCount = 0.0;
private boolean real = false;
public For() {
}
private For(int start, int inc, int limit, PSPackedArray p) {
iCount = start;
iIncrement = inc;
iLimit = limit;
procedure = p;
real = false;
}
public For(double start, double inc, double limit, PSPackedArray p) {
rCount = start;
rIncrement = inc;
rLimit = limit;
procedure = p;
real = true;
}
public boolean execute(OperandStack os) {
if (procedure == null) {
if (!os.checkType(PSNumber.class, PSNumber.class, PSNumber.class, PSPackedArray.class)) {
error(os, new TypeCheck());
return true;
}
PSPackedArray p = os.popPackedArray();
PSNumber limit = os.popNumber();
PSNumber inc = os.popNumber();
PSNumber start = os.popNumber();
os.execStack().pop();
if ((limit instanceof PSReal) ||
(inc instanceof PSReal) ||
(start instanceof PSReal)) {
os.execStack().push(new For(start.getDouble(), inc.getDouble(), limit.getDouble(), p));
} else {
os.execStack().push(new For(((PSInteger)start).getValue(), ((PSInteger)inc).getValue(), ((PSInteger)limit).getValue(), p));
}
return false;
}
if (real) {
if ((rIncrement >= 0.0) && (rCount <= rLimit)) {
os.push(rCount);
os.execStack().push(procedure);
rCount += rIncrement;
return false;
} else if ((rIncrement < 0.0) && (rCount >= rLimit)) {
os.push(rCount);
os.execStack().push(procedure);
rCount += rIncrement;
return false;
}
} else {
if ((iIncrement >= 0) && (iCount <= iLimit)) {
os.push(iCount);
os.execStack().push(procedure);
iCount += iIncrement;
return false;
} else if ((iIncrement < 0) && (iCount >= iLimit)) {
os.push(iCount);
os.execStack().push(procedure);
iCount += iIncrement;
return false;
}
}
return true;
}
}
class Repeat extends ControlOperator implements LoopingContext {
private PSPackedArray procedure = null;
private int limit = 0;
private int i = 0;
public Repeat() {
}
private Repeat(int n, PSPackedArray p) {
procedure = p;
limit = n;
i = 0;
}
public boolean execute(OperandStack os) {
if (procedure == null) {
if (!os.checkType(PSInteger.class, PSPackedArray.class)) {
error(os, new TypeCheck());
return true;
}
PSPackedArray p = os.popPackedArray();
PSInteger n = os.popInteger();
if (n.getValue() < 0) {
error(os, new RangeCheck());
return true;
}
os.execStack().pop();
os.execStack().push(new Repeat(n.getValue(), p));
return false;
}
if (i < limit) {
os.execStack().push(procedure);
i++;
return false;
}
return true;
}
}
class Loop extends ControlOperator implements LoopingContext {
private PSPackedArray procedure = null;
public Loop() {
}
private Loop(PSPackedArray p) {
procedure = p;
}
public boolean execute(OperandStack os) {
if (procedure == null) {
if (!os.checkType(PSPackedArray.class)) {
error(os, new TypeCheck());
return true;
}
os.execStack().pop();
os.execStack().push(new Loop(os.popPackedArray()));
return false;
}
os.execStack().push(procedure);
return false;
}
}
class Exit extends ControlOperator {
public boolean execute(OperandStack os) {
PSObject o = os.execStack().popObject();
while ((o != null) && !(o instanceof LoopingContext)) {
o = os.execStack().popObject();
}
if (o == null) {
System.err.println("Error: No enclosing LoopingContext; Command: exit");
os.execStack().push("quit");
os.execStack().push(os.dictStack().errorDictionary().get("handleerror"));
return false;
}
if ((o instanceof Stopped) || (o instanceof Run)) {
os.execStack().push(o);
os.execStack().push("invalidexit");
return false;
}
// ok
return false;
}
}
class Stop extends ControlOperator {
// Our stop operator will print the error message if not in a stopped context
public boolean execute(OperandStack os) {
PSObject o = os.execStack().popObject();
while ((o != null) && !(o instanceof Stopped)) {
o = os.execStack().popObject();
}
if (o == null) {
// FIXME: this should be part of a standard stopped context
// just a message written here
os.execStack().push("quit");
os.execStack().push(os.dictStack().errorDictionary().get("handleerror"));
} else {
// do as if stopped returned true
os.push(true);
}
return false;
}
}
class Stopped extends ControlOperator implements LoopingContext {
private boolean stopped = true;
public Stopped() {
}
private Stopped(boolean state) {
stopped = state;
}
public boolean execute(OperandStack os) {
if (stopped) {
if (!os.checkType(PSObject.class)) {
error(os, new TypeCheck());
return true;
}
PSObject obj = os.popObject();
os.execStack().pop();
os.execStack().push(new Stopped(false));
os.execStack().push(obj);
return false;
}
os.push(false);
return true;
}
}
class CountExecStack extends ControlOperator {
public boolean execute(OperandStack os) {
os.push(os.execStack().size());
return true;
}
}
class ExecStack extends ControlOperator {
{ operandTypes = new Class[] {PSArray.class}; }
public boolean execute(OperandStack os) {
PSArray a = os.popArray();
os.execStack().copyInto(a);
os.push(a.subArray(0, os.execStack().size()));
return true;
}
}
class Quit extends ControlOperator {
public boolean execute(OperandStack os) {
// FIXME: look at 637, quit should also be in the userdict
// empty the full execution stack
os.execStack().clear();
return false;
}
}
class Start extends ControlOperator {
public boolean execute(OperandStack os) {
// ignored
return true;
}
}
class EExec extends ControlOperator {
{ operandTypes = new Class[] { PSDataSource.class }; }
public boolean execute(OperandStack os) {
if (os.checkType(PSDataSource.class)) {
try {
PSDataSource source = os.popDataSource();
os.execStack().pop();
os.execStack().push(new PSInputFile(new EEXECDecryption(source.getInputStream(),
EEXECDecryption.EEXEC_R,
EEXECDecryption.N), source.getDSC()));
} catch (IOException e) {
error(os, new InvalidFileAccess());
}
return false;
} else {
error(os, new TypeCheck());
return true;
}
}
}