cabsupport.cpp

来自「java调用ie浏览器demo源码,可以用在windows或者linux」· C++ 代码 · 共 1,466 行 · 第 1/3 页

CPP
1,466
字号
//////////////////////////////////

// Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved. Use is

// subject to license terms.

//

// This program is free software; you can redistribute it and/or modify

// it under the terms of the Lesser GNU General Public License as

// published by the Free Software Foundation; either version 2 of the

// License, or (at your option) any later version.

//

// This program is distributed in the hope that it will be useful, but

// WITHOUT ANY WARRANTY; without even the implied warranty of

// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

// General Public License for more details.

//

// You should have received a copy of the GNU General Public License

// along with this program; if not, write to the Free Software

// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307

// USA.

#include "stdafx.h"

#include "PackerExt.h"

#include "CabSupport.h"





/////////////////////////////////////

//   UNPACKER

/////////////////////////////////////



#define MIN_CACHE_SIZE 1024

static LARGE_INTEGER _ZERO64 = {0};



HRESULT CreateStream(

    LPSTREAM *ppstm,

    long hint)

{

    OLE_DECL;

    switch(hint & 0x1){

    case HINT_IN_MEMORY:

        //??? SHCreateMemStream

        OLE_HR = CreateStreamOnHGlobal(

            NULL,

            TRUE,

            ppstm

        );

        break;

    case HINT_ON_DISK:

        {

            CTempFileStream *ps = new CTempFileStream();

            if(NULL==ps){

                OLE_HR = E_OUTOFMEMORY;

            } else {

                OLE_HR = ps->Create( _T(""), _T("cab") );

                if(FAILED(OLE_HR)){

                    ps->Release();

                } else {

                   *ppstm = ps;

                }

            }

        }

        break;

    }

    OLE_RETURN_HR

}



char *return_fdi_error_string(FDIERROR err)

{

    switch(err){

    case FDIERROR_NONE:

        return "No error";

    case FDIERROR_CABINET_NOT_FOUND:

        return "Cabinet not found";

    case FDIERROR_NOT_A_CABINET:

        return "Not a cabinet";

    case FDIERROR_UNKNOWN_CABINET_VERSION:

        return "Unknown cabinet version";

    case FDIERROR_CORRUPT_CABINET:

        return "Corrupt cabinet";

    case FDIERROR_ALLOC_FAIL:

        return "Memory allocation failed";

    case FDIERROR_BAD_COMPR_TYPE:

        return "Unknown compression type";

    case FDIERROR_MDI_FAIL:

        return "Failure decompressing data";

    case FDIERROR_TARGET_FILE:

        return "Failure writing to target file";

    case FDIERROR_RESERVE_MISMATCH:

        return "Cabinets in set have different RESERVE sizes";

    case FDIERROR_WRONG_CABINET:

        return "Cabinet returned on fdintNEXT_CABINET is incorrect";

    case FDIERROR_USER_ABORT:

        return "User aborted";

    default:

        return "Unknown error";

    }

}



int HR2CABERR(

    JNIEnv *env, 

    HRESULT hr, 

    const char *msg, 

    int ret)

{

    switch(hr){

    case E_OUTOFMEMORY:

        JNU_ThrowOutOfMemoryError(env, msg);

        errno = ENOMEM;

        return -1;

    case E_JAVAEXCEPTION:

        errno = EINVAL;

        return -1;

    default:

        ThrowJNIErrorOnOleError(env, hr, msg);

    }

    return FAILED(hr) ? -1 : ret;

}



void CCabUnpacker::checkInCache(DWORD size)

