using System.Collections.Generic;
namespace Infratab_Common
public static ulong Get(string hex, int start, int count)
result = BitFields.DoGet(hex, start, 56) << (count-56);
return result | BitFields.DoGet(hex, start, count);
private static ulong DoGet(string hex, int start, int count)
int haveBits = hex.Length * 4;
if (count > 56) throw new Exception("Bit field too long");
if (start >= haveBits || (start + count) > haveBits) throw new Exception("Hex string too short");
int firstByteIndex = start / 8;
byte firstByteMask = (byte)(0xff >> (start % 8));
int lastByteIndex = (start + count - 1) / 8;
int lastByteShift = 7 - ((start+count-1) % 8);
int wholeBytes = lastByteIndex - firstByteIndex - 1;
byte[] ba = HexToBytes(hex, firstByteIndex, lastByteIndex);
for (int i = 0; i < ba.Length; i++)
val = (val << 8) + ba[i];
return (val >> lastByteShift);
public static string Set(string hex, int start, int count, ulong val)
hex = BitFields.DoSet(hex, start, 56, (val >> (count-56)));
return BitFields.DoSet(hex, start, count, val);
private static string DoSet(string hex, int start, int count, ulong val)
int haveBits = hex.Length * 4;
if (count > 56) throw new Exception("Bit field too long");
if ((start + count) > haveBits)
hex = hex.PadRight(((int)(((((int)start+count)+7)/8)*2)), '0');
int firstByteIndex = start / 8;
byte firstByteMask = (byte)(0xff << (8-(start % 8)));
int lastByteIndex = (start + count - 1) / 8;
int lastByteShift = 7 - ((start + count - 1) % 8);
int lastByteMask = (byte)(0xff >> (1 + ((start + count - 1) % 8)));
int wholeBytes = lastByteIndex - firstByteIndex - 1;
byte[] ba = new byte[lastByteIndex-firstByteIndex+1];
val = val << lastByteShift;
if (lastByteIndex == firstByteIndex) lastByteMask |= firstByteMask;
ba[ba.Length-1] = (byte)((byte)val | (GetHexByte(hex, lastByteIndex) & lastByteMask));
for (int i=ba.Length-2; i>0; i--)
ba[0] = (byte)((byte)val | (GetHexByte(hex, firstByteIndex) & firstByteMask));
return BytesToHex(hex, firstByteIndex, lastByteIndex, ba);
private static byte GetHexByte(string hex, int which)
return Convert.ToByte(hex.Substring(which * 2, 2), 16);
private static byte[] HexToBytes(string hex, int first, int last)
byte[] ba = new byte[last-first+1];
for (int i = 0; i < ba.Length; i++)
ba[i] = GetHexByte(hex, first+i);
private static string BytesToHex(string hex, int first, int last, byte[] ba)
string s = hex.Substring(0,first*2);
for (int i = 0; i < last-first+1; i++)
s += ba[i].ToString("x2");
if (2*(last+1) < hex.Length)
s += hex.Substring(2*(last + 1));
string s = hex.Substring(0, first * 2);
for (int i = 0; i < last - first + 1; i++)
s += ba[i].ToString("x2");
if (2 * (last + 1) < hex.Length)
s += hex.Substring(2 * (last + 1));
public EpcHeader encoding;
public byte partition = 0;
public ulong company = 0;
public string product = null;
static public byte[] partBits = new byte[] { 40, 37, 34, 30, 27, 24, 20 };
static public byte[] partDigits = new byte[] { 12, 11, 10, 9, 8, 7, 6 };
public void Main(string[] args)
EpcSpec classInstance = new EpcSpec("33080B3B13880080BBF36D10");
Console.WriteLine(classInstance.ToPureUri());
public EpcSpec(EpcHeader encoding, byte filter, byte partition, ulong company, ulong item, ulong serial, string product)
this.encoding = encoding;
this.partition = partition;
public EpcSpec(EpcHeader encoding, byte filter, byte partition, ulong company, ulong item, ulong serial)
this.encoding = encoding;
this.partition = partition;
public EpcSpec(string tagID)
encoding = (EpcHeader)BitFields.Get(tagID, 0, 8);
filter = (byte)BitFields.Get(tagID, 08, 03);
partition = (byte)BitFields.Get(tagID, 11, 03);
companyBits = (partition <= 6) ? partBits[partition] : (byte)40;
company = BitFields.Get(tagID, 14, companyBits);
item = BitFields.Get(tagID, 14 + companyBits, 44 - companyBits);
serial = BitFields.Get(tagID, 58, 38);
company = BitFields.Get(tagID, 08, 28);
item = BitFields.Get(tagID, 36, 24);
serial = BitFields.Get(tagID, 60, 36);
filter = (byte)BitFields.Get(tagID, 08, 03);
partition = (byte)BitFields.Get(tagID, 11, 03);
companyBits = (partition <= 6) ? partBits[partition] : (byte)40;
company = BitFields.Get(tagID, 14, companyBits);
serial = BitFields.Get(tagID, 14 + companyBits, 58 - companyBits);
filter = (byte)BitFields.Get(tagID, 08, 03);
partition = (byte)BitFields.Get(tagID, 11, 03);
companyBits = (partition <= 6) ? partBits[partition] : (byte)40;
company = BitFields.Get(tagID, 14, companyBits);
item = BitFields.Get(tagID, 14 + companyBits, 41 - companyBits);
serial = BitFields.Get(tagID, 55, 41);
filter = (byte)BitFields.Get(tagID, 08, 03);
partition = (byte)BitFields.Get(tagID, 11, 03);
companyBits = (partition <= 6) ? partBits[partition] : (byte)40;
company = BitFields.Get(tagID, 14, companyBits);
item = BitFields.Get(tagID, 14 + companyBits, 44 - companyBits);
serial = BitFields.Get(tagID, 58, 38);
filter = (byte)BitFields.Get(tagID, 08, 03);
partition = (byte)BitFields.Get(tagID, 11, 03);
companyBits = (partition <= 6) ? partBits[partition] : (byte)40;
company = BitFields.Get(tagID, 14, companyBits);
serial = BitFields.Get(tagID, 14 + companyBits, 82 - companyBits);
filter = (byte)BitFields.Get(tagID, 08, 04);
company = BitFields.Get(tagID, 12, 48);
serial = BitFields.Get(tagID, 60, 36);
private string AddCheckDigit(string s, bool odd)
int first = (odd) ? 0 : 1;
for (i = first; i < len; i += 2)
accum += Convert.ToInt32(s.Substring(i, 1));
for (i = first; i < len; i += 2)
accum += Convert.ToInt32(s.Substring(i, 1));
return s + String.Format("{0:d1}", 10 - (accum % 10));
public void EncodeEANUCC()
companyDigits = partDigits[partition];
sc = String.Format("{0:d" + companyDigits + "}", company);
si = String.Format("{0:d" + (13 - companyDigits) + "}", item);
s = si.Substring(0, 1) + sc + si.Substring(1);
product = AddCheckDigit(s, true);
companyDigits = partDigits[partition];
sc = String.Format("{0:d" + companyDigits + "}", company);
si = String.Format("{0:d" + (17 - companyDigits) + "}", serial);
s = si.Substring(0, 1) + sc + si.Substring(1);
product = AddCheckDigit(s, true);
companyDigits = partDigits[partition];
sc = String.Format("{0:d" + companyDigits + "}", company);
si = String.Format("{0:d" + (12 - companyDigits) + "}", item);
product = AddCheckDigit(s, false);
companyDigits = partDigits[partition];
sc = String.Format("{0:d" + companyDigits + "}", company);
si = String.Format("{0:d" + (12 - companyDigits) + "}", item);
s = AddCheckDigit(sc + si, false);
product = "0" + s + String.Format("{0:d}", serial);
companyDigits = EpcSpec.partDigits[partition];
sc = String.Format("{0:d" + companyDigits + "}", company);
product = sc + String.Format("{0:d}", serial);
private void DecodeEANUCC()
if (product == null || product == "") return;
companyDigits = partDigits[partition];
company = Convert.ToUInt64(s.Substring(1, companyDigits));
item = Convert.ToUInt64(s.Substring(0, 1) + s.Substring(companyDigits + 1, 12 - companyDigits));
companyDigits = partDigits[partition];
company = Convert.ToUInt64(s.Substring(1, companyDigits));
serial = Convert.ToUInt64(s.Substring(0, 1) + s.Substring(companyDigits + 1, 16 - companyDigits));
companyDigits = EpcSpec.partDigits[partition];
company = Convert.ToUInt64(s.Substring(0, companyDigits));
item = Convert.ToUInt64(s.Substring(companyDigits, 12 - companyDigits));
companyDigits = EpcSpec.partDigits[partition];
company = Convert.ToUInt64(s.Substring(1, companyDigits));
item = Convert.ToUInt64(s.Substring(companyDigits + 1, 13 - companyDigits));
serial = Convert.ToUInt64(s.Substring(14));
companyDigits = EpcSpec.partDigits[partition];
company = Convert.ToUInt64(s.Substring(0, companyDigits));
serial = Convert.ToUInt64(s.Substring(companyDigits));
private void CheckPartition(out byte companyBits, out byte companyDigits)
if (filter > 7) throw new Exception("filter value too large.");
if (partition > 6) throw new Exception("partition value too large.");
companyBits = partBits[partition];
companyDigits = partDigits[partition];
if (company >= Math.Pow(10, companyDigits)) throw new Exception("company value too large.");
byte companyBits, companyDigits;
CheckPartition(out companyBits, out companyDigits);
if (item >= Math.Pow(10, 13 - companyDigits)) throw new Exception("item value too large.");
if (serial >= Math.Pow(2, 38)) throw new Exception("serial number too large.");
if (company >= Math.Pow(2, 28)) throw new Exception("manager number too large.");
if (item >= Math.Pow(2, 24)) throw new Exception("object number too large.");
if (serial >= Math.Pow(2, 36)) throw new Exception("serial number too large.");
CheckPartition(out companyBits, out companyDigits);
if (serial >= Math.Pow(10, 17 - companyDigits)) throw new Exception("serial number too large.");
CheckPartition(out companyBits, out companyDigits);
if (item >= Math.Pow(10, 12 - companyDigits)) throw new Exception("item value too large.");
if (serial >= Math.Pow(10, 12)) throw new Exception("serial number too large.");
CheckPartition(out companyBits, out companyDigits);
if (item >= Math.Pow(10, 12 - companyDigits)) throw new Exception("item value too large.");
if (serial >= Math.Pow(2, 38)) throw new Exception("serial number too large.");
CheckPartition(out companyBits, out companyDigits);
if (serial >= Math.Pow(2, 82 - companyBits)) throw new Exception("asset reference too large.");
if (filter >= Math.Pow(2, 4)) throw new Exception("filter number too large.");
if (company >= Math.Pow(2, 48)) throw new Exception("CAGE too large.");
if (serial >= Math.Pow(2, 36)) throw new Exception("serial number too large.");
public override string ToString()
tagID = BitFields.Set(tagID, 00, 08, (ulong)encoding);
companyBits = partBits[partition];
tagID = BitFields.Set(tagID, 08, 03, filter);
tagID = BitFields.Set(tagID, 11, 03, partition);
tagID = BitFields.Set(tagID, 14, companyBits, company);
tagID = BitFields.Set(tagID, 14 + companyBits, 44 - companyBits, item);
tagID = BitFields.Set(tagID, 58, 38, serial);
tagID = BitFields.Set(tagID, 08, 28, company);
tagID = BitFields.Set(tagID, 36, 24, item);
tagID = BitFields.Set(tagID, 60, 36, serial);
companyBits = partBits[partition];
tagID = BitFields.Set(tagID, 08, 03, filter);
tagID = BitFields.Set(tagID, 11, 03, partition);
tagID = BitFields.Set(tagID, 14, companyBits, company);
tagID = BitFields.Set(tagID, 14 + companyBits, 58 - companyBits, serial);
tagID = BitFields.Set(tagID, 72, 24, 0);
companyBits = partBits[partition];
tagID = BitFields.Set(tagID, 08, 03, filter);
tagID = BitFields.Set(tagID, 11, 03, partition);
tagID = BitFields.Set(tagID, 14, companyBits, company);
tagID = BitFields.Set(tagID, 14 + companyBits, 41 - companyBits, item);
tagID = BitFields.Set(tagID, 55, 41, serial);
companyBits = partBits[partition];
tagID = BitFields.Set(tagID, 08, 03, filter);
tagID = BitFields.Set(tagID, 11, 03, partition);
tagID = BitFields.Set(tagID, 14, companyBits, company);
tagID = BitFields.Set(tagID, 14 + companyBits, 44 - companyBits, item);
tagID = BitFields.Set(tagID, 58, 38, serial);
companyBits = partBits[partition];
tagID = BitFields.Set(tagID, 08, 03, filter);
tagID = BitFields.Set(tagID, 11, 03, partition);
tagID = BitFields.Set(tagID, 14, companyBits, company);
tagID = BitFields.Set(tagID, 14 + companyBits, 82 - companyBits, serial);
tagID = BitFields.Set(tagID, 08, 04, filter);
tagID = BitFields.Set(tagID, 12, 48, company);
tagID = BitFields.Set(tagID, 60, 36, serial);
string s = "urn:epc:tag:";
s += String.Format("sgtin-96:{0}.{1:d" + partDigits[partition] + "}.{2:d" + (13 - partDigits[partition]) + "}.{3}", filter, company, item, serial);
s += String.Format("gid-96:{0}.{1}.{2}", company, item, serial);
s += String.Format("sscc-96:{0}.{1:d" + partDigits[partition] + "}.{2:d" + (17 - partDigits[partition]) + "}", filter, company, serial);
s += String.Format("sgln-96:{0}.{1:d" + partDigits[partition] + "}.{2:d" + (12 - partDigits[partition]) + "}.{3}", filter, company, item, serial);
s += String.Format("grai-96:{0}.{1:d" + partDigits[partition] + "}.{2:d" + (12 - partDigits[partition]) + "}.{3}", filter, company, item, serial);
s += String.Format("giai-96:{0}.{1:d" + EpcSpec.partDigits[partition] + "}.{2:d}", filter, company, serial);
s += String.Format("dod-96:{0}.{1}.{2}", filter, company, serial);
public string ToPureUri()
string s = "urn:epc:id:";
s += String.Format("sgtin:{0:d" + partDigits[partition] + "}.{1:d" + (13 - partDigits[partition]) + "}.{2}", company, item, serial);
s += String.Format("gid:{0}.{1}.{2}", company, item, serial);
s += String.Format("sscc:{0:d" + partDigits[partition] + "}.{1:d" + (17 - partDigits[partition]) + "}", company, serial);
s += String.Format("sgln:{0:d" + partDigits[partition] + "}.{1:d" + (12 - partDigits[partition]) + "}.{2}", company, item, serial);
s += String.Format("grai:{0:d" + partDigits[partition] + "}.{1:d" + (12 - partDigits[partition]) + "}.{2}", company, item, serial);
s += String.Format("giai:{0:d" + partDigits[partition] + "}.{1:d}", company, serial);
s += String.Format("dod:{0}.{1}.{2}", filter, company, serial);