From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- Src/Winamp/JSAPI2_TransportAPI.cpp | 532 +++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 Src/Winamp/JSAPI2_TransportAPI.cpp (limited to 'Src/Winamp/JSAPI2_TransportAPI.cpp') diff --git a/Src/Winamp/JSAPI2_TransportAPI.cpp b/Src/Winamp/JSAPI2_TransportAPI.cpp new file mode 100644 index 00000000..be311ddb --- /dev/null +++ b/Src/Winamp/JSAPI2_TransportAPI.cpp @@ -0,0 +1,532 @@ +#include "JSAPI2_TransportAPI.h" +#include "JSAPI2_Security.h" +#include "JSAPI2_CallbackManager.h" +#include "main.h" +#include "JSAPI.h" +#include "JSAPI_CallbackParameters.h" + +#define SCRIPT_E_REPORTED 0x80020101 + +JSAPI2::TransportAPI::TransportAPI(const wchar_t *_key, JSAPI::ifc_info *info) +{ + this->info = info; + key = _key; + refCount = 1; +} + +JSAPI2::TransportAPI::~TransportAPI() +{ + // just in case someone forgot + JSAPI2::callbackManager.Deregister(this); + + size_t index = events.size(); + while(index--) + { + IDispatch *pEvent = events[index]; + if (NULL != pEvent) + pEvent->Release(); + } +} + +#define DISP_TABLE \ + CHECK_ID(Prev)\ + CHECK_ID(Play)\ + CHECK_ID(Pause)\ + CHECK_ID(Stop)\ + CHECK_ID(Next)\ + CHECK_ID(shuffle)\ + CHECK_ID(repeat)\ + CHECK_ID(position)\ + CHECK_ID(length)\ + CHECK_ID(url)\ + CHECK_ID(title)\ + CHECK_ID(playing)\ + CHECK_ID(paused)\ + CHECK_ID(GetMetadata)\ + CHECK_ID(RegisterForEvents)\ + CHECK_ID(UnregisterFromEvents)\ + + +#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str), +enum { + DISP_TABLE +}; + +#undef CHECK_ID +#define CHECK_ID(str)\ + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\ + { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; } + +HRESULT JSAPI2::TransportAPI::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++) + { + DISP_TABLE + + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} + +HRESULT JSAPI2::TransportAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT JSAPI2::TransportAPI::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +HRESULT JSAPI2::TransportAPI::ButtonPress(WPARAM button, const wchar_t *action, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + switch (security.GetActionAuthorization(L"transport", action, key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE); + break; + case JSAPI2::api_security::ACTION_ALLOWED: + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE); + SendMessageW(hMainWindow, WM_COMMAND, button, 0); + break; + } + return S_OK; +} + +HRESULT JSAPI2::TransportAPI::Prev(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + return ButtonPress(WINAMP_BUTTON1, L"controls", wFlags, pdispparams, pvarResult, puArgErr); +} + +HRESULT JSAPI2::TransportAPI::Play(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + return ButtonPress(WINAMP_BUTTON2, L"controls", wFlags, pdispparams, pvarResult, puArgErr); +} + +HRESULT JSAPI2::TransportAPI::Pause(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + return ButtonPress(WINAMP_BUTTON3, L"controls", wFlags, pdispparams, pvarResult, puArgErr); +} + +HRESULT JSAPI2::TransportAPI::Stop(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + return ButtonPress(WINAMP_BUTTON4, L"controls", wFlags, pdispparams, pvarResult, puArgErr); +} + +HRESULT JSAPI2::TransportAPI::Next(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + return ButtonPress(WINAMP_BUTTON5, L"controls", wFlags, pdispparams, pvarResult, puArgErr); +} + +HRESULT JSAPI2::TransportAPI::shuffle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYPUT) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr); + switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + return S_OK; + case JSAPI2::api_security::ACTION_ALLOWED: + if (!!config_shuffle != JSAPI_PARAM(pdispparams, 1).lVal) + SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_SHUFFLE, 0); + + return S_OK; + } + } + else if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BOOL; + V_BOOL(pvarResult) = (0 != config_shuffle) ? VARIANT_TRUE : VARIANT_FALSE;//(LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_SHUFFLE); + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; + + return E_FAIL; +} + + +HRESULT JSAPI2::TransportAPI::repeat(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYPUT) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr); + switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + return S_OK; + case JSAPI2::api_security::ACTION_ALLOWED: + if (!!config_repeat != !!JSAPI_PARAM(pdispparams, 1).boolVal) + SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_REPEAT, 0); + + return S_OK; + } + } + else if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BOOL; + V_BOOL(pvarResult) = (0 != config_repeat) ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; + + return E_FAIL; +} + +HRESULT JSAPI2::TransportAPI::position(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYPUT) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr); + if (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED) + { + SendMessageW(hMainWindow, WM_WA_IPC, JSAPI_PARAM(pdispparams, 1).lVal, IPC_JUMPTOTIME); + } + return S_OK; + } + else if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GETOUTPUTTIME); + return S_OK; + } + + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT JSAPI2::TransportAPI::length(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 2, IPC_GETOUTPUTTIME); + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT JSAPI2::TransportAPI::url(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + JSAPI_INIT_RESULT(pvarResult, VT_BSTR); + if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED) + { + JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileName)); + } + else + { + JSAPI_EMPTY_RESULT(pvarResult); + } + + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; + +} + +HRESULT JSAPI2::TransportAPI::title(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + JSAPI_INIT_RESULT(pvarResult, VT_BSTR); + + if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED) + { + JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileTitle)); + } + else + { + JSAPI_EMPTY_RESULT(pvarResult); + } + + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT JSAPI2::TransportAPI::playing(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BOOL; + switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + V_BOOL(pvarResult) = VARIANT_FALSE; + break; + case JSAPI2::api_security::ACTION_ALLOWED: + V_BOOL(pvarResult) = ::playing?VARIANT_TRUE:VARIANT_FALSE; + break; + } + + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT JSAPI2::TransportAPI::paused(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + if (wFlags & DISPATCH_PROPERTYGET) + { + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BOOL; + switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + V_BOOL(pvarResult) = VARIANT_FALSE; + break; + case JSAPI2::api_security::ACTION_ALLOWED: + V_BOOL(pvarResult) = ::paused?VARIANT_TRUE:VARIANT_FALSE; + break; + } + + return S_OK; + } + else + return DISP_E_MEMBERNOTFOUND; +} + +HRESULT JSAPI2::TransportAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr); + + JSAPI_INIT_RESULT(pvarResult, VT_BSTR); + + if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED) + { + wchar_t buffer[4096] = {0}; + extendedFileInfoStructW info; + + info.filename = FileName; + info.metadata = JSAPI_PARAM(pdispparams, 1).bstrVal; + info.ret = buffer; + info.retlen = sizeof(buffer)/sizeof(*buffer); + + if (NULL != info.filename && + NULL != info.metadata) + { + if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE)) + info.ret = NULL; + + JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret)); + } + else + JSAPI_EMPTY_RESULT(pvarResult); + + } + else + { + JSAPI_EMPTY_RESULT(pvarResult); + } + + return S_OK; +} + +HRESULT JSAPI2::TransportAPI::RegisterForEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + switch (security.GetActionAuthorization(L"transport", L"events", key, info, JSAPI2::api_security::ACTION_PROMPT)) + { + case JSAPI2::api_security::ACTION_DISALLOWED: + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE); + break; + case JSAPI2::api_security::ACTION_ALLOWED: + { + /** if this is the first time someone is registering an event + ** add ourselves to the callback manager + */ + if (events.empty()) + JSAPI2::callbackManager.Register(this); + + IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal; + event->AddRef(); + // TODO: benski> not sure, but we might need to: event->AddRef(); + events.push_back(event); + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE); + } + break; + } + return S_OK; +} + +HRESULT JSAPI2::TransportAPI::UnregisterFromEvents(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_DISPATCH, puArgErr); + + IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal; + // TODO: benski> not sure, but we might need to: event->Release(); + + size_t index = events.size(); + while(index--) + { + if (events[index] == event) + { + events.erase(events.begin() + index); + event->Release(); + } + } + + /** if we don't have any more event listeners + ** remove ourselves from the callback manager + */ + if (events.empty()) + JSAPI2::callbackManager.Deregister(this); + + return S_OK; +} + +#undef CHECK_ID +#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr); +HRESULT JSAPI2::TransportAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + switch (dispid) + { + DISP_TABLE + } + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP JSAPI2::TransportAPI::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 JSAPI2::TransportAPI::AddRef(void) +{ + return InterlockedIncrement(&refCount); +} + + +ULONG JSAPI2::TransportAPI::Release(void) +{ + LONG lRef = InterlockedDecrement(&refCount); + if (lRef == 0) delete this; + return lRef; +} + +void JSAPI2::TransportAPI::InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount) +{ + size_t index = events.size(); + if (0 == index) + { + JSAPI2::callbackManager.Deregister(this); + return; + } + + JSAPI::CallbackParameters *eventData= new JSAPI::CallbackParameters; + if (NULL == eventData) return; + + eventData->AddString(L"event", eventName); + + if (NULL != parameters && 0 != parametersCount) + eventData->AddPropertyIndirect(parameters, parametersCount); + + HRESULT hr; + while (index--) + { + IDispatch *pEvent = events[index]; + if (NULL != pEvent) + { + hr = JSAPI::InvokeEvent(eventData, pEvent); + if (FAILED(hr) && SCRIPT_E_REPORTED != hr) + { + events.erase(events.begin() + index); + pEvent->Release(); + } + } + } + + if (events.empty()) + JSAPI2::callbackManager.Deregister(this); + + eventData->Release(); +} + +void JSAPI2::TransportAPI::OnStop(int position, int is_full_stop) +{ + if (!is_full_stop) + { + JSAPI::CallbackParameters::PropertyTemplate parameter = + {JSAPI::CallbackParameters::typeLong, L"position", (ULONG_PTR)position}; + + InvokeEvent(L"OnStop", ¶meter, 1); + } + else + { + InvokeEvent(L"OnEndOfFile", NULL, 0); + } +} + +void JSAPI2::TransportAPI::OnPlay(const wchar_t *filename) +{ + JSAPI::CallbackParameters::PropertyTemplate parameter = + {JSAPI::CallbackParameters::typeString, L"filename", (ULONG_PTR)filename}; + + InvokeEvent(L"OnPlay", ¶meter, 1); +} + + +void JSAPI2::TransportAPI::OnPause(bool pause_state) +{ + JSAPI::CallbackParameters::PropertyTemplate parameter = + {JSAPI::CallbackParameters::typeBool, L"paused", (ULONG_PTR)pause_state}; + + InvokeEvent(L"OnPause", ¶meter, 1); +} \ No newline at end of file -- cgit