增强内存缓冲区和字符数组

发布于 2024-08-17 05:57:48 字数 2598 浏览 1 评论 0原文

我目前正在解压暴雪的 .mpq 文件之一以供阅读。 为了访问解压的字符缓冲区,我使用了 boost::interprocess::stream::memorybuffer。 因为 .mpq 文件具有始终以版本标头开头的分块结构(通常为 12 个字节,请参阅 http://wiki.devklog.net/index.php?title=The_MoPaQ_Archive_Format#2.2_Archive_Header),char* 数组表示似乎在第一个 \0 处截断,即使文件大小(大约1.6mb)保持不变并且(可能)始终分配。 结果是有效长度为 4 的流缓冲区(“REVM”和字节 nr.5 为 \0)。当尝试进一步阅读时,会引发异常。这是一个例子:

    // (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;
    }
}

也许有人可以帮助我。我对 STL 和 boost 编程非常陌生,而且对 C++ 编程也没有经验:P 希望得到一个方便的答案(请不要建议重写 libmpq 和底层 zlib 架构^^)。 MPQFile 类和底层解压缩方法实际上是从工作项目中获取的,因此错误要么是在使用 Streambuffer 类的缓冲区中的某个地方,要么是在使用 char 数组算术的内部,我对此一无所知。 顺便问一下,使用有符号/无符号字符作为数据缓冲区有什么区别?它与我的问题有什么关系吗(您可能会看到,在代码中随机 char* unsigned char* 被视为函数参数) 如果您需要更多信息,请随时询问:)

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 :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

琉璃梦幻 2024-08-24 05:57:48

您如何确定您的 char* 数组正在被您所说的“截断”?如果您打印它或在调试器中查看它,它看起来会被截断,因为它会被视为字符串,并以 \0 结尾。然而,“buffer”中的数据(假设 libmpq_file_getdata() 执行其应该执行的操作)将包含整个文件或数据块或其他内容。

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.

绝不服输 2024-08-24 05:57:48

抱歉,这些术语有点混乱(实际上不是内存缓冲区,流缓冲区的意思与代码中相同)

是的,你说得对......我在异常处理中犯了一个错误。在第一段代码之后就是:

// 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

注意丢失的!在 temp.first 之前。我对抛出的异常感到惊讶,查看了流缓冲区..内部缓冲区对其长度感到困惑(C#背景:P)。
抱歉,它现在按预期工作。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文