Package uk.co.nimp.scard

Source Code of uk.co.nimp.scard.StarScriptReader

package uk.co.nimp.scard;

import com.atolsystems.atolutilities.AStringUtilities;
import com.atolsystems.atolutilities.InputFileFormatException;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import uk.co.nimp.scard.ScriptPlayer.DelayNs;
import uk.co.nimp.smartcard.Apdu;

/**
*
* @author Sebastien Riou
*/
public class StarScriptReader {
    public static final String COMMENT = "CCMT";
    public static final String COMMENT2 = "COMT";
    public static final String C_STYLE_COMMENT = "//";
    public static final String C_STYLE_MULTILINE_COMMENT_OPEN = "/*";
    public static final String C_STYLE_MULTILINE_COMMENT_CLOSE = "*/";
    public static final String VCC_SETTING = "SVCC";
    public static final String POWER_OFF = "POFF";
    public static final String POWER_ON = "ACTIVATION";//no pps on reader which support that (pcsc do not support it)
    public static final String PCSC_POWER_ON = "PATR";//auto pps
    public static final String COMMAND = "CCMD";
    public static final String COMMAND_TIMEOUT_S = "CCMD_TIMEOUT";//in seconds
    public static final String COMMAND_PUSH_TIMEOUT_S = "CCMD_PUSH_TIMEOUT";//in seconds
    public static final String COMMAND_POP_TIMEOUT_S = "CCMD_POP_TIMEOUT";
    public static final String SAVE_RESULT = "SAVE";
    public static final String SAVE_IMMEDIATE_DATA = "SAVD";
    public static final String COMPARE = "CCMP";
    public static final String FIELD_ABSENT = "--";
    public static final String AND_OP = "AND";
    public static final String OR_OP = "OR";
    public static final String XOR_OP = "XOR";
    public static final String DELAY_MS = "DELY";
    /*PATR: Power On
    POFF: Power Off
    CCMD: ISO 7816 Command
    SAVE: Save output in buffer 'X'
    CCMP: Compare buffer 'X' with buffer 'X'
    SVCC: Select Voltage of VCC
    FREQ: Vary Frequency
    BREK: Break Point
    SAVD: variable save
    DELY: delay time after command execution(unit: ms)
    SCUR: Start Current Measurement
    GCUR: Get Average Current measured

*/

    public static final String PCSC_POWER_ON_ARG_COLD = "COLD";
    public static final String PCSC_POWER_ON_ARG_WARM = "WARM";

    protected static final String SYNTAX_ERROR_HEADER = "Star script syntax error at line ";
    protected static final String NO_ARG_ERROR = " does not take any argument so nothing else should be written on the same line.\n";

    protected List<Object> cmds;

    public StarScriptReader(File scriptFile) throws FileNotFoundException, IOException, InputFileFormatException {
        cmds=new ArrayList<Object>();
        parse(scriptFile);
    }

