diff --git a/!Docs/Related Files/FileGrayscaleEffect.fx b/!Docs/Related Files/FileGrayscaleEffect.fx
deleted file mode 100644
index 3a6d53b..0000000
--- a/!Docs/Related Files/FileGrayscaleEffect.fx
+++ /dev/null
@@ -1,8 +0,0 @@
-sampler2D implicitInput : register(s0);
-
-float4 main(float2 uv : TEXCOORD) : COLOR
-{
- float4 color = tex2D(implicitInput, uv);
- color.rgb = dot(color.rgb, float3(.3, .59, .11));
- return color;
-}
\ No newline at end of file
diff --git a/!Docs/Related Files/GeoLite2.url b/!Docs/Related Files/GeoLite2.url
deleted file mode 100644
index 6b3156a..0000000
--- a/!Docs/Related Files/GeoLite2.url
+++ /dev/null
@@ -1,5 +0,0 @@
-[{000214A0-0000-0000-C000-000000000046}]
-Prop3=19,11
-[InternetShortcut]
-IDList=
-URL=https://dev.maxmind.com/geoip/geoip2/geolite2/
diff --git a/.gitignore b/.gitignore
index be2577e..3698cbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,5 +16,4 @@ TestResults/
*~*.xlsx
*~*.docx
-$Build/
-$Help/
\ No newline at end of file
+$Build/
\ No newline at end of file
diff --git a/.nuget/Icons/namespace.png b/.nuget/Icons/namespace.png
new file mode 100644
index 0000000..a47634d
Binary files /dev/null and b/.nuget/Icons/namespace.png differ
diff --git a/.nuget/PackageIcon.pdn b/.nuget/PackageIcon.pdn
new file mode 100644
index 0000000..347df60
Binary files /dev/null and b/.nuget/PackageIcon.pdn differ
diff --git a/.nuget/PackageIcon.png b/.nuget/PackageIcon.png
new file mode 100644
index 0000000..ae5749a
Binary files /dev/null and b/.nuget/PackageIcon.png differ
diff --git a/Build.GeoIP/App.config b/Build.GeoIP/App.config
deleted file mode 100644
index e0767ee..0000000
--- a/Build.GeoIP/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Build.GeoIP/Build.GeoIP.csproj b/Build.GeoIP/Build.GeoIP.csproj
deleted file mode 100644
index a328bdd..0000000
--- a/Build.GeoIP/Build.GeoIP.csproj
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {5EA1BD73-E9C2-453C-A76A-691E2F5096BC}
- Exe
- Build.GeoIP
- Build.GeoIP
- v4.6.1
- 512
- true
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- latest
- false
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- latest
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {a3e69e94-20b1-4e18-b3e3-15e56a7f0288}
- BytecodeApi.FileFormats
-
-
- {ea00307e-ce27-4a53-b7db-052181e1c24c}
- BytecodeApi
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Build.GeoIP/CsvData.cs b/Build.GeoIP/CsvData.cs
deleted file mode 100644
index 27bfa15..0000000
--- a/Build.GeoIP/CsvData.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using BytecodeApi.Data;
-using BytecodeApi.IO;
-using BytecodeApi.IO.Http;
-using System.IO;
-using System.Linq;
-
-namespace Build.GeoIP
-{
- public class CsvData
- {
- public byte[] Country;
- public byte[] Range;
- public byte[] Range6;
- public byte[] Asn;
- public byte[] Asn6;
- public byte[] City;
- public byte[] CityRange;
- public byte[] CityRange6;
-
- public static CsvData ImportFromCloud()
- {
- CsvData csvData = new CsvData();
-
- BlobTree countryBlob = ZipCompression.Decompress(HttpClient.Default.CreateGetRequest("https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip").ReadBytes());
- BlobTree asnBlob = ZipCompression.Decompress(HttpClient.Default.CreateGetRequest("https://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN-CSV.zip").ReadBytes());
- BlobTree cityBlob = ZipCompression.Decompress(HttpClient.Default.CreateGetRequest("https://geolite.maxmind.com/download/geoip/database/GeoLite2-City-CSV.zip").ReadBytes());
-
- csvData.Country = FindBlob(countryBlob, "GeoLite2-Country-Locations-en.csv");
- csvData.Range = FindBlob(countryBlob, "GeoLite2-Country-Blocks-IPv4.csv");
- csvData.Range6 = FindBlob(countryBlob, "GeoLite2-Country-Blocks-IPv6.csv");
- csvData.Asn = FindBlob(asnBlob, "GeoLite2-ASN-Blocks-IPv4.csv");
- csvData.Asn6 = FindBlob(asnBlob, "GeoLite2-ASN-Blocks-IPv6.csv");
- csvData.City = FindBlob(cityBlob, "GeoLite2-City-Locations-en.csv");
- csvData.CityRange = FindBlob(cityBlob, "GeoLite2-City-Blocks-IPv4.csv");
- csvData.CityRange6 = FindBlob(cityBlob, "GeoLite2-City-Blocks-IPv6.csv");
-
- return csvData;
-
- byte[] FindBlob(BlobTree blobs, string name)
- {
- return blobs.Root.Nodes.First().Blobs[name].Content;
- }
- }
- public static CsvData ImportFromFiles()
- {
- const string path = @"A:\Downloads";
- CsvData csvData = new CsvData();
-
- csvData.Country = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-Country-CSV\GeoLite2-Country-Locations-en.csv"));
- csvData.Range = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-Country-CSV\GeoLite2-Country-Blocks-IPv4.csv"));
- csvData.Range6 = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-Country-CSV\GeoLite2-Country-Blocks-IPv6.csv"));
- csvData.Asn = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-ASN-CSV\GeoLite2-ASN-Blocks-IPv4.csv"));
- csvData.Asn6 = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-ASN-CSV\GeoLite2-ASN-Blocks-IPv6.csv"));
- csvData.City = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-City-CSV\GeoLite2-City-Locations-en.csv"));
- csvData.CityRange = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-City-CSV\GeoLite2-City-Blocks-IPv4.csv"));
- csvData.CityRange6 = File.ReadAllBytes(Path.Combine(path, @"GeoLite2-City-CSV\GeoLite2-City-Blocks-IPv6.csv"));
-
- return csvData;
- }
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/Asn.cs b/Build.GeoIP/Data/Asn.cs
deleted file mode 100644
index 401eebb..0000000
--- a/Build.GeoIP/Data/Asn.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class Asn
- {
- public int Number;
- public string Organization;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/AsnRange.cs b/Build.GeoIP/Data/AsnRange.cs
deleted file mode 100644
index 880ca97..0000000
--- a/Build.GeoIP/Data/AsnRange.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class AsnRange
- {
- public int Asn;
- public uint From;
- public uint To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/AsnRange6.cs b/Build.GeoIP/Data/AsnRange6.cs
deleted file mode 100644
index 07be9e5..0000000
--- a/Build.GeoIP/Data/AsnRange6.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class AsnRange6
- {
- public int Asn;
- public byte[] From;
- public byte[] To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/City.cs b/Build.GeoIP/Data/City.cs
deleted file mode 100644
index ef0ef2c..0000000
--- a/Build.GeoIP/Data/City.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class City
- {
- public int ID;
- public byte CountryIndex;
- public string Name;
- public string Subdivision1Name;
- public string Subdivision1IsoCode;
- public string Subdivision2Name;
- public string Subdivision2IsoCode;
- public string TimeZone;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/CityRange.cs b/Build.GeoIP/Data/CityRange.cs
deleted file mode 100644
index 8ff5324..0000000
--- a/Build.GeoIP/Data/CityRange.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class CityRange
- {
- public int CityIndex;
- public string PostalCode;
- public float Latitude;
- public float Longitude;
- public short AccuracyRadius;
- public uint From;
- public uint To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/CityRange6.cs b/Build.GeoIP/Data/CityRange6.cs
deleted file mode 100644
index e5576f0..0000000
--- a/Build.GeoIP/Data/CityRange6.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class CityRange6
- {
- public int CityIndex;
- public string PostalCode;
- public float Latitude;
- public float Longitude;
- public short AccuracyRadius;
- public byte[] From;
- public byte[] To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/Country.cs b/Build.GeoIP/Data/Country.cs
deleted file mode 100644
index a189918..0000000
--- a/Build.GeoIP/Data/Country.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class Country
- {
- public int ID;
- public string Name;
- public string IsoCode;
- public string Continent;
- public string ContinentIsoCode;
- public bool EuropeanUnion;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/IPRange.cs b/Build.GeoIP/Data/IPRange.cs
deleted file mode 100644
index 61c0df4..0000000
--- a/Build.GeoIP/Data/IPRange.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class IPRange
- {
- public byte CountryIndex;
- public uint From;
- public uint To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Data/IPRange6.cs b/Build.GeoIP/Data/IPRange6.cs
deleted file mode 100644
index 46e1947..0000000
--- a/Build.GeoIP/Data/IPRange6.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Build.GeoIP.Data
-{
- public sealed class IPRange6
- {
- public byte CountryIndex;
- public byte[] From;
- public byte[] To;
- }
-}
\ No newline at end of file
diff --git a/Build.GeoIP/Program.cs b/Build.GeoIP/Program.cs
deleted file mode 100644
index 4336cf1..0000000
--- a/Build.GeoIP/Program.cs
+++ /dev/null
@@ -1,409 +0,0 @@
-using Build.GeoIP.Data;
-using BytecodeApi;
-using BytecodeApi.Extensions;
-using BytecodeApi.FileFormats.Csv;
-using BytecodeApi.IO;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-
-namespace Build.GeoIP
-{
- public static class Program
- {
- private static CsvData Csv;
- private static Country[] Countries;
- private static IPRange[] IPRanges;
- private static IPRange6[] IPRanges6;
- private static List Asns;
- private static AsnRange[] AsnRanges;
- private static AsnRange6[] AsnRanges6;
- private static City[] Cities;
- private static CityRange[] CityRanges;
- private static CityRange6[] CityRanges6;
-
- public static void Main()
- {
- Console.WriteLine("Importing CSV data");
- Csv = CsvData.ImportFromCloud();
- //Csv = CsvData.ImportFromFiles();
-
- Console.WriteLine("Creating GeoIP.db");
- ParseCountries();
- Console.WriteLine("Writing GeoIP.db");
- WriteCountries();
- Console.WriteLine("Creating GeoIP.ASN.db");
- ParseAsn();
- Console.WriteLine("Writing GeoIP.ASN.db");
- WriteAsn();
- Console.WriteLine("Creating GeoIP.City.db");
- ParseCities();
- Console.WriteLine("Writing GeoIP.City.db");
- WriteCities();
-
- Console.WriteLine("Done.");
- }
-
- private static void ParseCountries()
- {
- Countries = CsvFile
- .EnumerateBinary(Csv.Country, ",", true, false, Encoding.UTF8)
- .Where(row => row[5].Value != "")
- .Select(row =>
- {
- string isoCode = row[4].Value.ToUpper();
- string continentIsoCode = row[2].Value.ToUpper();
- if (isoCode.Length != 2 || isoCode[0] > byte.MaxValue || isoCode[1] > byte.MaxValue) throw new FormatException("Country ISO code must be composed of two ANSI characters.");
- if (continentIsoCode.Length != 2 || continentIsoCode[0] > byte.MaxValue || continentIsoCode[1] > byte.MaxValue) throw new FormatException("Country continent code must be composed of two ANSI characters.");
-
- return new Country
- {
- ID = row[0].Int32Value.Value,
- Name = row[5].Value,
- IsoCode = isoCode,
- Continent = row[3].Value,
- ContinentIsoCode = continentIsoCode,
- EuropeanUnion = row[6].Int32Value.Value == 1
- };
- })
- .OrderBy(country => country.Name, StringComparer.OrdinalIgnoreCase)
- .ToArray();
-
- if (Countries.Length > 255) throw new OverflowException("The limit of 255 countries has been exceeded.");
-
- IPRanges = CsvFile
- .EnumerateBinary(Csv.Range, ",", true, false, Encoding.UTF8)
- .Where(row => row[1].Value != "")
- .Select(row => new
- {
- Range = row[0].Value,
- CountryIndex = GetCountryIndex(row[1].Int32Value.Value)
- })
- .Where(range => range.CountryIndex != null)
- .Select(range =>
- {
- ConvertCidr(range.Range, out uint from, out uint to);
-
- return new IPRange
- {
- CountryIndex = range.CountryIndex.Value,
- From = from,
- To = to
- };
- })
- .ToArray();
-
- IPRanges6 = CsvFile
- .EnumerateBinary(Csv.Range6, ",", true, false, Encoding.UTF8)
- .Where(row => row[1].Value != "")
- .Select(row => new
- {
- Range = row[0].Value,
- CountryIndex = GetCountryIndex(row[1].Int32Value.Value)
- })
- .Where(range => range.CountryIndex != null)
- .Select(range =>
- {
- ConvertCidr(range.Range, out byte[] from, out byte[] to);
-
- return new IPRange6
- {
- CountryIndex = range.CountryIndex.Value,
- From = from,
- To = to
- };
- })
- .ToArray();
-
- byte? GetCountryIndex(int id)
- {
- int index = Countries.IndexOf(country => country.ID == id);
- return index != -1 ? (byte)index : (byte?)null;
- }
- }
- private static void ParseAsn()
- {
- Asns = new List(ushort.MaxValue);
- List asnNumbers = new List(ushort.MaxValue);
-
- AsnRanges = CsvFile
- .EnumerateBinary(Csv.Asn, ",", true, false, Encoding.UTF8)
- .Select(row =>
- {
- int number = row[1].Int32Value.Value;
-
- AddAsn(number, row[2].Value);
- ConvertCidr(row[0].Value, out uint from, out uint to);
-
- return new AsnRange
- {
- Asn = number,
- From = from,
- To = to
- };
- })
- .ToArray();
-
- AsnRanges6 = CsvFile
- .EnumerateBinary(Csv.Asn6, ",", true, false, Encoding.UTF8)
- .Select(row =>
- {
- int number = row[1].Int32Value.Value;
-
- AddAsn(number, row[2].Value);
- ConvertCidr(row[0].Value, out byte[] from, out byte[] to);
-
- return new AsnRange6
- {
- Asn = number,
- From = from,
- To = to
- };
- })
- .ToArray();
-
- Asns = Asns.OrderBy(asn => asn.Organization, StringComparer.OrdinalIgnoreCase).ToList();
-
- void AddAsn(int number, string organization)
- {
- if (!asnNumbers.Contains(number))
- {
- asnNumbers.Add(number);
- Asns.Add(new Asn
- {
- Number = number,
- Organization = organization
- });
- }
- }
- }
- private static void ParseCities()
- {
- Cities = CsvFile
- .EnumerateBinary(Csv.City, ",", true, false, Encoding.UTF8)
- .Select(row => new City
- {
- ID = row[0].Int32Value.Value,
- CountryIndex = GetCountryIndex(row[4].Value),
- Name = row[10].Value,
- Subdivision1Name = row[7].Value,
- Subdivision1IsoCode = row[6].Value,
- Subdivision2Name = row[9].Value,
- Subdivision2IsoCode = row[8].Value,
- TimeZone = row[12].Value
- })
- .OrderBy(city => city.Name, StringComparer.OrdinalIgnoreCase)
- .ToArray();
-
- int[] cityIndices = Create.Array(Cities.Max(city => city.ID) + 1, -1);
- for (int i = 0; i < Cities.Length; i++) cityIndices[Cities[i].ID] = i;
-
- CityRanges = CsvFile
- .EnumerateBinary(Csv.CityRange, ",", true, false, Encoding.UTF8)
- .Where(row => row[1].Value != "")
- .Select(row =>
- {
- ConvertCidr(row[0].Value, out uint from, out uint to);
-
- return new CityRange
- {
- CityIndex = GetCityIndex(row[1].Int32Value.Value),
- PostalCode = row[6].Value,
- Latitude = row[7].Value.ToSingleOrNull().Value,
- Longitude = row[8].Value.ToSingleOrNull().Value,
- AccuracyRadius = Convert.ToInt16(row[9].Int32Value.Value),
- From = from,
- To = to
- };
- })
- .ToArray();
-
- CityRanges6 = CsvFile
- .EnumerateBinary(Csv.CityRange6, ",", true, false, Encoding.UTF8)
- .Where(row => row[1].Value != "")
- .Select(row =>
- {
- ConvertCidr(row[0].Value, out byte[] from, out byte[] to);
-
- return new CityRange6
- {
- CityIndex = GetCityIndex(row[1].Int32Value.Value),
- PostalCode = row[6].Value,
- Latitude = row[7].Value.ToSingleOrNull().Value,
- Longitude = row[8].Value.ToSingleOrNull().Value,
- AccuracyRadius = Convert.ToInt16(row[9].Int32Value.Value),
- From = from,
- To = to
- };
- })
- .ToArray();
-
- byte GetCountryIndex(string isoCode)
- {
- int index = Countries.IndexOf(country => country.IsoCode == isoCode);
- return index != -1 ? (byte)index : byte.MaxValue;
- }
- int GetCityIndex(int id)
- {
- int index = cityIndices[id];
- return index != -1 ? index : throw new FormatException("City ID '" + id + "' not found.");
- }
- }
- private static void WriteCountries()
- {
- using MemoryStream memoryStream = new MemoryStream();
-
- using (BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.UTF8))
- {
- writer.Write(DateTime.Now.Ticks);
- writer.Write((byte)Countries.Length);
- writer.Write(IPRanges.Length);
- writer.Write(IPRanges6.Length);
-
- foreach (Country country in Countries)
- {
- writer.Write(country.Name);
- writer.Write((byte)country.IsoCode[0]);
- writer.Write((byte)country.IsoCode[1]);
- writer.Write(country.Continent);
- writer.Write((byte)country.ContinentIsoCode[0]);
- writer.Write((byte)country.ContinentIsoCode[1]);
- writer.Write(country.EuropeanUnion);
- }
- foreach (IPRange range in IPRanges)
- {
- writer.Write(range.CountryIndex);
- writer.Write(range.From);
- writer.Write(range.To);
- }
- foreach (IPRange6 range in IPRanges6)
- {
- writer.Write(range.CountryIndex);
- writer.Write(range.From);
- writer.Write(range.To);
- }
- }
-
- File.WriteAllBytes(@"..\..\..\BytecodeApi.GeoIP\Resources\GeoIP.db", Compression.Compress(memoryStream.ToArray()));
- }
- private static void WriteAsn()
- {
- int[] asnIndices = Create.Array(Asns.Max(asn => asn.Number) + 1, -1);
- for (int i = 0; i < Asns.Count; i++) asnIndices[Asns[i].Number] = i;
-
- using MemoryStream memoryStream = new MemoryStream();
-
- using (BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.UTF8))
- {
- writer.Write(DateTime.Now.Ticks);
- writer.Write(Asns.Count);
- writer.Write(AsnRanges.Length);
- writer.Write(AsnRanges6.Length);
-
- foreach (Asn asn in Asns)
- {
- writer.Write(asn.Number);
- writer.Write(asn.Organization);
- }
- foreach (AsnRange range in AsnRanges)
- {
- writer.Write(GetAsnIndex(range.Asn));
- writer.Write(range.From);
- writer.Write(range.To);
- }
- foreach (AsnRange6 range in AsnRanges6)
- {
- writer.Write(GetAsnIndex(range.Asn));
- writer.Write(range.From);
- writer.Write(range.To);
- }
- }
-
- File.WriteAllBytes(@"..\..\..\BytecodeApi.GeoIP.ASN\Resources\GeoIP.ASN.db", Compression.Compress(memoryStream.ToArray()));
-
- int GetAsnIndex(int number)
- {
- int index = asnIndices[number];
- return index != -1 ? index : throw new FormatException("ASN ID '" + number + "' not found.");
- }
- }
- private static void WriteCities()
- {
- using MemoryStream memoryStream = new MemoryStream();
-
- using (BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.UTF8))
- {
- writer.Write(DateTime.Now.Ticks);
- writer.Write(Cities.Length);
- writer.Write(CityRanges.Length);
- writer.Write(CityRanges6.Length);
-
- foreach (City city in Cities)
- {
- writer.Write(city.CountryIndex);
- writer.Write(city.Name);
- writer.Write(city.Subdivision1Name);
- writer.Write(city.Subdivision1IsoCode);
- writer.Write(city.Subdivision2Name);
- writer.Write(city.Subdivision2IsoCode);
- writer.Write(city.TimeZone);
- }
- foreach (CityRange range in CityRanges)
- {
- writer.Write(range.CityIndex);
- writer.Write(range.PostalCode);
- writer.Write(range.Latitude);
- writer.Write(range.Longitude);
- writer.Write(range.AccuracyRadius);
- writer.Write(range.From);
- writer.Write(range.To);
- }
- foreach (CityRange6 range in CityRanges6)
- {
- writer.Write(range.CityIndex);
- writer.Write(range.PostalCode);
- writer.Write(range.Latitude);
- writer.Write(range.Longitude);
- writer.Write(range.AccuracyRadius);
- writer.Write(range.From);
- writer.Write(range.To);
- }
- }
-
- File.WriteAllBytes(@"..\..\..\BytecodeApi.GeoIP.City\Resources\GeoIP.City.db", Compression.Compress(memoryStream.ToArray()));
- }
-
- private static void ConvertCidr(string cidr, out uint from, out uint to)
- {
- uint[] parts = cidr.Split('.', '/').Select(part => Convert.ToUInt32(part)).ToArray();
- uint ip = parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3];
- uint mask = uint.MaxValue << (32 - (int)parts[4]);
-
- from = ip & mask;
- to = ip | ~mask;
- }
- private static void ConvertCidr(string cidr, out byte[] from, out byte[] to)
- {
- string[] parts = cidr.Split('/');
- int prefix = Convert.ToInt32(parts[1]);
- from = IPAddress.Parse(parts[0]).GetAddressBytes();
- to = from.ToArray();
-
- for (int i = 0; i < 16; i++)
- {
- for (int j = 0; j < 8; j++)
- {
- if (i * 8 + j >= prefix)
- {
- byte mask = (byte)(byte.MaxValue << (8 - j));
- from[i] &= mask;
- to[i] = (byte)(to[i] | ~mask);
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/BytecodeApi.CommandLineParser/.nuget/README.md b/BytecodeApi.CommandLineParser/.nuget/README.md
new file mode 100644
index 0000000..6df3688
--- /dev/null
+++ b/BytecodeApi.CommandLineParser/.nuget/README.md
@@ -0,0 +1,21 @@
+# BytecodeApi.CommandLineParser
+
+Library for commandline parsing and handling.
+
+## Examples
+
+See: [Examples](https://github.com/bytecode77/bytecode-api/blob/master/BytecodeApi.CommandLineParser/README.md)
+
+## Changelog
+
+### 5.0.0 (15.02.2026)
+
+* **change:** Targeting .NET 10.0
+
+### 4.0.0 (15.09.2025)
+
+* **change:** Targeting .NET 9.0
+
+### 3.0.0 (08.09.2023)
+
+* Initial release
\ No newline at end of file
diff --git a/BytecodeApi.CommandLineParser/BytecodeApi.CommandLineParser.csproj b/BytecodeApi.CommandLineParser/BytecodeApi.CommandLineParser.csproj
new file mode 100644
index 0000000..039c7ef
--- /dev/null
+++ b/BytecodeApi.CommandLineParser/BytecodeApi.CommandLineParser.csproj
@@ -0,0 +1,40 @@
+
+
+ net10.0
+ enable
+ enable
+ True
+ True
+
+
+ 5.0.0
+ 5.0.0
+ 5.0.0
+
+
+ BytecodeApi.CommandLineParser
+ BytecodeApi.CommandLineParser
+ Library for commandline parsing and handling.
+ bytecode77
+ Martin Fischer
+ © bytecode77, 2026.
+
+
+ BytecodeApi.CommandLineParser
+ commandline cli parsing cmd
+ https://bytecode77.com/bytecode-api
+ git
+ https://github.com/bytecode77/bytecode-api
+ MIT
+ .nuget\README.md
+ .nuget\PackageIcon.png
+ ../$Build
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BytecodeApi.CommandLineParser/CommandLineParserError.cs b/BytecodeApi.CommandLineParser/CommandLineParserError.cs
new file mode 100644
index 0000000..7a27a7e
--- /dev/null
+++ b/BytecodeApi.CommandLineParser/CommandLineParserError.cs
@@ -0,0 +1,52 @@
+namespace BytecodeApi.CommandLineParser;
+
+///
+/// Specifies a validation source for a , if validated using the object.
+///
+public enum CommandLineParserError
+{
+ ///
+ /// The exception is a general error that did not occur during validation using the object.
+ ///
+ None,
+ ///
+ /// The exception occurred in the method.
+ ///
+ OptionRequired,
+ ///
+ /// The exception occurred in the method.
+ ///
+ OptionNotDuplicate,
+ ///
+ /// The exception occurred in the method.
+ ///
+ ValueCount,
+ ///
+ /// The exception occurred in the method.
+ ///
+ MinimumValueCount,
+ ///
+ /// The exception occurred in the method.
+ ///
+ MaximumValueCount,
+ ///
+ /// The exception occurred in the method.
+ ///
+ Custom,
+ ///
+ /// The exception occurred in the method.
+ ///
+ Int32,
+ ///
+ /// The exception occurred in the method.
+ ///
+ FileExists,
+ ///
+ /// The exception occurred in the method.
+ ///
+ DirectoryExists,
+ ///
+ /// The exception occurred in the method.
+ ///
+ FileExtension
+}
\ No newline at end of file
diff --git a/BytecodeApi.CommandLineParser/CommandLineParserException.cs b/BytecodeApi.CommandLineParser/CommandLineParserException.cs
new file mode 100644
index 0000000..dfab8f8
--- /dev/null
+++ b/BytecodeApi.CommandLineParser/CommandLineParserException.cs
@@ -0,0 +1,29 @@
+namespace BytecodeApi.CommandLineParser;
+
+///
+/// The exception that is thrown when commandline parsing failed or was asserted using the object.
+///
+public sealed class CommandLineParserException : Exception
+{
+ ///
+ /// Gets a value that indicates what validation took place using the object. For general exceptions, is returned.
+ ///
+ public CommandLineParserError Error { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The message that describes the error.
+ public CommandLineParserException(string? message) : this(CommandLineParserError.None, message)
+ {
+ }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// If validated using the object, indicates what validation took place.
+ /// The message that describes the error.
+ public CommandLineParserException(CommandLineParserError error, string? message) : base(message)
+ {
+ Error = error;
+ }
+}
\ No newline at end of file
diff --git a/BytecodeApi.CommandLineParser/Option.cs b/BytecodeApi.CommandLineParser/Option.cs
new file mode 100644
index 0000000..172dd6f
--- /dev/null
+++ b/BytecodeApi.CommandLineParser/Option.cs
@@ -0,0 +1,120 @@
+using BytecodeApi.Extensions;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+
+namespace BytecodeApi.CommandLineParser;
+
+///
+/// Represents a commandline option, specified by possible arguments and alternatives.
+/// Example: "-p 12345" and "--password 12345"
+///
+[DebuggerDisplay($"{nameof(Option)}: Arguments = {{string.Join(\"|\", Arguments)}}, Alternatives = {{string.Join(\"|\", Alternatives)}}")]
+public sealed class Option : IEquatable