使用minizip从内存缓冲区打开文件

时间:2013-04-29 08:20:35

标签: c++ c zlib

我正在搜索如何使用minizip从内存缓冲区打开存档。

我在他们的网页http://www.winimage.com/zLibDll/minizip.html找到了ioapi_mem_c.zip。

我无法理解如何使用它。有人可以举个例子吗?

4 个答案:

答案 0 :(得分:6)

我解决了解压缩的问题: 我将此函数添加到unzip.c

extern unzFile ZEXPORT unzOpenBuffer (const  void* buffer, uLong size)
{
    char path[16] = {0};
    zlib_filefunc64_32_def memory_file;
    uLong base = (uLong)buffer;

    sprintf(path, "%x+%x", base, size);

    fill_memory_filefunc64_32(&memory_file);
    return unzOpenInternal(path, &memory_file, 0);
}

并在ioapi_mem.c中进行了一些更改:

void fill_memory_filefunc64_32 (pzlib_filefunc_def)
    zlib_filefunc64_32_def* pzlib_filefunc_def;
{
    pzlib_filefunc_def->zopen32_file = fopen_mem_func;
    pzlib_filefunc_def->zfile_func64.zopen64_file = fopen_mem_func;
    pzlib_filefunc_def->zfile_func64.zread_file = fread_mem_func;
    pzlib_filefunc_def->zfile_func64.zwrite_file = fwrite_mem_func;
    pzlib_filefunc_def->ztell32_file = ftell_mem_func;
    pzlib_filefunc_def->zseek32_file = fseek_mem_func;
    pzlib_filefunc_def->zfile_func64.zseek64_file = NULL;
    pzlib_filefunc_def->zfile_func64.zclose_file = fclose_mem_func;
    pzlib_filefunc_def->zfile_func64.zerror_file = ferror_mem_func;
    pzlib_filefunc_def->zfile_func64.opaque = NULL;
}

我希望这会帮助那些遇到同样问题的人。

以下是简单的类实现如何使用它:

 void ZipArchiveImpl::OpenArchive()
        {
            ASSERT(!mInited, "Already opened.");


            if ((mFileMode == FM_READ))
            {
                if (mArchiveName.size() == 0)
                {


                    u32 sz = mFile->GetFileSize();
                    mUnzBlock.Resize(sz);
                    mFile->SetPosition(0);
                    mFile->Read(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());

                    mUnzHandle = unzOpenBuffer(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());

                }
                else
                {
                    mUnzHandle = unzOpen(mArchiveName.c_str());
                }

                if (!mUnzHandle) return;
                FillMap();
            }

            else if (mFileMode == FM_WRITE)
            {
                ASSERT0(mArchiveName.size());
                mZipHandle = zipOpen(mArchiveName.c_str(), 0);

                if (!mZipHandle) return;
            }



            mInited = true;
        }

        IFile* ZipArchiveImpl::OpenRead(const std::string& name)
        {
            if (IsExist(name))
            {

                ZipFileInfo info = mFileMap.find(name)->second;

                MemoryBlock block(1);
                block.Resize(info.uncompressedSize);

                int res = unzGoToFilePos(mUnzHandle, &info.filePosInfo);
                if (UNZ_OK != res)
                {
                    return false;
                }

                // open the current file with optional password
                if (mArchivePassword != "")
                {
                    res = unzOpenCurrentFilePassword(info.zipFileHandle, mArchivePassword.c_str());
                }
                else
                {
                    res = unzOpenCurrentFile(info.zipFileHandle);
                }
                if (UNZ_OK != res)
                {
                    return false;
                }

                // read uncompressed data
                int readResult = unzReadCurrentFile(info.zipFileHandle, block.Data(), info.uncompressedSize);

                // close the file
                res = unzCloseCurrentFile(info.zipFileHandle);
                if (UNZ_OK != res)
                {
                    return false;
                }

                if (info.uncompressedSize == readResult)
                {
                    return ROBE_NEW MemoryFile(block.Data(), info.uncompressedSize);
                }
                else
                {
                    return NULL;
                }
            }
            else
            {
                return NULL;
            }
        }

        IFile* ZipArchiveImpl::OpenRead(u32 id)
        {
            ASSERT0(mFileNames.size() > id);
            if (IsExist(mFileNames[id]))
            {
                return OpenRead(mFileNames[id]);
            }
            else
            {
                return NULL;
            }
        }

        void ZipArchiveImpl::FillMap()
        {
            s32 walkRes = unzGoToFirstFile(mUnzHandle);
            unz_file_info info;
            while (UNZ_OK == walkRes)
            {

                // get info about current file
                char currentFileName[512];
                s32 fileInfoRes = unzGetCurrentFileInfo(mUnzHandle, &info, currentFileName, sizeof(currentFileName), 0, 0, 0, 0);

                std::string name = std::string(currentFileName);
                mFileNames.push_back(name);
                InitInfo(name, &info);
                walkRes = unzGoToNextFile(mUnzHandle);

            }
            OpenRead(0);

            if (UNZ_END_OF_LIST_OF_FILE != walkRes)
            {

            }
        }

        void ZipArchiveImpl::InitInfo(const std::string& name, unz_file_info* info)
        {
            ZipFileInfo zfi;
            mFileMap.insert(std::pair<std::string, ZipFileInfo>(name, zfi));
            mFileMap[name].zipFileHandle = mUnzHandle;
            int res = unzGetFilePos(mFileMap[name].zipFileHandle, &mFileMap[name].filePosInfo);

            mFileMap[name].uncompressedSize = info->uncompressed_size;

            char lastsymbol = name[name.size() - 1];
            if (lastsymbol == '/' || lastsymbol == '\\')
            {
                mFileMap[name].type = ZFT_DIR;
            }
            else
            {
                mFileMap[name].type = ZFT_FILE;
            }
        }


        ZipArchiveImpl::~ZipArchiveImpl()
        {
            if (mInited)
            {
                if (mUnzHandle) unzClose(mUnzHandle);
                if (mZipHandle) zipClose(mZipHandle, 0);
            }
        }

        bool ZipArchiveImpl::IsExist(const std::string& name)
        {
            return (mFileMap.find(name) != mFileMap.end());
        }

        void ZipArchiveImpl::SaveFileToZip(const std::string& path, IFile* file)
        {
            const u32 DefaultFileAttribute = 32;


            MemoryBlock block(1);
            block.Resize(file->GetFileSize());
            file->Read(block.Data(), block.GetSizeInBytes());

            zip_fileinfo zinfo;

            memset(&zinfo, 0, sizeof(zinfo));

            zinfo.internal_fa = 0;
            zinfo.external_fa = DefaultFileAttribute;

            ::boost::posix_time::ptime pt = ::boost::posix_time::from_time_t(time(0));
            std::tm ptm             = ::boost::posix_time::to_tm(pt);

            zinfo.dosDate           = 0;
            zinfo.tmz_date.tm_year  = ptm.tm_year;
            zinfo.tmz_date.tm_mon   = ptm.tm_mon;
            zinfo.tmz_date.tm_mday  = ptm.tm_mday;
            zinfo.tmz_date.tm_hour  = ptm.tm_hour;
            zinfo.tmz_date.tm_min   = ptm.tm_min;
            zinfo.tmz_date.tm_sec   = ptm.tm_sec;

            zipOpenNewFileInZip(mZipHandle, path.c_str(), &zinfo, 0, 0, 0, 0, 0, Z_DEFLATED, Z_BEST_SPEED);
            zipWriteInFileInZip(mZipHandle, block.Data(), block.GetSizeInBytes());
            zipCloseFileInZip(mZipHandle);
        }

        unsigned long ZipArchiveImpl::GetFileAttributes(const std::string& filePath)
        {
            unsigned long attrib = 0;
            #ifdef WIN32
            attrib = ::GetFileAttributes(filePath.c_str());
            #else
            struct stat path_stat;
            if (::stat(filePath.c_str(), &path_stat) == 0)
            {
                attrib = path_stat.st_mode;
            }
            #endif
            return attrib;
        }

答案 1 :(得分:1)

将此函数添加到unzip.c

extern unzFile ZEXPORT unzOpenBuffer(const  void* buffer, uLong size)
{
    zlib_filefunc_def filefunc32 = { 0 };
    ourmemory_t *punzmem = (ourmemory_t*)malloc(sizeof(ourmemory_t));
    punzmem->size = size;
    punzmem->base = (char *)malloc(punzmem->size);
    memcpy(punzmem->base, buffer, punzmem->size);
    punzmem->grow = 0;
    punzmem->cur_offset = 0;
    punzmem->limit = 0;
    fill_memory_filefunc(&filefunc32, punzmem);
    return unzOpen2(NULL, &filefunc32);
}

答案 2 :(得分:0)

查看链接中的代码,没有明显的方法来传递内存缓冲区。将内存缓冲区保存为文件,解压缩。

或者您可以实现自己的zlib_filefunc_def变体,该变体在一块内存而不是文件上运行。我认为这很难做到。

答案 3 :(得分:-2)

签出minizip的nmoinvaz分支:要从内存中的zip文件解压缩,请使用fill_memory_filefunc并提供正确的ourmemory_t结构

zlib_filefunc_def filefunc32 = {0};
ourmemory_t unzmem = {0};

unzmem.size = bufsize;
unzmem.base = (char *)malloc(unzmem.size);
memcpy(unzmem.base, buffer, unzmem.size);

fill_memory_filefunc(&filefunc32, &unzmem);

unzOpen2("__notused__", &filefunc32);