wined3d: Create a backup context if setting the pixel format failed in wined3d_contex...
[wine.git] / dlls / webservices / url.c
blob8bd3d82660f69a4bdf728bc9c29ca924c494fd9c
1 /*
2 * Copyright 2016 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winnls.h"
24 #include "winuser.h"
25 #include "webservices.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/list.h"
30 #include "webservices_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
34 static const WCHAR http[] = {'h','t','t','p'};
35 static const WCHAR https[] = {'h','t','t','p','s'};
36 static const WCHAR nettcp[] = {'n','e','t','.','t','c','p'};
37 static const WCHAR soapudp[] = {'s','o','a','p','.','u','d','p'};
38 static const WCHAR netpipe[] = {'n','e','t','.','p','i','p','e'};
40 static WS_URL_SCHEME_TYPE scheme_type( const WCHAR *str, ULONG len )
42 if (len == ARRAY_SIZE( http ) && !wcsnicmp( str, http, ARRAY_SIZE( http )))
43 return WS_URL_HTTP_SCHEME_TYPE;
45 if (len == ARRAY_SIZE( https ) && !wcsnicmp( str, https, ARRAY_SIZE( https )))
46 return WS_URL_HTTPS_SCHEME_TYPE;
48 if (len == ARRAY_SIZE( nettcp ) && !wcsnicmp( str, nettcp, ARRAY_SIZE( nettcp )))
49 return WS_URL_NETTCP_SCHEME_TYPE;
51 if (len == ARRAY_SIZE( soapudp ) && !wcsnicmp( str, soapudp, ARRAY_SIZE( soapudp )))
52 return WS_URL_SOAPUDP_SCHEME_TYPE;
54 if (len == ARRAY_SIZE( netpipe ) && !wcsnicmp( str, netpipe, ARRAY_SIZE( netpipe )))
55 return WS_URL_NETPIPE_SCHEME_TYPE;
57 return ~0u;
60 static USHORT default_port( WS_URL_SCHEME_TYPE scheme )
62 switch (scheme)
64 case WS_URL_HTTP_SCHEME_TYPE: return 80;
65 case WS_URL_HTTPS_SCHEME_TYPE: return 443;
66 case WS_URL_NETTCP_SCHEME_TYPE: return 808;
67 case WS_URL_SOAPUDP_SCHEME_TYPE:
68 case WS_URL_NETPIPE_SCHEME_TYPE: return 65535;
69 default:
70 ERR( "unhandled scheme %u\n", scheme );
71 return 0;
75 static unsigned char *strdup_utf8( const WCHAR *str, ULONG len, ULONG *ret_len )
77 unsigned char *ret;
78 *ret_len = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
79 if ((ret = heap_alloc( *ret_len )))
80 WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)ret, *ret_len, NULL, NULL );
81 return ret;
84 static inline int url_decode_byte( char c1, char c2 )
86 int ret;
88 if (c1 >= '0' && c1 <= '9') ret = (c1 - '0') * 16;
89 else if (c1 >= 'a' && c1 <= 'f') ret = (c1 - 'a' + 10) * 16;
90 else ret = (c1 - 'A' + 10) * 16;
92 if (c2 >= '0' && c2 <= '9') ret += c2 - '0';
93 else if (c2 >= 'a' && c2 <= 'f') ret += c2 - 'a' + 10;
94 else ret += c2 - 'A' + 10;
96 return ret;
99 static WCHAR *url_decode( WCHAR *str, ULONG len, WS_HEAP *heap, ULONG *ret_len )
101 WCHAR *p = str, *q, *ret;
102 BOOL decode = FALSE, convert = FALSE;
103 ULONG i, len_utf8, len_left;
104 unsigned char *utf8, *r;
106 *ret_len = len;
107 for (i = 0; i < len; i++, p++)
109 if ((len - i) < 3) break;
110 if (p[0] == '%' && iswxdigit( p[1] ) && iswxdigit( p[2] ))
112 decode = TRUE;
113 if (url_decode_byte( p[1], p[2] ) > 159)
115 convert = TRUE;
116 break;
118 *ret_len -= 2;
121 if (!decode) return str;
122 if (!convert)
124 if (!(q = ret = ws_alloc( heap, *ret_len * sizeof(WCHAR) ))) return NULL;
125 p = str;
126 while (len)
128 if (len >= 3 && p[0] == '%' && iswxdigit( p[1] ) && iswxdigit( p[2] ))
130 *q++ = url_decode_byte( p[1], p[2] );
131 p += 3;
132 len -= 3;
134 else
136 *q++ = *p++;
137 len -= 1;
140 return ret;
143 if (!(r = utf8 = strdup_utf8( str, len, &len_utf8 ))) return NULL;
144 len_left = len_utf8;
145 while (len_left)
147 if (len_left >= 3 && r[0] == '%' && isxdigit( r[1] ) && isxdigit( r[2] ))
149 r[0] = url_decode_byte( r[1], r[2] );
150 len_left -= 3;
151 memmove( r + 1, r + 3, len_left );
152 len_utf8 -= 2;
154 else len_left -= 1;
155 r++;
158 if (!(*ret_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, (char *)utf8,
159 len_utf8, NULL, 0 )))
161 WARN( "invalid UTF-8 sequence\n" );
162 heap_free( utf8 );
163 return NULL;
165 if ((ret = ws_alloc( heap, *ret_len * sizeof(WCHAR) )))
166 MultiByteToWideChar( CP_UTF8, 0, (char *)utf8, len_utf8, ret, *ret_len );
168 heap_free( utf8 );
169 return ret;
172 /**************************************************************************
173 * WsDecodeUrl [webservices.@]
175 HRESULT WINAPI WsDecodeUrl( const WS_STRING *str, ULONG flags, WS_HEAP *heap, WS_URL **ret,
176 WS_ERROR *error )
178 HRESULT hr = WS_E_QUOTA_EXCEEDED;
179 WCHAR *p, *q, *decoded = NULL;
180 WS_HTTP_URL *url = NULL;
181 ULONG len, len_decoded, port = 0;
183 TRACE( "%s %08x %p %p %p\n", str ? debugstr_wn(str->chars, str->length) : "null", flags,
184 heap, ret, error );
185 if (error) FIXME( "ignoring error parameter\n" );
187 if (!str || !heap) return E_INVALIDARG;
188 if (!str->length) return WS_E_INVALID_FORMAT;
189 if (flags)
191 FIXME( "unimplemented flags %08x\n", flags );
192 return E_NOTIMPL;
194 if (!(decoded = url_decode( str->chars, str->length, heap, &len_decoded )) ||
195 !(url = ws_alloc( heap, sizeof(*url) ))) goto done;
197 hr = WS_E_INVALID_FORMAT;
199 p = q = decoded;
200 len = len_decoded;
201 while (len && *q != ':') { q++; len--; };
202 if (*q != ':') goto done;
203 if ((url->url.scheme = scheme_type( p, q - p )) == ~0u) goto done;
205 if (!--len || *++q != '/') goto done;
206 if (!--len || *++q != '/') goto done;
208 p = ++q; len--;
209 while (len && *q != '/' && *q != ':' && *q != '?' && *q != '#') { q++; len--; };
210 if (q == p) goto done;
211 url->host.length = q - p;
212 url->host.chars = p;
214 if (len && *q == ':')
216 p = ++q; len--;
217 while (len && iswdigit( *q ))
219 if ((port = port * 10 + *q - '0') > 65535) goto done;
220 q++; len--;
222 url->port = port;
223 url->portAsString.length = q - p;
224 url->portAsString.chars = p;
226 if (!port)
228 url->port = default_port( url->url.scheme );
229 url->portAsString.length = 0;
230 url->portAsString.chars = NULL;
233 if (len && *q == '/')
235 p = q;
236 while (len && *q != '?') { q++; len--; };
237 url->path.length = q - p;
238 url->path.chars = p;
240 else url->path.length = 0;
242 if (len && *q == '?')
244 p = ++q; len--;
245 while (len && *q != '#') { q++; len--; };
246 url->query.length = q - p;
247 url->query.chars = p;
249 else url->query.length = 0;
251 if (len && *q == '#')
253 p = ++q; len--;
254 while (len && *q != '#') { q++; len--; };
255 url->fragment.length = q - p;
256 url->fragment.chars = p;
258 else url->fragment.length = 0;
260 *ret = (WS_URL *)url;
261 hr = S_OK;
263 done:
264 if (hr != S_OK)
266 if (decoded != str->chars) ws_free( heap, decoded, len_decoded );
267 ws_free( heap, url, sizeof(*url) );
269 TRACE( "returning %08x\n", hr );
270 return hr;
273 static const WCHAR *scheme_str( WS_URL_SCHEME_TYPE scheme, ULONG *len )
275 switch (scheme)
277 case WS_URL_HTTP_SCHEME_TYPE:
278 *len = ARRAY_SIZE( http );
279 return http;
281 case WS_URL_HTTPS_SCHEME_TYPE:
282 *len = ARRAY_SIZE( https );
283 return https;
285 case WS_URL_NETTCP_SCHEME_TYPE:
286 *len = ARRAY_SIZE( nettcp );
287 return nettcp;
289 case WS_URL_SOAPUDP_SCHEME_TYPE:
290 *len = ARRAY_SIZE( soapudp );
291 return soapudp;
293 case WS_URL_NETPIPE_SCHEME_TYPE:
294 *len = ARRAY_SIZE( netpipe );
295 return netpipe;
297 default:
298 ERR( "unhandled scheme %u\n", scheme );
299 return NULL;
303 static inline ULONG escape_size( unsigned char ch, const char *except )
305 const char *p = except;
306 while (*p)
308 if (*p == ch) return 1;
309 p++;
311 if ((ch >= 'a' && ch <= 'z' ) || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) return 1;
312 if (ch < 33 || ch > 126) return 3;
313 switch (ch)
315 case '/':
316 case '?':
317 case '"':
318 case '#':
319 case '%':
320 case '<':
321 case '>':
322 case '\\':
323 case '[':
324 case ']':
325 case '^':
326 case '`':
327 case '{':
328 case '|':
329 case '}':
330 return 3;
331 default:
332 return 1;
336 static HRESULT url_encode_size( const WCHAR *str, ULONG len, const char *except, ULONG *ret_len )
338 ULONG i, len_utf8;
339 BOOL convert = FALSE;
340 unsigned char *utf8;
342 *ret_len = 0;
343 for (i = 0; i < len; i++)
345 if (str[i] > 159)
347 convert = TRUE;
348 break;
350 *ret_len += escape_size( str[i], except );
352 if (!convert) return S_OK;
354 *ret_len = 0;
355 if (!(utf8 = strdup_utf8( str, len, &len_utf8 ))) return E_OUTOFMEMORY;
356 for (i = 0; i < len_utf8; i++) *ret_len += escape_size( utf8[i], except );
357 heap_free( utf8 );
359 return S_OK;
362 static ULONG url_encode_byte( unsigned char byte, const char *except, WCHAR *buf )
364 static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
365 switch (escape_size( byte, except ))
367 case 3:
368 buf[0] = '%';
369 buf[1] = hex[(byte >> 4) & 0xf];
370 buf[2] = hex[byte & 0xf];
371 return 3;
373 case 1:
374 buf[0] = byte;
375 return 1;
377 default:
378 ERR( "unhandled escape size\n" );
379 return 0;
384 static HRESULT url_encode( const WCHAR *str, ULONG len, WCHAR *buf, const char *except, ULONG *ret_len )
386 HRESULT hr = S_OK;
387 ULONG i, len_utf8, len_enc;
388 BOOL convert = FALSE;
389 WCHAR *p = buf;
390 unsigned char *utf8;
392 *ret_len = 0;
393 for (i = 0; i < len; i++)
395 if (str[i] > 159)
397 convert = TRUE;
398 break;
400 len_enc = url_encode_byte( str[i], except, p );
401 *ret_len += len_enc;
402 p += len_enc;
404 if (!convert) return S_OK;
406 p = buf;
407 *ret_len = 0;
408 if (!(utf8 = strdup_utf8( str, len, &len_utf8 ))) return E_OUTOFMEMORY;
409 for (i = 0; i < len_utf8; i++)
411 len_enc = url_encode_byte( utf8[i], except, p );
412 *ret_len += len_enc;
413 p += len_enc;
416 heap_free( utf8 );
417 return hr;
420 /**************************************************************************
421 * WsEncodeUrl [webservices.@]
423 HRESULT WINAPI WsEncodeUrl( const WS_URL *base, ULONG flags, WS_HEAP *heap, WS_STRING *ret,
424 WS_ERROR *error )
426 static const WCHAR fmtW[] = {':','%','u',0};
427 ULONG len = 0, len_scheme, len_enc, ret_size = 0;
428 const WS_HTTP_URL *url = (const WS_HTTP_URL *)base;
429 const WCHAR *scheme;
430 WCHAR *str = NULL, *p, *q;
431 ULONG port = 0;
432 HRESULT hr = WS_E_INVALID_FORMAT;
434 TRACE( "%p %08x %p %p %p\n", base, flags, heap, ret, error );
435 if (error) FIXME( "ignoring error parameter\n" );
437 if (!url || !heap || !ret) return E_INVALIDARG;
438 if (flags)
440 FIXME( "unimplemented flags %08x\n", flags );
441 return E_NOTIMPL;
443 if (!(scheme = scheme_str( url->url.scheme, &len_scheme ))) goto done;
444 len = len_scheme + 3; /* '://' */
445 len += 6; /* ':65535' */
447 if ((hr = url_encode_size( url->host.chars, url->host.length, "", &len_enc )) != S_OK)
448 goto done;
449 len += len_enc;
451 if ((hr = url_encode_size( url->path.chars, url->path.length, "/", &len_enc )) != S_OK)
452 goto done;
453 len += len_enc;
455 if ((hr = url_encode_size( url->query.chars, url->query.length, "/?", &len_enc )) != S_OK)
456 goto done;
457 len += len_enc + 1; /* '?' */
459 if ((hr = url_encode_size( url->fragment.chars, url->fragment.length, "/?", &len_enc )) != S_OK)
460 goto done;
461 len += len_enc + 1; /* '#' */
463 ret_size = len * sizeof(WCHAR);
464 if (!(str = ws_alloc( heap, ret_size )))
466 hr = WS_E_QUOTA_EXCEEDED;
467 goto done;
470 memcpy( str, scheme, len_scheme * sizeof(WCHAR) );
471 p = str + len_scheme;
472 p[0] = ':';
473 p[1] = p[2] = '/';
474 p += 3;
476 if ((hr = url_encode( url->host.chars, url->host.length, p, "", &len_enc )) != S_OK)
477 goto done;
478 p += len_enc;
480 if (url->portAsString.length)
482 q = url->portAsString.chars;
483 len = url->portAsString.length;
484 while (len && iswdigit( *q ))
486 if ((port = port * 10 + *q - '0') > 65535)
488 hr = WS_E_INVALID_FORMAT;
489 goto done;
491 q++; len--;
493 if (url->port && port != url->port)
495 hr = E_INVALIDARG;
496 goto done;
498 } else port = url->port;
500 if (port == default_port( url->url.scheme )) port = 0;
501 if (port)
503 WCHAR buf[7];
504 len = swprintf( buf, ARRAY_SIZE(buf), fmtW, port );
505 memcpy( p, buf, len * sizeof(WCHAR) );
506 p += len;
509 if ((hr = url_encode( url->path.chars, url->path.length, p, "/", &len_enc )) != S_OK)
510 goto done;
511 p += len_enc;
513 if (url->query.length)
515 *p++ = '?';
516 if ((hr = url_encode( url->query.chars, url->query.length, p, "/?", &len_enc )) != S_OK)
517 goto done;
518 p += len_enc;
521 if (url->fragment.length)
523 *p++ = '#';
524 if ((hr = url_encode( url->fragment.chars, url->fragment.length, p, "/?", &len_enc )) != S_OK)
525 goto done;
526 p += len_enc;
529 ret->length = p - str;
530 ret->chars = str;
531 hr = S_OK;
533 done:
534 if (hr != S_OK) ws_free( heap, str, ret_size );
535 TRACE( "returning %08x\n", hr );
536 return hr;