All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.function.PostScriptCompiler Maven / Gradle / Ivy

/*
 * ===========================================
 * 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.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[200]; //hold default values
    private final int[] dTypes = new int[200]; //hold default types

    private final double[] cValues = new double[250];
    private final int[] cTypes = new int[250];

    private int sp = 0;//stream pointer
    private int dp = 0;//default pointer
    private int cp = 0;//cur list pointer

    private final Stack braces = new Stack();

    public PostScriptCompiler(final byte[] stream) {
        parseStream(stream);
    }

    private void parseStream(byte[] stream) {
        int len = stream.length;
        while (sp < len) {
            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);
                }
            }
        }
        System.out.println(new String(stream));
    }

    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;
        double[] second;
        int n,j;
        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){
                    
                }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:
                //todo
                popItem();
                break;
            case C_IFELSE:
                //todo
                popItem();
                break;
            case C_COPY:
                first = popItem();
                if(first[0]>1){
                    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:
                cValues[cp] = cValues[cp - 1];
                cTypes[cp] = cTypes[cp - 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];
                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 x = 0; x < j; x++) {
                    for (int i = 0; i < n; i++) {
                        cValues[cp] = values[0];
                        cTypes[cp] = types[1];
                        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;

        System.arraycopy(inp, 0, cValues, 0, inp.length);

        int type;
        double value;
        while (dp < dLen) {
            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:
                    while(dTypes[dp] == T_EBRACE){
                        dp++;
                    }
                    break;
                default:
                    dp++;
            }
        }

        return cValues;

    }

//    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 = "{ abs }";
//        PostScriptCompiler pp = new PostScriptCompiler(ss.getBytes());
//
//        float inp[] = new float[]{-5.2f};
////        inp = pp.executeScript(inp);
//
//        System.out.println(inp[0]);
//    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy