• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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