    protected void parseActivationParameter(String args, String activationCmd){
        args=AStringUtilities.removeLeadingBlanks(args);
        args=AStringUtilities.removeTrailingBlanks(args);
        int protocol=GenericTerminal.PROTOCOL_ANY;
        int activation=GenericTerminal.ACTIVATION_ANY;
        if(false==args.isEmpty()){//arg is there, look for activation spec
            if(args.startsWith(PCSC_POWER_ON_ARG_COLD)){
                activation=GenericTerminal.ACTIVATION_FORCE_COLD;
                args=args.substring(PCSC_POWER_ON_ARG_COLD.length());
            } else if(args.startsWith(PCSC_POWER_ON_ARG_WARM)){
                activation=GenericTerminal.ACTIVATION_FORCE_WARM;
                args=args.substring(PCSC_POWER_ON_ARG_WARM.length());
            }
            args=AStringUtilities.removeLeadingBlanks(args);
        }
        if(false==args.isEmpty()){//arg is there, look for protocol spec
            int match[]=AStringUtilities.findFirstRegExp2(args, "\\*|"+
                    GenericTerminal.PROTOCOL_NAME_T_0+"|"+
                    GenericTerminal.PROTOCOL_NAME_T_1+"|"+
                    GenericTerminal.PROTOCOL_NAME_ANY_STD_CL);
            if(0==match[0]){//arg found
                protocol=GenericTerminal.getProtocolCode(args.substring(0,match[1]));
                args=args.substring(match[1]);
                args=AStringUtilities.removeLeadingBlanks(args);
            }
        }
        if(false==args.isEmpty()){//arg is there, look for frequency
            int frequency=Integer.decode(args);
            cmds.add(new ScriptPlayer.Frequency(frequency));
            args="";
        }
        //no more args allowed here
        if(false==args.isEmpty())
            throw new RuntimeException(activationCmd+" take at most 3 arguments.");
        if(activationCmd.equals(PCSC_POWER_ON))
            cmds.add(new ScriptPlayer.PcscPowerOn(protocol, activation));
        else
            cmds.add(new ScriptPlayer.PowerOn(activation));
    }
    String removeTrailingBlanksAndComments(String in){
        int i=in.indexOf("//");
        String out;
        if(-1!=i)
            out=in.substring(0, i);
        else
            out=AStringUtilities.removeTrailingBlanks(in);
        return out;
    }
    protected final void parse(File scriptFile) throws FileNotFoundException, IOException, InputFileFormatException{
        FileReader fr=new FileReader(scriptFile);
        try{
            BufferedReader br=new BufferedReader(fr);
            int lineNumber=0;
            String line="";
            String args="";
            int multilineCommentLevel=0;
            try{
                while(null!=line){
                    line=AStringUtilities.removeLeadingBlanks(line);
                    if(!line.isEmpty()){
                        if(0==multilineCommentLevel){
                            if(line.startsWith(COMMENT) | line.startsWith(COMMENT2)){
                                String comment;
                                if(line.startsWith(COMMENT+" "))
                                    comment=line.substring(COMMENT.length()+1);
                                else
                                    comment=line.substring(COMMENT.length());
                                comment=AStringUtilities.removeTrailingBlanks(comment);
                                cmds.add(comment);

                            } else if(line.startsWith(C_STYLE_COMMENT)){
                                //C Style comments are ignore completely so the user can write comments which are really just
                                //for people who actually read the script file
                                /*String comment=line.substring(C_STYLE_COMMENT.length());
                                comment=AStringUtilities.removeTrailingBlanks(comment);
                                cmds.add(comment);*/
                            } else if(line.startsWith(VCC_SETTING)){
                                args=line.substring(VCC_SETTING.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                int voltage=Integer.parseInt(args);
                                cmds.add(new ScriptPlayer.PowerSupplyVoltage(voltage));
                            } else if(line.startsWith(POWER_OFF)){
                                args=line.substring(POWER_OFF.length());
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                //no args allowed here
                                if(false==args.isEmpty())
                                    throw new RuntimeException(POWER_OFF+NO_ARG_ERROR);
                                cmds.add(new ScriptPlayer.PowerOff());

                            } else if(line.startsWith(PCSC_POWER_ON)){
                                args=line.substring(PCSC_POWER_ON.length());
                                parseActivationParameter(args, PCSC_POWER_ON);
                            } else if(line.startsWith(POWER_ON)){
                                args=line.substring(POWER_ON.length());
                                parseActivationParameter(args, POWER_ON);
                            } else if(line.startsWith(COMMAND_TIMEOUT_S)){
                                args=line.substring(COMMAND_TIMEOUT_S.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND_TIMEOUT_S+": timeout value not found");
                                String[] argArray = args.split("\\s");
                                if(1!=argArray.length)
                                    throw new RuntimeException(COMMAND_TIMEOUT_S+" take 1 argument, but "+argArray.length+" arguments have been found.");
                                int commandTimeout=Integer.parseInt(argArray[0]);
                                cmds.add(new ScriptPlayer.ApduTimeout(commandTimeout*1000));
                            }else if(line.startsWith(COMMAND_PUSH_TIMEOUT_S)){
                                args=line.substring(COMMAND_PUSH_TIMEOUT_S.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND_PUSH_TIMEOUT_S+": timeout value not found");
                                String[] argArray = args.split("\\s");
                                if(1!=argArray.length)
                                    throw new RuntimeException(COMMAND_PUSH_TIMEOUT_S+" take 1 argument, but "+argArray.length+" arguments have been found.");
                                int commandTimeout=Integer.parseInt(argArray[0]);
                                cmds.add(new ScriptPlayer.ApduTimeoutPush(commandTimeout*1000));
                            }else if(line.startsWith(COMMAND_POP_TIMEOUT_S)){
                                args=line.substring(COMMAND_POP_TIMEOUT_S.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(false==args.isEmpty())
                                    throw new RuntimeException(COMMAND_POP_TIMEOUT_S+" take no argument.");
                                cmds.add(new ScriptPlayer.ApduTimeoutPop());
                            }else if(line.startsWith(COMMAND)){
                                args=line.substring(COMMAND.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": CLA byte not found");
                                int cla=Integer.parseInt(args.substring(0,2), 16);
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": INS byte not found");
                                int ins=Integer.parseInt(args.substring(0,2), 16);
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": P1 byte not found");
                                int p1=Integer.parseInt(args.substring(0,2), 16);
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": P2 byte not found");
                                int p2=Integer.parseInt(args.substring(0,2), 16);
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": LC FIELD not found");
                                int lc=0;
                                if(false==args.startsWith(FIELD_ABSENT))
                                    lc=Integer.parseInt(args.substring(0,2), 16);
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMMAND+": LE FIELD not found");
                                int le=0;
                                if(false==args.startsWith(FIELD_ABSENT)){
                                    le=Integer.parseInt(args.substring(0,2), 16);
                                    if(0==le)
                                        le=256;
                                }
                                args=args.substring(2);
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);
                                //args=args.replace(" ", "");//to allow formating of lc data
                                Apdu apdu=new Apdu(cla,ins,p1,p2,lc,le);
                                if(0<lc){//we should find some data here
                                    apdu.setLcData(args, " ");
                                    if(lc!=apdu.getLc())
                                        throw new RuntimeException("LC field indicate "+lc+
                                                " bytes but "+apdu.getLc()+" bytes of data have been found.");
                                    args="";
                                }
                                //no args allowed here
                                if(false==args.isEmpty())
                                    throw new RuntimeException(COMMAND+" take at most 7 arguments. This may due to a mismatch between Lc and Lc Data length");

                                cmds.add(apdu);
                            }else if(line.startsWith(SAVE_RESULT)){
                                args=line.substring(SAVE_RESULT.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(SAVE_RESULT+": target buffer ID not found");
                                String[] argArray = args.split("\\s");
                                if(1!=argArray.length)
                                    throw new RuntimeException(SAVE_RESULT+" take 1 argument, but "+argArray.length+" arguments have been found.");
                                Integer id=Integer.parseInt(argArray[0]);
                                cmds.add(id);
                            } else if(line.startsWith(SAVE_IMMEDIATE_DATA)){
                                args=line.substring(SAVE_IMMEDIATE_DATA.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(SAVE_IMMEDIATE_DATA+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(2!=argArray.length)
                                    throw new RuntimeException(SAVE_IMMEDIATE_DATA+" take 2 arguments, but "+argArray.length+" arguments have been found.");
                                int id=Integer.parseInt(argArray[0]);
                                byte leData[]=AStringUtilities.hexToBytes(argArray[1].substring(0,argArray[1].length()-4));
                                short statusWord=AStringUtilities.hexToShort(argArray[1].substring(argArray[1].length()-4));
                                ScriptPlayer.ExpectedApduResponse expectedApduResponse=new ScriptPlayer.ExpectedApduResponse(id,leData,statusWord);
                                cmds.add(expectedApduResponse);
                            } else if(line.startsWith(COMPARE)){
                                args=line.substring(COMPARE.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(COMPARE+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(2!=argArray.length)
                                    throw new RuntimeException(COMPARE+" take 2 arguments, but "+argArray.length+" arguments have been found.");
                                int id1=Integer.parseInt(argArray[0]);
                                int id2=Integer.parseInt(argArray[1]);
                                ScriptPlayer.BufferOperation bufferOperation=new ScriptPlayer.BufferOperation(id1,id2,ScriptPlayer.BufferOperation.OP_FULL_COMPARISON);
                                cmds.add(bufferOperation);
                            } else if(line.startsWith(AND_OP)){
                                args=line.substring(AND_OP.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(AND_OP+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(2!=argArray.length)
                                    throw new RuntimeException(AND_OP+" take 2 arguments, but "+argArray.length+" arguments have been found.");
                                int id1=Integer.parseInt(argArray[0]);
                                int id2=Integer.parseInt(argArray[1]);
                                ScriptPlayer.BufferOperation bufferOperation=new ScriptPlayer.BufferOperation(id1,id2,ScriptPlayer.BufferOperation.OP_AND);
                                cmds.add(bufferOperation);
                            } else if(line.startsWith(OR_OP)){
                                args=line.substring(OR_OP.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(OR_OP+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(2!=argArray.length)
                                    throw new RuntimeException(OR_OP+" take 2 arguments, but "+argArray.length+" arguments have been found.");
                                int id1=Integer.parseInt(argArray[0]);
                                int id2=Integer.parseInt(argArray[1]);
                                ScriptPlayer.BufferOperation bufferOperation=new ScriptPlayer.BufferOperation(id1,id2,ScriptPlayer.BufferOperation.OP_OR);
                                cmds.add(bufferOperation);
                            } else if(line.startsWith(XOR_OP)){
                                args=line.substring(XOR_OP.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(XOR_OP+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(2!=argArray.length)
                                    throw new RuntimeException(XOR_OP+" take 2 arguments, but "+argArray.length+" arguments have been found.");
                                int id1=Integer.parseInt(argArray[0]);
                                int id2=Integer.parseInt(argArray[1]);
                                ScriptPlayer.BufferOperation bufferOperation=new ScriptPlayer.BufferOperation(id1,id2,ScriptPlayer.BufferOperation.OP_XOR);
                                cmds.add(bufferOperation);
                            } else if(line.startsWith(DELAY_MS)){
                                args=line.substring(DELAY_MS.length());
                                args=AStringUtilities.removeLeadingBlanks(args);
                                args=removeTrailingBlanksAndComments(args);//AStringUtilities.removeTrailingBlanks(args);
                                if(args.isEmpty())
                                    throw new RuntimeException(DELAY_MS+": arguments not found");
                                String[] argArray = args.split("\\s");
                                if(1!=argArray.length)
                                    throw new RuntimeException(DELAY_MS+" take 1 argument, but "+argArray.length+" arguments have been found.");
                                long delayMs=Integer.parseInt(argArray[0]);
                                cmds.add(new DelayNs(delayMs*1000000));
                            } else if(line.startsWith(C_STYLE_MULTILINE_COMMENT_OPEN))
                                multilineCommentLevel++;
                            else if(line.startsWith(C_STYLE_MULTILINE_COMMENT_CLOSE))
                                throw new RuntimeException("C style multiline comment unmatched: multilineCommentLevel="+multilineCommentLevel);
                            else {
                                throw new RuntimeException("Unable to parse the line");
                            }
                            args="";
                        }else if(line.startsWith(C_STYLE_MULTILINE_COMMENT_OPEN))
                            multilineCommentLevel++;
                        else if(line.startsWith(C_STYLE_MULTILINE_COMMENT_CLOSE))
                            multilineCommentLevel--;
                    }
                    line=br.readLine();
                    lineNumber++;
                }
            } catch(RuntimeException e){
                throw new InputFileFormatException(SYNTAX_ERROR_HEADER+lineNumber+"\n\n"+line+"\n\nArgument stack:["+args+"]\n",e);
            } finally {
                br.close();
            }
        }finally{
            fr.close();
        }
    }

    /**
     * Get the value of cmds
     *
     * @return the value of cmds
     */
    public List<? extends Object> getCmds() {
        return cmds;
    }

    /**
     * Set the value of cmds
     *
     * @param cmds new value of cmds
     */
    public void setCmds(List<? extends Object> cmds) {
        this.cmds = (List<Object>) cmds;
    }
    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    /**
     * Add PropertyChangeListener.
     *
     * @param listener
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    /**
     * Remove PropertyChangeListener.
     *
     * @param listener
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

}
TOP

Related Classes of uk.co.nimp.scard.StarScriptReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.