Calculate checksum for Laboratory Information System (LIS) frames - c#

I'm developing an instrument driver for a Laboratory Information System. I want to know how to calculate the checksum of a frame.
Explanation of the checksum algorithm:
Expressed by characters [0-9] and [A-F].
Characters beginning from the character after [STX] and until [ETB] or [ETX] (including [ETB] or [ETX]) are added in binary.
The 2-digit numbers, which represent the least significant 8 bits in hexadecimal code, are converted to ASCII characters [0-9] and
[A-F].
The most significant digit is stored in CHK1 and the least significant digit in CHK2.
I am not getting the 3rd and 4th points above.
This is a sample frame:
<STX>2Q|1|2^1||||20011001153000<CR><ETX><CHK1><CHK2><CR><LF>
What is the value of CHK1 and CHK2? How do I implement the given algorithm in C#?

Finally I got answer, here is the code for calculating checksum:
private string CalculateChecksum(string dataToCalculate)
{
byte[] byteToCalculate = Encoding.ASCII.GetBytes(dataToCalculate);
int checksum = 0;
foreach (byte chData in byteToCalculate)
{
checksum += chData;
}
checksum &= 0xff;
return checksum.ToString("X2");
}

You can do this in one line:
return Encoding.ASCII.GetBytes(dataToCalculate).Aggregate((r, n) => r += n).ToString("X2");

