解压内存文件

本文介绍了一个从内存中的zip文件解压缩的C++实现,通过定义zlib_filefunc_def结构体并自定义相关函数,配合unzOpen2使用,实现对内存中的zip文件进行解压,并将文件写入到指定目录。

当一段buffer为zip压缩内容时,如何解压缩呢,这里直接贴上代码

bool UnZipMemFile(MemFile* memfile, const std::wstring& dest_folder, zip_progress_callback cb_func, void* pVoid)
{
    zlib_filefunc_def zip_funcs;
    std::string strPathAnsi;
    int nRetCode;

    __int64 total_size = 0;
    DWORD dwResBuffer = 0;

    zip_funcs.zopen_file = ZipOpenFunc;
    zip_funcs.zread_file = ZipReadFunc;
    zip_funcs.zwrite_file = ZipWriteFunc;
    zip_funcs.ztell_file = ZipTellFunc;
    zip_funcs.zseek_file = ZipSeekFunc;
    zip_funcs.zclose_file = ZipCloseFunc;
    zip_funcs.zerror_file = ZipErrorFunc;
    zip_funcs.opaque=NULL;
    void* hZip = unzOpen2((const char*)memfile, &zip_funcs);
    if (NULL == hZip)
        return false;

    bool retval = false;
    std::wstring dest_root = dest_folder;
    FormatWinPath(dest_root);

    wchar_t ch = dest_folder[dest_folder.size() - 1];
    if (ch != L'\\')
        dest_root += L'\\';

    __int64 curpos = 0;
    std::string read_buffer;
    std::wstring last_path = dest_root;
    CreateDirectoryRecur(last_path);

    nRetCode = unzGoToFirstFile(hZip);
    while (UNZ_OK == nRetCode)
    {
        char szCurrentFile[260];
        unz_file_info fileInfo;
        uLong dwSeekPos;
        uLong dwSize;

        nRetCode = unzGetCurrentFileInfo(
            hZip,
            &fileInfo,
            szCurrentFile,
            sizeof(szCurrentFile),
            NULL,
            0,
            NULL,
            0
            );
        if (nRetCode != UNZ_OK)
            goto clean0;

        dwSeekPos = unzGetOffset(hZip);
        dwSize = fileInfo.uncompressed_size;

        if (dwSize > 0)
        {
            std::wstring tmp_path;
            std::wstring filename = dest_root + AnsiToUnicode(szCurrentFile, -1);
            FormatWinPath(filename);

            for (int i = filename.size() - 1; i > 0; i--)
            {
                if (filename[i] == L'\\')
                {
                    tmp_path = filename.substr(0, i);
                    break;
                }
            }

            if (tmp_path != last_path)
            {
                last_path = tmp_path;
                CreateDirectoryRecur(tmp_path);
            }

            nRetCode = unzOpenCurrentFile(hZip);
            if (nRetCode == UNZ_OK)
            {
                read_buffer.resize(dwSize + 4);
                nRetCode = unzReadCurrentFile(hZip, (void*)read_buffer.data(), dwSize);
                FILE* fp = _wfopen(filename.c_str(), L"wb");
                if (fp)
                {
                    fwrite(read_buffer.data(), 1, dwSize, fp);
                    fclose(fp);
                }               
                unzCloseCurrentFile(hZip);

                curpos += dwSize;
                if (cb_func)
                    cb_func(curpos, memfile->GetFileSize(), pVoid);
            }
        }

        nRetCode = unzGoToNextFile(hZip);
    }

    if (cb_func)
        cb_func(memfile->GetFileSize(), memfile->GetFileSize(), pVoid);

clean0:
    return retval;
}

 

 

其中的几个回调函数为:

    void* ZipOpenFunc(void* opaque, const char* filename, int mode)
    {
        return (void*)filename;
    }

    uLong ZipReadFunc(void* opaque, void* stream, void* buf, uLong size)
    {
        uLong ret = 0;
        MemFile* pMemFile = (MemFile*)stream;

        if (!pMemFile)
            goto clean0;

        pMemFile->ReadFile(buf, size, &ret);

clean0:
        return ret;
    }

    uLong ZipWriteFunc(void* opaque, void* stream, const void* buf, uLong size)
    {
        uLong ret = 0;
        MemFile* pMemFile = (MemFile*)stream;

        if (!pMemFile)
            goto clean0;

        pMemFile->WriteFile(buf, size, &ret);

clean0:
        return ret;
    }

    long ZipSeekFunc (void* opaque, void* stream, uLong offset, int origin)
    {
        uLong ret = -1;
        MemFile* pMemFile = (MemFile*)stream;
        DWORD dwRetCode;

        if (!pMemFile)
            goto clean0;

        dwRetCode = pMemFile->SetFilePointer(offset, NULL, origin);
        if (INVALID_SET_FILE_POINTER == dwRetCode)
            goto clean0;

        ret = 0;

clean0:
        return ret;
    }

    long ZipTellFunc(void* opaque, void* stream)
    {
        long ret=-1;
        MemFile* pMemFile = (MemFile*)stream;
        DWORD dwRetCode;

        if (!pMemFile)
            goto clean0;

        dwRetCode = pMemFile->SetFilePointer(0, NULL, FILE_CURRENT);
        if (INVALID_SET_FILE_POINTER == dwRetCode)
            goto clean0;

        ret = dwRetCode;

clean0:
        return ret;
    }

    int ZipCloseFunc(void* opaque, void* stream)
    {
        int ret=-1;
        MemFile* pMemFile = (MemFile*)stream;

        if (!pMemFile)
            goto clean0;

        if (!pMemFile->CloseHandle())
            goto clean0;

        ret = 0;

clean0:
        return ret;
    }

    int ZipErrorFunc(void* opaque, void* stream)
    {
        return 0;
    }

    void FormatFilePath(std::wstring & filepath)
    {
        int len = filepath.length();
        for(int i=0; i<len; i++)
        {
            if (filepath[i] == L'/')
                filepath[i] = L'\\';
        }
    }

 

