views:

117

answers:

2

Hello, 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 unexperienced 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 funtion arguments) If you need more infos, feel free to ask :)

+1  A: 

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.

Roel
Also, you mention 'streambuffer' but I don't see one in the code.
Roel
A: 

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.

banana
I'll just assume you mean 'bufferstream', which is again different from both 'memorybuffer' and 'streambuffer' :)As a hint for future C++ adventures, remove all 'using' statements from your code and make the namespaces explicit. This means more typing but it does make it easier for future readers of the code (such as potential Stack Overflow questions answerers) to see where classes are from.
Roel
yeah thank you I'm a scatterbrain -.-one more time reading had not hurt that much...
banana