Qt: memcpy failed.. How to copy? - c++

My question today is about Qt and the memcpy() function..
I got a QByteArray i_byte_array containing my raw data that I need. First thing I tried is to copy those data in a char* l_array.
Which gives me:
void blablafunctionblabla(const QByteArray& i_byte_array)
{
char* l_array = (char*)malloc(i_byte_array.size());
memcpy(l_array, i_byte_array, i_byte_array.size());
// OR: char* l_array = i_byte_array.data(); // same result
}
When I run the code I expected to copy the whole contents of i_byte_array which is:
i_byte_array values
As a result I get only this...:
l_array value
It seems the copying stopped at the first /0 ignoring the size I request him to copy..
So my questions is Why that happens with memcpy function? And How do I need to proceed in order to copy all raw data? (even /0 which is a useful data for me)

Actually memcpy does not ignore the null character. I guess the IDE (maybe Qt Creator) ignores the null character so you can't see the entire content of the char string.
If you import the l_array to a QByteArray by the following way:
QByteArray ba = QByteArray::fromRawData(l_array, i_byte_array.size());
You will see the content of ba is the same as i_byte_array.
You can check SO's question for the memcpy: How could I copy data that contain '\0' character.

Related

File writing and appending in Binary mode not working

I am trying to append into file in binary mode but the logic below is not working.
For Pdf files,file is getting corrupted and for text files, it is adding some junk data in addition to my file contents.
My variable m_strReceivedMessage is of type std::string.
std::ofstream out(file, std::ios::binary | std::ios_base::app );
int i = sizeof(m_strReceivedMessage);
if (out.is_open()) {
// out.write(m_strReceivedMessage.c_str(), m_strReceivedMessage.size());
//out << m_strReceivedMessage;
out.write(reinterpret_cast<char *>(&m_strReceivedMessage), m_strReceivedMessage.size());
}
You're printing the memory of the std::string object, rather than the character buffer that it contains. To get a pointer to the character buffer, see the data() member function. Hint: The fact that you need to cast std::string* using reinterpret_cast<char*> is a dead giveaway that you're doing something very wrong.
Also, I'm not familiar with the PDF spec, but I suspect that it may possibly contain nul bytes. And depending on how you get your std::string, it's possible you may have missed any content after the first nul. std::vector<char> would be more appropriate way to store binary data.

Expected behaviour when assigning std::string to non-terminated char array?

I'm working on C++ code developed by other people, and have found a section where a std::string is assigned to a char array which is not null-terminated. The code (simplified) is something like this:
char *filePath="c:\\filename.txt"; //file known to contain 20 chars per line.
int size=20;
char *buffer;
std::string bufferstr;
buffer=new char[size];
std::ifstream input(filePath, std::ios::in | std::ios::binary);
input.read(buffer,size);
bufferstr=buffer; // Assign string to non-null-terminated char array.
// Lots of other code omitted here.
input.close();
delete[] buffer;
I'm not surprised to find memory errors when checking the code with Dr. Memory, and have now changed this so that buffer is always null-terminated, but the code has had this error for about 3 years and has behaved as intended (on Windows, Linux, and Solaris) until I recently made changes in a seemingly unrelated part of the code.
My questions are:
- What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
- Why would this code have started misbehaving after I made changes elsewhere?
If the char array is non-null-terminated the result is UB. What is likely to happen is that string constructor will go beyond the allocated buffer and encounter a null byte sooner or later.
What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
std::string will consider everything from the pointer received to the first address containing a zero value, to be part of the string. Usually, this means you either get a few garbage characters at the end of your string, or you get an application core dump, with an error like "unable to allocate " or "access violation reading ".
Why would this code have started misbehaving after I made changes elsewhere?
Because your changes elsewhere, also changed where zeros were, in the memory adjacent to the end of your non-zero terminated buffer (this is an educated guess).

Converting use of memcpy to std::copy

