You've already forked lazarus-ccr
iphonelazext: update the way of parsing plistadded an ability to convert to XML, if non xml plist foundadded exception catch during reading of system configuration
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4037 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -488,8 +488,11 @@ procedure Register;
|
||||
begin
|
||||
// IDE integration is done in constructor
|
||||
Extension := TiPhoneExtension.Create;
|
||||
EnvOptions.Load;
|
||||
EnvOptions.RefreshVersions;
|
||||
try
|
||||
EnvOptions.Load;
|
||||
EnvOptions.RefreshVersions;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
@ -7,18 +7,18 @@ unit iphonelazext;
|
||||
interface
|
||||
|
||||
uses
|
||||
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
||||
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
||||
environment_iphone_options, project_iphone_options, iPhoneExtOptions,
|
||||
xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, xibfile,
|
||||
xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, xibfile, PlistFile,
|
||||
LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterUnit('ideext',@ideext.Register);
|
||||
RegisterUnit('ideext', @ideext.Register);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterPackage('iphonelazext',@Register);
|
||||
RegisterPackage('iphonelazext', @Register);
|
||||
end.
|
||||
|
@ -35,6 +35,7 @@ function CopySymLinks(const SrcDir, DstDir, FilterMask: string): Boolean;
|
||||
procedure EnumFilesAtDir(const PathUtf8 : AnsiString; Dst: TStrings);
|
||||
procedure EnumFilesAtDir(const PathUtf8, AMask : AnsiString; Dst: TStrings);
|
||||
procedure ExecCmdLineNoWait(const CmdLineUtf8: AnsiString);
|
||||
function ExecCmdLineStdOut(const CmdLineUtf8: AnsiString; var StdOut: string; var ErrCode: LongWord): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
@ -221,6 +222,58 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function ExecCmdLineStdOut(const CmdLineUtf8: AnsiString; var StdOut: string; var ErrCode: LongWord): Boolean;
|
||||
var
|
||||
OurCommand : String;
|
||||
OutputLines : TStringList;
|
||||
MemStream : TStringStream;
|
||||
OurProcess : TProcess;
|
||||
NumBytes : LongInt;
|
||||
begin
|
||||
// A temp Memorystream is used to buffer the output
|
||||
MemStream := TStringStream.Create('');
|
||||
|
||||
OurProcess := TProcess.Create(nil);
|
||||
try
|
||||
OurProcess.CommandLine := CmdLineUtf8;
|
||||
//OurProcess.Executable := CmdLineUtf8;
|
||||
//OurProcess.Parameters.Add(OurCommand);
|
||||
|
||||
// We cannot use poWaitOnExit here since we don't
|
||||
// know the size of the output. On Linux the size of the
|
||||
// output pipe is 2 kB; if the output data is more, we
|
||||
// need to read the data. This isn't possible since we are
|
||||
// waiting. So we get a deadlock here if we use poWaitOnExit.
|
||||
OurProcess.Options := [poUsePipes];
|
||||
OurProcess.Execute;
|
||||
while True do
|
||||
begin
|
||||
// make sure we have room
|
||||
//MemStream.SetSize(BytesRead + READ_BYTES);
|
||||
|
||||
// try reading it
|
||||
if OurProcess.Output.NumBytesAvailable > 0 then
|
||||
MemStream.CopyFrom(OurProcess.Output, OurProcess.Output.NumBytesAvailable)
|
||||
else begin
|
||||
if not OurProcess.Active then
|
||||
Break; // Program has finished execution.
|
||||
end;
|
||||
|
||||
end;
|
||||
//MemStream.SetSize(BytesRead);
|
||||
|
||||
//OutputLines := TStringList.Create;
|
||||
//OutputLines.LoadFromStream(MemStream);
|
||||
//OutputLines.Free;
|
||||
|
||||
StdOut:=MemStream.DataString;
|
||||
Result:=true;
|
||||
finally
|
||||
OurProcess.Free;
|
||||
MemStream.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
@ -19,7 +19,7 @@ unit PlistFile;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, DOM, XMLRead;
|
||||
Classes, SysUtils, DOM, XMLRead, XMLWrite, LazFilesUtils;
|
||||
|
||||
type
|
||||
TPlistType = (ltString, ltArray, ltDict, ltData, ltDate, ltBoolean, ltNumber);
|
||||
@ -49,16 +49,20 @@ type
|
||||
TPListFile = class(TObject)
|
||||
public
|
||||
root : TPListValue;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function GetStrValue(const valname: string): string;
|
||||
end;
|
||||
|
||||
function LoadFromXML(const fn: string; plist: TPListFile): Boolean; overload;
|
||||
function LoadFromXML(doc: TXMLDocument; plist: TPListFile): Boolean; overload;
|
||||
|
||||
procedure DebugPlistFile(const fl: TPListFile; Recursive: Boolean = false);
|
||||
|
||||
function WriteXML(const plist: TPlistFile): string;
|
||||
|
||||
procedure DebugPlistFile(const fl: TPListFile);
|
||||
|
||||
function LoadFromFile(const fn: string; plist: TPListFile): Boolean;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
procedure DebugValue(kv: TPListValue; const prefix: string );
|
||||
@ -84,21 +88,147 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DebugPlistFile(const fl: TPListFile; Recursive: Boolean = false);
|
||||
procedure DebugPlistFile(const fl: TPListFile);
|
||||
begin
|
||||
DebugValue(fl.root,'');
|
||||
end;
|
||||
|
||||
function LoadFromFile(const fn: string; plist: TPListFile): Boolean;
|
||||
var
|
||||
st : TFileStream;
|
||||
buf : string[5];
|
||||
xs : string;
|
||||
err : LongWord;
|
||||
m : TStringStream;
|
||||
doc : TXMLDocument;
|
||||
begin
|
||||
//todo: detect plist type and convert is necessary
|
||||
st:=TFileSTream.Create(fn, fmOpenRead or fmShareDenyNone);
|
||||
try
|
||||
st.Read(buf, 5);
|
||||
finally
|
||||
st.Free;
|
||||
end;
|
||||
if buf='<?xml' then
|
||||
Result:=LoadFromXML(fn, plist)
|
||||
else begin
|
||||
{$ifdef darwin}
|
||||
// the utility is not available anywhere else but OSX
|
||||
if not ExecCmdLineStdOut('plutil -convert xml1 -o - "'+fn+'"', xs, err) then begin
|
||||
Result:=false;
|
||||
Exit;
|
||||
end;
|
||||
m:=TStringStream.Create(xs);
|
||||
try
|
||||
ReadXMLFile(doc, m);
|
||||
Result:=LoadFromXML(doc, plist);
|
||||
doc.Free;
|
||||
finally
|
||||
m.Free;
|
||||
end;
|
||||
{$else}
|
||||
Result:=false;
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
prefix=
|
||||
PlistXMLPrefix=
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'+LineEnding+
|
||||
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'+LineEnding+
|
||||
'<plist version="1.0">'+LineEnding;
|
||||
'<plist version="1.0">';
|
||||
|
||||
const
|
||||
EncText = ['<', '>', '&'];
|
||||
amp = '&';
|
||||
lt = '<';
|
||||
gt = '>';
|
||||
|
||||
function XMLEncodeText(const v: WideString): string;
|
||||
var
|
||||
i : integer;
|
||||
j : Integer;
|
||||
k : integer;
|
||||
b : string;
|
||||
rp : string;
|
||||
begin
|
||||
Result:='';
|
||||
b:=UTF8Encode(v);
|
||||
j:=1;
|
||||
for i:=1 to length(b) do begin
|
||||
if b[i] in EncText then begin
|
||||
if length(Result)=0 then begin
|
||||
SetLength(Result, length(b)*5);
|
||||
k:=1;
|
||||
end;
|
||||
Move(b[j], Result[k], i-j);
|
||||
inc(k, i-j);
|
||||
case b[i] of
|
||||
'<': rp:=lt;
|
||||
'>': rp:=gt;
|
||||
'&': rp:=amp;
|
||||
end;
|
||||
j:=i+1;
|
||||
Move(rp[1], Result[k], length(rp));
|
||||
inc(k, length(rp));
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
if (Result='') and (b<>'') then
|
||||
Result:=b
|
||||
else begin
|
||||
if j<length(b) then begin
|
||||
i:=length(b)+1;
|
||||
Move(b[j], Result[k], i-j);
|
||||
inc(k, i-j);
|
||||
end;
|
||||
SetLength(Result, k-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
XMLPFX = #9;
|
||||
|
||||
procedure WriteXMLValue(v: TPListValue; dst: TStrings; const pfx: string);
|
||||
const
|
||||
boolTag : array [boolean] of string = ('<false/>','<true/>');
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
case v.ValueType of
|
||||
ltBoolean: dst.Add(pfx+boolTag[v.bool]);
|
||||
ltString: dst.Add(pfx+'<string>'+XMLEncodeText(v.str)+'</string>');
|
||||
ltDict: begin
|
||||
dst.Add(pfx+'<dict>');
|
||||
for i:=0 to v.count-1 do begin
|
||||
dst.Add(XMLPFX+'<key>'+XMLEncodeText(v.names[i])+'</key>');
|
||||
WriteXMLValue(v.items[i], dst, pfx+XMLPFX);
|
||||
end;
|
||||
dst.Add(pfx+'</dict>');
|
||||
end;
|
||||
ltArray: begin
|
||||
dst.Add(pfx+'<array>');
|
||||
for i:=0 to v.count-1 do
|
||||
WriteXMLValue(v.items[i], dst, pfx+XMLPFX);
|
||||
dst.Add(pfx+'</array>');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function WriteXML(const plist: TPlistFile): string;
|
||||
var
|
||||
st: TSTringList;
|
||||
begin
|
||||
Result:=prefix;
|
||||
Result:=Result+'</plist>';
|
||||
st:=TSTringList.Create;
|
||||
try
|
||||
st.Add(PlistXMLPrefix);
|
||||
WriteXMLValue(plist.root, st, '');
|
||||
st.Add('</plist>');
|
||||
Result:=st.Text;
|
||||
finally
|
||||
st.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function LoadFromXML(const fn: string; plist: TPListFile): Boolean; overload;
|
||||
@ -107,6 +237,7 @@ var
|
||||
begin
|
||||
ReadXMLFile(doc, fn);
|
||||
Result:=LoadFromXML(doc, plist);
|
||||
doc.Free;
|
||||
end;
|
||||
|
||||
function ReadValByNode(valnode: TDomNode): TPListValue; forward;
|
||||
@ -148,7 +279,7 @@ begin
|
||||
while Assigned(nd) do begin
|
||||
if nd.NodeName='key' then begin
|
||||
idx:=kv.AddValue;
|
||||
kv.names[idx]:=nd.TextContent;
|
||||
kv.names[idx]:=UTF8Encode(nd.TextContent);
|
||||
nd:=nd.NextSibling;
|
||||
if Assigned(nd) then begin
|
||||
kv.items[idx]:=ReadValByNode(nd);
|
||||
@ -180,6 +311,7 @@ function LoadFromXML(doc: TXMLDocument; plist: TPListFile): Boolean; overload;
|
||||
var
|
||||
root : TDOMNode;
|
||||
nd : TDOMNode;
|
||||
r : TPListValue;
|
||||
begin
|
||||
Result:=false;
|
||||
root:=doc.FirstChild; //('plist');
|
||||
@ -193,16 +325,42 @@ begin
|
||||
if not Assigned(root) then Exit;
|
||||
|
||||
nd:=root.FirstChild;
|
||||
r:=plist.root;
|
||||
plist.root:=ReadValByNode(nd);
|
||||
if Assigned(plist.root) then r.Free;
|
||||
Result:=true;
|
||||
end;
|
||||
|
||||
constructor TPListFile.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
root:=TPListValue.Create(ltDict)
|
||||
end;
|
||||
|
||||
destructor TPListFile.Destroy;
|
||||
begin
|
||||
root.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TPListFile.GetStrValue(const valname: string): string;
|
||||
var
|
||||
i : integer;
|
||||
begin
|
||||
if not Assigned(root) or (root.ValueType<>ltDict) then begin
|
||||
Result:='';
|
||||
Exit;
|
||||
end;
|
||||
|
||||
for i:=0 to root.count-1 do
|
||||
if root.names[i]=valname then begin
|
||||
Result:=UTF8Encode(root.items[i].str);
|
||||
Exit;
|
||||
end;
|
||||
Result:='';
|
||||
|
||||
end;
|
||||
|
||||
{ TPListValue }
|
||||
|
||||
constructor TPListValue.Create(AType: TPlistType);
|
||||
|
@ -47,13 +47,16 @@ var
|
||||
plist : TPListFile;
|
||||
begin
|
||||
Result:=False;
|
||||
plist:=TPListFile.Create(FileName);
|
||||
plist:=TPListFile.Create;
|
||||
try
|
||||
plistfile.LoadFromFile(FileName, plist);
|
||||
|
||||
Descr.Name:=plist.GetStrValue('CanonicalName');
|
||||
Descr.Alternate:=plist.GetStrValue('AlternateSDK');
|
||||
Descr.Version:=plist.GetStrValue('Version');
|
||||
|
||||
plist.Free;
|
||||
Descr.Name:=plist.GetStrValue('CanonicalName');
|
||||
Descr.Alternate:=plist.GetStrValue('AlternateSDK');
|
||||
Descr.Version:=plist.GetStrValue('Version');
|
||||
finally
|
||||
plist.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function isSDKDir(const SDKDir: String; var d: TSDKDescription): Boolean;
|
||||
@ -163,7 +166,8 @@ begin
|
||||
xib:='';
|
||||
for j:=0 to files.Count-1 do
|
||||
if AnsiLowerCase(ExtractFileExt(files[j]))='.plist' then begin
|
||||
plist:=TPListFile.Create(files[j]);
|
||||
plist:=TPListFile.Create;
|
||||
plistfile.LoadFromFile(files[j],plist);
|
||||
xib:=plist.GetStrValue('MainTemplateFile');
|
||||
descr:=plist.GetStrValue('Description');
|
||||
name:=ChangeFileExt(xib, '');
|
||||
|
Reference in New Issue
Block a user