lazarus-ccr/components/xdev_toolkit/PropListUtil.pas

177 lines
4.9 KiB
ObjectPascal

unit PropListUtil;
{
Class for working with property list (for example, app bundle's
Info.plist).
Author: Phil Hess.
Copyright: Copyright (C) 2010 Phil Hess. All rights reserved.
License: Modified LGPL. This means you can link your code to this
compiled unit (statically in a standalone executable or
dynamically in a library) without releasing your code. Only
changes to this unit need to be made publicly available.
}
{$MODE Delphi}
interface
uses
MacOSAll,
CFHelpers; {Handy routines for use with Core Foundation}
type {Note: Not all CF object types are supported yet by this class}
TCFPropertyList = class(TObject)
private
propertyList : CFPropertyListRef;
function GetValue(const KeyName : string) : UnivPtr;
public
destructor Destroy; override;
function LoadFromFile(const FileName : string) : Boolean;
function GetString(const KeyName : string) : string;
function GetBoolean(const KeyName : string) : Boolean;
end;
function GetInfoPlistString(const KeyName : string) : string;
implementation
destructor TCFPropertyList.Destroy;
begin
FreeCFRef(propertyList);
end;
function TCFPropertyList.LoadFromFile(const FileName : string) : Boolean;
{Adapted from example ObjC code given here:
http://developer.apple.com/library/mac/documentation/Cocoa/
Conceptual/PropertyLists/SerializePlist/SerializePlist.html#//
apple_ref/doc/uid/10000048i-CH7-SW5}
var
plistFileName : CFStringRef;
fileURL : CFURLRef;
resourceData : CFDataRef;
errorCode : SInt32;
errorString : CFStringRef;
begin
Result := False;
FreeAndNilCFRef(propertyList); {In case something previously loaded}
AnsiStrToCFStr(FileName, plistFileName);
fileURL := CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
plistFileName,
kCFURLPOSIXPathStyle, {Interpret as POSIX path}
False); {Not a directory}
{Note that if file name is not absolute, treated relative
to working directory.}
FreeCFRef(plistFileName);
{Read the XML file.
Note getting resource data, not specified properties.}
try
if not CFURLCreateDataAndPropertiesFromResource(
kCFAllocatorDefault,
fileURL,
@resourceData, {Place to put XML file's data}
nil,
nil,
errorCode) then
Exit;
{Description of function suggests resourceData might
be non-null even if failure, so release below.}
{Reconstitute the dictionary using the XML data.}
propertyList := CFPropertyListCreateFromXMLData(
kCFAllocatorDefault,
resourceData,
kCFPropertyListImmutable,
@errorString);
if Assigned(propertyList) then
Result := True
else
FreeCFRef(errorString); //return this too?
finally
FreeCFRef(fileURL);
FreeCFRef(resourceData);
end;
end; {TCFPropertyList.LoadFromFile}
function TCFPropertyList.GetValue(const KeyName : string) : UnivPtr;
{Retrieve key's CF value from property list.}
var
KeyRef : CFStringRef;
begin
Result := nil;
if not Assigned(propertyList) then {Error - list not loaded?}
Exit;
if CFGetTypeID(propertyList) <> CFDictionaryGetTypeID then {Not valid?}
Exit;
AnsiStrToCFStr(KeyName, KeyRef);
Result := CFDictionaryGetValue(propertyList, KeyRef);
FreeCFRef(KeyRef);
end;
function TCFPropertyList.GetString(const KeyName : string) : string;
{Retrieve key's string value from property list.}
var
Value : UnivPtr;
begin
Result := '';
Value := GetValue(KeyName);
if not Assigned(Value) then {Key not found?}
Exit;
if CFGetTypeID(Value) = CFStringGetTypeID then {Value is a string?}
Result := CFStrToAnsiStr(Value, kCFStringEncodingUTF8); //will always be UTF8
end;
function TCFPropertyList.GetBoolean(const KeyName : string) : Boolean;
{Retrieve key's Boolean value from property list.}
var
Value : UnivPtr;
begin
Result := False;
Value := GetValue(KeyName);
if not Assigned(Value) then {Key not found?}
Exit;
if CFGetTypeID(Value) = CFBooleanGetTypeID then {Value is a Boolean?}
Result := CFBooleanGetValue(Value);
end;
function GetInfoPlistString(const KeyName : string) : string;
{Retrieve key's string value from app bundle's Info.plist file.}
var
BundleRef : CFBundleRef;
KeyRef : CFStringRef;
ValueRef : CFTypeRef;
begin
Result := '';
BundleRef := CFBundleGetMainBundle;
if BundleRef = nil then {Executable not in an app bundle?}
Exit;
AnsiStrToCFStr(KeyName, KeyRef);
try
ValueRef := CFBundleGetValueForInfoDictionaryKey(BundleRef, KeyRef);
if CFGetTypeID(ValueRef) <> CFStringGetTypeID then {Value not a string?}
Exit;
Result := CFStrToAnsiStr(ValueRef, kCFStringEncodingUTF8); //will always be UTF8
finally
FreeCFRef(KeyRef);
end;
end; {GetInfoPlistString}
end.