1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
#include "main.h"
#include "navigation.h"
#include "servicehelper.h"
#include "handler.h"
#include "ifc_omservice.h"
#include "../Agave/URIHandler/svc_urihandler.h"
#include <api/service/waservicefactory.h>
#include "api.h"
#include <shlwapi.h>
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
|