Implemented stubs for SHRegEnumUSKey{A|W} and return end-of-list error
[wine] / dlls / shlwapi / url.c
1 /*
2  * Url functions
3  *
4  * Copyright 2000 Huw D M Davies for CodeWeavers.
5  */
6
7 #include <string.h>
8 #include "windef.h"
9 #include "winbase.h"
10 #include "winerror.h"
11 #include "wine/unicode.h"
12 #include "shlwapi.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(shell);
16
17 static const unsigned char HashDataLookup[256] = {
18  0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B,
19  0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07,
20  0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94,
21  0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46,
22  0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0,
23  0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6,
24  0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F,
25  0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
26  0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF,
27  0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40,
28  0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9,
29  0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4,
30  0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB,
31  0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB,
32  0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D,
33  0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
34  0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD,
35  0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17,
36  0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
37  0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
38
39 static BOOL URL_NeedEscape(CHAR ch, DWORD dwFlags)
40 {
41
42     if (isalnum(ch))
43         return FALSE;
44
45     if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
46         if(ch == ' ')
47             return TRUE;
48         else
49             return FALSE;
50     }
51
52     if (ch <= 31 || ch >= 127)
53         return TRUE;
54
55     else {
56         switch (ch) {
57         case ' ':
58         case '<':
59         case '>':
60         case '\"':
61         case '{':
62         case '}':
63         case '|':
64         case '\\':
65         case '^':
66         case ']':
67         case '[':
68         case '`':
69         case '&':
70             return TRUE;
71
72         default:
73             return FALSE;
74         }
75     }
76 }
77
78 /*************************************************************************
79  *        UrlCanonicalizeA     [SHLWAPI.@]
80  */
81 HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
82         LPDWORD pcchCanonicalized, DWORD dwFlags)
83 {
84     HRESULT hr = S_OK;
85
86     LPSTR lpszUrlCpy;
87     INT nLen;
88
89     TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszCanonicalized,
90           pcchCanonicalized, dwFlags);
91
92     nLen = strlen(pszUrl);
93     lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nLen + 1);
94
95     if (dwFlags & URL_DONT_SIMPLIFY)
96         memcpy(lpszUrlCpy, pszUrl, nLen + 1);
97     else {
98         FIXME("Simplify path\n");
99         memcpy(lpszUrlCpy, pszUrl, nLen + 1);
100     }
101
102     if(dwFlags & URL_UNESCAPE)
103         UrlUnescapeA(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
104
105     if(dwFlags & (URL_ESCAPE_UNSAFE | URL_ESCAPE_SPACES_ONLY)) {
106         DWORD EscapeFlags = dwFlags & (URL_ESCAPE_SPACES_ONLY
107                                        /* | URL_ESCAPE_PERCENT */);
108         hr = UrlEscapeA(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
109                         EscapeFlags);
110     } else { /* No escapping needed, just copy the string */
111         nLen = strlen(lpszUrlCpy);
112         if(nLen < *pcchCanonicalized)
113             memcpy(pszCanonicalized, lpszUrlCpy, nLen + 1);
114         else {
115             hr = E_POINTER;
116             nLen++;
117         }
118         *pcchCanonicalized = nLen;
119     }
120
121     HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
122   
123     return hr;
124 }
125
126 /*************************************************************************
127  *        UrlCanonicalizeW     [SHLWAPI.@]
128  */
129 HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, 
130                                 LPDWORD pcchCanonicalized, DWORD dwFlags)
131 {
132     FIXME("(%s %p %p 0x%08lx): stub\n",debugstr_w(pszUrl),
133           pszCanonicalized, pcchCanonicalized, dwFlags);
134     return E_NOTIMPL;
135 }
136
137 /*************************************************************************
138  *      UrlEscapeA      [SHLWAPI.@]
139  *
140  * Converts unsafe characters into their escape sequences.
141  *
142  * The converted string is returned in pszEscaped if the buffer size
143  * (which should be supplied in pcchEscaped) is large enough, in this
144  * case the function returns S_OK and pcchEscaped contains the length
145  * of the escaped string.  If the buffer is not large enough the
146  * function returns E_POINTER and pcchEscaped contains the required
147  * buffer size (including room for the '\0').
148  *
149  * By default the function stops converting at the first '?' or
150  * '#'. [MSDN says differently].  If URL_ESCAPE_SPACE_ONLY flag is set
151  * then only spaces are converted, but the conversion continues past a
152  * '?' or '#'.
153  *
154  * BUGS:
155  *
156  * None of the URL_ define values are documented, so they were
157  * determined by trial and error.  MSDN mentions URL_ESCAPE_PERCENT
158  * but I can't find a value that does this under win2000.
159  * URL_DONT_ESCAPE_EXTRA_INFO appears to be the default which is what
160  * we assume here.  URL_ESCAPE_SEGMENT_ONLY is not implemented
161  * (value??).  A value of 0x2000 for dwFlags seems to escape
162  * '/'s too - this is neither documented on MSDN nor implemented here.
163  * For character values that are converted see URL_NeedEscape.
164  */
165 HRESULT WINAPI UrlEscapeA(
166         LPCSTR pszUrl,
167         LPSTR pszEscaped,
168         LPDWORD pcchEscaped,
169         DWORD dwFlags)
170 {
171     LPCSTR src;
172     DWORD needed = 0, ret;
173     BOOL stop_escapping = FALSE;
174     char next[3], *dst = pszEscaped;
175     char hex[] = "0123456789ABCDEF";
176     INT len;
177
178     TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped,
179           pcchEscaped, dwFlags);
180
181     if(dwFlags & ~URL_ESCAPE_SPACES_ONLY)
182         FIXME("Unimplemented flags: %08lx\n", dwFlags);
183
184     for(src = pszUrl; *src; src++) {
185         if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
186            (*src == '#' || *src == '?'))
187             stop_escapping = TRUE;
188
189         if(URL_NeedEscape(*src, dwFlags) && stop_escapping == FALSE) {
190             next[0] = '%';
191             next[1] = hex[(*src >> 4) & 0xf];
192             next[2] = hex[*src & 0xf];
193             len = 3;
194         } else {
195             next[0] = *src;
196             len = 1;
197         }
198
199         if(needed + len <= *pcchEscaped) {
200             memcpy(dst, next, len);
201             dst += len;
202         }
203         needed += len;
204     }
205
206     if(needed < *pcchEscaped) {
207         *dst = '\0';
208         ret = S_OK;
209     } else {
210         needed++; /* add one for the '\0' */
211         ret = E_POINTER;
212     }
213     *pcchEscaped = needed;
214     return ret;
215 }       
216
217 /*************************************************************************
218  *      UrlEscapeW      [SHLWAPI.@]
219  */
220 HRESULT WINAPI UrlEscapeW(
221         LPCWSTR pszUrl,
222         LPWSTR pszEscaped,
223         LPDWORD pcchEscaped,
224         DWORD dwFlags)
225 {
226     FIXME("(%s %p %p 0x%08lx): stub\n",debugstr_w(pszUrl),
227           pszEscaped, pcchEscaped, dwFlags);
228     return E_NOTIMPL;
229 }
230
231
232 /*************************************************************************
233  *      UrlUnescapeA    [SHLWAPI.@]
234  *
235  * Converts escape sequences back to ordinary characters.
236  * 
237  * If URL_ESCAPE_INPLACE is set in dwFlags then pszUnescaped and
238  * pcchUnescaped are ignored and the converted string is returned in
239  * pszUrl, otherwise the string is returned in pszUnescaped.
240  * pcchUnescaped should contain the size of pszUnescaped on calling
241  * and will contain the length the the returned string on return if
242  * the buffer is big enough else it will contain the buffer size
243  * required (including room for the '\0').  The function returns S_OK
244  * on success or E_POINTER if the buffer is not large enough.  If the
245  * URL_DONT_ESCAPE_EXTRA_INFO flag is set then the conversion stops at
246  * the first occurrence of either '?' or '#'.
247  *
248  */
249 HRESULT WINAPI UrlUnescapeA(
250         LPCSTR pszUrl,
251         LPSTR pszUnescaped,
252         LPDWORD pcchUnescaped,
253         DWORD dwFlags)
254 {
255     char *dst, next;
256     LPCSTR src;
257     HRESULT ret;
258     DWORD needed;
259     BOOL stop_unescapping = FALSE;
260
261     TRACE("(%s, %p, %p, %08lx): stub\n", debugstr_a(pszUrl), pszUnescaped,
262           pcchUnescaped, dwFlags);
263
264     if(dwFlags & URL_UNESCAPE_INPLACE)
265         dst = (char*)pszUrl;
266     else
267         dst = pszUnescaped;
268
269     for(src = pszUrl, needed = 0; *src; src++, needed++) {
270         if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
271            (*src == '#' || *src == '?')) {
272             stop_unescapping = TRUE;
273             next = *src;
274         } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
275                   && stop_unescapping == FALSE) {
276             INT ih;
277             char buf[3];
278             memcpy(buf, src + 1, 2);
279             buf[2] = '\0';
280             ih = strtol(buf, NULL, 16);
281             next = (CHAR) ih;
282             src += 2; /* Advance to end of escape */
283         } else
284             next = *src;
285
286         if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
287             *dst++ = next;
288     }
289
290     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
291         *dst = '\0';
292         ret = S_OK;
293     } else {
294         needed++; /* add one for the '\0' */
295         ret = E_POINTER;
296     }
297     if(!(dwFlags & URL_UNESCAPE_INPLACE))
298         *pcchUnescaped = needed;
299
300     return ret;
301 }
302
303 /*************************************************************************
304  *      UrlUnescapeW    [SHLWAPI.@]
305  */
306 HRESULT WINAPI UrlUnescapeW(
307         LPCWSTR pszUrl,
308         LPWSTR pszUnescaped,
309         LPDWORD pcchUnescaped,
310         DWORD dwFlags)
311 {
312     FIXME("(%s, %p, %p, %08lx): stub\n", debugstr_w(pszUrl), pszUnescaped,
313           pcchUnescaped, dwFlags);
314     return E_NOTIMPL;
315 }
316
317 /*************************************************************************
318  *      HashData        [SHLWAPI.@]
319  *
320  * Hash an input block into a variable sized digest.
321  */
322 BOOL WINAPI HashData(const unsigned char *lpSrc, INT nSrcLen,
323                      unsigned char *lpDest, INT nDestLen)
324 {
325   INT srcCount = nSrcLen - 1, destCount = nDestLen - 1;
326
327   if (IsBadReadPtr(lpSrc, nSrcLen) ||
328       IsBadWritePtr(lpDest, nDestLen))
329     return FALSE;
330
331   while (destCount >= 0)
332   {
333     lpDest[destCount] = (destCount & 0xff);
334     destCount--;
335   }
336
337   while (srcCount >= 0)
338   {
339     destCount = nDestLen - 1;
340     while (destCount >= 0)
341     {
342       lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]];
343       destCount--;
344     }
345     srcCount--;
346   }
347   return TRUE;
348 }
349
350 /*************************************************************************
351  *      UrlHashA        [SHLWAPI.@]
352  *
353  * Hash an ASCII URL.
354  */
355 HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, INT nDestLen)
356 {
357   if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
358     return E_INVALIDARG;
359
360   HashData(pszUrl, strlen(pszUrl), lpDest, nDestLen);
361   return NOERROR;
362 }
363
364 /*************************************************************************
365  *      UrlApplySchemeW [SHLWAPI.@]
366  */
367 HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
368 {
369     HRESULT err = NOERROR;
370     FIXME("(%s %p %p %08lx): stub !\n", debugstr_w(pszIn), pszOut, pcchOut, dwFlags);
371     strcpyW(pszOut, pszIn);
372     *pcchOut = (err != E_POINTER) ? strlenW(pszOut) : 0;
373     return err;
374 }
375