private bool CheckChecksum(string data)
{
bool isValid =false
byte[] byteToCalculate = Encoding.ASCII.GetBytes(dataToCalculate);
int checkSum = 0;
for ( int i=i i<byteToCalculate.Length;i++)
{
checkSum += byteToCalculate[i];
}
checksum &= 0xff;
if (checksum == byteToCalculate[ChecksumPlace]
{
return true
}
else
{
return false
}
}

Related

C# Cannot convert `char' expression to type `string' [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
public class Kata
{
public static bool Narcissistic(int value)
{
//add variale to hold final result
int finalResult = 0;
//get the length of the value input
int valLength = value.ToString().Length;
//convert value given into an array of ints
string valString = value.ToString();
//iterate over each number and multiply that number by the length of value input
for (int i=0; i < valLength; i++) {
//convert char at index[i] of stringified value to int and mutiply by # of digits, store to result
finalResult += int.Parse(valString[i]) * valLength;
}
//return the result
return finalResult == value;
}
}
I'm getting an error when I run this that I understand, but don't quite know how to fix. My goal is to take a number (i.e 1234) and multiply each number by the total number of digits it contains (i.e 1*4 + 2*4 + 3*4...etc).
Assuming you have just Latin digit characters 0 to 9, you could use (valString[i] - '0') instead of int.Parse(valString[i]).
valString[i] is a char, not a string (which int.Parse() would expect). And chars are automatically converted to their Unicode integer code in C#, and as thhe digits 0 to 9 have consecutive Unicode values, '0' - '0' would be the Unicode value of the character for the digit 0 minus itself, i. e. 0, and so on up to '9' - '0' being 9 more than 0, i. e. 9.
This code would not work if there could be non Latin digits or non digit characters in your string. And looking at your complete code, the assumption should be met, as actually, you are converting from an int.
Here's a better option that avoids strings altogether
public static bool Narcissistic(int value)
{
if(value < 0) return false;
int sum = 0;
int count = 0;
while(value>0)
{
sum += value%10;
value /= 10;
count++;
}
return value == (sum*count);
}
Basically the value%10 will give you the least significate digit. Then the value /= 10; will truncate that digit. Once value is zero you've seen all the digits. And your formula (4*1 + 4*2 + 4*3 + 4*4) can of course just be 4*(1+2+3+4), which is the sum of the digits times the number of digits.
And presumably no negative number would be "Narcissistic" so you can just return false for them.
valString[i] will be a char - because that's what indexing does to a string. int.Parse expects a string. The simplest thing to do would probably just
finalResult += int.Parse(valString[i].ToString()) * valLength;
Assuming to turn a single character digit into a one-digit integer is your intention.
This is less "dangerous" than the traditional hack of subtracting '0' because you can rely on int.Parse to throw an exception if the char is anything but numeric.
You will also need to make the input argument uint, or define a behavior for negative numbers.
int.Parse() expects a string, but valString[i] is a character. You could just change this to valString[i].ToString(), but rather than parsing you can take advantage of the fact that the digit characters are encoded in sequence by casting them to int and subtracting the value of the 0 integer:
public static bool Narcissistic(int value)
{
int zero = (int)'0';
string valueString = value.ToString();
int total = 0;
foreach(char c in valueString)
{
int digit = ((int)c - zero);
total += digit * valueString.Length;
}
return total == value;
}
or
public static bool Narcissistic(int value)
{
int zero = (int)'0';
string valueString = value.ToString();
return valueString.Select(c => (c - zero) * valueString.Length).Sum() == value;
}
If you really want to you can write the second option as a one-liner:
public static bool Narcissistic(int value)
{
return value.ToString().Select(c => c - '0').Sum() * value.ToString().Length == value;
}

C# private function, IncrementArray

Can someone please explain in layman's terms the workings of this C# code?
for (int pos = 0; pos < EncryptedData.Length; pos += AesKey.Length);
{
Array.Copy(incPKGFileKey, 0, PKGFileKeyConsec, pos, PKGFileKey.Length);
IncrementArray(ref incPKGFileKey, PKGFileKey.Length - 1);
}
private Boolean IncrementArray(ref byte[] sourceArray, int position)
{
if (sourceArray[position] == 0xFF)
{
if (position != 0)
{
if (IncrementArray(ref sourceArray, position - 1))
{
sourceArray[position] = 0x00;
return true;
}
else return false;
}
else return false;
}
else
{
sourceArray[position] += 1;
return true;
}
}
I'm trying to port an app to Ruby but I'm having trouble understanding how the IncrementArray function works.
IncrementArray increments all entries of a byte array, with any overflow being added to the previous index, unless it's index 0 already.
The entire thing looks like some kind of encryption or decryption code. You might want to look for additional hints on which algorithm is used, as this kind of code is usually not self-explaining.
It looks to me like a big-endian addition algorithm:
Let's say you've got a long (64 bit, 8 byte) number:
var bigNumber = 0x123456FFFFFFFF;
But for some reason, we've got it coming to us as a byte array in Big-endian format:
// Get the little endian byte array representation of the number:
// [0xff 0xff 0xff 0xff 0xff 0x56 0x34 0x12]
byte[] source = BitConverter.GetBytes(bigNumber);
// BigEndian-ify it by reversing the byte array
source = source.Reverse().ToArray();
So now you want to add one to this "number" in it's current form, while maintaining any carrys/overflows like you would in normal arithmetic:
// increment the least significant byte by one, respecting carry
// (as it's bigendian, the least significant byte will be the last one)
IncrementArray(ref source, source.Length-1);
// we'll re-little-endian-ify it so we can convert it back
source = source.Reverse().ToArray();
// now we convert the array back into a long
var bigNumberIncremented = BitConverter.ToInt64(source, 0);
// Outputs: "Before +1:123456FFFFFFFF"
Console.WriteLine("Before +1:" + bigNumber);
// Outputs: "After +1:12345700000000"
Console.WriteLine("After +1:" + bigNumberIncremented);

EBCDIC to ASCII conversion, handling numeric values

I’m attempting to convert files from ECDIC to ASCII format and have run into an interesting issue. The files contain fixed length records with some fields being signed binary integers (described as B4 in the record layout), and long-precision numeric values (described as L8 in the record layout). I’ve been able to convert character data with no problem, but I’m not sure how to go about converting these numeric values. From a reference manual for the original system (an IBM 5110), the fields are described below.
B indicates the length (2, 4, or 8 bytes) of numeric data items in
fixed-point signed binary integer format that are to be converted to
BASIC internal data format. For record I/O file input, the next 2,
4, or 8 bytes in the record contain a signed binary value to be
converted by the system into internal data format and assigned to the
variable(s) specified in the READ FILE or REREAD FILE statement using
a FORM statement.
and
L indicates long-precision (8 characters) for numeric values. For
input, this entry indicates that an eight-position, long-precision
value in the record is to be assigned without conversion to a
corresponding numeric variable specified in the READ FILE or REREAD
FILE statement.
EDIT: Here's the code I'm using for the conversion
private void ConvertFile(EbcdicFile file)
{
if (file == null) return;
var filePath = Path.Combine(file.Path, file.FileName);
if (!File.Exists(filePath))
{
this.Logger.Info(string.Format("Cannot convert file {0}. It does not exist.", filePath));
return;
}
var ebcdic = Encoding.GetEncoding(37);
string convertedFilepath = Path.Combine(file.Path, file.ConvertedFileName);
byte[] fileData = File.ReadAllBytes(filePath);
if (!file.HasNumericFields)
File.WriteAllBytes(convertedFilepath, Encoding.Convert(ebcdic, Encoding.ASCII, fileData));
else
{
var convertedFileData = new List<byte>();
for (int position = 0; position < fileData.Length; position += file.RecordLength)
{
var segment = new ArraySegment<byte>(fileData, position, file.RecordLength);
file.Fields.ForEach(field =>
{
var fieldSegment = segment.Array.Skip(segment.Offset + field.Start - 1).Take(field.Length);
if (field.Type.Equals("string", StringComparison.OrdinalIgnoreCase))
{
convertedFileData.AddRange(
Encoding.Convert(ebcdic, Encoding.ASCII, fieldSegment.ToArray())
);
}
else if (field.Type.Equals("B4", StringComparison.OrdinalIgnoreCase))
{
// Not sure how to convert this field
}
else if (field.Type.Equals("L8", StringComparison.OrdinalIgnoreCase))
{
// Not sure how to convert this field
}
});
}
File.WriteAllBytes(convertedFilepath, convertedFileData.ToArray());
}
}
You must first know the fixed record size. Use FileStream.Read() to read one record worth of bytes. Then Encoding.GetString() to convert it to a string.
Then fish the fields out of the record using String.SubString(). A B4 is simply a SubString call with a length of 4, L8 with a length of 8. Further convert such a field to a number with Decimal.Parse(). You may have to divide the result, it wasn't clear what fixed-point multiplier is used. Good odds for 100.
Okay, so I've figured out how to convert both fields. B4 fields are very straightforward. They are essentially a 4-byte array which can be converted to an integer.
//The IBM 5110 were big endian machines, so reverse the array
if (BitConverter.IsLittleEndian)
Array.Reverse(by);
int value = BitConverter.ToInt32(by, 0);
The L8 fields are 8-bytes arrays that represented an IBM Double Precision Float. There are many ways this can be converted to an IEEE 754 Float. A few examples can be found at:
How To Read IBM 370 Data from a Binary File
Transform between IEEE, IBM or VAX floating point number formats and bytes expressions
Here's the version I used based on guidance from the articles.
private double IbmFloatToDouble(byte[] value)
{
if (ReferenceEquals(null, value))
throw new ArgumentNullException("value");
if (BitConverter.ToInt64(value, 0) == 0)
return 0;
int exponentBias = 64;
int ibmBase = 16;
double sign = 0.0D;
int signValue = (value[0] & 0x80) >> 7;
int exponentValue = (value[0] & 0x7f);
double fraction1 = (value[1] << 16) + (value[2] << 8) + value[3];
double fraction2 = (value[4] << 24) + (value[5] << 16) + (value[6] << 8) + value[7];
double exponent24 = 16777216.0; // 2^24
double exponent56 = 72057594037927936.0; // 2^56
double mantissa1 = fraction1 / exponent24;
double mantissa2 = fraction2 / exponent56;
double mantissa = mantissa1 + mantissa2;
double exponent = Math.Pow(ibmBase, exponentValue - exponentBias);
if (signValue == 0)
sign = 1.0;
else
sign = -1.0;
return (sign * mantissa * exponent);
}

Calculating the number of bits in a Subnet Mask in C#

I have a task to complete in C#. I have a Subnet Mask: 255.255.128.0.
I need to find the number of bits in the Subnet Mask, which would be, in this case, 17.
However, I need to be able to do this in C# WITHOUT the use of the System.Net library (the system I am programming in does not have access to this library).
It seems like the process should be something like:
1) Split the Subnet Mask into Octets.
2) Convert the Octets to be binary.
3) Count the number of Ones in each Octet.
4) Output the total number of found Ones.
However, my C# is pretty poor. Does anyone have the C# knowledge to help?
Bit counting algorithm taken from:
http://www.necessaryandsufficient.net/2009/04/optimising-bit-counting-using-iterative-data-driven-development/
string mask = "255.255.128.0";
int totalBits = 0;
foreach (string octet in mask.Split('.'))
{
byte octetByte = byte.Parse(octet);
while (octetByte != 0)
{
totalBits += octetByte & 1; // logical AND on the LSB
octetByte >>= 1; // do a bitwise shift to the right to create a new LSB
}
}
Console.WriteLine(totalBits);
The most simple algorithm from the article was used. If performance is critical, you might want to read the article and use a more optimized solution from it.
string ip = "255.255.128.0";
string a = "";
ip.Split('.').ToList().ForEach(x => a += Convert.ToInt32(x, 2).ToString());
int ones_found = a.Replace("0", "").Length;
A complete sample:
public int CountBit(string mask)
{
int ones=0;
Array.ForEach(mask.Split('.'),(s)=>Array.ForEach(Convert.ToString(int.Parse(s),2).Where(c=>c=='1').ToArray(),(k)=>ones++));
return ones
}
You can convert a number to binary like this:
string ip = "255.255.128.0";
string[] tokens = ip.Split('.');
string result = "";
foreach (string token in tokens)
{
int tokenNum = int.Parse(token);
string octet = Convert.ToString(tokenNum, 2);
while (octet.Length < 8)
octet = octet + '0';
result += octet;
}
int mask = result.LastIndexOf('1') + 1;
The solution is to use a binary operation like
foreach(string octet in ipAddress.Split('.'))
{
int oct = int.Parse(octet);
while(oct !=0)
{
total += oct & 1; // {1}
oct >>=1; //{2}
}
}
The trick is that on line {1} the binary AND is in sence a multiplication so multiplicating 1x0=0, 1x1=1. So if we have some hypothetic number
0000101001 and multiply it by 1 (so in binary world we execute &), which is nothig else then 0000000001, we get
0000101001
0000000001
Most right digit is 1 in both numbers so making binary AND return 1, otherwise if ANY of the numbers minor digit will be 0, the result will be 0.
So here, on line total += oct & 1 we add to tolal either 1 or 0, based on that digi number.
On line {2}, instead we just shift the minor bit to right by, actually, deviding the number by 2, untill it becomes 0.
Easy.
EDIT
This is valid for intgere and for byte types, but do not use this technique on floating point numbers. By the way, it's pretty valuable solution for this question.

