| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/strings/sys_string_conversions.h" |
| |
| #import <Foundation/Foundation.h> |
| #include <stddef.h> |
| |
| #include <string_view> |
| #include <vector> |
| |
| #include "base/apple/bridging.h" |
| #include "base/apple/foundation_util.h" |
| #include "base/apple/scoped_cftyperef.h" |
| #include "base/numerics/safe_conversions.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| // Converts the supplied CFString into the specified encoding, and returns it as |
| // a C++ library string of the template type. Returns an empty string on |
| // failure. |
| // |
| // Do not assert in this function since it is used by the assertion code! |
| template <typename StringType> |
| StringType CFStringToStringWithEncodingT(CFStringRef cfstring, |
| CFStringEncoding encoding) { |
| CFIndex length = CFStringGetLength(cfstring); |
| if (length == 0) { |
| return StringType(); |
| } |
| |
| CFRange whole_string = CFRangeMake(0, length); |
| CFIndex out_size; |
| CFIndex converted = CFStringGetBytes(cfstring, whole_string, encoding, |
| /*lossByte=*/0, |
| /*isExternalRepresentation=*/false, |
| /*buffer=*/nullptr, |
| /*maxBufLen=*/0, &out_size); |
| if (converted == 0 || out_size <= 0) { |
| return StringType(); |
| } |
| |
| // `out_size` is the number of UInt8-sized units needed in the destination. |
| // A buffer allocated as UInt8 units might not be properly aligned to |
| // contain elements of StringType::value_type. Use a container for the |
| // proper value_type, and convert `out_size` by figuring the number of |
| // value_type elements per UInt8. Leave room for a NUL terminator. |
| size_t elements = static_cast<size_t>(out_size) * sizeof(UInt8) / |
| sizeof(typename StringType::value_type) + |
| 1; |
| |
| std::vector<typename StringType::value_type> out_buffer(elements); |
| converted = |
| CFStringGetBytes(cfstring, whole_string, encoding, |
| /*lossByte=*/0, |
| /*isExternalRepresentation=*/false, |
| reinterpret_cast<UInt8*>(&out_buffer[0]), out_size, |
| /*usedBufLen=*/nullptr); |
| if (converted == 0) { |
| return StringType(); |
| } |
| |
| out_buffer[elements - 1] = '\0'; |
| return StringType(&out_buffer[0], elements - 1); |
| } |
| |
| // Given a C++ library string `in` with an encoding specified by `in_encoding`, |
| // converts it to `out_encoding` and returns it as a C++ library string of the |
| // `OutStringType` template type. Returns an empty string on failure. |
| // |
| // Do not assert in this function since it is used by the assertion code! |
| template <typename InStringType, typename OutStringType> |
| OutStringType StringToStringWithEncodingsT(const InStringType& in, |
| CFStringEncoding in_encoding, |
| CFStringEncoding out_encoding) { |
| typename InStringType::size_type in_length = in.length(); |
| if (in_length == 0) { |
| return OutStringType(); |
| } |
| |
| apple::ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy( |
| kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()), |
| checked_cast<CFIndex>(in_length * |
| sizeof(typename InStringType::value_type)), |
| in_encoding, |
| /*isExternalRepresentation=*/false, kCFAllocatorNull)); |
| if (!cfstring) { |
| return OutStringType(); |
| } |
| |
| return CFStringToStringWithEncodingT<OutStringType>(cfstring.get(), |
| out_encoding); |
| } |
| |
| // Given a std::string_view `in` with an encoding specified by `in_encoding`, |
| // returns it as a CFStringRef. Returns null on failure. |
| template <typename CharT> |
| apple::ScopedCFTypeRef<CFStringRef> StringPieceToCFStringWithEncodingsT( |
| std::basic_string_view<CharT> in, |
| CFStringEncoding in_encoding) { |
| const auto in_length = in.length(); |
| if (in_length == 0) { |
| return apple::ScopedCFTypeRef<CFStringRef>(CFSTR(""), |
| base::scoped_policy::RETAIN); |
| } |
| |
| return apple::ScopedCFTypeRef<CFStringRef>(CFStringCreateWithBytes( |
| kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()), |
| checked_cast<CFIndex>(in_length * sizeof(CharT)), in_encoding, false)); |
| } |
| |
| } // namespace |
| |
| // The CFStringEncodings used below specify the byte ordering explicitly, |
| // otherwise CFString will be confused when strings don't carry BOMs, as they |
| // typically won't. |
| |
| // Do not assert in this function since it is used by the assertion code! |
| std::string SysWideToUTF8(const std::wstring& wide) { |
| return StringToStringWithEncodingsT<std::wstring, std::string>( |
| wide, kCFStringEncodingUTF32LE, kCFStringEncodingUTF8); |
| } |
| |
| // Do not assert in this function since it is used by the assertion code! |
| std::wstring SysUTF8ToWide(std::string_view utf8) { |
| return StringToStringWithEncodingsT<std::string_view, std::wstring>( |
| utf8, kCFStringEncodingUTF8, kCFStringEncodingUTF32LE); |
| } |
| |
| std::string SysWideToNativeMB(const std::wstring& wide) { |
| return SysWideToUTF8(wide); |
| } |
| |
| std::wstring SysNativeMBToWide(std::string_view native_mb) { |
| return SysUTF8ToWide(native_mb); |
| } |
| |
| apple::ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef( |
| std::string_view utf8) { |
| return StringPieceToCFStringWithEncodingsT(utf8, kCFStringEncodingUTF8); |
| } |
| |
| apple::ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef( |
| std::u16string_view utf16) { |
| return StringPieceToCFStringWithEncodingsT(utf16, kCFStringEncodingUTF16LE); |
| } |
| |
| NSString* SysUTF8ToNSString(std::string_view utf8) { |
| return base::apple::CFToNSOwnershipCast(SysUTF8ToCFStringRef(utf8).release()); |
| } |
| |
| NSString* SysUTF16ToNSString(std::u16string_view utf16) { |
| return base::apple::CFToNSOwnershipCast( |
| SysUTF16ToCFStringRef(utf16).release()); |
| } |
| |
| std::string SysCFStringRefToUTF8(CFStringRef ref) { |
| return CFStringToStringWithEncodingT<std::string>(ref, kCFStringEncodingUTF8); |
| } |
| |
| std::u16string SysCFStringRefToUTF16(CFStringRef ref) { |
| return CFStringToStringWithEncodingT<std::u16string>( |
| ref, kCFStringEncodingUTF16LE); |
| } |
| |
| std::string SysNSStringToUTF8(NSString* nsstring) { |
| if (!nsstring) { |
| return std::string(); |
| } |
| return SysCFStringRefToUTF8(apple::NSToCFPtrCast(nsstring)); |
| } |
| |
| std::u16string SysNSStringToUTF16(NSString* nsstring) { |
| if (!nsstring) { |
| return std::u16string(); |
| } |
| return SysCFStringRefToUTF16(apple::NSToCFPtrCast(nsstring)); |
| } |
| |
| } // namespace base |