{

    OLE_DECL

    if( !bool(m_inCache) ){

        //INFO: we can open a stream to temp file here as an alternative

        OLE_HRT(CreateStream(

            &m_inCache,

             m_hint

        ));

    }

    STATSTG st;

    OLE_HRT(m_inCache->Stat(&st, STATFLAG_NONAME));

    if( st.cbSize.LowPart < size ){

        OLE_HRT(m_inCache->Seek(_ZERO64, SEEK_END, NULL));



        //java read

        //No more exceptions here!

        jsize cb = jsize(size) - st.cbSize.LowPart;

        jbyteArray jba = m_env_nt->NewByteArray( jsize(cb) );

        if( NULL == jba ){

            OLE_HR = E_OUTOFMEMORY;

        } else {

            jint ret = 0, read;

            while(0 < cb){

                read = CUnpackerExt::readNativeBytes(

                    m_env_nt,

                    jba,

                    ret,

                    cb

                );

                if( m_env_nt->ExceptionCheck() ){

                    OLE_HR = E_JAVAEXCEPTION;

                    break;

                }

                if( -1 == read ){

                    break;

                }

                cb -= read;

                ret += read;

            }



            //copy to stream

            if(SUCCEEDED(OLE_HR)){

                jbyte *pSrc = m_env_nt->GetByteArrayElements(jba, NULL);

                if(NULL==pSrc){

                    OLE_HR = E_OUTOFMEMORY;

                } else {

                    OLE_HR = m_inCache->Write(pSrc, ret, NULL);

                    m_env_nt->ReleaseByteArrayElements(jba, pSrc, JNI_ABORT);

                }

            }

            m_env_nt->DeleteLocalRef(jba);

        }  



        //here we can safely throw an exception if problem happens

        OLE_HRT(OLE_HR);

    }

}



UINT CCabUnpacker::read(

    CCabUnpacker::JStreamPointer *p, 

    void *pv, 

    UINT cb)

{

    ULONG read = (UINT)-1;

    OLE_TRY

    checkInCache(p->m_cbPos + cb);

    LARGE_INTEGER newpos = {p->m_cbPos, 0};

    OLE_HRT(m_inCache->Seek(newpos, SEEK_SET, NULL));

    OLE_HRT(m_inCache->Read(pv, cb, &read));

    p->m_cbPos += cb;

    OLE_CATCH

    return HR2CABERR(m_env_nt, OLE_HR, "stream read error", read);

}



long CCabUnpacker::seek(

    CCabUnpacker::JStreamPointer *p, 

    long dist, 

    int seektype)

{

    OLE_DECL;

    switch(seektype){

    case SEEK_END:

        OLE_HR = E_INVALIDARG;

        break;

    case SEEK_SET:

        p->m_cbPos = dist; 

        break;

    case SEEK_CUR:

        p->m_cbPos += dist; 

        break;

    }

    return HR2CABERR(m_env_nt, OLE_HR, "stream seek error", p->m_cbPos);    

}





HRESULT CCabUnpacker::writeOutCache(

    void *pv, 

    DWORD dwSize, 

    DWORD *pdwCopied)

{

    OLE_TRY

    HANDLE hhSignals[] = { m_hevClose, m_hevOutWriteReady, m_hCabThread };

    if(pdwCopied){

        *pdwCopied = 0;

    }

    while(1){

        {

            //out cache locked operation

            OLESyncro _lk(m_hmtLock);           

            DWORD dwFreeSpace;

            OLE_HRT(m_outCache.Space(&dwFreeSpace));

            if( 0 < dwFreeSpace ){

                DWORD dwWritten;

                OLE_HRT(m_outCache.DataAdd(pv, min(dwFreeSpace, dwSize), &dwWritten));



                dwSize -= dwWritten;

                pv = (LPBYTE)pv + dwWritten;

                if(pdwCopied){

                    *pdwCopied += dwWritten;

                }

                ::SetEvent(m_hevOutReadReady);

            }

        }

        //wait only if it needs 

        if( 0 == dwSize )

            break;



        switch( ::WaitForMultipleObjects(

            sizeof(hhSignals)/sizeof(*hhSignals),

            hhSignals,

            FALSE,

            INFINITE))

        {

        case WAIT_OBJECT_0:

            //closed, user cancel from 3-d thread            

            OLE_HR = S_FALSE;

            goto M_EXIT;

        case WAIT_OBJECT_0+1:

            //read happened 

            break;

        case WAIT_OBJECT_0+2:

            //seems error happens. details are m_ex 

            OLE_HR = S_FALSE;

            goto M_EXIT;

        default:

            //system error

            OLE_HRT(E_POINTER);

            goto M_EXIT;

        }

    }

M_EXIT: ;

    OLE_CATCH

    OLE_RETURN_HR

}



