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/Plugins/Library/ml_online/handler.cpp | 168 ++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Src/Plugins/Library/ml_online/handler.cpp (limited to 'Src/Plugins/Library/ml_online/handler.cpp') diff --git a/Src/Plugins/Library/ml_online/handler.cpp b/Src/Plugins/Library/ml_online/handler.cpp new file mode 100644 index 00000000..2191725e --- /dev/null +++ b/Src/Plugins/Library/ml_online/handler.cpp @@ -0,0 +1,168 @@ +#include "main.h" +#include "navigation.h" +#include "servicehelper.h" +#include "handler.h" +#include "ifc_omservice.h" +#include "../Agave/URIHandler/svc_urihandler.h" +#include +#include "api.h" + +#include + +static uint8_t quickhex(wchar_t c) +{ + int hexvalue = c; + if (hexvalue & 0x10) + hexvalue &= ~0x30; + else + { + hexvalue &= 0xF; + hexvalue += 9; + } + return hexvalue; +} + +static uint8_t DecodeEscape(const wchar_t *&str) +{ + uint8_t a = quickhex(*++str); + uint8_t b = quickhex(*++str); + str++; + return a * 16 + b; +} + +static void DecodeEscapedUTF8(wchar_t *&output, const wchar_t *&input) +{ + uint8_t utf8_data[1024] = {0}; // hopefully big enough!! + int num_utf8_words=0; + bool error=false; + + while (input && *input == '%' && num_utf8_words < sizeof(utf8_data)) + { + if (iswxdigit(input[1]) && iswxdigit(input[2])) + { + utf8_data[num_utf8_words++]=DecodeEscape(input); + } + else if (input[1] == '%') + { + input+=2; + utf8_data[num_utf8_words++]='%'; + } + else + { + error = true; + break; + } + } + + int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, 0, 0); + MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, output, len); + output += len; + + if (error) + { + *output++ = *input++; + } +} + +static void UrlDecode(const wchar_t *input, wchar_t *output, size_t len) +{ + const wchar_t *stop = output+len-4; // give ourself a cushion large enough to hold a full UTF-16 sequence + const wchar_t *itr = input; + while (itr && *itr) + { + if (output >= stop) + { + *output=0; + return; + } + + switch (*itr) + { + case '%': + DecodeEscapedUTF8(output, itr); + break; + case '&': + *output = 0; + return; + default: + *output++ = *itr++; + break; + } + } + *output = 0; +} +// first parameter has param name either null or = terminated, second is null terminated +static bool ParamCompare(const wchar_t *url_param, const wchar_t *param_name) +{ + while (url_param && *url_param && *param_name && *url_param!=L'=') + { + if (*url_param++ != *param_name++) + return false; + } + return true; +} + +static bool get_request_parm(const wchar_t *params, const wchar_t *param_name, wchar_t *value, size_t value_len) +{ + const wchar_t *t=params; + while (t && *t && *t != L'?') // find start of parameters + t++; + + while (t && *t) + { + t++; // skip ? or & + if (ParamCompare(t, param_name)) + { + while (t && *t && *t != L'=' && *t != '&') // find start of value + t++; + switch(*t) + { + case L'=': + UrlDecode(++t, value, value_len); + return true; + case 0: + case L'&': // no value + *value=0; + return true; + default: // shouldn't get here + return false; + } + } + while (t && *t && *t != L'&') // find next parameter + t++; + } + return false; +} + +int OnlineServicesURIHandler::ProcessFilename(const wchar_t *filename) +{ + if (HANDLED != IsMine(filename)) + return NOT_HANDLED; + + UINT serviceId = 0; + wchar_t szBuffer[512]=L""; + if (get_request_parm(filename, L"id", szBuffer, ARRAYSIZE(szBuffer)) && + L'\0' != szBuffer[0]) + { + if (FALSE == StrToIntEx(szBuffer, STIF_SUPPORT_HEX, (INT*)&serviceId)) + serviceId = 0; + } + + ServiceHelper_ShowService(serviceId, SHOWMODE_ENSUREVISIBLE); + return HANDLED_EXCLUSIVE; +} + +int OnlineServicesURIHandler::IsMine(const wchar_t *filename) +{ + if (!_wcsnicmp(filename, L"winamp://Online Services", 24) || !_wcsnicmp(filename, L"winamp://Online%20Services", 26)) + return HANDLED; + else + return NOT_HANDLED; +} + +#define CBCLASS OnlineServicesURIHandler +START_DISPATCH; +CB(PROCESSFILENAME, ProcessFilename); +CB(ISMINE, IsMine); +END_DISPATCH; +#undef CBCLASS \ No newline at end of file -- cgit