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:
skalogryz
2015-03-16 03:55:19 +00:00
parent 95edadbd29
commit 186029ef86
5 changed files with 241 additions and 23 deletions

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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 = '&amp;';
lt = '&lt;';
gt = '&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);

View File

@ -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, '');