A breakthrough I had
Just thought I would share a breakthrough that I had. You may think it's no big deal but I was stuck for an entire hour.
So I'm writing an IPS file patcher. Long story short, the IPS file stores its "records" in this format: (3 byte offset, 2 byte LENGTH, LENGTH bytes)
The problem is that the offset and length fields are stored as Big-Endian in the file.
So when you read the numbers from the file, it would read the numbers stored as Big-Endian as Little-Endian, which causes obvious issues.
2nd problem is, there are data types for 2 byte long data, but no such thing for data that is 3 bytes long.
So you have to use a larger data type (in this case a dword) to store it. This is fine, because if you put something smaller, it will just pad the most significant bits with zeros until the data begins.
Here is where the issue arises:
I use this to swap endians for a dword
This works if all of the bytes in x are taken, for example 0x1A2B3C4D. It will convert it to 0x4D3C2B1A.
However, like I said, since I am loading a 24 bit value into a 32 bit data type, the leftmost bits get padded with zeros.
If I load ABCDEF (in hexadecimal, obviously) into x, internally it will be stored as 0x00ABCDEF.
Thus, when the endian is swapped, it will result in 0xEFCDAB00. This is the issue. Because EFCDAB00 and EFCDAB are NOT the same thing. The former is a much larger number than intended.
So how do we convert the number back to 24 bits? I was stuck on this for an hour, until I finally thought of this:
First, you shift x to the right 8 bits. This will cause the problematic zeros on the right to go away.
However, now the leftmost bits contain FF. So now we have 0xFFEFCDAB.
Now, to get rid of the garbage on the left, we use bitwise and (&) with 0x00FFFFFF to get rid of them, and now we have our precious desired result: 0x00EFCDAB.
Example:

So I'm writing an IPS file patcher. Long story short, the IPS file stores its "records" in this format: (3 byte offset, 2 byte LENGTH, LENGTH bytes)
The problem is that the offset and length fields are stored as Big-Endian in the file.
So when you read the numbers from the file, it would read the numbers stored as Big-Endian as Little-Endian, which causes obvious issues.
2nd problem is, there are data types for 2 byte long data, but no such thing for data that is 3 bytes long.
So you have to use a larger data type (in this case a dword) to store it. This is fine, because if you put something smaller, it will just pad the most significant bits with zeros until the data begins.
Here is where the issue arises:
I use this to swap endians for a dword
Code:
dword swapEndian32(dword x)
{
return (x >> 24) |
((x << 8) & 0x00FF0000) |
((x >> 8) & 0x0000FF00) |
(x << 24);
}
However, like I said, since I am loading a 24 bit value into a 32 bit data type, the leftmost bits get padded with zeros.
If I load ABCDEF (in hexadecimal, obviously) into x, internally it will be stored as 0x00ABCDEF.
Thus, when the endian is swapped, it will result in 0xEFCDAB00. This is the issue. Because EFCDAB00 and EFCDAB are NOT the same thing. The former is a much larger number than intended.
So how do we convert the number back to 24 bits? I was stuck on this for an hour, until I finally thought of this:
Code:
dword _32to24(dword x)
{
return ((x >> 8) & 0x00FFFFFF);
}
However, now the leftmost bits contain FF. So now we have 0xFFEFCDAB.
Now, to get rid of the garbage on the left, we use bitwise and (&) with 0x00FFFFFF to get rid of them, and now we have our precious desired result: 0x00EFCDAB.
Example:

On 64 bit machines, as the name of the type suggests, it is 64 bit. It might be better to use types with a fixed size.