HRESULT CCabUnpacker::readOutCache(

    void *pv, 

    DWORD dwSize, 

    DWORD *pdwCopied)

{

    OLE_TRY

    HANDLE hhSignals[] = { m_hevClose, m_hevOutReadReady, m_hevEndOfEntry };

    if(pdwCopied){

        *pdwCopied = 0;

    }

    while(1){

        {

            //out cache locked operation

            OLESyncro _lk(m_hmtLock);           

            DWORD dwUsed;

            OLE_HRT(m_outCache.Used(&dwUsed));

            if( 0 < dwUsed ){

                DWORD dwRead;

                OLE_HRT(m_outCache.DataGet(pv, min(dwUsed, dwSize), &dwRead));



                dwSize -= dwRead;

                pv = (LPBYTE)pv + dwRead;

                if(pdwCopied){

                    *pdwCopied += dwRead;

                }

                ::SetEvent(m_hevOutWriteReady);

            }

        }

        //wait only if it needs 

        if(0 == dwSize)

            break;



        switch( ::WaitForMultipleObjects(

            sizeof(hhSignals)/sizeof(*hhSignals),

            hhSignals,

            FALSE,

            INFINITE))

        {

        case WAIT_OBJECT_0:

            //closed, user cancel from 3-d thread            

            OLE_HR = S_FALSE;

            goto M_EXIT;

        case WAIT_OBJECT_0+1:

            //write happened

            break;

        case WAIT_OBJECT_0+2:

            //no more read - end of file reached 

            goto M_EXIT;

        default:

            //system error

            OLE_HRT(E_POINTER);

            goto M_EXIT;

        }

    }

M_EXIT: ;

    OLE_CATCH

    OLE_RETURN_HR

}



UINT CCabUnpacker::write(

    CCabUnpacker::JStreamPointer *p, 

    void *pv, 

    UINT cb)

{

    OLE_DECL;

    DWORD uiTotal;

    OLE_HR = writeOutCache(pv, cb, &uiTotal);

    //all was written or error happened

    return HR2CABERR(m_env_nt, OLE_HR, "stream write error", uiTotal);

}



jint CCabUnpacker::readNativeBytes(
    JNIEnv *env, 
    jbyteArray buf, 
    jint off, 
    jint len)

{

    if( !checkValid(env) )

        return -1;



    OLE_DECL;

    DWORD dwCopied = (DWORD)-1;

    jbyte *pSrc = env->GetByteArrayElements(buf, NULL);

    //jbyte *pSrc = new jbyte[len];

    if(NULL==pSrc){

        OLE_HR = E_OUTOFMEMORY;

    } else {

        OLE_HR = readOutCache(pSrc + off, len, &dwCopied);

        env->ReleaseByteArrayElements(buf, pSrc, 0);

        //delete[] pSrc;

    }

    jint ret = HR2CABERR(env, OLE_HR, "stream out error", dwCopied);

    if( 0 < len && 0 == ret ){

        //STRACE1("no more read");

        ret = -1;

    }

    if( -1 == ret ){

        //STRACE1("no more read or error");

        ::SetEvent(m_hevLastEntryRead);

    }    

    if( !checkValid(env) )

        return -1;

    return ret;

}



