1 //===-- CFString.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  Created by Greg Clayton on 1/16/08.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CFString.h"
14 #include <glob.h>
15 #include <string>
16 
17 //----------------------------------------------------------------------
18 // CFString constructor
19 //----------------------------------------------------------------------
20 CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {}
21 
22 //----------------------------------------------------------------------
23 // CFString copy constructor
24 //----------------------------------------------------------------------
25 CFString::CFString(const CFString &rhs) : CFReleaser<CFStringRef>(rhs) {}
26 
27 //----------------------------------------------------------------------
28 // CFString copy constructor
29 //----------------------------------------------------------------------
30 CFString &CFString::operator=(const CFString &rhs) {
31   if (this != &rhs)
32     *this = rhs;
33   return *this;
34 }
35 
36 CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding)
37     : CFReleaser<CFStringRef>() {
38   if (cstr && cstr[0]) {
39     reset(
40         ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
41   }
42 }
43 
44 //----------------------------------------------------------------------
45 // Destructor
46 //----------------------------------------------------------------------
47 CFString::~CFString() {}
48 
49 const char *CFString::GetFileSystemRepresentation(std::string &s) {
50   return CFString::FileSystemRepresentation(get(), s);
51 }
52 
53 CFStringRef CFString::SetFileSystemRepresentation(const char *path) {
54   CFStringRef new_value = NULL;
55   if (path && path[0])
56     new_value =
57         ::CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
58   reset(new_value);
59   return get();
60 }
61 
62 CFStringRef CFString::SetFileSystemRepresentationFromCFType(CFTypeRef cf_type) {
63   CFStringRef new_value = NULL;
64   if (cf_type != NULL) {
65     CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
66 
67     if (cf_type_id == ::CFStringGetTypeID()) {
68       // Retain since we are using the existing object
69       new_value = (CFStringRef)::CFRetain(cf_type);
70     } else if (cf_type_id == ::CFURLGetTypeID()) {
71       new_value =
72           ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
73     }
74   }
75   reset(new_value);
76   return get();
77 }
78 
79 CFStringRef
80 CFString::SetFileSystemRepresentationAndExpandTilde(const char *path) {
81   std::string expanded_path;
82   if (CFString::GlobPath(path, expanded_path))
83     SetFileSystemRepresentation(expanded_path.c_str());
84   else
85     reset();
86   return get();
87 }
88 
89 const char *CFString::UTF8(std::string &str) {
90   return CFString::UTF8(get(), str);
91 }
92 
93 // Static function that puts a copy of the UTF8 contents of CF_STR into STR
94 // and returns the C string pointer that is contained in STR when successful,
95 // else
96 // NULL is returned. This allows the std::string parameter to own the extracted
97 // string,
98 // and also allows that string to be returned as a C string pointer that can be
99 // used.
100 
101 const char *CFString::UTF8(CFStringRef cf_str, std::string &str) {
102   if (cf_str) {
103     const CFStringEncoding encoding = kCFStringEncodingUTF8;
104     CFIndex max_utf8_str_len = CFStringGetLength(cf_str);
105     max_utf8_str_len =
106         CFStringGetMaximumSizeForEncoding(max_utf8_str_len, encoding);
107     if (max_utf8_str_len > 0) {
108       str.resize(max_utf8_str_len);
109       if (!str.empty()) {
110         if (CFStringGetCString(cf_str, &str[0], str.size(), encoding)) {
111           str.resize(strlen(str.c_str()));
112           return str.c_str();
113         }
114       }
115     }
116   }
117   return NULL;
118 }
119 
120 // Static function that puts a copy of the file system representation of CF_STR
121 // into STR and returns the C string pointer that is contained in STR when
122 // successful, else NULL is returned. This allows the std::string parameter
123 // to own the extracted string, and also allows that string to be returned as
124 // a C string pointer that can be used.
125 
126 const char *CFString::FileSystemRepresentation(CFStringRef cf_str,
127                                                std::string &str) {
128   if (cf_str) {
129     CFIndex max_length =
130         ::CFStringGetMaximumSizeOfFileSystemRepresentation(cf_str);
131     if (max_length > 0) {
132       str.resize(max_length);
133       if (!str.empty()) {
134         if (::CFStringGetFileSystemRepresentation(cf_str, &str[0],
135                                                   str.size())) {
136           str.erase(::strlen(str.c_str()));
137           return str.c_str();
138         }
139       }
140     }
141   }
142   str.erase();
143   return NULL;
144 }
145 
146 CFIndex CFString::GetLength() const {
147   CFStringRef str = get();
148   if (str)
149     return CFStringGetLength(str);
150   return 0;
151 }
152 
153 const char *CFString::GlobPath(const char *path, std::string &expanded_path) {
154   glob_t globbuf;
155   if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) {
156     expanded_path = globbuf.gl_pathv[0];
157     ::globfree(&globbuf);
158   } else
159     expanded_path.clear();
160 
161   return expanded_path.c_str();
162 }
163