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 + -
显示快捷键?