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 <vector> 11 12#include "base/apple/bridging.h" 13#include "base/apple/foundation_util.h" 14#include "base/apple/scoped_cftyperef.h" 15#include "base/numerics/safe_conversions.h" 16#include "base/strings/string_piece.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 StringPiece `in` with an encoding specified by `in_encoding`, returns 99// it as a CFStringRef. Returns null on failure. 100template <typename CharT> 101apple::ScopedCFTypeRef<CFStringRef> StringPieceToCFStringWithEncodingsT( 102 BasicStringPiece<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(StringPiece utf8) { 129 return StringToStringWithEncodingsT<StringPiece, std::wstring>( 130 utf8, kCFStringEncodingUTF8, kCFStringEncodingUTF32LE); 131} 132 133std::string SysWideToNativeMB(const std::wstring& wide) { 134 return SysWideToUTF8(wide); 135} 136 137std::wstring SysNativeMBToWide(StringPiece native_mb) { 138 return SysUTF8ToWide(native_mb); 139} 140 141apple::ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef(StringPiece utf8) { 142 return StringPieceToCFStringWithEncodingsT(utf8, kCFStringEncodingUTF8); 143} 144 145apple::ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef(StringPiece16 utf16) { 146 return StringPieceToCFStringWithEncodingsT(utf16, kCFStringEncodingUTF16LE); 147} 148 149NSString* SysUTF8ToNSString(StringPiece utf8) { 150 return base::apple::CFToNSOwnershipCast(SysUTF8ToCFStringRef(utf8).release()); 151} 152 153NSString* SysUTF16ToNSString(StringPiece16 utf16) { 154 return base::apple::CFToNSOwnershipCast( 155 SysUTF16ToCFStringRef(utf16).release()); 156} 157 158std::string SysCFStringRefToUTF8(CFStringRef ref) { 159 return CFStringToStringWithEncodingT<std::string>(ref, kCFStringEncodingUTF8); 160} 161 162std::u16string SysCFStringRefToUTF16(CFStringRef ref) { 163 return CFStringToStringWithEncodingT<std::u16string>( 164 ref, kCFStringEncodingUTF16LE); 165} 166 167std::string SysNSStringToUTF8(NSString* nsstring) { 168 if (!nsstring) { 169 return std::string(); 170 } 171 return SysCFStringRefToUTF8(apple::NSToCFPtrCast(nsstring)); 172} 173 174std::u16string SysNSStringToUTF16(NSString* nsstring) { 175 if (!nsstring) { 176 return std::u16string(); 177 } 178 return SysCFStringRefToUTF16(apple::NSToCFPtrCast(nsstring)); 179} 180 181} // namespace base 182