// Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The SFC licenses this file // to you 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 "StringUtilities.h" #define WHITESPACE " \n\r\t" #define WIDE_WHITESPACE L" \n\r\t" namespace webdriver { StringUtilities::StringUtilities(void) { } StringUtilities::~StringUtilities(void) { } std::wstring StringUtilities::ToWString(const std::string& input) { // Assumption: The wstring character count will be the same as the length of // the string character count. Allocate the buffer with that many wchar_t items // so that the first MultiByteToWideChar call will succeed most of the time as // an optimization. std::wstring output = L""; int input_string_byte_count = static_cast(input.size()) + 1; int wide_string_length = input_string_byte_count; std::vector output_buffer(wide_string_length); bool convert_failed = (0 == ::MultiByteToWideChar(CP_UTF8, 0, input.c_str(), input_string_byte_count, &output_buffer[0], wide_string_length)); if (convert_failed) { if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Buffer wasn't big enough. Call MultiByteToWideChar again with // NULL values to determine how big the buffer should be. wide_string_length = ::MultiByteToWideChar(CP_UTF8, 0, input.c_str(), input_string_byte_count, NULL, 0); output_buffer.resize(wide_string_length); convert_failed = (0 == ::MultiByteToWideChar(CP_UTF8, 0, input.c_str(), input_string_byte_count, &output_buffer[0], wide_string_length)); if (!convert_failed) { output = &output_buffer[0]; } } } else { output = &output_buffer[0]; } return output; } std::string StringUtilities::ToString(const std::wstring& input) { // Assumption: The byte count of the resulting narrow string will be at most // four times the character count of the input wstring. Allocate the buffer // with that many char items (bytes) so that the first WideCharToMultiByte // call will succeed most of the time as an optimization. std::string output = ""; int wide_string_length = static_cast(input.size()) + 1; int output_string_byte_count = wide_string_length * 4; std::vector string_buffer(output_string_byte_count); bool convert_failed = (0 == ::WideCharToMultiByte(CP_UTF8, 0, input.c_str(), wide_string_length, &string_buffer[0], output_string_byte_count, NULL, NULL)); if (convert_failed) { if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Buffer wasn't big enough. Call WideCharToMultiByte again with // NULL values to determine how big the buffer should be. output_string_byte_count = ::WideCharToMultiByte(CP_UTF8, 0, input.c_str(), wide_string_length, NULL, 0, NULL, NULL); string_buffer.resize(output_string_byte_count); convert_failed = (0 == ::WideCharToMultiByte(CP_UTF8, 0, input.c_str(), wide_string_length, &string_buffer[0], output_string_byte_count, NULL, NULL)); if (!convert_failed) { output = &string_buffer[0]; } } } else { output = &string_buffer[0]; } return output; } std::string StringUtilities::Format(const char* format, ...) { va_list args; va_start(args, format); size_t buffer_size = _vscprintf(format, args); std::vector buffer(buffer_size + 1); _vsnprintf_s(&buffer[0], buffer.size(), buffer_size + 1, format, args); va_end(args); std::string formatted = &buffer[0]; return formatted; } std::wstring StringUtilities::Format(const wchar_t* format, ...) { va_list args; va_start(args, format); size_t buffer_size = _vscwprintf(format, args); std::vector buffer(buffer_size + 1); _vsnwprintf_s(&buffer[0], buffer.size(), buffer_size + 1, format, args); va_end(args); std::wstring formatted = &buffer[0]; return formatted; } void StringUtilities::ToBuffer(const std::string& input, std::vector* buffer) { buffer->resize(input.size() + 1); strcpy_s(&((*buffer)[0]), buffer->size(), input.c_str()); (*buffer)[buffer->size() - 1] = L'\0'; } void StringUtilities::ToBuffer(const std::wstring& input, std::vector* buffer) { buffer->resize(input.size() + 1); wcscpy_s(&((*buffer)[0]), buffer->size(), input.c_str()); (*buffer)[buffer->size() - 1] = L'\0'; } std::string StringUtilities::Trim(const std::string& input) { return TrimRight(TrimLeft(input)); } std::string StringUtilities::TrimLeft(const std::string& input) { size_t startpos = input.find_first_not_of(WHITESPACE); return (startpos == std::string::npos) ? "" : input.substr(startpos); } std::string StringUtilities::TrimRight(const std::string& input) { size_t endpos = input.find_last_not_of(WHITESPACE); return (endpos == std::string::npos) ? "" : input.substr(0, endpos + 1); } std::wstring StringUtilities::Trim(const std::wstring& input) { return TrimRight(TrimLeft(input)); } std::wstring StringUtilities::TrimLeft(const std::wstring& input) { size_t startpos = input.find_first_not_of(WIDE_WHITESPACE); return (startpos == std::wstring::npos) ? L"" : input.substr(startpos); } std::wstring StringUtilities::TrimRight(const std::wstring& input) { size_t endpos = input.find_last_not_of(WIDE_WHITESPACE); return (endpos == std::wstring::npos) ? L"" : input.substr(0, endpos + 1); } void StringUtilities::Split(const std::string& input, const std::string& delimiter, std::vector* tokens) { std::string input_copy = input; while (input_copy.size() > 0) { size_t delimiter_pos = input_copy.find(delimiter); std::string token = input_copy.substr(0, delimiter_pos); if (delimiter_pos == std::string::npos) { input_copy = ""; } else { input_copy = input_copy.substr(delimiter_pos + delimiter.size()); } tokens->push_back(token); } } void StringUtilities::Split(const std::wstring& input, const std::wstring& delimiter, std::vector* tokens) { std::wstring input_copy = input; while (input_copy.size() > 0) { size_t delimiter_pos = input_copy.find(delimiter); std::wstring token = input_copy.substr(0, delimiter_pos); if (delimiter_pos == std::wstring::npos) { input_copy = L""; } else { input_copy = input_copy.substr(delimiter_pos + delimiter.size()); } tokens->push_back(token); } } std::wstring StringUtilities::CreateGuid() { UUID guid; RPC_WSTR guid_string = NULL; RPC_STATUS status = ::UuidCreate(&guid); if (status != RPC_S_OK) { // If we encounter an error, not bloody much we can do about it. // Just log it and continue. // LOG(WARN) << "UuidCreate returned a status other then RPC_S_OK: " << status; } status = ::UuidToString(&guid, &guid_string); if (status != RPC_S_OK) { // If we encounter an error, not bloody much we can do about it. // Just log it and continue. // LOG(WARN) << "UuidToString returned a status other then RPC_S_OK: " << status; } // RPC_WSTR is currently typedef'd in RpcDce.h (pulled in by rpc.h) // as unsigned short*. It needs to be typedef'd as wchar_t* wchar_t* cast_guid_string = reinterpret_cast(guid_string); std::wstring returned_guid(cast_guid_string); ::RpcStringFree(&guid_string); return returned_guid; } void StringUtilities::ComposeUnicodeString(std::wstring* input) { StringUtilities::NormalizeUnicodeString(NormalizationC, input); } void StringUtilities::DecomposeUnicodeString(std::wstring* input) { StringUtilities::NormalizeUnicodeString(NormalizationD, input); } void StringUtilities::NormalizeUnicodeString(NORM_FORM normalization_form, std::wstring* input) { if (FALSE == ::IsNormalizedString(normalization_form, input->c_str(), -1)) { int required = ::NormalizeString(normalization_form, input->c_str(), -1, NULL, 0); std::vector buffer(required); ::NormalizeString(normalization_form, input->c_str(), -1, &buffer[0], static_cast(buffer.size())); *input = &buffer[0]; } } } // namespace webdriver