using CSScriptLibrary; using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Text; using System.Text.RegularExpressions; namespace CScriptEngine { public class CScript : IDisposable { private bool disposed = false; private Assembly asm; private AsmHelper script; private dynamic scriptVB; private string code; private string filename; private bool useClass; private bool noCache; private bool isVB; public string text { set { this.code = value; } get { return this.code; } } public CScript() { string path = Assembly.GetExecutingAssembly().Location; UriBuilder uri = new UriBuilder(path); path = Uri.UnescapeDataString(uri.Path); CSScript.GlobalSettings.UseAlternativeCompiler = Path.Combine(Path.GetDirectoryName(path), "CSSCodeProvider.dll"); CSScript.GlobalSettings.AddSearchDir(Path.GetFullPath("Lib")); } public CScript(bool useClass = false, bool noCache = false) : this() { this.useClass = useClass; this.noCache = noCache; this.filename = CSScript.GetScriptTempFile(); CSScript.CacheEnabled = !this.noCache; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { if (this.script != null) { this.script.Dispose(); this.script = null; } if (this.scriptVB != null) { if (this.scriptVB is IDisposable) this.scriptVB.Dispose(); this.scriptVB = null; } } this.disposed = true; } } public bool check(out string result) { result = null; string context = this.code; string ext = null; string compiledPath = null; bool isFile; try { if (isFile = validatePath(ref context)) { ext = Path.GetExtension(context); this.isVB = ext.Equals(".vb", StringComparison.OrdinalIgnoreCase); this.filename = Path.ChangeExtension(this.filename, ext); compiledPath = CSScript.GetCachedScriptPath(context); if (compiledPath.isEmpty() || !File.Exists(compiledPath) || this.noCache) compiledPath = CSScript.CompileFile(context, this.noCache ? this.filename : null, true); } else { this.isVB = context.StartsWith("'"); if (!this.useClass) Precompiler.build(ref context); compiledPath = CSScript.CompileCode(context, this.noCache ? this.filename : null, true); } ProxyDomain pd = new ProxyDomain(); asm = pd.GetAssembly(compiledPath); if (isFile) this.script = new AsmHelper(asm).setProbingDirsFromFile(context); else this.script = new AsmHelper(asm).setProbingDirsFromCode(context); this.script.CachingEnabled = false;// !this.noCache; if (this.isVB) this.scriptVB = asm.CreateObject("Script"); } catch (csscript.CompilerException e) { CompilerErrorCollection errors = (CompilerErrorCollection)e.Data["Errors"]; foreach (CompilerError err in errors) { result += String.Format ( "{0}({1},{2}): {3} {4}: {5}{6}" , err.FileName , err.Line - 1 , err.Column , err.IsWarning ? "warning" : "error" , err.ErrorNumber , err.ErrorText , Environment.NewLine ); } return false; } catch (Exception ex) { result += ex.Message; return false; } return true; } /// /// Invoke C# script in IDE environment /// /// Method name to invoke /// Method arguments /// value if method not void /// /// Example script for UseClass = True: /// /// using System.IO; /// public class Script /// { /// public static bool Main(object[] args) /// { /// sys.debug(args.Length.ToString()); /// sys.debug(args.ToString()); /// string path = (args[0] as TData).toStr(); /// return File.Exists(path); /// } /// } /// /// Example script for UseClass = False: /// /// public static void Main(object[] args) /// { /// ... /// } /// public object run(string entry, object[] args) { object result = null; if (this.isVB) { try { result = scriptVB.Main(new object[] { args }); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } else if (this.script != null) { try { if (this.useClass) result = script.Invoke("Script." + entry, new object[] { args }); else result = script.Invoke("*." + entry, new object[] { args }); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } return result; } private static string replaceTarget(string source, string pattern, string replacement) { try { return Regex.Replace(source, pattern, replacement); } catch (ArgumentException ex) { Debug.WriteLine("!Replace target failed. Reason: " + ex.Message); } return string.Empty; } /// /// Validate the Path. If path is relative append the path to the project directory by default. /// /// Path to validate /// Relative path /// If want to check for File Path /// private static bool validatePath(ref string path, string RelativePath = "", string Extension = "") { // Check if it contains any Invalid Characters. if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) { try { // If path is relative take %IGXLROOT% as the base directory if (!Path.IsPathRooted(path)) { if (String.IsNullOrEmpty(RelativePath)) { // Exceptions handled by Path.GetFullPath // ArgumentException path is a zero-length string, contains only white space, or contains one or more of the invalid characters defined in GetInvalidPathChars. -or- The system could not retrieve the absolute path. // // SecurityException The caller does not have the required permissions. // // ArgumentNullException path is null. // // NotSupportedException path contains a colon (":") that is not part of a volume identifier (for example, "c:\"). // PathTooLongException The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters. // RelativePath is not passed so we would take the project path path = Path.GetFullPath(RelativePath); } else { // Make sure the path is relative to the RelativePath and not our project directory path = Path.Combine(RelativePath, path); } } // Exceptions from FileInfo Constructor: // System.ArgumentNullException: // fileName is null. // // System.Security.SecurityException: // The caller does not have the required permission. // // System.ArgumentException: // The file name is empty, contains only white spaces, or contains invalid characters. // // System.IO.PathTooLongException: // The specified path, file name, or both exceed the system-defined maximum // length. For example, on Windows-based platforms, paths must be less than // 248 characters, and file names must be less than 260 characters. // // System.NotSupportedException: // fileName contains a colon (:) in the middle of the string. FileInfo fileInfo = new FileInfo(path); // Exceptions using FileInfo.Length: // System.IO.IOException: // System.IO.FileSystemInfo.Refresh() cannot update the state of the file or // directory. // // System.IO.FileNotFoundException: // The file does not exist.-or- The Length property is called for a directory. bool throwEx = fileInfo.Length == -1; // Exceptions using FileInfo.IsReadOnly: // System.UnauthorizedAccessException: // Access to fileName is denied. // The file described by the current System.IO.FileInfo object is read-only.-or- // This operation is not supported on the current platform.-or- The caller does // not have the required permission. throwEx = fileInfo.IsReadOnly; if (String.IsNullOrEmpty(Extension)) return true; else { // Validate the Extension of the file. if (Path.GetExtension(path).Equals(Extension, StringComparison.InvariantCultureIgnoreCase)) { // Trim the Library Path path = path.Trim(); return true; } else return false; } } catch (ArgumentNullException) { // System.ArgumentNullException: // fileName is null. } catch (System.Security.SecurityException) { // System.Security.SecurityException: // The caller does not have the required permission. } catch (ArgumentException) { // System.ArgumentException: // The file name is empty, contains only white spaces, or contains invalid characters. } catch (UnauthorizedAccessException) { // System.UnauthorizedAccessException: // Access to fileName is denied. } catch (PathTooLongException) { // System.IO.PathTooLongException: // The specified path, file name, or both exceed the system-defined maximum // length. For example, on Windows-based platforms, paths must be less than // 248 characters, and file names must be less than 260 characters. } catch (NotSupportedException) { // System.NotSupportedException: // fileName contains a colon (:) in the middle of the string. } catch (FileNotFoundException) { // System.FileNotFoundException // The exception that is thrown when an attempt to access a file that does not // exist on disk fails. } catch (IOException) { // System.IO.IOException: // An I/O error occurred while opening the file. } catch (Exception) { // Unknown Exception. Might be due to wrong case or nulll checks. } } else { // Path contains invalid characters } return false; } } public class Precompiler { public static bool build(ref string content) { StringBuilder code = new StringBuilder(); code.AppendLine("// Auto-generated code"); code.AppendLine("using System;"); bool headerProcessed = false; string line; using (var sr = new StringReader(content)) while ((line = sr.ReadLine()) != null) { if (!headerProcessed && !line.TrimStart().StartsWith("using ")) //not using...; statement of the file header { if (!line.StartsWith("//") && line.Trim() != "") //not comments or empty line { headerProcessed = true; code.AppendLine("public class Script"); code.AppendLine("{"); } code.AppendFormat("\t{0}", line); code.Append(Environment.NewLine); } else { if (!line.TrimStart().StartsWith("using ")) code.AppendFormat("\t{0}", line); else code.Append(line); code.Append(Environment.NewLine); } } code.AppendLine("}"); content = code.ToString(); return true; } } /// /// ProxyDomain pd = new ProxyDomain(); /// Assembly assembly = pd.GetAssembly(assemblyFilePath); /// public class ProxyDomain : MarshalByRefObject { public Assembly GetAssembly(string assemblyPath) { try { return Assembly.LoadFrom(assemblyPath); } catch (Exception ex) { throw new InvalidOperationException(ex.Message); } } } public static class Extensions { public static AsmHelper setProbingDirsFromCode(this AsmHelper helper, string code) { var parser = new csscript.CSharpParser(code, isFile: false); List list = new List(helper.ProbingDirs); list.AddRange(parser.ExtraSearchDirs); helper.ProbingDirs = list.ToArray(); return helper; } public static AsmHelper setProbingDirsFromFile(this AsmHelper helper, string file) { var parser = new csscript.CSharpParser(file, isFile: true); List list = new List(helper.ProbingDirs); list.AddRange(parser.ExtraSearchDirs); helper.ProbingDirs = list.ToArray(); return helper; } } }