find checksum of a string in C# .net - c#

Hi I want to find a checksum of single string. here are the requirements of checksum.
32 digit/8byte check sum represented in hexadecimal character.
It should be XOR of header + session + body + message.
Lets suppose header + session + body + message = "This is test string". I want to calculate the checksum of this. So far I have developed below code.
Checksum is calculated correctly if string length(byte[] data) is multiple of 4.
If "data" is not a multiple of 4 I receive exception as
"System.IndexOutOfRangeException: Index was outside the bounds of the array".
I will be taking different inputs having different string length from user and hence the string length will be variable(means some time user can enter only ABCDE some times q and A and so on.). How can I fix this exception issue and calculate correct checksum with multiple of 4.
public string findchecksum(string userinput)
try
{
ASCIIEncoding enc = new ASCIIEncoding();
byte[] data = Encoding.ASCII.GetBytes(userinput);
byte[] checksum = new byte[4];
for (int i = 16; i <= data.Length - 1; i += 4)
{
checksum[0] = (byte)(checksum[0] ^ data[i]);
checksum[1] = (byte)(checksum[1] ^ data[i + 1]);
checksum[2] = (byte)(checksum[2] ^ data[i + 2]);
checksum[3] = (byte)(checksum[3] ^ data[i + 3]);
}
int check = 0;
for (int i = 0; i <= 3; i++)
{
int r = (Convert.ToInt32(checksum[i]));
int c = (-(r + (1))) & (0xff);
c <<= (24 - (i * 8));
check = (check | c);
}
return check.ToString("X");

Because you use i+3 inside your loop, your array size has to always be divisible by 4. You should extend your data array to met that requirement before entering the loop:
byte[] data = Encoding.ASCII.GetBytes(cmd);
if (data.Length % 4 != 0)
{
var data2 = new byte[(data.Length / 4 + 1) * 4];
Array.Copy(data, data2, data.Length);
data = data2;
}

Related

C# i use Modbus/TCP to get Data, Data type is 「LReal」. i want turn to double

i use Modbus/TCP to get data, data type is LReal.
but i want LReal to int.
this is my data.
staic_13 data is 「4.232」
but i get [80] 16400 [81]-2098 [82] -9962 [83] -30933.
i don't know how turn to double
Based on this experimental Python code,
>>> x = [16400, -2098, -9962, -30933]
>>> struct.unpack(">d", struct.pack(">4h", *x))
(4.242,)
it looks like you'd need to concatenate those 4 16-byte integers in big-endian format, then interpret those 8 bytes as a single big-endian double.
In .NET 6 (see this fiddle):
using System.Buffers.Binary;
using System;
short[] values = {16400, -2098, -9962, -30933};
byte[] buf = new byte[values.Length * sizeof(short)];
for (int i = 0; i < values.Length; i++)
{
BinaryPrimitives.WriteInt16BigEndian(buf.AsSpan(i * sizeof(short)), values[i]);
}
double result = BinaryPrimitives.ReadDoubleBigEndian(buf);
Console.WriteLine(result);
In .NET 4 (see this fiddle):
using System;
public class Program
{
public static void Main()
{
short[] values = {16400, -2098, -9962, -30933};
byte[] buf = new byte[8];
for (int i = 0; i < 4; i++)
{
byte[] sh_buf = BitConverter.GetBytes(values[i]);
if(BitConverter.IsLittleEndian) {
// Flip the bytes around if we're little-endian
buf[(3 - i) * 2] = sh_buf[0];
buf[(3 - i) * 2 + 1] = sh_buf[1];
} else {
buf[i * 2] = sh_buf[0];
buf[i * 2 + 1] = sh_buf[1];
}
}
double result = BitConverter.ToDouble(buf, 0);
Console.WriteLine(result);
}
}

How to append/insert bytes? [duplicate]

I want to add some string in the middle of image metadata block. Under some specific marker. I have to do it on bytes level since .NET has no support for custom metadata fields.
The block is built like 1C 02 XX YY YY ZZ ZZ ZZ ... where XX is the ID of the field I need to append and YY YY is the size of it, ZZ = data.
I imagine it should be more or less possible to read all the image data up to this marker (1C 02 XX) then increase the size bytes (YY YY), add data at the end of ZZ and then add the rest of the original file? Is this correct?
How should I go on with it? It needs to work as fast as possible with 4-5 MB JPEG files.
In general there is no way to speed up this operation. You have to read at least portion that needs to be moved and write it again in updated file. Creating new file and copying content to it may be faster if you can parallelize read and write operations.
Note: In you particular case it may not be possible to just insert content in the middle of the file as most of file formats are not designed with such modifcations in mind. Often there are offsets to portions of the file that will be invalid when you shift part of the file. Specifying what file format you trying to work with may help other people to provide better approaches.
Solved the problem with this code:
List<byte> dataNew = new List<byte>();
byte[] data = File.ReadAllBytes(jpegFilePath);
int j = 0;
for (int i = 1; i < data.Length; i++)
{
if (data[i - 1] == (byte)0x1C) // 1C IPTC
{
if (data[i] == (byte)0x02) // 02 IPTC
{
if (data[i + 1] == (byte)fileByte) // IPTC field_number, i.e. 0x78 = IPTC_120
{
j = i;
break;
}
}
}
}
for (int i = 0; i < j + 2; i++) // add data from file before this field
dataNew.Add(data[i]);
int countOld = (data[j + 2] & 255) << 8 | (data[j + 3] & 255); // curr field length
int countNew = valueToAdd.Length; // new string length
int newfullSize = countOld + countNew; // sum
byte[] newSize = BitConverter.GetBytes((Int16)newfullSize); // Int16 on 2 bytes (to use 2 bytes as size)
Array.Reverse(newSize); // changes order 10 00 to 00 10
for (int i = 0; i < newSize.Length; i++) // add changed size
dataNew.Add(newSize[i]);
for (int i = j + 4; i < j + 4 + countOld; i++) // add old field value
dataNew.Add(data[i]);
byte[] newString = ASCIIEncoding.ASCII.GetBytes(valueToAdd);
for (int i = 0; i < newString.Length; i++) // append with new field value
dataNew.Add(newString[i]);
for (int i = j + 4 + newfullSize; i < data.Length; i++) // add rest of the file
dataNew.Add(data[i]);
byte[] finalArray = dataNew.ToArray();
File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(jpegFilePath), "newfile.jpg"), finalArray);
Here is an easy and quite fast solution. It moves all bytes after given offset to their new position according to given extraBytes, so you can insert your data.
public void ExpandFile(FileStream stream, long offset, int extraBytes)
{
// http://stackoverflow.com/questions/3033771/file-io-with-streams-best-memory-buffer-size
const int SIZE = 4096;
var buffer = new byte[SIZE];
var length = stream.Length;
// Expand file
stream.SetLength(length + extraBytes);
var pos = length;
int to_read;
while (pos > offset)
{
to_read = pos - SIZE >= offset ? SIZE : (int)(pos - offset);
pos -= to_read;
stream.Position = pos;
stream.Read(buffer, 0, to_read);
stream.Position = pos + extraBytes;
stream.Write(buffer, 0, to_read);
}
Need to be checked, though...

Generating random string valid for UTF-8 encode and decode

For testing purpose, I need to generate a random string, which is then encoded into byte array for transferring over the Web and decoded back to a result string. The test uses NUnit framework to compare the original string with the result string. Since the encoded byte array has to be friendly for Web, it is encoded with UTF-8.
The string is encoded into a byte array by Encoder.GetBytes from UTF8Encoding. The byte array is decoded to string by Decoder.GetChars from UTF8Encoding.
The original string needs to be generated randomly and contain any sequence of characters, which can be encoded/decoded using UTF-8 encoding.
My first attempt to generate the string was:
public static String RandomString(Random rnd, Int32 length) {
StringBuilder str = new StringBuilder(length);
for (int i = 0; i < length; i++)
str.Append((char)rnd.Next(char.MinValue, char.MaxValue));
return str.ToString();
}
The above code produces strings with invalid sequences to encode.
I found some suggestions on the web and improved the code:
public static String RandomString(Random rnd, Int32 length) {
StringBuilder str = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char c = (char)rnd.Next(char.MinValue, char.MaxValue);
while (c >= 0xD800 && c <= 0xDFFF)
c = (char)rnd.Next(char.MinValue, char.MaxValue);
str.Append(c);
return str.ToString();
}
The above code has no problem with encoding, but decoding the byte array fails. Furthermore, I am not sure that the code can cover all possible cases.
Any suggestions, how to generate a random string with the given requirements in C#.
UPD: using a random string in encoding/decoding:
public static Encoder Utf8Encode = new UTF8Encoding(false, true).GetEncoder();
public static Decoder Utf8Decode = new UTF8Encoding(false, true).GetDecoder();
public unsafe void TestString(Random rnd, int length, byte* byteArray,
int arrayLenght) {
int encodedLen;
String str = RandomString(rnd, length);
fixed (char* pStr = str) {
encodedLen = Utf8Encode.GetBytes(pStr, str.Length, byteArray,
arrayLenght, true);
}
char* buffer = stackalloc char[8192];
int decodedLen = Utf8Decode.GetChars(byteArray, encodedLen, buffer,
8192, true);
String res = new String(buffer, 0, decodedLen);
Assert.AreEqual(str, res);
}
I have used the code below for generating random UTF-8 character byte sequences. I can't guarantee it captures every aspect of the UTF-8 spec, but it was valuable for my testing purposes, so I'm posting it here.
private static readonly (int, int)[] HeadByteDefinitions =
{
(1 << 7, 0b0000_0000),
(1 << 5, 0b1100_0000),
(1 << 4, 0b1110_0000),
(1 << 3, 0b1111_0000)
};
static byte[] RandomUtf8Char(Random gen)
{
const int totalNumberOfUtf8Chars = (1 << 7) + (1 << 11) + (1 << 16) + (1 << 21);
int tailByteCnt;
var rnd = gen.Next(totalNumberOfUtf8Chars);
if (rnd < (1 << 7))
tailByteCnt = 0;
else if (rnd < (1 << 7) + (1 << 11))
tailByteCnt = 1;
else if (rnd < (1 << 7) + (1 << 11) + (1 << 16))
tailByteCnt = 2;
else
tailByteCnt = 3;
var (range, offset) = HeadByteDefinitions[tailByteCnt];
var headByte = Convert.ToByte(gen.Next(range) + offset);
var tailBytes = Enumerable.Range(0, tailByteCnt)
.Select(_ => Convert.ToByte(gen.Next(1 << 6) + 0b1000_0000));
return new[] {headByte}.Concat(tailBytes).ToArray();
}

HEX to bit[ ] array (also known as bool[ ])

I'm kindda new to c# and i was looking for some ideas on 2 thing. I have looked far and wide for answers but haven't found an answer to my exact problem.
I have a byte array (called BA) within a for loop which keeps over-writting itself and there is no way for my to be able print it as a whole array. Is there a way to export it outside the for loop (maybe with a different name) so i can use it later on in the program? i just want something like this:
byte[] BA2 = {3 187,3 203,111 32, ...etc}; //(groups of 2bytes separated by commas).
From the original
string hexValues = "03 BB,03 CB,6F 20,57 6F,72 6C,64 21";
(and also to represent this information in bits (boolean) so {00000011 10111011,00000011 11001011, ...etc})
The second thing i must do is to shift these two bytes by 4 and apply and AND gate with FFF0 (which is the same as multiplying the first byte * 1, and the second by 0xF0). Then put this in a ushort[ ] (unsigned short array) which holds the transformed bytes in binary format and then from there convert it back to HEX.
I understand that this might be unclear (my code is kind of messy), and pretty complex. but i was hoping some of you c# guru's could lend me hand.
Here's my code so far, i have put in comments the bits that don't work so the code runs. but i desperatly need to fix them.
class Program
{
static void Main(string[] args)
{
string hexValues = "03 BB,03 CB,6F 20,57 6F,72 6C,64 21";
string[] hex2byte = hexValues.Split(',');
for (int j = 0; j < 6; j++)
{
Console.WriteLine("\n2 byte String is: "+ hex2byte[j]);
string[] hex1byte = hex2byte[j].Split(' ');
for (int k = 0; k < 2; k++)
{
Console.WriteLine("byte " + hex1byte[k]);
byte[] BA = StringToByteArray((hex1byte[k]));
//bool[] AA = BitConverter.ToBoolean(BA); // I'm essentially stuck here. I need somehting which actually works.
//for (int i2 = 0; i2 < 2; i2++); // This is my attemp to perform de shift and AND.
//{
// ushort[] X = new ushort[1];
// X[0] = (ushort)((ushort)(BA[0] << 4) + (ushort)((BA[1] & 0xF0) >> 4)); // They have to be in this order: ((1stByte & 0xFF) << 4) + ((2byte & 0xF0) >> 4); first to the left then the right.
//}
Console.WriteLine("Converted " + BA[0]);
}
}
//Console.WriteLine(BA[4]); // it says: Does not exist in current context. Can it only b accesed in the for loop?
Console.ReadKey();
} // Main method finishes.
// Define StringToByteArray method.
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
}
Is this what you are looking for?
string[] hexValues = new string[] { "03BB", "03CB", "6F20", "576F", "726C", "6421" };
ushort result = 0;
for (int i = 0; i < hexValues.Length; i++)
{
Console.WriteLine("2 byte String is {0}", hexValues[i]);
result = ushort.Parse(hexValues[i], NumberStyles.AllowHexSpecifier);
Console.WriteLine("converted: {0}", result.ToString());
Console.WriteLine("converted: {0}", result.ToString("x")); // "x" format in ToString -> very useful for creating hex strings.
}
For your shifting you can use the << and >> operators, and | and & for bitwise operations.

Converting from byte[] to string

I have the following code:
using (BinaryReader br = new BinaryReader(
File.Open(FILE_PATH, FileMode.Open, FileAccess.ReadWrite)))
{
int pos = 0;
int length = (int) br.BaseStream.Length;
while (pos < length)
{
b[pos] = br.ReadByte();
pos++;
}
pos = 0;
while (pos < length)
{
Console.WriteLine(Convert.ToString(b[pos]));
pos++;
}
}
The FILE_PATH is a const string that contains the path to the binary file being read.
The binary file is a mixture of integers and characters.
The integers are 1 bytes each and each character is written to the file as 2 bytes.
For example, the file has the following data :
1HELLO HOW ARE YOU45YOU ARE LOOKING GREAT //and so on
Please note: Each integer is associated with the string of characters following it. So 1 is associated with "HELLO HOW ARE YOU" and 45 with "YOU ARE LOOKING GREAT" and so on.
Now the binary is written (I do not know why but I have to live with this) such that '1' will take only 1 byte while 'H' (and other characters) take 2 bytes each.
So here is what the file actually contains:
0100480045..and so on
Heres the breakdown:
01 is the first byte for the integer 1
0048 are the 2 bytes for 'H' (H is 48 in Hex)
0045 are the 2 bytes for 'E' (E = 0x45)
and so on..
I want my Console to print human readable format out of this file: That I want it to print "1 HELLO HOW ARE YOU" and then "45 YOU ARE LOOKING GREAT" and so on...
Is what I am doing correct? Is there an easier/efficient way?
My line Console.WriteLine(Convert.ToString(b[pos])); does nothing but prints the integer value and not the actual character I want. It is OK for integers in the file but then how do I read out characters?
Any help would be much appreciated.
Thanks
I think what you are looking for is Encoding.GetString.
Since your string data is composed of 2 byte characters, how you can get your string out is:
for (int i = 0; i < b.Length; i++)
{
byte curByte = b[i];
// Assuming that the first byte of a 2-byte character sequence will be 0
if (curByte != 0)
{
// This is a 1 byte number
Console.WriteLine(Convert.ToString(curByte));
}
else
{
// This is a 2 byte character. Print it out.
Console.WriteLine(Encoding.Unicode.GetString(b, i, 2));
// We consumed the next character as well, no need to deal with it
// in the next round of the loop.
i++;
}
}
You can use String System.Text.UnicodeEncoding.GetString() which takes a byte[] array and produces a string.
I found this link very useful
Note that this is not the same as just blindly copying the bytes from the byte[] array into a hunk of memory and calling it a string. The GetString() method must validate the bytes and forbid invalid surrogates, for example.
using (BinaryReader br = new BinaryReader(File.Open(FILE_PATH, FileMode.Open, FileAccess.ReadWrite)))
{
int length = (int)br.BaseStream.Length;
byte[] buffer = new byte[length * 2];
int bufferPosition = 0;
while (pos < length)
{
byte b = br.ReadByte();
if(b < 10)
{
buffer[bufferPosition] = 0;
buffer[bufferPosition + 1] = b + 0x30;
pos++;
}
else
{
buffer[bufferPosition] = b;
buffer[bufferPosition + 1] = br.ReadByte();
pos += 2;
}
bufferPosition += 2;
}
Console.WriteLine(System.Text.Encoding.Unicode.GetString(buffer, 0, bufferPosition));
}

Categories

Resources