diff --git a/.github/workflows/auto-pr-from-main.yml b/.github/workflows/auto-pr-from-main.yml
index b05b9d1..6f3411f 100644
--- a/.github/workflows/auto-pr-from-main.yml
+++ b/.github/workflows/auto-pr-from-main.yml
@@ -45,12 +45,42 @@ jobs:
git checkout -b "$BRANCH_NAME"
# List outdated packages
- dotnet list QRCoder.Core.sln package --outdated
+ dotnet list QRCoder.Core.sln package --outdated --format json > outdated-packages.json
- # Update packages (this is a simplified approach)
+ # Update packages using the latest available versions
echo "📦 Updating NuGet packages..."
- dotnet add src/Metar.Decoder package --version latest || echo "No updates needed for Metar.Decoder"
- dotnet add src/Taf.Decoder package --version latest || echo "No updates needed for Taf.Decoder"
+ python3 - <<'PY'
+ import json
+ import pathlib
+ import subprocess
+
+ data = json.loads(pathlib.Path("outdated-packages.json").read_text())
+ updates = {}
+
+ for project in data.get("projects", []):
+ project_path = pathlib.Path(project["path"]).resolve()
+ for framework in project.get("frameworks", []):
+ for package in framework.get("topLevelPackages", []):
+ latest = package.get("latestVersion")
+ requested = package.get("requestedVersion")
+ if latest and latest != requested:
+ updates.setdefault(project_path, {})[package["id"]] = latest
+
+ for project_path, packages in updates.items():
+ for package_name, latest_version in sorted(packages.items()):
+ subprocess.run(
+ [
+ "dotnet",
+ "add",
+ str(project_path),
+ "package",
+ package_name,
+ "--version",
+ latest_version,
+ ],
+ check=True,
+ )
+ PY
# Check if there are any changes
if git diff --quiet; then
diff --git a/.github/workflows/ci-build-test.yml b/.github/workflows/ci-build-test.yml
index 839ace4..944a670 100644
--- a/.github/workflows/ci-build-test.yml
+++ b/.github/workflows/ci-build-test.yml
@@ -312,8 +312,8 @@ jobs:
- ✅ Performance Tests
---
- *Este PR foi criado automaticamente pelo pipeline CI/CD*
- branch: main
+ *Este PR foi criado automaticamente pelo pipeline CI/CD*
+ branch: auto-pr/${{ github.ref_name }}
delete-branch: true
draft: false
labels: |
diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml
index 9785b43..1aa1a63 100644
--- a/.github/workflows/code-quality.yml
+++ b/.github/workflows/code-quality.yml
@@ -100,7 +100,7 @@ jobs:
echo "✅ SONNAR_TOKEN is configured"
dotnet sonarscanner begin \
/o:"afonsoft" \
- /k:"afonsoft_metar-decoder" \
+ /k:"afonsoft_QRCoder.Core" \
/d:sonar.host.url="https://sonarcloud.io" \
/d:sonar.login="$SONAR_TOKEN" \
/d:sonar.scm.provider=git \
diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml
index 021f938..6107f2c 100644
--- a/.github/workflows/security-scan.yml
+++ b/.github/workflows/security-scan.yml
@@ -125,7 +125,7 @@ jobs:
echo "✅ SONNAR_TOKEN is configured"
dotnet sonarscanner begin \
/o:"afonsoft" \
- /k:"afonsoft_metar-decoder" \
+ /k:"afonsoft_QRCoder.Core" \
/d:sonar.host.url="https://sonarcloud.io" \
/d:sonar.login="${{ secrets.SONNAR_TOKEN }}" \
/d:sonar.scm.provider=git \
diff --git a/QRCoder.Core/Generators/PayloadGenerator.cs b/QRCoder.Core/Generators/PayloadGenerator.cs
index b63bcb8..5d6a2a2 100644
--- a/QRCoder.Core/Generators/PayloadGenerator.cs
+++ b/QRCoder.Core/Generators/PayloadGenerator.cs
@@ -627,136 +627,103 @@ public ContactData(ContactOutputType outputType, string firstname, string lastna
/// The string result.
public override string ToString()
{
- string payload = string.Empty;
if (outputType == ContactOutputType.MeCard)
- {
- payload += "MECARD+\r\n";
- if (!string.IsNullOrEmpty(firstname) && !string.IsNullOrEmpty(lastname))
- payload += $"N:{lastname}, {firstname}\r\n";
- else if (!string.IsNullOrEmpty(firstname) || !string.IsNullOrEmpty(lastname))
- payload += $"N:{firstname}{lastname}\r\n";
- if (!string.IsNullOrEmpty(org))
- payload += $"ORG:{org}\r\n";
- if (!string.IsNullOrEmpty(orgTitle))
- payload += $"TITLE:{orgTitle}\r\n";
- if (!string.IsNullOrEmpty(phone))
- payload += $"TEL:{phone}\r\n";
- if (!string.IsNullOrEmpty(mobilePhone))
- payload += $"TEL:{mobilePhone}\r\n";
- if (!string.IsNullOrEmpty(workPhone))
- payload += $"TEL:{workPhone}\r\n";
- if (!string.IsNullOrEmpty(email))
- payload += $"EMAIL:{email}\r\n";
- if (!string.IsNullOrEmpty(note))
- payload += $"NOTE:{note}\r\n";
- if (birthday != null)
- payload += $"BDAY:{((DateTime)birthday).ToString("yyyyMMdd")}\r\n";
- string addressString = string.Empty;
- if (addressOrder == AddressOrder.Default)
- {
- addressString = $"ADR:,,{(!string.IsNullOrEmpty(street) ? street + " " : "")}{(!string.IsNullOrEmpty(houseNumber) ? houseNumber : "")},{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")},{(!string.IsNullOrEmpty(city) ? city : "")},{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")},{(!string.IsNullOrEmpty(country) ? country : "")}\r\n";
- }
- else
- {
- addressString = $"ADR:,,{(!string.IsNullOrEmpty(houseNumber) ? houseNumber + " " : "")}{(!string.IsNullOrEmpty(street) ? street : "")},{(!string.IsNullOrEmpty(city) ? city : "")},{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")},{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")},{(!string.IsNullOrEmpty(country) ? country : "")}\r\n";
- }
- payload += addressString;
- if (!string.IsNullOrEmpty(website))
- payload += $"URL:{website}\r\n";
- if (!string.IsNullOrEmpty(nickname))
- payload += $"NICKNAME:{nickname}\r\n";
- payload = payload.Trim('\r', '\n');
- }
- else
- {
- var version = outputType.ToString().Substring(5);
- if (version.Length > 1)
- version = version.Insert(1, ".");
- else
- version += ".0";
+ return BuildMeCard();
- payload += "BEGIN:VCARD\r\n";
- payload += $"VERSION:{version}\r\n";
+ return BuildVCard();
+ }
- payload += $"N:{(!string.IsNullOrEmpty(lastname) ? lastname : "")};{(!string.IsNullOrEmpty(firstname) ? firstname : "")};;;\r\n";
- payload += $"FN:{(!string.IsNullOrEmpty(firstname) ? firstname + " " : "")}{(!string.IsNullOrEmpty(lastname) ? lastname : "")}\r\n";
- if (!string.IsNullOrEmpty(org))
- {
- payload += $"ORG:" + org + "\r\n";
- }
- if (!string.IsNullOrEmpty(orgTitle))
- {
- payload += $"TITLE:" + orgTitle + "\r\n";
- }
- if (!string.IsNullOrEmpty(phone))
- {
- payload += $"TEL;";
- if (outputType == ContactOutputType.VCard21)
- payload += $"HOME;VOICE:{phone}";
- else if (outputType == ContactOutputType.VCard3)
- payload += $"TYPE=HOME,VOICE:{phone}";
- else
- payload += $"TYPE=home,voice;VALUE=uri:tel:{phone}";
- payload += "\r\n";
- }
+ private string BuildMeCard()
+ {
+ var payload = new StringBuilder("MECARD+\r\n");
+ AppendName(payload, "N:");
+ AppendLine(payload, "ORG:", org);
+ AppendLine(payload, "TITLE:", orgTitle);
+ AppendLine(payload, "TEL:", phone);
+ AppendLine(payload, "TEL:", mobilePhone);
+ AppendLine(payload, "TEL:", workPhone);
+ AppendLine(payload, "EMAIL:", email);
+ AppendLine(payload, "NOTE:", note);
+ if (birthday != null)
+ AppendLine(payload, "BDAY:", ((DateTime)birthday).ToString("yyyyMMdd"));
+ payload.Append("ADR:,,").Append(BuildAddress(',')).Append("\r\n");
+ AppendLine(payload, "URL:", website);
+ AppendLine(payload, "NICKNAME:", nickname);
+ return payload.ToString().TrimEnd('\r', '\n');
+ }
- if (!string.IsNullOrEmpty(mobilePhone))
- {
- payload += $"TEL;";
- if (outputType == ContactOutputType.VCard21)
- payload += $"HOME;CELL:{mobilePhone}";
- else if (outputType == ContactOutputType.VCard3)
- payload += $"TYPE=HOME,CELL:{mobilePhone}";
- else
- payload += $"TYPE=home,cell;VALUE=uri:tel:{mobilePhone}";
- payload += "\r\n";
- }
+ private string BuildVCard()
+ {
+ var payload = new StringBuilder();
+ var version = outputType.ToString().Substring(5);
+ if (version.Length > 1)
+ version = version.Insert(1, ".");
+ else
+ version += ".0";
+
+ payload.Append("BEGIN:VCARD\r\n");
+ payload.Append("VERSION:").Append(version).Append("\r\n");
+ payload.Append("N:").Append(!string.IsNullOrEmpty(lastname) ? lastname : "").Append(";").Append(!string.IsNullOrEmpty(firstname) ? firstname : "").Append(";;;\r\n");
+ payload.Append("FN:").Append(!string.IsNullOrEmpty(firstname) ? firstname + " " : "").Append(!string.IsNullOrEmpty(lastname) ? lastname : "").Append("\r\n");
+ AppendLine(payload, "ORG:", org);
+ AppendLine(payload, "TITLE:", orgTitle);
+ AppendTelephone(payload, phone, "HOME;VOICE:", "TYPE=HOME,VOICE:", "TYPE=home,voice;VALUE=uri:tel:");
+ AppendTelephone(payload, mobilePhone, "HOME;CELL:", "TYPE=HOME,CELL:", "TYPE=home,cell;VALUE=uri:tel:");
+ AppendTelephone(payload, workPhone, "WORK;VOICE:", "TYPE=WORK,VOICE:", "TYPE=work,voice;VALUE=uri:tel:");
+ payload.Append("ADR;");
+ if (outputType == ContactOutputType.VCard21)
+ payload.Append("HOME;PREF:");
+ else if (outputType == ContactOutputType.VCard3)
+ payload.Append("TYPE=HOME,PREF:");
+ else
+ payload.Append("TYPE=home,pref:");
+ payload.Append(';').Append(';').Append(BuildAddress(';')).Append("\r\n");
+ if (birthday != null)
+ AppendLine(payload, "BDAY:", ((DateTime)birthday).ToString("yyyyMMdd"));
+ AppendLine(payload, "URL:", website);
+ AppendLine(payload, "EMAIL:", email);
+ AppendLine(payload, "NOTE:", note);
+ if (outputType != ContactOutputType.VCard21)
+ AppendLine(payload, "NICKNAME:", nickname);
+ payload.Append("END:VCARD");
+ return payload.ToString();
+ }
- if (!string.IsNullOrEmpty(workPhone))
- {
- payload += $"TEL;";
- if (outputType == ContactOutputType.VCard21)
- payload += $"WORK;VOICE:{workPhone}";
- else if (outputType == ContactOutputType.VCard3)
- payload += $"TYPE=WORK,VOICE:{workPhone}";
- else
- payload += $"TYPE=work,voice;VALUE=uri:tel:{workPhone}";
- payload += "\r\n";
- }
+ private void AppendName(StringBuilder payload, string prefix)
+ {
+ if (!string.IsNullOrEmpty(firstname) && !string.IsNullOrEmpty(lastname))
+ payload.Append(prefix).Append(lastname).Append(", ").Append(firstname).Append("\r\n");
+ else if (!string.IsNullOrEmpty(firstname) || !string.IsNullOrEmpty(lastname))
+ payload.Append(prefix).Append(firstname).Append(lastname).Append("\r\n");
+ }
- payload += "ADR;";
- if (outputType == ContactOutputType.VCard21)
- payload += "HOME;PREF:";
- else if (outputType == ContactOutputType.VCard3)
- payload += "TYPE=HOME,PREF:";
- else
- payload += "TYPE=home,pref:";
- string addressString = string.Empty;
- if (addressOrder == AddressOrder.Default)
- {
- addressString = $";;{(!string.IsNullOrEmpty(street) ? street + " " : "")}{(!string.IsNullOrEmpty(houseNumber) ? houseNumber : "")};{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")};{(!string.IsNullOrEmpty(city) ? city : "")};{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")};{(!string.IsNullOrEmpty(country) ? country : "")}\r\n";
- }
- else
- {
- addressString = $";;{(!string.IsNullOrEmpty(houseNumber) ? houseNumber + " " : "")}{(!string.IsNullOrEmpty(street) ? street : "")};{(!string.IsNullOrEmpty(city) ? city : "")};{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")};{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")};{(!string.IsNullOrEmpty(country) ? country : "")}\r\n";
- }
- payload += addressString;
-
- if (birthday != null)
- payload += $"BDAY:{((DateTime)birthday).ToString("yyyyMMdd")}\r\n";
- if (!string.IsNullOrEmpty(website))
- payload += $"URL:{website}\r\n";
- if (!string.IsNullOrEmpty(email))
- payload += $"EMAIL:{email}\r\n";
- if (!string.IsNullOrEmpty(note))
- payload += $"NOTE:{note}\r\n";
- if (outputType != ContactOutputType.VCard21 && !string.IsNullOrEmpty(nickname))
- payload += $"NICKNAME:{nickname}\r\n";
-
- payload += "END:VCARD";
- }
+ private static void AppendLine(StringBuilder payload, string prefix, string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ payload.Append(prefix).Append(value).Append("\r\n");
+ }
+
+ private void AppendTelephone(StringBuilder payload, string value, string v21Prefix, string v3Prefix, string v4Prefix)
+ {
+ if (string.IsNullOrEmpty(value))
+ return;
+
+ payload.Append("TEL;");
+ if (outputType == ContactOutputType.VCard21)
+ payload.Append(v21Prefix).Append(value);
+ else if (outputType == ContactOutputType.VCard3)
+ payload.Append(v3Prefix).Append(value);
+ else
+ payload.Append(v4Prefix).Append(value);
+ payload.Append("\r\n");
+ }
- return payload;
+ private string BuildAddress(char separator)
+ {
+ if (addressOrder == AddressOrder.Default)
+ return $"{(!string.IsNullOrEmpty(street) ? street + " " : "")}{(!string.IsNullOrEmpty(houseNumber) ? houseNumber : "")}{separator}{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")}{separator}{(!string.IsNullOrEmpty(city) ? city : "")}{separator}{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")}{separator}{(!string.IsNullOrEmpty(country) ? country : "")}";
+
+ return $"{(!string.IsNullOrEmpty(houseNumber) ? houseNumber + " " : "")}{(!string.IsNullOrEmpty(street) ? street : "")}{separator}{(!string.IsNullOrEmpty(city) ? city : "")}{separator}{(!string.IsNullOrEmpty(stateRegion) ? stateRegion : "")}{separator}{(!string.IsNullOrEmpty(zipCode) ? zipCode : "")}{separator}{(!string.IsNullOrEmpty(country) ? country : "")}";
}
///
@@ -2040,85 +2007,92 @@ public BezahlCode(AuthorityType authority, string name, string account, string b
/// The string result.
public override string ToString()
{
- var bezahlCodePayload = $"bank://{authority}?";
-
- bezahlCodePayload += $"name={Uri.EscapeDataString(name)}&";
+ var bezahlCodePayload = new StringBuilder($"bank://{authority}?");
+ AppendParameter(bezahlCodePayload, "name", Uri.EscapeDataString(name));
if (authority != AuthorityType.contact && authority != AuthorityType.contact_v2)
{
- //Handle what is same for all payments
+ AppendPaymentParameters(bezahlCodePayload);
+ }
+ else
+ {
+ AppendContactParameters(bezahlCodePayload);
+ }
+
+ return bezahlCodePayload.ToString().Trim('&');
+ }
+
+ private void AppendPaymentParameters(StringBuilder payload)
+ {
#pragma warning disable CS0612
- if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.singledirectdebit || authority == AuthorityType.singlepayment)
+ if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.singledirectdebit || authority == AuthorityType.singlepayment)
#pragma warning restore CS0612
+ {
+ AppendParameter(payload, "account", account);
+ AppendParameter(payload, "bnc", bnc);
+ if (postingKey > 0)
+ AppendParameter(payload, "postingkey", postingKey.ToString());
+ }
+ else
+ {
+ AppendParameter(payload, "iban", iban);
+ AppendParameter(payload, "bic", bic);
+ AppendParameter(payload, "separeference", Uri.EscapeDataString(sepaReference));
+ if (authority == AuthorityType.singledirectdebitsepa)
{
- bezahlCodePayload += $"account={account}&";
- bezahlCodePayload += $"bnc={bnc}&";
- if (postingKey > 0)
- bezahlCodePayload += $"postingkey={postingKey}&";
+ AppendParameter(payload, "creditorid", Uri.EscapeDataString(creditorId));
+ AppendParameter(payload, "mandateid", Uri.EscapeDataString(mandateId));
+ if (dateOfSignature != DateTime.MinValue)
+ AppendParameter(payload, "dateofsignature", dateOfSignature.ToString("ddMMyyyy"));
}
- else
- {
- bezahlCodePayload += $"iban={iban}&";
- bezahlCodePayload += $"bic={bic}&";
-
- if (!string.IsNullOrEmpty(sepaReference))
- bezahlCodePayload += $"separeference={Uri.EscapeDataString(sepaReference)}&";
+ }
- if (authority == AuthorityType.singledirectdebitsepa)
- {
- if (!string.IsNullOrEmpty(creditorId))
- bezahlCodePayload += $"creditorid={Uri.EscapeDataString(creditorId)}&";
- if (!string.IsNullOrEmpty(mandateId))
- bezahlCodePayload += $"mandateid={Uri.EscapeDataString(mandateId)}&";
- if (dateOfSignature != DateTime.MinValue)
- bezahlCodePayload += $"dateofsignature={dateOfSignature.ToString(DateFormat)}&";
- }
- }
- bezahlCodePayload += $"amount={amount:0.00}&".Replace(".", ",");
+ AppendParameter(payload, "amount", amount.ToString("0.00").Replace(".", ","));
+ AppendParameter(payload, "reason", Uri.EscapeDataString(reason));
+ AppendParameter(payload, "currency", currency.ToString());
+ AppendParameter(payload, "executiondate", executionDate.ToString("ddMMyyyy"));
- if (!string.IsNullOrEmpty(reason))
- bezahlCodePayload += $"reason={Uri.EscapeDataString(reason)}&";
- bezahlCodePayload += $"currency={currency}&";
- bezahlCodePayload += $"executiondate={executionDate.ToString(DateFormat)}&";
#pragma warning disable CS0612
- if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.periodicsinglepaymentsepa)
- {
- bezahlCodePayload += $"periodictimeunit={periodicTimeunit}&";
- bezahlCodePayload += $"periodictimeunitrotation={periodicTimeunitRotation}&";
- if (periodicFirstExecutionDate != DateTime.MinValue)
- bezahlCodePayload += $"periodicfirstexecutiondate={periodicFirstExecutionDate.ToString(DateFormat)}&";
- if (periodicLastExecutionDate != DateTime.MinValue)
- bezahlCodePayload += $"periodiclastexecutiondate={periodicLastExecutionDate.ToString(DateFormat)}&";
- }
+ if (authority == AuthorityType.periodicsinglepayment || authority == AuthorityType.periodicsinglepaymentsepa)
+ {
+ AppendParameter(payload, "periodictimeunit", periodicTimeunit);
+ AppendParameter(payload, "periodictimeunitrotation", periodicTimeunitRotation.ToString());
+ if (periodicFirstExecutionDate != DateTime.MinValue)
+ AppendParameter(payload, "periodicfirstexecutiondate", periodicFirstExecutionDate.ToString("ddMMyyyy"));
+ if (periodicLastExecutionDate != DateTime.MinValue)
+ AppendParameter(payload, "periodiclastexecutiondate", periodicLastExecutionDate.ToString("ddMMyyyy"));
+ }
#pragma warning restore CS0612
+ }
+
+ private void AppendContactParameters(StringBuilder payload)
+ {
+ if (authority == AuthorityType.contact)
+ {
+ AppendParameter(payload, "account", account);
+ AppendParameter(payload, "bnc", bnc);
}
- else
+ else if (authority == AuthorityType.contact_v2)
{
- //Handle what is same for all contacts
- if (authority == AuthorityType.contact)
+ if (!string.IsNullOrEmpty(account) && !string.IsNullOrEmpty(bnc))
{
- bezahlCodePayload += $"account={account}&";
- bezahlCodePayload += $"bnc={bnc}&";
+ AppendParameter(payload, "account", account);
+ AppendParameter(payload, "bnc", bnc);
}
- else if (authority == AuthorityType.contact_v2)
+ else
{
- if (!string.IsNullOrEmpty(account) && !string.IsNullOrEmpty(bnc))
- {
- bezahlCodePayload += $"account={account}&";
- bezahlCodePayload += $"bnc={bnc}&";
- }
- else
- {
- bezahlCodePayload += $"iban={iban}&";
- bezahlCodePayload += $"bic={bic}&";
- }
+ AppendParameter(payload, "iban", iban);
+ AppendParameter(payload, "bic", bic);
}
-
- if (!string.IsNullOrEmpty(reason))
- bezahlCodePayload += $"reason={Uri.EscapeDataString(reason)}&";
}
- return bezahlCodePayload.Trim('&');
+ AppendParameter(payload, "reason", Uri.EscapeDataString(reason));
+ }
+
+ private static void AppendParameter(StringBuilder payload, string key, string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ payload.Append(key).Append('=').Append(value).Append('&');
}
///
diff --git a/QRCoder.Core/Generators/QRCodeGenerator.cs b/QRCoder.Core/Generators/QRCodeGenerator.cs
index 3eda726..8137346 100644
--- a/QRCoder.Core/Generators/QRCodeGenerator.cs
+++ b/QRCoder.Core/Generators/QRCodeGenerator.cs
@@ -25,7 +25,6 @@ public class QRCodeGenerator : IDisposable
private static readonly List capacityTable = CreateCapacityTable();
private static readonly List galoisField = CreateAntilogTable();
private static readonly Dictionary alphanumEncDict = CreateAlphanumEncDict();
- private bool disposed;
///
/// Specifies the ECI (Extended Channel Interpretation) mode for character encoding.
@@ -193,105 +192,94 @@ public static QRCodeData GenerateQrCode(byte[] binaryData, ECCLevel eccLevel)
string modeIndicator = DecToBin((int)EncodingMode.Byte, 4);
string countIndicator = DecToBin(binaryData.Length, GetCountIndicatorLength(version, EncodingMode.Byte));
- string bitString = modeIndicator + countIndicator;
+ var bitString = new StringBuilder(modeIndicator + countIndicator);
foreach (byte b in binaryData)
{
- bitString += DecToBin(b, 8);
+ bitString.Append(DecToBin(b, 8));
}
- return GenerateQrCode(bitString, eccLevel, version);
+ return GenerateQrCode(bitString.ToString(), eccLevel, version);
}
private static QRCodeData GenerateQrCode(string bitString, ECCLevel eccLevel, int version)
{
- //Fill up data code word
var eccInfo = capacityECCTable.Single(x => x.Version == version && x.ErrorCorrectionLevel == eccLevel);
- var dataLength = eccInfo.TotalDataCodewords * 8;
- var lengthDiff = dataLength - bitString.Length;
+ var paddedBitString = PadToDataLength(bitString, eccInfo.TotalDataCodewords * 8);
+ var codeWordWithECC = CreateCodewordBlocks(paddedBitString, eccInfo);
+ var interleavedData = InterleaveCodewords(codeWordWithECC, eccInfo, version);
+ return PlaceModules(version, eccLevel, interleavedData);
+ }
+
+ private static string PadToDataLength(string bitString, int dataLength)
+ {
+ var padded = new StringBuilder(bitString);
+ var lengthDiff = dataLength - padded.Length;
if (lengthDiff > 0)
- bitString += new string('0', Math.Min(lengthDiff, 4));
- if ((bitString.Length % 8) != 0)
- bitString += new string('0', 8 - (bitString.Length % 8));
- while (bitString.Length < dataLength)
- bitString += "1110110000010001";
- if (bitString.Length > dataLength)
- bitString = bitString.Substring(0, dataLength);
-
- //Calculate error correction words
+ padded.Append(new string('0', Math.Min(lengthDiff, 4)));
+ if ((padded.Length % 8) != 0)
+ padded.Append(new string('0', 8 - (padded.Length % 8)));
+ while (padded.Length < dataLength)
+ padded.Append("1110110000010001");
+ if (padded.Length > dataLength)
+ padded.Length = dataLength;
+ return padded.ToString();
+ }
+
+ private static List CreateCodewordBlocks(string bitString, EccInfo eccInfo)
+ {
var codeWordWithECC = new List(eccInfo.BlocksInGroup1 + eccInfo.BlocksInGroup2);
- for (var i = 0; i < eccInfo.BlocksInGroup1; i++)
- {
- var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup1 * 8, eccInfo.CodewordsInGroup1 * 8);
- var bitBlockList = BinaryStringToBitBlockList(bitStr);
- var bitBlockListDec = BinaryStringListToDecList(bitBlockList);
- var eccWordList = CalculateECCWords(bitStr, eccInfo);
- var eccWordListDec = BinaryStringListToDecList(eccWordList);
- codeWordWithECC.Add(
- new CodewordBlock(1,
- i + 1,
- bitStr,
- bitBlockList,
- eccWordList,
- bitBlockListDec,
- eccWordListDec)
- );
- }
- bitString = bitString.Substring(eccInfo.BlocksInGroup1 * eccInfo.CodewordsInGroup1 * 8);
- for (var i = 0; i < eccInfo.BlocksInGroup2; i++)
+ var offset = 0;
+ AddCodewordBlocks(codeWordWithECC, bitString, eccInfo.BlocksInGroup1, eccInfo.CodewordsInGroup1, 1, ref offset, eccInfo);
+ AddCodewordBlocks(codeWordWithECC, bitString, eccInfo.BlocksInGroup2, eccInfo.CodewordsInGroup2, 2, ref offset, eccInfo);
+ return codeWordWithECC;
+ }
+
+ private static void AddCodewordBlocks(List codeWordWithECC, string bitString, int blockCount, int codewordsInBlock, int group, ref int offset, EccInfo eccInfo)
+ {
+ for (var i = 0; i < blockCount; i++)
{
- var bitStr = bitString.Substring(i * eccInfo.CodewordsInGroup2 * 8, eccInfo.CodewordsInGroup2 * 8);
- var bitBlockList = BinaryStringToBitBlockList(bitStr);
- var bitBlockListDec = BinaryStringListToDecList(bitBlockList);
- var eccWordList = CalculateECCWords(bitStr, eccInfo);
- var eccWordListDec = BinaryStringListToDecList(eccWordList);
- codeWordWithECC.Add(new CodewordBlock(2,
- i + 1,
- bitStr,
- bitBlockList,
- eccWordList,
- bitBlockListDec,
- eccWordListDec)
- );
+ var blockBitString = bitString.Substring(offset, codewordsInBlock * 8);
+ offset += codewordsInBlock * 8;
+ var bitBlockList = BinaryStringToBitBlockList(blockBitString);
+ var eccWordList = CalculateECCWords(blockBitString, eccInfo);
+ codeWordWithECC.Add(new CodewordBlock(group, i + 1, blockBitString, bitBlockList, eccWordList, BinaryStringListToDecList(bitBlockList), BinaryStringListToDecList(eccWordList)));
}
+ }
- //Interleave code words
+ private static string InterleaveCodewords(List codeWordWithECC, EccInfo eccInfo, int version)
+ {
var interleavedWordsSb = new StringBuilder();
for (var i = 0; i < Math.Max(eccInfo.CodewordsInGroup1, eccInfo.CodewordsInGroup2); i++)
{
- foreach (var codeBlock in codeWordWithECC)
- if (codeBlock.CodeWords.Count > i)
- interleavedWordsSb.Append(codeBlock.CodeWords[i]);
+ foreach (var codeWord in codeWordWithECC.Select(codeBlock => codeBlock.CodeWords).Where(codeWords => codeWords.Count > i).Select(codeWords => codeWords[i]))
+ interleavedWordsSb.Append(codeWord);
}
for (var i = 0; i < eccInfo.EccPerBlock; i++)
{
- foreach (var codeBlock in codeWordWithECC)
- if (codeBlock.ECCWords.Count > i)
- interleavedWordsSb.Append(codeBlock.ECCWords[i]);
+ foreach (var eccWord in codeWordWithECC.Select(codeBlock => codeBlock.ECCWords).Where(eccWords => eccWords.Count > i).Select(eccWords => eccWords[i]))
+ interleavedWordsSb.Append(eccWord);
}
+
interleavedWordsSb.Append(new string('0', remainderBits[version - 1]));
- var interleavedData = interleavedWordsSb.ToString();
+ return interleavedWordsSb.ToString();
+ }
- //Place interleaved data on module matrix
+ private static QRCodeData PlaceModules(int version, ECCLevel eccLevel, string interleavedData)
+ {
var qr = new QRCodeData(version);
var blockedModules = new List();
ModulePlacer.PlaceFinderPatterns(ref qr, ref blockedModules);
ModulePlacer.ReserveSeperatorAreas(qr.ModuleMatrix.Count, ref blockedModules);
- ModulePlacer.PlaceAlignmentPatterns(ref qr, alignmentPatternTable.Where(x => x.Version == version).Select(x => x.PatternPositions).First(), ref blockedModules);
+ ModulePlacer.PlaceAlignmentPatterns(ref qr, alignmentPatternTable.First(x => x.Version == version).PatternPositions, ref blockedModules);
ModulePlacer.PlaceTimingPatterns(ref qr, ref blockedModules);
ModulePlacer.PlaceDarkModule(ref qr, version, ref blockedModules);
ModulePlacer.ReserveVersionAreas(qr.ModuleMatrix.Count, version, ref blockedModules);
ModulePlacer.PlaceDataWords(ref qr, interleavedData, ref blockedModules);
var maskVersion = ModulePlacer.MaskCode(ref qr, version, ref blockedModules, eccLevel);
- var formatStr = GetFormatString(eccLevel, maskVersion);
-
- ModulePlacer.PlaceFormat(ref qr, formatStr);
+ ModulePlacer.PlaceFormat(ref qr, GetFormatString(eccLevel, maskVersion));
if (version >= 7)
- {
- var versionString = GetVersionString(version);
- ModulePlacer.PlaceVersion(ref qr, versionString);
- }
-
+ ModulePlacer.PlaceVersion(ref qr, GetVersionString(version));
ModulePlacer.AddQuietZone(ref qr);
return qr;
}
@@ -301,22 +289,7 @@ private static string GetFormatString(ECCLevel level, int maskVersion)
var generator = "10100110111";
var fStrMask = "101010000010010";
- var fStr = string.Empty;
- switch (level)
- {
- case ECCLevel.L:
- fStr = "01";
- break;
- case ECCLevel.M:
- fStr = "00";
- break;
- case ECCLevel.Q:
- fStr = "11";
- break;
- default:
- fStr = "10";
- break;
- }
+ var fStr = (level == ECCLevel.L) ? "01" : (level == ECCLevel.M) ? "00" : (level == ECCLevel.Q) ? "11" : "10";
fStr += DecToBin(maskVersion, 3);
var fStrEcc = fStr.PadRight(15, '0').TrimStart('0');
while (fStrEcc.Length > 10)
@@ -377,16 +350,13 @@ public static void AddQuietZone(ref QRCodeData qrCode)
}
}
- private static string ReverseString(string inp)
- {
- string newStr = string.Empty;
- if (inp.Length > 0)
- {
- for (int i = inp.Length - 1; i >= 0; i--)
- newStr += inp[i];
- }
- return newStr;
- }
+ private static string ReverseString(string inp)
+ {
+ var sb = new StringBuilder(inp.Length);
+ for (var i = inp.Length - 1; i >= 0; i--)
+ sb.Append(inp[i]);
+ return sb.ToString();
+ }
public static void PlaceVersion(ref QRCodeData qrCode, string versionStr)
{
@@ -522,32 +492,31 @@ public static void PlaceDataWords(ref QRCodeData qrCode, string data, ref List= 0)
+ for (var x = size - 1; x >= 0; x = x - 2)
{
- var currentX = x == 6 ? 5 : x;
+ if (x == 6)
+ x = 5;
for (var yMod = 1; yMod <= size; yMod++)
{
int y;
if (up)
{
y = size - yMod;
- if (datawords.Count > 0 && !IsBlocked(new SKRectI(currentX, y, 1, 1), blockedModules))
- qrCode.ModuleMatrix[y][currentX] = datawords.Dequeue();
- if (datawords.Count > 0 && currentX > 0 && !IsBlocked(new SKRectI(currentX - 1, y, 1, 1), blockedModules))
- qrCode.ModuleMatrix[y][currentX - 1] = datawords.Dequeue();
+ if (datawords.Count > 0 && !IsBlocked(new SKRectI(x, y, 1, 1), blockedModules))
+ qrCode.ModuleMatrix[y][x] = datawords.Dequeue();
+ if (datawords.Count > 0 && x > 0 && !IsBlocked(new SKRectI(x - 1, y, 1, 1), blockedModules))
+ qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue();
}
else
{
y = yMod - 1;
- if (datawords.Count > 0 && !IsBlocked(new SKRectI(currentX, y, 1, 1), blockedModules))
- qrCode.ModuleMatrix[y][currentX] = datawords.Dequeue();
- if (datawords.Count > 0 && currentX > 0 && !IsBlocked(new SKRectI(currentX - 1, y, 1, 1), blockedModules))
- qrCode.ModuleMatrix[y][currentX - 1] = datawords.Dequeue();
+ if (datawords.Count > 0 && !IsBlocked(new SKRectI(x, y, 1, 1), blockedModules))
+ qrCode.ModuleMatrix[y][x] = datawords.Dequeue();
+ if (datawords.Count > 0 && x > 0 && !IsBlocked(new SKRectI(x - 1, y, 1, 1), blockedModules))
+ qrCode.ModuleMatrix[y][x - 1] = datawords.Dequeue();
}
}
up = !up;
- x = currentX - 2;
}
}
@@ -610,22 +579,13 @@ public static void PlaceFinderPatterns(ref QRCodeData qrCode, ref List
}
}
- public static void PlaceAlignmentPatterns(ref QRCodeData qrCode, List alignmentPatternLocations, ref List blockedModules)
+ public static void PlaceAlignmentPatterns(ref QRCodeData qrCode, List alignmentPatternLocations, ref List blockedModules)
+ {
+ foreach (var loc in alignmentPatternLocations)
{
- foreach (var loc in alignmentPatternLocations)
- {
- var alignmentPatternRect = new SKRectI(loc.X, loc.Y, 5, 5);
- var blocked = false;
- foreach (var blockedRect in blockedModules)
- {
- if (Intersects(alignmentPatternRect, blockedRect))
- {
- blocked = true;
- break;
- }
- }
- if (blocked)
- continue;
+ var alignmentPatternRect = new SKRectI(loc.X, loc.Y, 5, 5);
+ if (blockedModules.Any(blockedRect => Intersects(alignmentPatternRect, blockedRect)))
+ continue;
for (var x = 0; x < 5; x++)
{
@@ -663,15 +623,10 @@ private static bool Intersects(SKRectI r1, SKRectI r2)
return r2.X < r1.X + r1.Width && r1.X < r2.X + r2.Width && r2.Y < r1.Y + r1.Height && r1.Y < r2.Y + r2.Height;
}
- private static bool IsBlocked(SKRectI r1, List blockedModules)
- {
- foreach (var blockedMod in blockedModules)
- {
- if (Intersects(blockedMod, r1))
- return true;
- }
- return false;
- }
+ private static bool IsBlocked(SKRectI r1, List blockedModules)
+ {
+ return blockedModules.Any(blockedMod => Intersects(blockedMod, r1));
+ }
private static class MaskPattern
{
@@ -717,44 +672,43 @@ public static bool Pattern8(int x, int y)
public static int Score(ref QRCodeData qrCode)
{
- int score1 = 0,
- score2 = 0,
- score3 = 0,
- score4 = 0;
var size = qrCode.ModuleMatrix.Count;
+ return ScoreLines(qrCode, size) + ScoreBlocks(qrCode, size) + ScoreFinderPatterns(qrCode, size) + ScoreBalance(qrCode, size);
+ }
- //Penalty 1
+ private static int ScoreLines(QRCodeData qrCode, int size)
+ {
+ var score = 0;
for (var y = 0; y < size; y++)
{
- var modInRow = 0;
- var modInColumn = 0;
- var lastValRow = qrCode.ModuleMatrix[y][0];
- var lastValColumn = qrCode.ModuleMatrix[0][y];
- for (var x = 0; x < size; x++)
- {
- if (qrCode.ModuleMatrix[y][x] == lastValRow)
- modInRow++;
- else
- modInRow = 1;
- if (modInRow == 5)
- score1 += 3;
- else if (modInRow > 5)
- score1++;
- lastValRow = qrCode.ModuleMatrix[y][x];
-
- if (qrCode.ModuleMatrix[x][y] == lastValColumn)
- modInColumn++;
- else
- modInColumn = 1;
- if (modInColumn == 5)
- score1 += 3;
- else if (modInColumn > 5)
- score1++;
- lastValColumn = qrCode.ModuleMatrix[x][y];
- }
+ score += ScoreLine(qrCode.ModuleMatrix[y].Cast().ToList());
+ score += ScoreLine(qrCode.ModuleMatrix.Select(row => row[y]).ToList());
}
+ return score;
+ }
+
+ private static int ScoreLine(IReadOnlyList line)
+ {
+ var score = 0;
+ var runLength = 1;
+ for (var i = 1; i < line.Count; i++)
+ {
+ if (line[i] == line[i - 1])
+ runLength++;
+ else
+ runLength = 1;
+
+ if (runLength == 5)
+ score += 3;
+ else if (runLength > 5)
+ score++;
+ }
+ return score;
+ }
- //Penalty 2
+ private static int ScoreBlocks(QRCodeData qrCode, int size)
+ {
+ var score = 0;
for (var y = 0; y < size - 1; y++)
{
for (var x = 0; x < size - 1; x++)
@@ -762,284 +716,114 @@ public static int Score(ref QRCodeData qrCode)
if (qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y][x + 1] &&
qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x] &&
qrCode.ModuleMatrix[y][x] == qrCode.ModuleMatrix[y + 1][x + 1])
- score2 += 3;
+ score += 3;
}
}
+ return score;
+ }
- //Penalty 3
+ private static int ScoreFinderPatterns(QRCodeData qrCode, int size)
+ {
+ var score = 0;
for (var y = 0; y < size; y++)
{
for (var x = 0; x < size - 10; x++)
{
- if ((qrCode.ModuleMatrix[y][x] &&
- !qrCode.ModuleMatrix[y][x + 1] &&
- qrCode.ModuleMatrix[y][x + 2] &&
- qrCode.ModuleMatrix[y][x + 3] &&
- qrCode.ModuleMatrix[y][x + 4] &&
- !qrCode.ModuleMatrix[y][x + 5] &&
- qrCode.ModuleMatrix[y][x + 6] &&
- !qrCode.ModuleMatrix[y][x + 7] &&
- !qrCode.ModuleMatrix[y][x + 8] &&
- !qrCode.ModuleMatrix[y][x + 9] &&
- !qrCode.ModuleMatrix[y][x + 10]) ||
- (!qrCode.ModuleMatrix[y][x] &&
- !qrCode.ModuleMatrix[y][x + 1] &&
- !qrCode.ModuleMatrix[y][x + 2] &&
- !qrCode.ModuleMatrix[y][x + 3] &&
- qrCode.ModuleMatrix[y][x + 4] &&
- !qrCode.ModuleMatrix[y][x + 5] &&
- qrCode.ModuleMatrix[y][x + 6] &&
- qrCode.ModuleMatrix[y][x + 7] &&
- qrCode.ModuleMatrix[y][x + 8] &&
- !qrCode.ModuleMatrix[y][x + 9] &&
- qrCode.ModuleMatrix[y][x + 10]))
- {
- score3 += 40;
- }
-
- if ((qrCode.ModuleMatrix[x][y] &&
- !qrCode.ModuleMatrix[x + 1][y] &&
- qrCode.ModuleMatrix[x + 2][y] &&
- qrCode.ModuleMatrix[x + 3][y] &&
- qrCode.ModuleMatrix[x + 4][y] &&
- !qrCode.ModuleMatrix[x + 5][y] &&
- qrCode.ModuleMatrix[x + 6][y] &&
- !qrCode.ModuleMatrix[x + 7][y] &&
- !qrCode.ModuleMatrix[x + 8][y] &&
- !qrCode.ModuleMatrix[x + 9][y] &&
- !qrCode.ModuleMatrix[x + 10][y]) ||
- (!qrCode.ModuleMatrix[x][y] &&
- !qrCode.ModuleMatrix[x + 1][y] &&
- !qrCode.ModuleMatrix[x + 2][y] &&
- !qrCode.ModuleMatrix[x + 3][y] &&
- qrCode.ModuleMatrix[x + 4][y] &&
- !qrCode.ModuleMatrix[x + 5][y] &&
- qrCode.ModuleMatrix[x + 6][y] &&
- qrCode.ModuleMatrix[x + 7][y] &&
- qrCode.ModuleMatrix[x + 8][y] &&
- !qrCode.ModuleMatrix[x + 9][y] &&
- qrCode.ModuleMatrix[x + 10][y]))
- {
- score3 += 40;
- }
+ if (MatchesFinderPattern(qrCode, x, y))
+ score += 40;
}
}
- //Penalty 4
- double blackModules = 0;
- foreach (var row in qrCode.ModuleMatrix)
- foreach (bool bit in row)
- if (bit)
- blackModules++;
-
- var percent = (blackModules / (qrCode.ModuleMatrix.Count * qrCode.ModuleMatrix.Count)) * 100;
- var prevMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5) * 5 - 50) / 5;
- var nextMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5) * 5 - 45) / 5;
- score4 = Math.Min(prevMultipleOf5, nextMultipleOf5) * 10;
+ for (var x = 0; x < size - 10; x++)
+ {
+ for (var y = 0; y < size; y++)
+ {
+ if (MatchesFinderPattern(qrCode, x, y, vertical: true))
+ score += 40;
+ }
+ }
- return score1 + score2 + score3 + score4;
+ return score;
}
- }
- }
-
- private static List CalculateECCWords(string bitString, EccInfo eccInfo)
- {
- var eccWords = eccInfo.EccPerBlock;
- var messagePolynom = CalculateMessagePolynom(bitString);
- var generatorPolynom = CalculateGeneratorPolynom(eccWords);
-
- for (var index = 0; index < messagePolynom.PolyItems.Count; index++)
- messagePolynom.PolyItems[index] = new PolynomItem(messagePolynom.PolyItems[index].Coefficient,
- messagePolynom.PolyItems[index].Exponent + eccWords);
- for (var index = 0; index < generatorPolynom.PolyItems.Count; index++)
- generatorPolynom.PolyItems[index] = new PolynomItem(generatorPolynom.PolyItems[index].Coefficient,
- generatorPolynom.PolyItems[index].Exponent + (messagePolynom.PolyItems.Count - 1));
-
- var leadTermSource = messagePolynom;
- var i = 0;
- while (leadTermSource.PolyItems.Count > 0 && leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent > 0)
- {
- if (leadTermSource.PolyItems[0].Coefficient == 0)
+ private static bool MatchesFinderPattern(QRCodeData qrCode, int x, int y, bool vertical = false)
{
- leadTermSource.PolyItems.RemoveAt(0);
- leadTermSource.PolyItems.Add(new PolynomItem(0, leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent - 1));
+ if (vertical)
+ {
+ return (qrCode.ModuleMatrix[x][y] &&
+ !qrCode.ModuleMatrix[x + 1][y] &&
+ qrCode.ModuleMatrix[x + 2][y] &&
+ qrCode.ModuleMatrix[x + 3][y] &&
+ qrCode.ModuleMatrix[x + 4][y] &&
+ !qrCode.ModuleMatrix[x + 5][y] &&
+ qrCode.ModuleMatrix[x + 6][y] &&
+ !qrCode.ModuleMatrix[x + 7][y] &&
+ !qrCode.ModuleMatrix[x + 8][y] &&
+ !qrCode.ModuleMatrix[x + 9][y] &&
+ !qrCode.ModuleMatrix[x + 10][y]) ||
+ (!qrCode.ModuleMatrix[x][y] &&
+ !qrCode.ModuleMatrix[x + 1][y] &&
+ !qrCode.ModuleMatrix[x + 2][y] &&
+ !qrCode.ModuleMatrix[x + 3][y] &&
+ qrCode.ModuleMatrix[x + 4][y] &&
+ !qrCode.ModuleMatrix[x + 5][y] &&
+ qrCode.ModuleMatrix[x + 6][y] &&
+ qrCode.ModuleMatrix[x + 7][y] &&
+ qrCode.ModuleMatrix[x + 8][y] &&
+ !qrCode.ModuleMatrix[x + 9][y] &&
+ qrCode.ModuleMatrix[x + 10][y]);
+ }
+
+ return (qrCode.ModuleMatrix[y][x] &&
+ !qrCode.ModuleMatrix[y][x + 1] &&
+ qrCode.ModuleMatrix[y][x + 2] &&
+ qrCode.ModuleMatrix[y][x + 3] &&
+ qrCode.ModuleMatrix[y][x + 4] &&
+ !qrCode.ModuleMatrix[y][x + 5] &&
+ qrCode.ModuleMatrix[y][x + 6] &&
+ !qrCode.ModuleMatrix[y][x + 7] &&
+ !qrCode.ModuleMatrix[y][x + 8] &&
+ !qrCode.ModuleMatrix[y][x + 9] &&
+ !qrCode.ModuleMatrix[y][x + 10]) ||
+ (!qrCode.ModuleMatrix[y][x] &&
+ !qrCode.ModuleMatrix[y][x + 1] &&
+ !qrCode.ModuleMatrix[y][x + 2] &&
+ !qrCode.ModuleMatrix[y][x + 3] &&
+ qrCode.ModuleMatrix[y][x + 4] &&
+ !qrCode.ModuleMatrix[y][x + 5] &&
+ qrCode.ModuleMatrix[y][x + 6] &&
+ qrCode.ModuleMatrix[y][x + 7] &&
+ qrCode.ModuleMatrix[y][x + 8] &&
+ !qrCode.ModuleMatrix[y][x + 9] &&
+ qrCode.ModuleMatrix[y][x + 10]);
}
- else
+
+ private static int ScoreBalance(QRCodeData qrCode, int size)
{
- var resPoly = MultiplyGeneratorPolynomByLeadterm(generatorPolynom, ConvertToAlphaNotation(leadTermSource).PolyItems[0], i);
- resPoly = ConvertToDecNotation(resPoly);
- resPoly = XORPolynoms(leadTermSource, resPoly);
- leadTermSource = resPoly;
+ var blackModules = qrCode.ModuleMatrix.Sum(row => row.Cast().Count(x => x));
+ var percent = ((double)blackModules / (size * size)) * 100;
+ var prevMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5d) * 5 - 50) / 5;
+ var nextMultipleOf5 = Math.Abs((int)Math.Floor(percent / 5d) * 5 - 45) / 5;
+ return Math.Min(prevMultipleOf5, nextMultipleOf5) * 10;
}
- i++;
- }
- return leadTermSource.PolyItems.Select(x => DecToBin(x.Coefficient, 8)).ToList();
- }
- private static Polynom ConvertToAlphaNotation(Polynom poly)
- {
- var newPoly = new Polynom();
- for (var i = 0; i < poly.PolyItems.Count; i++)
- newPoly.PolyItems.Add(
- new PolynomItem(
- (poly.PolyItems[i].Coefficient != 0
- ? GetAlphaExpFromIntVal(poly.PolyItems[i].Coefficient)
- : 0), poly.PolyItems[i].Exponent));
- return newPoly;
- }
-
- private static Polynom ConvertToDecNotation(Polynom poly)
- {
- var newPoly = new Polynom();
- for (var i = 0; i < poly.PolyItems.Count; i++)
- newPoly.PolyItems.Add(new PolynomItem(GetIntValFromAlphaExp(poly.PolyItems[i].Coefficient), poly.PolyItems[i].Exponent));
- return newPoly;
- }
-
- private static int GetVersion(int length, EncodingMode encMode, ECCLevel eccLevel)
- {
- var fittingVersions = capacityTable.Where(
- x => x.Details.Any(
- y => (y.ErrorCorrectionLevel == eccLevel
- && y.CapacityDict[encMode] >= Convert.ToInt32(length)
- )
- )
- ).Select(x => new
- {
- version = x.Version,
- capacity = x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel)
- .CapacityDict[encMode]
- });
-
- if (fittingVersions.Any())
- return fittingVersions.Min(x => x.version);
-
- var maxSizeByte = capacityTable.Where(
- x => x.Details.Any(
- y => (y.ErrorCorrectionLevel == eccLevel))
- ).Max(x => x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel).CapacityDict[encMode]);
- throw new DataTooLongException(eccLevel.ToString(), encMode.ToString(), maxSizeByte);
- }
-
- private static EncodingMode GetEncodingFromPlaintext(string plainText, bool forceUtf8)
- {
- if (forceUtf8) return EncodingMode.Byte;
- EncodingMode result = EncodingMode.Numeric; // assume numeric
- foreach (char c in plainText)
- {
- if (IsInRange(c, '0', '9')) continue; // numeric - char.IsDigit() for Latin1
- result = EncodingMode.Alphanumeric; // not numeric, assume alphanumeric
- if (IsInRange(c, 'A', 'Z') || alphanumEncTable.Contains(c)) continue; // alphanumeric
- return EncodingMode.Byte; // not numeric or alphanumeric, assume byte
- }
- return result; // either numeric or alphanumeric
- }
-
- private static bool IsInRange(char c, char min, char max)
- {
- return (uint)(c - min) <= (uint)(max - min);
- }
-
- private static Polynom CalculateMessagePolynom(string bitString)
- {
- var messagePol = new Polynom();
- for (var i = bitString.Length / 8 - 1; i >= 0; i--)
- {
- messagePol.PolyItems.Add(new PolynomItem(BinToDec(bitString.Substring(0, 8)), i));
- bitString = bitString.Remove(0, 8);
- }
- return messagePol;
- }
-
- private static Polynom CalculateGeneratorPolynom(int numEccWords)
- {
- var generatorPolynom = new Polynom();
- generatorPolynom.PolyItems.AddRange(new[]{
- new PolynomItem(0,1),
- new PolynomItem(0,0)
- });
- for (var i = 1; i <= numEccWords - 1; i++)
- {
- var multiplierPolynom = new Polynom();
- multiplierPolynom.PolyItems.AddRange(new[]{
- new PolynomItem(0,1),
- new PolynomItem(i,0)
- });
-
- generatorPolynom = MultiplyAlphaPolynoms(generatorPolynom, multiplierPolynom);
- }
-
- return generatorPolynom;
- }
-
- private static List BinaryStringToBitBlockList(string bitString)
- {
- const int blockSize = 8;
- var numberOfBlocks = (int)Math.Ceiling(bitString.Length / (double)blockSize);
- var blocklist = new List(numberOfBlocks);
-
- for (int i = 0; i < bitString.Length; i += blockSize)
- {
- blocklist.Add(bitString.Substring(i, blockSize));
}
-
- return blocklist;
}
- private static List BinaryStringListToDecList(List binaryStringList)
- {
- return binaryStringList.Select(binaryString => BinToDec(binaryString)).ToList();
- }
-
- private static int BinToDec(string binStr)
- {
- return Convert.ToInt32(binStr, 2);
- }
-
- private static string DecToBin(int decNum)
- {
- return Convert.ToString(decNum, 2);
- }
-
- private static string DecToBin(int decNum, int padLeftUpTo)
- {
- var binStr = DecToBin(decNum);
- return binStr.PadLeft(padLeftUpTo, '0');
- }
private static int GetCountIndicatorLength(int version, EncodingMode encMode)
{
- if (version < 10)
- {
- if (encMode == EncodingMode.Numeric)
- return 10;
- else if (encMode == EncodingMode.Alphanumeric)
- return 9;
- else
- return 8;
- }
- else if (version < 27)
- {
- if (encMode == EncodingMode.Numeric)
- return 12;
- else if (encMode == EncodingMode.Alphanumeric)
- return 11;
- else if (encMode == EncodingMode.Byte)
- return 16;
- else
- return 10;
- }
- else
+ var versionGroup = version < 10 ? 0 : version < 27 ? 1 : 2;
+ switch (encMode)
{
- if (encMode == EncodingMode.Numeric)
- return 14;
- else if (encMode == EncodingMode.Alphanumeric)
- return 13;
- else if (encMode == EncodingMode.Byte)
- return 16;
- else
- return 12;
+ case EncodingMode.Numeric:
+ return new[] { 10, 12, 14 }[versionGroup];
+ case EncodingMode.Alphanumeric:
+ return new[] { 9, 11, 13 }[versionGroup];
+ case EncodingMode.Byte:
+ return new[] { 8, 16, 16 }[versionGroup];
+ default:
+ return new[] { 8, 10, 12 }[versionGroup];
}
}
@@ -1143,6 +927,171 @@ private static string PlainTextToBinaryByte(string plainText, EciMode eciMode, b
return codeText;
}
+ private static Polynom ConvertToAlphaNotation(Polynom poly)
+ {
+ var newPoly = new Polynom();
+ for (var i = 0; i < poly.PolyItems.Count; i++)
+ newPoly.PolyItems.Add(
+ new PolynomItem(
+ poly.PolyItems[i].Coefficient != 0 ? GetAlphaExpFromIntVal(poly.PolyItems[i].Coefficient) : 0,
+ poly.PolyItems[i].Exponent));
+ return newPoly;
+ }
+
+ private static Polynom ConvertToDecNotation(Polynom poly)
+ {
+ var newPoly = new Polynom();
+ for (var i = 0; i < poly.PolyItems.Count; i++)
+ newPoly.PolyItems.Add(new PolynomItem(GetIntValFromAlphaExp(poly.PolyItems[i].Coefficient), poly.PolyItems[i].Exponent));
+ return newPoly;
+ }
+
+ private static Polynom CalculateMessagePolynom(string bitString)
+ {
+ var messagePol = new Polynom();
+ for (var i = bitString.Length / 8 - 1; i >= 0; i--)
+ {
+ messagePol.PolyItems.Add(new PolynomItem(BinToDec(bitString.Substring(0, 8)), i));
+ bitString = bitString.Remove(0, 8);
+ }
+ return messagePol;
+ }
+
+ private static Polynom CalculateGeneratorPolynom(int numEccWords)
+ {
+ var generatorPolynom = new Polynom();
+ generatorPolynom.PolyItems.AddRange(new[]
+ {
+ new PolynomItem(0, 1),
+ new PolynomItem(0, 0)
+ });
+ for (var i = 1; i <= numEccWords - 1; i++)
+ {
+ var multiplierPolynom = new Polynom();
+ multiplierPolynom.PolyItems.AddRange(new[]
+ {
+ new PolynomItem(0, 1),
+ new PolynomItem(i, 0)
+ });
+
+ generatorPolynom = MultiplyAlphaPolynoms(generatorPolynom, multiplierPolynom);
+ }
+
+ return generatorPolynom;
+ }
+
+ private static List BinaryStringToBitBlockList(string bitString)
+ {
+ const int blockSize = 8;
+ var numberOfBlocks = (int)Math.Ceiling(bitString.Length / (double)blockSize);
+ var blocklist = new List(numberOfBlocks);
+
+ for (int i = 0; i < bitString.Length; i += blockSize)
+ {
+ blocklist.Add(bitString.Substring(i, blockSize));
+ }
+
+ return blocklist;
+ }
+
+ private static List BinaryStringListToDecList(List binaryStringList)
+ {
+ return binaryStringList.Select(binaryString => BinToDec(binaryString)).ToList();
+ }
+
+ private static List CalculateECCWords(string bitString, EccInfo eccInfo)
+ {
+ var eccWords = eccInfo.EccPerBlock;
+ var messagePolynom = CalculateMessagePolynom(bitString);
+ var generatorPolynom = CalculateGeneratorPolynom(eccWords);
+
+ for (var i = 0; i < messagePolynom.PolyItems.Count; i++)
+ messagePolynom.PolyItems[i] = new PolynomItem(messagePolynom.PolyItems[i].Coefficient,
+ messagePolynom.PolyItems[i].Exponent + eccWords);
+
+ for (var i = 0; i < generatorPolynom.PolyItems.Count; i++)
+ generatorPolynom.PolyItems[i] = new PolynomItem(generatorPolynom.PolyItems[i].Coefficient,
+ generatorPolynom.PolyItems[i].Exponent + (messagePolynom.PolyItems.Count - 1));
+
+ var leadTermSource = messagePolynom;
+ for (var i = 0; (leadTermSource.PolyItems.Count > 0 && leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent > 0); i++)
+ {
+ if (leadTermSource.PolyItems[0].Coefficient == 0)
+ {
+ leadTermSource.PolyItems.RemoveAt(0);
+ leadTermSource.PolyItems.Add(new PolynomItem(0, leadTermSource.PolyItems[leadTermSource.PolyItems.Count - 1].Exponent - 1));
+ }
+ else
+ {
+ var resPoly = MultiplyGeneratorPolynomByLeadterm(generatorPolynom, ConvertToAlphaNotation(leadTermSource).PolyItems[0], i);
+ resPoly = ConvertToDecNotation(resPoly);
+ resPoly = XORPolynoms(leadTermSource, resPoly);
+ leadTermSource = resPoly;
+ }
+ }
+ return leadTermSource.PolyItems.Select(x => DecToBin(x.Coefficient, 8)).ToList();
+ }
+
+ private static int BinToDec(string binStr)
+ {
+ return Convert.ToInt32(binStr, 2);
+ }
+
+ private static string DecToBin(int decNum)
+ {
+ return Convert.ToString(decNum, 2);
+ }
+
+ private static string DecToBin(int decNum, int padLeftUpTo)
+ {
+ var binStr = DecToBin(decNum);
+ return binStr.PadLeft(padLeftUpTo, '0');
+ }
+
+ private static int GetVersion(int length, EncodingMode encMode, ECCLevel eccLevel)
+ {
+ var fittingVersions = capacityTable.Where(
+ x => x.Details.Any(
+ y => (y.ErrorCorrectionLevel == eccLevel
+ && y.CapacityDict[encMode] >= Convert.ToInt32(length)
+ )
+ )
+ ).Select(x => new
+ {
+ version = x.Version,
+ capacity = x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel)
+ .CapacityDict[encMode]
+ });
+
+ if (fittingVersions.Any())
+ return fittingVersions.Min(x => x.version);
+
+ var maxSizeByte = capacityTable.Where(
+ x => x.Details.Any(
+ y => (y.ErrorCorrectionLevel == eccLevel))
+ ).Max(x => x.Details.Single(y => y.ErrorCorrectionLevel == eccLevel).CapacityDict[encMode]);
+ throw new DataTooLongException(eccLevel.ToString(), encMode.ToString(), maxSizeByte);
+ }
+
+ private static EncodingMode GetEncodingFromPlaintext(string plainText, bool forceUtf8)
+ {
+ if (forceUtf8) return EncodingMode.Byte;
+ EncodingMode result = EncodingMode.Numeric;
+ foreach (char c in plainText)
+ {
+ if (IsInRange(c, '0', '9')) continue;
+ result = EncodingMode.Alphanumeric;
+ if (IsInRange(c, 'A', 'Z') || alphanumEncTable.Contains(c)) continue;
+ return EncodingMode.Byte;
+ }
+ return result;
+ }
+
+ private static bool IsInRange(char c, char min, char max)
+ {
+ return (uint)(c - min) <= (uint)(max - min);
+ }
+
private static Polynom XORPolynoms(Polynom messagePolynom, Polynom resPolynom)
{
var resultPolynom = new Polynom();
@@ -1256,31 +1205,32 @@ private static List CreateAlignmentPatternTable()
for (var i = 0; i < (7 * 40); i = i + 7)
{
- var points = new List();
- for (var x = 0; x < 7; x++)
+ localAlignmentPatternTable.Add(new AlignmentPattern
{
- if (alignmentPatternBaseValues[i + x] != 0)
- {
- for (var y = 0; y < 7; y++)
- {
- if (alignmentPatternBaseValues[i + y] != 0)
- {
- var p = new Point(alignmentPatternBaseValues[i + x] - 2, alignmentPatternBaseValues[i + y] - 2);
- if (!points.Contains(p))
- points.Add(p);
- }
- }
- }
- }
+ Version = (i + 7) / 7,
+ PatternPositions = CreateAlignmentPatternPoints(i)
+ });
+ }
+ return localAlignmentPatternTable;
+ }
- localAlignmentPatternTable.Add(new AlignmentPattern()
+ private static List CreateAlignmentPatternPoints(int offset)
+ {
+ var points = new List();
+ for (var x = 0; x < 7; x++)
+ {
+ if (alignmentPatternBaseValues[offset + x] == 0)
+ continue;
+ for (var y = 0; y < 7; y++)
{
- Version = (i + 7) / 7,
- PatternPositions = points
+ if (alignmentPatternBaseValues[offset + y] == 0)
+ continue;
+ var point = new Point(alignmentPatternBaseValues[offset + x] - 2, alignmentPatternBaseValues[offset + y] - 2);
+ if (!points.Contains(point))
+ points.Add(point);
}
- );
}
- return localAlignmentPatternTable;
+ return points;
}
private static List CreateCapacityECCTable()
@@ -1599,12 +1549,7 @@ public SKRectI(int x, int y, int w, int h)
///
public void Dispose()
{
- if (this.disposed)
- {
- return;
- }
-
- this.disposed = true;
+ GC.SuppressFinalize(this);
}
}
}