Author: dquintana Date: Thu Oct 9 00:10:20 2014 New Revision: 64630
URL: http://svn.reactos.org/svn/reactos?rev=64630&view=rev Log: [SHELL32] * Rewrite SHFileOperationA using human-readable code. CORE-8564
Modified: branches/shell-experiments/dll/win32/shell32/shlfileop.cpp
Modified: branches/shell-experiments/dll/win32/shell32/shlfileop.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/dll/win32/shel... ============================================================================== --- branches/shell-experiments/dll/win32/shell32/shlfileop.cpp [iso-8859-1] (original) +++ branches/shell-experiments/dll/win32/shell32/shlfileop.cpp [iso-8859-1] Thu Oct 9 00:10:20 2014 @@ -940,38 +940,56 @@
/************************************************************************* * - * SHNameTranslate HelperFunction for SHFileOperationA - * - * Translates a list of 0 terminated ASCII strings into Unicode. If *wString - * is NULL, only the necessary size of the string is determined and returned, - * otherwise the ASCII strings are copied into it and the buffer is increased - * to point to the location after the final 0 termination char. - */ -static DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more) -{ - DWORD size = 0, aSize = 0; - LPCSTR aString = (LPCSTR)*pWToFrom; - - if (aString) - { + * _ConvertAtoW helper function for SHFileOperationA + * + * Converts a string or string-list to unicode. + */ +static DWORD _ConvertAtoW(PCSTR strSrc, PCWSTR* pStrDest, BOOL isList) +{ + *pStrDest = NULL; + + // If the input is null, nothing to convert. + if (!strSrc) + return 0; + + // Measure the total size, depending on if it's a zero-terminated list. + int sizeA = 0; + if (isList) + { + PCSTR tmpSrc = strSrc; + int size; do { - size = lstrlenA(aString) + 1; - aSize += size; - aString += size; - } while ((size != 1) && more); - - /* The two sizes might be different in the case of multibyte chars */ - size = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, 0); - if (*wString) /* only in the second loop */ - { - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size); - *pWToFrom = *wString; - *wString += size; - } - } - return size; -} + size = lstrlenA(tmpSrc) + 1; + sizeA += size; + tmpSrc += size; + } while (size != 1); + } + else + { + sizeA = lstrlenA(strSrc) + 1; + } + + // Measure the + int sizeW = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, NULL, 0); + if (!sizeW) + return GetLastError(); + + PWSTR strDest = (PWSTR) HeapAlloc(GetProcessHeap(), 0, sizeW); + if (!strDest) + return ERROR_OUTOFMEMORY; + + int err = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, strDest, sizeW); + if (!err) + { + HeapFree(GetProcessHeap(), 0, strDest); + return GetLastError(); + } + + *pStrDest = strDest; + return 0; +} + /************************************************************************* * SHFileOperationA [SHELL32.@] * @@ -990,40 +1008,53 @@ */ int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp) { - SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp); - int retCode = 0; - DWORD size; - LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */ - wString = NULL; /* we change this in SHNameTranslate */ - - TRACE("\n"); - if (FO_DELETE == (nFileOp.wFunc & FO_MASK)) - nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */ - if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS)) - nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */ - while (1) /* every loop calculate size, second translate also, if we have storage for this */ - { - size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */ - size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */ - size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */ - - if (ForFree) - { - retCode = SHFileOperationW(&nFileOp); - HeapFree(GetProcessHeap(), 0, ForFree); /* we cannot use wString, it was changed */ - break; - } - else - { - wString = ForFree = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); - if (ForFree) continue; - retCode = ERROR_OUTOFMEMORY; - nFileOp.fAnyOperationsAborted = TRUE; - SetLastError(retCode); - return retCode; - } - } - + int errCode, retCode; + SHFILEOPSTRUCTW nFileOp = { 0 }; + + // Convert A information to W + nFileOp.hwnd = lpFileOp->hwnd; + nFileOp.wFunc = lpFileOp->wFunc; + nFileOp.fFlags = lpFileOp->fFlags; + + errCode = _ConvertAtoW(lpFileOp->pFrom, &nFileOp.pFrom, TRUE); + if (errCode != 0) + goto cleanup; + + if (FO_DELETE != (nFileOp.wFunc & FO_MASK)) + { + errCode = _ConvertAtoW(lpFileOp->pTo, &nFileOp.pTo, TRUE); + if (errCode != 0) + goto cleanup; + } + + if (nFileOp.fFlags & FOF_SIMPLEPROGRESS) + { + errCode = _ConvertAtoW(lpFileOp->lpszProgressTitle, &nFileOp.lpszProgressTitle, FALSE); + if (errCode != 0) + goto cleanup; + } + + // Call the actual function + retCode = SHFileOperationW(&nFileOp); + + // Cleanup +cleanup: + if (nFileOp.pFrom) + HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pFrom); + if (nFileOp.pTo) + HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pTo); + if (nFileOp.lpszProgressTitle) + HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.lpszProgressTitle); + + if (errCode != 0) + { + lpFileOp->fAnyOperationsAborted = TRUE; + SetLastError(errCode); + + return errCode; + } + + // Thankfully, the lpFileOp->hNameMappings = nFileOp.hNameMappings; lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted; return retCode;