Alright, I am reading some data from an old DOS file into a buffer in memory. However, the variables in DOS and XP x64 are different sizes and I am not sure how to get just what I need out of the memory buffer. For example, a DOS 'long' is four bytes, but that is eight bytes on x64 hardware. If my data buffer is a megabyte or two, how can I point that new 64bit long at a point in that buffer and have it get only four bytes of data out of it so it will be correct?
What exactly do you intend to do with your buffer?
Just for reading and processing those variables it does not matter how long the variables are but you have to know their structure.
You can create a buffer of unsigned chars and read the whole file.
Then you can get each variable by its start address (maybe you have to change endianness I don't know).
E.g.
1 2 3 4 5 6
unsignedchar *chars = newunsignedchar[FILESIZE];
// read file and save it in the buffer chars
unsignedlong *test;// 8 bytes
// set the address of the pointer at the place you wish
// to let you get the value of the next 8 bytes through *test
test = (unsignedlong*) (chars+VARIABLE_START_POSITION);
You could also access the variables just by typecasting without to create a pointer to the address you wish of the data type with X bytes size.
I won't have to change anything. I do read the data into a buffer the size of the file. But here is where it gets tricky. The first four bytes are a DOS 'long" that gives the number of records in the file, which start behind the four bytes for the 'long'.
1 2 3 4
char pData[2048]; //2kb for this example
long lRecordCount;
lRecordCount = &(pData[0]);
Unless I am mistaken, that will work properly on 16bit and even 32bit systems, but my trouble arises when I hit 64bit machines. The above code would start at the beginning of the buffer, but on an x64 system, wouldn't it read eight bytes instead of four since a 64bit long is eight bytes? I have never tried this before so I am completely lost. if this was a file, I could simply use 'fstream' to read four bytes of the file, but that's no good here.
*EDIT*
A better example is below. Assume that 'pData' points to a buffer anywhere from a few kB to a few MB in size.
1 2 3 4 5 6 7 8
//Get the required data from the buffer
this->lPreRecordCount = (long)&(pData[0]);
lJump = ((this->lPreRecordCount * 6) + 11);
this->pHeader->lXPosition = (long)&(pData[lJump]);
lJump += 4;
this->pHeader->lYPosition = (long)&(pData[lJump]);
lJump += 14;
this->pHeader->sLocationID = (short)&(pData[lJump]);
See I don't need all of the data in the file to do my work, only specifics. In this example, I grab the X and Y coordinates for another part of my program, and then grab the unique location identifier. The data between this info is useless to me and I skip it.
I changed the above to unsigned long since it is 64 bit, my mistake.
Here a table from Wikipedia
1 2 3 4 5
Data model shortintlonglonglong pointers Sample operating systems
LLP64 16 32 32 64 64 Microsoft Win64 (X64/IA64)
LP64 16 32 64 64 64 Most UNIX and UNIX-like systems (Solaris, Linux, etc)
ILP64 16 64 64 64 64 HAL
SILP64 64 64 64 64 64 ?
Either you know what data model you are looking for you can use a short int for example if that is the case if not you can do something like this when reading an unsigned variable with 32 bits for example (big endian):
1 2
// save 4 bytes no matter if lRecordCount is 4 or 8 bytes long
lRecordCount = (&(pData[0])) & 0xFFFFFFFF;
Could you explain that method in detail? I will also need to read in both signed and unsigned 'short' variables, signed and unsigned 'int' variables, and unsigned 'long' variables. I do not believe that I need to read in any float or double data types. The DOS program used only short, int, and long, as well as char, but char is the same on all platforms.
*EDIT*
Will that method work on both 32bit and 64bit platforms? This application will be released on 32bit and 64bit Windows initially, and 32bit and 64bit Linux later.
Here the example for 1, 2, and 4 bytes signed and unsigned with the same method. I'll take a 8byte container even though not necessary (the 'container' has to be at least 4 bytes long or more to read 4 bytes):
1 2 3 4 5 6 7 8 9 10 11 12 13
unsignedlonglong *container;
unsignedshort i;
unsignedchar *chars = newunsignedchar[20];
for(i = 0; i < 20; i++){chars[i] = 0xFF;}
// an example start byte is 10 from 0..19 (8 bytes)
container = (unsignedlonglong*)(chars+10);
// write unsigned 8 bit AND with 8bit set
cout << ((*container) & 0xFFULL) << "\n";
// write unsigned 16 bit AND with 16bit set
cout << ((*container) & 0xFFFFULL) << "\n";
// write unsigned 32 bit AND with 32bit set
cout << ((*container) & 0xFFFFFFFFULL) << "\n";<< "\n";
delete [] chars;
I'm sure there are niftier possiblities for the signed variables but this should work.
Yes, it does not matter if on a 32 bit or 64 bit platform (even if you declare the container as unsignedint *container; you will be able to read a variable of a maximum of 4 bytes) [edit]On a 16 bit platform it wouldn't work with an integer ;)[/edit]
[edit2]sry signed was not correct like this, I will write a correct version later.[/edit2]
[edit3]
While writing the signe version which would have been quite a little longer than the unsigned a much better and easier version crossed my mind. It was stupid of me not to think of it first (signed/unsigned 8-64bit):
There was actually a fairly easy answer all along that was overlooked. The code below works perfectly. I simply use a 32/64bit short for 16bit short/int, and a 32/64bit int for 16bit long. The rest is self-explanatory.
1 2 3 4 5 6 7 8
//Get the required data from the buffer
this->iPreRecordCount = *((signedint*)pData);
lJump = ((this->iPreRecordCount * 6) + 11);
this->pHeader->iXPosition = *((signedint*)(pData + lJump));
lJump += 4;
this->pHeader->iYPosition = *((signedint*)(pData + lJump));
lJump += 14;
this->pHeader->sLocationID = *((signedshortint*)(pData + lJump));