#include "macros.hpp"
#include "common.hpp"
#include <SystemConfiguration/SystemConfiguration.h>
#include <sys/types.h>
#include <sys/stat.h>
struct signature
{
ino_t sig_ino;
dev_t sig_dev;
size_t sig_size;
struct timespec sig_mtime;
struct timespec sig_ctime;
};
static CFDataRef get_path_signature(const char * path)
{
struct stat sbuf;
struct signature sig;
zero_struct(sig);
if (stat(path, &sbuf) == -1) {
return NULL;
}
sig.sig_dev = sbuf.st_dev;
sig.sig_ino = sbuf.st_ino;
sig.sig_mtime = sbuf.st_mtimespec;
sig.sig_ctime = sbuf.st_ctimespec;
sig.sig_size = sbuf.st_size;
return CFDataCreate(kCFAllocatorDefault,
(const UInt8 *)(&sig), sizeof(struct signature));
}
static CFPropertyListRef load_plist_from_path(const char * path)
{
CFURLRef url = NULL;
CFDataRef data = NULL;
CFStringRef err = NULL;
CFPropertyListRef plist = NULL;
url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
(const UInt8 *)path, strlen(path),
false );
if (url == NULL) {
VERBOSE("failed to build CFURL for '%s'\n", path);
goto done;
}
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
url, &data, NULL, NULL, NULL)) {
VERBOSE("failed to read CFURL data for '%s'\n", path);
goto done;
}
plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
data, kCFPropertyListImmutable, &err);
if (!plist) {
char errbuf[256];
CFStringGetCString(err, errbuf, sizeof(errbuf), kCFStringEncodingUTF8);
VERBOSE("plist parse error for '%s': %s\n",
path, errbuf);
}
done:
safe_release(err);
safe_release(url);
safe_release(data);
return plist;
}
Preferences::Preferences(const char * pspec)
: m_pspec(pspec), m_plist(NULL), m_scpref(NULL)
{
this->m_plist = load_plist_from_path(this->m_pspec.c_str());
if (this->m_plist) {
ASSERT(CFDictionaryGetTypeID() == CFGetTypeID(this->m_plist));
VERBOSE("loaded plist %s\n", pspec);
return;
}
cf_typeref<CFStringRef> appname(cfstring_wrap(getprogname()));
cf_typeref<CFStringRef> appid(cfstring_wrap(this->m_pspec.c_str()));
this->m_scpref = SCPreferencesCreate(kCFAllocatorDefault, appname, appid);
if (this->m_scpref == NULL) {
return;
}
if (SCError() != kSCStatusOK) {
safe_release(this->m_scpref);
}
if (this->m_scpref) {
VERBOSE("loaded SC preferences %s\n", pspec);
}
}
Preferences::~Preferences()
{
safe_release(this->m_plist);
safe_release(this->m_scpref);
}
CFDataRef Preferences::create_signature(void) const
{
if (this->m_plist) {
return get_path_signature(this->m_pspec.c_str());
}
if (this->m_scpref) {
CFDataRef sig;
if ((sig = SCPreferencesGetSignature(m_scpref))) {
return CFDataCreateCopy(kCFAllocatorDefault, sig);
}
}
return NULL;
}
CFPropertyListRef Preferences::get_value(CFStringRef key) const
{
CFPropertyListRef prefval = NULL;
if (!this->is_loaded()) {
return NULL;
}
if (this->m_plist) {
prefval = CFDictionaryGetValue((CFDictionaryRef)this->m_plist, key);
} else if (this->m_scpref) {
prefval = SCPreferencesGetValue(this->m_scpref, key);
}
if (Options::Debug) {
DEBUGMSG("%s value for key %s:\n",
this->m_pspec.c_str(), cfstring_convert(key).c_str());
CFShow(prefval);
}
return prefval;
}