I'm trying to convert a bit of VC 6.0 C++ code to C#. Specifically, I'm parsing through a binary dat file and I've run into a problem converting this bit of code:
ar.GetFile()->Read(buf,sizeof(int));
memmove(&x,buf,4);
pEBMA->before_after = static_cast<enum EBMA_Reserve>(x);
pEBMA->method = static_cast<enum EBMA_Method>(x >> 4);
Here is some related code.
struct EBMA_Data *pEBMA = &EBMA_data;
typedef CArray<struct EBMA_Data,struct EBMA_Data&> EBMA_data;
enum EBMA_Reserve
{EBMA_DONT_RESERVE,
EBMA_BEFORE,
EBMA_AFTER
};
enum EBMA_Method
{EBMA_CENTER,
EBMA_ALL_MATERIAL,
EBMA_FRACTION,
EBMA_RESERVE
};
struct EBMA_Data
{double reserved;
double fraction;
enum EBMA_Method method : 4;
enum EBMA_Reserve before_after : 4;
};
I've read this thread here Cast int to Enum in C#, but my code isn't giving me the same results as the legacy program.
Here is some of my code in C#:
reserved = reader.ReadDouble();
fraction = reader.ReadDouble();
beforeAfter = (EBMAReserve)Enum.ToObject(typeof(EBMAReserve), x);
method = (EBMAMethod)Enum.ToObject(typeof(EBMAMethod), (x >> 4));
I do have an endianness problem so I am reversing the endianness like so.
public override double ReadDouble()
{
byte[] b = this.ConvertByteArrayToBigEndian(base.ReadBytes(8));
double d = BitConverter.ToDouble(b, 0);
return d;
}
private byte[] ConvertByteArrayToBigEndian(byte[] b)
{
if (BitConverter.IsLittleEndian)
{
Array.Reverse(b);
}
return b;
}
So then I thought that maybe the endianness issue was still throwing me off so here is another attempt:
byte[] test = reader.ReadBytes(8);
Array.Reverse(test);
int test1 = BitConverter.ToInt32(buffer, 0);
int test2 = BitConverter.ToInt32(buffer, 4);
beforeAfter = (EBMAReserve)test1;
method = (EBMAMethod)test2;
I hope I've given enough details about what I'm trying to do.
EDIT:
This is how I solved my issue, apparently the values I needed were stored in the first byte of a 4 byte segment in the binary file. This is in a loop.
byte[] temp = reader.ReadBytes(4);
byte b = temp[0];
res = (EBMAReserve)(b & 0x0f);
meth = (EBMAMethod)(b >> 4);
EDIT: It actually looks like the structure size of EBMA_Data is 17 bytes.
struct EBMA_DATA
{
double reserved; //(8 bytes)
double fraction; //(8 bytes)
enum EBMA_Method method : 4; //(this is packed to 4 bits, not bytes)
enum EMBA_Reserve before_after : 4; //(this too, is packed to 4 bits)
}
so your read code should look something more like this:
EBMA_Data data = new EBMA_Data;
data.reserved = reader.ReadDouble();
data.fraction = reader.ReadDouble();
byte b = reader.ReadByte();
data.method = (EBMAMethod)(b >> 4);
data.before_after = (EBMAReserve)(b & 0x0f);
Not 100% sure, but it looks like the code that does the shift x >> 4 bytes may be the underlying issue that's being overlooked. If the EBMAReserve is the lower 4 bits of x and EBMAMethod is the top 4 bits, maybe this code would work?
EBMAReserve res = (EBMAReserve)(x & 0x0f);
EBMAMethod meth = (EBMAMethod)(x >> 4);
I think that is what the : 4 means after the enumerations in the struct, it's packing the two enums into the structure as a single byte instead of 2 bytes.
Related
The main problem is that I recive a binary number with only 10 bits in use from a SerialPort so I use this to receive the complete data:
byte[] buf = new byte[2];
serialPort.Read(buf, 0, buf.Length);
BitArray bits = new BitArray(buf);
The original idea for convert binary to int was this:
foreach (bool b in bits)
{
if(b){
binary += "1";
}
else{
binary+= "0";
}
}
decimal = Convert.ToInt32(binary, 2);
decimal = decimal >> 6;
binary is obviously a string, that works but I need to know if exists another solution, instead of the previuos code I try with this:
decimal = BitConverter.ToInt16(buf, 0);
But this only read the first 8 bits, I need the other 2 bits missing! If I change ToInt16 for a ToInt32
decimal = BitConverter.ToInt32(buf, 0);
The program stops for a System.ArgumentException: Destination array was not long enough...
What can I do?
You can just shift the values in the bytes so that they match, and put them together. If I got the use of bits right, that would be:
int value = (buf[0] << 2) | (buf[1] >> 6);
I've read the other posts on BitArray conversions and tried several myself but none seem to deliver the results I want.
My situation is as such, I have some c# code that controls an LED strip. To issue a single command to the strip I need at most 28 bits
1 bit for selecting between 2 led strips
6 for position (Max 48 addressable leds)
7 for color x3 (0-127 value for color)
Suppose I create a BitArray for that structure and as an example we populate it semi-randomly.
BitArray ba = new BitArray(28);
for(int i = 0 ;i < 28; i++)
{
if (i % 3 == 0)
ba.Set(i, true);
else
ba.Set(i, false);
}
Now I want to stick those 28 bits in 4 bytes (The last 4 bits can be a stop signal), and finally turn it into a String so I can send the string via USB to the LED strip.
All the methods I've tried convert each 1 and 0 as a literal char which is not the goal.
Is there a straightforward way to do this bit compacting in C#?
Well you could use BitArray.CopyTo:
byte[] bytes = new byte[4];
ba.CopyTo(bytes, 0);
Or:
int[] ints = new int[1];
ba.CopyTo(ints, 0);
It's not clear what you'd want the string representation to be though - you're dealing with naturally binary data rather than text data...
I wouldn't use a BitArray for this. Instead, I'd use a struct, and then pack that into an int when I need to:
struct Led
{
public readonly bool Strip;
public readonly byte Position;
public readonly byte Red;
public readonly byte Green;
public readonly byte Blue;
public Led(bool strip, byte pos, byte r, byte g, byte b)
{
// set private fields
}
public int ToInt()
{
const int StripBit = 0x01000000;
const int PositionMask = 0x3F; // 6 bits
// bits 21 through 26
const int PositionShift = 20;
const int ColorMask = 0x7F;
const int RedShift = 14;
const int GreenShift = 7;
int val = Strip ? 0 : StripBit;
val = val | ((Position & PositionMask) << PositionShift);
val = val | ((Red & ColorMask) << RedShift);
val = val | (Blue & ColorMask);
return val;
}
}
That way you can create your structures easily without having to fiddle with bit arrays:
var blue17 = new Led(true, 17, 0, 0, 127);
var blah22 = new Led(false, 22, 15, 97, 42);
and to get the values:
int blue17_value = blue17.ToInt();
You can turn the int into a byte array easily enough with BitConverter:
var blue17_bytes = BitConverter.GetBytes(blue17_value);
It's unclear to me why you want to send that as a string.
I'm not realizing what is wrong with my code, take a look:
C# code:
const int MOVE = 112;
MemoryStream m = new MemoryStream();
m.SetLength(4 + 1 + (1 + 1 + 1 + 1));
BinaryWriter bw = new BinaryWriter(m);
int id_ = getId();
bw.Write(Converter.GetBigEndian(id_));
sbyte eventMove = MOVE;
sbyte rowFromByte = 4;
sbyte colFromByte = 2;
sbyte rowToByte = 1;
sbyte colToByte = 3;
bw.Write(eventMove);
bw.Write(rowFromByte);
bw.Write(colFromByte);
bw.Write(rowToByte);
bw.Write(colToByte);
When I read on java I do:
ByteBuffer msg = an instance of ByteBuffer...
int id = msg.getInt();
byte event = msg.get();
byte rowFrom = msg.get();
byte colFrom = msg.get();
byte rowTo = msg.get();
byte colTo = msg.get();
Every time I read on java it reaches till the event ok.
Sometimes it works correctly, reads everything ok e.g if I put on c#:
sbyte rowFromByte = 12;
sbyte colFromByte = 2;
sbyte rowToByte = 1;
sbyte colToByte = 3;
It works, but if I put a value <= 7 on the first rowFromByte e.g:
sbyte rowFromByte = 4;
sbyte colFromByte = 2;
sbyte rowToByte = 1;
sbyte colToByte = 3;
the java code doesn't read the values correctly it reads:
rowFrom: -7, colFrom: 0, rowTo: -7, colTo: 0
SOLVED: the values above were printed wrongly (during the wrong time), because of that I thought there were problems with the code.
It prints the corrects values bellow:
rowFrom: 4, colFrom: 2, rowTo: 1, colTo: 3
On c# I use the Memorystream to get the bytes to send to java client:
MemoryStream message = the instance of memory stream...
bytesMessage = message.ToArray();
WHY putting a value <= 7 for rowFrom returns wrong bytes association on java?
There's something very weird or silly I'm not getting into.
I solved the problem.
The problem is that: there wasn't any problem with my code.
As I supposed this was a Silly stuff: I was printing the wrong variables on server.
I didn't know very well C# I posted this question on on stackoverflow.
Maybe this simple example can be useful for other people.
I need to read a byte from a .bin but starting from the specific bit, for example:
If I have this two bytes:
01010111 10101100
The program should be able to read from any bit, let's say starting in bit number 3 (or index 2):
01[010111 10]101100
And the result should be 01011110
I can read a byte starting from any bit except when the starting bit is the one at the end of a byte: 0101011[1 ...] //returns something different..
my code is:
byte readByte(int indexInBits, byte[] bytes)
{
int actualByte = (indexInBits+1)/8;
int indexInByte = (indexInBits)%8;
int b1 = bytes[actualByte] << indexInByte;
int b2 = bytes[actualByte+1] >> 8 - indexInByte;
return (byte)(b1 + b2);
}
What is wrong with it?
Thanks
byte ReadByte(int index, byte[] bytes)
{
int bytePos = index / 8;
int bitPos = index % 8;
int byte1 = bytes[bytePos] << bitPos;
int byte2 = bytes[bytePos + 1] >> 8 - bitPos;
return (byte)(byte1 + byte2);
}
I couldn't verify this right now, but this should work as expected.
I need to pass a parameter as two int parameters to a Telerik Report since it cannot accept Long parameters. What is the easiest way to split a long into two ints and reconstruct it without losing data?
Using masking and shifting is your best bet. long is guaranteed to be 64 bit and int 32 bit, according to the documentation, so you can mask off the bits into the two integers and then recombine.
See:
static int[] long2doubleInt(long a) {
int a1 = (int)(a & uint.MaxValue);
int a2 = (int)(a >> 32);
return new int[] { a1, a2 };
}
static long doubleInt2long(int a1, int a2)
{
long b = a2;
b = b << 32;
b = b | (uint)a1;
return b;
}
static void Main(string[] args)
{
long a = 12345678910111213;
int[] al = long2doubleInt(a);
long ap = doubleInt2long(al[0],al[1]);
System.Console.WriteLine(ap);
System.Console.ReadKey();
}
Note the use of bitwise operations throughout. This avoids the problems one might get when using addition or other numerical operations that might occur using negative numbers or rounding errors.
Note you can replace int with uint in the above code if you are able to use unsigned integers (this is always preferable in this sort of situation, as it's a lot clearer what's going on with the bits).
Doing bit-manipulation in C# can be awkward at times, particularly when dealing with signed values. You need to be using unsigned values whenever you plan on doing bit-manipulation. Unfortunately it's not going to yield the nicest looking code.
const long LOW_MASK = ((1L << 32) - 1);
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
int valueHigh = (int)(value >> 32);
int valueLow = (int)(value & LOW_MASK);
long reconstructed = unchecked((long)(((ulong)valueHigh << 32) | (uint)valueLow));
If you want a nicer way to do this, get the raw bytes for the long and get the corresponding integers from the bytes. The conversion to/from representations doesn't change very much.
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
byte[] valueBytes = BitConverter.GetBytes(value);
int valueHigh = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 4 : 0);
int valueLow = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 0 : 4);
byte[] reconstructedBytes = BitConverter.IsLittleEndian
? BitConverter.GetBytes(valueLow).Concat(BitConverter.GetBytes(valueHigh)).ToArray()
: BitConverter.GetBytes(valueHigh).Concat(BitConverter.GetBytes(valueLow)).ToArray();
long reconstructed = BitConverter.ToInt64(reconstructedBytes, 0);
For unigned the following will work:
ulong value = ulong.MaxValue - 12;
uint low = (uint)(value & (ulong)uint.MaxValue);
uint high = (uint)(value >> 32);
ulong value2 = ((ulong)high << 32) | low;
long x = long.MaxValue;
int lo = (int)(x & 0xffffffff);
int hi = (int)((x - ((long)lo & 0xffffffff)) >> 32);
long y = ((long)hi << 32) | ((long)lo & 0xffffffff);
Console.WriteLine(System.Convert.ToString(x, 16));
Console.WriteLine(System.Convert.ToString(lo, 16));
Console.WriteLine(System.Convert.ToString(hi, 16));
Console.WriteLine(System.Convert.ToString(y, 16));
Converting it to and from a string would be much simpler than converting it two and from a pair of ints. Is this an option?
string myStringValue = myLongValue.ToString();
myLongValue = long.Parse(myStringValue);
Instead of mucking with bit operations, just use a faux union. This also would work for different combinations of data types, not just long & 2 ints. More importantly, that avoids the need to be concerned about signs, endianness or other low-level details when you really only care about reading & writing bits in a consistent manner.
using System;
using System.Runtime.InteropServices;
public class Program
{
[StructLayout(LayoutKind.Explicit)]
private struct Mapper
{
[FieldOffset(0)]
public long Aggregated;
[FieldOffset(0)]
public int One;
[FieldOffset(sizeof(int))]
public int Two;
}
public static void Main()
{
var layout = new Mapper{ Aggregated = 0x00000000200000001 };
var one = layout.One;
var two = layout.Two;
Console.WriteLine("One: {0}, Two: {1}", one, two);
var secondLayout = new Mapper { One = one, Two = two };
var aggregated = secondLayout.Aggregated;
Console.WriteLine("Aggregated: {0}", aggregated.ToString("X"));
}
}