Exemple #1
0
        static void Main(string[] args)
        {
            var TargetAssembly = Assembly.LoadFile(Path.GetFullPath(args[0]));
            var TargetType     = TargetAssembly.GetType(args[1], true);
            var TargetFile     = args[2];
            var ProxyFullname  = args[3];
            var ProxyNamespace = ProxyFullname.Substring(0, ProxyFullname.LastIndexOf("."));
            var ProxyName      = ProxyFullname.Substring(ProxyFullname.LastIndexOf(".") + 1);

            AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args_)
            {
                string name = new AssemblyName(args_.Name).Name;


                string file_dll = new FileInfo(TargetAssembly.Location).Directory.FullName + @"\" + name + ".dll";
                string file_exe = new FileInfo(TargetAssembly.Location).Directory.FullName + @"\" + name + ".exe";


                var x = File.Exists(file_dll) ? Assembly.LoadFile(file_dll) :
                        (File.Exists(file_exe) ? Assembly.LoadFile(file_exe) : null);

                return(x);
            };

            var ExportedMethods =
                from SomeType in TargetType.GetCustomAttributes(typeof(AlchemyAttribute), false).Cast <AlchemyAttribute>()
                from m in SomeType.TargetType.GetMethods(BindingFlags.Static | BindingFlags.Public)
                let Parameters = m.GetParameters()
                                 select new { m, Parameters };

            var CModuleNamespacePartial = Path.GetFileNameWithoutExtension(TargetAssembly.Location);

            if (CModuleNamespacePartial.IndexOf(".") > -1)
            {
                CModuleNamespacePartial = CModuleNamespacePartial.Substring(0, CModuleNamespacePartial.IndexOf("."));
            }

            var CModuleNamespace = "cmodule." + CModuleNamespacePartial;

            using (var p = new ProtectiveFileStream(new FileInfo(TargetFile)))
                using (var s = new StreamWriter(p))
                    using (var w = new CodeWriter(s))
                    {
                        p.NotModified +=
                            delegate
                        {
                            Console.WriteLine("Not modified. " + TargetFile);
                        };

                        s.BaseStream.SetLength(0);

                        w.Statement("// Generated by ScriptCoreLib.Alchemy.ExportGenerator");
                        w.Statement("// Clear this file to force code generation.");

                        #region cmodule
                        w.Namespace(CModuleNamespace,
                                    delegate
                        {
                            w.Using("ScriptCoreLib");
                            w.Using("ScriptCoreLib.ActionScript.flash.utils");
                            w.Using("ScriptCoreLib.ActionScript.flash.display");

                            w.Statement("[global::System.Runtime.CompilerServices.CompilerGenerated]");
                            w.Statement("[Script(IsNative = true)]");
                            w.Block("public class CLibInit",
                                    delegate
                            {
                                w.Block("public void supplyFile(string path, ByteArray data)", null);
                                w.Block("public void putEnv(string key, string value)", null);
                                w.Block("public void setSprite(Sprite sprite)", null);
                                w.Block("public object init()",
                                        delegate
                                {
                                    w.Statement("return default(object);");
                                }
                                        );
                            }
                                    );
                        }
                                    );
                        #endregion

                        #region exported methods and main
                        w.Namespace(TargetType.Namespace,
                                    delegate
                        {
                            w.Using("ScriptCoreLib");
                            w.Using("ScriptCoreLib.Alchemy.Headers");
                            w.Block("partial class " + TargetType.Name,
                                    delegate
                            {
                                #region exposed methods
                                foreach (var k in ExportedMethods)
                                {
                                    w.Statement("[global::System.Runtime.CompilerServices.CompilerGenerated]");
                                    w.Block("static AS3_h._AS3_Val " + k.m.Name + "(object self, AS3_h._AS3_Val args)",
                                            delegate
                                    {
                                        foreach (var Parameter in k.Parameters)
                                        {
                                            if (typeof(int) == Parameter.ParameterType)
                                            {
                                                w.Statement("int " + Parameter.Name + ";");
                                            }
                                            else
                                            {
                                                throw new NotSupportedException();
                                            }
                                        }

                                        if (k.Parameters.Length > 0)
                                        {
                                            w.Statement("AS3_h.AS3_ArrayValue(args, \"" +
                                                        string.Join(", ",
                                                                    k.Parameters.Select(
                                                                        Parameter =>
                                            {
                                                return("IntType");
                                            }
                                                                        ).ToArray()
                                                                    )
                                                        + "\", __arglist(" +
                                                        string.Join(", ",
                                                                    k.Parameters.Select(
                                                                        Parameter =>
                                            {
                                                return("out " + Parameter.Name);
                                            }
                                                                        ).ToArray()
                                                                    )
                                                        + "));");
                                        }

                                        w.Statement("var __value = " + k.m.DeclaringType.FullName + "." + k.m.Name + "(" +
                                                    string.Join(", ",
                                                                k.Parameters.Select(
                                                                    Parameter =>
                                        {
                                            return(Parameter.Name);
                                        }
                                                                    ).ToArray()
                                                                )
                                                    + ");"
                                                    );

                                        foreach (var Parameter in k.Parameters)
                                        {
                                            if (typeof(int) == Parameter.ParameterType)
                                            {
                                                w.Statement(Parameter.Name + " = default(int);");
                                            }
                                            else
                                            {
                                                throw new NotSupportedException();
                                            }
                                        }

                                        if (k.m.ReflectedType.IsClass)
                                        {
                                            w.Statement("return AS3_h.AS3_Ptr(__value);");
                                        }
                                        else if (k.m.ReflectedType == typeof(string))
                                        {
                                            w.Statement("return AS3_h.AS3_String(__value);");
                                        }
                                        else
                                        {
                                            throw new NotSupportedException();
                                        }
                                    }
                                            );
                                }
                                #endregion

                                w.Statement("[global::System.Runtime.CompilerServices.CompilerGenerated]");
                                w.Statement("[Script(NoDecoration = true)]");
                                w.Block("static int main()",
                                        delegate
                                {
                                    foreach (var k in ExportedMethods)
                                    {
                                        w.Statement("var __" + k.m.Name + " = AS3_h.AS3_Function(null, " + k.m.Name + ");");
                                    }

                                    w.Statement("var __result = AS3_h.AS3_Object(\"" +
                                                string.Join(",",
                                                            ExportedMethods.Select(
                                                                m =>
                                    {
                                        return(m.m.Name + ": AS3ValType");
                                    }
                                                                ).ToArray()
                                                            )
                                                + "\", __arglist(" +
                                                string.Join(",",
                                                            ExportedMethods.Select(
                                                                m =>
                                    {
                                        return("__" + m.m.Name);
                                    }
                                                                ).ToArray()
                                                            )
                                                + "));");


                                    foreach (var k in ExportedMethods)
                                    {
                                        w.Statement("AS3_h.AS3_Release(__" + k.m.Name + ");");
                                    }

                                    w.Statement("AS3_h.AS3_LibInit(__result);");
                                    w.Statement("return 0;");
                                }
                                        );
                            }
                                    );
                        }
                                    );
                        #endregion

                        w.Namespace(ProxyNamespace,
                                    delegate
                        {
                            w.Using("System");
                            w.Using("ScriptCoreLib");
                            w.Using("ScriptCoreLib.ActionScript");
                            w.Using("ScriptCoreLib.ActionScript.Extensions");
                            w.Using("ScriptCoreLib.ActionScript.flash.utils");

                            w.Statement("[global::System.Runtime.CompilerServices.CompilerGenerated]");
                            w.Statement("[Script]");
                            w.Block("public static class " + ProxyName,
                                    delegate
                            {
                                w.Statement("public static ByteArray Memory;");

                                w.Statement("[Script(OptimizedCode = @\"return (ns::gstate).ds\")]");
                                w.Block("public static ByteArray get_ds(Namespace ns)",
                                        delegate
                                {
                                    w.Statement("return default(ByteArray);");
                                }
                                        );

                                Func <MethodInfo, string> GetGenericTypes =
                                    m =>
                                {
                                    var ReturnType = "";

                                    // a pointer
                                    if (m.ReturnType.IsArray)
                                    {
                                        ReturnType = "uint";
                                    }
                                    else if (m.ReturnType == typeof(string))
                                    {
                                        ReturnType = "string";
                                    }
                                    else if (m.ReturnType == typeof(int))
                                    {
                                        ReturnType = "int";
                                    }
                                    else
                                    {
                                        throw new NotSupportedException(m.ReturnType.FullName);
                                    }

                                    return(string.Join(", ",
                                                       m.GetParameters().Select(
                                                           Parameter =>
                                    {
                                        if (Parameter.ParameterType == typeof(int))
                                        {
                                            return "int";
                                        }

                                        if (Parameter.ParameterType == typeof(string))
                                        {
                                            return "string";
                                        }

                                        throw new NotSupportedException();
                                    }
                                                           ).ToArray()
                                                       )
                                           + (m.GetParameters().Any() ? ", " : "")
                                           + ReturnType);
                                };


                                foreach (var k in ExportedMethods)
                                {
                                    w.Statement("public static readonly Func<" + GetGenericTypes(k.m) + "> " + k.m.Name + ";");
                                }

                                w.Block("static " + ProxyName + "()",
                                        delegate
                                {
                                    w.Statement("var __loader = new " + CModuleNamespace + ".CLibInit();");
                                    w.Statement("var __lib = new DynamicDelegatesContainer { Subject = __loader.init() };");
                                    w.Statement(ProxyName + ".Memory = get_ds(new Namespace(\"" + CModuleNamespace + "\"));");

                                    foreach (var k in ExportedMethods)
                                    {
                                        w.Statement(ProxyName + "." + k.m.Name + " = __lib.ToFunc<" + GetGenericTypes(k.m) + ">(\"" + k.m.Name + "\");");
                                    }
                                }
                                        );
                            }
                                    );
                        }
                                    );
                    }
        }
        static void Main(string[] args)
        {
            var TargetAssembly = Assembly.LoadFile(Path.GetFullPath(args[0]));
            var TargetType     = TargetAssembly.GetType(args[1], true);
            var TargetFile     = args[2];

            using (var p = new ProtectiveFileStream(new FileInfo(TargetFile)))
                using (var s = new StreamWriter(p))
                    using (var w = new CodeWriter(s))
                    {
                        p.NotModified +=
                            delegate
                        {
                            Console.WriteLine("Not modified. " + TargetFile);
                        };

                        #region content
                        s.BaseStream.SetLength(0);

                        w.Statement("// The code was generated. Modifications will be lost if regenerated.");

                        var source = from k in TargetType.GetMethods()
                                     let CLA = k.GetCustomAttributes(typeof(APDUClassAttribute), false).Cast <APDUClassAttribute>().FirstOrDefault()
                                               where CLA != null
                                               let INS = k.GetCustomAttributes(typeof(APDUInstructionAttribute), false).Cast <APDUInstructionAttribute>().FirstOrDefault()
                                                         where INS != null
                                                         group new { k, CLA, INS } by CLA;


                        if (TargetFile.EndsWith(".Dispatch.cs"))
                        {
                            Console.WriteLine("will create dispatcher... " + TargetType.Name);


                            #region .Dispatch.cs for card
                            //w.Statement("using ScriptCoreLibJavaCard.javacard.framework;");
                            w.Statement("using " + typeof(Applet).Namespace + ";");

                            w.PartialTypeBlock(TargetType, null,
                                               delegate
                            {
                                w.Statement("[System.Runtime.CompilerServices.CompilerGeneratedAttribute]");
                                w.Block("internal bool Dispatch(APDU e)",
                                        delegate
                                {
                                    w.Statement("var buffer = e.getBuffer();");
                                    w.Statement("var CLA = (byte)buffer[ISO7816Constants.OFFSET_CLA];");
                                    w.Statement("var INS = (byte)buffer[ISO7816Constants.OFFSET_INS];");

                                    w.Statement("var P1 = (byte)buffer[ISO7816Constants.OFFSET_P1];");
                                    w.Statement("var P2 = (byte)buffer[ISO7816Constants.OFFSET_P2];");
                                    w.Statement("var Pi8 = (short)(((P1 & 0xff) << 8) + (P2 & 0xff));");


                                    foreach (var k in source)
                                    {
                                        #region CLA
                                        w.Region("CLA " + k.Key.CLA.ToHexLiteral(),
                                                 delegate
                                        {
                                            w.Block("if (CLA == " + k.Key.CLA.ToHexLiteral() + ")",
                                                    delegate
                                            {
                                                var Instructions = k.Select((q, i) => new { q.k, q.CLA, INS = q.CLA.AutoAssignInstructions ? (byte)i : q.INS.INS }).OrderBy(ik => ik.INS).ToArray();

                                                foreach (var i in Instructions.GroupBy(ik => ik.INS))
                                                {
                                                    #region INS

                                                    w.Block("if (INS == " + i.Key.ToHexLiteral() + ")",
                                                            delegate
                                                    {
                                                        // default calling convention...
                                                        // could be extended

                                                        if (i.Count() == 1)
                                                        {
                                                            DispatcherInvoke(w, i.Single().k);

                                                            w.Statement("return true;");
                                                        }
                                                        else
                                                        {
                                                            // we shall distinguish instructions via
                                                            // byte P1, yay

                                                            foreach (var jj in
                                                                     from j in i
                                                                     let jpp = j.k.GetParameters()
                                                                               where jpp.Length >= 1
                                                                               let j_P1 = jpp[1]
                                                                                          where j_P1.ParameterType == typeof(byte)
                                                                                          where (j_P1.Attributes & ParameterAttributes.HasDefault) == ParameterAttributes.HasDefault
                                                                                          let j_P1_value = (byte)j_P1.DefaultValue
                                                                                                           orderby j_P1_value
                                                                                                           select new { P1 = j_P1_value, j.k, j.CLA, j.INS }
                                                                     )
                                                            {
                                                                w.Block("if (P1 == " + jj.P1.ToHexLiteral() + ")",
                                                                        delegate
                                                                {
                                                                    DispatcherInvoke(w, jj.k);
                                                                    w.Statement("return true;");
                                                                }
                                                                        );
                                                            }

                                                            // maybe invoke the one without a default P1?
                                                            w.Statement("return false;");
                                                        }
                                                    }
                                                            );

                                                    #endregion
                                                }
                                            }
                                                    );
                                        }
                                                 );
                                        #endregion
                                    }

                                    w.Statement("return false;");
                                }
                                        );
                            }
                                               );
                            #endregion
                        }
                        else
                        {
                            Console.WriteLine("will create proxy... " + TargetType.Name);

                            #region proxy for host
                            //w.Statement("using ScriptCoreLib;");
                            w.Statement("using System;");

                            w.Block("namespace " + TargetType.Namespace,
                                    delegate
                            {
                                w.Statement("[System.Runtime.CompilerServices.CompilerGeneratedAttribute]");
                                //w.Statement("[Script]");

                                w.Block("public partial class " + TargetType.Name + "Proxy",
                                        delegate
                                {
                                    #region LengthExpected
                                    w.Statement("public byte LengthExpected;");
                                    w.Statement("public bool IsLengthExpectedSpecified;");

                                    w.Statement("public delegate void ByteArrayAction(byte[] e);");
                                    w.Statement("public ByteArrayAction Tx;");
                                    w.Statement("public ByteArrayAction Rx;");

                                    w.Block("protected byte[] InternalTransmit(byte[] data)",
                                            delegate
                                    {
                                        w.Statement("if (Tx != null) Tx(data);");
                                        w.Statement("var r = this.Transmitter.Transmit(data);");
                                        w.Statement("if (Rx != null) Rx(r);");
                                        w.Statement("return r;");
                                    }
                                            );

                                    //w.Statement("[Script]");
                                    w.Block("class WithLengthExpected_IDisposable : IDisposable",
                                            delegate
                                    {
                                        w.Statement("byte __LengthExpected;");
                                        w.Statement("bool __IsLengthExpectedSpecified;");
                                        w.Statement(TargetType.Name + "Proxy context;");

                                        w.Block("public WithLengthExpected_IDisposable(" + TargetType.Name + "Proxy context, byte value)",
                                                delegate
                                        {
                                            w.Statement("__LengthExpected = context.LengthExpected;");
                                            w.Statement("__IsLengthExpectedSpecified = context.IsLengthExpectedSpecified;");

                                            w.Statement("context.LengthExpected = value;");
                                            w.Statement("context.IsLengthExpectedSpecified = true;");

                                            w.Statement("this.context = context;");
                                        }
                                                );

                                        w.Block("public void Dispose()",
                                                delegate
                                        {
                                            w.Statement("this.context.LengthExpected = __LengthExpected;");
                                            w.Statement("this.context.IsLengthExpectedSpecified = __IsLengthExpectedSpecified;");
                                        }
                                                );
                                    }
                                            );

                                    w.Block("public IDisposable WithLengthExpected(byte value)",
                                            delegate
                                    {
                                        w.Statement("return new WithLengthExpected_IDisposable(this, value);");
                                    }
                                            );
                                    #endregion

                                    #region Tokens
                                    foreach (var Token in source.SelectMany(k => k).SelectMany(k => new[] { k.INS.InputParameterType, k.INS.OutputParameterType }).Where(k => k != null).Distinct())
                                    {
                                        #region GetCleanName
                                        Func <MethodInfo, string> GetCleanName =
                                            m =>
                                        {
                                            var Prefix = Token.Name + "_";

                                            if (m.Name.StartsWith(Prefix))
                                            {
                                                return(m.Name.Substring(Prefix.Length));
                                            }

                                            return(m.Name);
                                        };
                                        #endregion

                                        //w.Statement("[Script]");
                                        w.Block("public partial class " + Token.Name,
                                                delegate
                                        {
                                            foreach (var enumerator in source.SelectMany(k => k).Where(k => k.INS.InputParameterType == Token && k.INS.OutputParameterType == Token))
                                            {
                                                //w.Statement("[Script]");
                                                w.Block("public partial class " + GetCleanName(enumerator.k) + "Enumerator",
                                                        delegate
                                                {
                                                    w.Statement("private readonly " + TargetType.Name + "Proxy Host;");

                                                    w.Block("public " + GetCleanName(enumerator.k) + "Enumerator(" + TargetType.Name + "Proxy Host)",
                                                            delegate
                                                    {
                                                        w.Statement("this.Host = Host;");
                                                    }
                                                            );

                                                    w.Block("public bool MoveNext()",
                                                            delegate
                                                    {
                                                        w.Statement("this.Current = " + Token.Name + "." + GetCleanName(enumerator.k) + "(this.Host, this.Current);");
                                                        w.Statement("return Current != null;");
                                                    }
                                                            );

                                                    w.Block("public " + Token.Name + " Current",
                                                            delegate
                                                    {
                                                        w.Statement("get;");
                                                        w.Statement("private set;");
                                                    }
                                                            );
                                                }
                                                        );

                                                //w.Statement("[Script]");
                                                w.Block("public partial class " + GetCleanName(enumerator.k) + "Enumerable",
                                                        delegate
                                                {
                                                    w.Statement("private readonly " + TargetType.Name + "Proxy Host;");

                                                    w.Block("public " + GetCleanName(enumerator.k) + "Enumerable(" + TargetType.Name + "Proxy Host)",
                                                            delegate
                                                    {
                                                        w.Statement("this.Host = Host;");
                                                    }
                                                            );

                                                    w.Block("public " + GetCleanName(enumerator.k) + "Enumerator GetEnumerator()",
                                                            delegate
                                                    {
                                                        w.Statement("return new " + GetCleanName(enumerator.k) + "Enumerator(this.Host);");
                                                    }
                                                            );
                                                }
                                                        );
                                            }

                                            w.Statement("public " + TargetType.Name + "Proxy Host { get; set; }");
                                            w.Statement("public short Token { get; set; }");

                                            w.Block("public static implicit operator short(" + Token.Name + " e)",
                                                    delegate
                                            {
                                                w.Statement("if (e == null) return -1;");
                                                w.Statement("return e.Token;");
                                            }
                                                    );

                                            w.Block("static private " + Token.Name + " FromBytes(" + TargetType.Name + "Proxy host, byte[] data)",
                                                    delegate
                                            {
                                                w.Statement("if (data.Length != 4) return null;");
                                                w.Statement("if (data[2] != 0x90) return null;");
                                                w.Statement("if (data[3] != 0x00) return null;");

                                                w.Statement("var P1 = data[0];");
                                                w.Statement("var P2 = data[1];");
                                                w.Statement("var Pi8 = (short)(((P1 & 0xff) << 8) + (P2 & 0xff));");

                                                w.Statement("if (Pi8 < 0) return null;");


                                                w.Statement("return new " + Token.Name + " { Host = host, Token = Pi8 };");
                                            }
                                                    );
                                        }
                                                );
                                    }

                                    #endregion

                                    //w.Statement("[Script]");
                                    w.Block("public interface ITransmitter",
                                            delegate
                                    {
                                        w.Statement("byte[] Transmit(params byte[] e);");
                                    }
                                            );

                                    w.Statement("public ITransmitter Transmitter;");



                                    //w.Statement("public const long ApplicationAID = " + TargetAssembly.GetCustomAttributes(typeof(AIDAttribute), false).Cast<AIDAttribute>().First().Value + "L;");
                                    //w.Statement("public const long DefaultInstallationSuffix = " + TargetType.GetCustomAttributes(typeof(AIDAttribute), false).Cast<AIDAttribute>().First().Value + "L;");

                                    Action <object[]> Transmit =
                                        c =>
                                    {
                                        w.Statement("return this.Transmitter.Transmit(" + c.Aggregate("",
                                                                                                      (seed, value) =>
                                        {
                                            var x = value is byte? "0x" + ((byte)value).ToString("x2") :
                                                        value is int? "0x" + (((int)value) & 0xFF).ToString("x2") :
                                                            value.ToString();

                                            if (string.IsNullOrEmpty(seed))
                                            {
                                                return(x);
                                            }

                                            return(seed + ", " + x);
                                        }
                                                                                                      ) + ");");
                                    };

                                    w.Block("public byte[] SelectApplet()",
                                            delegate
                                    {
                                        var c = new AIDAttribute.Info(TargetType).ToSelectApplet().Select(k => (object)k).ToArray();

                                        Transmit(c);
                                    }
                                            );

                                    var EnumTypesToDefine = from x in source.SelectMany(k => k)
                                                            from y in x.k.GetParameters()
                                                            let yt = y.ParameterType
                                                                     where yt.IsEnum && Enum.GetUnderlyingType(yt) == typeof(byte)
                                                                     select yt;

                                    foreach (var EnumType in EnumTypesToDefine.Distinct())
                                    {
                                        w.Block("public enum " + EnumType.Name + " : byte",
                                                delegate
                                        {
                                            var Names  = Enum.GetNames(EnumType);
                                            var Values = (byte[])Enum.GetValues(EnumType);

                                            for (int i = 0; i < Names.Length; i++)
                                            {
                                                w.Statement(Names[i] + " = " + Values[i] + ",");
                                            }
                                        }
                                                );
                                    }

                                    var ProxyInstructions = source.SelectMany(k =>

                                                                              k.Select((q, i) => new { q.k, q.CLA, INS = q.CLA.AutoAssignInstructions ? (q.INS.ToINS((byte)i)) : q.INS })

                                                                              ).ToArray();

                                    foreach (var i in ProxyInstructions)
                                    {
                                        var ik  = i.k;
                                        var CLA = i.CLA.CLA;

                                        ProxyInvoke(w, Transmit, ik, CLA, i.INS);
                                    }
                                }
                                        );
                            }
                                    );
                            #endregion
                        }
                        #endregion
                    }
        }