Skip to content

Commit

Permalink
Merge pull request #207 from barnhill/UPC-E-fix
Browse files Browse the repository at this point in the history
UPC-E fix
  • Loading branch information
barnhill authored Jun 16, 2024
2 parents ce4628d + 19b4fbd commit 6ed8ac9
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 70 deletions.
6 changes: 3 additions & 3 deletions BarcodeStandard/BarcodeStandard.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>3.1.2</Version>
<Version>3.1.3</Version>
<PackageId>BarcodeLib</PackageId>
<Company>Pnuema Productions</Company>
<Product>BarcodeLib</Product>
Expand All @@ -18,8 +18,8 @@
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageIcon>upca.jpg</PackageIcon>
<PackageIconUrl />
<AssemblyVersion>3.1.2.0</AssemblyVersion>
<FileVersion>3.1.2.0</FileVersion>
<AssemblyVersion>3.1.3.0</AssemblyVersion>
<FileVersion>3.1.3.0</FileVersion>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<SignAssembly>true</SignAssembly>
Expand Down
229 changes: 162 additions & 67 deletions BarcodeStandard/Symbologies/UPCE.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Text;

namespace BarcodeStandard.Symbologies
{
Expand All @@ -10,7 +12,6 @@ internal class UPCE : BarcodeCommon, IBarcode
{
private readonly string[] EAN_Code_A = { "0001101", "0011001", "0010011", "0111101", "0100011", "0110001", "0101111", "0111011", "0110111", "0001011" };
private readonly string[] EAN_Code_B = { "0100111", "0110011", "0011011", "0100001", "0011101", "0111001", "0000101", "0010001", "0001001", "0010111" };
private readonly string[] EAN_Pattern = { "aaaaaa", "aababb", "aabbab", "aabbba", "abaabb", "abbaab", "abbbaa", "ababab", "ababba", "abbaba" };
private readonly string[] UPC_E_Code0 = { "bbbaaa", "bbabaa", "bbaaba", "bbaaab", "babbaa", "baabba", "baaabb", "bababa", "babaab", "baabab" };
private readonly string[] UPC_E_Code1 = { "aaabbb", "aababb", "aabbab", "aabbba", "abaabb", "abbaab", "abbbaa", "ababab", "ababba", "abbaba" };

Expand All @@ -27,93 +28,187 @@ internal UPCE(string input)
/// </summary>
private string Encode_UPCE()
{
if (RawData.Length != 6 && RawData.Length != 8 && RawData.Length != 12)
Error("EUPCE-1: Invalid data length. (8 or 12 numbers only)");
if (RawData.Length != 6 && RawData.Length != 8 && RawData.Length != 12)
{
Error("EUPCE-1: Invalid data length. (6, 8 or 12 numbers only)");
}

if (!IsNumericOnly(RawData))
Error("EUPCE-2: Numeric only.");
int numberSystem = 0;
//check numeric only
if (!IsNumericOnly(RawData))
{
Error("EUPCE-2: Numeric Data Only");
}

//check for a valid number system
var numberSystem = Int32.Parse(RawData[0].ToString());
if (numberSystem != 0 && numberSystem != 1)
Error("EUPCE-3: Invalid Number System (only 0 & 1 are valid)");
if (RawData.Length == 8)
{
//strip check digit off to recalculate
RawData = RawData.Substring(1, 6);
}

var CheckDigit = Int32.Parse(RawData[RawData.Length - 1].ToString());

//Convert to UPC-E from UPC-A if necessary
if (RawData.Length == 12)
{
var UPCECode = "";

//break apart into components
var manufacturer = RawData.Substring(1, 5);
var productCode = RawData.Substring(6, 5);

if (manufacturer.EndsWith("000") || manufacturer.EndsWith("100") || manufacturer.EndsWith("200") && Int32.Parse(productCode) <= 999)
{
//rule 1
UPCECode += manufacturer.Substring(0, 2); //first two of manufacturer
UPCECode += productCode.Substring(2, 3); //last three of product
UPCECode += manufacturer[2].ToString(); //third of manufacturer
}//if
else if (manufacturer.EndsWith("00") && Int32.Parse(productCode) <= 99)
{
//rule 2
UPCECode += manufacturer.Substring(0, 3); //first three of manufacturer
UPCECode += productCode.Substring(3, 2); //last two of product
UPCECode += "3"; //number 3
}//else if
else if (manufacturer.EndsWith("0") && Int32.Parse(productCode) <= 9)
{
//rule 3
UPCECode += manufacturer.Substring(0, 4); //first four of manufacturer
UPCECode += productCode[4]; //last digit of product
UPCECode += "4"; //number 4
}//else if
else if (!manufacturer.EndsWith("0") && Int32.Parse(productCode) <= 9 && Int32.Parse(productCode) >= 5)
{
//rule 4
UPCECode += manufacturer; //manufacturer
UPCECode += productCode[4]; //last digit of product
}//else if
else
Error("EUPCE-4: Illegal UPC-A entered for conversion. Unable to convert.");
numberSystem = Int16.Parse(RawData[0].ToString());
RawData = convertUPCAToUPCE();
}

RawData = UPCECode;
}//if
int checkDigit = Int16.Parse(calculateCheckDigit(convertUPCEToUPCA(RawData)));

//get encoding pattern
var pattern = "";

if (numberSystem == 0) pattern = UPC_E_Code0[CheckDigit];
else pattern = UPC_E_Code1[CheckDigit];
String pattern = getPattern(checkDigit, numberSystem);

//encode the data
var result = "101";
StringBuilder result = new StringBuilder("101");

var pos = 0;
foreach (var c in pattern)
int pos = 0;
foreach (char c in pattern)
{
var i = Int32.Parse(RawData[pos++].ToString());
int i = Int16.Parse(RawData[pos++].ToString());
if (c == 'a')
{
result += EAN_Code_A[i];
}//if
result.Append(EAN_Code_A[i]);
}
else if (c == 'b')
{
result += EAN_Code_B[i];
}//else if
}//foreach

//guard bars
result += "01010";
result.Append(EAN_Code_B[i]);
}
}

