1// Copyright 2012 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/strings/sys_string_conversions.h" 6 7#import <Foundation/Foundation.h> 8#include <stddef.h> 9 10#include <string_view> 11#include <vector> 12 13#include "base/apple/bridging.h" 14#include "base/apple/foundation_util.h" 15#include "base/apple/scoped_cftyperef.h" 16#include "base/numerics/safe_conversions.h" 17 18namespace base { 19 20namespace { 21 22// Converts the supplied CFString into the specified encoding, and returns it as 23// a C++ library string of the template type. Returns an empty string on 24// failure. 25// 26// Do not assert in this function since it is used by the assertion code! 27template <typename StringType> 28StringType CFStringToStringWithEncodingT(CFStringRef cfstring, 29 CFStringEncoding encoding) { 30 CFIndex length = CFStringGetLength(cfstring); 31 if (length == 0) { 32 return StringType(); 33 } 34 35 CFRange whole_string = CFRangeMake(0, length); 36 CFIndex out_size; 37 CFIndex converted = CFStringGetBytes(cfstring, whole_string, encoding, 38 /*lossByte=*/0, 39 /*isExternalRepresentation=*/false, 40 /*buffer=*/nullptr, 41 /*maxBufLen=*/0, &out_size); 42 if (converted == 0 || out_size <= 0) { 43 return StringType(); 44 } 45 46 // `out_size` is the number of UInt8-sized units needed in the destination. 47 // A buffer allocated as UInt8 units might not be properly aligned to 48 // contain elements of StringType::value_type. Use a container for the 49 // proper value_type, and convert `out_size` by figuring the number of 50 // value_type elements per UInt8. Leave room for a NUL terminator. 51 size_t elements = static_cast<size_t>(out_size) * sizeof(UInt8) / 52 sizeof(typename StringType::value_type) + 53 1; 54 55 std::vector<typename StringType::value_type> out_buffer(elements); 56 converted = 57 CFStringGetBytes(cfstring, whole_string, encoding, 58 /*lossByte=*/0, 59 /*isExternalRepresentation=*/false, 60 reinterpret_cast<UInt8*>(&out_buffer[0]), out_size, 61 /*usedBufLen=*/nullptr); 62 if (converted == 0) { 63 return StringType(); 64 } 65 66 out_buffer[elements - 1] = '\0'; 67 return StringType(&out_buffer[0], elements - 1); 68} 69 70// Given a C++ library string `in` with an encoding specified by `in_encoding`, 71// converts it to `out_encoding` and returns it as a C++ library string of the 72// `OutStringType` template type. Returns an empty string on failure. 73// 74// Do not assert in this function since it is used by the assertion code! 75template <typename InStringType, typename OutStringType> 76OutStringType StringToStringWithEncodingsT(const InStringType& in, 77 CFStringEncoding in_encoding, 78 CFStringEncoding out_encoding) { 79 typename InStringType::size_type in_length = in.length(); 80 if (in_length == 0) { 81 return OutStringType(); 82 } 83 84 apple::ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy( 85 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()), 86 checked_cast<CFIndex>(in_length * 87 sizeof(typename InStringType::value_type)), 88 in_encoding, 89 /*isExternalRepresentation=*/false, kCFAllocatorNull)); 90 if (!cfstring) { 91 return OutStringType(); 92 } 93 94 return CFStringToStringWithEncodingT<OutStringType>(cfstring.get(), 95 out_encoding); 96} 97 98// Given a std::string_view `in` with an encoding specified by `in_encoding`, 99// returns it as a CFStringRef. Returns null on failure. 100template <typename CharT> 101apple::ScopedCFTypeRef<CFStringRef> StringPieceToCFStringWithEncodingsT( 102 std::basic_string_view<CharT> in, 103 CFStringEncoding in_encoding) { 104 const auto in_length = in.length(); 105 if (in_length == 0) { 106 return apple::ScopedCFTypeRef<CFStringRef>(CFSTR(""), 107 base::scoped_policy::RETAIN); 108 } 109 110 return apple::ScopedCFTypeRef<CFStringRef>(CFStringCreateWithBytes( 111 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()), 112 checked_cast<CFIndex>(in_length * sizeof(CharT)), in_encoding, false)); 113} 114 115} // namespace 116 117// The CFStringEncodings used below specify the byte ordering explicitly, 118// otherwise CFString will be confused when strings don't carry BOMs, as they 119// typically won't. 120 121// Do not assert in this function since it is used by the assertion code! 122std::string SysWideToUTF8(const std::wstring& wide) { 123 return StringToStringWithEncodingsT<std::wstring, std::string>( 124 wide, kCFStringEncodingUTF32LE, kCFStringEncodingUTF8); 125} 126 127// Do not assert in this function since it is used by the assertion code! 128std::wstring SysUTF8ToWide(std::string_view utf8) { 129 return StringToStringWithEncodingsT<std::string_view, std::wstring>( 130 utf8, kCFStringEncodingUTF8, kCFStringEncodingUTF32LE); 131} 132 133std::string SysWideToNativeMB(const std::wstring& wide) { 134 return SysWideToUTF8(wide); 135} 136 137std::wstring SysNativeMBToWide(std::string_view native_mb) { 138 return SysUTF8ToWide(native_mb); 139} 140 141apple::ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef( 142 std::string_view utf8) { 143 return StringPieceToCFStringWithEncodingsT(utf8, kCFStringEncodingUTF8); 144} 145 146apple::ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef( 147 std::u16string_view utf16) { 148 return StringPieceToCFStringWithEncodingsT(utf16, kCFStringEncodingUTF16LE); 149} 150 151NSString* SysUTF8ToNSString(std::string_view utf8) { 152 return base::apple::CFToNSOwnershipCast(SysUTF8ToCFStringRef(utf8).release()); 153} 154 155NSString* SysUTF16ToNSString(std::u16string_view utf16) { 156 return base::apple::CFToNSOwnershipCast( 157 SysUTF16ToCFStringRef(utf16).release()); 158} 159 160std::string SysCFStringRefToUTF8(CFStringRef ref) { 161 return CFStringToStringWithEncodingT<std::string>(ref, kCFStringEncodingUTF8); 162} 163 164std::u16string SysCFStringRefToUTF16(CFStringRef ref) { 165 return CFStringToStringWithEncodingT<std::u16string>( 166 ref, kCFStringEncodingUTF16LE); 167} 168 169std::string SysNSStringToUTF8(NSString* nsstring) { 170 if (!nsstring) { 171 return std::string(); 172 } 173 return SysCFStringRefToUTF8(apple::NSToCFPtrCast(nsstring)); 174} 175 176std::u16string SysNSStringToUTF16(NSString* nsstring) { 177 if (!nsstring) { 178 return std::u16string(); 179 } 180 return SysCFStringRefToUTF16(apple::NSToCFPtrCast(nsstring)); 181} 182 183} // namespace base 184