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