ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

url.c
Go to the documentation of this file.
00001 /*
00002  * Url functions
00003  *
00004  * Copyright 2000 Huw D M Davies for CodeWeavers.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include "config.h"
00022 #include "wine/port.h"
00023 #include <stdarg.h>
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "winnls.h"
00029 #include "winerror.h"
00030 #include "wine/unicode.h"
00031 #include "wininet.h"
00032 #include "winreg.h"
00033 #include "winternl.h"
00034 #define NO_SHLWAPI_STREAM
00035 #include "shlwapi.h"
00036 #include "intshcut.h"
00037 #include "wine/debug.h"
00038 
00039 HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD);
00040 BOOL    WINAPI MLFreeLibrary(HMODULE);
00041 HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD);
00042 
00043 WINE_DEFAULT_DEBUG_CHANNEL(shell);
00044 
00045 /* The following schemes were identified in the native version of
00046  * SHLWAPI.DLL version 5.50
00047  */
00048 static const struct {
00049     URL_SCHEME  scheme_number;
00050     WCHAR scheme_name[12];
00051 } shlwapi_schemes[] = {
00052   {URL_SCHEME_FTP,        {'f','t','p',0}},
00053   {URL_SCHEME_HTTP,       {'h','t','t','p',0}},
00054   {URL_SCHEME_GOPHER,     {'g','o','p','h','e','r',0}},
00055   {URL_SCHEME_MAILTO,     {'m','a','i','l','t','o',0}},
00056   {URL_SCHEME_NEWS,       {'n','e','w','s',0}},
00057   {URL_SCHEME_NNTP,       {'n','n','t','p',0}},
00058   {URL_SCHEME_TELNET,     {'t','e','l','n','e','t',0}},
00059   {URL_SCHEME_WAIS,       {'w','a','i','s',0}},
00060   {URL_SCHEME_FILE,       {'f','i','l','e',0}},
00061   {URL_SCHEME_MK,         {'m','k',0}},
00062   {URL_SCHEME_HTTPS,      {'h','t','t','p','s',0}},
00063   {URL_SCHEME_SHELL,      {'s','h','e','l','l',0}},
00064   {URL_SCHEME_SNEWS,      {'s','n','e','w','s',0}},
00065   {URL_SCHEME_LOCAL,      {'l','o','c','a','l',0}},
00066   {URL_SCHEME_JAVASCRIPT, {'j','a','v','a','s','c','r','i','p','t',0}},
00067   {URL_SCHEME_VBSCRIPT,   {'v','b','s','c','r','i','p','t',0}},
00068   {URL_SCHEME_ABOUT,      {'a','b','o','u','t',0}},
00069   {URL_SCHEME_RES,        {'r','e','s',0}},
00070 };
00071 
00072 typedef struct {
00073     LPCWSTR pScheme;      /* [out] start of scheme                     */
00074     DWORD   szScheme;     /* [out] size of scheme (until colon)        */
00075     LPCWSTR pUserName;    /* [out] start of Username                   */
00076     DWORD   szUserName;   /* [out] size of Username (until ":" or "@") */
00077     LPCWSTR pPassword;    /* [out] start of Password                   */
00078     DWORD   szPassword;   /* [out] size of Password (until "@")        */
00079     LPCWSTR pHostName;    /* [out] start of Hostname                   */
00080     DWORD   szHostName;   /* [out] size of Hostname (until ":" or "/") */
00081     LPCWSTR pPort;        /* [out] start of Port                       */
00082     DWORD   szPort;       /* [out] size of Port (until "/" or eos)     */
00083     LPCWSTR pQuery;       /* [out] start of Query                      */
00084     DWORD   szQuery;      /* [out] size of Query (until eos)           */
00085 } WINE_PARSE_URL;
00086 
00087 typedef enum {
00088     SCHEME,
00089     HOST,
00090     PORT,
00091     USERPASS,
00092 } WINE_URL_SCAN_TYPE;
00093 
00094 static const CHAR hexDigits[] = "0123456789ABCDEF";
00095 
00096 static const WCHAR fileW[] = {'f','i','l','e','\0'};
00097 
00098 static const unsigned char HashDataLookup[256] = {
00099  0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B,
00100  0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07,
00101  0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94,
00102  0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46,
00103  0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0,
00104  0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6,
00105  0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F,
00106  0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
00107  0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF,
00108  0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40,
00109  0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9,
00110  0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4,
00111  0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB,
00112  0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB,
00113  0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D,
00114  0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
00115  0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD,
00116  0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17,
00117  0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
00118  0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
00119 
00120 static DWORD get_scheme_code(LPCWSTR scheme, DWORD scheme_len)
00121 {
00122     unsigned int i;
00123 
00124     for(i=0; i < sizeof(shlwapi_schemes)/sizeof(shlwapi_schemes[0]); i++) {
00125         if(scheme_len == strlenW(shlwapi_schemes[i].scheme_name)
00126            && !memcmp(scheme, shlwapi_schemes[i].scheme_name, scheme_len*sizeof(WCHAR)))
00127             return shlwapi_schemes[i].scheme_number;
00128     }
00129 
00130     return URL_SCHEME_UNKNOWN;
00131 }
00132 
00133 /*************************************************************************
00134  *      @   [SHLWAPI.1]
00135  *
00136  * Parse a Url into its constituent parts.
00137  *
00138  * PARAMS
00139  *  x [I] Url to parse
00140  *  y [O] Undocumented structure holding the parsed information
00141  *
00142  * RETURNS
00143  *  Success: S_OK. y contains the parsed Url details.
00144  *  Failure: An HRESULT error code.
00145  */
00146 HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y)
00147 {
00148     WCHAR scheme[INTERNET_MAX_SCHEME_LENGTH];
00149     const char *ptr = x;
00150     int len;
00151 
00152     TRACE("%s %p\n", debugstr_a(x), y);
00153 
00154     if(y->cbSize != sizeof(*y))
00155         return E_INVALIDARG;
00156 
00157     while(*ptr && (isalnum(*ptr) || *ptr == '-'))
00158         ptr++;
00159 
00160     if (*ptr != ':' || ptr <= x+1) {
00161         y->pszProtocol = NULL;
00162         return URL_E_INVALID_SYNTAX;
00163     }
00164 
00165     y->pszProtocol = x;
00166     y->cchProtocol = ptr-x;
00167     y->pszSuffix = ptr+1;
00168     y->cchSuffix = strlen(y->pszSuffix);
00169 
00170     len = MultiByteToWideChar(CP_ACP, 0, x, ptr-x,
00171             scheme, sizeof(scheme)/sizeof(WCHAR));
00172     y->nScheme = get_scheme_code(scheme, len);
00173 
00174     return S_OK;
00175 }
00176 
00177 /*************************************************************************
00178  *      @   [SHLWAPI.2]
00179  *
00180  * Unicode version of ParseURLA.
00181  */
00182 HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y)
00183 {
00184     const WCHAR *ptr = x;
00185 
00186     TRACE("%s %p\n", debugstr_w(x), y);
00187 
00188     if(y->cbSize != sizeof(*y))
00189         return E_INVALIDARG;
00190 
00191     while(*ptr && (isalnumW(*ptr) || *ptr == '-'))
00192         ptr++;
00193 
00194     if (*ptr != ':' || ptr <= x+1) {
00195         y->pszProtocol = NULL;
00196         return URL_E_INVALID_SYNTAX;
00197     }
00198 
00199     y->pszProtocol = x;
00200     y->cchProtocol = ptr-x;
00201     y->pszSuffix = ptr+1;
00202     y->cchSuffix = strlenW(y->pszSuffix);
00203     y->nScheme = get_scheme_code(x, ptr-x);
00204 
00205     return S_OK;
00206 }
00207 
00208 /*************************************************************************
00209  *        UrlCanonicalizeA     [SHLWAPI.@]
00210  *
00211  * Canonicalize a Url.
00212  *
00213  * PARAMS
00214  *  pszUrl            [I]   Url to cCanonicalize
00215  *  pszCanonicalized  [O]   Destination for converted Url.
00216  *  pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized
00217  *  dwFlags           [I]   Flags controlling the conversion.
00218  *
00219  * RETURNS
00220  *  Success: S_OK. The pszCanonicalized contains the converted Url.
00221  *  Failure: E_POINTER, if *pcchCanonicalized is too small.
00222  *
00223  * MSDN incorrectly describes the flags for this function. They should be:
00224  *|    URL_DONT_ESCAPE_EXTRA_INFO    0x02000000
00225  *|    URL_ESCAPE_SPACES_ONLY        0x04000000
00226  *|    URL_ESCAPE_PERCENT            0x00001000
00227  *|    URL_ESCAPE_UNSAFE             0x10000000
00228  *|    URL_UNESCAPE                  0x10000000
00229  *|    URL_DONT_SIMPLIFY             0x08000000
00230  *|    URL_ESCAPE_SEGMENT_ONLY       0x00002000
00231  */
00232 HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
00233     LPDWORD pcchCanonicalized, DWORD dwFlags)
00234 {
00235     LPWSTR url, canonical;
00236     HRESULT ret;
00237     DWORD   len;
00238 
00239     TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_a(pszUrl), pszCanonicalized,
00240         pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1);
00241 
00242     if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized)
00243     return E_INVALIDARG;
00244 
00245     len = strlen(pszUrl)+1;
00246     url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
00247     canonical = HeapAlloc(GetProcessHeap(), 0, *pcchCanonicalized*sizeof(WCHAR));
00248     if(!url || !canonical) {
00249         HeapFree(GetProcessHeap(), 0, url);
00250         HeapFree(GetProcessHeap(), 0, canonical);
00251         return E_OUTOFMEMORY;
00252     }
00253 
00254     MultiByteToWideChar(0, 0, pszUrl, -1, url, len);
00255 
00256     ret = UrlCanonicalizeW(url, canonical, pcchCanonicalized, dwFlags);
00257     if(ret == S_OK)
00258         WideCharToMultiByte(0, 0, canonical, -1, pszCanonicalized,
00259                 *pcchCanonicalized+1, 0, 0);
00260 
00261     HeapFree(GetProcessHeap(), 0, canonical);
00262     return ret;
00263 }
00264 
00265 /*************************************************************************
00266  *        UrlCanonicalizeW     [SHLWAPI.@]
00267  *
00268  * See UrlCanonicalizeA.
00269  */
00270 HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
00271                 LPDWORD pcchCanonicalized, DWORD dwFlags)
00272 {
00273     HRESULT hr = S_OK;
00274     DWORD EscapeFlags;
00275     LPCWSTR wk1, root;
00276     LPWSTR lpszUrlCpy, wk2, mp, mp2;
00277     INT state;
00278     DWORD nByteLen, nLen, nWkLen;
00279     WCHAR slash = '\0';
00280 
00281     static const WCHAR wszFile[] = {'f','i','l','e',':'};
00282     static const WCHAR wszRes[] = {'r','e','s',':'};
00283     static const WCHAR wszHttp[] = {'h','t','t','p',':'};
00284     static const WCHAR wszLocalhost[] = {'l','o','c','a','l','h','o','s','t'};
00285     static const WCHAR wszFilePrefix[] = {'f','i','l','e',':','/','/','/'};
00286 
00287     TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_w(pszUrl), pszCanonicalized,
00288         pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1);
00289 
00290     if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized)
00291     return E_INVALIDARG;
00292 
00293     if(!*pszUrl) {
00294         *pszCanonicalized = 0;
00295         return S_OK;
00296     }
00297 
00298     nByteLen = (strlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */
00299     /* Allocate memory for simplified URL (before escaping) */
00300     lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0,
00301             nByteLen+sizeof(wszFilePrefix)+sizeof(WCHAR));
00302 
00303     if ((nByteLen >= sizeof(wszHttp) &&
00304          !memcmp(wszHttp, pszUrl, sizeof(wszHttp))) ||
00305         (nByteLen >= sizeof(wszFile) &&
00306          !memcmp(wszFile, pszUrl, sizeof(wszFile))))
00307         slash = '/';
00308 
00309     if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile)
00310             && !memcmp(wszFile, pszUrl, sizeof(wszFile)))
00311         slash = '\\';
00312 
00313     if(nByteLen >= sizeof(wszRes) && !memcmp(wszRes, pszUrl, sizeof(wszRes))) {
00314         dwFlags &= ~URL_FILE_USE_PATHURL;
00315         slash = '\0';
00316     }
00317 
00318     /*
00319      * state =
00320      *         0   initial  1,3
00321      *         1   have 2[+] alnum  2,3
00322      *         2   have scheme (found :)  4,6,3
00323      *         3   failed (no location)
00324      *         4   have //  5,3
00325      *         5   have 1[+] alnum  6,3
00326      *         6   have location (found /) save root location
00327      */
00328 
00329     wk1 = pszUrl;
00330     wk2 = lpszUrlCpy;
00331     state = 0;
00332 
00333     if(pszUrl[1] == ':') { /* Assume path */
00334         memcpy(wk2, wszFilePrefix, sizeof(wszFilePrefix));
00335         wk2 += sizeof(wszFilePrefix)/sizeof(WCHAR);
00336         if (dwFlags & URL_FILE_USE_PATHURL)
00337         {
00338             slash = '\\';
00339             --wk2;
00340         }
00341         else
00342             dwFlags |= URL_ESCAPE_UNSAFE;
00343         state = 5;
00344     }
00345 
00346     while (*wk1) {
00347         switch (state) {
00348         case 0:
00349             if (!isalnumW(*wk1)) {state = 3; break;}
00350             *wk2++ = *wk1++;
00351             if (!isalnumW(*wk1)) {state = 3; break;}
00352             *wk2++ = *wk1++;
00353             state = 1;
00354             break;
00355         case 1:
00356             *wk2++ = *wk1;
00357             if (*wk1++ == ':') state = 2;
00358             break;
00359         case 2:
00360             *wk2++ = *wk1++;
00361             if (*wk1 != '/') {state = 6; break;}
00362             *wk2++ = *wk1++;
00363             if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszLocalhost)
00364                         && !strncmpW(wszFile, pszUrl, sizeof(wszFile)/sizeof(WCHAR))
00365                         && !memcmp(wszLocalhost, wk1, sizeof(wszLocalhost))){
00366                 wk1 += sizeof(wszLocalhost)/sizeof(WCHAR);
00367                 while(*wk1 == '\\' && (dwFlags & URL_FILE_USE_PATHURL))
00368                     wk1++;
00369             }
00370             if(*wk1 == '/' && (dwFlags & URL_FILE_USE_PATHURL))
00371                 wk1++;
00372             state = 4;
00373             break;
00374         case 3:
00375             nWkLen = strlenW(wk1);
00376             memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
00377             mp = wk2;
00378             wk1 += nWkLen;
00379             wk2 += nWkLen;
00380 
00381             if(slash) {
00382                 while(mp < wk2) {
00383                     if(*mp == '/' || *mp == '\\')
00384                         *mp = slash;
00385                     mp++;
00386                 }
00387             }
00388             break;
00389         case 4:
00390             if (!isalnumW(*wk1) && (*wk1 != '-') && (*wk1 != '.') && (*wk1 != ':'))
00391                 {state = 3; break;}
00392             while(isalnumW(*wk1) || (*wk1 == '-') || (*wk1 == '.') || (*wk1 == ':'))
00393                 *wk2++ = *wk1++;
00394             state = 5;
00395             if (!*wk1) {
00396                 if(slash)
00397                     *wk2++ = slash;
00398                 else
00399                     *wk2++ = '/';
00400             }
00401             break;
00402         case 5:
00403             if (*wk1 != '/' && *wk1 != '\\') {state = 3; break;}
00404             while(*wk1 == '/' || *wk1 == '\\') {
00405                 if(slash)
00406                     *wk2++ = slash;
00407                 else
00408                     *wk2++ = *wk1;
00409                 wk1++;
00410             }
00411             state = 6;
00412             break;
00413         case 6:
00414             if(dwFlags & URL_DONT_SIMPLIFY) {
00415                 state = 3;
00416                 break;
00417             }
00418  
00419             /* Now at root location, cannot back up any more. */
00420             /* "root" will point at the '/' */
00421 
00422             root = wk2-1;
00423             while (*wk1) {
00424                 mp = strchrW(wk1, '/');
00425                 mp2 = strchrW(wk1, '\\');
00426                 if(mp2 && (!mp || mp2 < mp))
00427                     mp = mp2;
00428                 if (!mp) {
00429                     nWkLen = strlenW(wk1);
00430                     memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
00431                     wk1 += nWkLen;
00432                     wk2 += nWkLen;
00433                     continue;
00434                 }
00435                 nLen = mp - wk1;
00436                 if(nLen) {
00437                     memcpy(wk2, wk1, nLen * sizeof(WCHAR));
00438                     wk2 += nLen;
00439                     wk1 += nLen;
00440                 }
00441                 if(slash)
00442                     *wk2++ = slash;
00443                 else
00444                     *wk2++ = *wk1;
00445                 wk1++;
00446 
00447                 while (*wk1 == '.') {
00448                     TRACE("found '/.'\n");
00449                     if (wk1[1] == '/' || wk1[1] == '\\') {
00450                         /* case of /./ -> skip the ./ */
00451                         wk1 += 2;
00452                     }
00453                     else if (wk1[1] == '.' && (wk1[2] == '/'
00454                             || wk1[2] == '\\' || wk1[2] == '?'
00455                             || wk1[2] == '#' || !wk1[2])) {
00456                         /* case /../ -> need to backup wk2 */
00457                         TRACE("found '/../'\n");
00458                         *(wk2-1) = '\0';  /* set end of string */
00459                         mp = strrchrW(root, '/');
00460                         mp2 = strrchrW(root, '\\');
00461                         if(mp2 && (!mp || mp2 < mp))
00462                             mp = mp2;
00463                         if (mp && (mp >= root)) {
00464                             /* found valid backup point */
00465                             wk2 = mp + 1;
00466                             if(wk1[2] != '/' && wk1[2] != '\\')
00467                                 wk1 += 2;
00468                             else
00469                                 wk1 += 3;
00470                         }
00471                         else {
00472                             /* did not find point, restore '/' */
00473                             *(wk2-1) = slash;
00474                             break;
00475                         }
00476                     }
00477                     else
00478                         break;
00479                 }
00480             }
00481             *wk2 = '\0';
00482             break;
00483         default:
00484             FIXME("how did we get here - state=%d\n", state);
00485             HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
00486             return E_INVALIDARG;
00487         }
00488         *wk2 = '\0';
00489     TRACE("Simplified, orig <%s>, simple <%s>\n",
00490           debugstr_w(pszUrl), debugstr_w(lpszUrlCpy));
00491     }
00492     nLen = lstrlenW(lpszUrlCpy);
00493     while ((nLen > 0) && ((lpszUrlCpy[nLen-1] <= ' ')))
00494         lpszUrlCpy[--nLen]=0;
00495 
00496     if((dwFlags & URL_UNESCAPE) ||
00497        ((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile)
00498                 && !memcmp(wszFile, pszUrl, sizeof(wszFile))))
00499         UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE);
00500 
00501     if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE |
00502                                  URL_ESCAPE_SPACES_ONLY |
00503                                  URL_ESCAPE_PERCENT |
00504                                  URL_DONT_ESCAPE_EXTRA_INFO |
00505                  URL_ESCAPE_SEGMENT_ONLY ))) {
00506     EscapeFlags &= ~URL_ESCAPE_UNSAFE;
00507     hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
00508             EscapeFlags);
00509     } else { /* No escaping needed, just copy the string */
00510         nLen = lstrlenW(lpszUrlCpy);
00511     if(nLen < *pcchCanonicalized)
00512         memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR));
00513     else {
00514         hr = E_POINTER;
00515         nLen++;
00516     }
00517     *pcchCanonicalized = nLen;
00518     }
00519 
00520     HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
00521 
00522     if (hr == S_OK)
00523     TRACE("result %s\n", debugstr_w(pszCanonicalized));
00524 
00525     return hr;
00526 }
00527 
00528 /*************************************************************************
00529  *        UrlCombineA     [SHLWAPI.@]
00530  *
00531  * Combine two Urls.
00532  *
00533  * PARAMS
00534  *  pszBase      [I] Base Url
00535  *  pszRelative  [I] Url to combine with pszBase
00536  *  pszCombined  [O] Destination for combined Url
00537  *  pcchCombined [O] Destination for length of pszCombined
00538  *  dwFlags      [I] URL_ flags from "shlwapi.h"
00539  *
00540  * RETURNS
00541  *  Success: S_OK. pszCombined contains the combined Url, pcchCombined
00542  *           contains its length.
00543  *  Failure: An HRESULT error code indicating the error.
00544  */
00545 HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
00546                LPSTR pszCombined, LPDWORD pcchCombined,
00547                DWORD dwFlags)
00548 {
00549     LPWSTR base, relative, combined;
00550     DWORD ret, len, len2;
00551 
00552     TRACE("(base %s, Relative %s, Combine size %d, flags %08x) using W version\n",
00553       debugstr_a(pszBase),debugstr_a(pszRelative),
00554       pcchCombined?*pcchCombined:0,dwFlags);
00555 
00556     if(!pszBase || !pszRelative || !pcchCombined)
00557     return E_INVALIDARG;
00558 
00559     base = HeapAlloc(GetProcessHeap(), 0,
00560                   (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
00561     relative = base + INTERNET_MAX_URL_LENGTH;
00562     combined = relative + INTERNET_MAX_URL_LENGTH;
00563 
00564     MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
00565     MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
00566     len = *pcchCombined;
00567 
00568     ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags);
00569     if (ret != S_OK) {
00570     *pcchCombined = len;
00571     HeapFree(GetProcessHeap(), 0, base);
00572     return ret;
00573     }
00574 
00575     len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0);
00576     if (len2 > *pcchCombined) {
00577     *pcchCombined = len2;
00578     HeapFree(GetProcessHeap(), 0, base);
00579     return E_POINTER;
00580     }
00581     WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1,
00582             0, 0);
00583     *pcchCombined = len2;
00584     HeapFree(GetProcessHeap(), 0, base);
00585     return S_OK;
00586 }
00587 
00588 /*************************************************************************
00589  *        UrlCombineW     [SHLWAPI.@]
00590  *
00591  * See UrlCombineA.
00592  */
00593 HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
00594                LPWSTR pszCombined, LPDWORD pcchCombined,
00595                DWORD dwFlags)
00596 {
00597     PARSEDURLW base, relative;
00598     DWORD myflags, sizeloc = 0;
00599     DWORD len, res1, res2, process_case = 0;
00600     LPWSTR work, preliminary, mbase, mrelative;
00601     static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'};
00602     HRESULT ret;
00603 
00604     TRACE("(base %s, Relative %s, Combine size %d, flags %08x)\n",
00605       debugstr_w(pszBase),debugstr_w(pszRelative),
00606       pcchCombined?*pcchCombined:0,dwFlags);
00607 
00608     if(!pszBase || !pszRelative || !pcchCombined)
00609     return E_INVALIDARG;
00610 
00611     base.cbSize = sizeof(base);
00612     relative.cbSize = sizeof(relative);
00613 
00614     /* Get space for duplicates of the input and the output */
00615     preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) *
00616                 sizeof(WCHAR));
00617     mbase = preliminary + INTERNET_MAX_URL_LENGTH;
00618     mrelative = mbase + INTERNET_MAX_URL_LENGTH;
00619     *preliminary = '\0';
00620 
00621     /* Canonicalize the base input prior to looking for the scheme */
00622     myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
00623     len = INTERNET_MAX_URL_LENGTH;
00624     ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags);
00625 
00626     /* Canonicalize the relative input prior to looking for the scheme */
00627     len = INTERNET_MAX_URL_LENGTH;
00628     ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags);
00629 
00630     /* See if the base has a scheme */
00631     res1 = ParseURLW(mbase, &base);
00632     if (res1) {
00633     /* if pszBase has no scheme, then return pszRelative */
00634     TRACE("no scheme detected in Base\n");
00635     process_case = 1;
00636     }
00637     else do {
00638         BOOL manual_search = FALSE;
00639 
00640         /* mk is a special case */
00641         if(base.nScheme == URL_SCHEME_MK) {
00642             static const WCHAR wsz[] = {':',':',0};
00643 
00644             WCHAR *ptr = strstrW(base.pszSuffix, wsz);
00645             if(ptr) {
00646                 int delta;
00647 
00648                 ptr += 2;
00649                 delta = ptr-base.pszSuffix;
00650                 base.cchProtocol += delta;
00651                 base.pszSuffix += delta;
00652                 base.cchSuffix -= delta;
00653             }
00654         }else {
00655             /* get size of location field (if it exists) */
00656             work = (LPWSTR)base.pszSuffix;
00657             sizeloc = 0;
00658             if (*work++ == '/') {
00659                 if (*work++ == '/') {
00660                     /* At this point have start of location and
00661                      * it ends at next '/' or end of string.
00662                      */
00663                     while(*work && (*work != '/')) work++;
00664                     sizeloc = (DWORD)(work - base.pszSuffix);
00665                 }
00666             }
00667         }
00668 
00669         /* If there is a '#' and the characters immediately preceding it are
00670          * ".htm[l]", then begin looking for the last leaf starting from
00671          * the '#'. Otherwise the '#' is not meaningful and just start
00672          * looking from the end. */
00673         if ((work = strchrW(base.pszSuffix + sizeloc, '#'))) {
00674             const WCHAR htmlW[] = {'.','h','t','m','l',0};
00675             const int len_htmlW = 5;
00676             const WCHAR htmW[] = {'.','h','t','m',0};
00677             const int len_htmW = 4;
00678 
00679             if (work - base.pszSuffix > len_htmW * sizeof(WCHAR)) {
00680                 work -= len_htmW;
00681                 if (strncmpiW(work, htmW, len_htmW) == 0)
00682                     manual_search = TRUE;
00683                 work += len_htmW;
00684             }
00685 
00686             if (!manual_search &&
00687                     work - base.pszSuffix > len_htmlW * sizeof(WCHAR)) {
00688                 work -= len_htmlW;
00689                 if (strncmpiW(work, htmlW, len_htmlW) == 0)
00690                     manual_search = TRUE;
00691                 work += len_htmlW;
00692             }
00693         }
00694 
00695         if (manual_search) {
00696             /* search backwards starting from the current position */
00697             while (*work != '/' && work > base.pszSuffix + sizeloc)
00698                 --work;
00699             if (work > base.pszSuffix + sizeloc)
00700                 base.cchSuffix = work - base.pszSuffix + 1;
00701         }else {
00702             /* search backwards starting from the end of the string */
00703             work = strrchrW((base.pszSuffix+sizeloc), '/');
00704             if (work) {
00705                 len = (DWORD)(work - base.pszSuffix + 1);
00706                 base.cchSuffix = len;
00707             }
00708         }
00709 
00710     /*
00711      * At this point:
00712      *    .pszSuffix   points to location (starting with '//')
00713      *    .cchSuffix   length of location (above) and rest less the last
00714      *                 leaf (if any)
00715      *    sizeloc   length of location (above) up to but not including
00716      *              the last '/'
00717      */
00718 
00719     res2 = ParseURLW(mrelative, &relative);
00720     if (res2) {
00721         /* no scheme in pszRelative */
00722         TRACE("no scheme detected in Relative\n");
00723         relative.pszSuffix = mrelative;  /* case 3,4,5 depends on this */
00724         relative.cchSuffix = strlenW(mrelative);
00725             if (*pszRelative  == ':') {
00726         /* case that is either left alone or uses pszBase */
00727         if (dwFlags & URL_PLUGGABLE_PROTOCOL) {
00728             process_case = 5;
00729             break;
00730         }
00731         process_case = 1;
00732         break;
00733         }
00734             if (isalnum(*mrelative) && (*(mrelative + 1) == ':')) {
00735         /* case that becomes "file:///" */
00736         strcpyW(preliminary, myfilestr);
00737         process_case = 1;
00738         break;
00739         }
00740             if ((*mrelative == '/') && (*(mrelative+1) == '/')) {
00741         /* pszRelative has location and rest */
00742         process_case = 3;
00743         break;
00744         }
00745             if (*mrelative == '/') {
00746         /* case where pszRelative is root to location */
00747         process_case = 4;
00748         break;
00749         }
00750             process_case = (*base.pszSuffix == '/' || base.nScheme == URL_SCHEME_MK) ? 5 : 3;
00751         break;
00752     }
00753 
00754     /* handle cases where pszRelative has scheme */
00755     if ((base.cchProtocol == relative.cchProtocol) &&
00756         (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) {
00757 
00758         /* since the schemes are the same */
00759             if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) {
00760         /* case where pszRelative replaces location and following */
00761         process_case = 3;
00762         break;
00763         }
00764             if (*relative.pszSuffix == '/') {
00765         /* case where pszRelative is root to location */
00766         process_case = 4;
00767         break;
00768         }
00769             /* replace either just location if base's location starts with a
00770              * slash or otherwise everything */
00771             process_case = (*base.pszSuffix == '/') ? 5 : 1;
00772         break;
00773     }
00774         if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) {
00775         /* case where pszRelative replaces scheme, location,
00776          * and following and handles PLUGGABLE
00777          */
00778         process_case = 2;
00779         break;
00780     }
00781     process_case = 1;
00782     break;
00783     } while(FALSE); /* a little trick to allow easy exit from nested if's */
00784 
00785     ret = S_OK;
00786     switch (process_case) {
00787 
00788     case 1:  /*
00789           * Return pszRelative appended to what ever is in pszCombined,
00790           * (which may the string "file:///"
00791           */
00792     strcatW(preliminary, mrelative);
00793     break;
00794 
00795     case 2:  /* case where pszRelative replaces scheme, and location */
00796     strcpyW(preliminary, mrelative);
00797     break;
00798 
00799     case 3:  /*
00800           * Return the pszBase scheme with pszRelative. Basically
00801           * keeps the scheme and replaces the domain and following.
00802           */
00803         memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR));
00804     work = preliminary + base.cchProtocol + 1;
00805     strcpyW(work, relative.pszSuffix);
00806     break;
00807 
00808     case 4:  /*
00809           * Return the pszBase scheme and location but everything
00810           * after the location is pszRelative. (Replace document
00811           * from root on.)
00812           */
00813         memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR));
00814     work = preliminary + base.cchProtocol + 1 + sizeloc;
00815     if (dwFlags & URL_PLUGGABLE_PROTOCOL)
00816             *(work++) = '/';
00817     strcpyW(work, relative.pszSuffix);
00818     break;
00819 
00820     case 5:  /*
00821           * Return the pszBase without its document (if any) and
00822           * append pszRelative after its scheme.
00823           */
00824         memcpy(preliminary, base.pszProtocol,
00825                (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR));
00826     work = preliminary + base.cchProtocol+1+base.cchSuffix - 1;
00827         if (*work++ != '/')
00828             *(work++) = '/';
00829     strcpyW(work, relative.pszSuffix);
00830     break;
00831 
00832     default:
00833     FIXME("How did we get here????? process_case=%d\n", process_case);
00834     ret = E_INVALIDARG;
00835     }
00836 
00837     if (ret == S_OK) {
00838     /* Reuse mrelative as temp storage as its already allocated and not needed anymore */
00839         if(*pcchCombined == 0)
00840             *pcchCombined = 1;
00841     ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, (dwFlags & ~URL_FILE_USE_PATHURL));
00842     if(SUCCEEDED(ret) && pszCombined) {
00843         lstrcpyW(pszCombined, mrelative);
00844     }
00845     TRACE("return-%d len=%d, %s\n",
00846           process_case, *pcchCombined, debugstr_w(pszCombined));
00847     }
00848     HeapFree(GetProcessHeap(), 0, preliminary);
00849     return ret;
00850 }
00851 
00852 /*************************************************************************
00853  *      UrlEscapeA  [SHLWAPI.@]
00854  */
00855 
00856 HRESULT WINAPI UrlEscapeA(
00857     LPCSTR pszUrl,
00858     LPSTR pszEscaped,
00859     LPDWORD pcchEscaped,
00860     DWORD dwFlags)
00861 {
00862     WCHAR bufW[INTERNET_MAX_URL_LENGTH];
00863     WCHAR *escapedW = bufW;
00864     UNICODE_STRING urlW;
00865     HRESULT ret;
00866     DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
00867 
00868     if (!pszEscaped || !pcchEscaped || !*pcchEscaped)
00869         return E_INVALIDARG;
00870 
00871     if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
00872         return E_INVALIDARG;
00873     if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) {
00874         escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
00875         ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags);
00876     }
00877     if(ret == S_OK) {
00878         RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
00879         if(*pcchEscaped > lenA) {
00880             RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
00881             pszEscaped[lenA] = 0;
00882             *pcchEscaped = lenA;
00883         } else {
00884             *pcchEscaped = lenA + 1;
00885             ret = E_POINTER;
00886         }
00887     }
00888     if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW);
00889     RtlFreeUnicodeString(&urlW);
00890     return ret;
00891 }
00892 
00893 #define WINE_URL_BASH_AS_SLASH    0x01
00894 #define WINE_URL_COLLAPSE_SLASHES 0x02
00895 #define WINE_URL_ESCAPE_SLASH     0x04
00896 #define WINE_URL_ESCAPE_HASH      0x08
00897 #define WINE_URL_ESCAPE_QUESTION  0x10
00898 #define WINE_URL_STOP_ON_HASH     0x20
00899 #define WINE_URL_STOP_ON_QUESTION 0x40
00900 
00901 static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags)
00902 {
00903 
00904     if (isalnumW(ch))
00905         return FALSE;
00906 
00907     if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
00908         if(ch == ' ')
00909         return TRUE;
00910     else
00911         return FALSE;
00912     }
00913 
00914     if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%'))
00915     return TRUE;
00916 
00917     if (ch <= 31 || ch >= 127)
00918     return TRUE;
00919 
00920     else {
00921         switch (ch) {
00922     case ' ':
00923     case '<':
00924     case '>':
00925     case '\"':
00926     case '{':
00927     case '}':
00928     case '|':
00929     case '\\':
00930     case '^':
00931     case ']':
00932     case '[':
00933     case '`':
00934     case '&':
00935         return TRUE;
00936 
00937     case '/':
00938             if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE;
00939             return FALSE;
00940 
00941     case '?':
00942         if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE;
00943             return FALSE;
00944 
00945         case '#':
00946             if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE;
00947             return FALSE;
00948 
00949     default:
00950         return FALSE;
00951     }
00952     }
00953 }
00954 
00955 
00956 /*************************************************************************
00957  *      UrlEscapeW  [SHLWAPI.@]
00958  *
00959  * Converts unsafe characters in a Url into escape sequences.
00960  *
00961  * PARAMS
00962  *  pszUrl      [I]   Url to modify
00963  *  pszEscaped  [O]   Destination for modified Url
00964  *  pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped
00965  *  dwFlags     [I]   URL_ flags from "shlwapi.h"
00966  *
00967  * RETURNS
00968  *  Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped
00969  *           contains its length.
00970  *  Failure: E_POINTER, if pszEscaped is not large enough. In this case
00971  *           pcchEscaped is set to the required length.
00972  *
00973  * Converts unsafe characters into their escape sequences.
00974  *
00975  * NOTES
00976  * - By default this function stops converting at the first '?' or
00977  *  '#' character.
00978  * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
00979  *   converted, but the conversion continues past a '?' or '#'.
00980  * - Note that this function did not work well (or at all) in shlwapi version 4.
00981  *
00982  * BUGS
00983  *  Only the following flags are implemented:
00984  *|     URL_ESCAPE_SPACES_ONLY
00985  *|     URL_DONT_ESCAPE_EXTRA_INFO
00986  *|     URL_ESCAPE_SEGMENT_ONLY
00987  *|     URL_ESCAPE_PERCENT
00988  */
00989 HRESULT WINAPI UrlEscapeW(
00990     LPCWSTR pszUrl,
00991     LPWSTR pszEscaped,
00992     LPDWORD pcchEscaped,
00993     DWORD dwFlags)
00994 {
00995     LPCWSTR src;
00996     DWORD needed = 0, ret;
00997     BOOL stop_escaping = FALSE;
00998     WCHAR next[5], *dst = pszEscaped;
00999     INT len;
01000     PARSEDURLW parsed_url;
01001     DWORD int_flags;
01002     DWORD slashes = 0;
01003     static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0};
01004 
01005     TRACE("(%s %p %p 0x%08x)\n", debugstr_w(pszUrl), pszEscaped,
01006       pcchEscaped, dwFlags);
01007 
01008     if(!pszUrl || !pcchEscaped)
01009         return E_INVALIDARG;
01010 
01011     if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
01012            URL_ESCAPE_SEGMENT_ONLY |
01013            URL_DONT_ESCAPE_EXTRA_INFO |
01014            URL_ESCAPE_PERCENT))
01015         FIXME("Unimplemented flags: %08x\n", dwFlags);
01016 
01017     /* fix up flags */
01018     if (dwFlags & URL_ESCAPE_SPACES_ONLY)
01019     /* if SPACES_ONLY specified, reset the other controls */
01020     dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO |
01021              URL_ESCAPE_PERCENT |
01022              URL_ESCAPE_SEGMENT_ONLY);
01023 
01024     else
01025     /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
01026     dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
01027 
01028 
01029     int_flags = 0;
01030     if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
01031         int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
01032     } else {
01033         parsed_url.cbSize = sizeof(parsed_url);
01034         if(ParseURLW(pszUrl, &parsed_url) != S_OK)
01035             parsed_url.nScheme = URL_SCHEME_INVALID;
01036 
01037         TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
01038 
01039         if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
01040             int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
01041 
01042         switch(parsed_url.nScheme) {
01043         case URL_SCHEME_FILE:
01044             int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
01045             int_flags &= ~WINE_URL_STOP_ON_HASH;
01046             break;
01047 
01048         case URL_SCHEME_HTTP:
01049         case URL_SCHEME_HTTPS:
01050             int_flags |= WINE_URL_BASH_AS_SLASH;
01051             if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
01052                 int_flags |= WINE_URL_ESCAPE_SLASH;
01053             break;
01054 
01055         case URL_SCHEME_MAILTO:
01056             int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH;
01057             int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH);
01058             break;
01059 
01060         case URL_SCHEME_INVALID:
01061             break;
01062 
01063         case URL_SCHEME_FTP:
01064         default:
01065             if(parsed_url.pszSuffix[0] != '/')
01066                 int_flags |= WINE_URL_ESCAPE_SLASH;
01067             break;
01068         }
01069     }
01070 
01071     for(src = pszUrl; *src; ) {
01072         WCHAR cur = *src;
01073         len = 0;
01074         
01075         if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) {
01076             int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1;
01077             while(cur == '/' || cur == '\\') {
01078                 slashes++;
01079                 cur = *++src;
01080             }
01081             if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */
01082                 if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\')
01083                 src += localhost_len + 1;
01084                 slashes = 3;
01085             }
01086 
01087             switch(slashes) {
01088             case 1:
01089             case 3:
01090                 next[0] = next[1] = next[2] = '/';
01091                 len = 3;
01092                 break;
01093             case 0:
01094                 len = 0;
01095                 break;
01096             default:
01097                 next[0] = next[1] = '/';
01098                 len = 2;
01099                 break;
01100             }
01101         }
01102         if(len == 0) {
01103 
01104             if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
01105                 stop_escaping = TRUE;
01106 
01107             if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
01108                 stop_escaping = TRUE;
01109 
01110             if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
01111 
01112             if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) {
01113                 next[0] = '%';
01114                 next[1] = hexDigits[(cur >> 4) & 0xf];
01115                 next[2] = hexDigits[cur & 0xf];
01116                 len = 3;
01117             } else {
01118                 next[0] = cur;
01119                 len = 1;
01120             }
01121             src++;
01122         }
01123 
01124     if(needed + len <= *pcchEscaped) {
01125         memcpy(dst, next, len*sizeof(WCHAR));
01126         dst += len;
01127     }
01128     needed += len;
01129     }
01130 
01131     if(needed < *pcchEscaped) {
01132         *dst = '\0';
01133     ret = S_OK;
01134     } else {
01135         needed++; /* add one for the '\0' */
01136     ret = E_POINTER;
01137     }
01138     *pcchEscaped = needed;
01139     return ret;
01140 }
01141 
01142 
01143 /*************************************************************************
01144  *      UrlUnescapeA    [SHLWAPI.@]
01145  *
01146  * Converts Url escape sequences back to ordinary characters.
01147  *
01148  * PARAMS
01149  *  pszUrl        [I/O]  Url to convert
01150  *  pszUnescaped  [O]    Destination for converted Url
01151  *  pcchUnescaped [I/O]  Size of output string
01152  *  dwFlags       [I]    URL_ESCAPE_ Flags from "shlwapi.h"
01153  *
01154  * RETURNS
01155  *  Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if
01156  *           dwFlags includes URL_ESCAPE_INPLACE.
01157  *  Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In
01158  *           this case pcchUnescaped is set to the size required.
01159  * NOTES
01160  *  If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at
01161  *  the first occurrence of either a '?' or '#' character.
01162  */
01163 HRESULT WINAPI UrlUnescapeA(
01164     LPSTR pszUrl,
01165     LPSTR pszUnescaped,
01166     LPDWORD pcchUnescaped,
01167     DWORD dwFlags)
01168 {
01169     char *dst, next;
01170     LPCSTR src;
01171     HRESULT ret;
01172     DWORD needed;
01173     BOOL stop_unescaping = FALSE;
01174 
01175     TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_a(pszUrl), pszUnescaped,
01176       pcchUnescaped, dwFlags);
01177 
01178     if (!pszUrl) return E_INVALIDARG;
01179 
01180     if(dwFlags & URL_UNESCAPE_INPLACE)
01181         dst = pszUrl;
01182     else
01183     {
01184         if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG;
01185         dst = pszUnescaped;
01186     }
01187 
01188     for(src = pszUrl, needed = 0; *src; src++, needed++) {
01189         if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
01190        (*src == '#' || *src == '?')) {
01191         stop_unescaping = TRUE;
01192         next = *src;
01193     } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
01194           && stop_unescaping == FALSE) {
01195         INT ih;
01196         char buf[3];
01197         memcpy(buf, src + 1, 2);
01198         buf[2] = '\0';
01199         ih = strtol(buf, NULL, 16);
01200         next = (CHAR) ih;
01201         src += 2; /* Advance to end of escape */
01202     } else
01203         next = *src;
01204 
01205     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
01206         *dst++ = next;
01207     }
01208 
01209     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
01210         *dst = '\0';
01211     ret = S_OK;
01212     } else {
01213         needed++; /* add one for the '\0' */
01214     ret = E_POINTER;
01215     }
01216     if(!(dwFlags & URL_UNESCAPE_INPLACE))
01217         *pcchUnescaped = needed;
01218 
01219     if (ret == S_OK) {
01220     TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
01221           debugstr_a(pszUrl) : debugstr_a(pszUnescaped));
01222     }
01223 
01224     return ret;
01225 }
01226 
01227 /*************************************************************************
01228  *      UrlUnescapeW    [SHLWAPI.@]
01229  *
01230  * See UrlUnescapeA.
01231  */
01232 HRESULT WINAPI UrlUnescapeW(
01233     LPWSTR pszUrl,
01234     LPWSTR pszUnescaped,
01235     LPDWORD pcchUnescaped,
01236     DWORD dwFlags)
01237 {
01238     WCHAR *dst, next;
01239     LPCWSTR src;
01240     HRESULT ret;
01241     DWORD needed;
01242     BOOL stop_unescaping = FALSE;
01243 
01244     TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszUrl), pszUnescaped,
01245       pcchUnescaped, dwFlags);
01246 
01247     if(!pszUrl) return E_INVALIDARG;
01248 
01249     if(dwFlags & URL_UNESCAPE_INPLACE)
01250         dst = pszUrl;
01251     else
01252     {
01253         if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG;
01254         dst = pszUnescaped;
01255     }
01256 
01257     for(src = pszUrl, needed = 0; *src; src++, needed++) {
01258         if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
01259            (*src == '#' || *src == '?')) {
01260         stop_unescaping = TRUE;
01261         next = *src;
01262         } else if(*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2))
01263           && stop_unescaping == FALSE) {
01264         INT ih;
01265         WCHAR buf[5] = {'0','x',0};
01266         memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
01267         buf[4] = 0;
01268         StrToIntExW(buf, STIF_SUPPORT_HEX, &ih);
01269         next = (WCHAR) ih;
01270         src += 2; /* Advance to end of escape */
01271     } else
01272         next = *src;
01273 
01274     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
01275         *dst++ = next;
01276     }
01277 
01278     if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
01279         *dst = '\0';
01280     ret = S_OK;
01281     } else {
01282         needed++; /* add one for the '\0' */
01283     ret = E_POINTER;
01284     }
01285     if(!(dwFlags & URL_UNESCAPE_INPLACE))
01286         *pcchUnescaped = needed;
01287 
01288     if (ret == S_OK) {
01289     TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
01290           debugstr_w(pszUrl) : debugstr_w(pszUnescaped));
01291     }
01292 
01293     return ret;
01294 }
01295 
01296 /*************************************************************************
01297  *      UrlGetLocationA     [SHLWAPI.@]
01298  *
01299  * Get the location from a Url.
01300  *
01301  * PARAMS
01302  *  pszUrl [I] Url to get the location from
01303  *
01304  * RETURNS
01305  *  A pointer to the start of the location in pszUrl, or NULL if there is
01306  *  no location.
01307  *
01308  * NOTES
01309  *  - MSDN erroneously states that "The location is the segment of the Url
01310  *    starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll
01311  *    stop at '?' and always return a NULL in this case.
01312  *  - MSDN also erroneously states that "If a file URL has a query string,
01313  *    the returned string is the query string". In all tested cases, if the
01314  *    Url starts with "fi" then a NULL is returned. V5 gives the following results:
01315  *|       Result   Url
01316  *|       ------   ---
01317  *|       NULL     file://aa/b/cd#hohoh
01318  *|       #hohoh   http://aa/b/cd#hohoh
01319  *|       NULL     fi://aa/b/cd#hohoh
01320  *|       #hohoh   ff://aa/b/cd#hohoh
01321  */
01322 LPCSTR WINAPI UrlGetLocationA(
01323     LPCSTR pszUrl)
01324 {
01325     PARSEDURLA base;
01326     DWORD res1;
01327 
01328     base.cbSize = sizeof(base);
01329     res1 = ParseURLA(pszUrl, &base);
01330     if (res1) return NULL;  /* invalid scheme */
01331 
01332     /* if scheme is file: then never return pointer */
01333     if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL;
01334 
01335     /* Look for '#' and return its addr */
01336     return strchr(base.pszSuffix, '#');
01337 }
01338 
01339 /*************************************************************************
01340  *      UrlGetLocationW     [SHLWAPI.@]
01341  *
01342  * See UrlGetLocationA.
01343  */
01344 LPCWSTR WINAPI UrlGetLocationW(
01345     LPCWSTR pszUrl)
01346 {
01347     PARSEDURLW base;
01348     DWORD res1;
01349 
01350     base.cbSize = sizeof(base);
01351     res1 = ParseURLW(pszUrl, &base);
01352     if (res1) return NULL;  /* invalid scheme */
01353 
01354     /* if scheme is file: then never return pointer */
01355     if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL;
01356 
01357     /* Look for '#' and return its addr */
01358     return strchrW(base.pszSuffix, '#');
01359 }
01360 
01361 /*************************************************************************
01362  *      UrlCompareA [SHLWAPI.@]
01363  *
01364  * Compare two Urls.
01365  *
01366  * PARAMS
01367  *  pszUrl1      [I] First Url to compare
01368  *  pszUrl2      [I] Url to compare to pszUrl1
01369  *  fIgnoreSlash [I] TRUE = compare only up to a final slash
01370  *
01371  * RETURNS
01372  *  less than zero, zero, or greater than zero indicating pszUrl2 is greater
01373  *  than, equal to, or less than pszUrl1 respectively.
01374  */
01375 INT WINAPI UrlCompareA(
01376     LPCSTR pszUrl1,
01377     LPCSTR pszUrl2,
01378     BOOL fIgnoreSlash)
01379 {
01380     INT ret, len, len1, len2;
01381 
01382     if (!fIgnoreSlash)
01383     return strcmp(pszUrl1, pszUrl2);
01384     len1 = strlen(pszUrl1);
01385     if (pszUrl1[len1-1] == '/') len1--;
01386     len2 = strlen(pszUrl2);
01387     if (pszUrl2[len2-1] == '/') len2--;
01388     if (len1 == len2)
01389     return strncmp(pszUrl1, pszUrl2, len1);
01390     len = min(len1, len2);
01391     ret = strncmp(pszUrl1, pszUrl2, len);
01392     if (ret) return ret;
01393     if (len1 > len2) return 1;
01394     return -1;
01395 }
01396 
01397 /*************************************************************************
01398  *      UrlCompareW [SHLWAPI.@]
01399  *
01400  * See UrlCompareA.
01401  */
01402 INT WINAPI UrlCompareW(
01403     LPCWSTR pszUrl1,
01404     LPCWSTR pszUrl2,
01405     BOOL fIgnoreSlash)
01406 {
01407     INT ret;
01408     size_t len, len1, len2;
01409 
01410     if (!fIgnoreSlash)
01411     return strcmpW(pszUrl1, pszUrl2);
01412     len1 = strlenW(pszUrl1);
01413     if (pszUrl1[len1-1] == '/') len1--;
01414     len2 = strlenW(pszUrl2);
01415     if (pszUrl2[len2-1] == '/') len2--;
01416     if (len1 == len2)
01417     return strncmpW(pszUrl1, pszUrl2, len1);
01418     len = min(len1, len2);
01419     ret = strncmpW(pszUrl1, pszUrl2, len);
01420     if (ret) return ret;
01421     if (len1 > len2) return 1;
01422     return -1;
01423 }
01424 
01425 /*************************************************************************
01426  *      HashData    [SHLWAPI.@]
01427  *
01428  * Hash an input block into a variable sized digest.
01429  *
01430  * PARAMS
01431  *  lpSrc    [I] Input block
01432  *  nSrcLen  [I] Length of lpSrc
01433  *  lpDest   [I] Output for hash digest
01434  *  nDestLen [I] Length of lpDest
01435  *
01436  * RETURNS
01437  *  Success: TRUE. lpDest is filled with the computed hash value.
01438  *  Failure: FALSE, if any argument is invalid.
01439  */
01440 HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen,
01441                      unsigned char *lpDest, DWORD nDestLen)
01442 {
01443   INT srcCount = nSrcLen - 1, destCount = nDestLen - 1;
01444 
01445   if (!lpSrc || !lpDest)
01446     return E_INVALIDARG;
01447 
01448   while (destCount >= 0)
01449   {
01450     lpDest[destCount] = (destCount & 0xff);
01451     destCount--;
01452   }
01453 
01454   while (srcCount >= 0)
01455   {
01456     destCount = nDestLen - 1;
01457     while (destCount >= 0)
01458     {
01459       lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]];
01460       destCount--;
01461     }
01462     srcCount--;
01463   }
01464   return S_OK;
01465 }
01466 
01467 /*************************************************************************
01468  *      UrlHashA    [SHLWAPI.@]
01469  *
01470  * Produce a Hash from a Url.
01471  *
01472  * PARAMS
01473  *  pszUrl   [I] Url to hash
01474  *  lpDest   [O] Destinationh for hash
01475  *  nDestLen [I] Length of lpDest
01476  * 
01477  * RETURNS
01478  *  Success: S_OK. lpDest is filled with the computed hash value.
01479  *  Failure: E_INVALIDARG, if any argument is invalid.
01480  */
01481 HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
01482 {
01483   if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
01484     return E_INVALIDARG;
01485 
01486   HashData((const BYTE*)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen);
01487   return S_OK;
01488 }
01489 
01490 /*************************************************************************
01491  * UrlHashW [SHLWAPI.@]
01492  *
01493  * See UrlHashA.
01494  */
01495 HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
01496 {
01497   char szUrl[MAX_PATH];
01498 
01499   TRACE("(%s,%p,%d)\n",debugstr_w(pszUrl), lpDest, nDestLen);
01500 
01501   if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
01502     return E_INVALIDARG;
01503 
01504   /* Win32 hashes the data as an ASCII string, presumably so that both A+W
01505    * return the same digests for the same URL.
01506    */
01507   WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0);
01508   HashData((const BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen);
01509   return S_OK;
01510 }
01511 
01512 /*************************************************************************
01513  *      UrlApplySchemeA [SHLWAPI.@]
01514  *
01515  * Apply a scheme to a Url.
01516  *
01517  * PARAMS
01518  *  pszIn   [I]   Url to apply scheme to
01519  *  pszOut  [O]   Destination for modified Url
01520  *  pcchOut [I/O] Length of pszOut/destination for length of pszOut
01521  *  dwFlags [I]   URL_ flags from "shlwapi.h"
01522  *
01523  * RETURNS
01524  *  Success: S_OK: pszOut contains the modified Url, pcchOut contains its length.
01525  *  Failure: An HRESULT error code describing the error.
01526  */
01527 HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
01528 {
01529     LPWSTR in, out;
01530     HRESULT ret;
01531     DWORD len;
01532 
01533     TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_a(pszIn),
01534             pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags);
01535 
01536     if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG;
01537 
01538     in = HeapAlloc(GetProcessHeap(), 0,
01539                   (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
01540     out = in + INTERNET_MAX_URL_LENGTH;
01541 
01542     MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
01543     len = INTERNET_MAX_URL_LENGTH;
01544 
01545     ret = UrlApplySchemeW(in, out, &len, dwFlags);
01546     if (ret != S_OK) {
01547         HeapFree(GetProcessHeap(), 0, in);
01548         return ret;
01549     }
01550 
01551     len = WideCharToMultiByte(CP_ACP, 0, out, -1, NULL, 0, NULL, NULL);
01552     if (len > *pcchOut) {
01553         ret = E_POINTER;
01554         goto cleanup;
01555     }
01556 
01557     WideCharToMultiByte(CP_ACP, 0, out, -1, pszOut, *pcchOut, NULL, NULL);
01558     len--;
01559 
01560 cleanup:
01561     *pcchOut = len;
01562     HeapFree(GetProcessHeap(), 0, in);
01563     return ret;
01564 }
01565 
01566 static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
01567 {
01568     HKEY newkey;
01569     BOOL j;
01570     INT index;
01571     DWORD value_len, data_len, dwType, i;
01572     WCHAR reg_path[MAX_PATH];
01573     WCHAR value[MAX_PATH], data[MAX_PATH];
01574     WCHAR Wxx, Wyy;
01575 
01576     MultiByteToWideChar(0, 0,
01577           "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes",
01578             -1, reg_path, MAX_PATH);
01579     RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
01580     index = 0;
01581     while(value_len = data_len = MAX_PATH,
01582       RegEnumValueW(newkey, index, value, &value_len,
01583             0, &dwType, (LPVOID)data, &data_len) == 0) {
01584     TRACE("guess %d %s is %s\n",
01585           index, debugstr_w(value), debugstr_w(data));
01586 
01587     j = FALSE;
01588     for(i=0; i<value_len; i++) {
01589         Wxx = pszIn[i];
01590         Wyy = value[i];
01591         /* remember that TRUE is not-equal */
01592         j = ChrCmpIW(Wxx, Wyy);
01593         if (j) break;
01594     }
01595     if ((i == value_len) && !j) {
01596         if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
01597         *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
01598         RegCloseKey(newkey);
01599         return E_POINTER;
01600         }
01601         strcpyW(pszOut, data);
01602         strcatW(pszOut, pszIn);
01603         *pcchOut = strlenW(pszOut);
01604         TRACE("matched and set to %s\n", debugstr_w(pszOut));
01605         RegCloseKey(newkey);
01606         return S_OK;
01607     }
01608     index++;
01609     }
01610     RegCloseKey(newkey);
01611     return E_FAIL;
01612 }
01613 
01614 static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
01615 {
01616     HKEY newkey;
01617     DWORD data_len, dwType;
01618     WCHAR data[MAX_PATH];
01619 
01620     static const WCHAR prefix_keyW[] =
01621         {'S','o','f','t','w','a','r','e',
01622          '\\','M','i','c','r','o','s','o','f','t',
01623          '\\','W','i','n','d','o','w','s',
01624          '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
01625          '\\','U','R','L',
01626          '\\','D','e','f','a','u','l','t','P','r','e','f','i','x',0};
01627 
01628     /* get and prepend default */
01629     RegOpenKeyExW(HKEY_LOCAL_MACHINE, prefix_keyW, 0, 1, &newkey);
01630     data_len = sizeof(data);
01631     RegQueryValueExW(newkey, NULL, 0, &dwType, (LPBYTE)data, &data_len);
01632     RegCloseKey(newkey);
01633     if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
01634         *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
01635         return E_POINTER;
01636     }
01637     strcpyW(pszOut, data);
01638     strcatW(pszOut, pszIn);
01639     *pcchOut = strlenW(pszOut);
01640     TRACE("used default %s\n", debugstr_w(pszOut));
01641     return S_OK;
01642 }
01643 
01644 /*************************************************************************
01645  *      UrlApplySchemeW [SHLWAPI.@]
01646  *
01647  * See UrlApplySchemeA.
01648  */
01649 HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
01650 {
01651     PARSEDURLW in_scheme;
01652     DWORD res1;
01653     HRESULT ret;
01654 
01655     TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_w(pszIn),
01656             pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags);
01657 
01658     if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG;
01659 
01660     if (dwFlags & URL_APPLY_GUESSFILE) {
01661     FIXME("(%s %p %p(%d) 0x%08x): stub URL_APPLY_GUESSFILE not implemented\n",
01662           debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags);
01663     strcpyW(pszOut, pszIn);
01664     *pcchOut = strlenW(pszOut);
01665     return S_FALSE;
01666     }
01667 
01668     in_scheme.cbSize = sizeof(in_scheme);
01669     /* See if the base has a scheme */
01670     res1 = ParseURLW(pszIn, &in_scheme);
01671     if (res1) {
01672     /* no scheme in input, need to see if we need to guess */
01673     if (dwFlags & URL_APPLY_GUESSSCHEME) {
01674         if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != E_FAIL)
01675         return ret;
01676     }
01677     }
01678     else {
01679     /* we have a scheme, see if valid (known scheme) */
01680     if (in_scheme.nScheme) {
01681         /* have valid scheme, so just copy and exit */
01682         if (strlenW(pszIn) + 1 > *pcchOut) {
01683         *pcchOut = strlenW(pszIn) + 1;
01684         return E_POINTER;
01685         }
01686         strcpyW(pszOut, pszIn);
01687         *pcchOut = strlenW(pszOut);
01688         TRACE("valid scheme, returning copy\n");
01689         return S_OK;
01690     }
01691     }
01692 
01693     /* If we are here, then either invalid scheme,
01694      * or no scheme and can't/failed guess.
01695      */
01696     if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) ||
01697        ((res1 != 0)) ) &&
01698      (dwFlags & URL_APPLY_DEFAULT)) {
01699     /* find and apply default scheme */
01700     return URL_ApplyDefault(pszIn, pszOut, pcchOut);
01701     }
01702 
01703     return S_FALSE;
01704 }
01705 
01706 /*************************************************************************
01707  *      UrlIsA      [SHLWAPI.@]
01708  *
01709  * Determine if a Url is of a certain class.
01710  *
01711  * PARAMS
01712  *  pszUrl [I] Url to check
01713  *  Urlis  [I] URLIS_ constant from "shlwapi.h"
01714  *
01715  * RETURNS
01716  *  TRUE if pszUrl belongs to the class type in Urlis.
01717  *  FALSE Otherwise.
01718  */
01719 BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis)
01720 {
01721     PARSEDURLA base;
01722     DWORD res1;
01723     LPCSTR last;
01724 
01725     TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis);
01726 
01727     if(!pszUrl)
01728         return FALSE;
01729 
01730     switch (Urlis) {
01731 
01732     case URLIS_OPAQUE:
01733     base.cbSize = sizeof(base);
01734     res1 = ParseURLA(pszUrl, &base);
01735     if (res1) return FALSE;  /* invalid scheme */
01736     switch (base.nScheme)
01737     {
01738     case URL_SCHEME_MAILTO:
01739     case URL_SCHEME_SHELL:
01740     case URL_SCHEME_JAVASCRIPT:
01741     case URL_SCHEME_VBSCRIPT:
01742     case URL_SCHEME_ABOUT:
01743         return TRUE;
01744     }
01745     return FALSE;
01746 
01747     case URLIS_FILEURL:
01748         return !StrCmpNA("file:", pszUrl, 5);
01749 
01750     case URLIS_DIRECTORY:
01751         last = pszUrl + strlen(pszUrl) - 1;
01752         return (last >= pszUrl && (*last == '/' || *last == '\\' ));
01753 
01754     case URLIS_URL:
01755         return PathIsURLA(pszUrl);
01756 
01757     case URLIS_NOHISTORY:
01758     case URLIS_APPLIABLE:
01759     case URLIS_HASQUERY:
01760     default:
01761     FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis);
01762     }
01763     return FALSE;
01764 }
01765 
01766 /*************************************************************************
01767  *      UrlIsW      [SHLWAPI.@]
01768  *
01769  * See UrlIsA.
01770  */
01771 BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis)
01772 {
01773     static const WCHAR stemp[] = { 'f','i','l','e',':',0 };
01774     PARSEDURLW base;
01775     DWORD res1;
01776     LPCWSTR last;
01777 
01778     TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis);
01779 
01780     if(!pszUrl)
01781         return FALSE;
01782 
01783     switch (Urlis) {
01784 
01785     case URLIS_OPAQUE:
01786     base.cbSize = sizeof(base);
01787     res1 = ParseURLW(pszUrl, &base);
01788     if (res1) return FALSE;  /* invalid scheme */
01789     switch (base.nScheme)
01790     {
01791     case URL_SCHEME_MAILTO:
01792     case URL_SCHEME_SHELL:
01793     case URL_SCHEME_JAVASCRIPT:
01794     case URL_SCHEME_VBSCRIPT:
01795     case URL_SCHEME_ABOUT:
01796         return TRUE;
01797     }
01798     return FALSE;
01799 
01800     case URLIS_FILEURL:
01801         return !strncmpW(stemp, pszUrl, 5);
01802 
01803     case URLIS_DIRECTORY:
01804         last = pszUrl + strlenW(pszUrl) - 1;
01805         return (last >= pszUrl && (*last == '/' || *last == '\\'));
01806 
01807     case URLIS_URL:
01808         return PathIsURLW(pszUrl);
01809 
01810     case URLIS_NOHISTORY:
01811     case URLIS_APPLIABLE:
01812     case URLIS_HASQUERY:
01813     default:
01814     FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis);
01815     }
01816     return FALSE;
01817 }
01818 
01819 /*************************************************************************
01820  *      UrlIsNoHistoryA     [SHLWAPI.@]
01821  *
01822  * Determine if a Url should not be stored in the users history list.
01823  *
01824  * PARAMS
01825  *  pszUrl [I] Url to check
01826  *
01827  * RETURNS
01828  *  TRUE, if pszUrl should be excluded from the history list,
01829  *  FALSE otherwise.
01830  */
01831 BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl)
01832 {
01833     return UrlIsA(pszUrl, URLIS_NOHISTORY);
01834 }
01835 
01836 /*************************************************************************
01837  *      UrlIsNoHistoryW     [SHLWAPI.@]
01838  *
01839  * See UrlIsNoHistoryA.
01840  */
01841 BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl)
01842 {
01843     return UrlIsW(pszUrl, URLIS_NOHISTORY);
01844 }
01845 
01846 /*************************************************************************
01847  *      UrlIsOpaqueA    [SHLWAPI.@]
01848  *
01849  * Determine if a Url is opaque.
01850  *
01851  * PARAMS
01852  *  pszUrl [I] Url to check
01853  *
01854  * RETURNS
01855  *  TRUE if pszUrl is opaque,
01856  *  FALSE Otherwise.
01857  *
01858  * NOTES
01859  *  An opaque Url is one that does not start with "<protocol>://".
01860  */
01861 BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl)
01862 {
01863     return UrlIsA(pszUrl, URLIS_OPAQUE);
01864 }
01865 
01866 /*************************************************************************
01867  *      UrlIsOpaqueW    [SHLWAPI.@]
01868  *
01869  * See UrlIsOpaqueA.
01870  */
01871 BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl)
01872 {
01873     return UrlIsW(pszUrl, URLIS_OPAQUE);
01874 }
01875 
01876 /*************************************************************************
01877  *  Scans for characters of type "type" and when not matching found,
01878  *  returns pointer to it and length in size.
01879  *
01880  * Characters tested based on RFC 1738
01881  */
01882 static LPCWSTR  URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type)
01883 {
01884     static DWORD alwayszero = 0;
01885     BOOL cont = TRUE;
01886 
01887     *size = 0;
01888 
01889     switch(type){
01890 
01891     case SCHEME:
01892     while (cont) {
01893         if ( (islowerW(*start) && isalphaW(*start)) ||
01894          isdigitW(*start) ||
01895                  (*start == '+') ||
01896                  (*start == '-') ||
01897                  (*start == '.')) {
01898         start++;
01899         (*size)++;
01900         }
01901         else
01902         cont = FALSE;
01903     }
01904         break;
01905 
01906     case USERPASS:
01907     while (cont) {
01908         if ( isalphaW(*start) ||
01909          isdigitW(*start) ||
01910          /* user/password only characters */
01911                  (*start == ';') ||
01912                  (*start == '?') ||
01913                  (*start == '&') ||
01914                  (*start == '=') ||
01915          /* *extra* characters */
01916                  (*start == '!') ||
01917                  (*start == '*') ||
01918                  (*start == '\'') ||
01919                  (*start == '(') ||
01920                  (*start == ')') ||
01921                  (*start == ',') ||
01922          /* *safe* characters */
01923                  (*start == '$') ||
01924                  (*start == '_') ||
01925                  (*start == '+') ||
01926                  (*start == '-') ||
01927                  (*start == '.') ||
01928                  (*start == ' ')) {
01929         start++;
01930         (*size)++;
01931             } else if (*start == '%') {
01932         if (isxdigitW(*(start+1)) &&
01933             isxdigitW(*(start+2))) {
01934             start += 3;
01935             *size += 3;
01936         } else
01937             cont = FALSE;
01938         } else
01939         cont = FALSE;
01940     }
01941     break;
01942 
01943     case PORT:
01944     while (cont) {
01945         if (isdigitW(*start)) {
01946         start++;
01947         (*size)++;
01948         }
01949         else
01950         cont = FALSE;
01951     }
01952     break;
01953 
01954     case HOST:
01955     while (cont) {
01956         if (isalnumW(*start) ||
01957                 (*start == '-') ||
01958                 (*start == '.') ||
01959                 (*start == ' ') ) {
01960         start++;
01961         (*size)++;
01962         }
01963         else
01964         cont = FALSE;
01965     }
01966     break;
01967     default:
01968     FIXME("unknown type %d\n", type);
01969     return (LPWSTR)&alwayszero;
01970     }
01971     /* TRACE("scanned %d characters next char %p<%c>\n",
01972      *size, start, *start); */
01973     return start;
01974 }
01975 
01976 /*************************************************************************
01977  *  Attempt to parse URL into pieces.
01978  */
01979 static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl)
01980 {
01981     LPCWSTR work;
01982 
01983     memset(pl, 0, sizeof(WINE_PARSE_URL));
01984     pl->pScheme = pszUrl;
01985     work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME);
01986     if (!*work || (*work != ':')) goto ErrorExit;
01987     work++;
01988     if ((*work != '/') || (*(work+1) != '/')) goto SuccessExit;
01989     pl->pUserName = work + 2;
01990     work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS);
01991     if (*work == ':' ) {
01992     /* parse password */
01993     work++;
01994     pl->pPassword = work;
01995     work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS);
01996         if (*work != '@') {
01997         /* what we just parsed must be the hostname and port
01998          * so reset pointers and clear then let it parse */
01999         pl->szUserName = pl->szPassword = 0;
02000         work = pl->pUserName - 1;
02001         pl->pUserName = pl->pPassword = 0;
02002     }
02003     } else if (*work == '@') {
02004     /* no password */
02005     pl->szPassword = 0;
02006     pl->pPassword = 0;
02007     } else if (!*work || (*work == '/') || (*work == '.')) {
02008     /* what was parsed was hostname, so reset pointers and let it parse */
02009     pl->szUserName = pl->szPassword = 0;
02010     work = pl->pUserName - 1;
02011     pl->pUserName = pl->pPassword = 0;
02012     } else goto ErrorExit;
02013 
02014     /* now start parsing hostname or hostnumber */
02015     work++;
02016     pl->pHostName = work;
02017     work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST);
02018     if (*work == ':') {
02019     /* parse port */
02020     work++;
02021     pl->pPort = work;
02022     work = URL_ScanID(pl->pPort, &pl->szPort, PORT);
02023     }
02024     if (*work == '/') {
02025     /* see if query string */
02026         pl->pQuery = strchrW(work, '?');
02027     if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery);
02028     }
02029   SuccessExit:
02030     TRACE("parse successful: scheme=%p(%d), user=%p(%d), pass=%p(%d), host=%p(%d), port=%p(%d), query=%p(%d)\n",
02031       pl->pScheme, pl->szScheme,
02032       pl->pUserName, pl->szUserName,
02033       pl->pPassword, pl->szPassword,
02034       pl->pHostName, pl->szHostName,
02035       pl->pPort, pl->szPort,
02036       pl->pQuery, pl->szQuery);
02037     return S_OK;
02038   ErrorExit:
02039     FIXME("failed to parse %s\n", debugstr_w(pszUrl));
02040     return E_INVALIDARG;
02041 }
02042 
02043 /*************************************************************************
02044  *      UrlGetPartA     [SHLWAPI.@]
02045  *
02046  * Retrieve part of a Url.
02047  *
02048  * PARAMS
02049  *  pszIn   [I]   Url to parse
02050  *  pszOut  [O]   Destination for part of pszIn requested
02051  *  pcchOut [I]   Size of pszOut
02052  *          [O]   length of pszOut string EXCLUDING '\0' if S_OK, otherwise
02053  *                needed size of pszOut INCLUDING '\0'.
02054  *  dwPart  [I]   URL_PART_ enum from "shlwapi.h"
02055  *  dwFlags [I]   URL_ flags from "shlwapi.h"
02056  *
02057  * RETURNS
02058  *  Success: S_OK. pszOut contains the part requested, pcchOut contains its length.
02059  *  Failure: An HRESULT error code describing the error.
02060  */
02061 HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut,
02062                DWORD dwPart, DWORD dwFlags)
02063 {
02064     LPWSTR in, out;
02065     DWORD ret, len, len2;
02066 
02067     if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0)
02068         return E_INVALIDARG;
02069 
02070     in = HeapAlloc(GetProcessHeap(), 0,
02071                   (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
02072     out = in + INTERNET_MAX_URL_LENGTH;
02073 
02074     MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
02075 
02076     len = INTERNET_MAX_URL_LENGTH;
02077     ret = UrlGetPartW(in, out, &len, dwPart, dwFlags);
02078 
02079     if (FAILED(ret)) {
02080     HeapFree(GetProcessHeap(), 0, in);
02081     return ret;
02082     }
02083 
02084     len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0);
02085     if (len2 > *pcchOut) {
02086     *pcchOut = len2+1;
02087     HeapFree(GetProcessHeap(), 0, in);
02088     return E_POINTER;
02089     }
02090     len2 = WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0);
02091     *pcchOut = len2-1;
02092     HeapFree(GetProcessHeap(), 0, in);
02093     return ret;
02094 }
02095 
02096 /*************************************************************************
02097  *      UrlGetPartW     [SHLWAPI.@]
02098  *
02099  * See UrlGetPartA.
02100  */
02101 HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut,
02102                DWORD dwPart, DWORD dwFlags)
02103 {
02104     WINE_PARSE_URL pl;
02105     HRESULT ret;
02106     DWORD scheme, size, schsize;
02107     LPCWSTR addr, schaddr;
02108 
02109     TRACE("(%s %p %p(%d) %08x %08x)\n",
02110       debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags);
02111 
02112     if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0)
02113         return E_INVALIDARG;
02114 
02115     *pszOut = '\0';
02116 
02117     addr = strchrW(pszIn, ':');
02118     if(!addr)
02119         scheme = URL_SCHEME_UNKNOWN;
02120     else
02121         scheme = get_scheme_code(pszIn, addr-pszIn);
02122 
02123     ret = URL_ParseUrl(pszIn, &pl);
02124 
02125     switch (dwPart) {
02126     case URL_PART_SCHEME:
02127         if (!pl.szScheme || scheme == URL_SCHEME_UNKNOWN) {
02128             *pcchOut = 0;
02129             return S_FALSE;
02130         }
02131         addr = pl.pScheme;
02132         size = pl.szScheme;
02133         break;
02134 
02135     case URL_PART_HOSTNAME:
02136             switch(scheme) {
02137             case URL_SCHEME_FTP:
02138             case URL_SCHEME_HTTP:
02139             case URL_SCHEME_GOPHER:
02140             case URL_SCHEME_TELNET:
02141             case URL_SCHEME_FILE:
02142             case URL_SCHEME_HTTPS:
02143                 break;
02144             default:
02145                 *pcchOut = 0;
02146                 return E_FAIL;
02147             }
02148 
02149             if(scheme==URL_SCHEME_FILE && (!pl.szHostName ||
02150                         (pl.szHostName==1 && *(pl.pHostName+1)==':'))) {
02151                 *pcchOut = 0;
02152                 return S_FALSE;
02153             }
02154 
02155         if (!pl.szHostName) {
02156             *pcchOut = 0;
02157             return S_FALSE;
02158         }
02159         addr = pl.pHostName;
02160         size = pl.szHostName;
02161         break;
02162 
02163     case URL_PART_USERNAME:
02164         if (!pl.szUserName) {
02165             *pcchOut = 0;
02166             return S_FALSE;
02167         }
02168         addr = pl.pUserName;
02169         size = pl.szUserName;
02170         break;
02171 
02172     case URL_PART_PASSWORD:
02173         if (!pl.szPassword) {
02174             *pcchOut = 0;
02175             return S_FALSE;
02176         }
02177         addr = pl.pPassword;
02178         size = pl.szPassword;
02179         break;
02180 
02181     case URL_PART_PORT:
02182         if (!pl.szPort) {
02183             *pcchOut = 0;
02184             return S_FALSE;
02185         }
02186         addr = pl.pPort;
02187         size = pl.szPort;
02188         break;
02189 
02190     case URL_PART_QUERY:
02191         if (!pl.szQuery) {
02192             *pcchOut = 0;
02193             return S_FALSE;
02194         }
02195         addr = pl.pQuery;
02196         size = pl.szQuery;
02197         break;
02198 
02199     default:
02200         *pcchOut = 0;
02201         return E_INVALIDARG;
02202     }
02203 
02204     if (dwFlags == URL_PARTFLAG_KEEPSCHEME) {
02205             if(!pl.pScheme || !pl.szScheme) {
02206                 *pcchOut = 0;
02207                 return E_FAIL;
02208             }
02209             schaddr = pl.pScheme;
02210             schsize = pl.szScheme;
02211             if (*pcchOut < schsize + size + 2) {
02212                 *pcchOut = schsize + size + 2;
02213                 return E_POINTER;
02214             }
02215             memcpy(pszOut, schaddr, schsize*sizeof(WCHAR));
02216             pszOut[schsize] = ':';
02217             memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR));
02218             pszOut[schsize+1+size] = 0;
02219             *pcchOut = schsize + 1 + size;
02220     }
02221     else {
02222         if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;}
02223             memcpy(pszOut, addr, size*sizeof(WCHAR));
02224             pszOut[size] = 0;
02225         *pcchOut = size;
02226     }
02227     TRACE("len=%d %s\n", *pcchOut, debugstr_w(pszOut));
02228 
02229     return ret;
02230 }
02231 
02232 /*************************************************************************
02233  * PathIsURLA   [SHLWAPI.@]
02234  *
02235  * Check if the given path is a Url.
02236  *
02237  * PARAMS
02238  *  lpszPath [I] Path to check.
02239  *
02240  * RETURNS
02241  *  TRUE  if lpszPath is a Url.
02242  *  FALSE if lpszPath is NULL or not a Url.
02243  */
02244 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
02245 {
02246     PARSEDURLA base;
02247     HRESULT hres;
02248 
02249     TRACE("%s\n", debugstr_a(lpstrPath));
02250 
02251     if (!lpstrPath || !*lpstrPath) return FALSE;
02252 
02253     /* get protocol        */
02254     base.cbSize = sizeof(base);
02255     hres = ParseURLA(lpstrPath, &base);
02256     return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID);
02257 }
02258 
02259 /*************************************************************************
02260  * PathIsURLW   [SHLWAPI.@]
02261  *
02262  * See PathIsURLA.
02263  */
02264 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
02265 {
02266     PARSEDURLW base;
02267     HRESULT hres;
02268 
02269     TRACE("%s\n", debugstr_w(lpstrPath));
02270 
02271     if (!lpstrPath || !*lpstrPath) return FALSE;
02272 
02273     /* get protocol        */
02274     base.cbSize = sizeof(base);
02275     hres = ParseURLW(lpstrPath, &base);
02276     return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID);
02277 }
02278 
02279 /*************************************************************************
02280  *      UrlCreateFromPathA      [SHLWAPI.@]
02281  * 
02282  * See UrlCreateFromPathW
02283  */
02284 HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
02285 {
02286     WCHAR bufW[INTERNET_MAX_URL_LENGTH];
02287     WCHAR *urlW = bufW;
02288     UNICODE_STRING pathW;
02289     HRESULT ret;
02290     DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
02291 
02292     if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath))
02293         return E_INVALIDARG;
02294     if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) {
02295         urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
02296         ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved);
02297     }
02298     if(ret == S_OK || ret == S_FALSE) {
02299         RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR));
02300         if(*pcchUrl > lenA) {
02301             RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR));
02302             pszUrl[lenA] = 0;
02303             *pcchUrl = lenA;
02304         } else {
02305             *pcchUrl = lenA + 1;
02306             ret = E_POINTER;
02307         }
02308     }
02309     if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW);
02310     RtlFreeUnicodeString(&pathW);
02311     return ret;
02312 }
02313 
02314 /*************************************************************************
02315  *      UrlCreateFromPathW      [SHLWAPI.@]
02316  *
02317  * Create a Url from a file path.
02318  *
02319  * PARAMS
02320  *  pszPath [I]    Path to convert
02321  *  pszUrl  [O]    Destination for the converted Url
02322  *  pcchUrl [I/O]  Length of pszUrl
02323  *  dwReserved [I] Reserved, must be 0
02324  *
02325  * RETURNS
02326  *  Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url
02327  *  Failure: An HRESULT error code.
02328  */
02329 HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
02330 {
02331     DWORD needed;
02332     HRESULT ret;
02333     WCHAR *pszNewUrl;
02334     WCHAR file_colonW[] = {'f','i','l','e',':',0};
02335     WCHAR three_slashesW[] = {'/','/','/',0};
02336     PARSEDURLW parsed_url;
02337 
02338     TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved);
02339 
02340     /* Validate arguments */
02341     if (dwReserved != 0)
02342         return E_INVALIDARG;
02343     if (!pszUrl || !pcchUrl)
02344         return E_INVALIDARG;
02345 
02346 
02347     parsed_url.cbSize = sizeof(parsed_url);
02348     if(ParseURLW(pszPath, &parsed_url) == S_OK) {
02349         if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) {
02350             needed = strlenW(pszPath);
02351             if (needed >= *pcchUrl) {
02352                 *pcchUrl = needed + 1;
02353                 return E_POINTER;
02354             } else {
02355                 *pcchUrl = needed;
02356                 strcpyW(pszUrl, pszPath);
02357                 return S_FALSE;
02358             }
02359     }
02360     }
02361 
02362     pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */
02363     strcpyW(pszNewUrl, file_colonW);
02364     if(isalphaW(pszPath[0]) && pszPath[1] == ':')
02365         strcatW(pszNewUrl, three_slashesW);
02366     strcatW(pszNewUrl, pszPath);
02367     ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT);
02368 
02369     HeapFree(GetProcessHeap(), 0, pszNewUrl);
02370     return ret;
02371 }
02372 
02373 /*************************************************************************
02374  *      SHAutoComplete      [SHLWAPI.@]
02375  *
02376  * Enable auto-completion for an edit control.
02377  *
02378  * PARAMS
02379  *  hwndEdit [I] Handle of control to enable auto-completion for
02380  *  dwFlags  [I] SHACF_ flags from "shlwapi.h"
02381  *
02382  * RETURNS
02383  *  Success: S_OK. Auto-completion is enabled for the control.
02384  *  Failure: An HRESULT error code indicating the error.
02385  */
02386 HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags)
02387 {
02388   FIXME("stub\n");
02389   return S_FALSE;
02390 }
02391 
02392 /*************************************************************************
02393  *  MLBuildResURLA  [SHLWAPI.405]
02394  *
02395  * Create a Url pointing to a resource in a module.
02396  *
02397  * PARAMS
02398  *  lpszLibName [I] Name of the module containing the resource
02399  *  hMod        [I] Callers module handle
02400  *  dwFlags     [I] Undocumented flags for loading the module
02401  *  lpszRes     [I] Resource name
02402  *  lpszDest    [O] Destination for resulting Url
02403  *  dwDestLen   [I] Length of lpszDest
02404  *
02405  * RETURNS
02406  *  Success: S_OK. lpszDest contains the resource Url.
02407  *  Failure: E_INVALIDARG, if any argument is invalid, or
02408  *           E_FAIL if dwDestLen is too small.
02409  */
02410 HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
02411                               LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen)
02412 {
02413   WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH];
02414   HRESULT hRet;
02415 
02416   if (lpszLibName)
02417     MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR));
02418 
02419   if (lpszRes)
02420     MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR));
02421 
02422   if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR))
02423     dwDestLen = sizeof(szLibName)/sizeof(WCHAR);
02424 
02425   hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags,
02426                         lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen);
02427   if (SUCCEEDED(hRet) && lpszDest)
02428     WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, 0, 0);
02429 
02430   return hRet;
02431 }
02432 
02433 /*************************************************************************
02434  *  MLBuildResURLA  [SHLWAPI.406]
02435  *
02436  * See MLBuildResURLA.
02437  */
02438 HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
02439                               LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen)
02440 {
02441   static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' };
02442 #define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR))
02443   HRESULT hRet = E_FAIL;
02444 
02445   TRACE("(%s,%p,0x%08x,%s,%p,%d)\n", debugstr_w(lpszLibName), hMod, dwFlags,
02446         debugstr_w(lpszRes), lpszDest, dwDestLen);
02447 
02448   if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes ||
02449       !lpszDest || (dwFlags && dwFlags != 2))
02450     return E_INVALIDARG;
02451 
02452   if (dwDestLen >= szResLen + 1)
02453   {
02454     dwDestLen -= (szResLen + 1);
02455     memcpy(lpszDest, szRes, sizeof(szRes));
02456 
02457     hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags);
02458 
02459     if (hMod)
02460     {
02461       WCHAR szBuff[MAX_PATH];
02462       DWORD len;
02463 
02464       len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR));
02465       if (len && len < sizeof(szBuff)/sizeof(WCHAR))
02466       {
02467         DWORD dwPathLen = strlenW(szBuff) + 1;
02468 
02469         if (dwDestLen >= dwPathLen)
02470         {
02471           DWORD dwResLen;
02472 
02473           dwDestLen -= dwPathLen;
02474           memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR));
02475 
02476           dwResLen = strlenW(lpszRes) + 1;
02477           if (dwDestLen >= dwResLen + 1)
02478           {
02479             lpszDest[szResLen + dwPathLen-1] = '/';
02480             memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR));
02481             hRet = S_OK;
02482           }
02483         }
02484       }
02485       MLFreeLibrary(hMod);
02486     }
02487   }
02488   return hRet;
02489 }
02490 
02491 /***********************************************************************
02492  *             UrlFixupW [SHLWAPI.462]
02493  *
02494  * Checks the scheme part of a URL and attempts to correct misspellings.
02495  *
02496  * PARAMS
02497  *  lpszUrl           [I] Pointer to the URL to be corrected
02498  *  lpszTranslatedUrl [O] Pointer to a buffer to store corrected URL
02499  *  dwMaxChars        [I] Maximum size of corrected URL
02500  *
02501  * RETURNS
02502  *  success: S_OK if URL corrected or already correct
02503  *  failure: S_FALSE if unable to correct / COM error code if other error
02504  *
02505  */
02506 HRESULT WINAPI UrlFixupW(LPCWSTR url, LPWSTR translatedUrl, DWORD maxChars)
02507 {
02508     DWORD srcLen;
02509 
02510     FIXME("(%s,%p,%d) STUB\n", debugstr_w(url), translatedUrl, maxChars);
02511 
02512     if (!url)
02513         return E_FAIL;
02514 
02515     srcLen = lstrlenW(url) + 1;
02516 
02517     /* For now just copy the URL directly */
02518     lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen);
02519 
02520     return S_OK;
02521 }

Generated on Sat May 26 2012 04:25:08 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.