Reversing a hash function

I have the following hash function, and I'm trying to get my way to reverse it, so that I can find the key from a hashed value.
uint Hash(string s)
{
uint result = 0;
for (int i = 0; i < s.Length; i++)
{
result = ((result << 5) + result) + s[i];
}
return result;
}
The code is in C# but I assume it is clear.
I am aware that for one hashed value, there can be more than one key, but my intent is not to find them all, just one that satisfies the hash function suffices.
EDIT :
The string that the function accepts is formed only from digits 0 to 9 and the chars '*' and '#' hence the Unhash function must respect this criteria too.
Any ideas? Thank you.
This should reverse the operations:
string Unhash(uint hash)
{
List<char> s = new List<char>();
while (hash != 0)
{
s.Add((char)(hash % 33));
hash /= 33;
}
s.Reverse();
return new string(s.ToArray());
}
This should return a string that gives the same hash as the original string, but it is very unlikely to be the exact same string.
Characters 0-9,*,# have ASCII values 48-57,42,35, or binary: 00110000 ... 00111001, 00101010, 00100011
First 5 bits of those values are different, and 6th bit is always 1. This means that you can deduce your last character in a loop by taking current hash:
uint lastChar = hash & 0x1F - ((hash >> 5) - 1) & 0x1F + 0x20;
(if this doesn't work, I don't know who wrote it)
Now roll back hash,
hash = (hash - lastChar) / 33;
and repeat the loop until hash becomes zero. I don't have C# on me, but I'm 70% confident that this should work with only minor changes.
Brute force should work if uint is 32 bits. Try at least 2^32 strings and one of them is likely to hash to the same value. Should only take a few minutes on a modern pc.
You have 12 possible characters, and 12^9 is about 2^32, so if you try 9 character strings you're likely to find your target hash. I'll do 10 character strings just to be safe.
(simple recursive implementation in C++, don't know C# that well)
#define NUM_VALID_CHARS 12
#define STRING_LENGTH 10
const char valid_chars[NUM_VALID_CHARS] = {'0', ..., '#' ,'*'};
void unhash(uint hash_value, char *string, int nchars) {
if (nchars == STRING_LENGTH) {
string[STRING_LENGTH] = 0;
if (Hash(string) == hash_value) { printf("%s\n", string); }
} else {
for (int i = 0; i < NUM_VALID_CHARS; i++) {
string[nchars] = valid_chars[i];
unhash(hash_value, string, nchars + 1);
}
}
}
Then call it with:
char string[STRING_LENGTH + 1];
unhash(hash_value, string, 0);
Hash functions are designed to be difficult or impossible to reverse, hence the name (visualize meat + potatoes being ground up)
I would start out by writing each step that result = ((result << 5) + result) + s[i]; does on a separate line. This will make solving a lot easier. Then all you have to do is the opposite of each line (in the opposite order too).

Categories

Resources