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