Author | Message | Time |
---|---|---|
z-stars | I'm making a packet builder for a bot in C++ and I wanna make a function that takes a DWORD (unsigned long) and puts it into a 4 bytes array. For example, if the DWORD's value was 10, the bytes array would have to be {0x00, 0x00, 0x00, 0x0A}. The problem is that I dunno how to do that. Thx in advance for ur help. (PS: I know that the dwords of a packet are in LittleEndian order but the order can be shifted later I think?) | July 21, 2004, 6:29 PM |
shadypalm88 | Take this advice with a grain of salt; I'm pretty new to C++ and am also writing a C++ packet buffer atm. However I did create a working buffer in Java and I'm basically porting it to C++. Basically you need to extract the relevant byte from the long and cast it onto a char. So if you have a char array named buffer, a variable called buflen keeping track of the length, and a variable called DWord containing the unsigned long, this code should work: [code]buffer[buflen++] = (char) (DWord & 0x000000FF); buffer[buflen++] = (char) ((DWord & 0x0000FF00) >> 8); buffer[buflen++] = (char) ((DWord & 0x00FF0000) >> 16); buffer[buflen++] = (char) ((DWord & 0xFF000000) >> 24);[/code] As I used another buffer (don't remember where I got it) as a reference to create my Java buffer, my assumptions might not be correct. The bitmask being AND'd with the DWORD preserves the byte you are currently interested in while setting the others to 0. The shifts move the byte you want to the point where the cast to a char will catch it. It's not a very good explanation; someone please correct me where I'm wrong | July 21, 2004, 6:51 PM |
Kp | [quote author=z-stars link=board=17;threadid=7800;start=0#msg71690 date=1090434577]I'm making a packet builder for a bot in C++ and I wanna make a function that takes a DWORD (unsigned long) and puts it into a 4 bytes array. For example, if the DWORD's value was 10, the bytes array would have to be {0x00, 0x00, 0x00, 0x0A}. The problem is that I dunno how to do that. Thx in advance for ur help. (PS: I know that the dwords of a packet are in LittleEndian order but the order can be shifted later I think?)[/quote] Easy. Mask out 8 bits at a time, storing each masked value into the appropriate array cell. Sample C code follows, which will produce the result you mentioned. Note that the result you mentioned is backwards from what most of us expect when we say to insert a dword into the buffer. :) [code] buf[ 3 ] = mylong & 0xff; mylong >>= 8; buf[ 2 ] = mylong & 0xff; mylong >>= 8; buf[ 1 ] = mylong & 0xff; buf[ 0 ] = mylong >> 8;[/code] | July 21, 2004, 6:52 PM |
z-stars | Thank you ppl it works :) | July 21, 2004, 7:09 PM |
iago | That's the easy way to do it, but not really the right way. Look up pointers :) | July 21, 2004, 7:24 PM |
Kp | [quote author=iago link=board=17;threadid=7800;start=0#msg71703 date=1090437890]That's the easy way to do it, but not really the right way. Look up pointers :)[/quote] What pointer-based solution do you propose for meeting the specified criteria? | July 21, 2004, 9:11 PM |
K | suppose you have a byte array: [code] // an array of 64 unsigned characters. BYTE bBuffer[64]; [/code] and an integer that tells you where the next data should be put: [code] int iNextPutIndex = 16; // the first unused index of the byte array bBuffer // i.e, bBuffer[16] is one past the end of our current data [/code] now, since we know that a DWORD is simply four bytes, and is represented like so in memory, and that a BYTE array is simply a block of 64 bytes in memory, let's have some pointer fun. [code] // this is the value we want to insert. DWORD dwToWrite = 0x00ABCDEF; // get the address in memory of the dword we want to write. DWORD* lpdwAddrOfdwToWrite = &dwToWrite; [/code] so now, think of our pointer to a dword as simply an array of four bytes. that's all an object in memory is, right? groups of bytes? So we could do this: [code] BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddrOfdwToWrite); // put the four bytes into our array for(int i = 0; i < 4; ++i) bBuffer[iNextPutIndex++] = bFourBytes[i]; [/code] or, we could just copy it over into the byte array we already have, like this: [code] BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddOrdwToWrite); memcpy(&bBuffer[iNextPutIndex], bFourBytes, 4); iNextPutIndex += 4; [/code] My code may be a little verbose, but that's the basic idea. Good luck! Edit: Added memcpy length arg. :P | July 21, 2004, 9:19 PM |
Kp | I expected to catch somebody screwing up and not reading the project specifications. I didn't expect it to be K. :) The original poster asked to have the lowermost byte of the long end up in the rightmost byte of result, which would be true on a big endian system. However, most (all?) bot development seems to be done on little endian systems, so a direct memory copy from one pointer to another will end up with the wrong order, relative to what the poster specified. Also, minor correction to K's code. memcpy takes three arguments, not two. The third argument is the amount to copy. See the manpage for full details. | July 21, 2004, 9:27 PM |
K | [quote author=Kp link=board=17;threadid=7800;start=0#msg71718 date=1090445270] I expected to catch somebody screwing up and not reading the project specifications. I didn't expect it to be K. :) The original poster asked to have the lowermost byte of the long end up in the rightmost byte of result, which would be true on a big endian system. However, most (all?) bot development seems to be done on little endian systems, so a direct memory copy from one pointer to another will end up with the wrong order, relative to what the poster specified. Also, minor correction to K's code. memcpy takes three arguments, not two. The third argument is the amount to copy. See the manpage for full details. [/quote] Well fine, use htonl first. ;) You're right, I completely missed the endianness. | July 21, 2004, 9:31 PM |
tA-Kane | So to recap, ya'll have gone over apparently three ways of putting a DWORD into a BYTE array, two very similar with endian conversion, one directly. Very long, with endian conversion: [code]buffer[buflen++] = (char) (DWord & 0x000000FF); buffer[buflen++] = (char) ((DWord & 0x0000FF00) >> 8); buffer[buflen++] = (char) ((DWord & 0x00FF0000) >> 16); buffer[buflen++] = (char) ((DWord & 0xFF000000) >> 24);[/code] Not as long, with endian conversion: [code]buf[ 3 ] = mylong & 0xff; mylong >>= 8; buf[ 2 ] = mylong & 0xff; mylong >>= 8; buf[ 1 ] = mylong & 0xff; buf[ 0 ] = mylong >> 8;[/code] Long and confusing, without endian conversion: [code]// an array of 64 unsigned characters. BYTE bBuffer[64]; int iNextPutIndex = 16; // the first unused index of the byte array bBuffer // i.e, bBuffer[16] is one past the end of our current data // this is the value we want to insert. DWORD dwToWrite = 0x00ABCDEF; // get the address in memory of the dword we want to write. DWORD* lpdwAddrOfdwToWrite = &dwToWrite; BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddrOfdwToWrite); // put the four bytes into our array for(int i = 0; i < 4; ++i) bBuffer[iNextPutIndex++] = bFourBytes; BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddOrdwToWrite); memcpy(&bBuffer[iNextPutIndex], bFourBytes, 4); iNextPutIndex += 4; [/code] Now, for [i]my solution, which is fairly short, quite simple, and even has endian conversion: [code]char Dst[4]; long *Buffer, Value; Value = 0x12345678; Buffer = (long *)Dst; /* buffer now points to the char array Dst */ *Buffer = ChangeEndian32(Value); /* Dst now contains the characters 0x78, 0x56, 0x34, and 0x12 in that order */[/code] Note that you'll need ROR32, ROL32, and ChangeEndian32 (rotate right, rotate left, and change endianness for 32 bits, respectively), which are defined as: [code]#define ROR32(value,count) ((value >> count) | (value << (32-count))) #define ROL32(value,count) ((value << count) | (value >> (32-count))) #define ChangeEndian32(value) (ROL32(value & 0xFF00FF00, 8) | ROR32(value & 0x00FF00FF, 8))[/code]These #defines should go into a header file, since they're used fairly often (especially so if you're needing endian swapping capability). Since they go into a header file, I don't count them toward the size of that code... ;) Edit:[quote author=K link=board=17;threadid=7800;start=0#msg71720 date=1090445501]Well fine, use htonl first. ;) You're right, I completely missed the endianness.[/quote]The problem with using htonl is that it's not going to do anything if the network byte order and the host byte order are the same, is it? | July 22, 2004, 5:16 PM |
kamakazie | [quote author=tA-Kane link=board=17;threadid=7800;start=0#msg71869 date=1090516598] Edit:[quote author=K link=board=17;threadid=7800;start=0#msg71720 date=1090445501]Well fine, use htonl first. ;) You're right, I completely missed the endianness.[/quote]The problem with using htonl is that it's not going to do anything if the network byte order and the host byte order are the same, is it? [/quote] How is using htonl a problem? | July 22, 2004, 6:11 PM |
Adron | htonl is a great function to use. It means the code works on all systems. Now for some code: [code] union { char buf[4]; unsigned int dword; }; dword = htonl(10); [/code] or simply [code] char buf[4]; *reinterpret_cast<unsigned long*>(buf) = htonl(10); [/code] | July 22, 2004, 7:56 PM |
tA-Kane | What about when the network byte order is the same as the host byte order? Would htonl still swap the endianness? By the definition of "host to network (long)", it would not. I'll give you an example. Mac OS X's host byte order is the same as network byte order; Big Endian. That is, the value 0x12345678 is exactly that when stored in memory. It's not stored as 0x78 0x56 0x34 0x12. Now if you wanted to send that value to Battle.net, you'd need to send the bytes 0x78 0x56 0x34 0x12, instead of the "natural" bytes of 0x12 0x34 0x56 0x78. Using htonl() in this case would not be beneficial, would it, since htonl() would (should) do nothing? So, if Mac OS X were to use htonl() with 0x12345678, and then send that to Battle.net, Battle.net would receive 0x12 0x34 0x56 0x78. Battle.net would then read that as 0x78563412, which is a different value than origionally sent. Sure, the code works on all systems, but that doesn't mean that it has the desired results. Am I wrong? | July 23, 2004, 4:31 AM |
kamakazie | [quote author=tA-Kane link=board=17;threadid=7800;start=0#msg72000 date=1090557098] What about when the network byte order is the same as the host byte order? Would htonl still swap the endianness? By the definition of "host to network (long)", it would not. I'll give you an example. Mac OS X's host byte order is the same as network byte order; Big Endian. That is, the value 0x12345678 is exactly that when stored in memory. It's not stored as 0x78 0x56 0x34 0x12. Now if you wanted to send that value to Battle.net, you'd need to send the bytes 0x78 0x56 0x34 0x12, instead of the "natural" bytes of 0x12 0x34 0x56 0x78. Using htonl() in this case would not be beneficial, would it, since htonl() would (should) do nothing? So, if Mac OS X were to use htonl() with 0x12345678, and then send that to Battle.net, Battle.net would receive 0x12 0x34 0x56 0x78. Battle.net would then read that as 0x78563412, which is a different value than origionally sent. Sure, the code works on all systems, but that doesn't mean that it has the desired results. Am I wrong? [/quote] The original specification calls for the byte order to be big-endian so there should be no problem. | July 23, 2004, 4:19 PM |
Adron | [quote author=tA-Kane link=board=17;threadid=7800;start=0#msg72000 date=1090557098] Am I wrong? [/quote] You're wrong in this problem. If you don't use htonl, but use some code to always swap the bytes, you'll be swapping the bytes wrong on systems where the bytes were already right from the start (i.e. Mac OS X). You should look more closely at the original specification. He asked for how to put the bytes in network byte order, not how to put them in the byte order battle.net expects. | July 23, 2004, 6:29 PM |
tA-Kane | [quote author=Adron link=board=17;threadid=7800;start=0#msg72065 date=1090607391]You should look more closely at the original specification. He asked for how to put the bytes in network byte order, not how to put them in the byte order battle.net expects.[/quote]I was simply pointing out that Battle.net's byte order is not network byte order, and thusly htonl() shouldn't be useful for Battle.net. If his post isn't in regards to Battle.net, what's it doing in the Battle.net bot development forum? I do agree that if all you want/need to do is put the bytes in network byte order, htonl() is what you should use, and not custom code. | July 24, 2004, 3:50 AM |
kamakazie | [quote author=tA-Kane link=board=17;threadid=7800;start=15#msg72149 date=1090641054] [quote author=Adron link=board=17;threadid=7800;start=0#msg72065 date=1090607391]You should look more closely at the original specification. He asked for how to put the bytes in network byte order, not how to put them in the byte order battle.net expects.[/quote] I was simply pointing out that Battle.net's byte order is not network byte order, and thusly htonl() shouldn't be useful for Battle.net. If his post isn't in regards to Battle.net, what's it doing in the Battle.net bot development forum? I do agree that if all you want/need to do is put the bytes in network byte order, htonl() is what you should use, and not custom code. [/quote] When you first said using htonl() is a problem, you never mentioned Battle.net. | July 24, 2004, 6:05 PM |