//end bars
result += "1";
//end-guard bars
result.Append("010101");

return result;
return result.ToString();
}//Encode_UPCE

private String getPattern(int checkDigit, int numberSystem)
{
if (numberSystem != 0 && numberSystem != 1)
{
Error("EUPCE-3: Invalid Number System (only 0 & 1 are valid)");
}

String pattern;

if (numberSystem == 0)
{
pattern = UPC_E_Code0[checkDigit];
}
else
{
pattern = UPC_E_Code1[checkDigit];
}

return pattern;
}

private String convertUPCAToUPCE()
{
String UPCECode = "";

//break apart into components
String manufacturer = RawData.Substring(1, 5);
String productCode = RawData.Substring(6, 5);

int numericProductCode = Int32.Parse(productCode);

if ((manufacturer.EndsWith("000") || manufacturer.EndsWith("100") || manufacturer.EndsWith("200")) && numericProductCode <= 999)
{
//rule 1
UPCECode += manufacturer.Substring(0, 2); //first two of manufacturer
UPCECode += productCode.Substring(2, 3); //last three of product
UPCECode += manufacturer[2]; //third of manufacturer
}
else if (manufacturer.EndsWith("00") && numericProductCode <= 99)
{
//rule 2
UPCECode += manufacturer.Substring(0, 3); //first three of manufacturer
UPCECode += productCode.Substring(3, 2); //last two of product
UPCECode += "3"; //number 3
}
else if (manufacturer.EndsWith("0") && numericProductCode <= 9)
{
//rule 3
UPCECode += manufacturer.Substring(0, 4); //first four of manufacturer
UPCECode += productCode[4]; //last digit of product
UPCECode += "4"; //number 4
}
else if (!manufacturer.EndsWith("0") && numericProductCode <= 9 && numericProductCode >= 5)
{
//rule 4
UPCECode += manufacturer; //manufacturer
UPCECode += productCode[4]; //last digit of product
}
else
{
Error("EUPCE-4: Illegal UPC-A entered for conversion. Unable to convert.");
}

return UPCECode;
}

private String convertUPCEToUPCA(String UPCECode)
{
String UPCACode = "0";
if (UPCECode.EndsWith("0") || UPCECode.EndsWith("1") || UPCECode.EndsWith("2"))
{
//rule 1
UPCACode += UPCECode.Substring(0, 2) + UPCECode[5] + "00"; //manufacturer
UPCACode += "00" + UPCECode.Substring(2, 3); //product
}
else if (UPCECode.EndsWith("3"))
{
//rule 2
UPCACode += UPCECode.Substring(0, 3) + "00"; //manufacturer
UPCACode += "000" + UPCECode.Substring(3, 2); //product
}
else if (UPCECode.EndsWith("4"))
{
//rule 3
UPCACode += UPCECode.Substring(0, 4) + "0"; //manufacturer
UPCACode += "0000" + UPCECode[4]; //product
}
else
{
//rule 4
UPCACode += UPCECode.Substring(0, 5); //manufacturer
UPCACode += "0000" + UPCECode[5]; //product
}

return UPCACode;
}

private String calculateCheckDigit(String upcA)
{
int cs = 0;
try
{
//calculate check digit
int sum = 0;

for (int i = 0; i < upcA.Length; i++)
{
int parseInt = Int16.Parse(upcA.Substring(i, 1));
if (i % 2 == 0)
{
sum += parseInt * 3;
}
else
{
sum += parseInt;
}
}

cs = (10 - sum % 10) % 10;
}
catch (Exception ex)

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest)

The variable 'ex' is declared but never used

Check warning on line 204 in BarcodeStandard/Symbologies/UPCE.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest)

The variable 'ex' is declared but never used
{
Error("EUPCE-5: Error calculating check digit.");
}

return cs.ToString();
}

#region IBarcode Members

public string Encoded_Value => Encode_UPCE();
Expand Down
25 changes: 25 additions & 0 deletions BarcodeStandardTests/Symbologies/UpcETests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using BarcodeStandard;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BarcodeStandardTests.Symbologies
{
[TestClass]
public class UpcETests
{
private readonly Barcode _barcode = new()
{
EncodedType = Type.UpcE,
};

[DataTestMethod]
[DataRow("038000000216", "101010000101101110100111001001100110010100111010101")]
[DataRow("654321", "101000010101100010011101011110100110110011001010101")]
[DataRow("06543214", "101000010101100010011101011110100110110011001010101")]
[DataRow("065100004327", "101000010101100010011101011110100110110011001010101")]
public void EncodeBarcode(string data, string expected)
{
_barcode.Encode(data);
Assert.AreEqual(expected, _barcode.EncodedValue, $"{_barcode.EncodedType}");
}
}
}

0 comments on commit 6ed8ac9

Please sign in to comment.