其中用到了一个MemFile类,这个类的源代码网上很多,也很简单,也贴出代码吧:

    class AURORA_EXPORT MemFile
    {
    public:
        MemFile();
        MemFile(PVOID lpBuffer, DWORD dwLength);
        virtual ~MemFile();

        void SetData(PVOID lpBuffer, DWORD dwLength);
        BOOL ReadFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead);

        BOOL WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten);

        DWORD SetFilePointer(
            ULONG lDistanceToMove,
            PLONG lpDistanceToMoveHigh,
            DWORD dwMoveMethod
            );

        BOOL CloseHandle();
        __int64 GetFileSize();

    private:
        CAtlArray<BYTE> m_buffer;
        DWORD m_dwCurrentPos;
    };

    MemFile::MemFile()
    {
    }

    MemFile::MemFile(PVOID lpBuffer, DWORD dwLength)
        : m_dwCurrentPos(0)
    {
        m_buffer.SetCount(dwLength);
        memcpy(m_buffer.GetData(), lpBuffer, dwLength);
    }

    MemFile::~MemFile()
    {
    }

    void MemFile::SetData(PVOID lpBuffer, DWORD dwLength)
    {
        m_buffer.SetCount(dwLength);
        memcpy(m_buffer.GetData(), lpBuffer, dwLength);
    }

    __int64 MemFile::GetFileSize()
    {
        return m_buffer.GetCount();
    }

    BOOL MemFile::ReadFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead)
    {
        BOOL retval = FALSE;
        DWORD dwReaded;

        if (!lpBuffer || !nNumberOfBytesToRead)
            goto clean0;

        if (m_dwCurrentPos + nNumberOfBytesToRead <= m_buffer.GetCount())
        {
            dwReaded = nNumberOfBytesToRead;
        }
        else
        {
            dwReaded = (DWORD)m_buffer.GetCount() - m_dwCurrentPos;
        }

        if (0 == dwReaded)
            goto clean0;

        memcpy(lpBuffer, m_buffer.GetData() + m_dwCurrentPos, dwReaded);
        m_dwCurrentPos += dwReaded;

        if (lpNumberOfBytesRead)
            *lpNumberOfBytesRead = dwReaded;

        retval = TRUE;

clean0:
        return retval;
    }

    BOOL MemFile::WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten)
    {
        BOOL retval = FALSE;
        DWORD dwWritten = nNumberOfBytesToWrite;

        if (!lpBuffer || !nNumberOfBytesToWrite)
            goto clean0;

        if (m_dwCurrentPos + nNumberOfBytesToWrite > m_buffer.GetCount())
        {
            m_buffer.SetCount(m_dwCurrentPos + nNumberOfBytesToWrite);
        }

        memcpy(m_buffer.GetData() + m_dwCurrentPos, lpBuffer, dwWritten);
        m_dwCurrentPos += dwWritten;

        if (lpNumberOfBytesWritten)
            *lpNumberOfBytesWritten = dwWritten;

        retval = TRUE;

clean0:
        return retval;
    }

    DWORD MemFile::SetFilePointer(
        ULONG lDistanceToMove,
        PLONG lpDistanceToMoveHigh,
        DWORD dwMoveMethod
        )
    {
        DWORD retval = INVALID_SET_FILE_POINTER;

        if (FILE_CURRENT == dwMoveMethod)
        {
            if (lDistanceToMove > 0)
            {
                if (m_dwCurrentPos + lDistanceToMove < m_buffer.GetCount())
                {
                    m_dwCurrentPos += lDistanceToMove;
                }
                else
                {
                    goto clean0;
                }
            }
            else
            {
                if (m_dwCurrentPos >= lDistanceToMove)
                {
                    m_dwCurrentPos += lDistanceToMove;
                }
                else
                {
                    goto clean0;
                }
            }
        }
        else if (FILE_END == dwMoveMethod)
        {
            if (lDistanceToMove > 0)
                goto clean0;

            if (m_buffer.GetCount() + lDistanceToMove < 0)
                goto clean0;

            m_dwCurrentPos = (DWORD)m_buffer.GetCount() + lDistanceToMove;
        }
        else if (FILE_BEGIN == dwMoveMethod)
        {
            if (lDistanceToMove < 0)
                goto clean0;

            if (lDistanceToMove >= m_buffer.GetCount())
                goto clean0;

            m_dwCurrentPos = lDistanceToMove;
        }

clean0:
        return m_dwCurrentPos;
    }

    BOOL MemFile::CloseHandle()
    {
        return TRUE;
    }

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值