|
|
/*****************************************************************************
* * ftpurl.cpp - Creating, encoding, and decoding URLs * *****************************************************************************/
#include "priv.h"
#include "ftpurl.h"
///////////////////////////////////////////////////////////////////////
// URL Path Functions (Obsolete?)
///////////////////////////////////////////////////////////////////////
/*****************************************************************************\
FUNCTION: UrlGetPath
DESCRIPTION: pszUrlPath will NOT include the fragment if there is any. \*****************************************************************************/ HRESULT UrlGetDifference(LPCTSTR pszBaseUrl, LPCTSTR pszSuperUrl, LPTSTR pszPathDiff, DWORD cchSize) { HRESULT hr = E_INVALIDARG;
pszPathDiff[0] = TEXT('\0'); if ((lstrlen(pszBaseUrl) <= lstrlen(pszSuperUrl)) && !StrCmpN(pszBaseUrl, pszSuperUrl, lstrlen(pszBaseUrl) - 1)) { LPTSTR pszDelta = (LPTSTR) &pszSuperUrl[lstrlen(pszBaseUrl)];
if (TEXT('/') == pszDelta[0]) pszDelta = CharNext(pszDelta); // Skip past this.
StrCpyN(pszPathDiff, pszDelta, cchSize); hr = S_OK; }
return hr; }
/*****************************************************************************\
FUNCTION: UrlGetPath
DESCRIPTION: pszUrlPath will NOT include the fragment if there is any. \*****************************************************************************/ HRESULT UrlPathToFilePath(LPCTSTR pszSourceUrlPath, LPTSTR pszDestFilePath, DWORD cchSize) { HRESULT hr = E_INVALIDARG; LPTSTR pszSeparator;
// Is the source and destination the differnt?
if (pszSourceUrlPath != pszDestFilePath) { // Yes, so we need to fill the dest before we start modifying it.
StrCpyN(pszDestFilePath, pszSourceUrlPath, cchSize); }
while (pszSeparator = StrChr(pszDestFilePath, TEXT('/'))) pszSeparator[0] = TEXT('\\');
// Some people use "Test%20File.txt" when "%20" is really in the file name.
// ASSERT(!StrChr(pszDestFilePath, TEXT('%'))); // Assert it doesn't contain '%' or it probably has escaped url stuff.
return hr; }
/*****************************************************************************\
FUNCTION: UrlPathRemoveSlashW
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathRemoveSlashW(LPWSTR pszUrlPath) { LPWSTR pszEndOfPath = &pszUrlPath[lstrlenW(pszUrlPath) - 1];
// Is it missing a backslash?
if ((pszEndOfPath >= pszUrlPath) && (CH_URL_URL_SLASHW == pszEndOfPath[0])) pszEndOfPath[0] = 0; // Yes, so remove it.
return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathRemoveSlashA
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathRemoveSlashA(LPSTR pszUrlPath) { LPSTR pszEndOfPath = &pszUrlPath[lstrlenA(pszUrlPath) - 1];
// Is it missing a backslash?
if ((pszEndOfPath >= pszUrlPath) && (CH_URL_URL_SLASHA == pszEndOfPath[0])) pszEndOfPath[0] = 0; // Yes, so remove it.
return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathRemoveFrontSlashW
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathRemoveFrontSlashW(LPWSTR pszUrlPath) { if (pszUrlPath && (CH_URL_URL_SLASHW == pszUrlPath[0])) return CharReplaceWithStrW(pszUrlPath, lstrlen(pszUrlPath), 1, SZ_EMPTYW); else return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathRemoveFrontSlashA
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathRemoveFrontSlashA(LPSTR pszUrlPath) { if (pszUrlPath && (CH_URL_URL_SLASHA == pszUrlPath[0])) return CharReplaceWithStrA(pszUrlPath, lstrlenA(pszUrlPath), 1, SZ_EMPTYA); else return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathToFilePathW
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathToFilePathW(LPWSTR pszPath) { while (pszPath = StrChrW(pszPath, CH_URL_URL_SLASHW)) pszPath[0] = CH_URL_SLASHW;
return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathToFilePathA
DESCRIPTION: \*****************************************************************************/ HRESULT UrlPathToFilePathA(LPSTR pszPath) { while (pszPath = StrChrA(pszPath, CH_URL_URL_SLASHA)) pszPath[0] = CH_URL_SLASHA;
return S_OK; }
/*****************************************************************************\
FUNCTION: FilePathToUrlPathW
DESCRIPTION: \*****************************************************************************/ HRESULT FilePathToUrlPathW(LPWSTR pszPath) { while (pszPath = StrChrW(pszPath, CH_URL_SLASHW)) pszPath[0] = CH_URL_URL_SLASHW;
return S_OK; }
/*****************************************************************************\
FUNCTION: FilePathToUrlPathA
DESCRIPTION: \*****************************************************************************/ HRESULT FilePathToUrlPathA(LPSTR pszPath) { while (pszPath = StrChrA(pszPath, CH_URL_SLASHA)) pszPath[0] = CH_URL_URL_SLASHA;
return S_OK; }
/*****************************************************************************\
FUNCTION: UrlPathAdd
DESCRIPTION: ... \*****************************************************************************/ HRESULT UrlPathAdd(LPTSTR pszUrl, DWORD cchUrlSize, LPCTSTR pszSegment) { // If the segment starts with a slash, skip it.
if (TEXT('/') == pszSegment[0]) pszSegment = CharNext(pszSegment);
StrCatBuff(pszUrl, pszSegment, cchUrlSize);
return S_OK; }
/*****************************************************************************\
StrRetFromFtpPidl \*****************************************************************************/ HRESULT StrRetFromFtpPidl(LPSTRRET pStrRet, DWORD shgno, LPCITEMIDLIST pidl) { HRESULT hr = S_OK; TCHAR szUrl[MAX_URL_STRING];
szUrl[0] = 0; hr = UrlCreateFromPidl(pidl, shgno, szUrl, ARRAYSIZE(szUrl), ICU_ESCAPE | ICU_USERNAME, TRUE); if (SUCCEEDED(hr)) { // Will it fit into STRRET.cStr?
if (lstrlen(szUrl) < ARRAYSIZE(pStrRet->cStr)) { // Yes, so there it goes...
pStrRet->uType = STRRET_CSTR; SHTCharToAnsi(szUrl, pStrRet->cStr, ARRAYSIZE(pStrRet->cStr)); } else { // No, so we will need to allocate it
LPWSTR pwzAllocedStr = NULL; UINT cch = lstrlen(szUrl) + 1;
pwzAllocedStr = (LPWSTR) SHAlloc(CbFromCchW(cch)); pStrRet->uType = STRRET_WSTR; pStrRet->pOleStr = pwzAllocedStr; if (pwzAllocedStr) SHTCharToUnicode(szUrl, pwzAllocedStr, cch); else hr = E_OUTOFMEMORY; } }
return hr; }
/*****************************************************************************\
FUNCTION: GetLastSegment
DESCRIPTION: \*****************************************************************************/ LPTSTR GetLastSegment(LPCTSTR pszUrl) { LPTSTR pszLastSeg = (LPTSTR) pszUrl; LPTSTR pszNextPossibleSeg;
while (pszNextPossibleSeg = StrChr(pszLastSeg, TEXT('/'))) { if (TEXT('\0') != CharNext(pszNextPossibleSeg)) pszLastSeg = CharNext(pszNextPossibleSeg); else break; // We are done.
}
if (TEXT('/') == pszLastSeg[0]) pszLastSeg = CharNext(pszLastSeg);
return pszLastSeg; }
/*****************************************************************************\
FUNCTION: UrlRemoveDownloadType
DESCRIPTION: \*****************************************************************************/ HRESULT UrlRemoveDownloadType(LPTSTR pszUrlPath, BOOL * pfTypeSpecified, BOOL * pfType) { HRESULT hr = S_FALSE; // Specified? (Not yet)
LPTSTR pszDownloadType;
if (pfTypeSpecified) *pfTypeSpecified = TRUE;
// Did the user specify a download type. szPath="Dir1/Dir2/file.txt;type=a".
// TODO: Search Recursively because each segment in the path can have a
// type.
// Example Url="ftp://server/Dir1;type=a/Dir2;type=a/File.txt;type=b
if (pszDownloadType = StrStrI(pszUrlPath, SZ_FTP_URL_TYPE)) { TCHAR chType;
if (pfTypeSpecified) *pfTypeSpecified = TRUE;
pszDownloadType[0] = TEXT('\0'); // Terminate pszUrlPath and remove this junk.
chType = pszDownloadType[ARRAYSIZE(SZ_FTP_URL_TYPE) - 1];
if (pfType) { if ((TEXT('a') == chType) || (TEXT('A') == chType)) *pfType = TRUE; else *pfType = TRUE; }
hr = S_OK; }
return hr; }
/*****************************************************************************\
FUNCTION: IsIPAddressStr
DESCRIPTION: This function exists to detect an IP Address server name ("124.42.3.53") vs. a DNS domain name ("foobar", or "ftp.foobar.com"). I current accept more than 4 segments because of 6-bit IP address.
TODO: To be thurough, I should probably made sure each segment is smaller than 256. \*****************************************************************************/ BOOL IsIPAddressStr(LPTSTR pszServer) { BOOL fIsIPAddressStr = TRUE; LPTSTR pszCurrentChar = pszServer; int nDigits = 0; int nSegments = 1;
while (fIsIPAddressStr && pszCurrentChar[0]) { if (TEXT('.') == pszCurrentChar[0]) { nSegments++; if ((0 == nDigits) || (4 < nDigits)) fIsIPAddressStr = FALSE; // it started with a '.', ie, ".xxxxx"
nDigits = 0; }
nDigits++; if (nDigits > 4) fIsIPAddressStr = FALSE; // To many digits, ie "12345.xxxx"
if (((TEXT('0') > pszCurrentChar[0]) || (TEXT('9') < pszCurrentChar[0])) && (TEXT('.') != pszCurrentChar[0])) { fIsIPAddressStr = FALSE; // it's outside of the 0-9 range.
}
pszCurrentChar++; // Next character.
}
if (nSegments != 4) fIsIPAddressStr = FALSE; // Needs to have at least 4 segments ("1.2.3.4", "1.2.3.4.5")
return fIsIPAddressStr; }
/*****************************************************************************\
FUNCTION: PidlGenerateSiteLookupStr
DESCRIPTION: Sample Input: "ftp://user:[email protected]:69/Dir1/Dir2/File.txt" Sample Output: "ftp://user:[email protected]:69/"
This is used to keep track of unique servers for CFtpSite. A CFtpSite needs to be created for each unique site, which includes different users that are logged onto the same site because of rooted directories. \*****************************************************************************/ HRESULT PidlGenerateSiteLookupStr(LPCITEMIDLIST pidl, LPTSTR pszLookupStr, DWORD cchSize) { HRESULT hr = E_FAIL;
// Some strange clients pass in non-Server IDs, like comdlg.
if (FtpID_IsServerItemID(pidl)) { LPITEMIDLIST pidlServer = FtpCloneServerID(pidl); if (pidlServer) { hr = UrlCreateFromPidlW(pidlServer, SHGDN_FORPARSING, pszLookupStr, cchSize, (ICU_ESCAPE | ICU_USERNAME), FALSE); ILFree(pidlServer); } else hr = E_OUTOFMEMORY; }
return hr; }
HRESULT PidlReplaceUserPassword(LPCITEMIDLIST pidlIn, LPITEMIDLIST * ppidlOut, IMalloc * pm, LPCTSTR pszUserName, LPCTSTR pszPassword) { TCHAR szServer[INTERNET_MAX_HOST_NAME_LENGTH]; TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH]; HRESULT hr = FtpPidl_GetServer(pidlIn, szServer, ARRAYSIZE(szServer));
if (!pszUserName) // May be NULL.
{ pszUserName = szUserName; EVAL(SUCCEEDED(FtpPidl_GetUserName(pidlIn, szUserName, ARRAYSIZE(szUserName)))); }
*ppidlOut = NULL; if (SUCCEEDED(hr)) { LPITEMIDLIST pidlServer;
hr = FtpServerID_Create(szServer, pszUserName, pszPassword, FtpServerID_GetTypeID(pidlIn), FtpServerID_GetPortNum(pidlIn), &pidlServer, pm, TRUE); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlFtpPath = _ILNext(pidlIn);
*ppidlOut = ILCombine(pidlServer, pidlFtpPath); ILFree(pidlServer); } }
return hr; }
HRESULT UrlReplaceUserPassword(LPTSTR pszUrlPath, DWORD cchSize, LPCTSTR pszUserName, LPCTSTR pszPassword) { HRESULT hr = E_FAIL; URL_COMPONENTS urlComps = {0}; TCHAR szServer[INTERNET_MAX_HOST_NAME_LENGTH]; TCHAR szUrlPath[MAX_URL_STRING]; TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH]; TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH]; TCHAR szExtraInfo[MAX_PATH]; // Includes Port Number and download type (ASCII, Binary, Detect)
BOOL fResult;
urlComps.dwStructSize = sizeof(urlComps); urlComps.lpszHostName = szServer; urlComps.dwHostNameLength = ARRAYSIZE(szServer); urlComps.lpszUrlPath = szUrlPath; urlComps.dwUrlPathLength = ARRAYSIZE(szUrlPath); urlComps.lpszExtraInfo = szExtraInfo; urlComps.dwExtraInfoLength = ARRAYSIZE(szExtraInfo);
urlComps.lpszUserName = szUserName; urlComps.dwUserNameLength = ARRAYSIZE(szUserName); urlComps.lpszPassword = szPassword; urlComps.dwPasswordLength = ARRAYSIZE(szPassword);
fResult = InternetCrackUrl(pszUrlPath, 0, ICU_DECODE, &urlComps); if (fResult) { urlComps.dwStructSize = sizeof(urlComps); urlComps.lpszHostName = szServer;
urlComps.lpszUserName = (LPTSTR)(pszUserName ? pszUserName : szUserName); urlComps.dwUserNameLength = (pszUserName ? lstrlen(pszUserName) : lstrlen(szUserName)); urlComps.lpszPassword = (LPTSTR)pszPassword; // It may be valid for caller to pass NULL
urlComps.dwPasswordLength = (pszPassword ? lstrlen(pszPassword) : 0); urlComps.lpszExtraInfo = szExtraInfo; urlComps.dwExtraInfoLength = ARRAYSIZE(szExtraInfo);
fResult = InternetCreateUrl(&urlComps, (ICU_ESCAPE_AUTHORITY | ICU_ESCAPE | ICU_USERNAME), pszUrlPath, &cchSize); if (fResult) { hr = S_OK; } }
return hr; }
// InternetCreateUrlW() will write into pszUrl but won't terminate the string.
// This is hard to detect because half the time the place where the terminator should
// go may coincidentally contain a terminator. This code forces the bug to happen.
#define TEST_FOR_INTERNETCREATEURL_BUG 1
#define INTERNETCREATEURL_BUG_WORKAROUND 1
HRESULT UrlCreateEx(LPCTSTR pszServer, LPCTSTR pszUser, LPCTSTR pszPassword, LPCTSTR pszUrlPath, LPCTSTR pszFragment, INTERNET_PORT ipPortNum, LPCTSTR pszDownloadType, LPTSTR pszUrl, DWORD cchSize, DWORD dwFlags) { HRESULT hr = E_FAIL; DWORD cchSizeCopy = cchSize;
#if DEBUG && TEST_FOR_INTERNETCREATEURL_BUG
LPTSTR pszDebugStr = pszUrl; for (DWORD dwIndex = (cchSize - 2); dwIndex; dwIndex--) { #ifndef INTERNETCREATEURL_BUG_WORKAROUND
pszDebugStr[0] = -1; // This will force a buffer w/o terminators.
#else // INTERNETCREATEURL_BUG_WORKAROUND
pszDebugStr[0] = 0; // This will work around the bug.
#endif // INTERNETCREATEURL_BUG_WORKAROUND
pszDebugStr++; } #endif // DEBUG && TEST_FOR_INTERNETCREATEURL_BUG
URL_COMPONENTS urlComp = {sizeof(URL_COMPONENTS), NULL, 0, INTERNET_SCHEME_FTP, (LPTSTR) pszServer, 0, ipPortNum, (LPTSTR) NULL_FOR_EMPTYSTR(pszUser), 0, (LPTSTR) NULL_FOR_EMPTYSTR(pszPassword), 0, (LPTSTR) pszUrlPath, 0, (LPTSTR) NULL, 0}; if (EVAL(InternetCreateUrl(&urlComp, dwFlags | ICU_ESCAPE_AUTHORITY | ICU_USERNAME, pszUrl, &cchSizeCopy))) { hr = S_OK; if (pszFragment) StrCatBuff(pszUrl, pszFragment, cchSize); }
#if DEBUG && TEST_FOR_INTERNETCREATEURL_BUG
#ifdef INTERNETCREATEURL_BUG_WORKAROUND
// Make sure we hit a terminator and not a -1, which should never happen in URL strings.
for (pszDebugStr = pszUrl; pszDebugStr[0]; pszDebugStr++) ASSERT(-1 != pszDebugStr[0]); #endif // INTERNETCREATEURL_BUG_WORKAROUND
#endif // DEBUG && TEST_FOR_INTERNETCREATEURL_BUG
return hr; }
HRESULT UrlCreate(LPCTSTR pszServer, LPCTSTR pszUser, LPCTSTR pszPassword, LPCTSTR pszUrlPath, LPCTSTR pszFragment, INTERNET_PORT ipPortNum, LPCTSTR pszDownloadType, LPTSTR pszUrl, DWORD cchSize) { return UrlCreateEx(pszServer, pszUser, pszPassword, pszUrlPath, pszFragment, ipPortNum, pszDownloadType, pszUrl, cchSize, ICU_ESCAPE); }
BOOL IsEmptyUrlPath(LPCTSTR pszUrlPath) { BOOL fResult = FALSE;
if (!pszUrlPath || !pszUrlPath[0] || (((TEXT('/') == pszUrlPath[0]) && (!pszUrlPath[1])))) { fResult = TRUE; }
return fResult; }
///////////////////////////////////////////////////////////////////////
// Wire Path Functions (UTF-8 or DBCS/MBCS)
///////////////////////////////////////////////////////////////////////
/*****************************************************************************\
FUNCTION: WirePathAdd
DESCRIPTION: ... \*****************************************************************************/ HRESULT WirePathAdd(LPWIRESTR pwWirePath, DWORD cchUrlSize, LPCWIRESTR pwWireSegment) { // If the segment starts with a slash, skip it.
if ('/' == pwWireSegment[0]) pwWireSegment = CharNextA(pwWireSegment);
StrCatBuffA(pwWirePath, pwWireSegment, cchUrlSize); return S_OK; }
/*****************************************************************************\
FUNCTION: WirePathAppendSlash
DESCRIPTION: \*****************************************************************************/ HRESULT WirePathAppendSlash(LPWIRESTR pwWirePath, DWORD cchWirePathSize) { HRESULT hr = E_FAIL; DWORD cchSize = lstrlenA(pwWirePath);
// Is there enough room?
if (cchSize < (cchWirePathSize - 1)) { LPWIRESTR pwEndOfPath = &pwWirePath[cchSize - 1];
// Is it missing a backslash?
if ((pwEndOfPath >= pwWirePath) && '/' != pwEndOfPath[0]) StrCatBuffA(pwEndOfPath, SZ_URL_SLASHA, (int)(cchWirePathSize - (pwEndOfPath - pwWirePath))); // Yes, so add it.
hr = S_OK; }
return hr; }
/*****************************************************************************\
FUNCTION: WirePathAppend
DESCRIPTION: ... \*****************************************************************************/ HRESULT WirePathAppend(LPWIRESTR pwWirePath, DWORD cchUrlSize, LPCWIRESTR pwWireSegment) { if (!EVAL(pwWireSegment)) return E_INVALIDARG;
WirePathAppendSlash(pwWirePath, cchUrlSize); // Make sure the base url ends in a '/'. Note it may be "ftp://".
return WirePathAdd(pwWirePath, cchUrlSize, pwWireSegment); }
/*****************************************************************************\
FUNCTION: UrlGetFirstPathSegment
PARAMETERS: [IN] pszFullPath - "Dir1\Dir2\Dir3" [OUT] szFirstItem - "Dir1" [OPTIONAL] [OUT] szRemaining - "Dir2\Dir3" [OPTIONAL] \*****************************************************************************/ HRESULT WirePathGetFirstSegment(LPCWIRESTR pwFtpWirePath, LPWIRESTR wFirstItem, DWORD cchFirstItemSize, BOOL * pfWasFragSeparator, LPWIRESTR wRemaining, DWORD cchRemainingSize, BOOL * pfIsDir) { HRESULT hr = S_OK; LPCWIRESTR pwSegEnding = StrChrA(pwFtpWirePath, CH_URL_URL_SLASH);
if (pfIsDir) *pfIsDir = FALSE;
ASSERT((CH_URL_URL_SLASHA != pwFtpWirePath[0])); // You will probably not get what you want.
if (pwSegEnding) { if (wFirstItem) { DWORD cchSize = (DWORD) (pwSegEnding - pwFtpWirePath + 1); StrCpyNA(wFirstItem, pwFtpWirePath, (cchSize <= cchFirstItemSize) ? cchSize : cchFirstItemSize); }
if (pfIsDir && (CH_URL_URL_SLASHA == pwSegEnding[0])) *pfIsDir = TRUE; // Tell them that it is a directory.
if (wRemaining) StrCpyNA(wRemaining, CharNextA(pwSegEnding), cchRemainingSize);
if (0 == pwSegEnding[1]) hr = S_FALSE; // End of the line.
} else { if (wFirstItem) StrCpyNA(wFirstItem, pwFtpWirePath, cchFirstItemSize); // pszFullPath contains only one segment
if (wRemaining) wRemaining[0] = 0; hr = S_FALSE; // Indicate that there aren't any more directories left.
}
return hr; }
///////////////////////////////////////////////////////////////////////
// Display Path Functions (Unicode)
///////////////////////////////////////////////////////////////////////
/*****************************************************************************\
FUNCTION: DisplayPathAdd
DESCRIPTION: ... \*****************************************************************************/ HRESULT DisplayPathAdd(LPWSTR pwzUrl, DWORD cchUrlSize, LPCWSTR pwzSegment) { // If the segment starts with a slash, skip it.
if (L'/' == pwzSegment[0]) pwzSegment = CharNext(pwzSegment);
StrCatBuffW(pwzUrl, pwzSegment, cchUrlSize); return S_OK; }
/*****************************************************************************\
FUNCTION: DisplayPathAppendSlash
DESCRIPTION: \*****************************************************************************/ HRESULT DisplayPathAppendSlash(LPWSTR pwzDisplayPath, DWORD cchSize) { DWORD cchCurrentSize = lstrlenW(pwzDisplayPath); HRESULT hr = CO_E_PATHTOOLONG;
if (cchCurrentSize < (cchSize - 2)) { LPWSTR pwzEndOfPath = &pwzDisplayPath[cchCurrentSize - 1];
// Is it missing a backslash?
if ((pwzEndOfPath >= pwzDisplayPath) && TEXT('/') != pwzEndOfPath[0]) StrCatBuff(pwzEndOfPath, SZ_URL_SLASH, (cchSize - cchCurrentSize + 1)); // Yes, so add it.
hr = S_OK; }
return hr; }
/*****************************************************************************\
FUNCTION: DisplayPathAppend
DESCRIPTION: ... \*****************************************************************************/ HRESULT DisplayPathAppend(LPWSTR pwzDisplayPath, DWORD cchUrlSize, LPCWSTR pwzDisplaySegment) { if (!EVAL(pwzDisplaySegment)) return E_INVALIDARG;
DisplayPathAppendSlash(pwzDisplayPath, cchUrlSize); // Make sure the base url ends in a '/'. Note it may be "ftp://".
return DisplayPathAdd(pwzDisplayPath, cchUrlSize, pwzDisplaySegment); }
/*****************************************************************************\
FUNCTION: DisplayPathGetFirstSegment
PARAMETERS: [IN] pszFullPath - "Dir1\Dir2\Dir3" [OUT] szFirstItem - "Dir1" [OPTIONAL] [OUT] szRemaining - "Dir2\Dir3" [OPTIONAL] \*****************************************************************************/ HRESULT DisplayPathGetFirstSegment(LPCWSTR pwzFullPath, LPWSTR pwzFirstItem, DWORD cchFirstItemSize, BOOL * pfWasFragSeparator, LPWSTR pwzRemaining, DWORD cchRemainingSize, BOOL * pfIsDir) { HRESULT hr = S_OK; LPWSTR pwzSegEnding = StrChrW(pwzFullPath, CH_URL_URL_SLASH);
if (pfIsDir) *pfIsDir = FALSE;
// This will happen if the user enters an incorrect URL, like "ftp://wired//"
// ASSERT((CH_URL_URL_SLASHW != pwzFullPath[0])); // You will probably not get what you want.
if (pwzSegEnding) { if (pwzFirstItem) { DWORD cchSize = (DWORD) (pwzSegEnding - pwzFullPath + 1); StrCpyNW(pwzFirstItem, pwzFullPath, (cchSize <= cchFirstItemSize) ? cchSize : cchFirstItemSize); }
if (pfIsDir && (CH_URL_URL_SLASHW == pwzSegEnding[0])) *pfIsDir = TRUE; // Tell them that it is a directory.
if (pwzRemaining) StrCpyNW(pwzRemaining, CharNextW(pwzSegEnding), cchRemainingSize);
if (0 == pwzSegEnding[1]) hr = S_FALSE; // End of the line.
} else { if (pwzFirstItem) StrCpyNW(pwzFirstItem, pwzFullPath, cchFirstItemSize); // pszFullPath contains only one segment
if (pwzRemaining) pwzRemaining[0] = 0; hr = S_FALSE; // Indicate that there aren't any more directories left.
}
return hr; }
|