【问题标题】:Open file from memory buffer using minizip使用 minizip 从内存缓冲区打开文件
【发布时间】:2013-04-29 08:20:34
【问题描述】:

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

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

我不明白如何使用它。谁能给我一个例子?

【问题讨论】:

    标签: c++ c zlib


    【解决方案1】:

    我解决了我的解压问题: 我将此功能添加到 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;
            }
    

    【讨论】:

    • 你能举个使用例子吗?我正在为此苦苦挣扎,但找不到有关如何使用该库从内存缓冲区解压缩的帮助
    • 我加我的 2 美分:首先,调用者需要下载 ioapi_mem_c.zip。其次,sprintf+scanf 在不同的 API 中传递指针的技巧将中断 64 位。代码:char path[16] = {0}; ... sprintf(path, "%x+%x", base, size); ...如果 (sscanf(filename,"%x+%x",&mem->base,&mem->size)!=2) 对于 32 位, %x 恰好可以工作,但对于 64 位,并不幸运。对于 C99 编译器, %p 用于此目的: char path[32] = {0}; sprintf(路径,“%p+%lu”,缓冲区,大小); if (sscanf(filename,"%p+%lu", &mem->base, &mem->size)!=2)
    【解决方案2】:

    将此功能添加到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);
    }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 在 ioapi_mem.c 他们已经做到了。所以我可以将 unzOpen2 函数与记忆函数一起使用。我发现注释: /* 文件名以以下形式指定: * + * 这在内存地址长于 * 整数大小的情况下可能不起作用,因此可能需要为 64 位 * 架构寻址 / 所以现在我了解了它们如何将其存储在 const char 文件名中。
      【解决方案4】:

      查看minizip 的 nmoinvaz fork:要从内存中的 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-29
        • 1970-01-01
        • 1970-01-01
        • 2013-01-10
        • 2013-05-20
        • 2020-03-11
        • 2022-09-24
        • 1970-01-01
        相关资源
        最近更新 更多