📄 ftppidl.cpp
字号:
/*****************************************************************************\
FUNCTION: UrlCreateFromPidl
DESCRIPTION:
Common worker that handles SHGDN_FORPARSING style GetDisplayNameOf's.
Note! that since we do not support junctions (duh), we can
safely walk down the pidl generating goop as we go, secure
in the knowledge that we are in charge of every subpidl.
_CHARSET_: Since FTP filenames are always in the ANSI character
set, by RFC 1738, we can return ANSI display names without loss
of fidelity. In a general folder implementation, we should be
using cStr to return display names, so that the UNICODE
version of the shell extension can handle UNICODE names.
\*****************************************************************************/
HRESULT UrlCreateFromPidl(LPCITEMIDLIST pidl, DWORD shgno, LPTSTR pszUrl, DWORD cchSize, DWORD dwFlags, BOOL fHidePassword)
{
HRESULT hr = S_OK;
pszUrl[0] = 0;
if (!EVAL(pidl) ||
!EVAL(IsValidPIDL(pidl)) ||
!FtpPidl_IsValid(pidl) ||
!FtpID_IsServerItemID(pidl) ||
!EVAL(pszUrl && (0 < cchSize)))
{
return E_INVALIDARG;
}
if (shgno & SHGDN_INFOLDER)
{
// shgno & SHGDN_INFOLDER ?
LPCITEMIDLIST pidlLast = ILGetLastID(pidl);
if (EVAL(pidlLast && !ILIsEmpty(pidlLast)))
{
hr = FtpPidl_GetDisplayName(pidlLast, pszUrl, cchSize);
// Do they want to reparse it later? If they do and it's
// a server, we need to give out the scheme also.
// (SHGDN_INFOLDER) = "ServerName"
// (SHGDN_INFOLDER|SHGDN_FORPARSING) = "ftp://ServerName/"
if ((shgno & SHGDN_FORPARSING) &&
(FtpID_IsServerItemID(pidlLast)))
{
// Yes, so we need to add the server name.
TCHAR szServerName[MAX_PATH];
StrCpyN(szServerName, pszUrl, ARRAYSIZE(szServerName));
wnsprintf(pszUrl, cchSize, TEXT("ftp://%s/"), szServerName);
}
}
else
hr = E_FAIL;
}
else
{
// Assume they want the full URL.
if (!EVAL((shgno & SHGDN_FORPARSING) ||
(shgno & SHGDN_FORADDRESSBAR) ||
(shgno == SHGDN_NORMAL)))
{
TraceMsg(TF_ALWAYS, "UrlCreateFromPidl() shgno=%#08lx and I dont know what to do with that.", shgno);
}
if ((shgno & SHGDN_FORPARSING) || (shgno & SHGDN_FORADDRESSBAR))
{
hr = ParseUrlCreateFromPidl(pidl, pszUrl, cchSize, dwFlags, fHidePassword);
}
else
hr = GetFullPrettyName(pidl, pszUrl, cchSize);
}
// TraceMsg(TF_FTPURL_UTILS, "UrlCreateFromPidl() pszUrl=%ls, shgno=%#08lX", pszUrl, shgno);
return hr;
}
/*****************************************************************************\
FUNCTION: CreateFtpPidlFromDisplayPathHelper
DESCRIPTION:
The work done in CreateFtpPidlFromUrlPath requires a fair amount of
stack space so we do most of the work in CreateFtpPidlFromDisplayPathHelper
to prevent overflowing the stack.
\*****************************************************************************/
HRESULT CreateFtpPidlFromDisplayPathHelper(LPCWSTR pwzFullPath, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, BOOL fIsTypeKnown, BOOL fIsDir, LPITEMIDLIST * ppidlCurrentID, LPWSTR * ppwzRemaining)
{
HRESULT hr = E_FAIL;
LPITEMIDLIST pidl;
WCHAR wzFirstItem[MAX_PATH];
WIRECHAR wFirstWireItem[MAX_PATH];
WCHAR wzRemaining[MAX_PATH];
BOOL fIsCurrSegmentADir = FALSE;
BOOL fIsCurrSegmentTypeKnown = fIsTypeKnown;
BOOL fIsFragSeparator = FALSE;
*ppwzRemaining = NULL;
*ppidl = 0;
if (pcchEaten)
*pcchEaten = 0; // The caller will parse the entire URL so we don't need to fill this in.
if (L'/' == pwzFullPath[0])
pwzFullPath = (LPWSTR) CharNextW(pwzFullPath);
DisplayPathGetFirstSegment(pwzFullPath, wzFirstItem, ARRAYSIZE(wzFirstItem), NULL, wzRemaining, ARRAYSIZE(wzRemaining), &fIsCurrSegmentADir);
// Is this the last segment?
if (!wzRemaining[0])
{
// Yes, so if the caller knows the type of the last segment, use it now.
if (fIsTypeKnown)
fIsCurrSegmentADir = fIsDir;
}
else
{
// No, so we are assured that fIsDirCurrent is correct because it must have been followed
// by a '/', or how could it be followed by another path segment?
fIsCurrSegmentTypeKnown = TRUE;
ASSERT(fIsCurrSegmentADir);
}
// NOTE: If the user entered "ftp://serv/Dir1/Dir2" fIsDir will be false for Dir2.
// It will be marked as ambigious. (TODO: Check for extension?)
EVAL(SUCCEEDED(pwe->UnicodeToWireBytes(NULL, wzFirstItem, ((pwe && pwe->IsUTF8Supported()) ? WIREENC_USE_UTF8 : WIREENC_NONE), wFirstWireItem, ARRAYSIZE(wFirstWireItem))));
hr = FtpItemID_CreateFake(wzFirstItem, wFirstWireItem, fIsCurrSegmentTypeKnown, !fIsCurrSegmentADir, FALSE, &pidl);
ASSERT(IsValidPIDL(pidl));
if (EVAL(SUCCEEDED(hr)))
{
if (wzRemaining[0])
{
Str_SetPtrW(ppwzRemaining, wzRemaining);
*ppidlCurrentID = pidl;
}
else
*ppidl = pidl;
}
return hr;
}
/*****************************************************************************\
FUNCTION: CreateFtpPidlFromUrlPath
DESCRIPTION:
This function will be passed the 'Path' of the URL and will create
each of the IDs for each path segment. This will happen by creating an ID
for the first path segment and then Combining that with the remaining
IDs which are obtained by a recursive call.
URL = "ftp://<UserName>:<Password>@<HostName>:<PortNum>/Dir1/Dir2/Dir3/file.txt[;Type=[a|b|d]]"
Url Path = "Dir1/Dir2/Dir3/file.txt"
pszFullPath - This URL will contain an URL Path (/Dir1/Dir2/MayBeFileOrDir).
fIsTypeKnown - We can detect all directories w/o ambiguity because they end
end '/' except for the last directory. fIsTypeKnown is used
if this information is known. If TRUE, fIsDir will be used to
disambiguate the last item. If FALSE, the last item will be marked
a directory if it doesn't have an extension.
The incoming name is %-encoded, but if we see an illegal %-sequence,
just leave the % alone.
Note that we return E_FAIL when given an unparseable path,
not E_INVALIDARG.
\*****************************************************************************/
HRESULT CreateFtpPidlFromDisplayPath(LPCWSTR pwzFullPath, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, BOOL fIsTypeKnown, BOOL fIsDir)
{
HRESULT hr = E_FAIL;
LPWSTR pwzRemaining = NULL;
LPITEMIDLIST pidlCurrentID = NULL;
hr = CreateFtpPidlFromDisplayPathHelper(pwzFullPath, pwe, pcchEaten, ppidl, fIsTypeKnown, fIsDir, &pidlCurrentID, &pwzRemaining);
if (EVAL(SUCCEEDED(hr)) && pwzRemaining)
{
LPITEMIDLIST pidlSub;
hr = CreateFtpPidlFromDisplayPath(pwzRemaining, pwe, pcchEaten, &pidlSub, fIsTypeKnown, fIsDir);
if (EVAL(SUCCEEDED(hr)))
{
*ppidl = ILCombine(pidlCurrentID, pidlSub);
hr = *ppidl ? S_OK : E_OUTOFMEMORY;
ILFree(pidlSub);
}
ILFree(pidlCurrentID);
Str_SetPtrW(&pwzRemaining, NULL);
}
return hr;
}
/*****************************************************************************\
FUNCTION: CreateFtpPidlFromDisplayPathHelper
DESCRIPTION:
The work done in CreateFtpPidlFromUrlPath requires a fair amount of
stack space so we do most of the work in CreateFtpPidlFromDisplayPathHelper
to prevent overflowing the stack.
\*****************************************************************************/
HRESULT CreateFtpPidlFromFtpWirePathHelper(LPCWIRESTR pwFtpWirePath, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, BOOL fIsTypeKnown, BOOL fIsDir, LPITEMIDLIST * ppidlCurrentID, LPWIRESTR * ppwRemaining)
{
HRESULT hr = E_FAIL;
LPITEMIDLIST pidl;
WIRECHAR wFirstItem[MAX_PATH];
WCHAR wzFirstItemDisplayName[MAX_PATH];
WIRECHAR wRemaining[MAX_PATH];
BOOL fIsCurrSegmentADir = FALSE;
BOOL fIsCurrSegmentTypeKnown = fIsTypeKnown;
BOOL fIsFragSeparator = FALSE;
*ppwRemaining = NULL;
*ppidl = 0;
if (pcchEaten)
*pcchEaten = 0; // The caller will parse the entire URL so we don't need to fill this in.
if ('/' == pwFtpWirePath[0])
pwFtpWirePath = (LPWIRESTR) CharNextA(pwFtpWirePath);
WirePathGetFirstSegment(pwFtpWirePath, wFirstItem, ARRAYSIZE(wFirstItem), NULL, wRemaining, ARRAYSIZE(wRemaining), &fIsCurrSegmentADir);
// Is this the last segment?
if (!wRemaining[0])
{
// Yes, so if the caller knows the type of the last segment, use it now.
if (fIsTypeKnown)
fIsCurrSegmentADir = fIsDir;
}
else
{
// No, so we are assured that fIsDirCurrent is correct because it must have been followed
// by a '/', or how could it be followed by another path segment?
fIsCurrSegmentTypeKnown = TRUE;
ASSERT(fIsCurrSegmentADir);
}
// NOTE: If the user entered "ftp://serv/Dir1/Dir2" fIsDir will be false for Dir2.
// It will be marked as ambigious. (TODO: Check for extension?)
EVAL(SUCCEEDED(pwe->WireBytesToUnicode(NULL, wFirstItem, WIREENC_IMPROVE_ACCURACY, wzFirstItemDisplayName, ARRAYSIZE(wzFirstItemDisplayName))));
hr = FtpItemID_CreateFake(wzFirstItemDisplayName, wFirstItem, fIsCurrSegmentTypeKnown, !fIsCurrSegmentADir, FALSE, &pidl);
ASSERT(IsValidPIDL(pidl));
if (EVAL(SUCCEEDED(hr)))
{
if (wRemaining[0])
{
Str_SetPtrA(ppwRemaining, wRemaining);
*ppidlCurrentID = pidl;
}
else
*ppidl = pidl;
}
return hr;
}
HRESULT CreateFtpPidlFromFtpWirePath(LPCWIRESTR pwFtpWirePath, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, BOOL fIsTypeKnown, BOOL fIsDir)
{
HRESULT hr = E_FAIL;
LPWIRESTR pwRemaining = NULL;
LPITEMIDLIST pidlCurrentID = NULL;
*ppidl = NULL;
if (!pwFtpWirePath[0] || (0 == StrCmpA(pwFtpWirePath, SZ_URL_SLASHA)))
return S_OK;
hr = CreateFtpPidlFromFtpWirePathHelper(pwFtpWirePath, pwe, pcchEaten, ppidl, fIsTypeKnown, fIsDir, &pidlCurrentID, &pwRemaining);
if (EVAL(SUCCEEDED(hr)) && pwRemaining)
{
LPITEMIDLIST pidlSub;
hr = CreateFtpPidlFromFtpWirePath(pwRemaining, pwe, pcchEaten, &pidlSub, fIsTypeKnown, fIsDir);
if (EVAL(SUCCEEDED(hr)))
{
*ppidl = ILCombine(pidlCurrentID, pidlSub);
hr = *ppidl ? S_OK : E_OUTOFMEMORY;
ILFree(pidlSub);
}
ILFree(pidlCurrentID);
Str_SetPtrA(&pwRemaining, NULL);
}
return hr;
}
HRESULT CreateFtpPidlFromUrlPathAndPidl(LPCITEMIDLIST pidl, CWireEncoding * pwe, LPCWIRESTR pwFtpWirePath, LPITEMIDLIST * ppidl)
{
HRESULT hr = E_FAIL;
LPITEMIDLIST pidlNew = ILClone(pidl);
if (pidlNew)
{
LPITEMIDLIST pidlLast = (LPITEMIDLIST) ILGetLastID(pidlNew);
while (!FtpID_IsServerItemID(pidlLast))
{
pidlLast->mkid.cb = 0; // Remove this ID.
pidlLast = (LPITEMIDLIST) ILGetLastID(pidlNew);
}
LPITEMIDLIST pidlUrlPath = NULL;
hr = CreateFtpPidlFromFtpWirePath(pwFtpWirePath, pwe, NULL, &pidlUrlPath, TRUE, TRUE);
if (EVAL(SUCCEEDED(hr)))
{
*ppidl = ILCombine(pidlNew, pidlUrlPath);
}
if (pidlLast)
ILFree(pidlLast);
if (pidlUrlPath)
ILFree(pidlUrlPath);
}
return hr;
}
/*****************************************************************************\
CreateFtpPidlFromUrl
The incoming name is %-encoded, but if we see an illegal %-sequence,
just leave the % alone.
Note that we return E_FAIL when given an unparseable path,
not E_INVALIDARG.
\*****************************************************************************/
HRESULT CreateFtpPidlFromUrl(LPCTSTR pszUrl, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, IMalloc * pm, BOOL fHidePassword)
{
return CreateFtpPidlFromUrlEx(pszUrl, pwe, pcchEaten, ppidl, pm, fHidePassword, FALSE, FALSE);
}
/*****************************************************************************\
FUNCTION: CreateFtpPidlFromUrlEx
DESCRIPTION:
pszUrl - This URL will contain an URL Path (/Dir1/Dir2/MayBeFileOrDir).
fIsTypeKnown - We can detect all directories w/o ambiguity because they end
end '/' except for the last directory. fIsTypeKnown is used
if this information is known. If TRUE, fIsDir will be used to
disambiguate the last item. If FALSE, the last item will be marked
a directory if it doesn't have an extension.
The incoming name is %-encoded, but if we see an illegal %-sequence,
just leave the % alone.
Note that we return E_FAIL when given an unparseable path,
not E_INVALIDARG.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -