using System;
using System.IO;
using System.Reflection;
using System.Text;
using OriginalCompilationException = MsieJavaScriptEngine.JsCompilationException;
using OriginalEngine = MsieJavaScriptEngine.MsieJsEngine;
using OriginalEngineException = MsieJavaScriptEngine.JsEngineException;
using OriginalEngineLoadException = MsieJavaScriptEngine.JsEngineLoadException;
using OriginalEngineMode = MsieJavaScriptEngine.JsEngineMode;
using OriginalEngineSettings = MsieJavaScriptEngine.JsEngineSettings;
using OriginalException = MsieJavaScriptEngine.JsException;
using OriginalFatalException = MsieJavaScriptEngine.JsFatalException;
using OriginalInterruptedException = MsieJavaScriptEngine.JsInterruptedException;
using OriginalPrecompiledScript = MsieJavaScriptEngine.PrecompiledScript;
using OriginalRuntimeException = MsieJavaScriptEngine.JsRuntimeException;
using OriginalScriptException = MsieJavaScriptEngine.JsScriptException;
using OriginalTypeConverter = MsieJavaScriptEngine.Utilities.TypeConverter;
using OriginalUndefined = MsieJavaScriptEngine.Undefined;
using OriginalUsageException = MsieJavaScriptEngine.JsUsageException;
using JavaScriptEngineSwitcher.Core;
using JavaScriptEngineSwitcher.Core.Helpers;
using JavaScriptEngineSwitcher.Core.Utilities;
using CoreStrings = JavaScriptEngineSwitcher.Core.Resources.Strings;
using WrapperCompilationException = JavaScriptEngineSwitcher.Core.JsCompilationException;
using WrapperEngineException = JavaScriptEngineSwitcher.Core.JsEngineException;
using WrapperEngineLoadException = JavaScriptEngineSwitcher.Core.JsEngineLoadException;
using WrapperException = JavaScriptEngineSwitcher.Core.JsException;
using WrapperFatalException = JavaScriptEngineSwitcher.Core.JsFatalException;
using WrapperInterruptedException = JavaScriptEngineSwitcher.Core.JsInterruptedException;
using WrapperRuntimeException = JavaScriptEngineSwitcher.Core.JsRuntimeException;
using WrapperScriptException = JavaScriptEngineSwitcher.Core.JsScriptException;
using WrapperUsageException = JavaScriptEngineSwitcher.Core.JsUsageException;
namespace JavaScriptEngineSwitcher.Msie
{
///
/// Adapter for the MSIE JS engine
///
public sealed class MsieJsEngine : JsEngineBase
{
///
/// Name of JS engine
///
public const string EngineName = "MsieJsEngine";
///
/// Version of original JS engine
///
private readonly string _engineVersion;
///
/// MSIE JS engine
///
private OriginalEngine _jsEngine;
///
/// Constructs an instance of adapter for the MSIE JS engine
///
public MsieJsEngine()
: this(new MsieSettings())
{ }
///
/// Constructs an instance of adapter for the MSIE JS engine
///
/// Settings of the MSIE JS engine
public MsieJsEngine(MsieSettings settings)
{
MsieSettings msieSettings = settings ?? new MsieSettings();
try
{
_jsEngine = new OriginalEngine(new OriginalEngineSettings
{
AllowReflection = msieSettings.AllowReflection,
EnableDebugging = msieSettings.EnableDebugging,
EngineMode = Utils.GetEnumFromOtherEnum(
msieSettings.EngineMode),
#if !NETSTANDARD1_3
MaxStackSize = msieSettings.MaxStackSize,
#endif
UseEcmaScript5Polyfill = msieSettings.UseEcmaScript5Polyfill,
UseJson2Library = msieSettings.UseJson2Library
});
_engineVersion = _jsEngine.Mode;
}
catch (OriginalUsageException e)
{
throw JsErrorHelpers.WrapEngineLoadException(e, EngineName, _engineVersion);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
#region Mapping
///
/// Makes a mapping of value from the host type to a script type
///
/// The source value
/// The mapped value
private static object MapToScriptType(object value)
{
if (value is Undefined)
{
return OriginalUndefined.Value;
}
return value;
}
///
/// Makes a mapping of value from the script type to a host type
///
/// The source value
/// The mapped value
private static object MapToHostType(object value)
{
if (value is OriginalUndefined)
{
return Undefined.Value;
}
return value;
}
private WrapperException WrapJsException(OriginalException originalException)
{
WrapperException wrapperException;
var originalScriptException = originalException as OriginalScriptException;
if (originalScriptException is not null)
{
WrapperScriptException wrapperScriptException;
var originalRuntimeException = originalScriptException as OriginalRuntimeException;
if (originalRuntimeException is not null)
{
WrapperRuntimeException wrapperRuntimeException;
if (originalRuntimeException is OriginalInterruptedException)
{
wrapperRuntimeException = new WrapperInterruptedException(originalScriptException.Message,
EngineName, _engineVersion, originalRuntimeException);
}
else
{
wrapperRuntimeException = new WrapperRuntimeException(originalScriptException.Message,
EngineName, _engineVersion, originalRuntimeException);
}
wrapperRuntimeException.CallStack = originalRuntimeException.CallStack;
wrapperScriptException = wrapperRuntimeException;
}
else if (originalScriptException is OriginalCompilationException)
{
wrapperScriptException = new WrapperCompilationException(originalScriptException.Message,
EngineName, _engineVersion, originalScriptException);
}
else
{
wrapperScriptException = new WrapperScriptException(originalScriptException.Message,
EngineName, _engineVersion, originalScriptException);
}
wrapperScriptException.Type = originalScriptException.Type;
wrapperScriptException.DocumentName = originalScriptException.DocumentName;
wrapperScriptException.LineNumber = originalScriptException.LineNumber;
wrapperScriptException.ColumnNumber = originalScriptException.ColumnNumber;
wrapperScriptException.SourceFragment = originalScriptException.SourceFragment;
wrapperException = wrapperScriptException;
}
else
{
if (originalException is OriginalUsageException)
{
wrapperException = new WrapperUsageException(originalException.Message,
EngineName, _engineVersion, originalException);
}
else if (originalException is OriginalEngineException)
{
if (originalException is OriginalEngineLoadException)
{
wrapperException = new WrapperEngineLoadException(originalException.Message,
EngineName, _engineVersion, originalException);
}
else
{
wrapperException = new WrapperEngineException(originalException.Message,
EngineName, _engineVersion, originalException);
}
}
else if (originalException is OriginalFatalException)
{
wrapperException = new WrapperFatalException(originalException.Message,
EngineName, _engineVersion, originalException);
}
else
{
wrapperException = new WrapperException(originalException.Message,
EngineName, _engineVersion, originalException);
}
}
wrapperException.Description = originalException.Description;
return wrapperException;
}
#endregion
#region JsEngineBase overrides
protected override IPrecompiledScript InnerPrecompile(string code)
{
return InnerPrecompile(code, null);
}
protected override IPrecompiledScript InnerPrecompile(string code, string documentName)
{
OriginalPrecompiledScript precompiledScript;
try
{
precompiledScript = _jsEngine.Precompile(code, documentName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
return new MsiePrecompiledScript(precompiledScript);
}
protected override object InnerEvaluate(string expression)
{
return InnerEvaluate(expression, null);
}
protected override object InnerEvaluate(string expression, string documentName)
{
object result;
try
{
result = _jsEngine.Evaluate(expression, documentName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
result = MapToHostType(result);
return result;
}
protected override T InnerEvaluate(string expression)
{
return InnerEvaluate(expression, null);
}
protected override T InnerEvaluate(string expression, string documentName)
{
object result = InnerEvaluate(expression, documentName);
return OriginalTypeConverter.ConvertToType(result);
}
protected override void InnerExecute(string code)
{
InnerExecute(code, null);
}
protected override void InnerExecute(string code, string documentName)
{
try
{
_jsEngine.Execute(code, documentName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override void InnerExecute(IPrecompiledScript precompiledScript)
{
var msiePrecompiledScript = precompiledScript as MsiePrecompiledScript;
if (msiePrecompiledScript is null)
{
throw new WrapperUsageException(
string.Format(CoreStrings.Usage_CannotConvertPrecompiledScriptToInternalType,
typeof(MsiePrecompiledScript).FullName),
Name, Version
);
}
try
{
_jsEngine.Execute(msiePrecompiledScript.PrecompiledScript);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override object InnerCallFunction(string functionName, params object[] args)
{
object result;
int argumentCount = args.Length;
var processedArgs = new object[argumentCount];
if (argumentCount > 0)
{
for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++)
{
processedArgs[argumentIndex] = MapToScriptType(args[argumentIndex]);
}
}
try
{
result = _jsEngine.CallFunction(functionName, processedArgs);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
result = MapToHostType(result);
return result;
}
protected override T InnerCallFunction(string functionName, params object[] args)
{
object result = InnerCallFunction(functionName, args);
return OriginalTypeConverter.ConvertToType(result);
}
protected override bool InnerHasVariable(string variableName)
{
bool result;
try
{
result = _jsEngine.HasVariable(variableName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
return result;
}
protected override object InnerGetVariableValue(string variableName)
{
object result;
try
{
result = _jsEngine.GetVariableValue(variableName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
result = MapToHostType(result);
return result;
}
protected override T InnerGetVariableValue(string variableName)
{
object result = InnerGetVariableValue(variableName);
return OriginalTypeConverter.ConvertToType(result);
}
protected override void InnerSetVariableValue(string variableName, object value)
{
object processedValue = MapToScriptType(value);
try
{
_jsEngine.SetVariableValue(variableName, processedValue);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override void InnerRemoveVariable(string variableName)
{
try
{
_jsEngine.RemoveVariable(variableName);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override void InnerEmbedHostObject(string itemName, object value)
{
object processedValue = MapToScriptType(value);
try
{
_jsEngine.EmbedHostObject(itemName, processedValue);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override void InnerEmbedHostType(string itemName, Type type)
{
try
{
_jsEngine.EmbedHostType(itemName, type);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
}
protected override void InnerInterrupt()
{
_jsEngine.Interrupt();
}
protected override void InnerCollectGarbage()
{
_jsEngine.CollectGarbage();
}
#region IJsEngine implementation
public override string Name
{
get { return EngineName; }
}
public override string Version
{
get { return _engineVersion; }
}
public override bool SupportsScriptPrecompilation
{
get { return _jsEngine.SupportsScriptPrecompilation; }
}
public override bool SupportsScriptInterruption
{
get { return true; }
}
public override bool SupportsGarbageCollection
{
get { return true; }
}
public override IPrecompiledScript PrecompileFile(string path, Encoding encoding = null)
{
VerifyNotDisposed();
if (path is null)
{
throw new ArgumentNullException(
nameof(path),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(path))
);
}
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(path)),
nameof(path)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(path))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidFileNameFormat, path),
nameof(path)
);
}
OriginalPrecompiledScript precompiledScript;
try
{
precompiledScript = _jsEngine.PrecompileFile(path, encoding);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (FileNotFoundException)
{
throw;
}
return new MsiePrecompiledScript(precompiledScript);
}
public override IPrecompiledScript PrecompileResource(string resourceName, Type type)
{
VerifyNotDisposed();
if (resourceName is null)
{
throw new ArgumentNullException(
nameof(resourceName),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(resourceName))
);
}
if (type is null)
{
throw new ArgumentNullException(
nameof(type),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(type))
);
}
if (string.IsNullOrWhiteSpace(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(resourceName)),
nameof(resourceName)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidResourceNameFormat, resourceName),
nameof(resourceName)
);
}
OriginalPrecompiledScript precompiledScript;
try
{
precompiledScript = _jsEngine.PrecompileResource(resourceName, type);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (NullReferenceException)
{
throw;
}
return new MsiePrecompiledScript(precompiledScript);
}
public override IPrecompiledScript PrecompileResource(string resourceName, Assembly assembly)
{
VerifyNotDisposed();
if (resourceName is null)
{
throw new ArgumentNullException(
nameof(resourceName),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(resourceName))
);
}
if (assembly is null)
{
throw new ArgumentNullException(
nameof(assembly),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(assembly))
);
}
if (string.IsNullOrWhiteSpace(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(resourceName)),
nameof(resourceName)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidResourceNameFormat, resourceName),
nameof(resourceName)
);
}
OriginalPrecompiledScript precompiledScript;
try
{
precompiledScript = _jsEngine.PrecompileResource(resourceName, assembly);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (NullReferenceException)
{
throw;
}
return new MsiePrecompiledScript(precompiledScript);
}
public override void ExecuteFile(string path, Encoding encoding = null)
{
VerifyNotDisposed();
if (path is null)
{
throw new ArgumentNullException(
nameof(path),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(path))
);
}
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(path)),
nameof(path)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(path))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidFileNameFormat, path),
nameof(path)
);
}
try
{
_jsEngine.ExecuteFile(path, encoding);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (FileNotFoundException)
{
throw;
}
}
public override void ExecuteResource(string resourceName, Type type)
{
VerifyNotDisposed();
if (resourceName is null)
{
throw new ArgumentNullException(
nameof(resourceName),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(resourceName))
);
}
if (type is null)
{
throw new ArgumentNullException(
nameof(type),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(type))
);
}
if (string.IsNullOrWhiteSpace(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(resourceName)),
nameof(resourceName)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidResourceNameFormat, resourceName),
nameof(resourceName)
);
}
try
{
_jsEngine.ExecuteResource(resourceName, type);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (NullReferenceException)
{
throw;
}
}
public override void ExecuteResource(string resourceName, Assembly assembly)
{
VerifyNotDisposed();
if (resourceName is null)
{
throw new ArgumentNullException(
nameof(resourceName),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(resourceName))
);
}
if (assembly is null)
{
throw new ArgumentNullException(
nameof(assembly),
string.Format(CoreStrings.Common_ArgumentIsNull, nameof(assembly))
);
}
if (string.IsNullOrWhiteSpace(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Common_ArgumentIsEmpty, nameof(resourceName)),
nameof(resourceName)
);
}
if (!ValidationHelpers.CheckDocumentNameFormat(resourceName))
{
throw new ArgumentException(
string.Format(CoreStrings.Usage_InvalidResourceNameFormat, resourceName),
nameof(resourceName)
);
}
try
{
_jsEngine.ExecuteResource(resourceName, assembly);
}
catch (OriginalException e)
{
throw WrapJsException(e);
}
catch (NullReferenceException)
{
throw;
}
}
#endregion
#region IDisposable implementation
public override void Dispose()
{
if (_disposedFlag.Set())
{
if (_jsEngine is not null)
{
_jsEngine.Dispose();
_jsEngine = null;
}
}
}
#endregion
#endregion
}
}