using System; using System.Drawing; using System.Drawing.Text; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace FastReport.Utils { /// /// Contains some configuration properties and settings that will be applied to the FastReport.Net /// environment, including Report, Designer and Preview components. /// public static partial class Config { #if COMMUNITY const string CONFIG_NAME = "FastReport.Community.config"; #elif MONO const string CONFIG_NAME = "FastReport.Mono.config"; #else const string CONFIG_NAME = "FastReport.config"; #endif #region Private Fields private static readonly CultureInfo engCultureInfo = new CultureInfo("en-US"); private static readonly XmlDocument FDoc = new XmlDocument(); private static readonly string version = typeof(Report).Assembly.GetName().Version.ToString(3); private static string FFolder = null; private static string FFontListFolder = null; private static string FLogs = ""; private static bool FIsRunningOnMono; private static ReportSettings FReportSettings = new ReportSettings(); private static bool FRightToLeft = false; private static string FTempFolder = null; private static string systemTempFolder = null; private static bool FStringOptimization = true; private static bool FWebMode; private static bool preparedCompressed = true; private static bool disableHotkeys = false; private static bool enableScriptSecurity = false; private static ScriptSecurityProperties scriptSecurityProps = null; private static bool forbidLocalData = false; private static bool userSetsScriptSecurity = false; private static readonly FRPrivateFontCollection privateFontCollection = new FRPrivateFontCollection(); internal static bool CleanupOnExit; private static CompilerSettings compilerSettings = new CompilerSettings(); private static string applicationFolder; private static readonly string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; private static bool disableLastFormatting = false; #endregion Private Fields #region Public Properties /// /// Gets a value indicating that the Mono runtime is used. /// public static bool IsRunningOnMono { get { return FIsRunningOnMono; } } #if CROSSPLATFORM public static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); #endif /// /// Gets or sets a value indicating is it impossible to specify a local data path in Xml and Csv. /// public static bool ForbidLocalData { get { return forbidLocalData; } set { forbidLocalData = value; } } /// /// Gets or sets the optimization of strings. Is experimental feature. /// public static bool IsStringOptimization { get { return FStringOptimization; } set { FStringOptimization = value; } } /// /// Enable or disable the compression in files with prepared reports (fpx). /// public static bool PreparedCompressed { get { return preparedCompressed; } set { preparedCompressed = value; } } /// /// Gets or sets the application folder. /// public static string ApplicationFolder { get { if(applicationFolder == null) return baseDirectory; return applicationFolder; } set { applicationFolder = value; } } /// /// Gets an english culture information for localization purposes /// public static CultureInfo EngCultureInfo { get { return engCultureInfo; } } /// /// Gets or sets the path used to load/save the configuration file. /// /// /// By default, the configuration file is saved to the application local data folder /// (C:\Documents and Settings\User_Name\Local Settings\Application Data\FastReport\). /// Set this property to "" if you want to store the configuration file in the application folder. /// public static string Folder { get { return FFolder; } set { FFolder = value; } } /// /// Gets or sets the path used to font.list file. /// /// /// By default, the font.list file is saved to the FastReport.config folder /// If WebMode enabled (or config file path is null), then file is saved in the application folder. /// public static string FontListFolder { get { return FFontListFolder; } set { FFontListFolder = value; } } /// /// Gets or sets the settings for the Report component. /// public static ReportSettings ReportSettings { get { return FReportSettings; } set { FReportSettings = value; } } /// /// Gets or sets a value indicating whether RTL layout should be used. /// public static bool RightToLeft { get { return FRightToLeft; } set { FRightToLeft = value; } } /// /// Gets or sets a value indicating whether hotkeys should be disabled. /// public static bool DisableHotkeys { get { return disableHotkeys; } set { disableHotkeys = value; } } /// /// Gets or sets a value indicating saving last formatting should be disabled. /// public static bool DisableLastFormatting { get { return disableLastFormatting; } set { disableLastFormatting = value; } } /// /// Gets the root item of config xml. /// public static XmlItem Root { get { return FDoc.Root; } } /// /// Gets or sets the path to the temporary folder used to store temporary files. /// /// /// The default value is null, so the system temp folder will be used. /// public static string TempFolder { get { return FTempFolder; } set { FTempFolder = value; } } /// /// Gets the path to the system temporary folder used to store temporary files. /// public static string SystemTempFolder { get { return systemTempFolder == null ? GetTempPath() : systemTempFolder; } } /// /// Gets FastReport version. /// public static string Version { get { return version; } } /// /// Called on script compile /// public static event EventHandler ScriptCompile; /// /// Gets a PrivateFontCollection instance. /// public static FRPrivateFontCollection PrivateFontCollection { get { return privateFontCollection; } } /// /// Enable report script validation. For WebMode only /// public static bool EnableScriptSecurity { get { return enableScriptSecurity; } set { if (OnEnableScriptSecurityChanged != null) OnEnableScriptSecurityChanged.Invoke(null, null); enableScriptSecurity = value; // userSetsScriptSecurity = true; if (value) { if(scriptSecurityProps == null) scriptSecurityProps = new ScriptSecurityProperties(); } } } /// /// Throws when property EnableScriptSecurity has been changed /// public static event EventHandler OnEnableScriptSecurityChanged; /// /// Properties of report script validation /// public static ScriptSecurityProperties ScriptSecurityProps { get { return scriptSecurityProps; } } /// /// Settings of report compiler. /// public static CompilerSettings CompilerSettings { get { return compilerSettings; } set { compilerSettings = value; } } #endregion Public Properties #region Internal Methods internal static string CreateTempFile(string dir) { if (String.IsNullOrEmpty(dir)) return GetTempFileName(); return Path.Combine(dir, Path.GetRandomFileName()); } internal static string GetTempFolder() { return TempFolder == null ? GetTempPath() : TempFolder; } internal static void Init() { FIsRunningOnMono = Type.GetType("Mono.Runtime") != null; #if SKIA Topten.RichTextKit.FontFallback.CharacterMatcher = characterMatcher; #endif CheckWebMode(); #if !CROSSPLATFORM if (!WebMode) LoadConfig(); #endif if (!userSetsScriptSecurity && WebMode) { enableScriptSecurity = true; // don't throw event scriptSecurityProps = new ScriptSecurityProperties(); } #if !COMMUNITY RestoreExportOptions(); #endif LoadPlugins(); // init TextRenderingHint.SystemDefault // bug in .Net: if you use any other hint before SystemDefault, the SystemDefault will // look like SingleBitPerPixel using (Bitmap bmp = new Bitmap(1, 1)) using (Graphics g = Graphics.FromImage(bmp)) { g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault; g.DrawString(" ", SystemFonts.DefaultFont, Brushes.Black, 0, 0); } } private static void CheckWebMode() { // If we/user sets 'WebMode = true' before this check - Config shouln't change it (because check may be incorrect) if (!WebMode) { #if NETSTANDARD || NETCOREAPP var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var loadedAsmbly in loadedAssemblies) { bool isAspNetCore = loadedAsmbly.GetName().Name.StartsWith("Microsoft.AspNetCore"); if (isAspNetCore) { WebMode = true; break; } } #else string processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; WebMode = String.Compare(processName, "iisexpress") == 0 || String.Compare(processName, "w3wp") == 0; #endif } } internal static void WriteLogString(string s) { WriteLogString(s, false); } internal static void WriteLogString(string s, bool distinct) { if (distinct) { if (FLogs.IndexOf(s + "\r\n") != -1) return; } FLogs += s + "\r\n"; } internal static void OnScriptCompile(ScriptSecurityEventArgs e) { if (ScriptCompile != null) { ScriptCompile.Invoke(null, e); } if (!e.IsValid) { throw new CompilerException(Res.Get("Messages,CompilerError")); } } #if NETSTANDARD || NETCOREAPP public static event EventHandler BeforeEmitCompile; internal static void OnBeforeScriptCompilation(object sender, Code.CodeDom.Compiler.CompilationEventArgs e) { if (BeforeEmitCompile != null) { BeforeEmitCompile.Invoke(sender, e); } } #endif #endregion Internal Methods #region Private Methods private static string GetTempFileName() { return Path.Combine(GetTempFolder(), SystemFake.DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss-") + Path.GetRandomFileName()); } private static string GetTempPath() { if (!string.IsNullOrEmpty(systemTempFolder)) return systemTempFolder; systemTempFolder = Environment.GetEnvironmentVariable("TMP"); if (string.IsNullOrEmpty(systemTempFolder)) systemTempFolder = Environment.GetEnvironmentVariable("TEMP"); if (string.IsNullOrEmpty(systemTempFolder)) systemTempFolder = Environment.GetEnvironmentVariable("TMPDIR"); if (string.IsNullOrEmpty(systemTempFolder)) systemTempFolder = Path.GetTempPath(); return systemTempFolder; } private static void CurrentDomain_ProcessExit(object sender, EventArgs e) { FDoc.Root.Name = "Config"; FDoc.AutoIndent = true; SaveUIStyle(); SaveUIOptions(); SavePreviewSettings(); SaveCompilerSettings(); SaveAuthServiceUser(); #if !COMMUNITY SaveExportOptions(); #endif if (!WebMode) { try { if (!Directory.Exists(Folder)) Directory.CreateDirectory(Folder); string configFile = Path.Combine(Folder, CONFIG_NAME); if (CleanupOnExit) { File.Delete(configFile); } else { FDoc.Save(configFile); } if (FLogs != "") File.WriteAllText(Path.Combine(Folder, "FastReport.logs"), FLogs); } catch { } } } private static void LoadConfig() { bool configLoaded = false; if (!Config.WebMode) { try { if (Folder == null) { string baseFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Folder = Path.Combine(baseFolder, "FastReport"); } else if (Folder == "") Folder = ApplicationFolder; } catch { } string fileName = Path.Combine(Folder, CONFIG_NAME); if (File.Exists(fileName)) { try { FDoc.Load(fileName); configLoaded = true; } catch { } } RestoreUIStyle(); RestoreDefaultLanguage(); RestoreUIOptions(); RestorePreviewSettings(); RestoreAuthServiceUser(); RestoreCompilerSettings(); Res.LoadDefaultLocale(); AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); } if (!configLoaded) { // load default config using (Stream stream = ResourceLoader.GetStream("FastReport.config")) { FDoc.Load(stream); } } } private static void LoadPlugins() { // main assembly initializer ProcessMainAssembly(); XmlItem pluginsItem = Root.FindItem("Plugins"); for (int i = 0; i < pluginsItem.Count; i++) { XmlItem item = pluginsItem[i]; string pluginName = item.GetProp("Name"); try { var assembly = Assembly.LoadFrom(pluginName); ProcessAssembly(assembly); } catch { } } // For CoreWin #if COREWIN LoadPluginsInCurrentFolder(); #endif } private static void LoadPluginsInCurrentFolder() { var appFolder = ApplicationFolder; if(!string.IsNullOrEmpty(appFolder)) { // find all plugin-connector in current directory var plugins = Directory.GetFiles(appFolder, "FastReport.Data.*.dll"); // initialize foreach (var pluginName in plugins) { try { var assembly = Assembly.LoadFrom(pluginName); ProcessAssembly(assembly); } catch { } } } } private static void ProcessAssembly(Assembly a) { foreach (Type t in a.GetTypes()) { if (t.IsSubclassOf(typeof(AssemblyInitializerBase))) Activator.CreateInstance(t); } } private static void RestoreDefaultLanguage() { XmlItem xi = Root.FindItem("Designer").FindItem("Code"); string defaultLanguage = xi.GetProp("DefaultScriptLanguage"); ReportSettings.DefaultLanguage = defaultLanguage == Language.Vb.ToString() ? Language.Vb : Language.CSharp; } private static void RestoreRightToLeft() { XmlItem xi = Root.FindItem("UIOptions"); string rtl = xi.GetProp("RightToLeft"); if (!String.IsNullOrEmpty(rtl)) { switch (rtl) { case "Auto": RightToLeft = CultureInfo.CurrentCulture.TextInfo.IsRightToLeft; break; case "No": RightToLeft = false; break; case "Yes": RightToLeft = true; break; default: RightToLeft = false; break; } } } /// /// Properties of ScriptSecurity /// public class ScriptSecurityProperties { private static readonly string[] defaultStopList = new[] { "GetType", "typeof", "TypeOf", // VB "DllImport", "LoadLibrary", "GetProcAddress", }; private string[] stopList; /// /// Add stubs for the most dangerous classes (in System.IO, System.Reflection etc) /// public bool AddStubClasses { get; set; } = true; /// /// List of keywords that shouldn't be declared in the report script /// public string[] StopList { get { return (string[])stopList.Clone(); } set { if(value != null) { OnStopListChanged?.Invoke(this, null); stopList = value; } } } /// /// Throws when has changed /// public event EventHandler OnStopListChanged; internal ScriptSecurityProperties() { SetDefaultStopList(); } internal ScriptSecurityProperties(string[] stopList) { this.stopList = stopList; } /// /// Sets default value for /// public void SetDefaultStopList() { StopList = defaultStopList; } } private static void SaveUIOptions() { XmlItem xi = Root.FindItem("UIOptions"); xi.SetProp("DisableHotkeys", Converter.ToString(DisableHotkeys)); xi.SetProp("DisableLastFormatting", Converter.ToString(DisableLastFormatting)); } private static void RestoreUIOptions() { RestoreRightToLeft(); XmlItem xi = Root.FindItem("UIOptions"); string disableHotkeysStringValue = xi.GetProp("DisableHotkeys"); if (!String.IsNullOrEmpty(disableHotkeysStringValue)) { disableHotkeys = disableHotkeysStringValue.ToLower() != "false"; } string disableLastFormattingStringValue = xi.GetProp("DisableLastFormatting"); if (!String.IsNullOrEmpty(disableLastFormattingStringValue)) { disableLastFormatting = disableLastFormattingStringValue.ToLower() != "false"; } } private static void SaveCompilerSettings() { XmlItem xi = Root.FindItem("CompilerSettings"); xi.SetProp("Placeholder", CompilerSettings.Placeholder); xi.SetProp("ExceptionBehaviour", Converter.ToString(CompilerSettings.ExceptionBehaviour)); } private static void RestoreCompilerSettings() { XmlItem xi = Root.FindItem("CompilerSettings"); CompilerSettings.Placeholder = xi.GetProp("Placeholder"); string exceptionBehaviour = xi.GetProp("ExceptionBehaviour"); if (!String.IsNullOrEmpty(exceptionBehaviour)) { try { CompilerSettings.ExceptionBehaviour = (CompilerExceptionBehaviour)Converter.FromString(typeof(CompilerExceptionBehaviour), exceptionBehaviour); } catch { CompilerSettings.ExceptionBehaviour = CompilerExceptionBehaviour.Default; } } } #endregion Private Methods } }