C++ ifstream.read; reads bytes less then given n bytes - c++

I'm trying to split up data into little packets. I'm not exactly sure how this read method is suppose to work but I've given a buffer size of 512 to read from the file.
But instead of getting 512 i just get 5 in my first packet. Others vary from 0 to above 512 ( which shouldn't happen).
It's a zip file I'm trying to split up:
In text the first few bytes look like this
(de bucket like characters are actually 2 characters)
It seems to grab the first 5 bytes as it should but afterwards just stops and goes to the next read block.
Since it's a buffer of 512 everything after the first 5 bytes is garbage.
I'm using an ifstream. And the mode is set to Binary.
Any suggestions?
void FileProcessor::send()
{
//If no file is opened return
if(!_file.is_open()) return;
//Reset position to beginning
_file.seekg(0, ios::beg);
//Result buffer
char * buffer;
char * partBytes = new char[_bufferSize];
//Read the file and send it over the network
while (_file.read(partBytes, _bufferSize))
{
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
//cout << strlen(partBytes);
//p->PrintHex(buffer,_bufferSize+Packet::HeaderSize);
//break;
cout << "Normal size : \t" << strlen(partBytes)<< "\tPacketSize: \t" << p->getLength()<<"\n";
//cout << strcmp(p->getData().c_str(),partBytes) << "\n";
writeToFile(p->getData().c_str(),p->getData().length());
delete p;
}
//Write final bytes if any
if(_file.gcount())
{
//writeToFile(partBytes, _file.gcount());
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
writeToFile(p->getData().c_str(),p->getData().length());
//cout << p->getLength() << "\n";
delete p;
}
//cout<< *p << "\n";
delete [] partBytes;
}
Im just testing a direct read write right now.

Inside your loop, instead of assuming it always reads a full buffer of data, use gcount() to find how many it actually read, and transmit that many.
I feel obliged to add that this:
buffer = Packet::create(Packet::FILE,partBytes);
Packet *p = Packet::create(buffer);
looks quite strange to me. Not sure it's wrong, but it's not immediately obvious that it's right either (and if it is right, the design seems a bit odd).
I'd also skip the dynamic allocation and deletion:
char * partBytes = new char[_bufferSize];
// ...
delete [] partBytes;
and use a std::vector<char> instead.

Related

How to read custom string with C++ from binary recursively

I've recently been getting in to IO with C++. I am trying to read a string from a binary file stream.
The custom type is saved like this:
The string is prefixed with the length of the string. So hello, would be stored like this: 6Hello\0.
I am basically reading text from a table (in this case a name table) in a binary file. The file header tells me the offset of this table (112 bytes in this case) and the number of names (318).
Using this information I can read the first byte at this offset. This tells me the length of the string (e.g. 6). So I'll start at the next byte and read 5 more to get the full string "Hello". This seems to work fine with the first name at the offset. trying to recursively read the rest provides a lot of garbage really. I've tried using loops and recursive functions but its not working out so well. Not sure what the problem is, so reverted to the original one name retrieval method. Here's the code:
int printName(fstream& fileObj, __int8 buff, DWORD offset, int& iteration){
fileObj.seekg(offset);
fileObj.read((char*)&buff, sizeof(char));
int nameSize = (int)buff;
char* szName = new char[nameSize];
for(int i=1; i <= nameSize; i++){
fileObj.seekg(offset+i);
fileObj.read((char*)&szName[i-1], sizeof(char));
}
cout << szName << endl;
return 0;
}
Any idea how to iterate through all 318 names without creating dodgy output?
Thanks for taking the time to look through this, your help is greatly appreciated.
You're overcomplicating a bit - there's no need to seek to the next sequential read.
Removing unused and pointless parameters, I would write this function something like this:
void printName(fstream& fileObj, DWORD offset) {
char size = 0;
if (fileObj.seekg(offset) && fileObj.read(&size, sizeof(char)))
{
char* name = new char[size];
if (fileObj.read(name, size))
{
cout << name << endl;
}
delete [] name;
}
}

Crash after string concatenation in C++

I have this program that reads data from a serial port. For each line, I'm trying to concatenate the current time with the line of data. For some reason, it crashes when around the second print (it seems like at the end of the brackets?). The weird part is, that if I comment the print out, it'll still crash
char * cdata;
{
if( BINARY_ASCII == 1 ) //right now this is just set to 0, please ignore
{
cdata = convertBSTRToByteArray(data , numChars);
}
else
{
cdata = convertBSTRToString(data);
//prints the original output
cout << "before timestamp concat is: " << cdata << "\n";
//this is supposed to concatenate each output line with the associated time
std::stringstream ss;
ss << currentDateTime() << "," << cdata;
std::string s = ss.str();
std::strcpy(cdata,s.c_str());
cout << "after timestamp concat is: " << cdata << "\n"; //around here it crashes
}
cout << "after the thing" << "\n"; //does not even get here
I thought that the char * data would be the issue, but I've tried initializing it like
char *cdata = 0;
and
char *cdata = new char [100];
to no change...
That makes me think that I did something wrong in the concatenation?
I think it's important to highlight the difference between arrays and pointers, here.
char * cdata;
This creates a pointer named cdata. It's uninitialized, so it contains some useless memory address. A pointer is just a memory address, which means it takes up 32 (or 64) bits, and that's it.
char *cdata = 0;
This creates a pointer named cdata, and initializes it to all zeros, which means it points to the 0th location in memory. This is usually used to indicate that you should not follow this pointer.
char *cdata = new char [100];
This creates a block (array) of 100 characters, but gives that array no name. Then it creates a pointer named cdata and sets it to the memory address of the unnamed 100-byte block. I.e.:
cdata [ 0x3Ad783B2 ] --------\
\
\
|
V
[ unnamed 100-byte block ]
The reason I'm stressing this distinction is that the next line obliterates it all:
cdata = convertBSTRToString(data);
That line sets cdata to point to whatever memory address is returned by convertBSTRToString. It does not matter what value cdata had before this line -- uninitialized, null, pointing to an unnamed block of memory -- now it is pointing to the block of memory created by convertBSTRToString.
Abusing more ASCII-art:
cdata [ 0x64ADB7C8 ] --------\
\
\
|
V
[ unknown size, created by convertBSTRToString ]
// hey, look over here! it still exists,
// but we just don't point to it anymore.
[ unnamed 100-byte block ]
Now that that's covered, here's why it matters. This line:
std::strcpy(cdata,s.c_str());
strcpy will take the data pointed to by the second parameter, and copy it, byte-by-byte, to the location pointed to by the first parameter. It does not pay attention to buffer size. It's a really stupid copy. No safety whatsoever - that's up to you to provide.
I'm not sure what you're trying to accomplish with this line anyway, because s holds the full string data you wanted to concatenate:
cout << "after timestamp concat is: " << s << "\n";
convertBSTRToString probably allocates a new buffer that's sized exactly right to hold the BSTR you passed in. That means you cannot expand its size.
In your code, you are trying to add currentDateTime()'s result into that buffer (in addition to its existing content). The data won't fit. Thus, bad things happen.
You would need to first allocate a buffer big enough to contain both the convertBSTRToString plus the currentDateTime then strcpy the convertBSTRToString and then strcat the currentDateTime. strcpy won't append, strcat does.

About socket recv and char[] in C++

I am creating a program that can get package and print it to console by C++.
I set the char array to 1024 like :
char* buffer = new char[1024];
When I get a message is not exactly 1024 character, there is many unknown character on the end of my message because of the empty space in the array. What can I do?
More information (I dont know if it is useful)
The socket is sent by a Java program
Socket socket = new Socket("127.0.0.1", 27555);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("I am your client :D");
out.flush();
And the server is written by C++ console application
char* recvData = new char[1024];
recv(socket, recvData, strlen(recvData), 0);
cout << recvData << endl;
There are three problems with the code:
recvData is unitialised when passed to strlen(). strlen() determines the length of the buffer when it finds a null terminating character, which could be within the buffer or outside. The size of the buffer, less one for terminating null character, should be passed as the maximum number of bytes to read.
the result of recv() is not queried. The code will use recvData even if the recv() failed, which is a bug.
recv() does not null terminate the buffer.
Save the result of recv() and if not -1 use it as an index into recvData to insert the null terminating character.
Alternatively, as this is c++ use a std::vector<char> and to manage dynamic memory allocation for you (if dynamic memory allocation is really required):
std::vector<char> recvData(1025); // Default initializes all elements to 0.
int result = recv(socket, recvData.data(), recvData.size() - 1);
if (result != -1)
{
std::cout << recvData.data() << std::endl;
}
Remember that data sent via sockets it just a stream of bytes, it is not separated into distinct messages. This means that:
out.write("I am your client :D");
might not be read by a single call to recv(). Equally:
out.write("I am your client :D");
out.write("OK");
might be read by a single call to recv(). It is the programmer's responsibility to implement a protocol if message-based processing is required.
strlen counts the number of bytes until a null ('\0') character is encountered. There is no guarantee that data returned by a single recv call wil be nul-terminated so you'll need to check the number of bytes returned then add your own terminator.
char* recvData = new char[1024];
int bytes = recv(socket, recvData, 1023, 0);
if (bytes == -1) {
cout << "error on recv" << endl;
}
else {
recvData[bytes] = '\0';
cout << recvData << endl;
}
recvData is not null terminated, so result of strlen() is undefined in this case. you have to do something like the following:
int len = 1024;
char *recvData = new char[len + 1];
int lenRead = recv(socket, recvData, len, 0);
if (lenRead < len)
recvData[lenRead] = '\0';
else
recvData[len] = '\0';
cout << recvData << endl;
Isn't this obvious? :)
Just send the length of the string first or terminate the string "properly" (by sending a \0 after the end of your string; I guess that's something Java isn't doing here).
But overall, you should include the "packet length" anyway, because you might want to ensure there's enough free space before writing to the buffer (using strlen() on an uninitialized array is usually a bad idea).

C++ copying files. Short on data

I'm trying to copy a file, but whatever I try, the copy seems to be a few bytes short.
_file is an ifstream set to binary mode.
void FileProcessor::send()
{
//If no file is opened return
if(!_file.is_open()) return;
//Reset position to beginning
_file.seekg(0, ios::beg);
//Result buffer
char * buffer;
char * partBytes = new char[_bufferSize];
//Packet *p;
//Read the file and send it over the network
while(_file.read(partBytes,_bufferSize))
{
//buffer = Packet::create(Packet::FILE,std::string(partBytes));
//p = Packet::create(buffer);
//cout<< p->getLength() << "\n";
//writeToFile(p->getData().c_str(),p->getLength());
writeToFile(partBytes,_bufferSize);
//delete[] buffer;
}
//cout<< *p << "\n";
delete [] partBytes;
}
_writeFile is the file to be written to.
void FileProcessor::writeToFile(const char *buffer,unsigned int size)
{
if(_writeFile.is_open())
{
_writeFile.write(buffer,size);
_writeFile.flush();
}
}
In this case I'm trying to copy a zip file.
But opening both the original and copy in notepad I noticed that while they look identical , It's different at the end where the copy is missing a few bytes.
Any suggestions?
You are assuming that the file's size is a multiple of _bufferSize. You have to check what's left on the buffer after the while:
while(_file.read(partBytes,_bufferSize)) {
writeToFile(partBytes,_bufferSize);
}
if(_file.gcount())
writeToFile(partBytes, _file.gcount());
Your while loop will terminate when it fails to read _bufferSize bytes because it hits an EOF.
The final call to read() might have read some data (just not a full buffer) but your code ignores it.
After your loop you need to check _file.gcount() and if it is not zero, write those remaining bytes out.
Are you copying from one type of media to another? Perhaps different sector sizes are causing the apparent weirdness.
What if _bufferSize doesn't divide evenly into the size of the file...that might cause extra bytes to be written.
You don't want to always do writeToFile(partBytes,_bufferSize); since it's possible (at the end) that less than _bufferSize bytes were read. Also, as pointed out in the comments on this answer, the ifstream is no longer "true" once the EOF is reached, so the last chunk isn't copied (this is your posted problem). Instead, use gcount() to get the number of bytes read:
do
{
_file.read(partBytes, _bufferSize);
writeToFile(partBytes, (unsigned int)_file.gcount());
} while (_file);
For comparisons of zip files, you might want to consider using a non-text editor to do the comparison; HxD is a great (free) hex editor with a file compare option.

using fread to read into int buffer

I would like to know if I can use fread to read data into an integer buffer.
I see fread() takes void * as the first parameter. So can't I just pass an integer
buffer (typecast to void *) and then use this to read howmuchevery bytes I want to from the file, as long as the buffer is big enough ?
ie. cant i do:
int buffer[10];
fread((void *)buffer, sizeof(int), 10, somefile);
// print contents of buffer
for(int i = 0; i < 10; i++)
cout << buffer[i] << endl;
What is wrong here ?
Thanks
This should work if you wrote the ints to the file using something like fwrite ("binary" write). If the file is human-readable (you can open it with a text editor and see numbers that make sense) you probably want fscanf / cin.
As others have mentioned fread should be able to do what you want
provided the input is in the binary format you expect. One caveat
I would add is that the code will have platform dependencies and
will not function correctly if the input file is moved between
platforms with differently sized integers or different
endian-nesses (sp).
Also, you should always check your return values; fread could fail.
Yes you can use fread to read into an array of integers
int buffer[10];
size_t readElements = fread((void *)buffer, sizeof(int), 10, somefile);
for(int i = 0; i < readElements; i++)
cout << buffer[i] << endl
You can check the number of elements fread returns to print out.
EDIT: provided you are reading from a file in binary mode and the values were written as cnicutar mentioned with fwrite.
I was trying the same and was getting the same result as yours, large int value when trying to read integer using fread() from a file and finally got the reason for it.
So suppose if your input file contains only:
"5"
"5 5 5"
The details I got from http://www.programmersheaven.com/mb/beginnercpp/396198/396198/fread-returns-invalid-integer/
fread() reads binary data (even if the file is opened in 'text'-mode). The number 540352565 in hex is 0x20352035, the 0x20 is the ASCII code of a space and 0x35 is the ASCII code of a '5' (they are in reversed order because using a little-endian machine).
So what fread does is read the ASCII codes from the file and builds an int from it, expecting binary data. This should explain the behavior when reading the '5 5 5' file. The same happens when reading the file with a single '5', but only one byte can be read (or two if it is followed by a newline) and fread should fail if it reads less than sizeof(int) bytes, which is 4 (in this case).
As the reaction to response is that it still does not work, I will provide here complete code, so you can try it out.
Please note that following code does NOT contain proper checks, and CAN crash if file does not exist, there is no memory left, no rights, etc.
In code should be added check for each open, close, read, write operations.
Moreover, I would allocate the buffer dynamically.
int* buffer = new int[10];
That is because I do not feel good when normal array is taken as pointer. But whatever. Please also note, that using correct type (uint32_t, 16, 8, int, short...) should be done to save space, according to number range.
Following code will create file and write there correct data that you can then read.
FILE* somefile;
somefile = fopen("/root/Desktop/CAH/scripts/cryptor C++/OUT/TOCRYPT/wee", "wb");
int buffer[10];
for(int i = 0; i < 10; i++)
buffer[i] = 15;
fwrite((void *)buffer, sizeof(int), 10, somefile);
// print contents of buffer
for(int i = 0; i < 10; i++)
cout << buffer[i] << endl;
fclose(somefile);
somefile = fopen("/root/Desktop/CAH/scripts/cryptor C++/OUT/TOCRYPT/wee", "rb");
fread((void *)buffer, sizeof(int), 10, somefile);
// print contents of buffer
for(int i = 0; i < 10; i++)
cout << buffer[i] << endl;
fclose(somefile);