| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "base/Win32UnicodeString.h" |
| |
| #include <algorithm> |
| |
| #include <windows.h> |
| |
| #include <string.h> |
| |
| namespace android { |
| namespace base { |
| |
| Win32UnicodeString::Win32UnicodeString() : mStr(nullptr), mSize(0u) {} |
| |
| Win32UnicodeString::Win32UnicodeString(const char* str, size_t len) |
| : mStr(nullptr), mSize(0u) { |
| reset(str, strlen(str)); |
| } |
| |
| Win32UnicodeString::Win32UnicodeString(const char* str) |
| : mStr(nullptr), mSize(0u) { |
| reset(str); |
| } |
| |
| Win32UnicodeString::Win32UnicodeString(const std::string& str) |
| : mStr(nullptr), mSize(0u) { |
| reset(str.c_str()); |
| } |
| |
| Win32UnicodeString::Win32UnicodeString(size_t size) : mStr(nullptr), mSize(0u) { |
| resize(size); |
| } |
| |
| Win32UnicodeString::Win32UnicodeString(const wchar_t* str) |
| : mStr(nullptr), mSize(0u) { |
| size_t len = str ? wcslen(str) : 0u; |
| resize(len); |
| ::memcpy(mStr, str ? str : L"", len * sizeof(wchar_t)); |
| } |
| |
| Win32UnicodeString::Win32UnicodeString(const Win32UnicodeString& other) |
| : mStr(nullptr), mSize(0u) { |
| resize(other.mSize); |
| ::memcpy(mStr, other.c_str(), other.mSize * sizeof(wchar_t)); |
| } |
| |
| Win32UnicodeString::~Win32UnicodeString() { |
| delete[] mStr; |
| } |
| |
| Win32UnicodeString& Win32UnicodeString::operator=( |
| const Win32UnicodeString& other) { |
| resize(other.mSize); |
| ::memcpy(mStr, other.c_str(), other.mSize * sizeof(wchar_t)); |
| return *this; |
| } |
| |
| Win32UnicodeString& Win32UnicodeString::operator=(const wchar_t* str) { |
| size_t len = str ? wcslen(str) : 0u; |
| resize(len); |
| ::memcpy(mStr, str ? str : L"", len * sizeof(wchar_t)); |
| return *this; |
| } |
| |
| wchar_t* Win32UnicodeString::data() { |
| if (!mStr) { |
| // Ensure the function never returns NULL. |
| // it is safe to const_cast the pointer here - user isn't allowed to |
| // write into it anyway |
| return const_cast<wchar_t*>(L""); |
| } |
| return mStr; |
| } |
| |
| std::string Win32UnicodeString::toString() const { |
| return convertToUtf8(mStr, mSize); |
| } |
| |
| void Win32UnicodeString::reset(const char* str, size_t len) { |
| if (mStr) { |
| delete[] mStr; |
| } |
| const int utf16Len = calcUtf16BufferLength(str, len); |
| mStr = new wchar_t[utf16Len + 1]; |
| mSize = static_cast<size_t>(utf16Len); |
| convertFromUtf8(mStr, utf16Len, str, len); |
| mStr[mSize] = L'\0'; |
| } |
| |
| void Win32UnicodeString::reset(const char* str) { |
| reset(str, strlen(str)); |
| } |
| |
| void Win32UnicodeString::resize(size_t newSize) { |
| if (newSize == 0) { |
| delete [] mStr; |
| mStr = nullptr; |
| mSize = 0; |
| } else if (newSize <= mSize) { |
| mStr[newSize] = 0; |
| mSize = newSize; |
| } else { |
| wchar_t* oldStr = mStr; |
| mStr = new wchar_t[newSize + 1u]; |
| size_t copySize = std::min<size_t>(newSize, mSize); |
| ::memcpy(mStr, oldStr ? oldStr : L"", copySize * sizeof(wchar_t)); |
| mStr[copySize] = L'\0'; |
| mStr[newSize] = L'\0'; |
| mSize = newSize; |
| delete[] oldStr; |
| } |
| } |
| |
| void Win32UnicodeString::append(const wchar_t* str) { |
| append(str, wcslen(str)); |
| } |
| |
| void Win32UnicodeString::append(const wchar_t* str, size_t len) { |
| // NOTE: This method should be rarely used, so don't try to optimize |
| // storage with larger capacity values and exponential increments. |
| if (!str || !len) { |
| return; |
| } |
| size_t oldSize = size(); |
| resize(oldSize + len); |
| memmove(mStr + oldSize, str, len * sizeof(wchar_t)); |
| } |
| |
| void Win32UnicodeString::append(const Win32UnicodeString& other) { |
| append(other.c_str(), other.size()); |
| } |
| |
| wchar_t* Win32UnicodeString::release() { |
| wchar_t* result = mStr; |
| mStr = nullptr; |
| mSize = 0u; |
| return result; |
| } |
| |
| // static |
| std::string Win32UnicodeString::convertToUtf8(const wchar_t* str, int len) { |
| std::string result; |
| const int utf8Len = calcUtf8BufferLength(str, len); |
| if (utf8Len > 0) { |
| result.resize(static_cast<size_t>(utf8Len)); |
| convertToUtf8(&result[0], utf8Len, str, len); |
| if (len == -1) { |
| result.resize(utf8Len - 1); // get rid of the null-terminator |
| } |
| } |
| return result; |
| } |
| |
| // returns the return value of a Win32UnicodeString public conversion function |
| // from a WinAPI conversion function returned code |
| static int convertRetVal(int winapiResult) { |
| return winapiResult ? winapiResult : -1; |
| } |
| |
| // static |
| int Win32UnicodeString::calcUtf8BufferLength(const wchar_t* str, int len) { |
| if (len < 0 && len != -1) { |
| return -1; |
| } |
| if (len == 0) { |
| return 0; |
| } |
| const int utf8Len = WideCharToMultiByte(CP_UTF8, // CodePage |
| 0, // dwFlags |
| str, // lpWideCharStr |
| len, // cchWideChar |
| nullptr, // lpMultiByteStr |
| 0, // cbMultiByte |
| nullptr, // lpDefaultChar |
| nullptr); // lpUsedDefaultChar |
| |
| return convertRetVal(utf8Len); |
| } |
| |
| // static |
| int Win32UnicodeString::calcUtf16BufferLength(const char* str, int len) { |
| if (len < 0 && len != -1) { |
| return -1; |
| } |
| if (len == 0) { |
| return 0; |
| } |
| const int utf16Len = MultiByteToWideChar(CP_UTF8, // CodePage |
| 0, // dwFlags |
| str, // lpMultiByteStr |
| len, // cbMultiByte |
| nullptr, // lpWideCharStr |
| 0); // cchWideChar |
| |
| return convertRetVal(utf16Len); |
| } |
| |
| // static |
| int Win32UnicodeString::convertToUtf8(char* outStr, int outLen, |
| const wchar_t* str, int len) { |
| if (!outStr || outLen < 0 || !str || (len < 0 && len != -1)) { |
| return -1; |
| } |
| if (len == 0) { |
| return 0; |
| } |
| |
| const int utf8Len = WideCharToMultiByte(CP_UTF8, // CodePage |
| 0, // dwFlags |
| str, // lpWideCharStr |
| len, // cchWideChar |
| outStr, // lpMultiByteStr |
| outLen, // cbMultiByte |
| nullptr, // lpDefaultChar |
| nullptr); // lpUsedDefaultChar |
| return convertRetVal(utf8Len); |
| } |
| |
| // static |
| int Win32UnicodeString::convertFromUtf8(wchar_t* outStr, int outLen, |
| const char* str, int len) { |
| if (!outStr || outLen < 0 || !str || (len < 0 && len != -1)) { |
| return -1; |
| } |
| if (len == 0) { |
| return 0; |
| } |
| |
| const int utf16Len = MultiByteToWideChar(CP_UTF8, // CodePage |
| 0, // dwFlags |
| str, // lpMultiByteStr |
| len, // cbMultiByte |
| outStr, // lpWideCharStr |
| outLen); // cchWideChar |
| return convertRetVal(utf16Len); |
| } |
| |
| } // namespace base |
| } // namespace android |