mirror of
https://github.com/MathiasLui/CSGO-Projects.git
synced 2025-05-07 14:21:17 +00:00
Add hacky damage displayer (Will get refactored)
* Change Shared namespace to SteamShared * Add damage displayer which also calculates, gets local weather and fuel prices * API Key for tankerkoenig has to be supplied because I didn't push it
This commit is contained in:
parent
d1652aa588
commit
50ac34fb28
61 changed files with 2982 additions and 38 deletions
65
DamagePrinter/DamagePrinter.sln
Normal file
65
DamagePrinter/DamagePrinter.sln
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.1.32407.343
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamagePrinter", "DamagePrinter\DamagePrinter.csproj", "{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamShared", "..\Shared\SteamHelpers\SteamHelpers\SteamShared.csproj", "{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoreSoft.MathExpressions", "..\Shared\LoreSoft.MathExpressions\LoreSoft.MathExpressions.csproj", "{B6813448-FCE2-429C-81B5-9722FEA839B8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|x64.Build.0 = Release|x64
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{AF6F5837-94D3-4D44-9D1C-6B5CD600C698}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|x64.Build.0 = Release|x64
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{4DB55154-E33B-49D8-BE05-DC11CA5B32A4}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|x64.Build.0 = Release|x64
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{B6813448-FCE2-429C-81B5-9722FEA839B8}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B75CC20D-F989-4D9F-86F7-9610737FCBE9}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
20
DamagePrinter/DamagePrinter/DamagePrinter.csproj
Normal file
20
DamagePrinter/DamagePrinter/DamagePrinter.csproj
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Shared\LoreSoft.MathExpressions\LoreSoft.MathExpressions.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Shared\SteamHelpers\SteamHelpers\SteamShared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
363
DamagePrinter/DamagePrinter/Program.cs
Normal file
363
DamagePrinter/DamagePrinter/Program.cs
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using SteamShared;
|
||||||
|
using LoreSoft.MathExpressions;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
static readonly uint WM_COPYDATA = 0x004A;
|
||||||
|
static SteamHelper steamHelper = new SteamHelper();
|
||||||
|
static MathEvaluator mathEval = new MathEvaluator();
|
||||||
|
static HttpClient httpClient = new HttpClient();
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||||
|
static extern int SendMessage(IntPtr windowHandle, uint message, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
string? gamePath = steamHelper.GetGamePathFromExactName("Counter-Strike: Global Offensive");
|
||||||
|
|
||||||
|
if (gamePath == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string consoleLogPath = Path.Combine(gamePath, "csgo", "console.log");
|
||||||
|
bool consoleLogExists = false;
|
||||||
|
|
||||||
|
long oldFileSize = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
oldFileSize = new FileInfo(consoleLogPath).Length;
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
long nextLineOffset = oldFileSize; // bytes from the start of the file, by default not to read anything
|
||||||
|
int minDamageToCount = 20;
|
||||||
|
bool initialScan = true;
|
||||||
|
var prevTaggedPlayers = new List<Tuple<string, int, int>>();
|
||||||
|
DateTime lastFuelRequestTime = DateTime.MinValue;
|
||||||
|
|
||||||
|
if (FindWindow("Valve001", null) == IntPtr.Zero)
|
||||||
|
File.Delete(consoleLogPath);
|
||||||
|
|
||||||
|
// here we start fresh at line 0 cause it got deleted
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (File.Exists(consoleLogPath))
|
||||||
|
{
|
||||||
|
bool update = false;
|
||||||
|
|
||||||
|
if (!consoleLogExists && initialScan) {
|
||||||
|
consoleLogExists = true;
|
||||||
|
initialScan = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long curFileSize = new FileInfo(consoleLogPath).Length;
|
||||||
|
if (curFileSize != oldFileSize)
|
||||||
|
{
|
||||||
|
update = true;
|
||||||
|
oldFileSize = curFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
int damageTakenTotal = 0;
|
||||||
|
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
using (var fs = File.Open(consoleLogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
|
{
|
||||||
|
fs.Position = nextLineOffset;
|
||||||
|
bool endOfFile = false;
|
||||||
|
|
||||||
|
while (!endOfFile)
|
||||||
|
{
|
||||||
|
string line = "";
|
||||||
|
bool endOfLine = false;
|
||||||
|
while (!endOfLine)
|
||||||
|
{
|
||||||
|
int nextByte = fs.ReadByte();
|
||||||
|
|
||||||
|
if (nextByte == -1 && line != "")
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
endOfFile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char nextChar = (char)nextByte;
|
||||||
|
|
||||||
|
if (nextChar == '\n' && line != "")
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
endOfLine = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(nextChar != '\r')
|
||||||
|
line += nextChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextLineOffset = fs.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
var taggedPlayers = new List<Tuple<string, int, int>>();
|
||||||
|
string calcKeyWord = "!calc";
|
||||||
|
string fuelPriceKeyWord = "!fuel";
|
||||||
|
string weatherKeyWord = "!weather";
|
||||||
|
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
/* -------------------------
|
||||||
|
Damage Given to "BOT Eugene" - 65 in 2 hits
|
||||||
|
-------------------------
|
||||||
|
Damage Taken from "BOT Eugene" - 117 in 4 hits*/
|
||||||
|
if (line.StartsWith("Damage Taken"))
|
||||||
|
{
|
||||||
|
Regex regexTaken = new Regex("Damage Taken from \"(.+?)\" - (\\d+) in \\d+ hits?");
|
||||||
|
Match takenMatch = regexTaken.Match(line);
|
||||||
|
|
||||||
|
if (takenMatch.Success)
|
||||||
|
{
|
||||||
|
damageTakenTotal += int.Parse(takenMatch.Groups[2].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.StartsWith("Damage Given"))
|
||||||
|
{
|
||||||
|
Regex regexTaken = new Regex("Damage Given to \"(.+?)\" - (\\d+) in (\\d+) hits?");
|
||||||
|
Match givenMatch = regexTaken.Match(line);
|
||||||
|
|
||||||
|
if (givenMatch.Success)
|
||||||
|
{
|
||||||
|
string name = givenMatch.Groups[1].Value;
|
||||||
|
int damage = int.Parse(givenMatch.Groups[2].Value);
|
||||||
|
int hits = int.Parse(givenMatch.Groups[3].Value);
|
||||||
|
|
||||||
|
if(damage < 100 && damage > minDamageToCount && taggedPlayers.FirstOrDefault(player => player.Item1 == name) == null)
|
||||||
|
// not in list yet so add
|
||||||
|
taggedPlayers.Add(new Tuple<string, int, int>(name, damage, hits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.ToLower().Contains(calcKeyWord + ' '))
|
||||||
|
{
|
||||||
|
// Calculate
|
||||||
|
string expression = line.Substring(line.IndexOf(calcKeyWord + ' ') + calcKeyWord.Length);
|
||||||
|
if (String.IsNullOrWhiteSpace(expression))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
double res = mathEval.Evaluate(expression);
|
||||||
|
Thread.Sleep(700); // so the chat message is shown if we requested it ourselves
|
||||||
|
ExecuteCommands(true, $"say \"Answer: {res}\"");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
else if (line.ToLower().Contains(fuelPriceKeyWord))
|
||||||
|
{
|
||||||
|
if (DateTime.Now - lastFuelRequestTime < TimeSpan.FromMinutes(1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string apiKey = "";
|
||||||
|
string nordOelID = "69ad1928-e972-421b-a33c-4319da73deaa";
|
||||||
|
string shellID = "a507dd35-4a7f-46d1-86b6-accc4769a47b";
|
||||||
|
string request = $"https://creativecommons.tankerkoenig.de/json/prices.php?ids={nordOelID},{shellID}&apikey={apiKey}";
|
||||||
|
|
||||||
|
HttpResponseMessage response;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = httpClient.GetAsync(request).Result;
|
||||||
|
|
||||||
|
lastFuelRequestTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
catch { continue; }
|
||||||
|
|
||||||
|
var responseString = response.Content.ReadAsStringAsync().Result;
|
||||||
|
|
||||||
|
dynamic? jsonResponse = JsonConvert.DeserializeObject(responseString);
|
||||||
|
|
||||||
|
if (jsonResponse == null || (bool)jsonResponse!.ok == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var cmds = new List<string>();
|
||||||
|
|
||||||
|
if((string)jsonResponse!.prices[nordOelID].status == "open")
|
||||||
|
{
|
||||||
|
cmds.Add($"say \"NORDOEL: Super: {(string)jsonResponse!.prices[nordOelID].e5} Euro, Diesel: {(string)jsonResponse!.prices[nordOelID].diesel} Euro\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmds.Add("say \"NORDOEL: Geschlossen\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((string)jsonResponse.prices[shellID].status == "open")
|
||||||
|
{
|
||||||
|
cmds.Add($"say \"Shell: Super: {(string)jsonResponse!.prices[shellID].e5} Euro, Diesel: {(string)jsonResponse!.prices[shellID].diesel} Euro\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmds.Add("say \"Shell: Geschlossen\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecuteCommands(true, cmds.ToArray());
|
||||||
|
}
|
||||||
|
else if (line.ToLower().Contains(weatherKeyWord))
|
||||||
|
{
|
||||||
|
string request = $"https://api.open-meteo.com/v1/forecast?latitude=54.2335&longitude=10.3397&hourly=temperature_2m,cloudcover&daily=precipitation_hours&timezone=Europe%2FBerlin";
|
||||||
|
|
||||||
|
HttpResponseMessage response;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = httpClient.GetAsync(request).Result;
|
||||||
|
}
|
||||||
|
catch { continue; }
|
||||||
|
|
||||||
|
var responseString = response.Content.ReadAsStringAsync().Result;
|
||||||
|
|
||||||
|
dynamic? jsonResponse = JsonConvert.DeserializeObject(responseString);
|
||||||
|
|
||||||
|
if (jsonResponse == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string cmd = $"say \"{((double)jsonResponse!.hourly.temperature_2m[0]).ToString(System.Globalization.CultureInfo.InvariantCulture)} C, Wolkendecke {(double)jsonResponse!.hourly.cloudcover[0]} %, Stunden Regen: {Math.Round((double)jsonResponse!.daily.precipitation_hours[0] * 100 / 24)} %\"";
|
||||||
|
|
||||||
|
ExecuteCommands(true, cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool didPlayerDie = damageTakenTotal >= 100;
|
||||||
|
|
||||||
|
if (!didPlayerDie)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (areListsEqual(taggedPlayers, prevTaggedPlayers))
|
||||||
|
{
|
||||||
|
// Last is the same as previous, likely dealt damage, died and now the round ended and it was printed again
|
||||||
|
Console.WriteLine("Double console output.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevTaggedPlayers = taggedPlayers;
|
||||||
|
|
||||||
|
if (taggedPlayers.Count < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string[] commands = new string[taggedPlayers.Count];
|
||||||
|
|
||||||
|
// We didn't have a round end, but got killed
|
||||||
|
for (int i = 0; i < commands.Length; i++)
|
||||||
|
{
|
||||||
|
commands[i] += "say_team \"";
|
||||||
|
if (taggedPlayers[i].Item2 > 90)
|
||||||
|
{
|
||||||
|
// One-shot
|
||||||
|
commands[i] += $"{taggedPlayers[i].Item1} is one-shot {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
else if (taggedPlayers[i].Item2 >= 70)
|
||||||
|
{
|
||||||
|
// Lit
|
||||||
|
commands[i] += $"{taggedPlayers[i].Item1} is lit for {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tagged
|
||||||
|
commands[i] += $"{taggedPlayers[i].Item1} is tagged for {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
|
||||||
|
commands[i] += "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify players
|
||||||
|
ExecuteCommands(false, commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool areListsEqual(List<Tuple<string, int, int>> list1, List<Tuple<string, int, int>> list2)
|
||||||
|
{
|
||||||
|
if (list1.Count != list2.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// still same length
|
||||||
|
for (int i = 0; i < list1.Count; i++)
|
||||||
|
{
|
||||||
|
if (list1[i].Item1 != list2[i].Item1)
|
||||||
|
return false;
|
||||||
|
if (list1[i].Item2 != list2[i].Item2)
|
||||||
|
return false;
|
||||||
|
if (list1[i].Item3 != list2[i].Item3)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExecuteCommands(bool triggeredByCommand, params string[] cmds)
|
||||||
|
{
|
||||||
|
if (cmds == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IntPtr hWnd = FindWindow("Valve001", null!);
|
||||||
|
|
||||||
|
if (hWnd == IntPtr.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int chatTimeoutMs = 700;
|
||||||
|
int commandsHandled = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < cmds.Length; i++)
|
||||||
|
{
|
||||||
|
if (cmds[i] == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cmds[i] = cmds[i].Trim();
|
||||||
|
|
||||||
|
COPYDATASTRUCT data;
|
||||||
|
data.dwData = 0;
|
||||||
|
data.cbData = (uint)cmds[i].Length + 1;
|
||||||
|
data.lpData = cmds[i];
|
||||||
|
|
||||||
|
if (triggeredByCommand)
|
||||||
|
Thread.Sleep(chatTimeoutMs);
|
||||||
|
|
||||||
|
// Allocate for data
|
||||||
|
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(data));
|
||||||
|
Marshal.StructureToPtr(data, ptr, false);
|
||||||
|
|
||||||
|
int ret = SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ptr);
|
||||||
|
|
||||||
|
Console.WriteLine(cmds[i]);
|
||||||
|
|
||||||
|
// Free data
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
commandsHandled++;
|
||||||
|
|
||||||
|
if (cmds[i].StartsWith("say") || cmds[i].StartsWith("say_team"))
|
||||||
|
Thread.Sleep(chatTimeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmds.Length > 0 && commandsHandled == cmds.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct COPYDATASTRUCT
|
||||||
|
{
|
||||||
|
public ulong dwData;
|
||||||
|
public uint cbData;
|
||||||
|
public string lpData;
|
||||||
|
}
|
225
Shared/LoreSoft.MathExpressions/ConvertExpression.cs
Normal file
225
Shared/LoreSoft.MathExpressions/ConvertExpression.cs
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
using LoreSoft.MathExpressions.UnitConversion;
|
||||||
|
using System.Globalization;
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class representing unit convertion expressions.
|
||||||
|
/// </summary>
|
||||||
|
public class ConvertExpression : ExpressionBase
|
||||||
|
{
|
||||||
|
private static Dictionary<string, ConvertionMap> convertionCache;
|
||||||
|
private static object cacheLock = new object();
|
||||||
|
|
||||||
|
private ConvertionMap current;
|
||||||
|
private string expression;
|
||||||
|
|
||||||
|
/// <summary>The format of a convertion expression.</summary>
|
||||||
|
public const string ExpressionFormat = "[{0}->{1}]";
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="ConvertExpression"/> class.</summary>
|
||||||
|
/// <param name="expression">The convertion expression for this instance.</param>
|
||||||
|
public ConvertExpression(string expression)
|
||||||
|
{
|
||||||
|
VerifyCache();
|
||||||
|
if (!convertionCache.ContainsKey(expression))
|
||||||
|
throw new ArgumentException(Resources.InvalidConvertionExpression + expression, "expression");
|
||||||
|
|
||||||
|
this.expression = expression;
|
||||||
|
current = convertionCache[expression];
|
||||||
|
base.Evaluate = new MathEvaluate(Convert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
public override int ArgumentCount
|
||||||
|
{
|
||||||
|
get { return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Convert the numbers to the new unit.</summary>
|
||||||
|
/// <param name="numbers">The numbers used in the convertion.</param>
|
||||||
|
/// <returns>The result of the convertion execution.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Convert(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double fromValue = numbers[0];
|
||||||
|
|
||||||
|
switch (current.UnitType)
|
||||||
|
{
|
||||||
|
case UnitType.Length:
|
||||||
|
return LengthConverter.Convert(
|
||||||
|
(LengthUnit) current.FromUnit,
|
||||||
|
(LengthUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
case UnitType.Mass:
|
||||||
|
return MassConverter.Convert(
|
||||||
|
(MassUnit) current.FromUnit,
|
||||||
|
(MassUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
case UnitType.Speed:
|
||||||
|
return SpeedConverter.Convert(
|
||||||
|
(SpeedUnit) current.FromUnit,
|
||||||
|
(SpeedUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
case UnitType.Temperature:
|
||||||
|
return TemperatureConverter.Convert(
|
||||||
|
(TemperatureUnit) current.FromUnit,
|
||||||
|
(TemperatureUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
case UnitType.Time:
|
||||||
|
return TimeConverter.Convert(
|
||||||
|
(TimeUnit) current.FromUnit,
|
||||||
|
(TimeUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
case UnitType.Volume:
|
||||||
|
return VolumeConverter.Convert(
|
||||||
|
(VolumeUnit) current.FromUnit,
|
||||||
|
(VolumeUnit) current.ToUnit,
|
||||||
|
fromValue);
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException("numbers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///<summary>
|
||||||
|
/// Determines whether the specified expression name is for unit convertion.
|
||||||
|
///</summary>
|
||||||
|
///<param name="expression">The expression to check.</param>
|
||||||
|
///<returns><c>true</c> if the specified expression is a unit convertion; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool IsConvertExpression(string expression)
|
||||||
|
{
|
||||||
|
//do basic checks before creating cache
|
||||||
|
if (string.IsNullOrEmpty(expression))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (expression[0] != '[')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
VerifyCache();
|
||||||
|
return convertionCache.ContainsKey(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void VerifyCache()
|
||||||
|
{
|
||||||
|
if (convertionCache != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (cacheLock)
|
||||||
|
{
|
||||||
|
if (convertionCache != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
convertionCache = new Dictionary<string, ConvertionMap>(
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
AddToCache<LengthUnit>(UnitType.Length);
|
||||||
|
AddToCache<MassUnit>(UnitType.Mass);
|
||||||
|
AddToCache<SpeedUnit>(UnitType.Speed);
|
||||||
|
AddToCache<TemperatureUnit>(UnitType.Temperature);
|
||||||
|
AddToCache<TimeUnit>(UnitType.Time);
|
||||||
|
AddToCache<VolumeUnit>(UnitType.Volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddToCache<T>(UnitType unitType)
|
||||||
|
where T : struct, IComparable, IFormattable, IConvertible
|
||||||
|
{
|
||||||
|
Type enumType = typeof(T);
|
||||||
|
int[] a = (int[])Enum.GetValues(enumType);
|
||||||
|
|
||||||
|
for (int x = 0; x < a.Length; x++)
|
||||||
|
{
|
||||||
|
MemberInfo parentInfo = GetMemberInfo(enumType, Enum.GetName(enumType, x));
|
||||||
|
string parrentKey = AttributeReader.GetAbbreviation(parentInfo);
|
||||||
|
|
||||||
|
for (int i = 0; i < a.Length; i++)
|
||||||
|
{
|
||||||
|
if (x == i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MemberInfo info = GetMemberInfo(enumType, Enum.GetName(enumType, i));
|
||||||
|
|
||||||
|
string key = string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
ExpressionFormat,
|
||||||
|
parrentKey,
|
||||||
|
AttributeReader.GetAbbreviation(info));
|
||||||
|
|
||||||
|
convertionCache.Add(
|
||||||
|
key, new ConvertionMap(unitType, x, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MemberInfo GetMemberInfo(Type type, string name)
|
||||||
|
{
|
||||||
|
MemberInfo[] info = type.GetMember(name);
|
||||||
|
if (info == null || info.Length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return info[0];
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </returns>
|
||||||
|
/// <filterPriority>2</filterPriority>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConvertionMap
|
||||||
|
{
|
||||||
|
public ConvertionMap(UnitType unitType, int fromUnit, int toUnit)
|
||||||
|
{
|
||||||
|
_unitType = unitType;
|
||||||
|
_fromUnit = fromUnit;
|
||||||
|
_toUnit = toUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnitType _unitType;
|
||||||
|
|
||||||
|
public UnitType UnitType
|
||||||
|
{
|
||||||
|
get { return _unitType; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _fromUnit;
|
||||||
|
|
||||||
|
public int FromUnit
|
||||||
|
{
|
||||||
|
get { return _fromUnit; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _toUnit;
|
||||||
|
|
||||||
|
public int ToUnit
|
||||||
|
{
|
||||||
|
get { return _toUnit; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format(
|
||||||
|
CultureInfo.CurrentCulture,
|
||||||
|
"{0}, [{1}->{2}]",
|
||||||
|
_unitType,
|
||||||
|
_fromUnit,
|
||||||
|
_toUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
Shared/LoreSoft.MathExpressions/ExpressionBase.cs
Normal file
35
Shared/LoreSoft.MathExpressions/ExpressionBase.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>The base class for expressions</summary>
|
||||||
|
public abstract class ExpressionBase : IExpression
|
||||||
|
{
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
public abstract int ArgumentCount { get; }
|
||||||
|
|
||||||
|
private MathEvaluate _evaluateDelegate;
|
||||||
|
|
||||||
|
/// <summary>Gets or sets the evaluate delegate.</summary>
|
||||||
|
/// <value>The evaluate delegate.</value>
|
||||||
|
public virtual MathEvaluate Evaluate
|
||||||
|
{
|
||||||
|
get { return _evaluateDelegate; }
|
||||||
|
set { _evaluateDelegate = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Validates the specified numbers for the expression.</summary>
|
||||||
|
/// <param name="numbers">The numbers to validate.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
protected void Validate(double[] numbers)
|
||||||
|
{
|
||||||
|
if (numbers == null)
|
||||||
|
throw new ArgumentNullException("numbers");
|
||||||
|
if (numbers.Length != ArgumentCount)
|
||||||
|
throw new ArgumentException(Resources.InvalidLengthOfArray, "numbers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
Shared/LoreSoft.MathExpressions/FunctionExpression.cs
Normal file
113
Shared/LoreSoft.MathExpressions/FunctionExpression.cs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class representing the System.Math function expressions
|
||||||
|
/// </summary>
|
||||||
|
public class FunctionExpression : ExpressionBase
|
||||||
|
{
|
||||||
|
// must be sorted
|
||||||
|
/// <summary>The supported math functions by this class.</summary>
|
||||||
|
private static readonly string[] mathFunctions = new string[]
|
||||||
|
{
|
||||||
|
"abs", "acos", "asin", "atan", "ceiling", "cos", "cosh", "exp",
|
||||||
|
"floor", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="FunctionExpression"/> class.</summary>
|
||||||
|
/// <param name="function">The function name for this instance.</param>
|
||||||
|
public FunctionExpression(string function) : this(function, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="FunctionExpression"/> class.</summary>
|
||||||
|
/// <param name="function">The function.</param>
|
||||||
|
/// <param name="validate">if set to <c>true</c> to validate the function name.</param>
|
||||||
|
internal FunctionExpression(string function, bool validate)
|
||||||
|
{
|
||||||
|
function = function.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (validate && !IsFunction(function))
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format(CultureInfo.CurrentCulture, Resources.InvalidFunctionName, _function),
|
||||||
|
"function");
|
||||||
|
|
||||||
|
_function = function;
|
||||||
|
base.Evaluate = new MathEvaluate(Execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _function;
|
||||||
|
|
||||||
|
/// <summary>Gets the name function for this instance.</summary>
|
||||||
|
/// <value>The function name.</value>
|
||||||
|
public string Function
|
||||||
|
{
|
||||||
|
get { return _function; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Executes the function on specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers used in the function.</param>
|
||||||
|
/// <returns>The result of the function execution.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Execute(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
|
||||||
|
string function = char.ToUpperInvariant(_function[0]) + _function.Substring(1);
|
||||||
|
MethodInfo method = typeof (Math).GetMethod(
|
||||||
|
function,
|
||||||
|
BindingFlags.Static | BindingFlags.Public,
|
||||||
|
null,
|
||||||
|
new Type[] { typeof(double) },
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (method == null)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Resources.InvalidFunctionName, _function));
|
||||||
|
|
||||||
|
object[] parameters = new object[numbers.Length];
|
||||||
|
Array.Copy(numbers, parameters, numbers.Length);
|
||||||
|
return (double) method.Invoke(null, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
public override int ArgumentCount
|
||||||
|
{
|
||||||
|
get { return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified function name is a function.</summary>
|
||||||
|
/// <param name="function">The function name.</param>
|
||||||
|
/// <returns><c>true</c> if the specified name is a function; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool IsFunction(string function)
|
||||||
|
{
|
||||||
|
return (Array.BinarySearch(
|
||||||
|
mathFunctions, function,
|
||||||
|
StringComparer.OrdinalIgnoreCase) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.</summary>
|
||||||
|
/// <returns>A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.</returns>
|
||||||
|
/// <filterPriority>2</filterPriority>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _function;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the function names.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of function names.</returns>
|
||||||
|
public static string[] GetFunctionNames()
|
||||||
|
{
|
||||||
|
return (string[])mathFunctions.Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Shared/LoreSoft.MathExpressions/GlobalSuppressions.cs
Normal file
2
Shared/LoreSoft.MathExpressions/GlobalSuppressions.cs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "LoreSoft.MathExpressions.Metadata")]
|
15
Shared/LoreSoft.MathExpressions/IExpression.cs
Normal file
15
Shared/LoreSoft.MathExpressions/IExpression.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The interface used when running expressions
|
||||||
|
/// </summary>
|
||||||
|
public interface IExpression
|
||||||
|
{
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
int ArgumentCount { get; }
|
||||||
|
/// <summary>Gets or sets the evaluate delegate.</summary>
|
||||||
|
/// <value>The evaluate delegate.</value>
|
||||||
|
MathEvaluate Evaluate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
185
Shared/LoreSoft.MathExpressions/LoreSoft.MathExpressions.csproj
Normal file
185
Shared/LoreSoft.MathExpressions/LoreSoft.MathExpressions.csproj
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>9.0.30729</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{B6813448-FCE2-429C-81B5-9722FEA839B8}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LoreSoft.MathExpressions</RootNamespace>
|
||||||
|
<AssemblyName>LoreSoft.MathExpressions</AssemblyName>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>MathExpressions.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<FileUpgradeFlags>
|
||||||
|
</FileUpgradeFlags>
|
||||||
|
<OldToolsVersion>3.5</OldToolsVersion>
|
||||||
|
<UpgradeBackupLocation>
|
||||||
|
</UpgradeBackupLocation>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\..\Build\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<DocumentationFile>..\..\Build\Debug\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>..\..\Build\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<DocumentationFile>..\..\Build\Release\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>..\..\Build\x86\Debug\</OutputPath>
|
||||||
|
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
|
||||||
|
<DocumentationFile>..\..\Build\Debug\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||||
|
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<OutputPath>..\..\Build\x86\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<DocumentationFile>..\..\Build\Release\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||||
|
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>..\..\Build\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
|
||||||
|
<DocumentationFile>..\..\Build\Debug\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||||
|
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||||
|
<OutputPath>..\..\Build\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<DocumentationFile>..\..\Build\Release\LoreSoft.MathExpressions.XML</DocumentationFile>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||||
|
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="ConvertExpression.cs" />
|
||||||
|
<Compile Include="ExpressionBase.cs" />
|
||||||
|
<Compile Include="FunctionExpression.cs" />
|
||||||
|
<Compile Include="GlobalSuppressions.cs" />
|
||||||
|
<Compile Include="IExpression.cs" />
|
||||||
|
<Compile Include="MathEvaluate.cs" />
|
||||||
|
<Compile Include="MathEvaluator.cs" />
|
||||||
|
<Compile Include="MathOperators.cs" />
|
||||||
|
<Compile Include="Metadata\AttributeReader.cs" />
|
||||||
|
<Compile Include="NumberExpression.cs" />
|
||||||
|
<Compile Include="OperatorExpression.cs" />
|
||||||
|
<Compile Include="ParseException.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Metadata\AbbreviationAttribute.cs" />
|
||||||
|
<Compile Include="UnitConversion\LengthConverter.cs" />
|
||||||
|
<Compile Include="UnitConversion\MassConverter.cs" />
|
||||||
|
<Compile Include="UnitConversion\SpeedConverter.cs" />
|
||||||
|
<Compile Include="UnitConversion\TemperatureConverter.cs" />
|
||||||
|
<Compile Include="UnitConversion\TimeConverter.cs" />
|
||||||
|
<Compile Include="UnitConversion\UnitType.cs" />
|
||||||
|
<Compile Include="UnitConversion\VolumeConverter.cs" />
|
||||||
|
<Compile Include="VariableDictionary.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="MathExpressions.snk" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Windows Installer 3.1</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
7
Shared/LoreSoft.MathExpressions/MathEvaluate.cs
Normal file
7
Shared/LoreSoft.MathExpressions/MathEvaluate.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>Delegate used by an expression to do the math evaluation.</summary>
|
||||||
|
/// <param name="numbers">The numbers to evaluate.</param>
|
||||||
|
/// <returns>The result of the evaluated numbers.</returns>
|
||||||
|
public delegate double MathEvaluate(double[] numbers);
|
||||||
|
}
|
458
Shared/LoreSoft.MathExpressions/MathEvaluator.cs
Normal file
458
Shared/LoreSoft.MathExpressions/MathEvaluator.cs
Normal file
|
@ -0,0 +1,458 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluate math expressions
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Using the MathEvaluator to calculate a math expression.
|
||||||
|
/// <code>
|
||||||
|
/// MathEvaluator eval = new MathEvaluator();
|
||||||
|
/// //basic math
|
||||||
|
/// double result = eval.Evaluate("(2 + 1) * (1 + 2)");
|
||||||
|
/// //calling a function
|
||||||
|
/// result = eval.Evaluate("sqrt(4)");
|
||||||
|
/// //evaluate trigonometric
|
||||||
|
/// result = eval.Evaluate("cos(pi * 45 / 180.0)");
|
||||||
|
/// //convert inches to feet
|
||||||
|
/// result = eval.Evaluate("12 [in->ft]");
|
||||||
|
/// //use variable
|
||||||
|
/// result = eval.Evaluate("answer * 10");
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public class MathEvaluator : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>The name of the answer variable.</summary>
|
||||||
|
/// <seealso cref="Variables"/>
|
||||||
|
public const string AnswerVariable = "answer";
|
||||||
|
|
||||||
|
//instance scope to optimize reuse
|
||||||
|
private Stack<string> _symbolStack;
|
||||||
|
private Queue<IExpression> _expressionQueue;
|
||||||
|
private Dictionary<string, IExpression> _expressionCache;
|
||||||
|
private StringBuilder _buffer;
|
||||||
|
private Stack<double> _calculationStack;
|
||||||
|
private Stack<double> _parameters;
|
||||||
|
private List<string> _innerFunctions;
|
||||||
|
|
||||||
|
private StringReader _expressionReader;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MathEvaluator"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public MathEvaluator()
|
||||||
|
{
|
||||||
|
_variables = new VariableDictionary(this);
|
||||||
|
_innerFunctions = new List<string>(FunctionExpression.GetFunctionNames());
|
||||||
|
_functions = new ReadOnlyCollection<string>(_innerFunctions);
|
||||||
|
_expressionCache = new Dictionary<string, IExpression>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
_symbolStack = new Stack<string>();
|
||||||
|
_expressionQueue = new Queue<IExpression>();
|
||||||
|
_buffer = new StringBuilder();
|
||||||
|
_calculationStack = new Stack<double>();
|
||||||
|
_parameters = new Stack<double>(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VariableDictionary _variables;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the variables collections.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The variables for <see cref="MathEvaluator"/>.</value>
|
||||||
|
public VariableDictionary Variables
|
||||||
|
{
|
||||||
|
get { return _variables; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadOnlyCollection<string> _functions;
|
||||||
|
|
||||||
|
/// <summary>Gets the functions available to <see cref="MathEvaluator"/>.</summary>
|
||||||
|
/// <value>The functions for <see cref="MathEvaluator"/>.</value>
|
||||||
|
/// <seealso cref="RegisterFunction"/>
|
||||||
|
public ReadOnlyCollection<string> Functions
|
||||||
|
{
|
||||||
|
get { return _functions; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the answer from the last evaluation.</summary>
|
||||||
|
/// <value>The answer variable value.</value>
|
||||||
|
/// <seealso cref="Variables"/>
|
||||||
|
public double Answer
|
||||||
|
{
|
||||||
|
get { return _variables[AnswerVariable]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Evaluates the specified expression.</summary>
|
||||||
|
/// <param name="expression">The expression to evaluate.</param>
|
||||||
|
/// <returns>The result of the evaluated expression.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When expression is null or empty.</exception>
|
||||||
|
/// <exception cref="ParseException">When there is an error parsing the expression.</exception>
|
||||||
|
public double Evaluate(string expression)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(expression))
|
||||||
|
throw new ArgumentNullException("expression");
|
||||||
|
|
||||||
|
_expressionReader = new StringReader(expression);
|
||||||
|
_symbolStack.Clear();
|
||||||
|
_expressionQueue.Clear();
|
||||||
|
|
||||||
|
ParseExpressionToQueue();
|
||||||
|
|
||||||
|
double result = CalculateFromQueue();
|
||||||
|
|
||||||
|
_variables[AnswerVariable] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Registers a function for the <see cref="MathEvaluator"/>.</summary>
|
||||||
|
/// <param name="functionName">Name of the function.</param>
|
||||||
|
/// <param name="expression">An instance of <see cref="IExpression"/> for the function.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">When functionName or expression are null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When IExpression.Evaluate property is null or the functionName is already registered.</exception>
|
||||||
|
/// <seealso cref="Functions"/>
|
||||||
|
/// <seealso cref="IExpression"/>
|
||||||
|
public void RegisterFunction(string functionName, IExpression expression)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(functionName))
|
||||||
|
throw new ArgumentNullException("functionName");
|
||||||
|
if (expression == null)
|
||||||
|
throw new ArgumentNullException("expression");
|
||||||
|
if (expression.Evaluate == null)
|
||||||
|
throw new ArgumentException(Resources.EvaluatePropertyCanNotBeNull, "expression");
|
||||||
|
if (_innerFunctions.BinarySearch(functionName) >= 0)
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Resources.FunctionNameRegistered, functionName), "functionName");
|
||||||
|
|
||||||
|
_innerFunctions.Add(functionName);
|
||||||
|
_innerFunctions.Sort();
|
||||||
|
_expressionCache.Add(functionName, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified name is a function.</summary>
|
||||||
|
/// <param name="name">The name of the function.</param>
|
||||||
|
/// <returns><c>true</c> if the specified name is function; otherwise, <c>false</c>.</returns>
|
||||||
|
internal bool IsFunction(string name)
|
||||||
|
{
|
||||||
|
return (_innerFunctions.BinarySearch(name, StringComparer.OrdinalIgnoreCase) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseExpressionToQueue()
|
||||||
|
{
|
||||||
|
char l = '\0';
|
||||||
|
char c = '\0';
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// last non white space char
|
||||||
|
if (!char.IsWhiteSpace(c))
|
||||||
|
l = c;
|
||||||
|
|
||||||
|
c = (char)_expressionReader.Read();
|
||||||
|
|
||||||
|
if (char.IsWhiteSpace(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryNumber(c, l))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryString(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryStartGroup(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryOperator(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryEndGroup(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryConvert(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
throw new ParseException(Resources.InvalidCharacterEncountered + c);
|
||||||
|
} while (_expressionReader.Peek() != -1);
|
||||||
|
|
||||||
|
ProcessSymbolStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryConvert(char c)
|
||||||
|
{
|
||||||
|
if (c != '[')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_buffer.Length = 0;
|
||||||
|
_buffer.Append(c);
|
||||||
|
|
||||||
|
char p = (char)_expressionReader.Peek();
|
||||||
|
while (char.IsLetter(p) || char.IsWhiteSpace(p) || p == '-' || p == '>' || p == ']')
|
||||||
|
{
|
||||||
|
if (!char.IsWhiteSpace(p))
|
||||||
|
_buffer.Append((char)_expressionReader.Read());
|
||||||
|
else
|
||||||
|
_expressionReader.Read();
|
||||||
|
|
||||||
|
if (p == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = (char)_expressionReader.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConvertExpression.IsConvertExpression(_buffer.ToString()))
|
||||||
|
{
|
||||||
|
IExpression e = GetExpressionFromSymbol(_buffer.ToString());
|
||||||
|
_expressionQueue.Enqueue(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ParseException(Resources.InvalidConvertionExpression + _buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryString(char c)
|
||||||
|
{
|
||||||
|
if (!char.IsLetter(c))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_buffer.Length = 0;
|
||||||
|
_buffer.Append(c);
|
||||||
|
|
||||||
|
char p = (char)_expressionReader.Peek();
|
||||||
|
while (char.IsLetter(p))
|
||||||
|
{
|
||||||
|
_buffer.Append((char)_expressionReader.Read());
|
||||||
|
p = (char)_expressionReader.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_variables.ContainsKey(_buffer.ToString()))
|
||||||
|
{
|
||||||
|
double value = _variables[_buffer.ToString()];
|
||||||
|
NumberExpression expression = new NumberExpression(value);
|
||||||
|
_expressionQueue.Enqueue(expression);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsFunction(_buffer.ToString()))
|
||||||
|
{
|
||||||
|
_symbolStack.Push(_buffer.ToString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ParseException(Resources.InvalidVariableEncountered + _buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryStartGroup(char c)
|
||||||
|
{
|
||||||
|
if (c != '(')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_symbolStack.Push(c.ToString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryEndGroup(char c)
|
||||||
|
{
|
||||||
|
if (c != ')')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool hasStart = false;
|
||||||
|
|
||||||
|
while (_symbolStack.Count > 0)
|
||||||
|
{
|
||||||
|
string p = _symbolStack.Pop();
|
||||||
|
if (p == "(")
|
||||||
|
{
|
||||||
|
hasStart = true;
|
||||||
|
|
||||||
|
if (_symbolStack.Count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
string n = _symbolStack.Peek();
|
||||||
|
if (FunctionExpression.IsFunction(n))
|
||||||
|
{
|
||||||
|
p = _symbolStack.Pop();
|
||||||
|
IExpression f = GetExpressionFromSymbol(p);
|
||||||
|
_expressionQueue.Enqueue(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IExpression e = GetExpressionFromSymbol(p);
|
||||||
|
_expressionQueue.Enqueue(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasStart)
|
||||||
|
throw new ParseException(Resources.UnbalancedParentheses);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryOperator(char c)
|
||||||
|
{
|
||||||
|
if (!OperatorExpression.IsSymbol(c))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool repeat;
|
||||||
|
string s = c.ToString();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
string p = _symbolStack.Count == 0 ? string.Empty : _symbolStack.Peek();
|
||||||
|
repeat = false;
|
||||||
|
if (_symbolStack.Count == 0)
|
||||||
|
_symbolStack.Push(s);
|
||||||
|
else if (p == "(")
|
||||||
|
_symbolStack.Push(s);
|
||||||
|
else if (Precedence(s) > Precedence(p))
|
||||||
|
_symbolStack.Push(s);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IExpression e = GetExpressionFromSymbol(_symbolStack.Pop());
|
||||||
|
_expressionQueue.Enqueue(e);
|
||||||
|
repeat = true;
|
||||||
|
}
|
||||||
|
} while (repeat);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryNumber(char c, char l)
|
||||||
|
{
|
||||||
|
bool isNumber = NumberExpression.IsNumber(c);
|
||||||
|
// only negative when last char is group start or symbol
|
||||||
|
bool isNegative = NumberExpression.IsNegativeSign(c) &&
|
||||||
|
(l == '\0' || l == '(' || OperatorExpression.IsSymbol(l));
|
||||||
|
|
||||||
|
if (!isNumber && !isNegative)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_buffer.Length = 0;
|
||||||
|
_buffer.Append(c);
|
||||||
|
|
||||||
|
char p = (char)_expressionReader.Peek();
|
||||||
|
while (NumberExpression.IsNumber(p))
|
||||||
|
{
|
||||||
|
_buffer.Append((char)_expressionReader.Read());
|
||||||
|
p = (char)_expressionReader.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
double value;
|
||||||
|
if (!(double.TryParse(_buffer.ToString(), out value)))
|
||||||
|
throw new ParseException(Resources.InvalidNumberFormat + _buffer);
|
||||||
|
|
||||||
|
NumberExpression expression = new NumberExpression(value);
|
||||||
|
_expressionQueue.Enqueue(expression);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessSymbolStack()
|
||||||
|
{
|
||||||
|
while (_symbolStack.Count > 0)
|
||||||
|
{
|
||||||
|
string p = _symbolStack.Pop();
|
||||||
|
if (p.Length == 1 && p == "(")
|
||||||
|
throw new ParseException(Resources.UnbalancedParentheses);
|
||||||
|
|
||||||
|
IExpression e = GetExpressionFromSymbol(p);
|
||||||
|
_expressionQueue.Enqueue(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IExpression GetExpressionFromSymbol(string p)
|
||||||
|
{
|
||||||
|
IExpression e;
|
||||||
|
|
||||||
|
if (_expressionCache.ContainsKey(p))
|
||||||
|
e = _expressionCache[p];
|
||||||
|
else if (OperatorExpression.IsSymbol(p))
|
||||||
|
{
|
||||||
|
e = new OperatorExpression(p);
|
||||||
|
_expressionCache.Add(p, e);
|
||||||
|
}
|
||||||
|
else if (FunctionExpression.IsFunction(p))
|
||||||
|
{
|
||||||
|
e = new FunctionExpression(p, false);
|
||||||
|
_expressionCache.Add(p, e);
|
||||||
|
}
|
||||||
|
else if (ConvertExpression.IsConvertExpression(p))
|
||||||
|
{
|
||||||
|
e = new ConvertExpression(p);
|
||||||
|
_expressionCache.Add(p, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new ParseException(Resources.InvalidSymbolOnStack + p);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Precedence(string c)
|
||||||
|
{
|
||||||
|
if (c.Length == 1 && (c[0] == '*' || c[0] == '/' || c[0] == '%'))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double CalculateFromQueue()
|
||||||
|
{
|
||||||
|
double result;
|
||||||
|
_calculationStack.Clear();
|
||||||
|
|
||||||
|
foreach (IExpression expression in _expressionQueue)
|
||||||
|
{
|
||||||
|
if (_calculationStack.Count < expression.ArgumentCount)
|
||||||
|
throw new ParseException(Resources.NotEnoughNumbers + expression);
|
||||||
|
|
||||||
|
_parameters.Clear();
|
||||||
|
for (int i = 0; i < expression.ArgumentCount; i++)
|
||||||
|
_parameters.Push(_calculationStack.Pop());
|
||||||
|
|
||||||
|
_calculationStack.Push(expression.Evaluate.Invoke(_parameters.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _calculationStack.Pop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and - optionally - managed resources
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and managed resources
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">
|
||||||
|
/// <c>true</c> to release both managed and unmanaged resources;
|
||||||
|
/// <c>false</c> to release only unmanaged resources.
|
||||||
|
/// </param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (_expressionReader != null)
|
||||||
|
{
|
||||||
|
_expressionReader.Dispose();
|
||||||
|
_expressionReader = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
BIN
Shared/LoreSoft.MathExpressions/MathExpressions.snk
Normal file
BIN
Shared/LoreSoft.MathExpressions/MathExpressions.snk
Normal file
Binary file not shown.
19
Shared/LoreSoft.MathExpressions/MathOperators.cs
Normal file
19
Shared/LoreSoft.MathExpressions/MathOperators.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>Math Operators</summary>
|
||||||
|
public enum MathOperators
|
||||||
|
{
|
||||||
|
/// <summary>Add Operator</summary>
|
||||||
|
Add,
|
||||||
|
/// <summary>Subtract Operator</summary>
|
||||||
|
Subtract,
|
||||||
|
/// <summary>Multiple Operator</summary>
|
||||||
|
Multiple,
|
||||||
|
/// <summary>Divide Operator</summary>
|
||||||
|
Divide,
|
||||||
|
/// <summary>Modulo Operator</summary>
|
||||||
|
Modulo,
|
||||||
|
/// <summary>Power Operator</summary>
|
||||||
|
Power
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions.Metadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies an abbreviation for a instance.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsageAttribute(AttributeTargets.All)]
|
||||||
|
public sealed class AbbreviationAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbbreviationAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The abbreviation text.</param>
|
||||||
|
public AbbreviationAttribute(string text)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _text;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the abbreviation text.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The abbreviation text.</value>
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _text; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </returns>
|
||||||
|
/// <filterPriority>2</filterPriority>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
Shared/LoreSoft.MathExpressions/Metadata/AttributeReader.cs
Normal file
108
Shared/LoreSoft.MathExpressions/Metadata/AttributeReader.cs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions.Metadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class to read attributes from type members.
|
||||||
|
/// </summary>
|
||||||
|
public static class AttributeReader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description from the <see cref="DescriptionAttribute"/> on an enum.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">An enum type.</typeparam>
|
||||||
|
/// <param name="instance">The value to get the description from.</param>
|
||||||
|
/// <returns>The <see cref="DescriptionAttribute.Description"/> or the name of the instance.</returns>
|
||||||
|
/// <seealso cref="DescriptionAttribute"/>
|
||||||
|
public static string GetDescription<T>(T instance)
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
throw new ArgumentNullException("instance");
|
||||||
|
|
||||||
|
string result = instance.ToString();
|
||||||
|
|
||||||
|
Type type = instance.GetType();
|
||||||
|
MemberInfo[] members = type.GetMember(result);
|
||||||
|
|
||||||
|
if (members == null || members.Length == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return GetDescription(members[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description from the <see cref="DescriptionAttribute"/> on a MemberInfo.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The member info to look for the description.</param>
|
||||||
|
/// <returns>The <see cref="DescriptionAttribute.Description"/> or the name of the member.</returns>
|
||||||
|
/// <seealso cref="DescriptionAttribute"/>
|
||||||
|
public static string GetDescription(MemberInfo info)
|
||||||
|
{
|
||||||
|
if (info == null)
|
||||||
|
throw new ArgumentNullException("info");
|
||||||
|
|
||||||
|
string result = info.Name;
|
||||||
|
|
||||||
|
object[] attributes = info.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||||
|
if (attributes == null || attributes.Length == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
DescriptionAttribute description = attributes[0] as DescriptionAttribute;
|
||||||
|
if (description == null || string.IsNullOrEmpty(description.Description))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return description.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the abbreviation from the <see cref="AbbreviationAttribute"/> on an enum.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">An enum type.</typeparam>
|
||||||
|
/// <param name="instance">The enum to get the abbreviation from.</param>
|
||||||
|
/// <returns>The <see cref="AbbreviationAttribute.Text"/> or the name of the memeber.</returns>
|
||||||
|
/// <seealso cref="AbbreviationAttribute"/>
|
||||||
|
public static string GetAbbreviation<T>(T instance)
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
throw new ArgumentNullException("instance");
|
||||||
|
|
||||||
|
string result = instance.ToString();
|
||||||
|
|
||||||
|
Type type = instance.GetType();
|
||||||
|
MemberInfo[] members = type.GetMember(result);
|
||||||
|
|
||||||
|
if (members == null || members.Length == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return GetAbbreviation(members[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the abbreviation from the <see cref="AbbreviationAttribute"/> on a instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The instance info look for the abbreviation.</param>
|
||||||
|
/// <returns>The <see cref="AbbreviationAttribute.Text"/> or the name of the instance.</returns>
|
||||||
|
/// <seealso cref="AbbreviationAttribute"/>
|
||||||
|
public static string GetAbbreviation(MemberInfo info)
|
||||||
|
{
|
||||||
|
if (info == null)
|
||||||
|
throw new ArgumentNullException("info");
|
||||||
|
|
||||||
|
string result = info.Name;
|
||||||
|
|
||||||
|
object[] attributes = info.GetCustomAttributes(typeof(AbbreviationAttribute), false);
|
||||||
|
if (attributes == null || attributes.Length == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
AbbreviationAttribute abbreviation = attributes[0] as AbbreviationAttribute;
|
||||||
|
if (abbreviation == null || string.IsNullOrEmpty(abbreviation.Text))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return abbreviation.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
Shared/LoreSoft.MathExpressions/NumberExpression.cs
Normal file
68
Shared/LoreSoft.MathExpressions/NumberExpression.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing a constant number expression.
|
||||||
|
/// </summary>
|
||||||
|
public class NumberExpression : ExpressionBase
|
||||||
|
{
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="NumberExpression"/> class.</summary>
|
||||||
|
/// <param name="value">The number value for this expression.</param>
|
||||||
|
public NumberExpression(double value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
base.Evaluate = delegate
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
public override int ArgumentCount
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private double _value;
|
||||||
|
|
||||||
|
/// <summary>Gets the number value for this expression.</summary>
|
||||||
|
/// <value>The number value.</value>
|
||||||
|
public double Value
|
||||||
|
{
|
||||||
|
get { return _value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified char is a number.</summary>
|
||||||
|
/// <param name="c">The char to test.</param>
|
||||||
|
/// <returns><c>true</c> if the specified char is a number; otherwise, <c>false</c>.</returns>
|
||||||
|
/// <remarks>This method checks if the char is a digit or a decimal separator.</remarks>
|
||||||
|
public static bool IsNumber(char c)
|
||||||
|
{
|
||||||
|
NumberFormatInfo f = CultureInfo.CurrentUICulture.NumberFormat;
|
||||||
|
return char.IsDigit(c) || f.NumberDecimalSeparator.IndexOf(c) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified char is negative sign.</summary>
|
||||||
|
/// <param name="c">The char to check.</param>
|
||||||
|
/// <returns><c>true</c> if the specified char is negative sign; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool IsNegativeSign(char c)
|
||||||
|
{
|
||||||
|
NumberFormatInfo f = CultureInfo.CurrentUICulture.NumberFormat;
|
||||||
|
return f.NegativeSign.IndexOf(c) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </returns>
|
||||||
|
/// <filterPriority>2</filterPriority>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _value.ToString(CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
Shared/LoreSoft.MathExpressions/OperatorExpression.cs
Normal file
203
Shared/LoreSoft.MathExpressions/OperatorExpression.cs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
using System;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing a math operator expression.
|
||||||
|
/// </summary>
|
||||||
|
public class OperatorExpression : ExpressionBase
|
||||||
|
{
|
||||||
|
/// <summary>The supported math operators by this class.</summary>
|
||||||
|
private static readonly char[] operatorSymbols = new char[] {'+', '-', '*', '/', '%', '^'};
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="OperatorExpression"/> class.</summary>
|
||||||
|
/// <param name="operator">The operator to use for this class.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">When the operator is null or empty.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the operator is invalid.</exception>
|
||||||
|
public OperatorExpression(string @operator)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(@operator))
|
||||||
|
throw new ArgumentNullException("operator");
|
||||||
|
|
||||||
|
switch (@operator)
|
||||||
|
{
|
||||||
|
case "+":
|
||||||
|
base.Evaluate = new MathEvaluate(Add);
|
||||||
|
_mathOperator = MathOperators.Add;
|
||||||
|
break;
|
||||||
|
case "-":
|
||||||
|
base.Evaluate = new MathEvaluate(Subtract);
|
||||||
|
_mathOperator = MathOperators.Subtract;
|
||||||
|
break;
|
||||||
|
case "*":
|
||||||
|
base.Evaluate = new MathEvaluate(Multiple);
|
||||||
|
_mathOperator = MathOperators.Multiple;
|
||||||
|
break;
|
||||||
|
case "/":
|
||||||
|
base.Evaluate = new MathEvaluate(Divide);
|
||||||
|
_mathOperator = MathOperators.Divide;
|
||||||
|
break;
|
||||||
|
case "%":
|
||||||
|
base.Evaluate = new MathEvaluate(Modulo);
|
||||||
|
_mathOperator = MathOperators.Modulo;
|
||||||
|
break;
|
||||||
|
case "^":
|
||||||
|
base.Evaluate = new MathEvaluate(Power);
|
||||||
|
_mathOperator = MathOperators.Power;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException(Resources.InvalidOperator + @operator, "operator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MathOperators _mathOperator;
|
||||||
|
|
||||||
|
/// <summary>Gets the math operator.</summary>
|
||||||
|
/// <value>The math operator.</value>
|
||||||
|
public MathOperators MathOperator
|
||||||
|
{
|
||||||
|
get { return _mathOperator; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the number of arguments this expression uses.</summary>
|
||||||
|
/// <value>The argument count.</value>
|
||||||
|
public override int ArgumentCount
|
||||||
|
{
|
||||||
|
get { return 2; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Add(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double result = 0;
|
||||||
|
foreach (double n in numbers)
|
||||||
|
result += n;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Subtracts the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Subtract(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double? result = null;
|
||||||
|
foreach (double n in numbers)
|
||||||
|
if (result.HasValue)
|
||||||
|
result -= n;
|
||||||
|
else
|
||||||
|
result = n;
|
||||||
|
|
||||||
|
return result ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Multiples the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Multiple(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double? result = null;
|
||||||
|
foreach (double n in numbers)
|
||||||
|
if (result.HasValue)
|
||||||
|
result *= n;
|
||||||
|
else
|
||||||
|
result = n;
|
||||||
|
|
||||||
|
return result ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Divides the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Divide(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double? result = null;
|
||||||
|
foreach (double n in numbers)
|
||||||
|
if (result.HasValue)
|
||||||
|
result /= n;
|
||||||
|
else
|
||||||
|
result = n;
|
||||||
|
|
||||||
|
return result ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Modulo the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Modulo(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
double? result = null;
|
||||||
|
foreach (double n in numbers)
|
||||||
|
if (result.HasValue)
|
||||||
|
result %= n;
|
||||||
|
else
|
||||||
|
result = n;
|
||||||
|
|
||||||
|
return result ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Power for the specified numbers.</summary>
|
||||||
|
/// <param name="numbers">The numbers.</param>
|
||||||
|
/// <returns>The result of the operation.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">When numbers is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When the length of numbers do not equal <see cref="ArgumentCount"/>.</exception>
|
||||||
|
public double Power(double[] numbers)
|
||||||
|
{
|
||||||
|
base.Validate(numbers);
|
||||||
|
return Math.Pow(numbers[0], numbers[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified string is a math symbol.</summary>
|
||||||
|
/// <param name="s">The string to check.</param>
|
||||||
|
/// <returns><c>true</c> if the specified string is a math symbol; otherwise, <c>false</c>.</returns>
|
||||||
|
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||||
|
public static bool IsSymbol(string s)
|
||||||
|
{
|
||||||
|
if (s == null || s.Length != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char c = s[0];
|
||||||
|
return IsSymbol(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified char is a math symbol.</summary>
|
||||||
|
/// <param name="c">The char to check.</param>
|
||||||
|
/// <returns><c>true</c> if the specified char is a math symbol; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool IsSymbol(char c)
|
||||||
|
{
|
||||||
|
return Array.Exists(operatorSymbols, delegate(char s) { return s == c; });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
|
||||||
|
/// </returns>
|
||||||
|
/// <filterPriority>2</filterPriority>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _mathOperator.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
Shared/LoreSoft.MathExpressions/ParseException.cs
Normal file
40
Shared/LoreSoft.MathExpressions/ParseException.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception that is thrown when there is an error parsing a math expression.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class ParseException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="ParseException"/> class.</summary>
|
||||||
|
public ParseException()
|
||||||
|
: base()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="ParseException"/> class.</summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
public ParseException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="ParseException"/> class.</summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
/// <param name="innerException">The inner exception.</param>
|
||||||
|
public ParseException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ParseException"/> class with serialized data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
|
||||||
|
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
|
||||||
|
protected ParseException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
Shared/LoreSoft.MathExpressions/Properties/AssemblyInfo.cs
Normal file
50
Shared/LoreSoft.MathExpressions/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.34209
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[assembly: System.Reflection.AssemblyTitle("LoreSoft.MathExpressions")]
|
||||||
|
[assembly: System.Reflection.AssemblyProduct("LoreSoft.MathExpressions")]
|
||||||
|
[assembly: System.Reflection.AssemblyDescription("Math Expression Parser.")]
|
||||||
|
[assembly: System.Reflection.AssemblyCompany("LoreSoft")]
|
||||||
|
[assembly: System.Reflection.AssemblyCopyright("Copyright © 2015 Paul Welter")]
|
||||||
|
[assembly: System.Runtime.InteropServices.Guid("348985f4-3fcf-4ec3-b207-6f09e918b297")]
|
||||||
|
[assembly: System.Runtime.InteropServices.ComVisible(false)]
|
||||||
|
[assembly: System.CLSCompliant(true)]
|
||||||
|
[assembly: System.Reflection.AssemblyConfiguration("Release")]
|
||||||
|
[assembly: System.Reflection.AssemblyVersion("1.2.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyFileVersion("1.2.0.36")]
|
||||||
|
[assembly: System.Reflection.AssemblyInformationalVersion("1.2.0.36")]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal sealed partial class ThisAssembly {
|
||||||
|
|
||||||
|
internal const string AssemblyTitle = "LoreSoft.MathExpressions";
|
||||||
|
|
||||||
|
internal const string AssemblyProduct = "LoreSoft.MathExpressions";
|
||||||
|
|
||||||
|
internal const string AssemblyDescription = "Math Expression Parser.";
|
||||||
|
|
||||||
|
internal const string AssemblyCompany = "LoreSoft";
|
||||||
|
|
||||||
|
internal const string AssemblyCopyright = "Copyright © 2015 Paul Welter";
|
||||||
|
|
||||||
|
internal const string Guid = "348985f4-3fcf-4ec3-b207-6f09e918b297";
|
||||||
|
|
||||||
|
internal const string AssemblyConfiguration = "Release";
|
||||||
|
|
||||||
|
internal const string AssemblyVersion = "1.2.0.0";
|
||||||
|
|
||||||
|
internal const string AssemblyFileVersion = "1.2.0.36";
|
||||||
|
|
||||||
|
internal const string AssemblyInformationalVersion = "1.2.0.36";
|
||||||
|
|
||||||
|
private ThisAssembly() {
|
||||||
|
}
|
||||||
|
}
|
198
Shared/LoreSoft.MathExpressions/Properties/Resources.Designer.cs
generated
Normal file
198
Shared/LoreSoft.MathExpressions/Properties/Resources.Designer.cs
generated
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LoreSoft.MathExpressions.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The IExpression.Evaluate property can not be null..
|
||||||
|
/// </summary>
|
||||||
|
internal static string EvaluatePropertyCanNotBeNull {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("EvaluatePropertyCanNotBeNull", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The function name '{0}' is already registered..
|
||||||
|
/// </summary>
|
||||||
|
internal static string FunctionNameRegistered {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("FunctionNameRegistered", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid character: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidCharacterEncountered {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidCharacterEncountered", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid convertion expression: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidConvertionExpression {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidConvertionExpression", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid function name '{0}'..
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidFunctionName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidFunctionName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid length of array..
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidLengthOfArray {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidLengthOfArray", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid math expression..
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidMathExpression {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidMathExpression", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid number format: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidNumberFormat {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidNumberFormat", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid operator: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidOperator {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidOperator", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid symbol on stack: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidSymbolOnStack {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidSymbolOnStack", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid function or variable: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidVariableEncountered {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidVariableEncountered", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid number for expression: .
|
||||||
|
/// </summary>
|
||||||
|
internal static string NotEnoughNumbers {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NotEnoughNumbers", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Unbalanced parentheses..
|
||||||
|
/// </summary>
|
||||||
|
internal static string UnbalancedParentheses {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("UnbalancedParentheses", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The variable name conflicts with function '{0}'..
|
||||||
|
/// </summary>
|
||||||
|
internal static string VariableNameConflict {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("VariableNameConflict", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The variable name can only contain letters..
|
||||||
|
/// </summary>
|
||||||
|
internal static string VariableNameContainsLetters {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("VariableNameContainsLetters", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
165
Shared/LoreSoft.MathExpressions/Properties/Resources.resx
Normal file
165
Shared/LoreSoft.MathExpressions/Properties/Resources.resx
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="InvalidLengthOfArray" xml:space="preserve">
|
||||||
|
<value>Invalid length of array.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidFunctionName" xml:space="preserve">
|
||||||
|
<value>Invalid function name '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="EvaluatePropertyCanNotBeNull" xml:space="preserve">
|
||||||
|
<value>The IExpression.Evaluate property can not be null.</value>
|
||||||
|
</data>
|
||||||
|
<data name="FunctionNameRegistered" xml:space="preserve">
|
||||||
|
<value>The function name '{0}' is already registered.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidCharacterEncountered" xml:space="preserve">
|
||||||
|
<value>Invalid character: </value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidVariableEncountered" xml:space="preserve">
|
||||||
|
<value>Invalid function or variable: </value>
|
||||||
|
</data>
|
||||||
|
<data name="UnbalancedParentheses" xml:space="preserve">
|
||||||
|
<value>Unbalanced parentheses.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidNumberFormat" xml:space="preserve">
|
||||||
|
<value>Invalid number format: </value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidSymbolOnStack" xml:space="preserve">
|
||||||
|
<value>Invalid symbol on stack: </value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidOperator" xml:space="preserve">
|
||||||
|
<value>Invalid operator: </value>
|
||||||
|
</data>
|
||||||
|
<data name="VariableNameConflict" xml:space="preserve">
|
||||||
|
<value>The variable name conflicts with function '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="VariableNameContainsLetters" xml:space="preserve">
|
||||||
|
<value>The variable name can only contain letters.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidMathExpression" xml:space="preserve">
|
||||||
|
<value>Invalid math expression.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidConvertionExpression" xml:space="preserve">
|
||||||
|
<value>Invalid convertion expression: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NotEnoughNumbers" xml:space="preserve">
|
||||||
|
<value>Invalid number for expression: </value>
|
||||||
|
</data>
|
||||||
|
</root>
|
|
@ -0,0 +1,75 @@
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Length</summary>
|
||||||
|
public enum LengthUnit
|
||||||
|
{
|
||||||
|
/// <summary>Millimeter unit (mm)</summary>
|
||||||
|
[Abbreviation("mm")]
|
||||||
|
Millimeter = 0,
|
||||||
|
/// <summary>Centimeter unit (cm)</summary>
|
||||||
|
[Abbreviation("cm")]
|
||||||
|
Centimeter = 1,
|
||||||
|
/// <summary>Meter unit (m)</summary>
|
||||||
|
[Abbreviation("m")]
|
||||||
|
Meter = 2,
|
||||||
|
/// <summary>Kilometer unit (km)</summary>
|
||||||
|
[Abbreviation("km")]
|
||||||
|
Kilometer = 3,
|
||||||
|
/// <summary>Inch unit (in)</summary>
|
||||||
|
[Abbreviation("in")]
|
||||||
|
Inch = 4,
|
||||||
|
/// <summary>Feet unit (ft)</summary>
|
||||||
|
[Abbreviation("ft")]
|
||||||
|
Feet = 5,
|
||||||
|
/// <summary>Yard unit (yd)</summary>
|
||||||
|
[Abbreviation("yd")]
|
||||||
|
Yard = 6,
|
||||||
|
/// <summary>Mile unit (mile)</summary>
|
||||||
|
[Abbreviation("mile")]
|
||||||
|
Mile = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing length convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class LengthConverter
|
||||||
|
{
|
||||||
|
// In enum order
|
||||||
|
private static readonly double[] factors = new double[]
|
||||||
|
{
|
||||||
|
0.001d, //millimeter
|
||||||
|
0.01d, //centimeter
|
||||||
|
1d, //meter
|
||||||
|
1000d, //kilometer
|
||||||
|
0.3048d/12d, //inch
|
||||||
|
0.3048d, //feet
|
||||||
|
0.9144d, //yard
|
||||||
|
0.3048d*5280d, //mile
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
LengthUnit fromUnit,
|
||||||
|
LengthUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
double fromFactor = factors[(int)fromUnit];
|
||||||
|
double toFactor = factors[(int) toUnit];
|
||||||
|
double result = fromFactor * fromValue / toFactor;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Mass</summary>
|
||||||
|
public enum MassUnit
|
||||||
|
{
|
||||||
|
/// <summary>Milligram unit (mg)</summary>
|
||||||
|
[Abbreviation("mg")]
|
||||||
|
Milligram = 0,
|
||||||
|
/// <summary>Gram unit (g)</summary>
|
||||||
|
[Abbreviation("g")]
|
||||||
|
Gram = 1,
|
||||||
|
/// <summary>Kilogram unit (kg)</summary>
|
||||||
|
[Abbreviation("kg")]
|
||||||
|
Kilogram = 2,
|
||||||
|
/// <summary>Ounce unit (oz)</summary>
|
||||||
|
[Abbreviation("oz")]
|
||||||
|
Ounce = 3,
|
||||||
|
/// <summary>Pound unit (lb)</summary>
|
||||||
|
[Abbreviation("lb")]
|
||||||
|
Pound = 4,
|
||||||
|
/// <summary>Ton unit (ton)</summary>
|
||||||
|
[Abbreviation("ton")]
|
||||||
|
Ton = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing mass convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class MassConverter
|
||||||
|
{
|
||||||
|
// In enum order
|
||||||
|
private static readonly double[] factors = new double[]
|
||||||
|
{
|
||||||
|
0.000001d, //milligram
|
||||||
|
0.001d, //gram
|
||||||
|
1d, //kilogram
|
||||||
|
0.45359237d/16d, //ounce
|
||||||
|
0.45359237d, //pound
|
||||||
|
0.45359237d*2000d, //ton [short, US]
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
MassUnit fromUnit,
|
||||||
|
MassUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
double fromFactor = factors[(int)fromUnit];
|
||||||
|
double toFactor = factors[(int)toUnit];
|
||||||
|
double result = fromFactor * fromValue / toFactor;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
using System.ComponentModel;
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Speed</summary>
|
||||||
|
public enum SpeedUnit
|
||||||
|
{
|
||||||
|
/// <summary>Meter/Second unit (m/s)</summary>
|
||||||
|
[Abbreviation("m/s")]
|
||||||
|
[Description("Meter/Second")]
|
||||||
|
MeterPerSecond = 0,
|
||||||
|
/// <summary>Kilometer/Hour unit (kph)</summary>
|
||||||
|
[Abbreviation("kph")]
|
||||||
|
[Description("Kilometer/Hour")]
|
||||||
|
KilometerPerHour = 1,
|
||||||
|
/// <summary>Foot/Second unit (ft/s)</summary>
|
||||||
|
[Abbreviation("ft/s")]
|
||||||
|
[Description("Foot/Second")]
|
||||||
|
FootPerSecond = 2,
|
||||||
|
/// <summary>Mile/Hour unit (mph)</summary>
|
||||||
|
[Abbreviation("mph")]
|
||||||
|
[Description("Mile/Hour")]
|
||||||
|
MilePerHour = 3,
|
||||||
|
/// <summary>Knot unit (knot)</summary>
|
||||||
|
[Abbreviation("knot")]
|
||||||
|
Knot = 4,
|
||||||
|
/// <summary>Mach unit (mach)</summary>
|
||||||
|
[Abbreviation("mach")]
|
||||||
|
Mach = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing speed convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class SpeedConverter
|
||||||
|
{
|
||||||
|
// In enum order
|
||||||
|
private static readonly double[] factors = new double[]
|
||||||
|
{
|
||||||
|
1d, //meter/second
|
||||||
|
1000d/3600d, //kilometer/hour
|
||||||
|
0.3048d, //foot/second
|
||||||
|
(0.3048d*5280d)/3600d, //mile/hour (mph)
|
||||||
|
1852d/3600d, //knot
|
||||||
|
340.29d, //mach
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
SpeedUnit fromUnit,
|
||||||
|
SpeedUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
double fromFactor = factors[(int)fromUnit];
|
||||||
|
double toFactor = factors[(int)toUnit];
|
||||||
|
double result = fromFactor * fromValue / toFactor;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Temperature</summary>
|
||||||
|
public enum TemperatureUnit
|
||||||
|
{
|
||||||
|
/// <summary>Degrees Celsius unit (c)</summary>
|
||||||
|
[Abbreviation("c")]
|
||||||
|
Celsius = 0,
|
||||||
|
/// <summary>Degrees Fahrenheit unit (f)</summary>
|
||||||
|
[Abbreviation("f")]
|
||||||
|
Fahrenheit = 1,
|
||||||
|
/// <summary>Degrees Kelvin unit (k)</summary>
|
||||||
|
[Abbreviation("k")]
|
||||||
|
Kelvin = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing temperature convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class TemperatureConverter
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
TemperatureUnit fromUnit,
|
||||||
|
TemperatureUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
double result = 0;
|
||||||
|
|
||||||
|
if (fromUnit == TemperatureUnit.Celsius)
|
||||||
|
{
|
||||||
|
if (toUnit == TemperatureUnit.Kelvin)
|
||||||
|
result = fromValue + 273.15d;
|
||||||
|
else if (toUnit == TemperatureUnit.Fahrenheit)
|
||||||
|
//(9/5 * C) + 32 = F
|
||||||
|
result = (9.0d/5.0d*fromValue) + 32d;
|
||||||
|
}
|
||||||
|
else if (fromUnit == TemperatureUnit.Kelvin)
|
||||||
|
{
|
||||||
|
if (toUnit == TemperatureUnit.Celsius)
|
||||||
|
result = fromValue - 273.15d;
|
||||||
|
else if (toUnit == TemperatureUnit.Fahrenheit)
|
||||||
|
result = 5.0d/9.0d*((fromValue - 273.15d) + 32d);
|
||||||
|
}
|
||||||
|
else if (fromUnit == TemperatureUnit.Fahrenheit)
|
||||||
|
{
|
||||||
|
if (toUnit == TemperatureUnit.Celsius)
|
||||||
|
//(F - 32) * 5/9 = C
|
||||||
|
result = 5.0d/9.0d*(fromValue - 32d);
|
||||||
|
else if (toUnit == TemperatureUnit.Kelvin)
|
||||||
|
result = (5.0d/9.0d*(fromValue - 32d)) + 273.15;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
using System;
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Time</summary>
|
||||||
|
public enum TimeUnit
|
||||||
|
{
|
||||||
|
/// <summary>Millisecond unit (ms)</summary>
|
||||||
|
[Abbreviation("ms")]
|
||||||
|
Millisecond = 0,
|
||||||
|
/// <summary>Second unit (sec)</summary>
|
||||||
|
[Abbreviation("sec")]
|
||||||
|
Second = 1,
|
||||||
|
/// <summary>Minute unit (min)</summary>
|
||||||
|
[Abbreviation("min")]
|
||||||
|
Minute = 2,
|
||||||
|
/// <summary>Hour unit (hr)</summary>
|
||||||
|
[Abbreviation("hr")]
|
||||||
|
Hour = 3,
|
||||||
|
/// <summary>Day unit (d)</summary>
|
||||||
|
[Abbreviation("d")]
|
||||||
|
Day = 4,
|
||||||
|
/// <summary>Week unit (wk)</summary>
|
||||||
|
[Abbreviation("wk")]
|
||||||
|
Week = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing time convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class TimeConverter
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
TimeUnit fromUnit,
|
||||||
|
TimeUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
TimeSpan span;
|
||||||
|
switch (fromUnit)
|
||||||
|
{
|
||||||
|
case TimeUnit.Millisecond:
|
||||||
|
span = TimeSpan.FromMilliseconds(fromValue);
|
||||||
|
break;
|
||||||
|
case TimeUnit.Second:
|
||||||
|
span = TimeSpan.FromSeconds(fromValue);
|
||||||
|
break;
|
||||||
|
case TimeUnit.Minute:
|
||||||
|
span = TimeSpan.FromMinutes(fromValue);
|
||||||
|
break;
|
||||||
|
case TimeUnit.Hour:
|
||||||
|
span = TimeSpan.FromHours(fromValue);
|
||||||
|
break;
|
||||||
|
case TimeUnit.Day:
|
||||||
|
span = TimeSpan.FromDays(fromValue);
|
||||||
|
break;
|
||||||
|
case TimeUnit.Week:
|
||||||
|
span = TimeSpan.FromDays(fromValue * 7d);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException("fromUnit");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (toUnit)
|
||||||
|
{
|
||||||
|
case TimeUnit.Millisecond:
|
||||||
|
return span.TotalMilliseconds;
|
||||||
|
case TimeUnit.Second:
|
||||||
|
return span.TotalSeconds;
|
||||||
|
case TimeUnit.Minute:
|
||||||
|
return span.TotalMinutes;
|
||||||
|
case TimeUnit.Hour:
|
||||||
|
return span.TotalHours;
|
||||||
|
case TimeUnit.Day:
|
||||||
|
return span.TotalDays;
|
||||||
|
case TimeUnit.Week:
|
||||||
|
return span.TotalDays / 7d;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException("toUnit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
Shared/LoreSoft.MathExpressions/UnitConversion/UnitType.cs
Normal file
19
Shared/LoreSoft.MathExpressions/UnitConversion/UnitType.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
///<summary>The unit types available for conversion.</summary>
|
||||||
|
public enum UnitType
|
||||||
|
{
|
||||||
|
///<summary>Length unit types.</summary>
|
||||||
|
Length,
|
||||||
|
///<summary>Mass unit types.</summary>
|
||||||
|
Mass,
|
||||||
|
///<summary>Speed unit types.</summary>
|
||||||
|
Speed,
|
||||||
|
///<summary>Temperature unit types.</summary>
|
||||||
|
Temperature,
|
||||||
|
///<summary>Time unit types.</summary>
|
||||||
|
Time,
|
||||||
|
///<summary>Volume unit types.</summary>
|
||||||
|
Volume
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using LoreSoft.MathExpressions.Metadata;
|
||||||
|
using System.ComponentModel;
|
||||||
|
namespace LoreSoft.MathExpressions.UnitConversion
|
||||||
|
{
|
||||||
|
/// <summary>Units for Liquid Volume</summary>
|
||||||
|
public enum VolumeUnit
|
||||||
|
{
|
||||||
|
/// <summary>Milliliter unit (ml)</summary>
|
||||||
|
[Abbreviation("ml")]
|
||||||
|
Milliliter = 0,
|
||||||
|
/// <summary>Liter unit (l)</summary>
|
||||||
|
[Abbreviation("l")]
|
||||||
|
Liter = 1,
|
||||||
|
/// <summary>Kiloliter unit (kl)</summary>
|
||||||
|
[Abbreviation("kl")]
|
||||||
|
Kiloliter = 2,
|
||||||
|
/// <summary>Fluid ounce unit (oz)</summary>
|
||||||
|
[Abbreviation("oz")]
|
||||||
|
[Description("Fluid Ounce")]
|
||||||
|
FluidOunce = 3,
|
||||||
|
/// <summary>Cup unit (cup)</summary>
|
||||||
|
[Abbreviation("cup")]
|
||||||
|
Cup = 4,
|
||||||
|
/// <summary>Pint unit (pt)</summary>
|
||||||
|
[Abbreviation("pt")]
|
||||||
|
Pint = 5,
|
||||||
|
/// <summary>Quart unit (qt)</summary>
|
||||||
|
[Abbreviation("qt")]
|
||||||
|
Quart = 6,
|
||||||
|
/// <summary>Gallon unit (gal)</summary>
|
||||||
|
[Abbreviation("gal")]
|
||||||
|
Gallon = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing liquid volume convertion.
|
||||||
|
/// </summary>
|
||||||
|
public static class VolumeConverter
|
||||||
|
{
|
||||||
|
// In enum order
|
||||||
|
private static readonly double[] factors = new double[]
|
||||||
|
{
|
||||||
|
0.000001d, //milliliter
|
||||||
|
0.001d, //liter
|
||||||
|
1d, //kiloliter
|
||||||
|
0.0037854118d/128d, //ounce [US, liquid]
|
||||||
|
0.0037854118d/16d, //cup [US]
|
||||||
|
0.0037854118d/8d, //pint [US, liquid]
|
||||||
|
0.0037854118d/4d, //quart [US, liquid]
|
||||||
|
0.0037854118d, //gallon [US, liquid]
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified from unit to the specified unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromUnit">Covert from unit.</param>
|
||||||
|
/// <param name="toUnit">Covert to unit.</param>
|
||||||
|
/// <param name="fromValue">Covert from value.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static double Convert(
|
||||||
|
VolumeUnit fromUnit,
|
||||||
|
VolumeUnit toUnit,
|
||||||
|
double fromValue)
|
||||||
|
{
|
||||||
|
if (fromUnit == toUnit)
|
||||||
|
return fromValue;
|
||||||
|
|
||||||
|
double fromFactor = factors[(int)fromUnit];
|
||||||
|
double toFactor = factors[(int)toUnit];
|
||||||
|
double result = fromFactor * fromValue / toFactor;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
Shared/LoreSoft.MathExpressions/VariableDictionary.cs
Normal file
82
Shared/LoreSoft.MathExpressions/VariableDictionary.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LoreSoft.MathExpressions.Properties;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Security.Permissions;
|
||||||
|
|
||||||
|
namespace LoreSoft.MathExpressions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class representing a collection of variable names and values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Variable names can only contain letters, numbers and symbols are not allowed.
|
||||||
|
/// </remarks>
|
||||||
|
[Serializable]
|
||||||
|
public class VariableDictionary : Dictionary<string, double>
|
||||||
|
{
|
||||||
|
private MathEvaluator _evaluator;
|
||||||
|
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="VariableDictionary"/> class.</summary>
|
||||||
|
/// <param name="evaluator">The evaluator.</param>
|
||||||
|
internal VariableDictionary(MathEvaluator evaluator)
|
||||||
|
: base(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
_evaluator = evaluator;
|
||||||
|
base.Add(MathEvaluator.AnswerVariable, 0);
|
||||||
|
base.Add("pi", Math.PI);
|
||||||
|
base.Add("e", Math.E);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VariableDictionary"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object containing the information required to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
|
||||||
|
/// <param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure containing the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
|
||||||
|
protected VariableDictionary(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>Adds the specified variable and value to the dictionary.</summary>
|
||||||
|
/// <param name="name">The name of the variable to add.</param>
|
||||||
|
/// <param name="value">The value of the variable.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">When variable name is null.</exception>
|
||||||
|
/// <exception cref="ArgumentException">When variable name contains non-letters or the name exists in the <see cref="MathEvaluator.Functions"/> list.</exception>
|
||||||
|
/// <seealso cref="MathEvaluator"/>
|
||||||
|
/// <seealso cref="MathEvaluator.Variables"/>
|
||||||
|
/// <seealso cref="MathEvaluator.Functions"/>
|
||||||
|
public new void Add(string name, double value)
|
||||||
|
{
|
||||||
|
Validate(name);
|
||||||
|
base.Add(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Validate(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
throw new ArgumentNullException("name");
|
||||||
|
|
||||||
|
if (_evaluator.IsFunction(name))
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Resources.VariableNameConflict, name), "name");
|
||||||
|
|
||||||
|
for (int i = 0; i < name.Length; i++)
|
||||||
|
if (!char.IsLetter(name[i]))
|
||||||
|
throw new ArgumentException(Resources.VariableNameContainsLetters, "name");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the <see cref="T:System.Runtime.Serialization.ISerializable"/> interface and returns the data needed to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object that contains the information required to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/> instance.</param>
|
||||||
|
/// <param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure that contains the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Generic.Dictionary`2"/> instance.</param>
|
||||||
|
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
|
||||||
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
base.GetObjectData(info, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
using Shared.Models;
|
using SteamShared.Models;
|
||||||
using Shared.ZatVdfParser;
|
using SteamShared.ZatVdfParser;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -9,7 +9,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared
|
namespace SteamShared
|
||||||
{
|
{
|
||||||
public class CsgoHelper
|
public class CsgoHelper
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Drawing.Imaging;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Shared
|
namespace SteamShared
|
||||||
{
|
{
|
||||||
#region DDSImage Class
|
#region DDSImage Class
|
||||||
public class DDSImage : IDisposable
|
public class DDSImage : IDisposable
|
||||||
|
|
|
@ -7,7 +7,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace Shared
|
namespace SteamShared
|
||||||
{
|
{
|
||||||
public static class Globals
|
public static class Globals
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
internal class BSPHeader
|
internal class BSPHeader
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
internal class BSPLump
|
internal class BSPLump
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class CsgoMap
|
public class CsgoMap
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class CsgoWeapon
|
public class CsgoWeapon
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class MapCustomOverwriteMapping
|
public class MapCustomOverwriteMapping
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class MapPoint
|
public class MapPoint
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavApproachSpot
|
public class NavApproachSpot
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavArea
|
public class NavArea
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavAreaBind
|
public class NavAreaBind
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavConnectionData
|
public class NavConnectionData
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavEncounterPath
|
public class NavEncounterPath
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavEncounterSpot
|
public class NavEncounterSpot
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavHeader
|
public class NavHeader
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum HidingSpotAttribute
|
public enum HidingSpotAttribute
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavLadder
|
public class NavLadder
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavLadderIDSequence
|
public class NavLadderIDSequence
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class NavMesh
|
public class NavMesh
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class PlayerSpawn
|
public class PlayerSpawn
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class Settings
|
public class Settings
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class SteamGame
|
public class SteamGame
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class SteamLibrary
|
public class SteamLibrary
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Shared.Models
|
namespace SteamShared.Models
|
||||||
{
|
{
|
||||||
public class Vector3
|
public class Vector3
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,9 +4,9 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Shared.Models;
|
using SteamShared.Models;
|
||||||
|
|
||||||
namespace Shared
|
namespace SteamShared
|
||||||
{
|
{
|
||||||
public enum NavDisplayModes { None, Wireframe, Filled }
|
public enum NavDisplayModes { None, Wireframe, Filled }
|
||||||
|
|
||||||
|
|
12
Shared/SteamHelpers/SteamHelpers/SourceCFG/SourceCFG.cs
Normal file
12
Shared/SteamHelpers/SteamHelpers/SourceCFG/SourceCFG.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SteamShared
|
||||||
|
{
|
||||||
|
public class SourceCFG
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Shared.ZatVdfParser;
|
using SteamShared.ZatVdfParser;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Shared.Models;
|
using SteamShared.Models;
|
||||||
|
|
||||||
namespace Shared
|
namespace SteamShared
|
||||||
{
|
{
|
||||||
public class SteamHelper
|
public class SteamHelper
|
||||||
{
|
{
|
||||||
|
@ -75,7 +75,7 @@ namespace Shared
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forcefully tries to update the <see cref="SteamPath"/> property with the current Steam path, even if it should be already set.
|
/// Forcefully tries to update the <see cref="SteamLibraries"/> property with the current Steam libraries, even if they should be already set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateSteamLibraries()
|
public void UpdateSteamLibraries()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
|
<RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Shared.ZatVdfParser
|
namespace SteamShared.ZatVdfParser
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class was copied from <see cref="https://stackoverflow.com/questions/39065573/reading-values-from-an-acf-manifest-file">here</see> as a backup, in case <see cref="VDFFile"/> didn't work well enough.
|
/// This class was copied from <see cref="https://stackoverflow.com/questions/39065573/reading-values-from-an-acf-manifest-file">here</see> as a backup, in case <see cref="VDFFile"/> didn't work well enough.
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Shared.ZatVdfParser
|
namespace SteamShared.ZatVdfParser
|
||||||
{
|
{
|
||||||
public class Element
|
public class Element
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Shared.ZatVdfParser
|
namespace SteamShared.ZatVdfParser
|
||||||
{
|
{
|
||||||
public class VDFFile
|
public class VDFFile
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ namespace Shared.ZatVdfParser
|
||||||
string? line = null;
|
string? line = null;
|
||||||
while ((line = reader.ReadLine()) != null)
|
while ((line = reader.ReadLine()) != null)
|
||||||
{
|
{
|
||||||
if (line.StartsWith("\0"))
|
if (line.StartsWith("\0", StringComparison.Ordinal))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
line = line.Trim();
|
line = line.Trim();
|
||||||
|
|
Loading…
Add table
Reference in a new issue