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