I have a bit of code that that uses memcpy and I am trying to convert it over to using std::copy. I am getting stuck on the syntax but this is code currently works for memcpy
length=sizeof(int)+title.size()*80;
char *otitle=new char [length];
unsigned int *ntitle=reinterpret_cast<unsigned int *>(otitle);
*ntitle=title.size();
for (i=0; i< title.size(); i++){
memcpy(otitle+sizeof(int)+i*80, getTitle(i).c_str(), 80);
//std::copy(getTitle(i).begin(), getTitle(i).end() , otitle);
}
doSomething(otitle, length);
delete otitle;
The line that is commented out isn't correct and so I would appreciate any help. Essentially, "title" is an std::vector and the function "getTitle()" returns the string in the ith element of "title. otitle is a long character array and I want to be able to copy over each element of "title" into otitle (see memcpy).
Since getTitle returns a string by value, when you call it twice, you get two different strings. You need to make sure you are calling begin and end on the same string though. So you can store the result in another string variable.
std::string str = getTitle(i);
std::copy(str.begin(), str.end(), otitle + sizeof(int) + i*80);
If your original version with memcpy handles copying over a null-terminator (can't tell from your snippet), you'll need to handle that manually. There are other details that might be wrong here, because I don't know the exact details of what your code is supposed to be doing, but this at least gives a correct usage of std::copy.

dynamic memory allocation to buffer

I am working on visual c++. I am a beginner of c++ and i am in a strange situation that i have "Contents" variable of type-
char FileContents[200000] ;
now i have taken a size of a file using sizeof operator like this
int SizeOfFile =Sizeof(File);
and now i have to copy the data of this file into "Contents" whch has array index 200000.Suppose i do so by
memcpy(FileContents,&File[0],SizeOfFile);
and i output the contents of "FileContents" into a file at any location(according to my wish) .
What i found is the file contents are displayed properly but as the contents of file are finished i have strange data like "ÌÌÌÌÌÌÌÌÌÌ". please see below-
</body>
</html> //Here finshes the file and after that i have this kind of data as you see below
ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ..and so on until file ends.
and i know its due to memory allocation of char FileContents[200000] ; because the "SizeOfFile" is very small value and after its size i have strange "ÌÌÌÌÌ" and i don't want to see them . What i want is the file which contains only the contents of "FileContents" nothing else. And i can't allocate the memory of FileContents dynalically. because it has to be equal to the "SizeOfFile" which we are getting dynamically using Sizeof(File) .
What to do in this situtaion iin order to get rid of these "ÌÌÌÌÌÌÌÌÌ" values ? Any solution?
You need to initialize the array with zeroes, since its initial contents are undetermined and could contain any value:
// initialize with 0
char FileContents[200000] = {};
You can also set the elements to zero after initialization using std::fill:
// set all elements to 0 after initialization
std::fill(FileContents, FileContents + 200000, 0); // C++03 or C++11
std::fill(std::begin(FileContents), std::end(FileContents), 0); // C++11
When it comes to interpreting char array as strings, these are treated as null terminated strings, meaning the end of the string is marked by the first 0 found.
you need to fill all data with '\0' chars.
So use this:
char FileContents[200000] = {};
doing this worked for me-
char FileContents[200000] ={0};
and do the same after it as i done before.

boost memorybuffer and char array

I'm currently unpacking one of blizzard's .mpq file for reading.
For accessing the unpacked char buffer, I'm using a boost::interprocess::stream::memorybuffer.
Because .mpq files have a chunked structure always beginning with a version header (usually 12 bytes, see http://wiki.devklog.net/index.php?title=The_MoPaQ_Archive_Format#2.2_Archive_Header), the char* array representation seems to truncate at the first \0, even if the filesize (something about 1.6mb) remains constant and (probably) always allocated.
The result is a streambuffer with an effective length of 4 ('REVM' and byte nr.5 is \0). When attempting to read further, an exception is thrown. Here an example:
// (somewhere in the code)
{
MPQFile curAdt(FilePath);
size_t size = curAdt.getSize(); // roughly 1.6 mb
bufferstream memorybuf((char*)curAdt.getBuffer(), curAdt.getSize());
// bufferstream.m_buf.m_buffer is now 'REVM\0' (Debugger says so),
// but internal length field still at 1.6 mb
}
//////////////////////////////////////////////////////////////////////////////
// wrapper around a file oof the mpq_archive of libmpq
MPQFile::MPQFile(const char* filename) // I apologize my naming inconsistent convention :P
{
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
{
// gOpenArchives points to MPQArchive, wrapper around the mpq_archive, has mpq_archive * mpq_a as member
mpq_archive &mpq_a = (*i)->mpq_a;
// if file exists in that archive, tested via hash table in file, not important here, scroll down if you want
mpq_hash hash = (*i)->GetHashEntry(filename);
uint32 blockindex = hash.blockindex;
if ((blockindex == 0xFFFFFFFF) || (blockindex == 0)) {
continue; //file not found
}
uint32 fileno = blockindex;
// Found!
size = libmpq_file_info(&mpq_a, LIBMPQ_FILE_UNCOMPRESSED_SIZE, fileno);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
eof = true;
buffer = 0;
return;
}
buffer = new char[size]; // note: size is 1.6 mb at this time
// Now here comes the tricky part... if I step over the libmpq_file_getdata
// function, I'll get my truncated char array, which I absolutely don't want^^
libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);
return;
}
}
Maybe someone could help me. I'm really new to STL and boost programming and also inexperienced in C++ programming anyways :P Hope to get a convenient answer (plz not suggest to rewrite libmpq and the underlying zlib architecture^^).
The MPQFile class and the underlying uncompress methods are acutally taken from a working project, so the mistake is either somewhere in the use of the buffer with the streambuffer class or something internal with char array arithmetic I haven't a clue of.
By the way, what is the difference between using signed/unsigned chars as data buffers? Has it anything to do with my problem (you might see, that in the code randomly char* unsigned char* is taken as function arguments)
If you need more infos, feel free to ask :)
How are you determining that your char* array is being 'truncated' as you call it? If you're printing it or viewing it in a debugger it will look truncated because it will be treated like a string, which is terminated by \0. The data in 'buffer' however (assuming libmpq_file_getdata() does what it's supposed to do) will contain the whole file or data chunk or whatever.
Sorry, messed up a bit with these terms (not memorybuffer actually, streambuffer is meant as in the code)
Yeah you where right... I had a mistake in my exception handling. Right after that first bit of code comes this:
// check if the file has been open
//if (!mpf.is_open())
pair<char*, size_t> temp = memorybuf.buffer();
if(temp.first)
throw AdtException(ADT_PARSEERR_EFILE);//Can't open the File
notice the missing ! before temp.first . I was surprized by the exception thrown, looked at the streambuffer .. internal buffer at was confused of its length (C# background :P).
Sorry for that, it's working as expected now.