Don't allow comctl32 controls to access their infoPtr before it has
[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 "shlwapi.h"
12 #include "debugtools.h"
13
14 DEFAULT_DEBUG_CHANNEL(shell);
15
16 static BOOL URL_NeedEscape(CHAR ch, DWORD dwFlags)
17 {
18
19     if (isalnum(ch))
20         return FALSE;
21
22     if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
23         if(ch == ' ')
24             return TRUE;
25         else
26             return FALSE;
27     }
28
29     if (ch <= 31 || ch >= 127)
30         return TRUE; 
31
32     else {
33         switch (ch) {
34         case ' ':
35         case '<':
36         case '>':
37         case '\"':
38         case '{':
39         case '}':
40         case '|':
41         case '\\':
42         case '^':
43         case ']':
44         case '[':
45         case '`':
46         case '&':
47             return TRUE;
48
49         default:
50             return FALSE;
51         }
52     }
53 }
54
55 /*************************************************************************
56  *        UrlCanonicalizeA     [SHLWAPI]
57  */
58 HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, 
59         LPDWORD pcchCanonicalized, DWORD dwFlags)
60 {
61     HRESULT hr = S_OK;
62
63     LPSTR lpszUrlCpy;
64     INT nLen;
65
66     TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszCanonicalized,
67           pcchCanonicalized, dwFlags);
68
69     nLen = strlen(pszUrl);
70     lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nLen + 1);
71        
72     if (dwFlags & URL_DONT_SIMPLIFY)
73         memcpy(lpszUrlCpy, pszUrl, nLen + 1);
74     else {
75         FIXME("Simplify path\n");
76         memcpy(lpszUrlCpy, pszUrl, nLen + 1);
77     }
78
79     if(dwFlags & URL_UNESCAPE)
80         UrlUnescapeA(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
81
82     if(dwFlags & (URL_ESCAPE_UNSAFE | URL_ESCAPE_SPACES_ONLY)) {
83         DWORD EscapeFlags = dwFlags & (URL_ESCAPE_SPACES_ONLY
84                                        /* | URL_ESCAPE_PERCENT */);
85         hr = UrlEscapeA(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
86                         EscapeFlags);
87     } else { /* No escapping needed, just copy the string */
88         nLen = strlen(lpszUrlCpy);
89         if(nLen < *pcchCanonicalized)
90             memcpy(pszCanonicalized, lpszUrlCpy, nLen + 1);
91         else {
92             hr = E_POINTER;
93             nLen++;
94         }
95         *pcchCanonicalized = nLen;
96     }
97
98     HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
99   
100     return hr;
101 }
102
103 /*************************************************************************
104  *        UrlCanonicalizeW     [SHLWAPI]
105  */
106 HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, 
107                                 LPDWORD pcchCanonicalized, DWORD dwFlags)
108 {
109     FIXME("(%s %p %p 0x%08lx): stub\n",debugstr_w(pszUrl),
110           pszCanonicalized, pcchCanonicalized, dwFlags);
111     return E_NOTIMPL;
112 }
113
114 /*************************************************************************
115  *      UrlEscapeA      [SHLWAPI]
116  *
117  * Converts unsafe characters into their escape sequences.
118  *
119  * The converted string is returned in pszEscaped if the buffer size
120  * (which should be supplied in pcchEscaped) is large enough, in this
121  * case the function returns S_OK and pcchEscaped contains the length
122  * of the escaped string.  If the buffer is not large enough the
123  * function returns E_POINTER and pcchEscaped contains the required
124  * buffer size (including room for the '\0').
125  *
126  * By default the function stops converting at the first '?' or
127  * '#'. [MSDN says differently].  If URL_ESCAPE_SPACE_ONLY flag is set
128  * then only spaces are converted, but the conversion continues past a
129  * '?' or '#'.
130  *
131  * BUGS:
132  *
133  * None of the URL_ define values are documented, so they were
134  * determined by trial and error.  MSDN mentions URL_ESCAPE_PERCENT
135  * but I can't find a value that does this under win2000.
136  * URL_DONT_ESCAPE_EXTRA_INFO appears to be the default which is what
137  * we assume here.  URL_ESCAPE_SEGMENT_ONLY is not implemented
138  * (value??).  A value of 0x2000 for dwFlags seems to escape
139  * '/'s too - this is neither documented on MSDN nor implemented here.
140  * For character values that are converted see URL_NeedEscape.
141  */
142 HRESULT WINAPI UrlEscapeA(
143         LPCSTR pszUrl,
144         LPSTR pszEscaped,
145         LPDWORD pcchEscaped,
146         DWORD dwFlags)
147 {
148     LPCSTR src;
149     DWORD needed = 0, ret;
150     BOOL stop_escapping = FALSE;
151     char next[3], *dst = pszEscaped;
152     char hex[] = "0123456789ABCDEF";
153     INT len;
154
155     TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped,
156           pcchEscaped, dwFlags);
157
158     if(dwFlags & ~URL_ESCAPE_SPACES_ONLY)
159         FIXME("Unimplemented flags: %08lx\n", dwFlags);
160
161     for(src = pszUrl; *src; src++) {
162         if(!(dwFlags & URL_ESCAPE_SPACES_ONLY) &&
163            (*src == '#' || *src == '?'))
164             stop_escapping = TRUE;
165
166         if(URL_NeedEscape(*src, dwFlags) && stop_escapping == FALSE) {
167             next[0] = '%';
168             next[1] = hex[(*src >> 4) & 0xf];
169             next[2] = hex[*src & 0xf];
170             len = 3;
171         } else {
172             next[0] = *src;
173             len = 1;
174         }
175
176         if(needed + len <= *pcchEscaped) {
177             memcpy(dst, next, len);
178             dst += len;
179         }
180         needed += len;
181     }
182
183     if(needed < *pcchEscaped) {
184         *dst = '\0';
185         ret = S_OK;
186     } else {
187         needed++; /* add one for the '\0' */
188         ret = E_POINTER;
189     }
190     *pcchEscaped = needed;
191     return ret;
192 }       
193
194 /*************************************************************************
195  *      UrlEscapeW      [SHLWAPI]
196  */
197 HRESULT WINAPI UrlEscapeW(
198         LPCWSTR pszUrl,
199         LPWSTR pszEscaped,
200         LPDWORD pcchEscaped,
201         DWORD dwFlags)
202 {
203     FIXME("(%s %p %p 0x%08lx): stub\n",debugstr_w(pszUrl),
204           pszEscaped, pcchEscaped, dwFlags);
205     return E_NOTIMPL;
206 }       
207
208
209 /*************************************************************************
210  *      UrlUnescapeA    [SHLWAPI]
211  *
212  * Converts escape sequences back to ordinary characters.
213  * 
214  * If URL_ESCAPE_INPLACE is set in dwFlags then pszUnescaped and
215  * pcchUnescaped are ignored and the converted string is returned in
216  * pszUrl, otherwise the string is returned in pszUnescaped.
217  * pcchUnescaped should contain the size of pszUnescaped on calling
218  * and will contain the length the the returned string on return if
219  * the buffer is big enough else it will contain the buffer size
220  * required (including room for the '\0').  The function returns S_OK
221  * on success or E_POINTER if the buffer is not large enough.  If the
222  * URL_DONT_ESCAPE_EXTRA_INFO flag is set then the conversion stops at
223  * the first occurrence of either '?' or '#'.
224  *
225  */
226 HRESULT WINAPI UrlUnescapeA(
227         LPCSTR pszUrl,
228         LPSTR pszUnescaped,
229         LPDWORD pcchUnescaped,
230         DWORD dwFlags)
231 {
232     char *dst, next;
233     LPCSTR src;
234     HRESULT ret;
235     DWORD needed;
236     BOOL stop_unescapping = FALSE;
237
238     TRACE("(%s, %p, %p, %08lx): stub\n", debugstr_a(pszUrl), pszUnescaped,
239           pcchUnescaped, dwFlags);
240
241     if(dwFlags & URL_UNESCAPE_INPLACE)
242         dst = (char*)pszUrl;
243     else
244         dst = pszUnescaped;
245
246     for(src = pszUrl, needed = 0; *src; src++, needed++) {
247         if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
248            (*src == '#' || *src == '?')) {
249             stop_unescapping = TRUE;
250             next = *src;
251         } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
252                   && stop_unescapping == FALSE) {
253             INT ih;
254             char buf[3];
255             memcpy(buf, src + 1, 2);
256             buf[2] = '\0';
257             ih = strtol(buf, NULL, 16);
258             next = (CHAR) ih;
259             src += 2; /* Advance to end of escape */
260         } else
261             next = *src;
262
263         if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
264             *dst++ = next;
265     }
266
267     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
268         *dst = '\0';
269         ret = S_OK;
270     } else {
271         needed++; /* add one for the '\0' */
272         ret = E_POINTER;
273     }
274     if(!(dwFlags & URL_UNESCAPE_INPLACE))
275         *pcchUnescaped = needed;
276
277     return ret;
278 }
279
280 /*************************************************************************
281  *      UrlUnescapeW    [SHLWAPI]
282  */
283 HRESULT WINAPI UrlUnescapeW(
284         LPCWSTR pszUrl,
285         LPWSTR pszUnescaped,
286         LPDWORD pcchUnescaped,
287         DWORD dwFlags)
288 {
289     FIXME("(%s, %p, %p, %08lx): stub\n", debugstr_w(pszUrl), pszUnescaped,
290           pcchUnescaped, dwFlags);
291     return E_NOTIMPL;
292 }