{
*****************************************************************************
* *
* This file is part of the iPhone Laz Extension *
* *
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
* for details about the copyright. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
*****************************************************************************
}
unit iPhoneBundle;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LazFileUtils, PlistFile;
const
platform_iPhoneSim = 'iphonesimulator';
sdk_iPhoneSim2_0 = 'iphonesimulator2.0';
sdk_iPhoneSim2_1 = 'iphonesimulator2.1';
sdk_iPhoneSim2_2 = 'iphonesimulator2.2';
sdk_iPhoneSim3_0 = 'iphonesimulator3.0';
sdk_iPhoneSim3_1 = 'iphonesimulator3.1';
type
TiPhoneBundleInfo = record
DisplayName : WideString; {if DisplayName='' then DisplayName=BundleName}
iPlatform : WideString;
SDKVersion : WideString;
AppID : WideString;
MainNib : WideString;
end;
function GetiPhoneSimUserPath: WideString;
procedure MakeSimSpaceStruct(const BundleName: WideString; var BundleAppDir: WideString);
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, BundleName: WideString; var BundleAppDir: WideString);
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, SpaceName, BundleName: WideString; var BundleAppDir: WideString);
function GetBundleExeName(const BundleAppDir, ExeName: WideString): WideString;
procedure WritePkgFile(const FileName: WideString);
function WriteDefInfoList_(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
function WriteDefInfoList(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
procedure CreateBundle(const BundleName, ExeName: WideString; const Info: TiPhoneBundleInfo; var FullBundlePath, FullExeName: WideString);
procedure CreateBundle(const BundleName, SpaceName, ExeName: WideString; const Info: TiPhoneBundleInfo; var RealSpace, FullBundlePath, FullExeName: WideString);
function GetBundleFullDir(const BundleName, SpaceName: WideString): WideString;
function GetSandBoxDir(const SpaceName: WideString): WideString;
function AddPathDelim(const w: WideString): WideString;
function RandomSpaceName: WideString;
implementation
uses
iPhoneExtOptions;
function RandomSpaceName: WideString;
var
g : TGUID;
id : String;
begin
CreateGUID(g);
id:=GUIDToString(g);
id:=Copy(id, 2, length(id)-2);
Result:=id;
end;
procedure CreateBundle(const BundleName, SpaceName, ExeName: WideString; const Info: TiPhoneBundleInfo; var RealSpace, FullBundlePath, FullExeName: WideString);
var
appdir : WideString;
begin
if SpaceName='' then
RealSpace:=RandomSpaceName
else
RealSpace:=SpaceName;
MakeSimSpaceStruct(GetiPhoneSimUserPath, RealSpace, BundleName, appdir);
FullBundlePath:=appdir;
appdir:=AddPathDelim(appdir);
FullExeName:=appdir+ExeName;
WritePkgFile(appdir+'PkgInfo');
WriteDefInfoList(appdir+'Info.plist', BundleName, ExeName, Info);
end;
function GetBundleFullDir(const BundleName, SpaceName: WideString): WideString;
var
path8 : String;
space8 : String;
p : string;
begin
path8:=UTF8Encode(GetiPhoneSimUserPath);
space8:=UTF8Encode(SpaceName);
p:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(path8)+space8);
Result:=UTF8Decode(p+UTF8Encode(BundleName)+'.app');
end;
function GetSandBoxDir(const SpaceName: WideString): WideString;
var
path8 : String;
space8 : String;
p : string;
begin
path8:=UTF8Encode(GetiPhoneSimUserPath);
space8:=UTF8Encode(SpaceName);
p:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(path8)+space8);
if DirectoryExistsUTF8(p) then
Result:=UTF8Decode(p)
else if DirectoryExistsUTF8(path8) then
result:=path8
else
result :='';
end;
procedure CreateBundle(const BundleName, ExeName: WideString; const Info: TiPhoneBundleInfo; var FullBundlePath, FullExeName: WideString);
var
sp : WideString;
begin
CreateBundle(BundleName, '', ExeName, Info, sp, FullBundlePath, FullExeName);
end;
function AddPathDelim(const w: WideString): WideString;
begin
if w='' then
Result:=PathDelim
else if w[length(w)]<>PathDelim then
Result:=w+PathDelim;
end;
function GetiPhoneSimUserPath: WideString;
var
s : String;
begin
s := EnvOptions.SimAppsPath;
EnvOptions.SubstituteMacros(s);
result := s;
end;
{
~/Library/Application Support/iPhone Simulator/Users/%SPACENAME%
%SPACENAME%/Applications
%SPACENAME%/Applications/%AppBundle.app%
%SPACENAME%/Documents
%SPACENAME%/tmp
}
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, SpaceName, BundleName: WideString; var BundleAppDir: WideString);
var
path8 : String;
space8 : String;
p : string;
begin
path8:=UTF8Encode(iPhoneSimUserPath);
space8:=UTF8Encode(SpaceName);
p:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(path8)+space8);
BundleAppDir:=UTF8Decode(p+UTF8Encode(BundleName)+'.app');
ForceDirectories(UTF8Encode(BundleAppDir));
ForceDirectories(p+'Documents');
ForceDirectories(p+'tmp');
end;
procedure MakeSimSpaceStruct(const iPhoneSimUserPath, BundleName: WideString; var BundleAppDir: WideString);
begin
MakeSimSpaceStruct(iPhoneSimUserPath, RandomSpaceName, BundleName, BundleAppDir);
end;
procedure MakeSimSpaceStruct(const BundleName: WideString; var BundleAppDir: WideString);
begin
MakeSimSpaceStruct( GetiPhoneSimUserPath, BundleName, BundleAppDir);
end;
function GetBundleExeName(const BundleAppDir, ExeName: WideString): WideString;
begin
Result:=AddPathDelim(BundleAppDir)+ExeName;
end;
procedure WritePkgFile(const FileName: WideString);
var
fs : TFileStream;
s : String;
begin
fs:=TFileStream.Create( UTF8Encode(FileName), fmCreate);
s:='APPL????';
fs.Write(s[1], length(s));
fs.Free;
end;
procedure InitDefaultPlist(pl: TPListFile);
var
arr : TPListValue;
begin
SetStr(pl, 'CFBundleDevelopmentRegion', 'English');
SetStr(pl, 'CFBundleDisplayName', '');
SetStr(pl, 'CFBundleExecutable', '');
SetStr(pl, 'CFBundleIdentifier', '');
SetStr(pl, 'CFBundleInfoDictionaryVersion', '6.0');
SetStr(pl, 'CFBundleName', '');
SetStr(pl, 'CFBundlePackageType', 'APPL');
SetStr(pl, 'CFBundleSignature', '????');
SetArr(pl, 'CFBundleSupportedPlatforms');
SetStr(pl, 'CFBundleVersion', '1.0');
SetStr(pl, 'DTPlatformName', '');
SetStr(pl, 'DTSDKName', '');
SetBool(pl, 'LSRequiresIPhoneOS', true);
arr:=SetArr(pl, 'UISupportedInterfaceOrientations');
AddStr(arr, 'UIInterfaceOrientationPortrait');
AddStr(arr, 'UIInterfaceOrientationLandscapeLeft');
end;
function WriteDefInfoList(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
var
pl : TPListFile;
arr : TPListValue;
begin
pl := TPListFile.Create;
try
if not FileExists(InfoFileName) then begin
InitDefaultPlist(pl);
end else
LoadFromFile(InfoFileName, pl);
SetStr(pl, 'CFBundleDisplayName', info.DisplayName);
SetStr(pl, 'CFBundleExecutable', ExeName);
SetStr(pl, 'CFBundleIdentifier', info.AppID);
SetStr(pl, 'CFBundleName', BundleName);
arr:=SetArr(pl, 'CFBundleSupportedPlatforms');
SetStr(arr, 0, info.iPlatform);
SetStr(pl, 'DTPlatformName', info.iPlatform);
SetStr(pl, 'DTSDKName', info.SDKVersion);
SaveToXMLFile(pl, InfoFileName);
finally
pl.Free;
end;
end;
function WriteDefInfoList_(const InfoFileName, BundleName, ExeName: WideString; const info: TiPhoneBundleInfo): Boolean;
const
BundleFormat : AnsiString =
''#10+
''#10+
''#10+
''#10+
' CFBundleDevelopmentRegion'#10+ ' English'#10+
' CFBundleDisplayName'#10+ ' %s'#10+ {display name}
' CFBundleExecutable'#10+ ' %s'#10+ {exe name}
' CFBundleIdentifier'#10+ ' %s'#10+ {company + bundle name}
' CFBundleInfoDictionaryVersion'#10+ ' 6.0'#10+
' CFBundleName'#10+ ' %s'#10+ {bundle name}
' CFBundlePackageType'#10+ ' APPL'#10+
' CFBundleSignature'#10+ ' ????'#10+
' CFBundleSupportedPlatforms'#10+ ' '#10+' %s'#10+' '#10+ {platform}
'%s'+ // optional MainNib name
' CFBundleVersion'#10+ ' 1.0'#10+
' DTPlatformName'#10+ ' %s'#10+ {platform}
' DTSDKName'#10+ ' %s'#10+ {sdk version}
' LSRequiresIPhoneOS'#10+ ' '#10+
' UISupportedInterfaceOrientations'#10+
' '#10+
' UIInterfaceOrientationPortrait'#10+
' UIInterfaceOrientationLandscapeLeft'#10+
' '#10+
''#10+
'';
function MainNibString(const NibName: WideString): AnsiString;
begin
if NibName='' then Result:=''
else Result:='NSMainNibFile'+UTF8Encode(NibName)+''#10;
end;
var
dispName : WideString;
s : String;
fs : TFileStream;
begin
Result:=false;
if BundleName='' then Exit;
dispName:=info.DisplayName;
if dispName='' then dispName:=BundleName;
with info do
s:=Format( BundleFormat,
[ UTF8Encode(dispName),
UTF8Encode(ExeName),
UTF8Encode(AppID),
UTF8Encode(BundleName),
UTF8Encode(iPlatform),
MainNibString(info.MainNib),
UTF8Encode(iPlatform),
UTF8Encode(SDKVersion)
]);
if FileExists(InfoFileName) then DeleteFile(InfoFileName);
fs:=TFileStream.Create(UTF8Encode(InfoFileName), fmCreate or fmOpenWrite);
try
if s<>'' then fs.Write(s[1], length(s));
finally
fs.Free;
end;
end;
end.