Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,4 @@ dotnet_diagnostic.IDE0005.severity = warning
# Enforce formatting https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#rule-id-ide0055-fix-formatting
dotnet_diagnostic.IDE0055.severity = error
dotnet_diagnostic.IDE1006.severity = error
dotnet_diagnostic.IDE0022.severity = error
dotnet_diagnostic.IDE0022.severity = none
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);IDE0005</NoWarn>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisMode>None</AnalysisMode>
<AnalysisMode>Recommended</AnalysisMode>
</PropertyGroup>

<!-- Include README for packable projects -->
Expand Down
2 changes: 1 addition & 1 deletion QRCoder/ASCIIQRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public AsciiQRCode(QRCodeData data) : base(data) { }
public string GetGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true, string endOfLine = "\n")
{
if (repeatPerModule < 1)
throw new Exception("The repeatPerModule-parameter must be 1 or greater.");
throw new ArgumentOutOfRangeException(nameof(repeatPerModule), "The repeatPerModule parameter must be 1 or greater.");
return string.Join(endOfLine, GetLineByLineGraphic(repeatPerModule, darkColorString, whiteSpaceString, drawQuietZones));
}

Expand Down
10 changes: 5 additions & 5 deletions QRCoder/ArtQRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor,
BackgroundImageStyle backgroundImageStyle = BackgroundImageStyle.DataAreaOnly, Bitmap? finderPatternImage = null)
{
if (pixelSizeFactor > 1)
throw new Exception("The parameter pixelSize must be between 0 and 1. (0-100%)");
throw new ArgumentOutOfRangeException(nameof(pixelSizeFactor), "The parameter pixelSizeFactor must be between 0 and 1. (0-100%)");
int pixelSize = (int)Math.Min(pixelsPerModule, Math.Floor(pixelsPerModule * pixelSizeFactor));

var numModules = QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8);
Expand Down Expand Up @@ -134,7 +134,7 @@ public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor,
/// <param name="pixelSize">Size of the dots</param>
/// <param name="brush">Color of the pixels</param>
/// <returns></returns>
private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush)
private static Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush)
{
// draw a dot
var bitmap = new Bitmap(pixelSize, pixelSize);
Expand Down Expand Up @@ -168,7 +168,7 @@ private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush
/// <param name="y">Y position</param>
/// <param name="numModules">Total number of modules per row</param>
/// <returns>true, if position is part of quiet zone</returns>
private bool IsPartOfQuietZone(int x, int y, int numModules)
private static bool IsPartOfQuietZone(int x, int y, int numModules)
{
return
x < 4 || //left
Expand All @@ -186,7 +186,7 @@ private bool IsPartOfQuietZone(int x, int y, int numModules)
/// <param name="numModules">Total number of modules per row</param>
/// <param name="offset">Offset in modules (usually depending on drawQuietZones parameter)</param>
/// <returns>true, if position is part of any finder pattern</returns>
private bool IsPartOfFinderPattern(int x, int y, int numModules, int offset)
private static bool IsPartOfFinderPattern(int x, int y, int numModules, int offset)
{
var cornerSize = 11 - offset;
var outerLimitLow = (numModules - cornerSize - 1);
Expand All @@ -204,7 +204,7 @@ private bool IsPartOfFinderPattern(int x, int y, int numModules, int offset)
/// <param name="image"></param>
/// <param name="newSize"></param>
/// <returns>Resized image as bitmap</returns>
private Bitmap Resize(Bitmap image, int newSize)
private static Bitmap Resize(Bitmap image, int newSize)
{
float scale = Math.Min((float)newSize / image.Width, (float)newSize / image.Height);
var scaledWidth = (int)(image.Width * scale);
Expand Down
2 changes: 1 addition & 1 deletion QRCoder/Base64QRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor,
#if NET6_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
#endif
private string BitmapToBase64(Bitmap bmp, ImageType imgType)
private static string BitmapToBase64(Bitmap bmp, ImageType imgType)
{
var iFormat = imgType switch
{
Expand Down
20 changes: 2 additions & 18 deletions QRCoder/BitmapByteQRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public byte[] GetGraphic(int pixelsPerModule)
/// <param name="lightColorHtmlHex">The color of the light modules in HTML hex format.</param>
/// <returns>Returns the QR code graphic as a bitmap byte array.</returns>
public byte[] GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex)
=> GetGraphic(pixelsPerModule, HexColorToByteArray(darkColorHtmlHex), HexColorToByteArray(lightColorHtmlHex));
=> GetGraphic(pixelsPerModule, darkColorHtmlHex.HexColorToByteArray(), lightColorHtmlHex.HexColorToByteArray());

/// <summary>
/// Returns the QR code graphic as a bitmap byte array.
Expand Down Expand Up @@ -134,29 +134,13 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC
}


/// <summary>
/// Converts a hex color string to a byte array.
/// </summary>
/// <param name="colorString">The hex color string to convert.</param>
/// <returns>Returns the color as a byte array.</returns>
private byte[] HexColorToByteArray(string colorString)
{
if (colorString.StartsWith("#"))
colorString = colorString.Substring(1);
byte[] byteColor = new byte[colorString.Length / 2];
for (int i = 0; i < byteColor.Length; i++)
byteColor[i] = byte.Parse(colorString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture);
return byteColor;
}


/// <summary>
/// Converts an integer to a 4 bytes and writes them to a byte array at given position
/// </summary>
/// <param name="inp">The integer to convert.</param>
/// <param name="destinationIndex">Index of destinationArray where the converted bytes are written to</param>
/// <param name="destinationArray">Destination byte array that receives the bytes</param>
private void CopyIntAs4ByteToArray(int inp, int destinationIndex, byte[] destinationArray)
private static void CopyIntAs4ByteToArray(int inp, int destinationIndex, byte[] destinationArray)
{
unchecked
{
Expand Down
26 changes: 26 additions & 0 deletions QRCoder/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,30 @@ public static bool IsNullOrWhiteSpace(
return string.IsNullOrWhiteSpace(value);
#endif
}

/// <summary>
/// Converts a hex color string to a byte array.
/// </summary>
/// <param name="colorString">Color in HEX format like #ffffff.</param>
/// <returns>Returns the color as a byte array.</returns>
internal static byte[] HexColorToByteArray(this string colorString)
{
var offset = 0;
if (colorString.StartsWith("#", StringComparison.Ordinal))
offset = 1;
byte[] byteColor = new byte[(colorString.Length - offset) / 2];
for (int i = 0; i < byteColor.Length; i++)
#if HAS_SPAN
byteColor[i] = byte.Parse(colorString.AsSpan(i * 2 + offset, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
#else
byteColor[i] = byte.Parse(colorString.Substring(i * 2 + offset, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
#endif
return byteColor;
}

#if NETSTANDARD1_3
/// <inheritdoc cref="char.ToString()"/>
internal static string ToString(this char c, CultureInfo _)
=> c.ToString();
#endif
}
1 change: 1 addition & 0 deletions QRCoder/Extensions/StringValueAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace QRCoder.Extensions;
/// Used to represent a string value for a value in an enum
/// </summary>
[Obsolete("This attribute will be removed in a future version of QRCoder.")]
[AttributeUsage(AttributeTargets.Field)]
public class StringValueAttribute : Attribute
{

Expand Down
12 changes: 8 additions & 4 deletions QRCoder/PayloadGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,24 @@ public static partial class PayloadGenerator
private static bool IsValidIban(string iban)
{
//Clean IBAN
var ibanCleared = iban.ToUpper().Replace(" ", "").Replace("-", "");
var ibanCleared = iban.ToUpperInvariant().Replace(" ", "").Replace("-", "");

//Check for general structure
var structurallyValid = Regex.IsMatch(ibanCleared, @"^[a-zA-Z]{2}[0-9]{2}([a-zA-Z0-9]?){16,30}$");

//Check IBAN checksum
var checksumValid = false;
var sum = $"{ibanCleared.Substring(4)}{ibanCleared.Substring(0, 4)}".ToCharArray().Aggregate("", (current, c) => current + (char.IsLetter(c) ? (c - 55).ToString() : c.ToString()));
var sum = $"{ibanCleared.Substring(4)}{ibanCleared.Substring(0, 4)}".ToCharArray().Aggregate("", (current, c) => current + (char.IsLetter(c) ? (c - 55).ToString(CultureInfo.InvariantCulture) : c.ToString(CultureInfo.InvariantCulture)));
int m = 0;
for (int i = 0; i < (int)Math.Ceiling((sum.Length - 2) / 7d); i++)
{
var offset = (i == 0 ? 0 : 2);
var start = i * 7 + offset;
#if NET5_0_OR_GREATER
var n = string.Concat(i == 0 ? "" : m.ToString(CultureInfo.InvariantCulture), sum.AsSpan(start, Math.Min(9 - offset, sum.Length - start)));
#else
var n = (i == 0 ? "" : m.ToString()) + sum.Substring(start, Math.Min(9 - offset, sum.Length - start));
#endif
if (!int.TryParse(n, NumberStyles.Any, CultureInfo.InvariantCulture, out m))
break;
m %= 97;
Expand All @@ -49,8 +53,8 @@ private static bool IsValidQRIban(string iban)
var foundQrIid = false;
try
{
var ibanCleared = iban.ToUpper().Replace(" ", "").Replace("-", "");
var possibleQrIid = Convert.ToInt32(ibanCleared.Substring(4, 5));
var ibanCleared = iban.ToUpperInvariant().Replace(" ", "").Replace("-", "");
var possibleQrIid = Convert.ToInt32(ibanCleared.Substring(4, 5), CultureInfo.InvariantCulture);
foundQrIid = possibleQrIid >= 30000 && possibleQrIid <= 31999;
}
catch { }
Expand Down
50 changes: 26 additions & 24 deletions QRCoder/PayloadGenerator/BezahlCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
}
else if (internalMode == 2)
{
#pragma warning disable CS0612
#pragma warning disable CS0618
if (authority != AuthorityType.periodicsinglepayment && authority != AuthorityType.singledirectdebit && authority != AuthorityType.singlepayment)
throw new BezahlCodeException("The constructor with 'account' and 'bnc' may only be used with 'non SEPA' authority types. Either choose another authority type or switch constructor.");
if (authority == AuthorityType.periodicsinglepayment && (string.IsNullOrEmpty(periodicTimeunit) || periodicTimeunitRotation == 0))
throw new BezahlCodeException("When using 'periodicsinglepayment' as authority type, the parameters 'periodicTimeunit' and 'periodicTimeunitRotation' must be set.");
#pragma warning restore CS0612
#pragma warning restore CS0618
}
else if (internalMode == 3)
{
Expand All @@ -155,17 +155,17 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
_reason = reason;

//Non-SEPA payment types
#pragma warning disable CS0612
#pragma warning disable CS0618
if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.singledirectdebit || authority == AuthorityType.singlepayment || authority == AuthorityType.contact || (authority == AuthorityType.contact_v2 && oldWayFilled))
{
#pragma warning restore CS0612
#pragma warning restore CS0618

if (!Regex.IsMatch(account.Replace(" ", ""), @"^[0-9]{1,9}$"))
throw new BezahlCodeException("The account entered isn't valid.");
_account = account.Replace(" ", "").ToUpper();
_account = account.Replace(" ", "").ToUpperInvariant();
if (!Regex.IsMatch(bnc.Replace(" ", ""), @"^[0-9]{1,9}$"))
throw new BezahlCodeException("The bnc entered isn't valid.");
_bnc = bnc.Replace(" ", "").ToUpper();
_bnc = bnc.Replace(" ", "").ToUpperInvariant();

if (authority != AuthorityType.contact && authority != AuthorityType.contact_v2)
{
Expand All @@ -180,10 +180,10 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
{
if (!IsValidIban(iban))
throw new BezahlCodeException("The IBAN entered isn't valid.");
_iban = iban.Replace(" ", "").ToUpper();
_iban = iban.Replace(" ", "").ToUpperInvariant();
if (!IsValidBic(bic))
throw new BezahlCodeException("The BIC entered isn't valid.");
_bic = bic.Replace(" ", "").ToUpper();
_bic = bic.Replace(" ", "").ToUpperInvariant();

if (authority != AuthorityType.contact_v2)
{
Expand All @@ -205,7 +205,7 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
//Checks for all payment types
if (authority != AuthorityType.contact && authority != AuthorityType.contact_v2)
{
if (amount.ToString().Replace(",", ".").Contains(".") && amount.ToString().Replace(",", ".").Split('.')[1].TrimEnd('0').Length > 2)
if (amount.ToString(CultureInfo.InvariantCulture).Contains('.') && amount.ToString(CultureInfo.InvariantCulture).Split('.')[1].TrimEnd('0').Length > 2)
throw new BezahlCodeException("Amount must have less than 3 digits after decimal point.");
if (amount < 0.01m || amount > 999999999.99m)
throw new BezahlCodeException("Amount has to at least 0.01 and must be smaller or equal to 999999999.99.");
Expand All @@ -221,11 +221,11 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
throw new BezahlCodeException("Execution date must be today or in future.");
_executionDate = (DateTime)executionDate;
}
#pragma warning disable CS0612
#pragma warning disable CS0618
if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.periodicsinglepaymentsepa)
#pragma warning restore CS0612
#pragma warning restore CS0618
{
if (periodicTimeunit.ToUpper() != "M" && periodicTimeunit.ToUpper() != "W")
if (periodicTimeunit.ToUpperInvariant() != "M" && periodicTimeunit.ToUpperInvariant() != "W")
throw new BezahlCodeException("The periodicTimeunit must be either 'M' (monthly) or 'W' (weekly).");
_periodicTimeunit = periodicTimeunit;
if (periodicTimeunitRotation < 1 || periodicTimeunitRotation > 52)
Expand Down Expand Up @@ -253,9 +253,9 @@ public override string ToString()
if (_authority != AuthorityType.contact && _authority != AuthorityType.contact_v2)
{
//Handle what is same for all payments
#pragma warning disable CS0612
#pragma warning disable CS0618
if (_authority == AuthorityType.periodicsinglepayment || _authority == AuthorityType.singledirectdebit || _authority == AuthorityType.singlepayment)
#pragma warning restore CS0612
#pragma warning restore CS0618
{
bezahlCodePayload += $"account={_account}&";
bezahlCodePayload += $"bnc={_bnc}&";
Expand All @@ -277,26 +277,26 @@ public override string ToString()
if (!string.IsNullOrEmpty(_mandateId))
bezahlCodePayload += $"mandateid={Uri.EscapeDataString(_mandateId)}&";
if (_dateOfSignature != DateTime.MinValue)
bezahlCodePayload += $"dateofsignature={_dateOfSignature.ToString("ddMMyyyy")}&";
bezahlCodePayload += $"dateofsignature={_dateOfSignature.ToString("ddMMyyyy", CultureInfo.InvariantCulture)}&";
}
}
bezahlCodePayload += $"amount={_amount:0.00}&".Replace(".", ",");
bezahlCodePayload += string.Format(CultureInfo.InvariantCulture, "amount={0:0.00}&", _amount).Replace(".", ",");

if (!string.IsNullOrEmpty(_reason))
bezahlCodePayload += $"reason={Uri.EscapeDataString(_reason)}&";
bezahlCodePayload += $"currency={_currency}&";
bezahlCodePayload += $"executiondate={_executionDate.ToString("ddMMyyyy")}&";
#pragma warning disable CS0612
bezahlCodePayload += $"executiondate={_executionDate.ToString("ddMMyyyy", CultureInfo.InvariantCulture)}&";
#pragma warning disable CS0618
if (_authority == AuthorityType.periodicsinglepayment || _authority == AuthorityType.periodicsinglepaymentsepa)
{
bezahlCodePayload += $"periodictimeunit={_periodicTimeunit}&";
bezahlCodePayload += $"periodictimeunitrotation={_periodicTimeunitRotation}&";
if (_periodicFirstExecutionDate != DateTime.MinValue)
bezahlCodePayload += $"periodicfirstexecutiondate={_periodicFirstExecutionDate.ToString("ddMMyyyy")}&";
bezahlCodePayload += $"periodicfirstexecutiondate={_periodicFirstExecutionDate.ToString("ddMMyyyy", CultureInfo.InvariantCulture)}&";
if (_periodicLastExecutionDate != DateTime.MinValue)
bezahlCodePayload += $"periodiclastexecutiondate={_periodicLastExecutionDate.ToString("ddMMyyyy")}&";
bezahlCodePayload += $"periodiclastexecutiondate={_periodicLastExecutionDate.ToString("ddMMyyyy", CultureInfo.InvariantCulture)}&";
}
#pragma warning restore CS0612
#pragma warning restore CS0618
}
else
{
Expand Down Expand Up @@ -1047,6 +1047,7 @@ public enum Currency
}


#pragma warning disable CA1707 // Underscore in identifier
/// <summary>
/// Operation modes of the BezahlCode
/// </summary>
Expand All @@ -1055,7 +1056,7 @@ public enum AuthorityType
/// <summary>
/// Single payment (Überweisung)
/// </summary>
[Obsolete]
[Obsolete("Use singlepaymentsepa instead for SEPA-compliant payments")]
singlepayment,
/// <summary>
/// Single SEPA payment (SEPA-Überweisung)
Expand All @@ -1064,7 +1065,7 @@ public enum AuthorityType
/// <summary>
/// Single debit (Lastschrift)
/// </summary>
[Obsolete]
[Obsolete("Use singledirectdebitsepa instead for SEPA-compliant payments")]
singledirectdebit,
/// <summary>
/// Single SEPA debit (SEPA-Lastschrift)
Expand All @@ -1073,7 +1074,7 @@ public enum AuthorityType
/// <summary>
/// Periodic payment (Dauerauftrag)
/// </summary>
[Obsolete]
[Obsolete("Use periodicsinglepaymentsepa instead for SEPA-compliant payments")]
periodicsinglepayment,
/// <summary>
/// Periodic SEPA payment (SEPA-Dauerauftrag)
Expand All @@ -1088,6 +1089,7 @@ public enum AuthorityType
/// </summary>
contact_v2
}
#pragma warning restore CA1707 // Underscore in identifier

/// <summary>
/// Exception class for BezahlCode errors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public override string ToString()
.ToArray());
}

return $"{Enum.GetName(typeof(BitcoinLikeCryptoCurrencyType), _currencyType)!.ToLower()}:{_address}{query}";
return $"{Enum.GetName(typeof(BitcoinLikeCryptoCurrencyType), _currencyType)!.ToLowerInvariant()}:{_address}{query}";
}

/// <summary>
Expand Down
Loading