123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322 |
- /*
- * Url functions
- *
- * Copyright 2000 Huw D M Davies for CodeWeavers.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "config.h"
- #include "wine/port.h"
- #include <stdarg.h>
- #include <string.h>
- #include <stdlib.h>
- #include "windef.h"
- #include "winbase.h"
- #include "winnls.h"
- #include "winerror.h"
- #include "wine/unicode.h"
- #include "wininet.h"
- #include "winreg.h"
- #include "winternl.h"
- #define NO_SHLWAPI_STREAM
- #include "shlwapi.h"
- #include "wine/debug.h"
- HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD);
- BOOL WINAPI MLFreeLibrary(HMODULE);
- HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD);
- WINE_DEFAULT_DEBUG_CHANNEL(shell);
- /* The following schemes were identified in the native version of
- * SHLWAPI.DLL version 5.50
- */
- typedef struct {
- URL_SCHEME scheme_number;
- LPCSTR scheme_name;
- } SHL_2_inet_scheme;
- static const SHL_2_inet_scheme shlwapi_schemes[] = {
- {URL_SCHEME_FTP, "ftp"},
- {URL_SCHEME_HTTP, "http"},
- {URL_SCHEME_GOPHER, "gopher"},
- {URL_SCHEME_MAILTO, "mailto"},
- {URL_SCHEME_NEWS, "news"},
- {URL_SCHEME_NNTP, "nntp"},
- {URL_SCHEME_TELNET, "telnet"},
- {URL_SCHEME_WAIS, "wais"},
- {URL_SCHEME_FILE, "file"},
- {URL_SCHEME_MK, "mk"},
- {URL_SCHEME_HTTPS, "https"},
- {URL_SCHEME_SHELL, "shell"},
- {URL_SCHEME_SNEWS, "snews"},
- {URL_SCHEME_LOCAL, "local"},
- {URL_SCHEME_JAVASCRIPT, "javascript"},
- {URL_SCHEME_VBSCRIPT, "vbscript"},
- {URL_SCHEME_ABOUT, "about"},
- {URL_SCHEME_RES, "res"},
- {0, 0}
- };
- typedef struct {
- LPCWSTR pScheme; /* [out] start of scheme */
- DWORD szScheme; /* [out] size of scheme (until colon) */
- LPCWSTR pUserName; /* [out] start of Username */
- DWORD szUserName; /* [out] size of Username (until ":" or "@") */
- LPCWSTR pPassword; /* [out] start of Password */
- DWORD szPassword; /* [out] size of Password (until "@") */
- LPCWSTR pHostName; /* [out] start of Hostname */
- DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */
- LPCWSTR pPort; /* [out] start of Port */
- DWORD szPort; /* [out] size of Port (until "/" or eos) */
- LPCWSTR pQuery; /* [out] start of Query */
- DWORD szQuery; /* [out] size of Query (until eos) */
- } WINE_PARSE_URL;
- typedef enum {
- SCHEME,
- HOST,
- PORT,
- USERPASS,
- } WINE_URL_SCAN_TYPE;
- static const CHAR hexDigits[] = "0123456789ABCDEF";
- static const WCHAR fileW[] = {'f','i','l','e','\0'};
- static const unsigned char HashDataLookup[256] = {
- 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B,
- 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07,
- 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94,
- 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46,
- 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0,
- 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6,
- 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F,
- 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
- 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF,
- 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40,
- 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9,
- 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4,
- 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB,
- 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB,
- 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D,
- 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
- 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD,
- 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17,
- 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
- 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
- static BOOL URL_JustLocation(LPCWSTR str)
- {
- while(*str && (*str == L'/')) str++;
- if (*str) {
- while (*str && ((*str == L'-') ||
- (*str == L'.') ||
- isalnumW(*str))) str++;
- if (*str == L'/') return FALSE;
- }
- return TRUE;
- }
- /*************************************************************************
- * @ [SHLWAPI.1]
- *
- * Parse a Url into its constituent parts.
- *
- * PARAMS
- * x [I] Url to parse
- * y [O] Undocumented structure holding the parsed information
- *
- * RETURNS
- * Success: S_OK. y contains the parsed Url details.
- * Failure: An HRESULT error code.
- */
- HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y)
- {
- DWORD cnt;
- const SHL_2_inet_scheme *inet_pro;
- y->nScheme = URL_SCHEME_INVALID;
- if (y->cbSize != sizeof(*y)) return E_INVALIDARG;
- /* FIXME: leading white space generates error of 0x80041001 which
- * is undefined
- */
- if (*x <= ' ') return 0x80041001;
- cnt = 0;
- y->cchProtocol = 0;
- y->pszProtocol = x;
- while (*x) {
- if (*x == ':') {
- y->cchProtocol = cnt;
- cnt = -1;
- y->pszSuffix = x+1;
- break;
- }
- x++;
- cnt++;
- }
- /* check for no scheme in string start */
- /* (apparently schemes *must* be larger than a single character) */
- if ((*x == '\0') || (y->cchProtocol <= 1)) {
- y->pszProtocol = NULL;
- return 0x80041001;
- }
- /* found scheme, set length of remainder */
- y->cchSuffix = lstrlenA(y->pszSuffix);
- /* see if known scheme and return indicator number */
- y->nScheme = URL_SCHEME_UNKNOWN;
- inet_pro = shlwapi_schemes;
- while (inet_pro->scheme_name) {
- if (!strncasecmp(inet_pro->scheme_name, y->pszProtocol,
- min(y->cchProtocol, lstrlenA(inet_pro->scheme_name)))) {
- y->nScheme = inet_pro->scheme_number;
- break;
- }
- inet_pro++;
- }
- return S_OK;
- }
- /*************************************************************************
- * @ [SHLWAPI.2]
- *
- * Unicode version of ParseURLA.
- */
- HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y)
- {
- DWORD cnt;
- const SHL_2_inet_scheme *inet_pro;
- LPSTR cmpstr;
- INT len;
- y->nScheme = URL_SCHEME_INVALID;
- if (y->cbSize != sizeof(*y)) return E_INVALIDARG;
- /* FIXME: leading white space generates error of 0x80041001 which
- * is undefined
- */
- if (*x <= L' ') return 0x80041001;
- cnt = 0;
- y->cchProtocol = 0;
- y->pszProtocol = x;
- while (*x) {
- if (*x == L':') {
- y->cchProtocol = cnt;
- cnt = -1;
- y->pszSuffix = x+1;
- break;
- }
- x++;
- cnt++;
- }
- /* check for no scheme in string start */
- /* (apparently schemes *must* be larger than a single character) */
- if ((*x == L'\0') || (y->cchProtocol <= 1)) {
- y->pszProtocol = NULL;
- return 0x80041001;
- }
- /* found scheme, set length of remainder */
- y->cchSuffix = lstrlenW(y->pszSuffix);
- /* see if known scheme and return indicator number */
- len = WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, 0, 0, 0, 0);
- cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len);
- WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, cmpstr, len, 0, 0);
- y->nScheme = URL_SCHEME_UNKNOWN;
- inet_pro = shlwapi_schemes;
- while (inet_pro->scheme_name) {
- if (!strncasecmp(inet_pro->scheme_name, cmpstr,
- min(len, lstrlenA(inet_pro->scheme_name)))) {
- y->nScheme = inet_pro->scheme_number;
- break;
- }
- inet_pro++;
- }
- HeapFree(GetProcessHeap(), 0, cmpstr);
- return S_OK;
- }
- /*************************************************************************
- * UrlCanonicalizeA [SHLWAPI.@]
- *
- * Canonicalize a Url.
- *
- * PARAMS
- * pszUrl [I] Url to cCanonicalize
- * pszCanonicalized [O] Destination for converted Url.
- * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized
- * dwFlags [I] Flags controlling the conversion.
- *
- * RETURNS
- * Success: S_OK. The pszCanonicalized contains the converted Url.
- * Failure: E_POINTER, if *pcchCanonicalized is too small.
- *
- * MSDN incorrectly describes the flags for this function. They should be:
- *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000
- *| URL_ESCAPE_SPACES_ONLY 0x04000000
- *| URL_ESCAPE_PERCENT 0x00001000
- *| URL_ESCAPE_UNSAFE 0x10000000
- *| URL_UNESCAPE 0x10000000
- *| URL_DONT_SIMPLIFY 0x08000000
- *| URL_ESCAPE_SEGMENT_ONLY 0x00002000
- */
- HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
- LPDWORD pcchCanonicalized, DWORD dwFlags)
- {
- LPWSTR base, canonical;
- DWORD ret, len, len2;
- TRACE("(%s %p %p 0x%08lx) using W version\n",
- debugstr_a(pszUrl), pszCanonicalized,
- pcchCanonicalized, dwFlags);
- if(!pszUrl || !pszCanonicalized || !pcchCanonicalized)
- return E_INVALIDARG;
- base = HeapAlloc(GetProcessHeap(), 0,
- (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
- canonical = base + INTERNET_MAX_URL_LENGTH;
- MultiByteToWideChar(0, 0, pszUrl, -1, base, INTERNET_MAX_URL_LENGTH);
- len = INTERNET_MAX_URL_LENGTH;
- ret = UrlCanonicalizeW(base, canonical, &len, dwFlags);
- if (ret != S_OK) {
- HeapFree(GetProcessHeap(), 0, base);
- return ret;
- }
- len2 = WideCharToMultiByte(0, 0, canonical, len, 0, 0, 0, 0);
- if (len2 > *pcchCanonicalized) {
- *pcchCanonicalized = len;
- HeapFree(GetProcessHeap(), 0, base);
- return E_POINTER;
- }
- WideCharToMultiByte(0, 0, canonical, len+1, pszCanonicalized,
- *pcchCanonicalized, 0, 0);
- *pcchCanonicalized = len2;
- HeapFree(GetProcessHeap(), 0, base);
- return S_OK;
- }
- /*************************************************************************
- * UrlCanonicalizeW [SHLWAPI.@]
- *
- * See UrlCanonicalizeA.
- */
- HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
- LPDWORD pcchCanonicalized, DWORD dwFlags)
- {
- HRESULT hr = S_OK;
- DWORD EscapeFlags;
- LPWSTR lpszUrlCpy, wk1, wk2, mp, root;
- INT nByteLen, state;
- DWORD nLen;
- TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized,
- pcchCanonicalized, dwFlags);
- if(!pszUrl || !pszCanonicalized || !pcchCanonicalized)
- return E_INVALIDARG;
- nByteLen = (lstrlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */
- lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nByteLen);
- if (dwFlags & URL_DONT_SIMPLIFY)
- memcpy(lpszUrlCpy, pszUrl, nByteLen);
- else {
- /*
- * state =
- * 0 initial 1,3
- * 1 have 2[+] alnum 2,3
- * 2 have scheme (found :) 4,6,3
- * 3 failed (no location)
- * 4 have // 5,3
- * 5 have 1[+] alnum 6,3
- * 6 have location (found /) save root location
- */
- wk1 = (LPWSTR)pszUrl;
- wk2 = lpszUrlCpy;
- state = 0;
- while (*wk1) {
- switch (state) {
- case 0:
- if (!isalnumW(*wk1)) {state = 3; break;}
- *wk2++ = *wk1++;
- if (!isalnumW(*wk1)) {state = 3; break;}
- *wk2++ = *wk1++;
- state = 1;
- break;
- case 1:
- *wk2++ = *wk1;
- if (*wk1++ == L':') state = 2;
- break;
- case 2:
- if (*wk1 != L'/') {state = 3; break;}
- *wk2++ = *wk1++;
- if (*wk1 != L'/') {state = 6; break;}
- *wk2++ = *wk1++;
- state = 4;
- break;
- case 3:
- strcpyW(wk2, wk1);
- wk1 += strlenW(wk1);
- wk2 += strlenW(wk2);
- break;
- case 4:
- if (!isalnumW(*wk1) && (*wk1 != L'-') && (*wk1 != L'.')) {state = 3; break;}
- while(isalnumW(*wk1) || (*wk1 == L'-') || (*wk1 == L'.')) *wk2++ = *wk1++;
- state = 5;
- break;
- case 5:
- if (*wk1 != L'/') {state = 3; break;}
- *wk2++ = *wk1++;
- state = 6;
- break;
- case 6:
- /* Now at root location, cannot back up any more. */
- /* "root" will point at the '/' */
- root = wk2-1;
- while (*wk1) {
- TRACE("wk1=%c\n", (CHAR)*wk1);
- mp = strchrW(wk1, L'/');
- if (!mp) {
- strcpyW(wk2, wk1);
- wk1 += strlenW(wk1);
- wk2 += strlenW(wk2);
- continue;
- }
- nLen = mp - wk1 + 1;
- strncpyW(wk2, wk1, nLen);
- wk2 += nLen;
- wk1 += nLen;
- if (*wk1 == L'.') {
- TRACE("found '/.'\n");
- if (*(wk1+1) == L'/') {
- /* case of /./ -> skip the ./ */
- wk1 += 2;
- }
- else if (*(wk1+1) == L'.') {
- /* found /.. look for next / */
- TRACE("found '/..'\n");
- if (*(wk1+2) == L'/' || *(wk1+2) == L'?' || *(wk1+2) == L'#' || *(wk1+2) == 0) {
- /* case /../ -> need to backup wk2 */
- TRACE("found '/../'\n");
- *(wk2-1) = L'\0'; /* set end of string */
- mp = strrchrW(root, L'/');
- if (mp && (mp >= root)) {
- /* found valid backup point */
- wk2 = mp + 1;
- if(*(wk1+2) != L'/')
- wk1 += 2;
- else
- wk1 += 3;
- }
- else {
- /* did not find point, restore '/' */
- *(wk2-1) = L'/';
- }
- }
- }
- }
- }
- *wk2 = L'\0';
- break;
- default:
- FIXME("how did we get here - state=%d\n", state);
- HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
- return E_INVALIDARG;
- }
- }
- *wk2 = L'\0';
- TRACE("Simplified, orig <%s>, simple <%s>\n",
- debugstr_w(pszUrl), debugstr_w(lpszUrlCpy));
- }
- nLen = lstrlenW(lpszUrlCpy);
- while ((nLen > 0) && ((lpszUrlCpy[nLen-1] == '\r')||(lpszUrlCpy[nLen-1] == '\n')))
- lpszUrlCpy[--nLen]=0;
- if(dwFlags & URL_UNESCAPE)
- UrlUnescapeW(lpszUrlCpy, NULL, NULL, URL_UNESCAPE_INPLACE);
- if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE |
- URL_ESCAPE_SPACES_ONLY |
- URL_ESCAPE_PERCENT |
- URL_DONT_ESCAPE_EXTRA_INFO |
- URL_ESCAPE_SEGMENT_ONLY ))) {
- EscapeFlags &= ~URL_ESCAPE_UNSAFE;
- hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
- EscapeFlags);
- } else { /* No escaping needed, just copy the string */
- nLen = lstrlenW(lpszUrlCpy);
- if(nLen < *pcchCanonicalized)
- memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR));
- else {
- hr = E_POINTER;
- nLen++;
- }
- *pcchCanonicalized = nLen;
- }
- HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
- if (hr == S_OK)
- TRACE("result %s\n", debugstr_w(pszCanonicalized));
- return hr;
- }
- /*************************************************************************
- * UrlCombineA [SHLWAPI.@]
- *
- * Combine two Urls.
- *
- * PARAMS
- * pszBase [I] Base Url
- * pszRelative [I] Url to combine with pszBase
- * pszCombined [O] Destination for combined Url
- * pcchCombined [O] Destination for length of pszCombined
- * dwFlags [I] URL_ flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK. pszCombined contains the combined Url, pcchCombined
- * contains its length.
- * Failure: An HRESULT error code indicating the error.
- */
- HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
- LPSTR pszCombined, LPDWORD pcchCombined,
- DWORD dwFlags)
- {
- LPWSTR base, relative, combined;
- DWORD ret, len, len2;
- TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n",
- debugstr_a(pszBase),debugstr_a(pszRelative),
- pcchCombined?*pcchCombined:0,dwFlags);
- if(!pszBase || !pszRelative || !pcchCombined)
- return E_INVALIDARG;
- base = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
- (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
- relative = base + INTERNET_MAX_URL_LENGTH;
- combined = relative + INTERNET_MAX_URL_LENGTH;
- MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
- MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
- len = *pcchCombined;
- ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags);
- if (ret != S_OK) {
- *pcchCombined = len;
- HeapFree(GetProcessHeap(), 0, base);
- return ret;
- }
- len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0);
- if (len2 > *pcchCombined) {
- *pcchCombined = len2;
- HeapFree(GetProcessHeap(), 0, base);
- return E_POINTER;
- }
- WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1,
- 0, 0);
- *pcchCombined = len2;
- HeapFree(GetProcessHeap(), 0, base);
- return S_OK;
- }
- /*************************************************************************
- * UrlCombineW [SHLWAPI.@]
- *
- * See UrlCombineA.
- */
- HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
- LPWSTR pszCombined, LPDWORD pcchCombined,
- DWORD dwFlags)
- {
- PARSEDURLW base, relative;
- DWORD myflags, sizeloc = 0;
- DWORD len, res1, res2, process_case = 0;
- LPWSTR work, preliminary, mbase, mrelative;
- static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'};
- static const WCHAR single_slash[] = {'/','\0'};
- HRESULT ret;
- TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n",
- debugstr_w(pszBase),debugstr_w(pszRelative),
- pcchCombined?*pcchCombined:0,dwFlags);
- if(!pszBase || !pszRelative || !pcchCombined)
- return E_INVALIDARG;
- base.cbSize = sizeof(base);
- relative.cbSize = sizeof(relative);
- /* Get space for duplicates of the input and the output */
- preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) *
- sizeof(WCHAR));
- mbase = preliminary + INTERNET_MAX_URL_LENGTH;
- mrelative = mbase + INTERNET_MAX_URL_LENGTH;
- *preliminary = L'\0';
- /* Canonicalize the base input prior to looking for the scheme */
- myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
- len = INTERNET_MAX_URL_LENGTH;
- ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags);
- /* Canonicalize the relative input prior to looking for the scheme */
- len = INTERNET_MAX_URL_LENGTH;
- ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags);
- /* See if the base has a scheme */
- res1 = ParseURLW(mbase, &base);
- if (res1) {
- /* if pszBase has no scheme, then return pszRelative */
- TRACE("no scheme detected in Base\n");
- process_case = 1;
- }
- else do {
- /* get size of location field (if it exists) */
- work = (LPWSTR)base.pszSuffix;
- sizeloc = 0;
- if (*work++ == L'/') {
- if (*work++ == L'/') {
- /* At this point have start of location and
- * it ends at next '/' or end of string.
- */
- while(*work && (*work != L'/')) work++;
- sizeloc = (DWORD)(work - base.pszSuffix);
- }
- }
- /* Change .sizep2 to not have the last leaf in it,
- * Note: we need to start after the location (if it exists)
- */
- work = strrchrW((base.pszSuffix+sizeloc), L'/');
- if (work) {
- len = (DWORD)(work - base.pszSuffix + 1);
- base.cchSuffix = len;
- }
- /*
- * At this point:
- * .pszSuffix points to location (starting with '//')
- * .cchSuffix length of location (above) and rest less the last
- * leaf (if any)
- * sizeloc length of location (above) up to but not including
- * the last '/'
- */
- res2 = ParseURLW(mrelative, &relative);
- if (res2) {
- /* no scheme in pszRelative */
- TRACE("no scheme detected in Relative\n");
- relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */
- relative.cchSuffix = strlenW(mrelative);
- if (*pszRelative == L':') {
- /* case that is either left alone or uses pszBase */
- if (dwFlags & URL_PLUGGABLE_PROTOCOL) {
- process_case = 5;
- break;
- }
- process_case = 1;
- break;
- }
- if (isalnum(*mrelative) && (*(mrelative + 1) == L':')) {
- /* case that becomes "file:///" */
- strcpyW(preliminary, myfilestr);
- process_case = 1;
- break;
- }
- if ((*mrelative == L'/') && (*(mrelative+1) == L'/')) {
- /* pszRelative has location and rest */
- process_case = 3;
- break;
- }
- if (*mrelative == L'/') {
- /* case where pszRelative is root to location */
- process_case = 4;
- break;
- }
- process_case = (*base.pszSuffix == L'/') ? 5 : 3;
- break;
- }
- /* handle cases where pszRelative has scheme */
- if ((base.cchProtocol == relative.cchProtocol) &&
- (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) {
- /* since the schemes are the same */
- if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) {
- /* case where pszRelative replaces location and following */
- process_case = 3;
- break;
- }
- if (*relative.pszSuffix == L'/') {
- /* case where pszRelative is root to location */
- process_case = 4;
- break;
- }
- /* case where scheme is followed by document path */
- process_case = 5;
- break;
- }
- if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) {
- /* case where pszRelative replaces scheme, location,
- * and following and handles PLUGGABLE
- */
- process_case = 2;
- break;
- }
- process_case = 1;
- break;
- } while(FALSE); /* a litte trick to allow easy exit from nested if's */
- ret = S_OK;
- switch (process_case) {
- case 1: /*
- * Return pszRelative appended to what ever is in pszCombined,
- * (which may the string "file:///"
- */
- strcatW(preliminary, mrelative);
- break;
- case 2: /*
- * Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified
- * and pszRelative starts with "//", then append a "/"
- */
- strcpyW(preliminary, mrelative);
- if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
- URL_JustLocation(relative.pszSuffix))
- strcatW(preliminary, single_slash);
- break;
- case 3: /*
- * Return the pszBase scheme with pszRelative. Basically
- * keeps the scheme and replaces the domain and following.
- */
- strncpyW(preliminary, base.pszProtocol, base.cchProtocol + 1);
- work = preliminary + base.cchProtocol + 1;
- strcpyW(work, relative.pszSuffix);
- if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) &&
- URL_JustLocation(relative.pszSuffix))
- strcatW(work, single_slash);
- break;
- case 4: /*
- * Return the pszBase scheme and location but everything
- * after the location is pszRelative. (Replace document
- * from root on.)
- */
- strncpyW(preliminary, base.pszProtocol, base.cchProtocol+1+sizeloc);
- work = preliminary + base.cchProtocol + 1 + sizeloc;
- if (dwFlags & URL_PLUGGABLE_PROTOCOL)
- *(work++) = L'/';
- strcpyW(work, relative.pszSuffix);
- break;
- case 5: /*
- * Return the pszBase without its document (if any) and
- * append pszRelative after its scheme.
- */
- strncpyW(preliminary, base.pszProtocol, base.cchProtocol+1+base.cchSuffix);
- work = preliminary + base.cchProtocol+1+base.cchSuffix - 1;
- if (*work++ != L'/')
- *(work++) = L'/';
- strcpyW(work, relative.pszSuffix);
- break;
- default:
- FIXME("How did we get here????? process_case=%ld\n", process_case);
- ret = E_INVALIDARG;
- }
- if (ret == S_OK) {
- /* Reuse mrelative as temp storage as its already allocated and not needed anymore */
- ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, dwFlags);
- if(SUCCEEDED(ret) && pszCombined) {
- lstrcpyW(pszCombined, mrelative);
- }
- TRACE("return-%ld len=%ld, %s\n",
- process_case, *pcchCombined, debugstr_w(pszCombined));
- }
- HeapFree(GetProcessHeap(), 0, preliminary);
- return ret;
- }
- /*************************************************************************
- * UrlEscapeA [SHLWAPI.@]
- */
- HRESULT WINAPI UrlEscapeA(
- LPCSTR pszUrl,
- LPSTR pszEscaped,
- LPDWORD pcchEscaped,
- DWORD dwFlags)
- {
- WCHAR bufW[INTERNET_MAX_URL_LENGTH];
- WCHAR *escapedW = bufW;
- UNICODE_STRING urlW;
- HRESULT ret;
- DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
- if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
- return E_INVALIDARG;
- if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) {
- escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
- ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags);
- }
- if(ret == S_OK) {
- RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
- if(*pcchEscaped > lenA) {
- RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
- pszEscaped[lenA] = 0;
- *pcchEscaped = lenA;
- } else {
- *pcchEscaped = lenA + 1;
- ret = E_POINTER;
- }
- }
- if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW);
- RtlFreeUnicodeString(&urlW);
- return ret;
- }
- #define WINE_URL_BASH_AS_SLASH 0x01
- #define WINE_URL_COLLAPSE_SLASHES 0x02
- #define WINE_URL_ESCAPE_SLASH 0x04
- #define WINE_URL_ESCAPE_HASH 0x08
- #define WINE_URL_ESCAPE_QUESTION 0x10
- #define WINE_URL_STOP_ON_HASH 0x20
- #define WINE_URL_STOP_ON_QUESTION 0x40
- static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags)
- {
- if (isalnumW(ch))
- return FALSE;
- if(dwFlags & URL_ESCAPE_SPACES_ONLY) {
- if(ch == ' ')
- return TRUE;
- else
- return FALSE;
- }
- if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%'))
- return TRUE;
- if (ch <= 31 || ch >= 127)
- return TRUE;
- else {
- switch (ch) {
- case ' ':
- case '<':
- case '>':
- case '\"':
- case '{':
- case '}':
- case '|':
- case '\\':
- case '^':
- case ']':
- case '[':
- case '`':
- case '&':
- return TRUE;
- case '/':
- if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE;
- return FALSE;
- case '?':
- if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE;
- return FALSE;
- case '#':
- if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE;
- return FALSE;
- default:
- return FALSE;
- }
- }
- }
- /*************************************************************************
- * UrlEscapeW [SHLWAPI.@]
- *
- * Converts unsafe characters in a Url into escape sequences.
- *
- * PARAMS
- * pszUrl [I] Url to modify
- * pszEscaped [O] Destination for modified Url
- * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped
- * dwFlags [I] URL_ flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped
- * contains its length.
- * Failure: E_POINTER, if pszEscaped is not large enough. In this case
- * pcchEscaped is set to the required length.
- *
- * Converts unsafe characters into their escape sequences.
- *
- * NOTES
- * - By default this function stops converting at the first '?' or
- * '#' character.
- * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
- * converted, but the conversion continues past a '?' or '#'.
- * - Note that this function did not work well (or at all) in shlwapi version 4.
- *
- * BUGS
- * Only the following flags are implemented:
- *| URL_ESCAPE_SPACES_ONLY
- *| URL_DONT_ESCAPE_EXTRA_INFO
- *| URL_ESCAPE_SEGMENT_ONLY
- *| URL_ESCAPE_PERCENT
- */
- HRESULT WINAPI UrlEscapeW(
- LPCWSTR pszUrl,
- LPWSTR pszEscaped,
- LPDWORD pcchEscaped,
- DWORD dwFlags)
- {
- LPCWSTR src;
- DWORD needed = 0, ret;
- BOOL stop_escaping = FALSE;
- WCHAR next[5], *dst = pszEscaped;
- INT len;
- PARSEDURLW parsed_url;
- DWORD int_flags;
- DWORD slashes = 0;
- static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0};
- TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped,
- pcchEscaped, dwFlags);
- if(!pszUrl || !pszEscaped || !pcchEscaped)
- return E_INVALIDARG;
- if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
- URL_ESCAPE_SEGMENT_ONLY |
- URL_DONT_ESCAPE_EXTRA_INFO |
- URL_ESCAPE_PERCENT))
- FIXME("Unimplemented flags: %08lx\n", dwFlags);
- /* fix up flags */
- if (dwFlags & URL_ESCAPE_SPACES_ONLY)
- /* if SPACES_ONLY specified, reset the other controls */
- dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO |
- URL_ESCAPE_PERCENT |
- URL_ESCAPE_SEGMENT_ONLY);
- else
- /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
- dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
- int_flags = 0;
- if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
- int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
- } else {
- parsed_url.cbSize = sizeof(parsed_url);
- if(ParseURLW(pszUrl, &parsed_url) != S_OK)
- parsed_url.nScheme = URL_SCHEME_INVALID;
- TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
- if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
- int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
- switch(parsed_url.nScheme) {
- case URL_SCHEME_FILE:
- int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
- int_flags &= ~WINE_URL_STOP_ON_HASH;
- break;
- case URL_SCHEME_HTTP:
- case URL_SCHEME_HTTPS:
- int_flags |= WINE_URL_BASH_AS_SLASH;
- if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
- int_flags |= WINE_URL_ESCAPE_SLASH;
- break;
- case URL_SCHEME_MAILTO:
- int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH;
- int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH);
- break;
- case URL_SCHEME_INVALID:
- break;
- case URL_SCHEME_FTP:
- default:
- if(parsed_url.pszSuffix[0] != '/')
- int_flags |= WINE_URL_ESCAPE_SLASH;
- break;
- }
- }
- for(src = pszUrl; *src; ) {
- WCHAR cur = *src;
- len = 0;
-
- if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) {
- int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1;
- while(cur == '/' || cur == '\\') {
- slashes++;
- cur = *++src;
- }
- if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */
- if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\')
- src += localhost_len + 1;
- slashes = 3;
- }
- switch(slashes) {
- case 1:
- case 3:
- next[0] = next[1] = next[2] = '/';
- len = 3;
- break;
- case 0:
- len = 0;
- break;
- default:
- next[0] = next[1] = '/';
- len = 2;
- break;
- }
- }
- if(len == 0) {
- if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
- stop_escaping = TRUE;
- if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
- stop_escaping = TRUE;
- if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
- if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) {
- next[0] = L'%';
- next[1] = hexDigits[(cur >> 4) & 0xf];
- next[2] = hexDigits[cur & 0xf];
- len = 3;
- } else {
- next[0] = cur;
- len = 1;
- }
- src++;
- }
- if(needed + len <= *pcchEscaped) {
- memcpy(dst, next, len*sizeof(WCHAR));
- dst += len;
- }
- needed += len;
- }
- if(needed < *pcchEscaped) {
- *dst = '\0';
- ret = S_OK;
- } else {
- needed++; /* add one for the '\0' */
- ret = E_POINTER;
- }
- *pcchEscaped = needed;
- return ret;
- }
- /*************************************************************************
- * UrlUnescapeA [SHLWAPI.@]
- *
- * Converts Url escape sequences back to ordinary characters.
- *
- * PARAMS
- * pszUrl [I/O] Url to convert
- * pszUnescaped [O] Destination for converted Url
- * pcchUnescaped [I/O] Size of output string
- * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if
- * dwFlags includes URL_ESCAPE_INPLACE.
- * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In
- * this case pcchUnescaped is set to the size required.
- * NOTES
- * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at
- * the first occurrence of either a '?' or '#' character.
- */
- HRESULT WINAPI UrlUnescapeA(
- LPSTR pszUrl,
- LPSTR pszUnescaped,
- LPDWORD pcchUnescaped,
- DWORD dwFlags)
- {
- char *dst, next;
- LPCSTR src;
- HRESULT ret;
- DWORD needed;
- BOOL stop_unescaping = FALSE;
- TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszUrl), pszUnescaped,
- pcchUnescaped, dwFlags);
- if(!pszUrl || !pszUnescaped || !pcchUnescaped)
- return E_INVALIDARG;
- if(dwFlags & URL_UNESCAPE_INPLACE)
- dst = pszUrl;
- else
- dst = pszUnescaped;
- for(src = pszUrl, needed = 0; *src; src++, needed++) {
- if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
- (*src == '#' || *src == '?')) {
- stop_unescaping = TRUE;
- next = *src;
- } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
- && stop_unescaping == FALSE) {
- INT ih;
- char buf[3];
- memcpy(buf, src + 1, 2);
- buf[2] = '\0';
- ih = strtol(buf, NULL, 16);
- next = (CHAR) ih;
- src += 2; /* Advance to end of escape */
- } else
- next = *src;
- if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
- *dst++ = next;
- }
- if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
- *dst = '\0';
- ret = S_OK;
- } else {
- needed++; /* add one for the '\0' */
- ret = E_POINTER;
- }
- if(!(dwFlags & URL_UNESCAPE_INPLACE))
- *pcchUnescaped = needed;
- if (ret == S_OK) {
- TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
- debugstr_a(pszUrl) : debugstr_a(pszUnescaped));
- }
- return ret;
- }
- /*************************************************************************
- * UrlUnescapeW [SHLWAPI.@]
- *
- * See UrlUnescapeA.
- */
- HRESULT WINAPI UrlUnescapeW(
- LPWSTR pszUrl,
- LPWSTR pszUnescaped,
- LPDWORD pcchUnescaped,
- DWORD dwFlags)
- {
- WCHAR *dst, next;
- LPCWSTR src;
- HRESULT ret;
- DWORD needed;
- BOOL stop_unescaping = FALSE;
- TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszUrl), pszUnescaped,
- pcchUnescaped, dwFlags);
- if(!pszUrl || !pszUnescaped || !pcchUnescaped)
- return E_INVALIDARG;
- if(dwFlags & URL_UNESCAPE_INPLACE)
- dst = pszUrl;
- else
- dst = pszUnescaped;
- for(src = pszUrl, needed = 0; *src; src++, needed++) {
- if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
- (*src == L'#' || *src == L'?')) {
- stop_unescaping = TRUE;
- next = *src;
- } else if(*src == L'%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2))
- && stop_unescaping == FALSE) {
- INT ih;
- WCHAR buf[5] = {'0','x',0};
- memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
- buf[4] = 0;
- StrToIntExW(buf, STIF_SUPPORT_HEX, &ih);
- next = (WCHAR) ih;
- src += 2; /* Advance to end of escape */
- } else
- next = *src;
- if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
- *dst++ = next;
- }
- if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
- *dst = L'\0';
- ret = S_OK;
- } else {
- needed++; /* add one for the '\0' */
- ret = E_POINTER;
- }
- if(!(dwFlags & URL_UNESCAPE_INPLACE))
- *pcchUnescaped = needed;
- if (ret == S_OK) {
- TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
- debugstr_w(pszUrl) : debugstr_w(pszUnescaped));
- }
- return ret;
- }
- /*************************************************************************
- * UrlGetLocationA [SHLWAPI.@]
- *
- * Get the location from a Url.
- *
- * PARAMS
- * pszUrl [I] Url to get the location from
- *
- * RETURNS
- * A pointer to the start of the location in pszUrl, or NULL if there is
- * no location.
- *
- * NOTES
- * - MSDN erroneously states that "The location is the segment of the Url
- * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll
- * stop at '?' and always return a NULL in this case.
- * - MSDN also erroneously states that "If a file URL has a query string,
- * the returned string is the query string". In all tested cases, if the
- * Url starts with "fi" then a NULL is returned. V5 gives the following results:
- *| Result Url
- *| ------ ---
- *| NULL file://aa/b/cd#hohoh
- *| #hohoh http://aa/b/cd#hohoh
- *| NULL fi://aa/b/cd#hohoh
- *| #hohoh ff://aa/b/cd#hohoh
- */
- LPCSTR WINAPI UrlGetLocationA(
- LPCSTR pszUrl)
- {
- PARSEDURLA base;
- DWORD res1;
- base.cbSize = sizeof(base);
- res1 = ParseURLA(pszUrl, &base);
- if (res1) return NULL; /* invalid scheme */
- /* if scheme is file: then never return pointer */
- if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL;
- /* Look for '#' and return its addr */
- return strchr(base.pszSuffix, '#');
- }
- /*************************************************************************
- * UrlGetLocationW [SHLWAPI.@]
- *
- * See UrlGetLocationA.
- */
- LPCWSTR WINAPI UrlGetLocationW(
- LPCWSTR pszUrl)
- {
- PARSEDURLW base;
- DWORD res1;
- base.cbSize = sizeof(base);
- res1 = ParseURLW(pszUrl, &base);
- if (res1) return NULL; /* invalid scheme */
- /* if scheme is file: then never return pointer */
- if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL;
- /* Look for '#' and return its addr */
- return strchrW(base.pszSuffix, L'#');
- }
- /*************************************************************************
- * UrlCompareA [SHLWAPI.@]
- *
- * Compare two Urls.
- *
- * PARAMS
- * pszUrl1 [I] First Url to compare
- * pszUrl2 [I] Url to compare to pszUrl1
- * fIgnoreSlash [I] TRUE = compare only up to a final slash
- *
- * RETURNS
- * less than zero, zero, or greater than zero indicating pszUrl2 is greater
- * than, equal to, or less than pszUrl1 respectively.
- */
- INT WINAPI UrlCompareA(
- LPCSTR pszUrl1,
- LPCSTR pszUrl2,
- BOOL fIgnoreSlash)
- {
- INT ret, len, len1, len2;
- if (!fIgnoreSlash)
- return strcmp(pszUrl1, pszUrl2);
- len1 = strlen(pszUrl1);
- if (pszUrl1[len1-1] == '/') len1--;
- len2 = strlen(pszUrl2);
- if (pszUrl2[len2-1] == '/') len2--;
- if (len1 == len2)
- return strncmp(pszUrl1, pszUrl2, len1);
- len = min(len1, len2);
- ret = strncmp(pszUrl1, pszUrl2, len);
- if (ret) return ret;
- if (len1 > len2) return 1;
- return -1;
- }
- /*************************************************************************
- * UrlCompareW [SHLWAPI.@]
- *
- * See UrlCompareA.
- */
- INT WINAPI UrlCompareW(
- LPCWSTR pszUrl1,
- LPCWSTR pszUrl2,
- BOOL fIgnoreSlash)
- {
- INT ret;
- size_t len, len1, len2;
- if (!fIgnoreSlash)
- return strcmpW(pszUrl1, pszUrl2);
- len1 = strlenW(pszUrl1);
- if (pszUrl1[len1-1] == '/') len1--;
- len2 = strlenW(pszUrl2);
- if (pszUrl2[len2-1] == '/') len2--;
- if (len1 == len2)
- return strncmpW(pszUrl1, pszUrl2, len1);
- len = min(len1, len2);
- ret = strncmpW(pszUrl1, pszUrl2, len);
- if (ret) return ret;
- if (len1 > len2) return 1;
- return -1;
- }
- /*************************************************************************
- * HashData [SHLWAPI.@]
- *
- * Hash an input block into a variable sized digest.
- *
- * PARAMS
- * lpSrc [I] Input block
- * nSrcLen [I] Length of lpSrc
- * lpDest [I] Output for hash digest
- * nDestLen [I] Length of lpDest
- *
- * RETURNS
- * Success: TRUE. lpDest is filled with the computed hash value.
- * Failure: FALSE, if any argument is invalid.
- */
- HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen,
- unsigned char *lpDest, DWORD nDestLen)
- {
- INT srcCount = nSrcLen - 1, destCount = nDestLen - 1;
- if (IsBadReadPtr(lpSrc, nSrcLen) ||
- IsBadWritePtr(lpDest, nDestLen))
- return E_INVALIDARG;
- while (destCount >= 0)
- {
- lpDest[destCount] = (destCount & 0xff);
- destCount--;
- }
- while (srcCount >= 0)
- {
- destCount = nDestLen - 1;
- while (destCount >= 0)
- {
- lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]];
- destCount--;
- }
- srcCount--;
- }
- return S_OK;
- }
- /*************************************************************************
- * UrlHashA [SHLWAPI.@]
- *
- * Produce a Hash from a Url.
- *
- * PARAMS
- * pszUrl [I] Url to hash
- * lpDest [O] Destinationh for hash
- * nDestLen [I] Length of lpDest
- *
- * RETURNS
- * Success: S_OK. lpDest is filled with the computed hash value.
- * Failure: E_INVALIDARG, if any argument is invalid.
- */
- HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
- {
- if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
- return E_INVALIDARG;
- HashData((const BYTE*)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen);
- return S_OK;
- }
- /*************************************************************************
- * UrlHashW [SHLWAPI.@]
- *
- * See UrlHashA.
- */
- HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
- {
- char szUrl[MAX_PATH];
- TRACE("(%s,%p,%ld)\n",debugstr_w(pszUrl), lpDest, nDestLen);
- if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
- return E_INVALIDARG;
- /* Win32 hashes the data as an ASCII string, presumably so that both A+W
- * return the same digests for the same URL.
- */
- WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0);
- HashData((const BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen);
- return S_OK;
- }
- /*************************************************************************
- * UrlApplySchemeA [SHLWAPI.@]
- *
- * Apply a scheme to a Url.
- *
- * PARAMS
- * pszIn [I] Url to apply scheme to
- * pszOut [O] Destination for modified Url
- * pcchOut [I/O] Length of pszOut/destination for length of pszOut
- * dwFlags [I] URL_ flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length.
- * Failure: An HRESULT error code describing the error.
- */
- HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
- {
- LPWSTR in, out;
- DWORD ret, len, len2;
- TRACE("(in %s, out size %ld, flags %08lx) using W version\n",
- debugstr_a(pszIn), *pcchOut, dwFlags);
- in = HeapAlloc(GetProcessHeap(), 0,
- (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
- out = in + INTERNET_MAX_URL_LENGTH;
- MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
- len = INTERNET_MAX_URL_LENGTH;
- ret = UrlApplySchemeW(in, out, &len, dwFlags);
- if ((ret != S_OK) && (ret != S_FALSE)) {
- HeapFree(GetProcessHeap(), 0, in);
- return ret;
- }
- len2 = WideCharToMultiByte(0, 0, out, len+1, 0, 0, 0, 0);
- if (len2 > *pcchOut) {
- *pcchOut = len2;
- HeapFree(GetProcessHeap(), 0, in);
- return E_POINTER;
- }
- WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0);
- *pcchOut = len2;
- HeapFree(GetProcessHeap(), 0, in);
- return ret;
- }
- static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
- {
- HKEY newkey;
- BOOL j;
- INT index;
- DWORD value_len, data_len, dwType, i;
- WCHAR reg_path[MAX_PATH];
- WCHAR value[MAX_PATH], data[MAX_PATH];
- WCHAR Wxx, Wyy;
- MultiByteToWideChar(0, 0,
- "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes",
- -1, reg_path, MAX_PATH);
- RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
- index = 0;
- while(value_len = data_len = MAX_PATH,
- RegEnumValueW(newkey, index, value, &value_len,
- 0, &dwType, (LPVOID)data, &data_len) == 0) {
- TRACE("guess %d %s is %s\n",
- index, debugstr_w(value), debugstr_w(data));
- j = FALSE;
- for(i=0; i<value_len; i++) {
- Wxx = pszIn[i];
- Wyy = value[i];
- /* remember that TRUE is not-equal */
- j = ChrCmpIW(Wxx, Wyy);
- if (j) break;
- }
- if ((i == value_len) && !j) {
- if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
- *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
- RegCloseKey(newkey);
- return E_POINTER;
- }
- strcpyW(pszOut, data);
- strcatW(pszOut, pszIn);
- *pcchOut = strlenW(pszOut);
- TRACE("matched and set to %s\n", debugstr_w(pszOut));
- RegCloseKey(newkey);
- return S_OK;
- }
- index++;
- }
- RegCloseKey(newkey);
- return -1;
- }
- static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
- {
- HKEY newkey;
- DWORD data_len, dwType;
- WCHAR reg_path[MAX_PATH];
- WCHAR value[MAX_PATH], data[MAX_PATH];
- /* get and prepend default */
- MultiByteToWideChar(0, 0,
- "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix",
- -1, reg_path, MAX_PATH);
- RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
- data_len = MAX_PATH;
- value[0] = L'@';
- value[1] = L'\0';
- RegQueryValueExW(newkey, value, 0, &dwType, (LPBYTE)data, &data_len);
- RegCloseKey(newkey);
- if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
- *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
- return E_POINTER;
- }
- strcpyW(pszOut, data);
- strcatW(pszOut, pszIn);
- *pcchOut = strlenW(pszOut);
- TRACE("used default %s\n", debugstr_w(pszOut));
- return S_OK;
- }
- /*************************************************************************
- * UrlApplySchemeW [SHLWAPI.@]
- *
- * See UrlApplySchemeA.
- */
- HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
- {
- PARSEDURLW in_scheme;
- DWORD res1;
- HRESULT ret;
- TRACE("(in %s, out size %ld, flags %08lx)\n",
- debugstr_w(pszIn), *pcchOut, dwFlags);
- if (dwFlags & URL_APPLY_GUESSFILE) {
- FIXME("(%s %p %p(%ld) 0x%08lx): stub URL_APPLY_GUESSFILE not implemented\n",
- debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags);
- strcpyW(pszOut, pszIn);
- *pcchOut = strlenW(pszOut);
- return S_FALSE;
- }
- in_scheme.cbSize = sizeof(in_scheme);
- /* See if the base has a scheme */
- res1 = ParseURLW(pszIn, &in_scheme);
- if (res1) {
- /* no scheme in input, need to see if we need to guess */
- if (dwFlags & URL_APPLY_GUESSSCHEME) {
- if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != -1)
- return ret;
- }
- }
- else {
- /* we have a scheme, see if valid (known scheme) */
- if (in_scheme.nScheme) {
- /* have valid scheme, so just copy and exit */
- if (strlenW(pszIn) + 1 > *pcchOut) {
- *pcchOut = strlenW(pszIn) + 1;
- return E_POINTER;
- }
- strcpyW(pszOut, pszIn);
- *pcchOut = strlenW(pszOut);
- TRACE("valid scheme, returing copy\n");
- return S_OK;
- }
- }
- /* If we are here, then either invalid scheme,
- * or no scheme and can't/failed guess.
- */
- if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) ||
- ((res1 != 0)) ) &&
- (dwFlags & URL_APPLY_DEFAULT)) {
- /* find and apply default scheme */
- return URL_ApplyDefault(pszIn, pszOut, pcchOut);
- }
- /* just copy and give proper return code */
- if (strlenW(pszIn) + 1 > *pcchOut) {
- *pcchOut = strlenW(pszIn) + 1;
- return E_POINTER;
- }
- strcpyW(pszOut, pszIn);
- *pcchOut = strlenW(pszOut);
- TRACE("returning copy, left alone\n");
- return S_FALSE;
- }
- /*************************************************************************
- * UrlIsA [SHLWAPI.@]
- *
- * Determine if a Url is of a certain class.
- *
- * PARAMS
- * pszUrl [I] Url to check
- * Urlis [I] URLIS_ constant from "shlwapi.h"
- *
- * RETURNS
- * TRUE if pszUrl belongs to the class type in Urlis.
- * FALSE Otherwise.
- */
- BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis)
- {
- PARSEDURLA base;
- DWORD res1;
- LPCSTR last;
- TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis);
- switch (Urlis) {
- case URLIS_OPAQUE:
- base.cbSize = sizeof(base);
- res1 = ParseURLA(pszUrl, &base);
- if (res1) return FALSE; /* invalid scheme */
- if ((*base.pszSuffix == '/') && (*(base.pszSuffix+1) == '/'))
- /* has scheme followed by 2 '/' */
- return FALSE;
- return TRUE;
- case URLIS_FILEURL:
- return !StrCmpNA("file://", pszUrl, 7);
- case URLIS_DIRECTORY:
- last = pszUrl + strlen(pszUrl) - 1;
- return (last >= pszUrl && (*last == '/' || *last == '\\' ));
- case URLIS_URL:
- return PathIsURLA(pszUrl);
- case URLIS_NOHISTORY:
- case URLIS_APPLIABLE:
- case URLIS_HASQUERY:
- default:
- FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis);
- }
- return FALSE;
- }
- /*************************************************************************
- * UrlIsW [SHLWAPI.@]
- *
- * See UrlIsA.
- */
- BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis)
- {
- static const WCHAR stemp[] = { 'f','i','l','e',':','/','/',0 };
- PARSEDURLW base;
- DWORD res1;
- LPCWSTR last;
- TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis);
- switch (Urlis) {
- case URLIS_OPAQUE:
- base.cbSize = sizeof(base);
- res1 = ParseURLW(pszUrl, &base);
- if (res1) return FALSE; /* invalid scheme */
- if ((*base.pszSuffix == '/') && (*(base.pszSuffix+1) == '/'))
- /* has scheme followed by 2 '/' */
- return FALSE;
- return TRUE;
- case URLIS_FILEURL:
- return !strncmpW(stemp, pszUrl, 7);
- case URLIS_DIRECTORY:
- last = pszUrl + strlenW(pszUrl) - 1;
- return (last >= pszUrl && (*last == '/' || *last == '\\'));
- case URLIS_URL:
- return PathIsURLW(pszUrl);
- case URLIS_NOHISTORY:
- case URLIS_APPLIABLE:
- case URLIS_HASQUERY:
- default:
- FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis);
- }
- return FALSE;
- }
- /*************************************************************************
- * UrlIsNoHistoryA [SHLWAPI.@]
- *
- * Determine if a Url should not be stored in the users history list.
- *
- * PARAMS
- * pszUrl [I] Url to check
- *
- * RETURNS
- * TRUE, if pszUrl should be excluded from the history list,
- * FALSE otherwise.
- */
- BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl)
- {
- return UrlIsA(pszUrl, URLIS_NOHISTORY);
- }
- /*************************************************************************
- * UrlIsNoHistoryW [SHLWAPI.@]
- *
- * See UrlIsNoHistoryA.
- */
- BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl)
- {
- return UrlIsW(pszUrl, URLIS_NOHISTORY);
- }
- /*************************************************************************
- * UrlIsOpaqueA [SHLWAPI.@]
- *
- * Determine if a Url is opaque.
- *
- * PARAMS
- * pszUrl [I] Url to check
- *
- * RETURNS
- * TRUE if pszUrl is opaque,
- * FALSE Otherwise.
- *
- * NOTES
- * An opaque Url is one that does not start with "<protocol>://".
- */
- BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl)
- {
- return UrlIsA(pszUrl, URLIS_OPAQUE);
- }
- /*************************************************************************
- * UrlIsOpaqueW [SHLWAPI.@]
- *
- * See UrlIsOpaqueA.
- */
- BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl)
- {
- return UrlIsW(pszUrl, URLIS_OPAQUE);
- }
- /*************************************************************************
- * Scans for characters of type "type" and when not matching found,
- * returns pointer to it and length in size.
- *
- * Characters tested based on RFC 1738
- */
- static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type)
- {
- static DWORD alwayszero = 0;
- BOOL cont = TRUE;
- *size = 0;
- switch(type){
- case SCHEME:
- while (cont) {
- if ( (islowerW(*start) && isalphaW(*start)) ||
- isdigitW(*start) ||
- (*start == L'+') ||
- (*start == L'-') ||
- (*start == L'.')) {
- start++;
- (*size)++;
- }
- else
- cont = FALSE;
- }
- break;
- case USERPASS:
- while (cont) {
- if ( isalphaW(*start) ||
- isdigitW(*start) ||
- /* user/password only characters */
- (*start == L';') ||
- (*start == L'?') ||
- (*start == L'&') ||
- (*start == L'=') ||
- /* *extra* characters */
- (*start == L'!') ||
- (*start == L'*') ||
- (*start == L'\'') ||
- (*start == L'(') ||
- (*start == L')') ||
- (*start == L',') ||
- /* *safe* characters */
- (*start == L'$') ||
- (*start == L'_') ||
- (*start == L'+') ||
- (*start == L'-') ||
- (*start == L'.')) {
- start++;
- (*size)++;
- } else if (*start == L'%') {
- if (isxdigitW(*(start+1)) &&
- isxdigitW(*(start+2))) {
- start += 3;
- *size += 3;
- } else
- cont = FALSE;
- } else
- cont = FALSE;
- }
- break;
- case PORT:
- while (cont) {
- if (isdigitW(*start)) {
- start++;
- (*size)++;
- }
- else
- cont = FALSE;
- }
- break;
- case HOST:
- while (cont) {
- if (isalnumW(*start) ||
- (*start == L'-') ||
- (*start == L'.') ) {
- start++;
- (*size)++;
- }
- else
- cont = FALSE;
- }
- break;
- default:
- FIXME("unknown type %d\n", type);
- return (LPWSTR)&alwayszero;
- }
- /* TRACE("scanned %ld characters next char %p<%c>\n",
- *size, start, *start); */
- return start;
- }
- /*************************************************************************
- * Attempt to parse URL into pieces.
- */
- static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl)
- {
- LPCWSTR work;
- memset(pl, 0, sizeof(WINE_PARSE_URL));
- pl->pScheme = pszUrl;
- work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME);
- if (!*work || (*work != L':')) goto ErrorExit;
- work++;
- if ((*work != L'/') || (*(work+1) != L'/')) goto ErrorExit;
- pl->pUserName = work + 2;
- work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS);
- if (*work == L':' ) {
- /* parse password */
- work++;
- pl->pPassword = work;
- work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS);
- if (*work != L'@') {
- /* what we just parsed must be the hostname and port
- * so reset pointers and clear then let it parse */
- pl->szUserName = pl->szPassword = 0;
- work = pl->pUserName - 1;
- pl->pUserName = pl->pPassword = 0;
- }
- } else if (*work == L'@') {
- /* no password */
- pl->szPassword = 0;
- pl->pPassword = 0;
- } else if (!*work || (*work == L'/') || (*work == L'.')) {
- /* what was parsed was hostname, so reset pointers and let it parse */
- pl->szUserName = pl->szPassword = 0;
- work = pl->pUserName - 1;
- pl->pUserName = pl->pPassword = 0;
- } else goto ErrorExit;
- /* now start parsing hostname or hostnumber */
- work++;
- pl->pHostName = work;
- work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST);
- if (*work == L':') {
- /* parse port */
- work++;
- pl->pPort = work;
- work = URL_ScanID(pl->pPort, &pl->szPort, PORT);
- }
- if (*work == L'/') {
- /* see if query string */
- pl->pQuery = strchrW(work, L'?');
- if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery);
- }
- TRACE("parse successful: scheme=%p(%ld), user=%p(%ld), pass=%p(%ld), host=%p(%ld), port=%p(%ld), query=%p(%ld)\n",
- pl->pScheme, pl->szScheme,
- pl->pUserName, pl->szUserName,
- pl->pPassword, pl->szPassword,
- pl->pHostName, pl->szHostName,
- pl->pPort, pl->szPort,
- pl->pQuery, pl->szQuery);
- return S_OK;
- ErrorExit:
- FIXME("failed to parse %s\n", debugstr_w(pszUrl));
- return E_INVALIDARG;
- }
- /*************************************************************************
- * UrlGetPartA [SHLWAPI.@]
- *
- * Retrieve part of a Url.
- *
- * PARAMS
- * pszIn [I] Url to parse
- * pszOut [O] Destination for part of pszIn requested
- * pcchOut [I/O] Length of pszOut/destination for length of pszOut
- * dwPart [I] URL_PART_ enum from "shlwapi.h"
- * dwFlags [I] URL_ flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK. pszOut contains the part requested, pcchOut contains its length.
- * Failure: An HRESULT error code describing the error.
- */
- HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut,
- DWORD dwPart, DWORD dwFlags)
- {
- LPWSTR in, out;
- DWORD ret, len, len2;
- in = HeapAlloc(GetProcessHeap(), 0,
- (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
- out = in + INTERNET_MAX_URL_LENGTH;
- MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
- len = INTERNET_MAX_URL_LENGTH;
- ret = UrlGetPartW(in, out, &len, dwPart, dwFlags);
- if (ret != S_OK) {
- HeapFree(GetProcessHeap(), 0, in);
- return ret;
- }
- len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0);
- if (len2 > *pcchOut) {
- *pcchOut = len2;
- HeapFree(GetProcessHeap(), 0, in);
- return E_POINTER;
- }
- WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0);
- *pcchOut = len2;
- HeapFree(GetProcessHeap(), 0, in);
- return S_OK;
- }
- /*************************************************************************
- * UrlGetPartW [SHLWAPI.@]
- *
- * See UrlGetPartA.
- */
- HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut,
- DWORD dwPart, DWORD dwFlags)
- {
- WINE_PARSE_URL pl;
- HRESULT ret;
- DWORD size, schsize;
- LPCWSTR addr, schaddr;
- LPWSTR work;
- TRACE("(%s %p %p(%ld) %08lx %08lx)\n",
- debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags);
- ret = URL_ParseUrl(pszIn, &pl);
- if (!ret) {
- schaddr = pl.pScheme;
- schsize = pl.szScheme;
- switch (dwPart) {
- case URL_PART_SCHEME:
- if (!pl.szScheme) return E_INVALIDARG;
- addr = pl.pScheme;
- size = pl.szScheme;
- break;
- case URL_PART_HOSTNAME:
- if (!pl.szHostName) return E_INVALIDARG;
- addr = pl.pHostName;
- size = pl.szHostName;
- break;
- case URL_PART_USERNAME:
- if (!pl.szUserName) return E_INVALIDARG;
- addr = pl.pUserName;
- size = pl.szUserName;
- break;
- case URL_PART_PASSWORD:
- if (!pl.szPassword) return E_INVALIDARG;
- addr = pl.pPassword;
- size = pl.szPassword;
- break;
- case URL_PART_PORT:
- if (!pl.szPort) return E_INVALIDARG;
- addr = pl.pPort;
- size = pl.szPort;
- break;
- case URL_PART_QUERY:
- if (!pl.szQuery) return E_INVALIDARG;
- addr = pl.pQuery;
- size = pl.szQuery;
- break;
- default:
- return E_INVALIDARG;
- }
- if (dwFlags == URL_PARTFLAG_KEEPSCHEME) {
- if (*pcchOut < size + schsize + 2) {
- *pcchOut = size + schsize + 2;
- return E_POINTER;
- }
- strncpyW(pszOut, schaddr, schsize);
- work = pszOut + schsize;
- *work = L':';
- strncpyW(work+1, addr, size);
- *pcchOut = size + schsize + 1;
- work += (size + 1);
- *work = L'\0';
- }
- else {
- if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;}
- strncpyW(pszOut, addr, size);
- *pcchOut = size;
- work = pszOut + size;
- *work = L'\0';
- }
- TRACE("len=%ld %s\n", *pcchOut, debugstr_w(pszOut));
- }
- return ret;
- }
- /*************************************************************************
- * PathIsURLA [SHLWAPI.@]
- *
- * Check if the given path is a Url.
- *
- * PARAMS
- * lpszPath [I] Path to check.
- *
- * RETURNS
- * TRUE if lpszPath is a Url.
- * FALSE if lpszPath is NULL or not a Url.
- */
- BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
- {
- PARSEDURLA base;
- DWORD res1;
- if (!lpstrPath || !*lpstrPath) return FALSE;
- /* get protocol */
- base.cbSize = sizeof(base);
- res1 = ParseURLA(lpstrPath, &base);
- return (base.nScheme != URL_SCHEME_INVALID);
- }
- /*************************************************************************
- * PathIsURLW [SHLWAPI.@]
- *
- * See PathIsURLA.
- */
- BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
- {
- PARSEDURLW base;
- DWORD res1;
- if (!lpstrPath || !*lpstrPath) return FALSE;
- /* get protocol */
- base.cbSize = sizeof(base);
- res1 = ParseURLW(lpstrPath, &base);
- return (base.nScheme != URL_SCHEME_INVALID);
- }
- /*************************************************************************
- * UrlCreateFromPathA [SHLWAPI.@]
- *
- * See UrlCreateFromPathW
- */
- HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
- {
- WCHAR bufW[INTERNET_MAX_URL_LENGTH];
- WCHAR *urlW = bufW;
- UNICODE_STRING pathW;
- HRESULT ret;
- DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
- if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath))
- return E_INVALIDARG;
- if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) {
- urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
- ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved);
- }
- if(ret == S_OK || ret == S_FALSE) {
- RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR));
- if(*pcchUrl > lenA) {
- RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR));
- pszUrl[lenA] = 0;
- *pcchUrl = lenA;
- } else {
- *pcchUrl = lenA + 1;
- ret = E_POINTER;
- }
- }
- if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW);
- RtlFreeUnicodeString(&pathW);
- return ret;
- }
- /*************************************************************************
- * UrlCreateFromPathW [SHLWAPI.@]
- *
- * Create a Url from a file path.
- *
- * PARAMS
- * pszPath [I] Path to convert
- * pszUrl [O] Destination for the converted Url
- * pcchUrl [I/O] Length of pszUrl
- * dwReserved [I] Reserved, must be 0
- *
- * RETURNS
- * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url
- * Failure: An HRESULT error code.
- */
- HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
- {
- DWORD needed;
- HRESULT ret;
- WCHAR *pszNewUrl;
- WCHAR file_colonW[] = {'f','i','l','e',':',0};
- WCHAR three_slashesW[] = {'/','/','/',0};
- PARSEDURLW parsed_url;
- TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved);
- /* Validate arguments */
- if (dwReserved != 0)
- return E_INVALIDARG;
- if (!pszUrl || !pcchUrl)
- return E_INVALIDARG;
- parsed_url.cbSize = sizeof(parsed_url);
- if(ParseURLW(pszPath, &parsed_url) == S_OK) {
- if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) {
- needed = strlenW(pszPath);
- if (needed >= *pcchUrl) {
- *pcchUrl = needed + 1;
- return E_POINTER;
- } else {
- *pcchUrl = needed;
- strcpyW(pszUrl, pszPath);
- return S_FALSE;
- }
- }
- }
- pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */
- strcpyW(pszNewUrl, file_colonW);
- if(isalphaW(pszPath[0]) && pszPath[1] == ':')
- strcatW(pszNewUrl, three_slashesW);
- strcatW(pszNewUrl, pszPath);
- ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT);
- HeapFree(GetProcessHeap(), 0, pszNewUrl);
- return ret;
- }
- /*************************************************************************
- * SHAutoComplete [SHLWAPI.@]
- *
- * Enable auto-completion for an edit control.
- *
- * PARAMS
- * hwndEdit [I] Handle of control to enable auto-completion for
- * dwFlags [I] SHACF_ flags from "shlwapi.h"
- *
- * RETURNS
- * Success: S_OK. Auto-completion is enabled for the control.
- * Failure: An HRESULT error code indicating the error.
- */
- HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags)
- {
- FIXME("SHAutoComplete stub\n");
- return S_FALSE;
- }
- /*************************************************************************
- * MLBuildResURLA [SHLWAPI.405]
- *
- * Create a Url pointing to a resource in a module.
- *
- * PARAMS
- * lpszLibName [I] Name of the module containing the resource
- * hMod [I] Callers module handle
- * dwFlags [I] Undocumented flags for loading the module
- * lpszRes [I] Resource name
- * lpszDest [O] Destination for resulting Url
- * dwDestLen [I] Length of lpszDest
- *
- * RETURNS
- * Success: S_OK. lpszDest constains the resource Url.
- * Failure: E_INVALIDARG, if any argument is invalid, or
- * E_FAIL if dwDestLen is too small.
- */
- HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
- LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen)
- {
- WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH];
- HRESULT hRet;
- if (lpszLibName)
- MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR));
- if (lpszRes)
- MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR));
- if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR))
- dwDestLen = sizeof(szLibName)/sizeof(WCHAR);
- hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags,
- lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen);
- if (SUCCEEDED(hRet) && lpszDest)
- WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, 0, 0);
- return hRet;
- }
- /*************************************************************************
- * MLBuildResURLA [SHLWAPI.406]
- *
- * See MLBuildResURLA.
- */
- HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
- LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen)
- {
- static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' };
- #define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR))
- HRESULT hRet = E_FAIL;
- TRACE("(%s,%p,0x%08lx,%s,%p,%ld)\n", debugstr_w(lpszLibName), hMod, dwFlags,
- debugstr_w(lpszRes), lpszDest, dwDestLen);
- if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes ||
- !lpszDest || (dwFlags && dwFlags != 2))
- return E_INVALIDARG;
- if (dwDestLen >= szResLen + 1)
- {
- dwDestLen -= (szResLen + 1);
- memcpy(lpszDest, szRes, sizeof(szRes));
- hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags);
- if (hMod)
- {
- WCHAR szBuff[MAX_PATH];
- DWORD len;
- len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR));
- if (len && len < sizeof(szBuff)/sizeof(WCHAR))
- {
- DWORD dwPathLen = strlenW(szBuff) + 1;
- if (dwDestLen >= dwPathLen)
- {
- DWORD dwResLen;
- dwDestLen -= dwPathLen;
- memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR));
- dwResLen = strlenW(lpszRes) + 1;
- if (dwDestLen >= dwResLen + 1)
- {
- lpszDest[szResLen + dwPathLen + dwResLen] = '/';
- memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR));
- hRet = S_OK;
- }
- }
- }
- MLFreeLibrary(hMod);
- }
- }
- return hRet;
- }
|