Writing Hard drive serial string to Binary file - c#

I have a simple function that grabs the hard drive serial number from the C:\ drive and puts it into a string:
ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"C:\"");
disk.Get();
string hdStr = Convert.ToString(disk["VolumeSerialNumber"]);
I'm then attempting to convert the string above into ASCII and then write it out to a binary file, the issue I'm having is, when converting this string and saving the file using streamwriter, and opening the file in a hex editor, I'm seeing more bytes that I originally wanted to write so for example "16342D1F4A61BC"
Will come out as: 08 16 34 2d 1f 4a 61 c2 bc
It's adding the 08 and c2 in there somehow...
The more complete version is as follows:
string constructor2 = "16342D1F4A61BC";
string StrValue = "";
while (constructor2.Length > 0)
{
StrValue += System.Convert.ToChar(System.Convert.ToUInt32(constructor2.Substring(0, 2), 16)).ToString();
// Remove from the hex object the converted value
constructor2 = constructor2.Substring(2, constructor2.Length - 2);
}
FileStream writeStream;
try
{
writeStream = new FileStream(Path.GetDirectoryName(Application.ExecutablePath) + "\\license.mgr", FileMode.Create);
BinaryWriter writeBinay = new BinaryWriter(writeStream);
writeBinay.Write(StrValue);
writeBinay.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Can anyone help me understand how these are getting added in?

Try this:
string constructor2 = "16342D1F4A61BC";
File.WriteAllBytes("test.bin", ToBytesFromHexa(constructor2));
With the following helper routines:
public static byte[] ToBytesFromHexa(string text)
{
if (text == null)
throw new ArgumentNullException("text");
List<byte> bytes = new List<byte>();
bool low = false;
byte prev = 0;
for (int i = 0; i < text.Length ; i++)
{
byte b = GetHexaByte(text[i]);
if (b == 0xFF)
continue;
if (low)
{
bytes.Add((byte)(prev * 16 + b));
}
else
{
prev = b;
}
low = !low;
}
return bytes.ToArray();
}
public static byte GetHexaByte(char c)
{
if ((c >= '0') && (c <= '9'))
return (byte)(c - '0');
if ((c >= 'A') && (c <= 'F'))
return (byte)(c - 'A' + 10);
if ((c >= 'a') && (c <= 'f'))
return (byte)(c - 'a' + 10);
return 0xFF;
}

Try using System.Text.Encoding.ASCII.GetBytes(hdStr) to get the bytes that represent the string in ASCII.

How important is endian-ness to you in the file?
Perhaps you can use something like:
byte[] b = BitConverter.GetBytes(Convert.ToUInt32(hdStr, 16));

Related

Difference in C# and C++ Byte array conversion for object

I am trying to convert some C++ code to C# for an application. The function I am trying to convert calculates the Checksum of an object which comprises of MAC address among other details. The Checksum function in C++ is defined as :
unsigned short CalculateCheckSum(unsigned char* p, int n)
{
unsigned short x, checksum = 0;
for (unsigned long i = 0; i < n; ++i)
{
x = p[i];
x <<= i % 8;
checksum += x;
}
return checksum != 0 ? checksum : 51;
I have written the same function defined in C# is :
public static ushort CalculateCheckSum(byte[] p, int n)
{
ushort x, checksum = 0;
for (int i = 0; i < n; ++i)
{
x = p[i];
x <<= i % 8;
checksum += x;
}
return (ushort)(checksum != 0 ? checksum : 51);
}
Here is the code that calculates the checksum in C++ :
PCInfoClass pcInfo;
char nicIDStr[1024];
strcpy_s(nicIDStr, "34-29-8f-93-16-61");
NICAddressStrToBinary(nicIDStr, pcInfo.nicID);
char outbuf[1000];
pcInfo.timeStamp = 1234;
pcInfo.expDate = 0;
I32 pcInfoSz = 20;
pcInfo.checksum = 0;
unsigned char* byteStr;
byteStr = (unsigned char*)&pcInfo;
pcInfo.checksum = CalculateCheckSum(byteStr, pcInfoSz);
Since the CalculateCheckSum method, takes a Byte array as an argument, I have used the BinaryFormatter class which comes with System.Runtime. I have tried to replicate the same functionality in C# with the following lines :
PCInfoClass pcInfo = new PCInfoClass();
char[] nicIDStr = new char[1024];
string str = "34-29-8f-93-16-61";
for (int i = 0; i < str.Length; i++)
{
nicIDStr[i] = str[i];
}
NICAddressStrToBinary(nicIDStr, pcInfo.nicID);
pcInfo.timeStamp = 1234;
pcInfo.expDate = 0;
int pcInfoSz = 20;
pcInfo.checksum = 0;
pcInfo.checksum = CalculateCheckSum(ObjectToByteArray1(pcInfo), pcInfoSz);
public static byte[] ObjectToByteArray1(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
Unfortunately the value of checksum comes out to be different for both approaches so the conversion is stuck at this point.
The other method used in this code is NICAddressStrToBinary, in C++ its defined as :
bool NICAddressStrToBinary(const char* nicIDStr, unsigned char* outbuf)
{
int c, i, dgt;
if (nicIDStr == NULL) return false;
//converted char to integer as ascii number.
for (dgt = 0, i = 0; (c = nicIDStr[i]) != '\0'; ++i)
{
//if it is 45 '-' then the loop will continue;
if (c == '-') continue;
//if the ascii value is between 48 to 57 then we will decrrease with 48 of given integer
if ('0' <= c && c <= '9')
{
c -= '0';
}
else
if ('a' <= c && c <= 'f')
{
c -= 'a' - 10;
}
else
if ('A' <= c && c <= 'F')
{
c -= 'A' - 10;
}
else
{
return false;
}
if (dgt >= 6 * 2)
{
return false;
}
if (outbuf != NULL)
{
if ((dgt & 1) == 0)
{
//// it means c<<4 is c*2power4
outbuf[dgt / 2] = c << 4;
}
else
{
outbuf[dgt / 2] |= c;
}
}
dgt++;
}
if (dgt < 6 * 2)
{
return false;
}
return true;
}
In C# its been rewritten as :
public static void NICAddressStrToBinary(char[] nicIDStr, byte[] outbuf)
{
int c, i, dgt;
if (nicIDStr == null) return ;
for (dgt = 0, i = 0; i<=nicIDStr.Length-1; ++i)
{
c = nicIDStr[i];
if (c == '-') continue;
if ('0' <= c && c <= '9')
{
c -= '0';
}
else if ('a' <= c && c <= 'f')
{
c -= 'a' - 10;
}
else if ('A' <= c && c <= 'F')
{
c -= 'A' - 10;
}
else
{
return;
}
/* make sure there aren't too many digits
*/
if (dgt >= 6 * 2)
{
return ;
}
/* accumulate the binary NIC ID
* remembering that we're starting
* with the most significant digits first
*/
if (outbuf != null)
{
if ((dgt & 1) == 0)
{
//// it means c<<4 is c*2power4
outbuf[dgt / 2] = (byte)(c << 4);
}
else
{
outbuf[dgt / 2] |= (byte)c;
}
}
/* advance the digit index
*/
dgt++;
}
/* make sure I have enough digits
*/
if (dgt < 6 * 2)
{
return ;
}
return ;
}
Can someone please tell me what could be the cause of different values being calculated in C++ and C#?
Since the CalculateCheckSum method, takes a Byte array as an argument, I have used the BinaryFormatter class which comes with System.Runtime.
That would have been a reasonable choice in isolation, but BinaryFormatter uses a complicated format that isn't "just the bytes of the object". Those bytes are probably in there somewhere, but a lot of other stuff is too. So in this case it doesn't work out.
Even in C# there are ways to get the raw bytes of a given object, but you would have to specifically design PCInfoClass for that purpose: make it a struct, use a fixed-size array for nicID (references are a no-go). Then you can use some tricks (which trick you can use depends on the version of .NET you're targeting) to get the raw bytes of that struct.
My recommendation would be to use a BinaryWriter to manually write each field to a MemoryStream, then use ToArray as you did. Be very careful to call the right overloads of Write, and explicitly write padding bytes as well. I cannot write that code for you without knowing what the class definition looked like in C++.

Read unicode char from large textfile

How to read the unicode char? like "ä"
public static string Read(int length, string absolutePath)
{
StringBuilder resultAsString = new StringBuilder();
using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(absolutePath))
using (MemoryMappedViewStream memoryMappedViewStream = memoryMappedFile.CreateViewStream(0, length))
{
for (int i = 0; i < length; i++)
{
int result = memoryMappedViewStream.ReadByte();
if (result == -1)
{
break;
}
char letter = (char)result;
resultAsString.Append(letter);
}
}
return resultAsString.ToString();
}
the read int (result) is 195 and the char cast gives me not the expected result.
Not sure if that's what you ask for, but, you can use StreamReader
StreamReader sr = new StreamReader(stream, Encoding.Unicode);
If you just want to load and read a UTF-8 file into a string variable the code can be as simple as
var text = File.ReadAllText(filePath, Encoding.UTF8);
If you insist on processing UTF-8 data byte-by-byte though, there is a bit more complex parsing.
Here's a rough (but working) sketch, to go with your original code:
StringBuilder resultAsString = new StringBuilder();
using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(filePath))
using (MemoryMappedViewStream viewStream = memoryMappedFile.CreateViewStream(0, new FileInfo(filePath).Length))
{
int b;
while((b = viewStream.ReadByte()) != -1)
{
int acc = b;
bool readUtfDataBytes(int bytesToRead)
{
while (bytesToRead-- > 0)
{
var nextB = viewStream.ReadByte();
if (nextB == -1) return false; // EOS reached
if ((nextB & 0xC0) != 0x80) return false; // invalid UTF-8 data byte
acc <<= 6;
acc |= nextB & 0x3F;
}
return true;
}
if (b >= 0xF0) // 1111 0000
{
acc &= 0x07;
if (!readUtfDataBytes(3)) break; // break on malformed UTF-8
}
else if (b >= 0xE0) // 1110 0000
{
acc &= 0x0F;
if (!readUtfDataBytes(2)) break; // break on malformed UTF-8
}
else if (b >= 0xC0) // 1100 0000
{
acc &= 0x1F;
if (!readUtfDataBytes(1)) break; // break on malformed UTF-8
}
else if (b >= 0x80)
{
break; // break on malformed UTF-8
}
if (acc == 0xFEFF)
{
// ignore UTF-8 BOM
}
else
{
resultAsString.Append(Char.ConvertFromUtf32(acc));
}
}
}

Input to SQL Stored Procedure

I am trying to grab a querystring from the URL and send it to my stored procedure in MSSQL. The querystring is of type varbinary and when i try to send it my application is throwing an exception. I also wanted to return the select statement at the bottom of my storedprocedure that simply says Select 'Processed'
had to actually create a function to parse hex code and then send it to the database
static byte[] ParseHexString(string value)
{
if (string.IsNullOrEmpty(value)) return null;
if (1 == (1 & value.Length)) throw new ArgumentException("Invalid length for a hex string.", "value");
int startIndex = 0;
int length = value.Length;
char[] input = value.ToCharArray();
if ('0' == input[0] && 'x' == input[1])
{
if (2 == length) return null;
startIndex = 2;
length -= 2;
}
Func<char, byte> charToWord = c =>
{
if ('0' <= c && c <= '9') return (byte)(c - '0');
if ('A' <= c && c <= 'F') return (byte)(10 + c - 'A');
if ('a' <= c && c <= 'f') return (byte)(10 + c - 'a');
throw new ArgumentException("Invalid character for a hex string.", "value");
};
byte[] result = new byte[length >> 1];
for (int index = 0, i = startIndex; index < result.Length; index++, i += 2)
{
byte w1 = charToWord(input[i]);
byte w2 = charToWord(input[i + 1]);
result[index] = (byte)((w1 << 4) + w2);
}
return result;
}
If you wish Byte[] type, You can try with this code, you don't pass string
cmd.Parameters.Add("#dec", SqlDbType.VarBinary).Value = ;//Relpace with your new Byte[]
Or if you want string type, you can try with string type
cmd.Parameters.Add("#dec", SqlDbType.VarChar).Value = QS;//Your string
Link : http://msdn.microsoft.com/fr-fr/library/system.data.sqldbtype%28v=vs.80%29.aspx
Shouldn't you send a byte array (byte[]) for a binary? I don't think it will accept pure strings. Try converting it to byte array with System.Text.Encoding.UTF8.GetBytes method.
UPDATE: This question's answer tells to use a special type for binary data: What SqlDbType maps to varBinary(max)?
Aghilas has specified how to assign value as byte array, and in the second line
and the regular way of passing as values

Generating URL-friendly unique string with embedded datetime

I'm personally tired of reimplementing "a ticket" mechanism for my web projects for some one-time operations like account activation or password reset. I know it's simple but it requires me to keep (and persist!) two pieces of data: a ticket itself and an expiration date.
So I have this idea, to generate a unique string with embedded datetime (expiration date) in it, which we can check upon receiving as a part of url-request.
I've started with this:
var clearTicket = Convert.ToInt64(expiration.ToString("yyyyMMddhhmm")).ToString("x12") + key.ToString("N");
But I want it to be more compact. Something BaseXX-ish I suppose.
Any ideas how to implement this encoding/decoding efficiently (considering url-safe charset)?
It took me some time, so I hope it helps:
First of all, you should substract 200000000000 from "yyyyMMddhhmm", because you actually don't need the first two digits for the next 88 years.
Here is the implementation for encoding and decoding Base64, using only URL-safe characters.
If you have any questions, feel free to ask.
public string Base64Encode (Int64 Number)
{
string HelpString = "";
if (Number >= 64)
{
HelpString = Base64Encode(Number / 64);
}
return (HelpString += Base64EncodeHelper(Number % 64));
}
public string Base64EncodeHelper(Int64 Number)
{
string HelpString = "";
Number += 65;
if ((Number >= 65 && Number <= 90) || (Number >= 97 && Number <= 122)) // 0 - 25 and 32 - 57
{
HelpString = Convert.ToString((char)Number);
}
else if (Number >= 91 && Number <= 96) // 26 - 31
{
HelpString = Convert.ToString((char)(Number - 43));
}
else if (Number >= 123 && Number <= 126) // 58 - 61
{
HelpString = Convert.ToString((char)(Number - 69));
}
else if (Number == 127) // 62
{
HelpString = "-";
}
else // 63
{
HelpString = "_";
}
return (HelpString);
}
public Int64 Base64Decode(string Encoded)
{
Int64 Result = 0, HelpInt = 0;
int i = Encoded.Length - 1;
foreach (char Character in Encoded)
{
int CharInInt = (int)Character;
if (Character == '_')
{
HelpInt = 63;
}
else if (Character == '-')
{
HelpInt = 62;
}
else if (((CharInInt + 69) >= 123) && ((CharInInt + 69) <= 126))
{
HelpInt = CharInInt + 4;
}
else if (((CharInInt + 43) >= 91) && ((CharInInt + 43) <= 96))
{
HelpInt = CharInInt - 22;
}
else
{
HelpInt = CharInInt - 65;
}
Result += Convert.ToInt64((Math.Pow(64, Convert.ToDouble(i))) * HelpInt);
i--;
}
return Result;
}
You can extend string like this:
public static string ToURLParameter(this string text)
{
if (String.IsNullOrEmpty(text)) return "";
// to lowercase, trim extra spaces
text = text.Trim();
var len = text.Length;
var sb = new StringBuilder(len);
bool prevdash = false;
char c;
//
text = text.Replace('Å', 'A');
text = text.Replace('å', 'a');
text = text.Replace('Ä', 'A');
text = text.Replace('ä', 'a');
text = text.Replace('Ö', 'O');
text = text.Replace('ö', 'o');
for (int i = 0; i < text.Length; i++)
{
c = text[i];
if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-')
{
if (!prevdash)
{
sb.Append('-');
prevdash = true;
}
}
else if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'))
{
sb.Append(c);
prevdash = false;
}
if (i == 80) break;
}
text = sb.ToString();
// remove trailing dash, if there is one
if (text.EndsWith("-"))
text = text.Substring(0, text.Length - 1);
return text;
}
and then you can use it on any variable that is string like:
string something = "asdfljasdklf";
<%= something.ToUrlParameter() %>
I've finally created a solution using techniques described in these answers:
Compressing big number (or string) to small value
How do you convert Byte Array to Hexadecimal String, and vice versa?
Works great!
Thanks you all for your help!

Converting long string of binary to hex c#

I'm looking for a way to convert a long string of binary to a hex string.
the binary string looks something like this "0110011010010111001001110101011100110100001101101000011001010110001101101011"
I've tried using
hex = String.Format("{0:X2}", Convert.ToUInt64(hex, 2));
but that only works if the binary string fits into a Uint64 which if the string is long enough it won't.
is there another way to convert a string of binary into hex?
Thanks
I just knocked this up. Maybe you can use as a starting point...
public static string BinaryStringToHexString(string binary)
{
if (string.IsNullOrEmpty(binary))
return binary;
StringBuilder result = new StringBuilder(binary.Length / 8 + 1);
// TODO: check all 1's or 0's... throw otherwise
int mod4Len = binary.Length % 8;
if (mod4Len != 0)
{
// pad to length multiple of 8
binary = binary.PadLeft(((binary.Length / 8) + 1) * 8, '0');
}
for (int i = 0; i < binary.Length; i += 8)
{
string eightBits = binary.Substring(i, 8);
result.AppendFormat("{0:X2}", Convert.ToByte(eightBits, 2));
}
return result.ToString();
}
This might help you:
string HexConverted(string strBinary)
{
string strHex = Convert.ToInt32(strBinary,2).ToString("X");
return strHex;
}
Convert.ToInt32("1011", 2).ToString("X");
For string longer than this, you can simply break it into multiple bytes:
var binary = "0110011010010111001001110101011100110100001101101000011001010110001101101011";
var hex = string.Join(" ",
Enumerable.Range(0, binary.Length / 8)
.Select(i => Convert.ToByte(binary.Substring(i * 8, 8), 2).ToString("X2")));
I came up with this method. I am new to programming and C# but I hope you will appreciate it:
static string BinToHex(string bin)
{
StringBuilder binary = new StringBuilder(bin);
bool isNegative = false;
if (binary[0] == '-')
{
isNegative = true;
binary.Remove(0, 1);
}
for (int i = 0, length = binary.Length; i < (4 - length % 4) % 4; i++) //padding leading zeros
{
binary.Insert(0, '0');
}
StringBuilder hexadecimal = new StringBuilder();
StringBuilder word = new StringBuilder("0000");
for (int i = 0; i < binary.Length; i += 4)
{
for (int j = i; j < i + 4; j++)
{
word[j % 4] = binary[j];
}
switch (word.ToString())
{
case "0000": hexadecimal.Append('0'); break;
case "0001": hexadecimal.Append('1'); break;
case "0010": hexadecimal.Append('2'); break;
case "0011": hexadecimal.Append('3'); break;
case "0100": hexadecimal.Append('4'); break;
case "0101": hexadecimal.Append('5'); break;
case "0110": hexadecimal.Append('6'); break;
case "0111": hexadecimal.Append('7'); break;
case "1000": hexadecimal.Append('8'); break;
case "1001": hexadecimal.Append('9'); break;
case "1010": hexadecimal.Append('A'); break;
case "1011": hexadecimal.Append('B'); break;
case "1100": hexadecimal.Append('C'); break;
case "1101": hexadecimal.Append('D'); break;
case "1110": hexadecimal.Append('E'); break;
case "1111": hexadecimal.Append('F'); break;
default:
return "Invalid number";
}
}
if (isNegative)
{
hexadecimal.Insert(0, '-');
}
return hexadecimal.ToString();
}
Considering four bits can be expressed by one hex value, you can simply go by groups of four and convert them seperately, the value won't change that way.
string bin = "11110110";
int rest = bin.Length % 4;
if(rest != 0)
bin = new string('0', 4-rest) + bin; //pad the length out to by divideable by 4
string output = "";
for(int i = 0; i <= bin.Length - 4; i +=4)
{
output += string.Format("{0:X}", Convert.ToByte(bin.Substring(i, 4), 2));
}
If you want to iterate over the hexadecimal representation of each byte in the string, you could use the following extension. I've combined Mitch's answer with this.
static class StringExtensions
{
public static IEnumerable<string> ToHex(this String s) {
if (s == null)
throw new ArgumentNullException("s");
int mod4Len = s.Length % 8;
if (mod4Len != 0)
{
// pad to length multiple of 8
s = s.PadLeft(((s.Length / 8) + 1) * 8, '0');
}
int numBitsInByte = 8;
for (var i = 0; i < s.Length; i += numBitsInByte)
{
string eightBits = s.Substring(i, numBitsInByte);
yield return string.Format("{0:X2}", Convert.ToByte(eightBits, 2));
}
}
}
Example:
string test = "0110011010010111001001110101011100110100001101101000011001010110001101101011";
foreach (var hexVal in test.ToHex())
{
Console.WriteLine(hexVal);
}
Prints
06
69
72
75
73
43
68
65
63
6B
If you're using .NET 4.0 or later and if you're willing to use System.Numerics.dll (for BigInteger class), the following solution works fine:
public static string ConvertBigBinaryToHex(string bigBinary)
{
BigInteger bigInt = BigInteger.Zero;
int exponent = 0;
for (int i = bigBinary.Length - 1; i >= 0; i--, exponent++)
{
if (bigBinary[i] == '1')
bigInt += BigInteger.Pow(2, exponent);
}
return bigInt.ToString("X");
}
Considering four bits can be expressed by one hex value, you can simply go by groups of four and convert them seperately, the value won't change that way.
string bin = "11110110";
int rest = bin.Length % 4;
bin = bin.PadLeft(rest, '0'); //pad the length out to by divideable by 4
string output = "";
for(int i = 0; i <= bin.Length - 4; i +=4)
{
output += string.Format("{0:X}", Convert.ToByte(bin.Substring(i, 4), 2));
}
static string BinToHex(string bin)
{
if (bin == null)
throw new ArgumentNullException("bin");
if (bin.Length % 8 != 0)
throw new ArgumentException("The length must be a multiple of 8", "bin");
var hex = Enumerable.Range(0, bin.Length / 8)
.Select(i => bin.Substring(8 * i, 8))
.Select(s => Convert.ToByte(s, 2))
.Select(b => b.ToString("x2"));
return String.Join(null, hex);
}
Using LINQ
string BinaryToHex(string binaryString)
{
var offset = 0;
StringBuilder sb = new();
while (offset < binaryString.Length)
{
var nibble = binaryString
.Skip(offset)
.Take(4);
sb.Append($"{Convert.ToUInt32(nibble.toString()), 2):X}");
offset += 4;
}
return sb.ToString();
}
You can take the input number four digit at a time. Convert this digit to ex ( as you did is ok ) then concat the string all together. So you obtain a string representing the number in hex, independetly from the size. Depending on where start MSB on your input string, may be the output string you obtain the way i described must be reversed.

Categories

Resources