#include "CFBundle.h"
#ifdef __APPLE__
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <CoreFoundation/CoreFoundation.h>
#include <assert.h>
#include <glob.h>
#include <memory>
#endif
namespace llvm {
namespace dsymutil {
#ifdef __APPLE__
template <typename T> struct CFDeleter {
void operator()(T *P) {
if (P)
::CFRelease(P);
}
};
template <typename T>
using CFReleaser = std::unique_ptr<std::remove_pointer_t<T>,
CFDeleter<std::remove_pointer_t<T>>>;
class CFString : public CFReleaser<CFStringRef> {
public:
CFString(CFStringRef CFStr = nullptr) : CFReleaser<CFStringRef>(CFStr) {}
const char *UTF8(std::string &Str) const {
return CFString::UTF8(get(), Str);
}
CFIndex GetLength() const {
if (CFStringRef Str = get())
return CFStringGetLength(Str);
return 0;
}
static const char *UTF8(CFStringRef CFStr, std::string &Str);
};
const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) {
if (!CFStr)
return nullptr;
const CFStringEncoding Encoding = kCFStringEncodingUTF8;
CFIndex MaxUTF8StrLength = CFStringGetLength(CFStr);
MaxUTF8StrLength =
CFStringGetMaximumSizeForEncoding(MaxUTF8StrLength, Encoding);
if (MaxUTF8StrLength > 0) {
Str.resize(MaxUTF8StrLength);
if (!Str.empty() &&
CFStringGetCString(CFStr, &Str[0], Str.size(), Encoding)) {
Str.resize(strlen(Str.c_str()));
return Str.c_str();
}
}
return nullptr;
}
class CFBundle : public CFReleaser<CFBundleRef> {
public:
CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); }
CFBundle(CFURLRef Url)
: CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url)
: nullptr) {}
CFStringRef GetIdentifier() const {
if (CFBundleRef bundle = get())
return ::CFBundleGetIdentifier(bundle);
return nullptr;
}
CFTypeRef GetValueForInfoDictionaryKey(CFStringRef key) const {
if (CFBundleRef bundle = get())
return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
return nullptr;
}
private:
void SetFromPath(StringRef Path);
};
void CFBundle::SetFromPath(StringRef Path) {
reset();
if (Path.empty() || !sys::fs::exists(Path))
return;
SmallString<256> RealPath;
sys::fs::real_path(Path, RealPath, true);
do {
CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(),
false));
reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get()));
if (get() != nullptr) {
if (GetIdentifier() != nullptr)
return;
reset();
}
sys::path::remove_filename(RealPath);
} while (RealPath != sys::path::root_name(RealPath));
}
#endif
CFBundleInfo getBundleInfo(StringRef ExePath) { … }
}
}