winamp/Src/Winamp/jnetcom.cpp
2024-09-24 14:54:57 +02:00

529 lines
12 KiB
C++

#include "jnetcom.h"
#include "../nu/AutoChar.h"
/* --- Jnetlib COM object --- */
extern "C" extern HANDLE DuplicateCurrentThread();
JNetCOM::JNetCOM( IDispatch *_dispatch )
{
refCount = 1;
token = 0;
dispatch = _dispatch;
threadId = GetCurrentThreadId();
threadHandle = DuplicateCurrentThread();
retained = false;
if ( NULL != dispatch )
dispatch->AddRef();
}
JNetCOM::~JNetCOM()
{
if ( retained )
{
if ( NULL != WAC_API_DOWNLOADMANAGER )
WAC_API_DOWNLOADMANAGER->ReleaseDownload( token );
}
CloseHandle( threadHandle );
if ( NULL != dispatch )
dispatch->Release();
}
enum
{
DISP_JNETCOM_ABORT,
DISP_JNETCOM_ADDHEADER,
DISP_JNETCOM_CONNECT,
DISP_JNETCOM_GETCONTENT,
DISP_JNETCOM_GETCONTENTASSTRING,
DISP_JNETCOM_GETERRORSTRING,
DISP_JNETCOM_GETHEADER,
DISP_JNETCOM_GETREPLY,
DISP_JNETCOM_GETREPLYCODE,
DISP_JNETCOM_GETURL,
DISP_JNETCOM_SETPOSTSTRING,
};
#define CHECK_ID(str, id)\
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
{ rgdispid[i] = id; continue; }
HRESULT JNetCOM::GetIDsOfNames( REFIID riid, OLECHAR FAR *FAR *rgszNames, unsigned int cNames, LCID lcid, DISPID FAR *rgdispid )
{
bool unknowns = false;
for ( unsigned int i = 0; i != cNames; i++ )
{
CHECK_ID( "Abort", DISP_JNETCOM_ABORT );
CHECK_ID( "AddHeader", DISP_JNETCOM_ADDHEADER );
CHECK_ID( "Connect", DISP_JNETCOM_CONNECT );
CHECK_ID( "GetContent", DISP_JNETCOM_GETCONTENT );
CHECK_ID( "GetContentAsString", DISP_JNETCOM_GETCONTENTASSTRING );
CHECK_ID( "GetErrorString", DISP_JNETCOM_GETERRORSTRING );
CHECK_ID( "GetHeader", DISP_JNETCOM_GETHEADER );
CHECK_ID( "GetReply", DISP_JNETCOM_GETREPLY );
CHECK_ID( "GetReplyCode", DISP_JNETCOM_GETREPLYCODE );
CHECK_ID( "GetURL", DISP_JNETCOM_GETURL );
CHECK_ID( "SetPOSTString", DISP_JNETCOM_SETPOSTSTRING );
rgdispid[ i ] = DISPID_UNKNOWN;
unknowns = true;
}
if ( unknowns )
return DISP_E_UNKNOWNNAME;
else
return S_OK;
}
HRESULT JNetCOM::GetTypeInfo( unsigned int itinfo, LCID lcid, ITypeInfo FAR *FAR *pptinfo )
{
return E_NOTIMPL;
}
HRESULT JNetCOM::GetTypeInfoCount( unsigned int FAR *pctinfo )
{
return E_NOTIMPL;
}
HRESULT JNetCOM::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR *pexecinfo, unsigned int FAR *puArgErr )
{
switch ( dispid )
{
case DISP_JNETCOM_ABORT:
return Abort();
case DISP_JNETCOM_ADDHEADER:
return AddHeader( pdispparams->rgvarg[ 0 ].bstrVal );
case DISP_JNETCOM_CONNECT:
if ( pdispparams->cArgs == 2 )
return Connect( pdispparams->rgvarg[ 1 ].bstrVal, pdispparams->rgvarg[ 0 ].bstrVal );
else
return Connect( pdispparams->rgvarg[ 0 ].bstrVal, L"GET" );
case DISP_JNETCOM_GETCONTENT:
return GetContent( pvarResult );
case DISP_JNETCOM_GETCONTENTASSTRING:
return GetContentAsString( pvarResult );
case DISP_JNETCOM_GETERRORSTRING:
return GetErrorString( pvarResult );
case DISP_JNETCOM_GETHEADER:
return GetHeader( pdispparams->rgvarg[ 0 ].bstrVal, pvarResult );
case DISP_JNETCOM_GETREPLY:
return GetReply( pvarResult );
case DISP_JNETCOM_GETREPLYCODE:
return GetReplyCode( pvarResult );
case DISP_JNETCOM_GETURL:
return GetUrl( pvarResult );
case DISP_JNETCOM_SETPOSTSTRING:
break;
}
return DISP_E_MEMBERNOTFOUND;
}
STDMETHODIMP JNetCOM::QueryInterface( REFIID riid, PVOID *ppvObject )
{
if ( !ppvObject )
return E_POINTER;
else if ( IsEqualIID( riid, IID_IDispatch ) )
*ppvObject = (IDispatch *)this;
else if ( IsEqualIID( riid, IID_IUnknown ) )
*ppvObject = this;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG JNetCOM::AddRef( void )
{
return InterlockedIncrement( &refCount );
}
ULONG JNetCOM::Release( void )
{
LONG lRef = InterlockedDecrement( &refCount );
if ( lRef == 0 )
delete this;
return lRef;
}
/* ---- */
HRESULT JNetCOM::Abort()
{
if ( NULL != WAC_API_DOWNLOADMANAGER )
WAC_API_DOWNLOADMANAGER->CancelDownload( token );
return S_OK;
}
HRESULT JNetCOM::AddHeader( LPCWSTR header )
{
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
http->addheader( AutoChar( header, CP_UTF8 ) );
return S_OK;
}
HRESULT JNetCOM::Connect( LPCWSTR url, LPCWSTR requestMethod )
{
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
AddRef();
token = WAC_API_DOWNLOADMANAGER->DownloadEx( AutoChar( url, CP_UTF8 ), this, api_downloadManager::DOWNLOADEX_BUFFER );
return S_OK;
}
HRESULT JNetCOM::GetContent( VARIANT *variant )
{
char dummy[ 1 ] = { 0 };
size_t sourcelen = 0;
void *source = 0;
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen );
if ( !sourcelen || !source )
{
source = dummy;
sourcelen = 1;
}
SAFEARRAY *bufferArray = SafeArrayCreateVector( VT_UI1, 0, (ULONG)sourcelen );
void *data;
SafeArrayAccessData( bufferArray, &data );
memcpy( data, source, sourcelen );
SafeArrayUnaccessData( bufferArray );
VariantInit( variant );
V_VT( variant ) = VT_ARRAY | VT_UI1;
V_ARRAY( variant ) = bufferArray;
return S_OK;
}
HRESULT JNetCOM::GetContentAsString( VARIANT *variant )
{
// TODO: try to determine character encoding
size_t sourcelen = 0;
void *source = 0;
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
if ( WAC_API_DOWNLOADMANAGER->GetBuffer( token, &source, &sourcelen ) == 0 )
{
if ( source && sourcelen )
{
int len = MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, 0, 0 );
BSTR str = SysAllocStringLen( 0, len );
MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)source, (int)sourcelen, str, len );
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = str;
return S_OK;
}
else
{
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = SysAllocString( L"" );
return S_OK;
}
}
else
return E_FAIL;
}
HRESULT JNetCOM::GetErrorString( VARIANT *variant )
{
const char *source = 0;
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
source = http->geterrorstr();
if ( !source )
source = "";
int sourcelen = (int)strlen( source );
int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
BSTR str = SysAllocStringLen( 0, len );
MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = str;
return S_OK;
}
HRESULT JNetCOM::GetHeader( LPCWSTR header, VARIANT *variant )
{
const char *source = 0;
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
source = http->getheader( AutoChar( header, CP_UTF8 ) );
if ( !source )
source = "";
int sourcelen = (int)strlen( source );
int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
BSTR str = SysAllocStringLen( 0, len );
MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = str;
return S_OK;
}
HRESULT JNetCOM::GetReply( VARIANT *variant )
{
const char *source = 0;
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
source = http->GetReply();
if ( !source )
source = "";
int sourcelen = (int)strlen( source );
int len = MultiByteToWideChar( CP_ACP, 0, source, sourcelen, 0, 0 );
BSTR str = SysAllocStringLen( 0, len );
MultiByteToWideChar( CP_ACP, 0, source, sourcelen, str, len );
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = str;
return S_OK;
}
HRESULT JNetCOM::GetReplyCode( VARIANT *variant )
{
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
int code = 0;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
code = http->getreplycode();
VariantInit( variant );
V_VT( variant ) = VT_UI4;
V_UI4( variant ) = code;
return S_OK;
}
HRESULT JNetCOM::GetUrl( VARIANT *variant )
{
if ( NULL == WAC_API_DOWNLOADMANAGER )
return E_POINTER;
const char *source = 0;
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
if ( http )
source = http->get_url();
if ( !source )
source = "";
int sourcelen = (int)strlen( source );
int len = MultiByteToWideChar( 1252, 0, source, sourcelen, 0, 0 );
BSTR str = SysAllocStringLen( 0, len );
MultiByteToWideChar( 1252, 0, source, sourcelen, str, len );
VariantInit( variant );
V_VT( variant ) = VT_BSTR;
V_BSTR( variant ) = str;
return S_OK;
}
extern void CallDispatchMethod( IDispatch *dispatch, DISPPARAMS &params, OLECHAR *name );
struct APCWait
{
IDispatch *dispatch;
HANDLE hEvent;
};
#define AutoAPC(name) \
static VOID CALLBACK name ## APC(ULONG_PTR param) {\
APCWait *wait = (APCWait *)param;\
\
DISPPARAMS params;\
params.cArgs = 0;\
params.cNamedArgs = 0;\
params.rgdispidNamedArgs = 0;\
params.rgvarg = 0;\
if (wait->dispatch != NULL)\
CallDispatchMethod(wait->dispatch, params, L ## #name);\
if (wait->hEvent)\
SetEvent(wait->hEvent);\
}
AutoAPC( OnFinish );
AutoAPC( OnTick );
AutoAPC( OnError );
AutoAPC( OnCancel );
AutoAPC( OnConnect );
AutoAPC( OnInit );
void JNetCOM::Call( PAPCFUNC func )
{
DWORD curThreadId = GetCurrentThreadId();
if ( curThreadId == threadId )
{
APCWait wait;
wait.dispatch = dispatch;
wait.hEvent = 0;
func( (ULONG_PTR)&wait );
}
else
{
if ( threadHandle )
{
APCWait wait;
wait.dispatch = dispatch;
wait.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( QueueUserAPC( func, threadHandle, (ULONG_PTR)&wait ) != 0 )
WaitForSingleObject( wait.hEvent, INFINITE );
CloseHandle( wait.hEvent );
}
}
}
void JNetCOM::OnFinish( DownloadToken token )
{
if ( NULL != WAC_API_DOWNLOADMANAGER )
WAC_API_DOWNLOADMANAGER->RetainDownload( token );
retained = true;
Call( OnFinishAPC );
token = 0;
Release();
}
void JNetCOM::OnTick( DownloadToken token )
{
//Call(OnTickAPC);
}
void JNetCOM::OnError( DownloadToken token, int error )
{
if ( NULL != WAC_API_DOWNLOADMANAGER )
WAC_API_DOWNLOADMANAGER->RetainDownload( token );
retained = true;
Call( OnErrorAPC );
token = 0;
Release();
}
void JNetCOM::OnCancel( DownloadToken token )
{
if ( NULL != WAC_API_DOWNLOADMANAGER )
WAC_API_DOWNLOADMANAGER->RetainDownload( token );
retained = true;
Call( OnCancelAPC );
token = 0;
Release();
}
void JNetCOM::OnConnect( DownloadToken token )
{
Call( OnConnectAPC );
}
void JNetCOM::OnInit( DownloadToken token )
{
Call( OnInitAPC );
}
size_t JNetCOM::Dispatchable_AddRef()
{
return InterlockedIncrement( &refCount );
}
size_t JNetCOM::Dispatchable_Release()
{
LONG lRef = InterlockedDecrement( &refCount );
if ( lRef == 0 )
delete this;
return lRef;
}
#define CBCLASS JNetCOM
START_DISPATCH;
CB( ADDREF, Dispatchable_AddRef )
CB( RELEASE, Dispatchable_Release )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
END_DISPATCH;
#undef CBCLASS