org.jpedal.function.PostScriptCompiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2016 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* PostScriptCompiler.java
* ---------------
*/
package org.jpedal.function;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Stack;
//class will be used in future for speed execution
public class PostScriptCompiler {
private static final int C_ABS = 96370;
private static final int C_ADD = 96417;
private static final int C_ATAN = 3004320;
private static final int C_CEILING = 660387005;
private static final int C_COS = 98695;
private static final int C_CVI = 98902;
private static final int C_CVR = 98911;
private static final int C_DIV = 99473;
private static final int C_EXP = 100893;
private static final int C_FLOOR = 97526796;
private static final int C_IDIV = 3227528;
private static final int C_LN = 3458;
private static final int C_LOG = 107332;
private static final int C_MOD = 108290;
private static final int C_MUL = 108484;
private static final int C_NEG = 108944;
private static final int C_SIN = 113880;
private static final int C_SQRT = 3538208;
private static final int C_SUB = 114240;
private static final int C_ROUND = 108704142;
private static final int C_TRUNCATE = 1852984678;
private static final int C_AND = 96727;
private static final int C_BITSHIFT = 1125715861;
private static final int C_EQ = 3244;
private static final int C_FALSE = 97196323;
private static final int C_GE = 3294;
private static final int C_GT = 3309;
private static final int C_LE = 3449;
private static final int C_LT = 3464;
private static final int C_NE = 3511;
private static final int C_NOT = 109267;
private static final int C_OR = 3555;
private static final int C_TRUE = 3569038;
private static final int C_XOR = 118875;
private static final int C_IF = 3357;
private static final int C_IFELSE = -1191590954;
private static final int C_COPY = 3059573;
private static final int C_EXCH = 3127384;
private static final int C_POP = 111185;
private static final int C_DUP = 99839;
private static final int C_INDEX = 100346066;
private static final int C_ROLL = 3506301;
private static final int T_COMMAND = 1;
private static final int T_NUMBER = 2;
private static final int T_BOOLEAN = 3;
private static final int T_SBRACE = 123; //start brace
private static final int T_EBRACE = 125; //end brace
private static final double radToDegrees = 180f / Math.PI;
private static final double toBase10=Math.log(10);
private static final byte[] CHAR256 = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 2, 0, 2, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
private final double[] dValues = new double[1000]; //hold default values
private final int[] dTypes = new int[1000]; //hold default types
private final double[] cValues ;
private final int[] cTypes ;
private int sp;//stream pointer
private int dp;//default pointer
private int cp;//cur list pointer
private final Stack braces = new Stack();
public PostScriptCompiler(final byte[] stream) {
parseStream(stream);
cValues = new double[Math.max(20, dp+10)];
cTypes = new int[cValues.length];
}
private void parseStream(byte[] stream) {
int len = stream.length;
while (sp < len && dp < dValues.length) {
int cc = stream[sp++] & 0xff;
if (cc == T_SBRACE) {
if (!braces.empty()) {
pushDefault(T_SBRACE, T_SBRACE);
}
braces.push(Boolean.TRUE);
} else if (cc == T_EBRACE) {
braces.pop();
if (!braces.empty()) {
pushDefault(T_EBRACE, T_EBRACE);
}
} else if (isDigit(cc) || isFullStop(cc) || cc == 43 || cc == 45) {
StringBuilder sb = new StringBuilder();
while (sp < len) {
if (isWhiteSpace(cc) || isDelimiter(cc)) {
sp--;
break;
} else {
sb.append((char) cc);
cc = stream[sp++] & 0xff;
}
}
pushDefault(Double.parseDouble(sb.toString()), T_NUMBER);
} else if (cc > 96 && cc < 123) {
StringBuilder sb = new StringBuilder();
while (sp < len) {
if (isWhiteSpace(cc) || isDelimiter(cc)) {
sp--;
break;
} else {
sb.append((char) cc);
cc = stream[sp++] & 0xff;
}
}
int com = getCommand(sb.toString());
if (com != -1) {
pushDefault(com, T_COMMAND);
}
}
}
}
private static int getCommand(String s) {
switch (s.hashCode()) {
case C_ABS:
return C_ABS;
case C_ADD:
return C_ADD;
case C_ATAN:
return C_ATAN;
case C_CEILING:
return C_CEILING;
case C_COS:
return C_COS;
case C_CVI:
return C_CVI;
case C_CVR:
return C_CVR;
case C_DIV:
return C_DIV;
case C_EXP:
return C_EXP;
case C_FLOOR:
return C_FLOOR;
case C_IDIV:
return C_IDIV;
case C_LN:
return C_LN;
case C_LOG:
return C_LOG;
case C_MOD:
return C_MOD;
case C_MUL:
return C_MUL;
case C_NEG:
return C_NEG;
case C_SIN:
return C_SIN;
case C_SQRT:
return C_SQRT;
case C_SUB:
return C_SUB;
case C_ROUND:
return C_ROUND;
case C_TRUNCATE:
return C_TRUNCATE;
case C_AND:
return C_AND;
case C_BITSHIFT:
return C_BITSHIFT;
case C_EQ:
return C_EQ;
case C_FALSE:
return C_FALSE;
case C_GE:
return C_GE;
case C_GT:
return C_GT;
case C_LE:
return C_LE;
case C_LT:
return C_LT;
case C_NE:
return C_NE;
case C_NOT:
return C_NOT;
case C_OR:
return C_OR;
case C_TRUE:
return C_TRUE;
case C_XOR:
return C_XOR;
case C_IF:
return C_IF;
case C_IFELSE:
return C_IFELSE;
case C_COPY:
return C_COPY;
case C_EXCH:
return C_EXCH;
case C_POP:
return C_POP;
case C_DUP:
return C_DUP;
case C_INDEX:
return C_INDEX;
case C_ROLL:
return C_ROLL;
}
return -1;
}
private void pushDefault(double value, int type) {
dValues[dp] = value;
dTypes[dp] = type;
dp++;
}
private static boolean isWhiteSpace(int ch) {
return CHAR256[ch] == 1;
}
private static boolean isDigit(int ch) {
return CHAR256[ch] == 4;
}
private static boolean isFullStop(int ch) {
return ch == 46;
}
public static boolean isDelimiter(int ch) {
return CHAR256[ch] == 2;
}
private void executeCommand(int cmd) {
double[] first, second;
int n,j, old;
switch (cmd) {
case C_ABS:
first = popItem();
cValues[cp] = Math.abs(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_ADD:
first = popItem();
second = popItem();
cValues[cp] = first[0] + second[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_ATAN:
first = popItem();
second = popItem();
double tt = 0;
final double tangent = second[0]/first[0];
if(first[0]>=0 && second[0]>=0){
tt = Math.toDegrees(Math.atan(tangent));
} else if (first[0]>0 && second[0]<=0){
double tmp = Math.abs(Math.toDegrees(Math.atan(tangent)));
tt = tmp+90;
} else if (first[0]<=0 && second[0]<=0){
double tmp = Math.abs(Math.toDegrees(Math.atan(tangent)));
tt = tmp+180;
} else if (first[0]<=0 && second[0]>=0){
double tmp = Math.abs(Math.toDegrees(Math.atan(tangent)));
tt = tmp + 270;
}
cValues[cp] = tt;
cTypes[cp] = (int) first[1];
cp++;
break;
case C_CEILING:
first = popItem();
cValues[cp] = Math.ceil(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_COS:
first = popItem();
cValues[cp] = Math.sin(first[0] / radToDegrees);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_CVI:
first = popItem();
cValues[cp] = (int) first[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_CVR:
first = popItem();
cValues[cp] = first[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_DIV:
first = popItem();
second = popItem();
cValues[cp] = second[0] / first[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_EXP:
first = popItem();
second = popItem();
cValues[cp] = Math.pow(second[0],first[0]);
cTypes[cp] = (int) first[1];
break;
case C_FLOOR:
first = popItem();
cValues[cp] = Math.floor(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_IDIV:
first = popItem();
second = popItem();
cValues[cp] = ((int) second[0]) / ((int) first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_LN:
first = popItem();
cValues[cp] = Math.log(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_LOG:
first = popItem();
cValues[cp] = Math.log(first[0])/toBase10;
cTypes[cp] = (int) first[1];
cp++;
break;
case C_MOD:
first = popItem();
second = popItem();
cValues[cp] = ((int) second[0]) % ((int) first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_MUL:
first = popItem();
second = popItem();
cValues[cp] = first[0] * second[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_NEG:
first = popItem();
cValues[cp] = -first[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_SIN:
first = popItem();
cValues[cp] = Math.sin(first[0] / radToDegrees);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_SQRT:
first = popItem();
cValues[cp] = Math.sqrt(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_SUB:
first = popItem();
second = popItem();
cValues[cp] = second[0] - first[0];
cTypes[cp] = (int) first[1];
cp++;
break;
case C_ROUND:
first = popItem();
cValues[cp] = Math.round(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_TRUNCATE:
first = popItem();
cValues[cp] = (int)(first[0]);
cTypes[cp] = (int) first[1];
cp++;
break;
case C_AND:
first = popItem();
second = popItem();
if(first[1] == T_NUMBER && second[1] == T_NUMBER){
cValues[cp] = ((int)second[0]) & ((int)first[0]);
cTypes[cp] = T_NUMBER;
}else{
cValues[cp] = first[0] == second[0] ? 1 : 0 ;
cTypes[cp] = T_BOOLEAN;
}
cp++;
break;
case C_BITSHIFT:
first = popItem();
second = popItem();
cValues[cp] = ((int)second[0])<<((int)first[0]);
cTypes[cp] = (int)first[1];
cp++;
break;
case C_EQ:
first = popItem();
second = popItem();
cValues[cp] = first[0] == second[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_FALSE:
cValues[cp] = 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_GE:
first = popItem();
second = popItem();
cValues[cp] = second[0] >= first[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_GT:
first = popItem();
second = popItem();
cValues[cp] = second[0] > first[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_LE:
first = popItem();
second = popItem();
cValues[cp] = second[0] <= first[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_LT:
first = popItem();
second = popItem();
cValues[cp] = second[0] < first[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_NE:
first = popItem();
second = popItem();
cValues[cp] = second[0] != first[0] ? 1 : 0;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_NOT:
first = popItem();
if(first[1] == T_NUMBER){
cValues[cp] = ~(int)first[0];
}else{
cValues[cp] = first[0] != 1 ? 1 : 0;
}
cTypes[cp] = (int)first[1];
cp++;
break;
case C_OR:
first = popItem();
second = popItem();
if(first[1] == T_NUMBER && second[1] == T_NUMBER){
cValues[cp] = ((int)second[0]) | ((int)first[0]);
cTypes[cp] = T_NUMBER;
}else{
cValues[cp] = first[0]==1 || second[0]==1 ? 1 : 0 ;
cTypes[cp] = T_BOOLEAN;
}
cp++;
break;
case C_TRUE:
cValues[cp] = 1;
cTypes[cp] = T_BOOLEAN;
cp++;
break;
case C_XOR:
first = popItem();
second = popItem();
cValues[cp] = ((int)second[0]) ^ ((int)first[0]);
if(first[1] == T_NUMBER && second[1] == T_NUMBER){
cTypes[cp] = T_NUMBER;
}else{
cTypes[cp] = T_BOOLEAN;
}
cp++;
break;
case C_IF:
old = dp;
first = popItem();
if (first[0] == 1) {
while (dTypes[dp] != T_SBRACE && dp > 0) {
dp--;
}
dp++;
executeInterval(old);
}
dp = old;
break;
case C_IFELSE:
//todo
old = dp;
first = popItem();
if (first[0] == 1) {
int br = 0;
while(dp > 0){
int cdp = dTypes[dp--];
if(cdp == T_SBRACE){
br++;
}else if(cdp == T_EBRACE){
br--;
}
if(cdp == T_SBRACE && br == 0){
break;
}
}
int end = dp;
br = 0;
while(dp > 0){
int cdp = dTypes[dp--];
if(cdp == T_SBRACE){
br++;
}else if(cdp == T_EBRACE){
br--;
}
if(cdp == T_SBRACE && br == 0){
break;
}
}
dp+=2;
executeInterval(end);
} else {
int br = 0;
while(dp > 0){
int cdp = dTypes[dp--];
if(cdp == T_SBRACE){
br++;
}else if(cdp == T_EBRACE){
br--;
}
if(cdp == T_SBRACE && br == 0){
break;
}
}
dp+=2;
executeInterval(old);
}
dp = old;
break;
case C_COPY:
first = popItem();
if (first[0] > 0) {
n = (int) first[0];
double[] values = new double[n];
int[] types = new int[n];
System.arraycopy(cValues, cValues.length - n, values, 0, n);
System.arraycopy(cTypes, cValues.length - n, types, 0, n);
for (int i = 0; i < n; i++) {
cValues[cp] = values[0];
cTypes[cp] = types[1];
cp++;
}
}
break;
case C_EXCH:
first = popItem();
second = popItem();
cValues[cp] = first[0];
cTypes[cp] = (int)first[1];
cp++;
cValues[cp] = second[0];
cTypes[cp] = (int)second[1];
cp++;
break;
case C_POP:
popItem();
break;
case C_DUP:
first = popItem();
cValues[cp] = first[0];
cTypes[cp] = (int)first[1];
cp++;
cValues[cp] = first[0];
cTypes[cp] = (int)first[1];
cp++;
break;
case C_INDEX:
first = popItem();
n = (int)first[0];
cValues[cp] = cValues[cp - 1 - n];
cTypes[cp] = cTypes[cp - 1 - n];
cp++;
break;
case C_ROLL:
j = (int)(popItem()[0]);
n = (int)(popItem()[0]);
if(n == 0 || j == 0 || n > cp){ //should not roll in these cases
break;
}
LinkedList listV = new LinkedList();
LinkedList listT = new LinkedList();
for (int i = 0; i < n; i++) {
double[] dd = popItem();
listV.add(dd[0]);
listT.add((int)dd[1]);
}
if (j > 0) {
for (int i = 0; i < j; i++) {
double v = listV.removeFirst();
int t = listT.removeFirst();
listV.addLast(v);
listT.addLast(t);
}
} else {
j *= -1;
for (int i = 0; i < j; i++) {
double v = listV.removeLast();
int t = listT.removeLast();
listV.addFirst(v);
listT.addFirst(t);
}
}
for (int i = 0; i < n; i++) {
cValues[cp] = listV.removeLast();
cTypes[cp] = listT.removeLast();
cp++;
}
break;
}
}
private double[] popItem() {
cp--;
return new double[]{cValues[cp], cTypes[cp]};
}
public double[] executeScript(float[] inp) {
Arrays.fill(cValues, 0);
cp = inp.length;
int dLen = dValues.length;
dp = 0;
for (int i = 0; i < inp.length; i++) {
cValues[i] = inp[i];
cTypes[i] = T_NUMBER;
}
executeInterval(dLen);
return cValues;
}
private void executeInterval(int maxDP){
int type;
double value;
while (dp < maxDP) {
type = dTypes[dp];
value = dValues[dp];
switch (type) {
case T_COMMAND:
executeCommand((int) value);
dp++;
break;
case T_NUMBER:
cValues[cp] = dValues[dp];
cTypes[cp] = dTypes[dp];
cp++;
dp++;
break;
case T_SBRACE:
int buff = 1;
while (buff != 0 && dp < maxDP) {
dp++;
int t = dTypes[dp];
if(t == T_SBRACE){
buff++;
}else if(t == T_EBRACE){
buff--;
}
}
break;
default:
dp++;
}
}
}
// public static void main(String[] args) {
// String[] cmds = new String[]{
// "abs", "add", "atan", "ceiling", "cos", "cvi", "cvr", "div", "exp", "floor", "idiv",
// "ln", "log", "mod", "mul", "neg", "sin", "sqrt", "sub", "round", "truncate", "and",
// "bitshift", "eq", "false", "ge", "gt", "le", "lt", "ne", "not", "or", "true", "xor",
// "if", "ifelse", "copy", "exch", "pop", "dup", "index", "roll"};
//
// for (String cmd : cmds) {
//// System.out.println("case C_" + cmd.toUpperCase() + " :\n return C_" + cmd.toUpperCase() + ";");
// }
//
// String ss = "{ 1 index}";
// PostScriptCompiler pp = new PostScriptCompiler(ss.getBytes());
//
// float inp[] = new float[]{4,1,3,2};
// double vv[] = pp.executeScript(inp);
//
// for (int i = 0; i < 5; i++) {
// System.out.println(vv[i]);
// }
// }
}