aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/JSAPI2_TransportAPI.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/JSAPI2_TransportAPI.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/Winamp/JSAPI2_TransportAPI.cpp')
-rw-r--r--Src/Winamp/JSAPI2_TransportAPI.cpp532
1 files changed, 532 insertions, 0 deletions
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", &parameter, 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", &parameter, 1);
+}
+
+
+void JSAPI2::TransportAPI::OnPause(bool pause_state)
+{
+ JSAPI::CallbackParameters::PropertyTemplate parameter =
+ {JSAPI::CallbackParameters::typeBool, L"paused", (ULONG_PTR)pause_state};
+
+ InvokeEvent(L"OnPause", &parameter, 1);
+} \ No newline at end of file