static void reply(APDU apdu, sbyte a0, sbyte a1, sbyte a2, sbyte a3)
 {
     var buffer = apdu.getBuffer();
     buffer[0] = a0;
     buffer[1] = a1;
     buffer[2] = a2;
     buffer[3] = a3;
     apdu.setOutgoingAndSend(0, 4);
 }
        public short GetAnswerFromOtherApplet(APDU apdu)
        {
            short counter = 0;

            var buffer = apdu.getBuffer();

            var CLA = buffer[ISO7816Constants.OFFSET_CLA];
            var INS = buffer[ISO7816Constants.OFFSET_INS];
            var P1 = buffer[ISO7816Constants.OFFSET_P1];
            var P2 = buffer[ISO7816Constants.OFFSET_P2];
            var LC = buffer[ISO7816Constants.OFFSET_LC];


            //buffer = ret; - need to use array copy!!

            var temp = (byte)0xB2;

            if (CLA == (sbyte)0x00 && INS == (sbyte)temp)
            {
                //last name
                if(P1 == (sbyte)0x01 && P2 == (sbyte)0x04)
                {
                    sbyte[] ret = new sbyte[6];
                    ret[0] = (sbyte)0x6b;
                    ret[1] = (sbyte)0x69;
                    ret[2] = (sbyte)0x69;
                    ret[3] = (sbyte)0x76;
                    ret[4] = (sbyte)0x65;
                    ret[5] = (sbyte)0x72;
                    javacard.framework.Util.arrayCopy(ret, 0, buffer, 0, (short)ret.Length);
                    counter = (short)ret.Length;
                }
                //first name
                else if (P1 == (sbyte)0x02 && P2 == (sbyte)0x04)
                {
                    sbyte[] ret = new sbyte[5];
                    ret[0] = (sbyte)0x6a;
                    ret[1] = (sbyte)0x6f;
                    ret[2] = (sbyte)0x6e;
                    ret[3] = (sbyte)0x61;
                    ret[4] = (sbyte)0x73;
                    javacard.framework.Util.arrayCopy(ret, 0, buffer, 0, (short)ret.Length);
                    counter = (short)ret.Length;
                }
            }

            return counter;
        }
        private void ProvideStorage(APDU apdu)
        {
            // /send 802000000104
            // /send 8030000004CA22FE33
            // /send 8040000004

            var buffer = apdu.getBuffer();

            var CLA = buffer[ISO7816Constants.OFFSET_CLA];
            var INS = buffer[ISO7816Constants.OFFSET_INS];
            var P1 = buffer[ISO7816Constants.OFFSET_P1];
            var P2 = buffer[ISO7816Constants.OFFSET_P2];
            var LC = buffer[ISO7816Constants.OFFSET_LC];

            unchecked
            {
                if (CLA == (sbyte)0x10)
                {
                    #region Add File
                    if (INS == (sbyte)0x1)
                    {
                        var n = new File { NextFile = FirstFile };

                        apdu.setIncomingAndReceive();

                        n.Name = new sbyte[LC];

                        Util.arrayCopyNonAtomic(buffer, (short)(ISO7816Constants.OFFSET_LC + 1), n.Name, 0, LC);

                        this.FirstFile = n;

                        reply(apdu, 6, 6, 6, Count);
                    }
                    #endregion

                    #region Count
                    if (INS == (sbyte)0x2)
                    {
                        reply(apdu, 6, 6, 6, Count);
                    }
                    #endregion

                    //reply(apdu, 6, 6, 1, 1);
                }
            }
        }
        private void ProvideFileSystem(APDU apdu)
        {
            // /send 802000000104
            // /send 8030000004CA22FE33
            // /send 8040000004

            var buffer = apdu.getBuffer();

            var CLA = buffer[ISO7816Constants.OFFSET_CLA];
            var INS = buffer[ISO7816Constants.OFFSET_INS];
            var P1 = buffer[ISO7816Constants.OFFSET_P1];
            var P2 = buffer[ISO7816Constants.OFFSET_P2];
            var LC = buffer[ISO7816Constants.OFFSET_LC];

            
            unchecked
            {
                if (CLA == (sbyte)0x80)
                {
                    if (INS == 0)
                    {

                        buffer[0] = (sbyte)0xDE;
                        buffer[1] = (sbyte)0xAD;
                        buffer[2] = (sbyte)0xBE;
                        buffer[3] = (sbyte)0xEF;
                        apdu.setOutgoingAndSend(0, 4);
                    }
                    else if (INS == (sbyte)0x20)
                    {
                        /*
                        CREATE FILE: creates the file with the size given in the data field
                        APDU: CLA 0x80, INS: 0x20, Lc=0x01, Data=size of the file (max 0xFF=255 bytes)
                        */

                        //apdu.setIncomingAndReceive();

                        var Size = (short)P1;

                        this.FileBytes = new sbyte[Size];
                    }
                    else if (INS == (sbyte)0x30)
                    {
                        /*
                        WRITE FILE: writes the data bytes from the APDU to the file
                        APDU: CLA 0x80, INS: 0x30, Lc=0xXX (number of bytes to write), Data=bytes to write to the file
                        */

                        apdu.setIncomingAndReceive();

                        var length = (short)LC;

                        if (length > this.FileBytes.Length)
                            length = (short)this.FileBytes.Length;

                        Util.arrayCopyNonAtomic(buffer, (short)(ISO7816Constants.OFFSET_LC + 2), this.FileBytes, 0, length);

                    }
                    else if (INS == (byte)0x40)
                    {
                        /*
				
                        READ FILE: sends some the data bytes from the file to the terminal
                        APDU: CLA 0x80, INS: 0x40, Le=0xXX (number of bytes to read)
                         */

                        Util.arrayCopyNonAtomic(this.FileBytes, (short)0, buffer, (short)0, P1);


                        apdu.setOutgoingAndSend((short)0, (short)P1);
                    }
                }
            }
        }
        private void response(APDU apdu)
        {
        //     static void reply(APDU apdu, sbyte a0, sbyte a1, sbyte a2, sbyte a3)
        //{
        //    var buffer = apdu.getBuffer();
        //    buffer[0] = a0;
        //    buffer[1] = a1;
        //    buffer[2] = a2;
        //    buffer[3] = a3;
        //    apdu.setOutgoingAndSend(0, 4);
        //}


            //upload "E:\jsc.svn\examples\java\javacard\JavacardAppletExample\JavacardAppletExample\bin\Release\web\release\JavacardAppletExample\javacard\JavacardAppletExample.cap"
            //upload "E:\jsc.svn\examples\java\javacard\TestjavaAppletCommunication\TestjavaAppletCommunication\bin\Release\web\release\JavacardAppletExample\javacard\JavacardAppletExample.cap"
            //install A0A1A2A3A40002 A0A1A2A3A4000202
            //install A0A1A2A3A40003 A0A1A2A3A4000301

            if (APDU.getProtocol() != APDU.PROTOCOL_MEDIA_USB)
            {

                var buffer = apdu.getBuffer();

                var CLA = buffer[ISO7816Constants.OFFSET_CLA];
                var INS = buffer[ISO7816Constants.OFFSET_INS];
                var P1 = buffer[ISO7816Constants.OFFSET_P1];
                var P2 = buffer[ISO7816Constants.OFFSET_P2];
                var LC = buffer[ISO7816Constants.OFFSET_LC];

                //var rets = new sbyte[5];
                //rets[0] = CLA;
                //rets[1] = INS;
                //rets[2] = P1;
                //rets[3] = P2;
                //rets[4] = LC;

                //buffer = rets;
                //apdu.setOutgoingAndSend(0, (short)rets.Length);


                //reply(apdu, INS, P1, P2, LC);
                List<sbyte[]> whiteList = new List<sbyte[]>();

                byte[] masterFile = new byte[] { 0x00, 0xA4, 0x00, 0x0C };
                byte[] EEEEcatalogue = new byte[] { 0x00, 0xA4, 0x01, 0x0C, 0x02, 0xEE, 0xEE };
                byte[] setSecEnv1 = new byte[] { 0x00, 0x22, 0xF3, 0x01 };
                byte[] signatureHash = new byte[] { 0x00, 0x2a, 0x9E, 0x9A }; // Partly. Additional length and hash is provided
                byte[] pin1VerifyPartly = new byte[] { 0x00, 0x20, 0x00, 0x01};
                byte[] pukVerifyPartly = new byte[] { 0x00, 0x20, 0x00, 0x00 };
                byte[] pin2VerifyPartly = new byte[] { 0x00, 0x20, 0x00, 0x02 }; //additional Pin2 len and Pin2 as ASCII
                byte[] selectFile5044 = new byte[] { 0x00, 0xa4, 0x02, 0x04};
                byte[] selectFromPersoFile = new byte[] {0x00, 0xB2, 0x01, 0x04, 0x00 };
                byte[] readPersoResponse = new byte[] { 0x00, 0xC0, 0x00, 0x00 };


                whiteList.Add((sbyte[])(object)masterFile);
                whiteList.Add((sbyte[])(object)EEEEcatalogue);
                whiteList.Add((sbyte[])(object)setSecEnv1);
                whiteList.Add((sbyte[])(object)signatureHash);
                whiteList.Add((sbyte[])(object)pin1VerifyPartly);
                whiteList.Add((sbyte[])(object)pukVerifyPartly);
                whiteList.Add((sbyte[])(object)pin2VerifyPartly);
                whiteList.Add((sbyte[])(object)selectFile5044);
                //whiteList.Add((sbyte[])(object)selectFromPersoFile);
                whiteList.Add((sbyte[])(object)readPersoResponse);

                var isValid = false;

                foreach (var arr in whiteList)
                {
                    if (arr[0] == CLA && arr[1] == INS && arr[2] == P1 && arr[3] == P2)
                    {
                        isValid = true;
                    }

                    if(CLA == selectFromPersoFile[0] && INS == selectFromPersoFile[1] && selectFromPersoFile[2] > 0x00 && selectFromPersoFile[2] > 0x10 && P2 == selectFromPersoFile[3])
                    {
                        isValid = true;
                    }
                }
                         


                byte[] AID = { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0x00, 0x02, 0x02 };
                var casted = (sbyte[])(object)AID;
                var s = new AID(casted, 0, (sbyte)casted.Length);


                if (casted == null)
                {
                    reply(apdu, 6, 6, 6, 6);
                    return;
                }

                if (s == null)
                {
                    reply(apdu, 5, 5, 5, 5);
                    return;
                }

                if (!isValid)
                {
                    reply(apdu, 2, 2, 2, 2);
                    return;
                }

                var temp = JCSystem.getAppletShareableInterfaceObject(s, 0);

                if (temp == null)
                {
                    reply(apdu, 1, 1, 1, 1);
                }
                else
                {
                    //reply(apdu, 3, 3, 3, 3);
                    
                    test sio = (test)temp;
                    var ret = sio.GetAnswerFromOtherApplet(apdu);
                    if (sio == null)
                    {
                        reply(apdu, 9, 9, 9, 9);
                    }
                    else
                    {
                        if (ret != 0)
                        {
                            apdu.setOutgoingAndSend(0, ret);
                            
                                //reply(apdu, 2, 2, 2, 2);
                                //var b = apdu.getBuffer();
                                //b = ret;
                                //apdu.setOutgoingAndSend(0, (short)ret.Length);
                            //}
                        }
                        else
                        {
                            reply(apdu, 8, 8, 8, 8);
                        }
                    }
                }
            }
            else
            {
                reply(apdu, 5, 5, 5, 5);
            }
        }