[dsymutil][NFC] Replace calls to CoreFoundation with LLVM equivalent.

This patch replaces a block of logic that was implemented using
CoreFoundations calls with functionally equivalent logic that makes use
of LLVM libraries.

llvm-svn: 321522
This commit is contained in:
Jonas Devlieghere 2017-12-28 14:05:49 +00:00
parent da8daa3fe8
commit 314981bacd
1 changed files with 33 additions and 53 deletions

View File

@ -11,6 +11,7 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <assert.h> #include <assert.h>
@ -56,7 +57,7 @@ public:
static const char *UTF8(CFStringRef CFStr, std::string &Str); static const char *UTF8(CFStringRef CFStr, std::string &Str);
}; };
/// Static function that puts a copy of the UTF8 contents of CFStringRef into /// Static function that puts a copy of the UTF-8 contents of CFStringRef into
/// std::string and returns the C string pointer that is contained in the /// std::string and returns the C string pointer that is contained in the
/// std::string when successful, nullptr otherwise. /// std::string when successful, nullptr otherwise.
/// ///
@ -85,13 +86,10 @@ const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) {
/// RAII wrapper around CFBundleRef. /// RAII wrapper around CFBundleRef.
class CFBundle : public CFReleaser<CFBundleRef> { class CFBundle : public CFReleaser<CFBundleRef> {
public: public:
CFBundle(const char *Path = nullptr) : CFReleaser<CFBundleRef>() { CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); }
if (Path && Path[0])
SetFromPath(Path);
}
CFBundle(CFURLRef url) CFBundle(CFURLRef Url)
: CFReleaser<CFBundleRef>(url ? ::CFBundleCreate(nullptr, url) : CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url)
: nullptr) {} : nullptr) {}
/// Return the bundle identifier. /// Return the bundle identifier.
@ -109,67 +107,49 @@ public:
} }
private: private:
/// Update this instance with a new bundle created from the given path. /// Helper to initialize this instance with a new bundle created from the
bool SetFromPath(const char *Path); /// given path. This function will recursively remove components from the
/// path in its search for the nearest Info.plist.
void SetFromPath(StringRef Path);
}; };
bool CFBundle::SetFromPath(const char *InPath) { void CFBundle::SetFromPath(StringRef Path) {
// Release our old bundle and URL. // Start from an empty/invalid CFBundle.
reset(); reset();
if (InPath && InPath[0]) { if (Path.empty() || !sys::fs::exists(Path))
char ResolvedPath[PATH_MAX]; return;
const char *Path = ::realpath(InPath, ResolvedPath);
if (Path == nullptr)
Path = InPath;
CFAllocatorRef Allocator = kCFAllocatorDefault; SmallString<256> RealPath;
// Make our Bundle URL. sys::fs::real_path(Path, RealPath, /*expand_tilde*/ true);
do {
// Create a CFURL from the current path and use it to create a CFBundle.
CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation( CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation(
Allocator, (const UInt8 *)Path, strlen(Path), false)); kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(),
if (BundleURL.get()) { false));
CFIndex LastLength = LONG_MAX; reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get()));
while (BundleURL.get() != nullptr) { // If we have a valid bundle and find its identifier we are done.
// Check the Path range and make sure we didn't make it to just "/", if (get() != nullptr) {
// ".", or "..". if (GetIdentifier() != nullptr)
CFRange rangeIncludingSeparators; return;
CFRange range = ::CFURLGetByteRangeForComponent( reset();
BundleURL.get(), kCFURLComponentPath, &rangeIncludingSeparators);
if (range.length > LastLength)
break;
reset(::CFBundleCreate(Allocator, BundleURL.get()));
if (get() != nullptr) {
if (GetIdentifier() != nullptr)
break;
reset();
}
BundleURL.reset(::CFURLCreateCopyDeletingLastPathComponent(
Allocator, BundleURL.get()));
LastLength = range.length;
}
} }
}
return get() != nullptr; // Remove the last component of the path and try again until there's
// nothing left but the root.
sys::path::remove_filename(RealPath);
} while (RealPath != sys::path::root_name(RealPath));
} }
#endif #endif
/// On Darwin, try and find the original executable's Info.plist information /// On Darwin, try and find the original executable's Info.plist to extract
/// using CoreFoundation calls by creating a URL for the executable and /// information about the bundle. Return default values on other platforms.
/// chopping off the last Path component. The CFBundle can then get the
/// identifier and grab any needed information from it directly. Return default
/// CFBundleInfo on other platforms.
CFBundleInfo getBundleInfo(StringRef ExePath) { CFBundleInfo getBundleInfo(StringRef ExePath) {
CFBundleInfo BundleInfo; CFBundleInfo BundleInfo;
#ifdef __APPLE__ #ifdef __APPLE__
if (ExePath.empty() || !sys::fs::exists(ExePath))
return BundleInfo;
auto PrintError = [&](CFTypeID TypeID) { auto PrintError = [&](CFTypeID TypeID) {
CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID)); CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID));
std::string TypeIDStr; std::string TypeIDStr;
@ -178,7 +158,7 @@ CFBundleInfo getBundleInfo(StringRef ExePath) {
<< ", but it should be a string in: " << ExePath << ".\n"; << ", but it should be a string in: " << ExePath << ".\n";
}; };
CFBundle Bundle(ExePath.data()); CFBundle Bundle(ExePath);
if (CFStringRef BundleID = Bundle.GetIdentifier()) { if (CFStringRef BundleID = Bundle.GetIdentifier()) {
CFString::UTF8(BundleID, BundleInfo.IDStr); CFString::UTF8(BundleID, BundleInfo.IDStr);
if (CFTypeRef TypeRef = if (CFTypeRef TypeRef =