/*

bool isHexSubstr(LPSTR pPos, int len, long *pdw)

{

    CHAR szHex[] = "0123456789abcdefABCDEF";

    BYTE Nibbles[] = {

        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 

        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 

        0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F 

    };

    *pdw = 0;

    for(int i = 0; i < len; ++i){

        LPSTR p = strchr(szHex, pPos[i]);

        if( NULL==p ){

            *pdw = -1;

            return false;

        } else {

            *pdw <<= 4;

            *pdw |= Nibbles[(int)(p-szHex)];

        }

    }

    return true;

}





void CCabUnpacker::ParseEntryName()

{

    //extract string like this nnnn{01234567-01234567xxxx}.eeee\0

    LPCSTR pDotPos = strrchr(m_pEntryName, '.');

    if(NULL==pDotPos){

        //there is not any extension

        pDotPos = m_pEntryName + strlen(m_pEntryName);

    }

    LPSTR pCloseInfoPos = strrchr(m_pEntryName, '}');

    if(NULL==pCloseInfoPos){

        return;

    }



    LPSTR pOpenInfoPos = strrchr(pCloseInfoPos, '{');

    //8hex+8hex+1minus=17 

    if(

        NULL!=pOpenInfoPos && 

        (pCloseInfoPos - pOpenInfoPos)>17 &&

        '-'==pCloseInfoPos[9] &&

        isHexSubstr(pCloseInfoPos+1, 8, &m_crc) &&

        isHexSubstr(pCloseInfoPos+10, 8, &m_csize) )

    {

       //truncate file name to original form nnnn.eeee\0

       *pOpenInfoPos = 0;

       strcat(m_pEntryName, pDotPos);

    }

}

*/



void CCabUnpacker::signalNewEntrtyFound(

    LPCSTR lpEntryName,

    USHORT time,

    USHORT date,

    int    oflag,

    long   osize)

{

    m_dos_time = MAKELONG(time, date);



    //Mask out attribute bits other than read-only,

    //hidden, system, and archive, since the other

    //attribute bits are reserved for use by

    //the cabinet format.

    //_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH



    m_oflag = oflag; //attributes of original

    m_osize = osize;//uncompressed of size



    free(m_pEntryName);

    m_pEntryName = lpEntryName ? _strdup(lpEntryName) : NULL;

    if(NULL!=m_pEntryName){

        for(LPSTR pPos = m_pEntryName; *pPos; ++pPos){

            if('\\'==*pPos){

                *pPos = '/';

            }

        }

    }

    

    ::ResetEvent(m_hevEndOfEntry);

    ::SetEvent(m_hevNewEntryFound);

}



INT_PTR  CCabUnpacker::notification(

    FDINOTIFICATIONTYPE fdint, 

    PFDINOTIFICATION pfdin)

{

    INT_PTR ret = 0;

    switch(fdint){

    case fdintCABINET_INFO:// general information about the cabinet

        setProperty(cab_next_file, pfdin->psz1);//next cabinet

        setProperty(cab_next_disk, pfdin->psz2);//next disk

        setProperty(cab_path,      pfdin->psz3);//cabinet path

        setProperty(cab_set_ID,    pfdin->setID); //cabinet set ID (int)

        setProperty(cab_number,    pfdin->iCabinet); //cabinet # in set (int)

        break;

    case fdintPARTIAL_FILE:// first file in cabinet is continuation

        setProperty(cab_torn_file, pfdin->psz1);//name of continued file

        setProperty(cab_prev_file, pfdin->psz2);//name of cabinet where file starts 

        setProperty(cab_prev_disk, pfdin->psz3);//name of disk where file starts

        //signal here that new synthetic folder-section has come

        if(NULL!=pfdin->psz3){

            CHAR szSyntheticPath[1024];

            if( 0 > _snprintf(
                szSyntheticPath, 1024, "cab_prev://%s|/%s/%s/", 
                pfdin->psz3,
                pfdin->psz2,
                pfdin->psz1))
            {
                szSyntheticPath[1023] = 0;

            }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?