summaryrefslogtreecommitdiffstats
path: root/adb/sysdeps_win32.cpp
diff options
context:
space:
mode:
authorSpencer Low <CompareAndSwap@gmail.com>2015-10-21 22:22:50 -0700
committerSpencer Low <CompareAndSwap@gmail.com>2015-11-10 15:48:54 -0800
commitac9514a4524f98b2029dbcda9326a763d25492b1 (patch)
tree9d33845468022540c4f8debe60e82a06ea8cb628 /adb/sysdeps_win32.cpp
parent48f2e1ed317f6a330b129c788bd19dac2a4df8ad (diff)
downloadsystem_core-ac9514a4524f98b2029dbcda9326a763d25492b1.tar.gz
system_core-ac9514a4524f98b2029dbcda9326a763d25492b1.tar.bz2
system_core-ac9514a4524f98b2029dbcda9326a763d25492b1.zip
adb/base: fix adb push of Unicode filenames on Win32
ae5a6c06cdd9ae1a0a7cdc42711f0a5594e54dcd made adb push use android::base::ReadFileToString() for small files, but that API did not support UTF-8 filenames on Windows, until this fix which does the following: - Add android::base::{WideToUTF8,UTF8ToWide}() which are only available on Windows. The signatures are based on Chromium's APIs of the same name. - Add the namespace android::base::utf8 which has versions of APIs that take UTF-8 strings. To use this, make sure your code is in a namespace and then do "using namespace android::base::utf8;". On Windows, this will make calls to open() call android::base::utf8::open(), and on other platforms, it will just call the regular ::open(). - Make ReadFileToString() and WriteStringToFile() use utf8::open() and utf8::unlink(). - Adapt unittests from Chromium. - fastboot needs to link with libcutils because it links with libbase which depends on libcutils for gettid() for logging. Change-Id: I1aeac40ff358331d7a1ff457ce894bfb17863904 Signed-off-by: Spencer Low <CompareAndSwap@gmail.com>
Diffstat (limited to 'adb/sysdeps_win32.cpp')
-rw-r--r--adb/sysdeps_win32.cpp125
1 files changed, 45 insertions, 80 deletions
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index e32588932..3305757d2 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -35,6 +35,7 @@
#include <base/logging.h>
#include <base/stringprintf.h>
#include <base/strings.h>
+#include <base/utf8.h>
#include "adb.h"
@@ -3516,100 +3517,61 @@ static void _widen_fatal(const char *fmt, ...) {
exit(-1);
}
-// TODO: Consider implementing widen() and narrow() out of std::wstring_convert
-// once libcxx is supported on Windows. Or, consider libutils/Unicode.cpp.
-
-// Convert from UTF-8 to UTF-16. A size of -1 specifies a NULL terminated
-// string. Any other size specifies the number of chars to convert, excluding
-// any NULL terminator (if you're passing an explicit size, you probably don't
-// have a NULL terminated string in the first place).
-std::wstring widen(const char* utf8, const int size) {
- // Note: Do not call SystemErrorCodeToString() from widen() because
- // SystemErrorCodeToString() calls narrow() which may call fatal() which
- // calls adb_vfprintf() which calls widen(), potentially causing infinite
- // recursion.
- const int chars_to_convert = MultiByteToWideChar(CP_UTF8, 0, utf8, size,
- NULL, 0);
- if (chars_to_convert <= 0) {
- // UTF-8 to UTF-16 should be lossless, so we don't expect this to fail.
- _widen_fatal("MultiByteToWideChar failed counting: %d, "
- "GetLastError: %lu", chars_to_convert, GetLastError());
- }
-
+// Convert size number of UTF-8 char's to UTF-16. Fatal exit on error.
+std::wstring widen(const char* utf8, const size_t size) {
std::wstring utf16;
- size_t chars_to_allocate = chars_to_convert;
- if (size == -1) {
- // chars_to_convert includes a NULL terminator, so subtract space
- // for that because resize() includes that itself.
- --chars_to_allocate;
- }
- utf16.resize(chars_to_allocate);
-
- // This uses &string[0] to get write-access to the entire string buffer
- // which may be assuming that the chars are all contiguous, but it seems
- // to work and saves us the hassle of using a temporary
- // std::vector<wchar_t>.
- const int result = MultiByteToWideChar(CP_UTF8, 0, utf8, size, &utf16[0],
- chars_to_convert);
- if (result != chars_to_convert) {
- // UTF-8 to UTF-16 should be lossless, so we don't expect this to fail.
- _widen_fatal("MultiByteToWideChar failed conversion: %d, "
- "GetLastError: %lu", result, GetLastError());
- }
-
- // If a size was passed in (size != -1), then the string is NULL terminated
- // by a NULL char that was written by std::string::resize(). If size == -1,
- // then MultiByteToWideChar() read a NULL terminator from the original
- // string and converted it to a NULL UTF-16 char in the output.
+ if (!android::base::UTF8ToWide(utf8, size, &utf16)) {
+ // If we call fatal() here and fatal() calls widen(), then there may be
+ // infinite recursion. To avoid this, call _widen_fatal() instead.
+ _widen_fatal("cannot convert from UTF-8 to UTF-16");
+ }
return utf16;
}
-// Convert a NULL terminated string from UTF-8 to UTF-16.
+// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Fatal exit
+// on error.
std::wstring widen(const char* utf8) {
- // Pass -1 to let widen() determine the string length.
- return widen(utf8, -1);
+ std::wstring utf16;
+ if (!android::base::UTF8ToWide(utf8, &utf16)) {
+ // If we call fatal() here and fatal() calls widen(), then there may be
+ // infinite recursion. To avoid this, call _widen_fatal() instead.
+ _widen_fatal("cannot convert from UTF-8 to UTF-16");
+ }
+
+ return utf16;
}
-// Convert from UTF-8 to UTF-16.
+// Convert a UTF-8 std::string (including any embedded NULL characters) to
+// UTF-16. Fatal exit on error.
std::wstring widen(const std::string& utf8) {
- return widen(utf8.c_str(), utf8.length());
+ std::wstring utf16;
+ if (!android::base::UTF8ToWide(utf8, &utf16)) {
+ // If we call fatal() here and fatal() calls widen(), then there may be
+ // infinite recursion. To avoid this, call _widen_fatal() instead.
+ _widen_fatal("cannot convert from UTF-8 to UTF-16");
+ }
+
+ return utf16;
}
-// Convert from UTF-16 to UTF-8.
+// Convert a UTF-16 std::wstring (including any embedded NULL characters) to
+// UTF-8. Fatal exit on error.
std::string narrow(const std::wstring& utf16) {
- return narrow(utf16.c_str());
+ std::string utf8;
+ if (!android::base::WideToUTF8(utf16, &utf8)) {
+ fatal("cannot convert from UTF-16 to UTF-8");
+ }
+
+ return utf8;
}
-// Convert from UTF-16 to UTF-8.
+// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Fatal exit
+// on error.
std::string narrow(const wchar_t* utf16) {
- // Note: Do not call SystemErrorCodeToString() from narrow() because
- // SystemErrorCodeToString() calls narrow() and we don't want potential
- // infinite recursion.
- const int chars_required = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL,
- 0, NULL, NULL);
- if (chars_required <= 0) {
- // UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
- fatal("WideCharToMultiByte failed counting: %d, GetLastError: %lu",
- chars_required, GetLastError());
- }
-
std::string utf8;
- // Subtract space for the NULL terminator because resize() includes
- // that itself. Note that this could potentially throw a std::bad_alloc
- // exception.
- utf8.resize(chars_required - 1);
-
- // This uses &string[0] to get write-access to the entire string buffer
- // which may be assuming that the chars are all contiguous, but it seems
- // to work and saves us the hassle of using a temporary
- // std::vector<char>.
- const int result = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, &utf8[0],
- chars_required, NULL, NULL);
- if (result != chars_required) {
- // UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
- fatal("WideCharToMultiByte failed conversion: %d, GetLastError: %lu",
- result, GetLastError());
+ if (!android::base::WideToUTF8(utf16, &utf8)) {
+ fatal("cannot convert from UTF-16 to UTF-8");
}
return utf8;
@@ -3752,9 +3714,12 @@ int adb_chmod(const char* path, int mode) {
// on error.
static int _console_write_utf8(const char* buf, size_t size, FILE* stream,
HANDLE console) {
- // Convert from UTF-8 to UTF-16.
+ std::wstring output;
+
+ // Try to convert from data that might be UTF-8 to UTF-16, ignoring errors.
+ // Data might not be UTF-8 if the user cat's random data, runs dmesg, etc.
// This could throw std::bad_alloc.
- const std::wstring output(widen(buf, size));
+ (void)android::base::UTF8ToWide(buf, size, &output);
// Note that this does not do \n => \r\n translation because that
// doesn't seem necessary for the Windows console. For the Windows