Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions QRCoder.Xaml/QRCoder.Xaml.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<TargetFrameworks>net35;net40;net5.0-windows;net6.0-windows</TargetFrameworks>
<UseWPF Condition="'$(TargetFramework)' == 'net5.0-windows' OR '$(TargetFramework)' == 'net6.0-windows'">true</UseWPF>
<IsPackable>true</IsPackable>
<AnalysisMode>Recommended</AnalysisMode>

<!-- Set NuGet package properties -->
<Description>QRCoder.Xaml is the XamlQRCode-extension for the popular QRCoder .NET library.</Description>
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 pixelSize 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
Loading