using System;
using System.Globalization;
using System.Text;
using System.IO;
namespace Wayne.FDCPOSInterface
{
public class SignedFuellingInfo
{
///
/// A class that calculates a CRC32 value from various sources.
///
public class Crc32
{
#region Fields
private UInt32[] table;
private UInt32 initialValue;
private UInt32 crc;
private UInt32 length;
private byte[] tempBuffer;
#endregion
#region Construction
///
/// Constructor.
/// Initializes the CRC to 0xFFFFFFFF.
///
public Crc32()
: this(0xffffffff)
{
}
///
/// Constructor.
///
/// The initial value of the CRC.
public Crc32(UInt32 initialValue)
{
this.initialValue = initialValue;
UInt32 poly = 0xedb88320;
table = new UInt32[256];
UInt32 temp = 0;
for (UInt32 i = 0; i < table.Length; i++)
{
temp = i;
for (UInt32 j = 8; j > 0; j--)
{
if ((temp & 1) == 1)
temp = (UInt32)((temp >> 1) ^ poly);
else
temp >>= 1;
}
table[i] = temp;
}
Reset();
}
#endregion
#region Properties
///
/// The CRC32 value.
///
public UInt32 Value
{
get { return ~crc; }
}
///
/// The total length of the data.
///
public UInt32 Length
{
get { return length; }
}
#endregion
#region Methods
///
/// Resets the CRC32 value.
///
public void Reset()
{
crc = initialValue;
length = 0;
}
///
/// Appends a byte array to the CRC32 value.
///
/// The bytes to append.
public void Append(byte[] bytes)
{
Append(bytes, 0, bytes.Length);
}
///
/// Appends a byte array to the CRC32 value.
///
/// The bytes to append.
/// The offset of the array of where to start.
/// The number of bytes to read from the array.
public void Append(byte[] bytes, int offset, int length)
{
this.length += (UInt32)length;
for (int i = offset; i < length; i++)
{
byte index = (byte)(((crc) & 0xff) ^ bytes[i]);
crc = (UInt32)((crc >> 8) ^ table[index]);
}
}
///
/// Appends a text string to the CRC32 value.
///
/// The text to append.
public void Append(string text)
{
if (!string.IsNullOrEmpty(text))
Append(Encoding.Unicode.GetBytes(text));
}
///
/// Appends the content of a file to the CRC32 value.
///
/// The filename of the file to append.
public void AppendFile(string filename)
{
AppendFile(filename, 16384);
}
///
/// Appends the content of a file to the CRC32 value.
///
/// The filename of the file to append.
/// The size of the read-buffer to use.
public void AppendFile(string filename, int bufferSize)
{
try
{
if ((tempBuffer == null) || (bufferSize != tempBuffer.Length))
tempBuffer = new byte[bufferSize];
using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (BinaryReader binaryReader = new BinaryReader(fileStream))
{
int usedBufferSize;
do
{
usedBufferSize = binaryReader.Read(tempBuffer, 0, bufferSize);
if (usedBufferSize > 0)
Append(tempBuffer, 0, usedBufferSize);
}
while (usedBufferSize == bufferSize);
}
}
}
catch { }
}
#endregion
}
public class Data
{
public DateTime DateTime { get; set; }
public int PumpNumber { get; set; }
public string ProductName { get; set; }
public decimal TotalAmount { get; set; }
public decimal Volume { get; set; }
public decimal Price { get; set; }
public string CurrencySymbol { get; set; }
public bool CurrencySymbolAfterValue { get; set; }
public bool SpaceBetweenCurrencySymbolAndValue { get; set; }
public string VolumeUnit { get; set; }
public int ControllerModuleCrc { get; set; }
public int PrinterWidth { get; set; }
}
private const string Iv = "@BEPQRV]";
private readonly Crc32 crc32 = new Crc32((uint)(
((Iv[6] - Iv[0]) * (Iv[7] - Iv[0]) + (Iv[2] - Iv[0])) * 1024 * 1024 +
((Iv[3] - Iv[0]) * (Iv[5] - Iv[0]) + (Iv[1] - Iv[0])) * 1024 +
((Iv[6] - Iv[0]) * (Iv[7] - Iv[0]) + (Iv[4] - Iv[0]))));
private const string SignChar = "^";
private const string BadSignReplaceChar = " ";
private const string SignError = "\r\n^*PUMP INFO SIGN ERROR*^\r\n";
public string EncodeReceiptText(Data data)
{
StringBuilder result = new StringBuilder();
NumberFormatInfo numberFormatInfo = new NumberFormatInfo
{
NumberDecimalDigits = 2,
NumberDecimalSeparator = ","
};
if (data.PrinterWidth < 30)
{
// Design for 24 chars
// ===================
string preText = data.PrinterWidth > 24 ? new string(' ', data.PrinterWidth - 24) : string.Empty;
//^ #12 [20100503085824] ^45697A3C
result.Append(preText + GetSignedString(string.Concat(SignChar, " #", data.PumpNumber.ToString().PadRight(3),
"[", data.DateTime.ToString("yyyyMMddHHmmss"), "] ", SignChar)));
//^ Blyfri 95 ^2C5BD546
result.Append(preText + GetSignedString(string.Concat(SignChar, " ", data.ProductName.PadRight(21), SignChar)));
//^ 563,74 DKK ^65B9F8A3
result.Append(preText + GetSignedString(string.Concat(SignChar, GetCurrencyString(numberFormatInfo, data).PadLeft(21), " ", SignChar)));
//^ 54,52 L ^98C35479
result.Append(preText + GetSignedString(string.Concat(SignChar, data.Volume.ToString(numberFormatInfo).PadLeft(10), " ", data.VolumeUnit.PadRight(11), SignChar)));
//^ @ 10,34 DKK/L ^465D9872
result.Append(preText + GetSignedString(string.Concat(SignChar, string.Concat("@ ", data.Price.ToString(numberFormatInfo)).PadLeft(10), " ", string.Concat(data.CurrencySymbol, "/", data.VolumeUnit).PadRight(11), SignChar)));
//^ CS A8F0EC90:######## ^6A9C8FC4)
result.Append(preText + GetSignedString(string.Concat(SignChar, " CS ", data.ControllerModuleCrc.ToString("X8"), " ######## ", SignChar)));
}
else
{
// Design for 30 chars
// ===================
string preText = data.PrinterWidth > 30 ? new string(' ', data.PrinterWidth - 30) : string.Empty;
//123456789012345678901234567890
//^ #12 [20100503085824] ^4A7692AE
result.Append(preText + GetSignedString(string.Concat(SignChar, " #", data.PumpNumber.ToString().PadRight(3),
"[", data.DateTime.ToString("yyyyMMddHHmmss"), "] ", SignChar)));
//123456789012345678901234567890
//^ Unlead 95 563,74 SEK ^3CE18720
result.Append(preText + GetSignedString(string.Concat(SignChar, " ", data.ProductName.PadRight(14), GetCurrencyString(numberFormatInfo, data).PadLeft(12), " ", SignChar)));
//123456789012345678901234567890
//^ 54,52 L @ 10,34 SEK/L ^0A1B0FB2
result.Append(preText + GetSignedString(string.Concat(SignChar, " ", string.Concat(data.Volume.ToString(numberFormatInfo), " ", data.VolumeUnit,
" @ ", data.Price.ToString(numberFormatInfo), " ", data.CurrencySymbol, "/", data.VolumeUnit).PadRight(27), SignChar)));
//123456789012345678901234567890
//^ C/S A8F0EC90:######## ^05198FB7
result.Append(preText + GetSignedString(string.Concat(SignChar, " C/S ", data.ControllerModuleCrc.ToString("X8"), " ######## ", SignChar)));
}
return result.ToString();
}
public string DecodeReceiptText(string text, int printerModuleCrc)
{
bool hasError = false;
int offset = 0;
int startCharIndex, endCharIndex;
do
{
startCharIndex = text.IndexOf(SignChar, offset);
if (startCharIndex > -1)
{
endCharIndex = text.IndexOf(SignChar, startCharIndex + 1);
if (endCharIndex == -1)
{
text = text.Replace(SignChar, BadSignReplaceChar);
hasError = true;
}
else
{
if (text.Length <= endCharIndex + 8)
{
text = text.Remove(startCharIndex, 1).Insert(startCharIndex, BadSignReplaceChar).Remove(endCharIndex, 1).Insert(endCharIndex, BadSignReplaceChar);
hasError = true;
}
else
{
string crcString = text.Substring(endCharIndex + 1, 8);
string signedText = text.Substring(startCharIndex, endCharIndex - startCharIndex + 1);
if (!crcString.Equals(GetStringSignValue(signedText), StringComparison.InvariantCultureIgnoreCase))
{
text = text.Remove(startCharIndex, 1).Insert(startCharIndex, BadSignReplaceChar).Remove(endCharIndex, 1).Insert(endCharIndex, BadSignReplaceChar);
hasError = true;
}
int printerModuleCrcIndex = signedText.IndexOf("########");
if (printerModuleCrcIndex > -1)
text = text.Remove(startCharIndex + printerModuleCrcIndex, 8).Insert(startCharIndex + printerModuleCrcIndex, printerModuleCrc.ToString("X8"));
text = text.Remove(endCharIndex + 1, 8);
}
offset = endCharIndex + 1;
}
}
else
endCharIndex = -1;
}
while ((startCharIndex > -1) && (endCharIndex > -1));
if (hasError)
return text + SignError;
return text;
}
private static string GetCurrencyString(IFormatProvider numberFormatInfo, Data data)
{
if (data.CurrencySymbolAfterValue)
return string.Concat(data.TotalAmount.ToString(numberFormatInfo), data.SpaceBetweenCurrencySymbolAndValue ? " " : string.Empty, data.CurrencySymbol);
return string.Concat(data.CurrencySymbol, data.SpaceBetweenCurrencySymbolAndValue ? " " : string.Empty, data.TotalAmount.ToString(numberFormatInfo));
}
private string GetSignedString(string text)
{
return string.Concat(text, GetStringSignValue(text));
}
private string GetStringSignValue(string text)
{
crc32.Reset();
crc32.Append(text);
return crc32.Value.ToString("X8");
}
}
}