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;
}
}
}