//===- llvm/Support/Win32/PathV2.cpp - Windows Path Impl --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Windows specific implementation of the PathV2 API. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic Windows code that //=== is guaranteed to work on *all* Windows variants. //===----------------------------------------------------------------------===// #include "Windows.h" using namespace llvm; namespace { error_code UTF8ToUTF16(const StringRef &utf8, SmallVectorImpl &utf16) { int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), utf8.size(), utf16.begin(), 0); if (len == 0) return make_error_code(windows_error(::GetLastError())); utf16.reserve(len + 1); utf16.set_size(len); len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), utf8.size(), utf16.begin(), utf16.size()); if (len == 0) return make_error_code(windows_error(::GetLastError())); // Make utf16 null terminated. utf16.push_back(0); utf16.pop_back(); return make_error_code(errc::success); } } namespace llvm { namespace sys { namespace path { error_code current_path(SmallVectorImpl &result) { SmallVector cur_path; cur_path.reserve(128); retry_cur_dir: DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); // A zero return value indicates a failure other than insufficient space. if (len == 0) return make_error_code(windows_error(::GetLastError())); // If there's insufficient space, the len returned is larger than the len // given. if (len > cur_path.capacity()) { cur_path.reserve(len); goto retry_cur_dir; } cur_path.set_size(len); // cur_path now holds the current directory in utf-16. Convert to utf-8. // Find out how much space we need. Sadly, this function doesn't return the // size needed unless you tell it the result size is 0, which means you // _always_ have to call it twice. len = ::WideCharToMultiByte(CP_UTF8, NULL, cur_path.data(), cur_path.size(), result.data(), 0, NULL, NULL); if (len == 0) return make_error_code(windows_error(::GetLastError())); result.reserve(len); result.set_size(len); // Now do the actual conversion. len = ::WideCharToMultiByte(CP_UTF8, NULL, cur_path.data(), cur_path.size(), result.data(), result.size(), NULL, NULL); if (len == 0) return make_error_code(windows_error(::GetLastError())); return make_error_code(errc::success); } } // end namespace path namespace fs { error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { // Get arguments. SmallString<128> from_storage; SmallString<128> to_storage; StringRef f = from.toNullTerminatedStringRef(from_storage); StringRef t = to.toNullTerminatedStringRef(to_storage); // Convert to utf-16. SmallVector wide_from; SmallVector wide_to; if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; // Copy the file. BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(), copt != copy_option::overwrite_if_exists); if (res == 0) return make_error_code(windows_error(::GetLastError())); return make_error_code(errc::success); } } // end namespace fs } // end namespace sys } // end namespace llvm