summaryrefslogtreecommitdiff
path: root/utils/pas2jni/writer.pas
diff options
context:
space:
mode:
authoryury <yury@3ad0048d-3df7-0310-abae-a5850022a9f2>2013-04-03 13:38:36 +0000
committeryury <yury@3ad0048d-3df7-0310-abae-a5850022a9f2>2013-04-03 13:38:36 +0000
commit9f290b5f921874d703e503529ae60c65144845c8 (patch)
treee4c6036c3785b92bfaa8f57484ab0f9e5f0040fd /utils/pas2jni/writer.pas
parentbb87e635a307900d3ffccd53a9872663361f6492 (diff)
downloadfpc-9f290b5f921874d703e503529ae60c65144845c8.tar.gz
+ pas2jni - an utility to generates a JNI (Java Native Interface) bridge for a Pascal code. Then the Pascal code (including classes and other advanced features) can be easily used in Java programs.
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@24137 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'utils/pas2jni/writer.pas')
-rw-r--r--utils/pas2jni/writer.pas2156
1 files changed, 2156 insertions, 0 deletions
diff --git a/utils/pas2jni/writer.pas b/utils/pas2jni/writer.pas
new file mode 100644
index 0000000000..984b15d3eb
--- /dev/null
+++ b/utils/pas2jni/writer.pas
@@ -0,0 +1,2156 @@
+{
+ pas2jni - JNI bridge generator for Pascal.
+
+ Copyright (c) 2013 by Yury Sidorov.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+
+unit writer;
+
+{$mode objfpc}{$H+}
+
+interface
+
+{$define DEBUG}
+
+{$ifdef DEBUG}
+{$ASSERTIONS ON}
+{$endif}
+
+uses
+ Classes, SysUtils, def, contnrs, PPUParser;
+
+const
+ MaxMethodPointers = 10000;
+
+type
+ { TTextOutStream }
+
+ TTextOutStream = class(TFileStream)
+ private
+ FIndent: integer;
+ FIndStr: string;
+ procedure SetIndednt(const AValue: integer);
+ public
+ procedure Write(const s: ansistring); overload;
+ procedure WriteLn(const s: ansistring = ''; ExtraIndent: integer = 0);
+ procedure IncI;
+ procedure DecI;
+ property Indent: integer read FIndent write SetIndednt;
+ property SIndent: string read FIndStr;
+ end;
+
+ { TWriter }
+
+ TWriter = class
+ private
+ Fjs, Fps: TTextOutStream;
+ FClasses: TStringList;
+ FPkgDir: string;
+ FUniqueCnt: integer;
+ FThisUnit: TUnitDef;
+
+ function DoCheckItem(const ItemName: string): TCheckItemResult;
+
+ procedure ProcessRules(d: TDef; const Prefix: string = '');
+ function GetUniqueNum: integer;
+ function DefToJniType(d: TDef; var err: boolean): string;
+ function DefToJniSig(d: TDef): string;
+ function DefToJavaType(d: TDef): string;
+ function GetJavaClassPath(d: TDef; const AClassName: string = ''): string;
+ function JniToPasType(d: TDef; const v: string; CheckNil: boolean): string;
+ function PasToJniType(d: TDef; const v: string): string;
+ function GetTypeInfoVar(ClassDef: TDef): string;
+ function GetClassPrefix(ClassDef: TDef; const AClassName: string = ''): string;
+ function IsJavaSimpleType(d: TDef): boolean;
+ function GetProcDeclaration(d: TProcDef; const ProcName: string = ''): string;
+ function GetJavaProcDeclaration(d: TProcDef; const ProcName: string = ''): string;
+ function GetJniFuncType(d: TDef): string;
+ function GetJavaClassName(cls: TDef; it: TDef): string;
+ procedure RegisterPseudoClass(d: TDef);
+ function GetPasIntType(Size: integer): string;
+// procedure AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType);
+ function AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType): TProcDef;
+ procedure AddNativeMethod(ParentDef: TDef; const JniName, Name, Signature: string);
+ function GetProcSignature(d: TProcDef): string;
+ procedure EHandlerStart;
+ procedure EHandlerEnd(const EnvVarName: string; const ExtraCode: string = '');
+
+ procedure WriteClassInfoVar(d: TDef);
+ procedure WriteComment(d: TDef; const AType: string);
+ procedure WriteClass(d: TDef; PreInfo: boolean);
+ procedure WriteProc(d: TProcDef; Variable: TVarDef = nil; AParent: TDef = nil);
+ procedure WriteVar(d: TVarDef; AParent: TDef = nil);
+ procedure WriteConst(d: TConstDef);
+ procedure WriteEnum(d: TDef);
+ procedure WriteProcType(d: TProcDef; PreInfo: boolean);
+ procedure WriteSet(d: TSetDef);
+ procedure WriteUnit(u: TUnitDef);
+ procedure WriteOnLoad;
+ public
+ SearchPath: string;
+ LibName: string;
+ JavaPackage: string;
+ Units: TStringList;
+ OutPath: string;
+ JavaOutPath: string;
+ IncludeList: TStringList;
+ ExcludeList: TStringList;
+
+ constructor Create;
+ destructor Destroy; override;
+ procedure ProcessUnits;
+ end;
+
+implementation
+
+const
+ JNIType: array[TBasicType] of string =
+ ('', 'jshort', 'jbyte', 'jint', 'jshort', 'jlong', 'jint', 'jlong', 'jfloat', 'jdouble', 'jstring',
+ 'jstring', 'jboolean', 'jchar', 'jchar', 'jint', 'jlong', 'jstring');
+ JNITypeSig: array[TBasicType] of string =
+ ('V', 'S', 'B', 'I', 'S', 'J', 'I', 'J', 'F', 'D', 'Ljava/lang/String;', 'Ljava/lang/String;',
+ 'Z', 'C', 'C', 'I', 'J', 'Ljava/lang/String;');
+ JavaType: array[TBasicType] of string =
+ ('void', 'short', 'byte', 'int', 'short', 'long', 'int', 'long', 'float', 'double', 'String',
+ 'String', 'boolean', 'char', 'char', 'int', 'long', 'String');
+
+ TextIndent = 2;
+
+ ExcludeStd: array[1..43] of string = (
+ 'classes.TStream.ReadComponent', 'classes.TStream.ReadComponentRes', 'classes.TStream.WriteComponent', 'classes.TStream.WriteComponentRes',
+ 'classes.TStream.WriteDescendent', 'classes.TStream.WriteDescendentRes', 'classes.TStream.WriteResourceHeader', 'classes.TStream.FixupResourceHeader',
+ 'classes.TStream.ReadResHeader', 'classes.TComponent.WriteState', 'classes.TComponent.ExecuteAction', 'classes.TComponent.UpdateAction',
+ 'classes.TComponent.GetEnumerator', 'classes.TComponent.VCLComObject', 'classes.TComponent.DesignInfo', 'classes.TComponent.Destroying',
+ 'classes.TComponent.FreeNotification', 'classes.TComponent.RemoveFreeNotification', 'classes.TComponent.FreeOnRelease', 'classes.TComponent.SetSubComponent',
+ 'system.TObject.newinstance', 'system.TObject.FreeInstance', 'system.TObject.SafeCallException', 'system.TObject.InitInstance',
+ 'system.TObject.CleanupInstance', 'system.TObject.ClassInfo', 'system.TObject.AfterConstruction', 'system.TObject.BeforeDestruction',
+ 'system.TObject.GetInterfaceEntry', 'system.TObject.GetInterfaceTable', 'system.TObject.MethodAddress', 'system.TObject.MethodName',
+ 'system.TObject.FieldAddress', 'classes.TComponent.ComponentState', 'classes.TComponent.ComponentStyle', 'classes.TList.GetEnumerator',
+ 'classes.TList.List', 'classes.TList.FPOAttachObserver', 'classes.TList.FPODetachObserver', 'classes.TList.FPONotifyObservers',
+ 'classes.TPersistent.FPOAttachObserver', 'classes.TPersistent.FPODetachObserver', 'classes.TPersistent.FPONotifyObservers'
+ );
+
+ ExcludeDelphi7: array[1..25] of string = (
+ 'system.TObject.StringMessageTable', 'system.TObject.GetInterfaceEntryByStr', 'system.TObject.UnitName', 'system.TObject.Equals',
+ 'system.TObject.GetHashCode', 'system.TObject.ToString','classes.TStream.ReadByte', 'classes.TStream.ReadWord',
+ 'classes.TStream.ReadDWord', 'classes.TStream.ReadQWord', 'classes.TStream.ReadAnsiString', 'classes.TStream.WriteByte',
+ 'classes.TStream.WriteWord', 'classes.TStream.WriteDWord', 'classes.TStream.WriteQWord', 'classes.TStream.WriteAnsiString',
+ 'classes.TCollection.Exchange', 'classes.TStrings.Equals', 'classes.TStrings.GetNameValue', 'classes.TStrings.ExtractName',
+ 'classes.TStrings.TextLineBreakStyle', 'classes.TStrings.StrictDelimiter', 'classes.TStrings.GetEnumerator', 'classes.TStringList.OwnsObjects',
+ 'classes.TList.AddList'
+ );
+
+ SUnsupportedType = '<unsupported type>';
+
+function JniCaliing: string;
+begin
+ Result:='{$ifdef windows} stdcall {$else} cdecl {$endif};';
+end;
+
+{ TTextOutStream }
+
+procedure TTextOutStream.SetIndednt(const AValue: integer);
+begin
+ if FIndent = AValue then exit;
+ FIndent:=AValue;
+ SetLength(FIndStr, FIndent*TextIndent);
+ if FIndent > 0 then
+ FillChar(FIndStr[1], FIndent*TextIndent, ' ');
+end;
+
+procedure TTextOutStream.Write(const s: ansistring);
+begin
+ WriteBuffer(PChar(s)^, Length(s));
+end;
+
+procedure TTextOutStream.WriteLn(const s: ansistring; ExtraIndent: integer);
+begin
+ if s = '' then
+ Write(LineEnding)
+ else begin
+ Indent:=Indent + ExtraIndent;
+ try
+ Write(FIndStr + s + LineEnding);
+ finally
+ Indent:=Indent - ExtraIndent;
+ end;
+ end;
+end;
+
+procedure TTextOutStream.IncI;
+begin
+ Indent:=Indent + 1;
+end;
+
+procedure TTextOutStream.DecI;
+begin
+ if Indent > 0 then
+ Indent:=Indent - 1;
+end;
+
+type
+ { TClassInfo }
+ TClassInfo = class
+ public
+ Def: TDef;
+ Funcs: TObjectList;
+ IsCommonClass: boolean;
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+ TProcInfo = class
+ public
+ Name: string;
+ JniName: string;
+ JniSignature: string;
+ end;
+
+{ TClassInfo }
+
+constructor TClassInfo.Create;
+begin
+ Funcs:=TObjectList.Create(True);
+end;
+
+destructor TClassInfo.Destroy;
+begin
+ Funcs.Free;
+ inherited Destroy;
+end;
+
+{ TWriter }
+
+function TWriter.DefToJniType(d: TDef; var err: boolean): string;
+begin
+ if d = nil then begin
+ Result:=SUnsupportedType;
+ err:=True;
+ end
+ else begin
+ if not d.IsUsed then begin
+ Result:='<excluded type> ' + d.Name;
+ err:=True;
+ end
+ else
+ case d.DefType of
+ dtType:
+ Result:=JNIType[TTypeDef(d).BasicType];
+ dtClass, dtRecord, dtEnum:
+ Result:='jobject';
+ dtProcType:
+ if poMethodPtr in TProcDef(d).ProcOpt then
+ Result:='jobject'
+ else begin
+ Result:=SUnsupportedType + ' ' + d.Name;
+ err:=True;
+ end;
+ dtSet:
+ if TSetDef(d).Size <= 4 then
+ Result:='jobject'
+ else begin
+ Result:=SUnsupportedType + ' ' + d.Name;
+ err:=True;
+ end;
+ else begin
+ Result:=SUnsupportedType + ' ' + d.Name;
+ err:=True;
+ d.SetNotUsed;
+ end;
+ end;
+ end;
+end;
+
+function TWriter.DoCheckItem(const ItemName: string): TCheckItemResult;
+begin
+ if IncludeList.IndexOf(ItemName) >= 0 then
+ Result:=crInclude
+ else
+ if ExcludeList.IndexOf(ItemName) >= 0 then
+ Result:=crExclude
+ else
+ Result:=crDefault;
+end;
+
+procedure TWriter.ProcessRules(d: TDef; const Prefix: string);
+var
+ i: integer;
+ s: string;
+begin
+ s:=Prefix + d.Name;
+ i:=IncludeList.IndexOf(s);
+ if i >= 0 then begin
+ i:=ptruint(IncludeList.Objects[i]);
+ if (i = 0) or (d.Count = i - 1) then
+ d.IsUsed:=True;
+ end
+ else
+ if ExcludeList.IndexOf(s) >= 0 then begin
+ d.SetNotUsed;
+ end;
+ if not (d.DefType in [dtUnit, dtClass, dtRecord]) then
+ exit;
+ s:=s + '.';
+ for i:=0 to d.Count - 1 do
+ ProcessRules(d[i], s);
+end;
+
+function TWriter.GetUniqueNum: integer;
+begin
+ Inc(FUniqueCnt);
+ Result:=FUniqueCnt;
+end;
+
+function TWriter.DefToJniSig(d: TDef): string;
+begin
+ if d = nil then
+ Result:=SUnsupportedType
+ else
+ case d.DefType of
+ dtType:
+ Result:=JNITypeSig[TTypeDef(d).BasicType];
+ dtClass, dtRecord, dtProcType, dtSet, dtEnum:
+ Result:='L' + GetJavaClassPath(d) + ';';
+ else
+ Result:=SUnsupportedType;
+ end;
+end;
+
+function TWriter.DefToJavaType(d: TDef): string;
+begin
+ if d = nil then
+ Result:=SUnsupportedType
+ else
+ case d.DefType of
+ dtType:
+ Result:=JavaType[TTypeDef(d).BasicType];
+ dtClass, dtRecord, dtProcType, dtSet, dtEnum:
+ Result:=d.Name;
+ else
+ Result:=SUnsupportedType;
+ end;
+end;
+
+function TWriter.GetJavaClassPath(d: TDef; const AClassName: string): string;
+var
+ n: string;
+begin
+ if AClassName = '' then
+ n:=d.AliasName
+ else
+ n:=AClassName;
+ Result:=StringReplace(JavaPackage, '.', '/', [rfReplaceAll]);
+ if Result <> '' then
+ Result:=Result + '/';
+ if d.DefType = dtUnit then
+ Result:=Result + n
+ else
+ Result:=Result + d.Parent.AliasName + '$' + n;
+end;
+
+procedure TWriter.WriteClass(d: TDef; PreInfo: boolean);
+var
+ WrittenItems: TList;
+
+ procedure _WriteConstructors(c: TClassDef; Written: TStringList);
+ var
+ i, j: integer;
+ p: TProcDef;
+ OldRet: TDef;
+ s: string;
+ begin
+ if c = nil then
+ exit;
+ for i:=0 to c.Count - 1 do
+ with c[i] do begin
+ if (DefType = dtProc) and not c.IsPrivate and (TProcDef(c[i]).ProcType = ptConstructor) then begin
+ p:=TProcDef(c[i]);
+ j:=Written.IndexOf(p.Name);
+ if (j < 0) or (Written.Objects[j] = c) then begin
+ s:=p.Name + ':';
+ for j:=0 to p.Count - 1 do
+ s:=s + DefToJniSig(p[j]);
+ if Written.IndexOf(s) < 0 then begin
+ OldRet:=p.ReturnType;
+ p.ReturnType:=d;
+ p.Parent:=d;
+ try
+ WriteProc(p);
+ finally
+ p.ReturnType:=OldRet;
+ p.Parent:=c;
+ end;
+ Written.Add(s);
+ if not (poOverload in p.ProcOpt) then
+ Written.AddObject(p.Name, c);
+ end;
+ end;
+ end;
+ end;
+
+ _WriteConstructors(c.AncestorClass, Written);
+ end;
+
+ procedure WriteConstructors;
+ var
+ cc: TStringList;
+ begin
+ if not TClassDef(d).HasAbstractMethods then begin
+ // Writing all constructors including parent's
+ cc:=TStringList.Create;
+ try
+ cc.Sorted:=True;
+ _WriteConstructors(TClassDef(d), cc);
+ finally
+ cc.Free;
+ end;
+ end;
+ end;
+
+ procedure _WriteReplacedItems(c: TClassDef);
+ var
+ i: integer;
+ p: TReplDef;
+ begin
+ c:=c.AncestorClass;
+ if c = nil then
+ exit;
+ if c.HasReplacedItems then begin
+ for i:=0 to c.Count - 1 do
+ with c[i] do begin
+ p:=TReplDef(c[i]);
+ if (DefType in ReplDefs) and ((p.IsReplaced) or p.IsReplImpl) then begin
+ if p.ReplacedItem <> nil then
+ WrittenItems.Add(p.ReplacedItem);
+ if WrittenItems.IndexOf(p) >= 0 then
+ continue;
+ case p.DefType of
+ dtProc:
+ WriteProc(TProcDef(p), nil, d);
+ dtProp, dtField:
+ WriteVar(TVarDef(p), d);
+ end;
+ end;
+ end;
+ end;
+ _WriteReplacedItems(c);
+ end;
+
+ procedure WriteReplacedItems;
+ begin
+ _WriteReplacedItems(TClassDef(d));
+ end;
+
+ procedure WriteItems(Regular, Replaced, ReplImpl: boolean);
+ var
+ i: integer;
+ it: TReplDef;
+ begin
+ for i:=0 to d.Count - 1 do begin
+ it:=TReplDef(d[i]);
+ if not (it.DefType in ReplDefs) then
+ continue;
+ if not (it.IsReplImpl or it.IsReplaced) then begin
+ if not Regular then
+ continue;
+ end
+ else
+ if (not Replaced and it.IsReplaced) or (not ReplImpl and it.IsReplImpl) then
+ continue;
+ if it.ReplacedItem <> nil then
+ WrittenItems.Add(it.ReplacedItem);
+ case it.DefType of
+ dtProc:
+ if TProcDef(it).ProcType <> ptConstructor then
+ WriteProc(TProcDef(it));
+ dtProp, dtField:
+ WriteVar(TVarDef(it));
+ end;
+ end;
+ end;
+
+var
+ s, ss: string;
+ RegularClass: boolean;
+begin
+ if PreInfo then begin
+ WriteClassInfoVar(d);
+
+ if d.DefType = dtRecord then begin
+ s:=d.Parent.Name + '.' + d.Name;
+ Fps.WriteLn;
+ Fps.WriteLn(Format('function _%s_CreateObj(env: PJNIEnv; const r: %s): jobject;', [GetClassPrefix(d), s]));
+ Fps.WriteLn(Format('var pr: ^%s;', [s]));
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('New(pr); pr^:=r;');
+ Fps.WriteLn(Format('Result:=_CreateJavaObj(env, pr, %s);', [GetTypeInfoVar(d)]));
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ ss:=Format('_%s_Free', [GetClassPrefix(d)]);
+ Fps.WriteLn(Format('procedure %s(env: PJNIEnv; _self: JObject; r: jlong);', [ss]) + JniCaliing);
+ Fps.WriteLn(Format('var pr: ^%s;', [s]));
+ Fps.WriteLn('begin');
+ Fps.WriteLn('pr:=pointer(ptruint(r));', 1);
+ Fps.WriteLn('Dispose(pr);', 1);
+ Fps.WriteLn('end;');
+
+ AddNativeMethod(d, ss, 'Release', '(J)V');
+ end;
+ exit;
+ end;
+
+ // Java
+ case d.DefType of
+ dtClass:
+ s:='class';
+ dtRecord:
+ s:='record';
+ else
+ s:='';
+ end;
+ WriteComment(d, s);
+ s:='public static class ' + GetJavaClassName(d, nil) + ' extends ';
+ if d.DefType = dtClass then
+ with TClassDef(d) do begin
+ if AncestorClass <> nil then begin
+ ss:=AncestorClass.Name;
+ if ImplementsReplacedItems then
+ ss:='__' + ss;
+ s:=s + ss;
+ end
+ else
+ s:=s + 'PascalObject';
+ end
+ else
+ s:=s + Format('%s.system.Record', [JavaPackage]);
+ Fjs.WriteLn(s + ' {');
+ Fjs.IncI;
+ if d.DefType = dtRecord then begin
+ Fjs.WriteLn('private native void Release(long pasobj);');
+ Fjs.WriteLn(Format('public %s() { }', [d.Name]));
+ Fjs.WriteLn(Format('public void Free() { Release(_pasobj); super.Free(); }', [d.Name]));
+ Fjs.WriteLn(Format('public int Size() { return %d; }', [TRecordDef(d).Size]));
+ end;
+
+ WrittenItems:=TList.Create;
+ try
+ RegularClass:=(d.DefType = dtClass) and not TClassDef(d).HasReplacedItems;
+ if RegularClass then
+ WriteConstructors;
+ // Write regular items
+ WriteItems(True, False, RegularClass);
+ if RegularClass and TClassDef(d).ImplementsReplacedItems then
+ // Write implementation wrappers for replaced mehods
+ WriteReplacedItems;
+
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+
+ if (d.DefType = dtClass) and (TClassDef(d).HasReplacedItems) then begin
+ // Write replaced items
+ Fjs.WriteLn(Format('public static class %s extends __%0:s {', [d.AliasName]));
+ Fjs.IncI;
+
+ WriteConstructors;
+ WriteItems(False, True, True);
+
+ if TClassDef(d).ImplementsReplacedItems then
+ // Write implementation wrappers for replaced mehods
+ WriteReplacedItems;
+
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+ end;
+ finally
+ WrittenItems.Free;
+ end;
+end;
+
+procedure TWriter.WriteProc(d: TProcDef; Variable: TVarDef; AParent: TDef);
+var
+ i, j, ClassIdx: integer;
+ s, ss: string;
+ err, tf: boolean;
+ pi: TProcInfo;
+ ci: TClassInfo;
+ IsTObject: boolean;
+ tempvars: TStringList;
+ vd: TVarDef;
+ UseTempObjVar: boolean;
+ ItemDef: TDef;
+begin
+ ASSERT(d.DefType = dtProc);
+ if d.IsPrivate or not d.IsUsed then
+ exit;
+ IsTObject:=(d.Parent.DefType = dtClass) and (TClassDef(d.Parent).AncestorClass = nil);
+ if (d.ProcType = ptDestructor) and not IsTObject then
+ exit;
+ if Variable <> nil then
+ ItemDef:=Variable
+ else
+ ItemDef:=d;
+ tempvars:=nil;
+ pi:=TProcInfo.Create;
+ with d do
+ try
+ pi.Name:=Name;
+ s:=GetClassPrefix(d.Parent) + pi.Name;
+ pi.JniName:=s;
+ pi.JniSignature:=GetProcSignature(d);
+ if AParent = nil then begin
+ // Checking duplicate name
+ ClassIdx:=FClasses.IndexOf(GetJavaClassName(d.Parent, ItemDef));
+ if ClassIdx >= 0 then begin
+ ci:=TClassInfo(FClasses.Objects[ClassIdx]);
+ j:=1;
+ repeat
+ err:=False;
+ for i:=0 to ci.Funcs.Count - 1 do
+ with TProcInfo(ci.Funcs[i]) do
+ if CompareText(JniName, pi.JniName) = 0 then begin
+ Inc(j);
+ pi.JniName:=Format('%s_%d', [s, j]);
+ err:=True;
+ break;
+ end;
+ until not err;
+ end;
+
+ err:=False;
+ if ProcType in [ptFunction, ptConstructor] then
+ s:='function'
+ else
+ s:='procedure';
+ s:=s + ' ' + pi.JniName + '(_env: PJNIEnv; _jobj: jobject';
+
+ UseTempObjVar:=(ProcType = ptProcedure) and (Variable <> nil) and (Variable.VarType <> nil) and (Variable.VarType.DefType = dtProcType) and (Variable.Parent.DefType <> dtUnit);
+
+ for j:=0 to Count - 1 do
+ with TVarDef(Items[j]) do begin
+ s:=s + '; ' + Name + ': ';
+ if VarOpt * [voVar, voOut] = [] then
+ s:=s + DefToJniType(VarType, err)
+ else begin
+ s:=s + 'jarray';
+ if tempvars = nil then
+ tempvars:=TStringList.Create;
+ if VarType = nil then
+ err:=True
+ else
+ Tag:=tempvars.AddObject('__tmp_' + Name, d.Items[j]) + 1;
+ end;
+ end;
+ s:=s + ')';
+
+ if ProcType in [ptFunction, ptConstructor] then
+ s:=s + ': ' + DefToJniType(ReturnType, err);
+ s:=s + '; ' + JniCaliing;
+ if err then begin
+ d.SetNotUsed;
+ s:='// ' + s;
+ end;
+ Fps.WriteLn;
+ Fps.WriteLn(s);
+ if err then
+ exit;
+ if (tempvars <> nil) or UseTempObjVar then begin
+ s:='';
+ Fps.WriteLn('var');
+ Fps.IncI;
+ if tempvars <> nil then begin
+ for i:=0 to tempvars.Count - 1 do begin
+ vd:=TVarDef(tempvars.Objects[i]);
+ Fps.WriteLn(Format('%s: %s;', [tempvars[i], vd.VarType.Name]));
+ if IsJavaSimpleType(vd.VarType) then begin
+ Fps.WriteLn(Format('%s_arr: P%s;', [tempvars[i], DefToJniType(vd.VarType, err)]));
+ if s = '' then
+ s:='__iscopy: JBoolean;';
+ end;
+ end;
+ if s <> '' then
+ Fps.WriteLn(s);
+ end;
+ if UseTempObjVar then
+ Fps.WriteLn('__objvar: ' + d.Parent.Name + ';');
+ Fps.DecI;
+ end;
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ EHandlerStart;
+
+ tf:=False;
+ // Assign var parameter values to local vars
+ if tempvars <> nil then begin
+ for i:=0 to tempvars.Count - 1 do begin
+ vd:=TVarDef(tempvars.Objects[i]);
+ Fps.WriteLn(Format('if _env^^.GetArrayLength(_env, %s) <> 1 then _RaiseVarParamException(''%s'');', [vd.Name, vd.Name]));
+ if IsJavaSimpleType(vd.VarType) then begin
+ Fps.WriteLn(Format('%s_arr:=_env^^.Get%sArrayElements(_env, %s, __iscopy);', [tempvars[i], GetJniFuncType(vd.VarType), vd.Name]));
+ Fps.WriteLn(Format('if %s_arr = nil then _RaiseVarParamException(''%s'');', [tempvars[i], vd.Name]));
+ s:=tempvars[i] + '_arr^';
+ tf:=True;
+ end
+ else
+ s:=Format('_env^^.GetObjectArrayElement(_env, %s, 0)', [vd.Name]);
+ if voVar in vd.VarOpt then
+ Fps.WriteLn(tempvars[i] + ':=' + JniToPasType(vd.VarType, s, False) + ';');
+ end;
+ end;
+
+ if tf then begin
+ Fps.WriteLn('try');
+ Fps.IncI;
+ end;
+
+ s:='';
+ if Parent.DefType = dtUnit then
+ s:=Parent.Name + '.'
+ else
+ if ProcType = ptConstructor then
+ s:=Parent.Parent.Name + '.' + Parent.Name + '.'
+ else
+ s:=JniToPasType(d.Parent, '_jobj', True) + '.';
+
+ if Variable = nil then begin
+ // Regular proc
+ s:=s + pi.Name;
+ if Count > 0 then begin
+ s:=s + '(';
+ for j:=0 to Count - 1 do begin
+ vd:=TVarDef(Items[j]);
+ if vd.Tag <> 0 then
+ ss:=tempvars[vd.Tag - 1]
+ else begin
+ ss:=Items[j].Name;
+ ss:=JniToPasType(vd.VarType, ss, False);
+ end;
+ if j <> 0 then
+ s:=s + ', ';
+ s:=s + ss;
+ end;
+ s:=s + ')';
+ end;
+ end
+ else begin
+ // Var access
+ if UseTempObjVar then begin
+ System.Delete(s, Length(s), 1);
+ Fps.WriteLn('__objvar:=' + s + ';');
+ s:='__objvar.';
+ end;
+ s:=s + Variable.Name;
+ if Variable.IndexType <> nil then begin
+ ASSERT(Count >= 1);
+ i:=1;
+ s:=Format('%s[%s]', [s, JniToPasType(TVarDef(Items[0]).VarType, Items[0].Name, False)]);
+ end
+ else
+ i:=0;
+ if ProcType = ptProcedure then begin
+ ASSERT(Count = i + 1);
+ if Variable.VarType.DefType = dtProcType then begin
+ Fps.WriteLn(Format('_RefMethodPtr(_env, TMethod(%s), False);', [s]));
+ ss:=Format('_RefMethodPtr(_env, TMethod(%s), True);', [s]);
+ end;
+ s:=s + ':=' + JniToPasType(TVarDef(Items[i]).VarType, Items[i].Name, False);
+ end;
+ end;
+
+ if ProcType in [ptFunction, ptConstructor] then
+ s:='Result:=' + PasToJniType(ReturnType, s);
+ s:=s + ';';
+ Fps.WriteLn(s);
+
+ if (Variable <> nil) and UseTempObjVar then
+ Fps.WriteLn(ss);
+
+ // Return var/out parameters
+ if tempvars <> nil then begin
+ for i:=0 to tempvars.Count - 1 do begin
+ vd:=TVarDef(tempvars.Objects[i]);
+ if IsJavaSimpleType(vd.VarType) then
+ Fps.WriteLn(Format('%s_arr^:=%s;', [tempvars[i], PasToJniType(vd.VarType, tempvars[i])]))
+ else
+ Fps.WriteLn(Format('_env^^.SetObjectArrayElement(_env, %s, 0, %s);', [vd.Name, PasToJniType(vd.VarType, tempvars[i])]));
+ end;
+ end;
+
+ if IsTObject and ( (ProcType = ptDestructor) or (CompareText(Name, 'Free') = 0) ) then
+ Fps.WriteLn(Format('_env^^.SetLongField(_env, _jobj, %s.ObjFieldId, 0);', [GetTypeInfoVar(d.Parent)]));
+
+ if tf then begin
+ Fps.WriteLn('finally', -1);
+
+ if tempvars <> nil then begin
+ for i:=0 to tempvars.Count - 1 do begin
+ vd:=TVarDef(tempvars.Objects[i]);
+ if IsJavaSimpleType(vd.VarType) then
+ Fps.WriteLn(Format('_env^^.Release%sArrayElements(_env, %s, %s_arr, 0);', [JavaType[TTypeDef(vd.VarType).BasicType], vd.Name, tempvars[i]]));
+ end;
+ end;
+
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ end;
+
+ s:='';
+ if ProcType in [ptFunction, ptConstructor] then begin
+ s:='0';
+ if (ReturnType.DefType = dtType) and (TTypeDef(ReturnType).BasicType <= btDouble) then
+ s:='0'
+ else
+ s:=Format('%s(0)', [DefToJniType(ReturnType, err)]);
+ s:='Result:=' + s + ';';
+ end;
+ EHandlerEnd('_env', s);
+
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ AParent:=d.Parent;
+ end
+ else
+ ClassIdx:=FClasses.IndexOf(GetJavaClassName(AParent, ItemDef));
+
+ if ClassIdx < 0 then begin
+ ci:=TClassInfo.Create;
+ ci.Def:=AParent;
+ s:=GetJavaClassName(AParent, ItemDef);
+ ci.IsCommonClass:=s <> AParent.Name;
+ ClassIdx:=FClasses.AddObject(s, ci);
+ end;
+ TClassInfo(FClasses.Objects[ClassIdx]).Funcs.Add(pi);
+ pi:=nil;
+
+ // Java part
+ s:=GetJavaProcDeclaration(d) + ';';
+ if (Parent.DefType = dtUnit) or (ProcType = ptConstructor) then
+ s:='static ' + s;
+
+ if Variable = nil then
+ Fjs.WriteLn('// ' + GetProcDeclaration(d));
+ if poPrivate in ProcOpt then
+ ss:='private'
+ else
+ if poProtected in ProcOpt then
+ ss:='protected'
+ else
+ ss:='public';
+ Fjs.WriteLn(ss + ' native ' + s);
+ finally
+ pi.Free;
+ tempvars.Free;
+ end;
+end;
+
+procedure TWriter.WriteVar(d: TVarDef; AParent: TDef);
+var
+ pd: TProcDef;
+ t: TTypeDef;
+ s: string;
+begin
+ if not d.IsUsed then
+ exit;
+ if d.VarType <> nil then begin
+ case d.DefType of
+ dtVar:
+ s:='var';
+ dtProp:
+ s:='property';
+ else
+ s:='';
+ end;
+ s:=Trim(s + ' ' + d.Name);
+ if d.IndexType <> nil then
+ s:=s + '[]';
+ Fjs.WriteLn(Format('// %s: %s', [s, d.VarType.Name]));
+ end;
+
+ if voRead in d.VarOpt then begin
+ pd:=TProcDef.Create(nil, dtProc);
+ try
+ pd.IsUsed:=True;
+ pd.Parent:=d.Parent;
+ pd.ProcType:=ptFunction;
+ pd.Name:='get' + d.Name;
+ pd.ReturnType:=d.VarType;
+ if d.IndexType <> nil then
+ with TVarDef.Create(pd, dtParam) do begin
+ Name:='_Index';
+ AliasName:='Index';
+ VarType:=d.IndexType;
+ VarOpt:=[voRead];
+ end;
+ WriteProc(pd, d, AParent);
+ finally
+ pd.Free;
+ end;
+ end;
+
+ if voWrite in d.VarOpt then begin
+ pd:=TProcDef.Create(nil, dtProc);
+ try
+ pd.IsUsed:=True;
+ pd.Parent:=d.Parent;
+ pd.ProcType:=ptProcedure;
+ pd.Name:='set' + d.Name;
+ if d.IndexType <> nil then
+ with TVarDef.Create(pd, dtParam) do begin
+ Name:='_Index';
+ AliasName:='Index';
+ VarType:=d.IndexType;
+ VarOpt:=[voRead];
+ end;
+ with TVarDef.Create(pd, dtParam) do begin
+ Name:='_Value';
+ AliasName:='Value';
+ VarType:=d.VarType;
+ VarOpt:=[voRead];
+ end;
+ t:=TTypeDef.Create(nil, dtType);
+ try
+ t.BasicType:=btVoid;
+ pd.ReturnType:=t;
+ WriteProc(pd, d, AParent);
+ finally
+ t.Free;
+ end;
+ finally
+ pd.Free;
+ end;
+ end;
+end;
+
+procedure TWriter.WriteConst(d: TConstDef);
+var
+ s: string;
+begin
+ if not d.IsUsed then
+ exit;
+ if d.VarType = nil then begin
+ if Copy(d.Value, 1, 1) = '"' then
+ s:='String'
+ else
+ s:='double';
+ end
+ else
+ s:=DefToJavaType(d.VarType);
+ Fjs.WriteLn(Format('public static final %s %s = %s;', [s, d.Name, d.Value]));
+end;
+
+procedure TWriter.WriteEnum(d: TDef);
+var
+ i: integer;
+ s: string;
+begin
+ if not d.IsUsed then
+ exit;
+
+ RegisterPseudoClass(d);
+
+ WriteComment(d, 'enum');
+ Fjs.WriteLn(Format('public enum %s {', [d.Name]));
+ Fjs.IncI;
+ for i:=0 to d.Count - 1 do begin
+ s:=Format('%s (%s)', [d[i].Name, TConstDef(d[i]).Value]);
+ if i <> d.Count - 1 then
+ s:=s + ','
+ else
+ s:=s + ';';
+ Fjs.WriteLn(s);
+ end;
+ Fjs.WriteLn;
+ Fjs.WriteLn('private final int Value;');
+ Fjs.WriteLn(Format('%s(int v) { Value=v; }', [d.Name]));
+ Fjs.WriteLn('public int Ord() { return Value; }');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+end;
+
+procedure TWriter.WriteProcType(d: TProcDef; PreInfo: boolean);
+
+ procedure _AccessSimpleArray(vd: TVarDef; VarIndex: integer; DoSet: boolean);
+ begin
+ with vd do begin
+ Fps.WriteLn(Format('_tmp_%s:=_env^^.Get%sArrayElements(_env, _args[%d].L, PJBoolean(nil)^);', [Name, GetJniFuncType(VarType), VarIndex]));
+ Fps.WriteLn(Format('if _tmp_%s <> nil then', [Name]));
+ if DoSet then
+ Fps.WriteLn(Format('_tmp_%s^:=%s;', [Name, PasToJniType(VarType, Name)]), 1)
+ else
+ Fps.WriteLn(Format('%s:=%s;', [Name, JniToPasType(VarType, '_tmp_' + Name + '^', False)]), 1);
+ Fps.WriteLn(Format('_env^^.Release%sArrayElements(_env, _args[%d].L, _tmp_%s, 0);', [GetJniFuncType(VarType), VarIndex, Name]));
+ end;
+ end;
+
+var
+ vd: TVarDef;
+ i: integer;
+ s, ss: string;
+ err: boolean;
+begin
+ if not d.IsUsed or not (poMethodPtr in d.ProcOpt) then
+ exit;
+
+ if PreInfo then begin
+ WriteClassInfoVar(d);
+
+ // Handler proc
+ Fps.WriteLn;
+ vd:=TVarDef.Create(nil, dtParam);
+ try
+ vd.Name:='_data';
+ vd.VarType:=TTypeDef.Create(nil, dtType);
+ with TTypeDef(vd.VarType) do begin
+ Name:='pointer';
+ BasicType:=btPointer;
+ end;
+ d.Insert(0, vd);
+ Fps.WriteLn(GetProcDeclaration(d, Format('%sHandler', [GetClassPrefix(d)])) + ';');
+ finally
+ vd.VarType.Free;
+ vd.Free;
+ end;
+ Fps.WriteLn('var');
+ Fps.IncI;
+ Fps.WriteLn('_env: PJNIEnv;');
+ Fps.WriteLn('_mpi: _TMethodPtrInfo;');
+ if d.Count > 0 then begin
+ Fps.WriteLn(Format('_args: array[0..%d] of jvalue;', [d.Count - 1]));
+ for i:=0 to d.Count - 1 do
+ with TVarDef(d[i]) do
+ if (VarOpt * [voOut, voVar] <> []) and IsJavaSimpleType(VarType) then
+ Fps.WriteLn(Format('_tmp_%s: P%s;', [Name, DefToJniType(VarType, err)]));
+ end;
+ Fps.DecI;
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('CurJavaVM^^.GetEnv(CurJavaVM, @_env, JNI_VERSION_1_6);');
+ Fps.WriteLn('_MethodPointersCS.Enter;');
+ Fps.WriteLn('try');
+ Fps.WriteLn('_mpi:=_TMethodPtrInfo(_MethodPointers[-integer(ptruint(_data)) - 1]);', 1);
+ Fps.WriteLn('finally');
+ Fps.WriteLn('_MethodPointersCS.Leave;', 1);
+ Fps.WriteLn('end;');
+
+ for i:=0 to d.Count - 1 do
+ with TVarDef(d[i]) do begin
+ if VarOpt * [voOut, voVar] = [] then begin
+ s:='L';
+ if VarType.DefType = dtType then
+ s:=Copy(JNITypeSig[TTypeDef(VarType).BasicType], 1, 1);
+ ss:=PasToJniType(VarType, Name);
+ end
+ else begin
+ s:='L';
+ if IsJavaSimpleType(VarType) then
+ ss:=Format('_env^^.New%sArray(_env, 1)', [GetJniFuncType(VarType)])
+ else begin
+ if voVar in VarOpt then
+ ss:=PasToJniType(VarType, Name)
+ else
+ ss:='nil';
+ ss:=Format('_env^^.NewObjectArray(_env, 1, %s.ClassRef, %s)', [GetTypeInfoVar(VarType), ss]);
+ end;
+ end;
+ Fps.WriteLn(Format('_args[%d].%s:=%s;', [i, s, ss]));
+ if (voVar in VarOpt) and IsJavaSimpleType(VarType) then
+ _AccessSimpleArray(TVarDef(d[i]), i, True);
+ end;
+
+ if d.Count > 0 then
+ s:='@_args'
+ else
+ s:='nil';
+ // Calling Java handler
+ s:=Format('_env^^.Call%sMethodA(_env, _mpi.Obj, _mpi.MethodId, %s)', [GetJniFuncType(d.ReturnType), s]);
+ if d.ProcType = ptFunction then
+ s:=Format('Result:=%s', [JniToPasType(d.ReturnType, s, False)]);
+ Fps.WriteLn(s + ';');
+ // Processing var/out parameters
+ for i:=0 to d.Count - 1 do
+ with TVarDef(d[i]) do
+ if VarOpt * [voOut, voVar] <> [] then
+ if IsJavaSimpleType(VarType) then
+ _AccessSimpleArray(TVarDef(d[i]), i, False)
+ else begin
+ s:=Format('_env^^.GetObjectArrayElement(_env, _args[%d].L, 0)', [i]);
+ Fps.WriteLn(Format('%s:=%s;', [Name, JniToPasType(VarType, s, False)]));
+ end;
+
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ // Get handler proc
+ Fps.WriteLn;
+ Fps.WriteLn(Format('function %sGetHandler(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo): %s.%s;',
+ [GetClassPrefix(d), d.Parent.Name, d.Name]));
+ Fps.WriteLn('var mpi: _TMethodPtrInfo;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('Result:=nil;');
+ Fps.WriteLn('mpi:=_TMethodPtrInfo(_GetPasObj(env, jobj, ci, False));');
+ Fps.WriteLn('if mpi = nil then exit;');
+ Fps.WriteLn('if mpi.Index = 0 then');
+ Fps.WriteLn('TMethod(Result):=mpi.RealMethod', 1);
+ Fps.WriteLn('else');
+ Fps.WriteLn('with TMethod(Result) do begin', 1);
+ Fps.WriteLn('Data:=pointer(ptruint(-integer(mpi.Index)));', 2);
+ Fps.WriteLn(Format('Code:=@%sHandler;', [GetClassPrefix(d)]), 2);
+ Fps.WriteLn('end;', 1);
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ exit;
+ end;
+
+ err:=False;
+ WriteComment(d, 'procedural type');
+
+ RegisterPseudoClass(d);
+
+ Fjs.WriteLn(Format('/* Pascal prototype: %s */', [GetProcDeclaration(d, 'Execute')]));
+ Fjs.WriteLn(Format('/* Java prototype: %s */', [GetJavaProcDeclaration(d, 'Execute')]));
+
+ Fjs.WriteLn(Format('public static class %s extends %s.system.MethodPtr {', [d.Name, JavaPackage]));
+ Fjs.IncI;
+ Fjs.WriteLn(Format('private String HandlerSig = "%s";', [GetProcSignature(d)]));
+ Fjs.WriteLn(Format('public %s(Object Obj, String MethodName) { Init(Obj, MethodName, HandlerSig); }', [d.Name]));
+ Fjs.WriteLn(Format('public %s() { Init(this, "Execute", HandlerSig); }', [d.Name]));
+ Fjs.WriteLn(Format('protected %s throws NoSuchMethodException { throw new NoSuchMethodException(); }', [GetJavaProcDeclaration(d, 'Execute')]));
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+end;
+
+procedure TWriter.WriteSet(d: TSetDef);
+begin
+ if not d.IsUsed then
+ exit;
+ if d.ElType = nil then
+ raise Exception.Create('No element type.');
+
+ WriteComment(d, '');
+ Fjs.WriteLn(Format('/* set of %s */', [d.ElType.Name]));
+ if d.Size > 4 then begin
+ Fjs.WriteLn('/* Set size more than 32 bits is not supported */');
+ exit;
+ end;
+
+ RegisterPseudoClass(d);
+
+ Fjs.WriteLn(Format('public static class %s extends %s.system.Set<%s,%s> {', [d.Name, JavaPackage, d.Name, d.ElType.Name]));
+ Fjs.IncI;
+ Fjs.WriteLn(Format('protected byte Size() { return %d; }', [d.Size]));
+ Fjs.WriteLn(Format('protected int Base() { return %d; }', [d.Base]));
+ Fjs.WriteLn(Format('protected int ElMax() { return %d; }', [d.ElMax]));
+ Fjs.WriteLn(Format('protected int Ord(%s Element) { return Element.Ord(); }', [d.ElType.Name]));
+ Fjs.WriteLn(Format('public %s() { }', [d.Name]));
+ Fjs.WriteLn(Format('public %s(%s... Elements) { super(Elements); }', [d.Name, d.ElType.Name]));
+ Fjs.WriteLn(Format('public %0:s(%0:s... Elements) { super(Elements); }', [d.Name]));
+ Fjs.WriteLn(Format('public static %0:s Exclude(%0:s s1, %0:s s2) { %0:s r = new %0:s(s1); r.Exclude(s2); return r; }', [d.Name]));
+ Fjs.WriteLn(Format('public static %0:s Intersect(%0:s s1, %0:s s2) { %0:s r = new %0:s(s1); r.Intersect(s2); return r; }', [d.Name]));
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+end;
+
+procedure TWriter.WriteUnit(u: TUnitDef);
+var
+ d: TDef;
+ i: integer;
+begin
+ if u.Processed then
+ exit;
+ u.Processed:=True;
+
+ if not u.IsUsed then
+ exit;
+
+ for i:=0 to High(u.UsedUnits) do
+ WriteUnit(u.UsedUnits[i]);
+
+ Fps.WriteLn;
+ Fps.WriteLn(Format('{ Unit %s }', [u.Name]));
+
+ u.Name:=LowerCase(u.Name);
+ Fjs:=TTextOutStream.Create(IncludeTrailingPathDelimiter(FPkgDir) + u.Name + '.java', fmCreate);
+ try
+ Fjs.WriteLn(Format('package %s;', [JavaPackage]));
+ if Length(u.UsedUnits) > 0 then begin
+ Fjs.WriteLn;
+ for i:=0 to High(u.UsedUnits) do
+ if u.UsedUnits[i].IsUsed then
+ Fjs.WriteLn(Format('import %s.%s.*;', [JavaPackage, LowerCase(u.UsedUnits[i].Name)]));
+ end;
+ Fjs.WriteLn;
+ Fjs.WriteLn('public class ' + u.Name + ' {');
+ Fjs.IncI;
+ if u.Name = 'system' then begin
+ Fjs.WriteLn('static private boolean _JniLibLoaded = false;');
+ Fjs.WriteLn('public static void InitJni() {');
+ Fjs.WriteLn('if (!_JniLibLoaded) {', 1);
+ Fjs.WriteLn('_JniLibLoaded=true;', 2);
+ Fjs.WriteLn(Format('System.loadLibrary("%s");', [LibName]), 2);
+ Fjs.WriteLn('}', 1);
+ Fjs.WriteLn('}');
+
+ // Support functions
+ Fjs.WriteLn('public native static long AllocMemory(int Size);');
+ AddNativeMethod(u, '_AllocMemory', 'AllocMemory', '(I)J');
+
+ // Base object
+ Fjs.WriteLn;
+ Fjs.WriteLn('public static class PascalObject {');
+ Fjs.IncI;
+ Fjs.WriteLn(Format('static { %s.system.InitJni(); }', [JavaPackage]));
+ Fjs.WriteLn('protected long _pasobj = 0;');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+ Fjs.WriteLn('public static long Pointer(PascalObject obj) { return obj._pasobj; }');
+
+ // Record
+ Fjs.WriteLn;
+ Fjs.WriteLn('public static class Record extends PascalObject {');
+ Fjs.IncI;
+ Fjs.WriteLn('protected void finalize() { Free(); }');
+ Fjs.WriteLn('public Record() { _pasobj = AllocMemory(Size()); }');
+ Fjs.WriteLn('public void Free() { _pasobj = 0; }');
+ Fjs.WriteLn('public int Size() { return 0; }');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+
+ // Method pointer base class
+ d:=TClassDef.Create(FThisUnit, dtClass);
+ d.Name:='_TMethodPtrInfo';
+ d.AliasName:='MethodPtr';
+ WriteClassInfoVar(d);
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _TMethodPtrInfo_Init(env: PJNIEnv; _self, JavaObj: JObject; AMethodName, AMethodSig: jstring);' + JniCaliing);
+ Fps.WriteLn('var mpi: _TMethodPtrInfo;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ EHandlerStart;
+ Fps.WriteLn('mpi:=_TMethodPtrInfo.Create(env, JavaObj, ansistring(_StringFromJString(env, AMethodName)), ansistring(_StringFromJString(env, AMethodSig)));');
+ Fps.WriteLn(Format('env^^.SetLongField(env, _self, %s.ObjFieldId, Int64(ptruint(mpi)));', [GetTypeInfoVar(d)]));
+ EHandlerEnd('env');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ AddNativeMethod(d, '_TMethodPtrInfo_Init', 'Init', Format('(Ljava/lang/Object;%s%s)V', [JNITypeSig[btString], JNITypeSig[btString]]));
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _TMethodPtrInfo_Release(env: PJNIEnv; _self: JObject);' + JniCaliing);
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ EHandlerStart;
+ Fps.WriteLn(Format('_TMethodPtrInfo(_GetPasObj(env, _self, %s, True)).Release(env);', [GetTypeInfoVar(d)]));
+ EHandlerEnd('env');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ AddNativeMethod(d, '_TMethodPtrInfo_Release', 'Release', '()V');
+
+ Fjs.WriteLn;
+ Fjs.WriteLn('public static class MethodPtr extends PascalObject {');
+ Fjs.IncI;
+
+ Fjs.WriteLn('private native void Release();');
+ Fjs.WriteLn('protected void finalize() { if (_pasobj != 0) Release(); }');
+ Fjs.WriteLn('protected native void Init(Object Obj, String MethodName, String MethodSignature);');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+
+ // Set base class
+ Fjs.WriteLn('public static class Set<TS extends Set<?,?>,TE> {');
+ Fjs.IncI;
+ Fjs.WriteLn('protected int Value = 0;');
+ Fjs.WriteLn('protected byte Size() { return 0; }');
+ Fjs.WriteLn('protected int Base() { return 0; }');
+ Fjs.WriteLn('protected int ElMax() { return 0; }');
+ Fjs.WriteLn('protected int Ord(TE Element) { return 0; }');
+ Fjs.WriteLn('protected int GetMask(TE Element) {');
+ Fjs.IncI;
+ Fjs.WriteLn('return 1 << (Ord(Element) - Base());');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn('public Set() { }');
+ Fjs.WriteLn('public Set(TE... Elements) { Include(Elements); }');
+ Fjs.WriteLn('public Set(TS... Elements) { for (TS e : Elements) Include(e); }');
+ Fjs.WriteLn('public void Include(TE... Elements) { for (TE e: Elements) Value = Value | GetMask(e); }');
+ Fjs.WriteLn('public void Include(TS s) { Value=Value | s.Value; }');
+ Fjs.WriteLn('public void Exclude(TE... Elements) { for (TE e: Elements) Value = Value & ~GetMask(e); }');
+ Fjs.WriteLn('public void Exclude(TS s) { Value=Value & ~s.Value; }');
+ Fjs.WriteLn('public void Assign(TS s) { Value=s.Value; }');
+ Fjs.WriteLn('public void Intersect(TS s) { Value=Value & s.Value; }');
+ Fjs.WriteLn('public boolean Compare(TS s) { return Value == s.Value; }');
+ Fjs.WriteLn('public boolean Has(TE Element) { return (Value & GetMask(Element)) != 0; }');
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ Fjs.WriteLn;
+ end;
+ Fjs.WriteLn(Format('static { %s.system.InitJni(); }', [JavaPackage]));
+ Fjs.WriteLn;
+
+ // First pass
+ for i:=0 to u.Count - 1 do begin
+ d:=u[i];
+ if not d.IsUsed then
+ continue;
+ case d.DefType of
+ dtSet, dtEnum:
+ WriteClassInfoVar(d);
+ dtClass, dtRecord:
+ WriteClass(d, True);
+ dtProcType:
+ WriteProcType(TProcDef(d), True);
+ end;
+ end;
+
+ // Second pass
+ for i:=0 to u.Count - 1 do begin
+ d:=u[i];
+ if not d.IsUsed then
+ continue;
+ case d.DefType of
+ dtClass, dtRecord:
+ WriteClass(d, False);
+ dtProc:
+ WriteProc(TProcDef(d));
+ dtVar, dtProp:
+ WriteVar(TVarDef(d));
+ dtEnum:
+ WriteEnum(d);
+ dtProcType:
+ WriteProcType(TProcDef(d), False);
+ dtSet:
+ WriteSet(TSetDef(d));
+ dtConst:
+ WriteConst(TConstDef(d));
+ end;
+ end;
+
+ Fjs.DecI;
+ Fjs.WriteLn('}');
+ finally
+ Fjs.Free;
+ end;
+end;
+
+procedure TWriter.WriteOnLoad;
+var
+ i, j: integer;
+ ci: TClassInfo;
+ s, ss, fn: string;
+ d: TTypeDef;
+begin
+ if FClasses.Count = 0 then
+ exit;
+ Fps.WriteLn;
+ Fps.WriteLn('function JNI_OnLoad(vm: PJavaVM; reserved: pointer): jint;' + JniCaliing);
+
+ Fps.WriteLn('const');
+ for i:=0 to FClasses.Count - 1 do begin
+ ci:=TClassInfo(FClasses.Objects[i]);
+ if ci.Funcs.Count = 0 then
+ continue;
+ Fps.WriteLn(Format(' _%sNativeMethods: array[0..%d] of JNINativeMethod = (', [GetClassPrefix(ci.Def, FClasses[i]), ci.Funcs.Count - 1]));
+ for j:=0 to ci.Funcs.Count - 1 do begin
+ with TProcInfo(ci.Funcs[j]) do
+ Fps.Write(Format(' (name: ''%s''; signature: ''%s''; fnPtr: @%s)', [Name, JniSignature, JniName]));
+ if j < ci.Funcs.Count - 1 then
+ Fps.Write(',');
+ Fps.WriteLn;
+ end;
+ Fps.WriteLn(' );');
+ end;
+
+ Fps.WriteLn;
+ Fps.WriteLn('var');
+ Fps.IncI;
+ Fps.WriteLn('env: PJNIEnv;');
+ Fps.WriteLn;
+ Fps.WriteLn('function _Reg(ClassName: PAnsiChar; Methods: PJNINativeMethod; Count: integer; ci: _PJavaClassInfo; const FieldName: ansistring = ''_pasobj''; const FieldSig: ansistring = ''J''): boolean;');
+ Fps.WriteLn('var');
+ Fps.WriteLn('c: jclass;', 1);
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('Result:=False;');
+ Fps.WriteLn('c:=env^^.FindClass(env, ClassName);');
+ Fps.WriteLn('if c = nil then exit;');
+ Fps.WriteLn('Result:=(Count = 0) or (env^^.RegisterNatives(env, c, Methods, Count) = 0);');
+ Fps.WriteLn('if Result and (ci <> nil) then begin');
+ Fps.IncI;
+ Fps.WriteLn('ci^.ClassRef:=env^^.NewGlobalRef(env, c);');
+ Fps.WriteLn('Result:=ci^.ClassRef <> nil;');
+ Fps.WriteLn('if Result and (FieldName <> '''') then begin');
+ Fps.WriteLn('ci^.ObjFieldId:=env^^.GetFieldID(env, ci^.ClassRef, PAnsiChar(FieldName), PAnsiChar(FieldSig));', 1);
+ Fps.WriteLn('Result:=ci^.ObjFieldId <> nil;', 1);
+ Fps.WriteLn('end;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn;
+ Fps.WriteLn('begin', -1);
+ Fps.WriteLn('Result:=JNI_ERR;');
+ Fps.WriteLn('if vm^^.GetEnv(vm, @env, JNI_VERSION_1_6) <> JNI_OK then exit;');
+ Fps.WriteLn('CurJavaVM:=vm;');
+
+ d:=TTypeDef.Create(nil, dtType);
+ try
+ d.BasicType:=btString;
+ s:=JNITypeSig[d.BasicType];
+ s:=Copy(s, 2, Length(s) - 2);
+ Fps.WriteLn(Format('if not _Reg(''%s'', nil, 0, @%s, '''', '''') then exit;',
+ [s, GetTypeInfoVar(d)]));
+ finally
+ d.Free;
+ end;
+
+ for i:=0 to FClasses.Count - 1 do begin
+ ci:=TClassInfo(FClasses.Objects[i]);
+ s:=GetTypeInfoVar(ci.Def);
+ if (s = '') or (ci.IsCommonClass) then
+ s:='nil'
+ else
+ s:='@' + s;
+ if ci.Funcs.Count = 0 then
+ ss:='nil'
+ else
+ ss:=Format('@_%sNativeMethods', [GetClassPrefix(ci.Def, FClasses[i])]);
+ fn:='';
+ if ci.Def <> nil then
+ if ci.Def.DefType in [dtSet, dtEnum] then
+ fn:=', ''Value'', ''I''';
+ Fps.WriteLn(Format('if not _Reg(''%s'', %s, %d, %s%s) then exit;',
+ [GetJavaClassPath(ci.Def, FClasses[i]), ss, ci.Funcs.Count, s, fn]));
+ end;
+
+ Fps.WriteLn('Result:=JNI_VERSION_1_6;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn;
+ Fps.WriteLn('exports JNI_OnLoad;');
+end;
+
+function TWriter.JniToPasType(d: TDef; const v: string; CheckNil: boolean): string;
+var
+ n: string;
+begin
+ Result:=v;
+ if d = nil then
+ exit;
+ case d.DefType of
+ dtType:
+ with TTypeDef(d) do
+ case BasicType of
+ btString, btWideString:
+ begin
+ Result:=Format('_StringFromJString(_env, %s)', [Result]);
+ if BasicType <> btWideString then
+ Result:=Format('%s(%s)', [d.Name, Result]);
+ end;
+ btBoolean:
+ Result:=Format('LongBool(%s)', [Result]);
+ btChar:
+ Result:=Format('char(widechar(%s))', [Result]);
+ btWideChar:
+ Result:=Format('widechar(%s)', [Result]);
+ btEnum:
+ Result:=Format('%s(%s)', [d.Name, Result]);
+ btPointer:
+ Result:=Format('pointer(ptruint(%s))', [Result]);
+ btGuid:
+ Result:=Format('StringToGUID(ansistring(_StringFromJString(_env, %s)))', [Result]);
+ end;
+ dtClass:
+ begin
+ if CheckNil then
+ n:='True'
+ else
+ n:='False';
+ Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d), n]);
+ end;
+ dtRecord:
+ Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, True)^)', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
+ dtProcType:
+ Result:=Format('%sGetHandler(_env, %s, %s)', [GetClassPrefix(d), Result, GetTypeInfoVar(d)]);
+ dtEnum:
+ Result:=Format('%s.%s(_GetIntObjValue(_env, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
+ dtSet:
+ Result:=Format('%s.%s(%s(_GetIntObjValue(_env, %s, %s)))', [d.Parent.Name, d.Name, GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
+ end;
+end;
+
+function TWriter.PasToJniType(d: TDef; const v: string): string;
+begin
+ Result:=v;
+ if d = nil then
+ exit;
+ case d.DefType of
+ dtType:
+ with TTypeDef(d) do
+ case BasicType of
+ btString, btWideString:
+ Result:=Format('_StringToJString(_env, _JNIString(%s))', [Result]);
+ btBoolean:
+ Result:=Format('jboolean(LongBool(%s))', [Result]);
+ btChar:
+ Result:=Format('jchar(widechar(%s))', [Result]);
+ btWideChar:
+ Result:=Format('jchar(%s)', [Result]);
+ btEnum:
+ Result:=Format('jint(%s)', [Result]);
+ btPointer:
+ Result:=Format('ptruint(pointer(%s))', [Result]);
+ btGuid:
+ Result:=Format('_StringToJString(_env, _JNIString(GUIDToString(%s)))', [Result]);
+ end;
+ dtClass:
+ Result:=Format('_CreateJavaObj(_env, %s, %s)', [Result, GetTypeInfoVar(d)]);
+ dtRecord:
+ Result:=Format('_%s_CreateObj(_env, %s)', [GetClassPrefix(d), Result]);
+ dtProcType:
+ Result:=Format('_CreateMethodPtrObject(_env, TMethod(%s), %s)', [Result, GetTypeInfoVar(d)]);
+ dtEnum:
+ Result:=Format('_CreateIntObj(_env, longint(%s), %s)', [Result, GetTypeInfoVar(d)]);
+ dtSet:
+ Result:=Format('_CreateIntObj(_env, %s(%s), %s)', [GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
+ end;
+end;
+
+function TWriter.GetTypeInfoVar(ClassDef: TDef): string;
+begin
+ if ClassDef.DefType = dtUnit then
+ Result:=''
+ else
+ if ClassDef.DefType = dtType then
+ Result:='_Java_' + JavaType[TTypeDef(ClassDef).BasicType] + '_Info'
+ else
+ Result:='_JNI_' + ClassDef.Parent.Name + '_' + ClassDef.Name + '_Info';
+end;
+
+function TWriter.GetClassPrefix(ClassDef: TDef; const AClassName: string): string;
+begin
+ if AClassName = '' then
+ Result:=ClassDef.Name
+ else
+ Result:=AClassName;
+ Result:=Result + '_';
+ if ClassDef.DefType <> dtUnit then
+ Result:=ClassDef.Parent.Name + '_' + Result;
+ Result:='JNI_' + Result;
+end;
+
+function TWriter.IsJavaSimpleType(d: TDef): boolean;
+begin
+ Result:=(d <> nil) and (d.DefType = dtType) and (Length(JNITypeSig[TTypeDef(d).BasicType]) = 1);
+end;
+
+function TWriter.GetProcDeclaration(d: TProcDef; const ProcName: string): string;
+var
+ s, ss: string;
+ j: integer;
+begin
+ with d do begin
+ if Count > 0 then
+ s:='('
+ else
+ s:='';
+ for j:=0 to Count - 1 do
+ with TVarDef(Items[j]) do begin
+ if j > 0 then
+ s:=s + '; ';
+ if voVar in VarOpt then
+ s:=s + 'var '
+ else
+ if voOut in VarOpt then
+ s:=s + 'out '
+ else
+ if voConst in VarOpt then
+ s:=s + 'const ';
+ s:=s + Name + ': ' + VarType.Name;
+ end;
+
+ if Count > 0 then
+ s:=s + ')';
+ case ProcType of
+ ptConstructor:
+ ss:='constructor';
+ ptDestructor:
+ ss:='destructor';
+ ptProcedure:
+ ss:='procedure';
+ ptFunction:
+ ss:='function';
+ else
+ ss:='';
+ end;
+ if ProcType in [ptConstructor, ptFunction] then
+ s:=s + ': ' + ReturnType.Name;
+ ss:=ss + ' ';
+ if ProcName <> '' then
+ ss:=ss + ProcName
+ else
+ ss:=ss + Name;
+ Result:=ss + s;
+ end;
+end;
+
+function TWriter.GetJavaProcDeclaration(d: TProcDef; const ProcName: string): string;
+var
+ s: string;
+ j: integer;
+begin
+ with d do begin
+ if ProcName <> '' then
+ s:=ProcName
+ else
+ s:=AliasName;
+ s:=DefToJavaType(ReturnType) + ' ' + s + '(';
+ for j:=0 to Count - 1 do
+ with TVarDef(Items[j]) do begin
+ if j > 0 then
+ s:=s + ', ';
+ s:=s + DefToJavaType(VarType);
+ if VarOpt * [voVar, voOut] <> [] then
+ s:=s + '[]';
+ s:=s + ' ' + AliasName;
+ end;
+ s:=s + ')';
+ end;
+ Result:=s;
+end;
+
+function TWriter.GetJniFuncType(d: TDef): string;
+begin
+ if IsJavaSimpleType(d) then begin
+ Result:=JavaType[TTypeDef(d).BasicType];
+ Result[1]:=UpCase(Result[1]);
+ end
+ else
+ Result:='Object';
+end;
+
+function TWriter.GetJavaClassName(cls: TDef; it: TDef): string;
+begin
+ Result:=cls.AliasName;
+ if (cls.DefType <> dtClass) or ((it <> nil) and not (it.DefType in ReplDefs)) then
+ exit;
+ with TClassDef(cls) do begin
+ if not (HasReplacedItems or ImplementsReplacedItems) then
+ exit;
+ if ImplementsReplacedItems and not HasReplacedItems then
+ exit;
+ if it <> nil then
+ with TReplDef(it) do begin
+ if (it.DefType = dtProc) and (TProcDef(it).ProcType = ptConstructor) then
+ exit;
+ if IsReplaced or IsReplImpl then
+ exit;
+ end;
+ end;
+ Result:='__' + Result;
+end;
+
+procedure TWriter.RegisterPseudoClass(d: TDef);
+var
+ ci: TClassInfo;
+begin
+ if FClasses.IndexOf(d.Name) < 0 then begin
+ ci:=TClassInfo.Create;
+ ci.Def:=d;
+ FClasses.AddObject(d.Name, ci);
+ end;
+end;
+
+function TWriter.GetPasIntType(Size: integer): string;
+begin
+ case Size of
+ 1: Result:='byte';
+ 2: Result:='word';
+ else
+ Result:='cardinal';
+ end;
+end;
+
+function TWriter.AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType): TProcDef;
+var
+ i: integer;
+ vd: TVarDef;
+begin
+ Result:=TProcDef.Create(ParentDef, dtProc);
+ Result.Name:=JniName;
+ Result.AliasName:=Name;
+ if RetType = btVoid then
+ Result.ProcType:=ptProcedure
+ else
+ Result.ProcType:=ptFunction;
+ for i:=0 to High(Params) do begin
+ vd:=TVarDef.Create(Result, dtParam);
+ vd.Name:=Format('p%d', [i + 1]);
+ vd.VarType:=TTypeDef.Create(vd, dtType);
+ TTypeDef(vd.VarType).BasicType:=Params[i];
+ end;
+ Result.ReturnType:=TTypeDef.Create(ParentDef, dtType);
+ TTypeDef(Result.ReturnType).BasicType:=RetType;
+end;
+
+procedure TWriter.AddNativeMethod(ParentDef: TDef; const JniName, Name, Signature: string);
+var
+ i: integer;
+ ci: TClassInfo;
+ pi: TProcInfo;
+begin
+ pi:=TProcInfo.Create;
+ pi.Name:=Name;
+ pi.JniName:=JniName;
+ pi.JniSignature:=Signature;
+ i:=FClasses.IndexOf(ParentDef.AliasName);
+ if i < 0 then begin
+ ci:=TClassInfo.Create;
+ ci.Def:=ParentDef;
+ i:=FClasses.AddObject(ParentDef.AliasName, ci);
+ end;
+ TClassInfo(FClasses.Objects[i]).Funcs.Add(pi);
+end;
+
+function TWriter.GetProcSignature(d: TProcDef): string;
+var
+ j: integer;
+begin
+ Result:='(';
+ for j:=0 to d.Count - 1 do
+ with TVarDef(d[j]) do begin
+ if VarOpt * [voVar, voOut] <> [] then
+ Result:=Result + '[';
+ Result:=Result + DefToJniSig(VarType);
+ end;
+ Result:=Result + ')' + DefToJniSig(d.ReturnType);
+end;
+
+procedure TWriter.EHandlerStart;
+begin
+ Fps.WriteLn('try');
+ Fps.IncI;
+end;
+
+procedure TWriter.EHandlerEnd(const EnvVarName: string; const ExtraCode: string);
+begin
+ Fps.WriteLn('except', -1);
+ Fps.WriteLn(Format('_HandleJNIException(%s);', [EnvVarName]));
+ if ExtraCode <> '' then
+ Fps.WriteLn(ExtraCode);
+ Fps.DecI;
+ Fps.WriteLn('end;');
+end;
+
+procedure TWriter.WriteClassInfoVar(d: TDef);
+begin
+ Fps.WriteLn;
+ Fps.WriteLn(Format('var %s: _TJavaClassInfo;', [GetTypeInfoVar(d)]));
+end;
+
+procedure TWriter.WriteComment(d: TDef; const AType: string);
+begin
+ Fps.WriteLn;
+ Fps.WriteLn(Format('{ %s }', [d.Name]));
+
+ Fjs.WriteLn(Format('/* %s %s */', [AType, d.Name]));
+{$ifdef DEBUG}
+ Fjs.WriteLn(Format('/* Ref count: %d */', [d.RefCnt]));
+{$endif}
+end;
+
+{
+procedure TWriter.AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType);
+var
+ i: integer;
+ ci: TClassInfo;
+ pi: TProcInfo;
+begin
+ pi:=TProcInfo.Create;
+ pi.Name:=Name;
+ pi.JniName:=JniName;
+ pi.JniSignature:='(';
+ for i:=0 to High(Params) do
+ pi.JniSignature:=pi.JniSignature + JNITypeSig[Params[i]];
+ pi.JniSignature:=pi.JniSignature + ')';
+ pi.JniSignature:=pi.JniSignature + JNITypeSig[RetType];
+
+ i:=FClasses.IndexOf(ParentDef.Name);
+ if i < 0 then begin
+ ci:=TClassInfo.Create;
+ ci.Def:=ParentDef;
+ i:=FClasses.AddObject(ParentDef.Name, ci);
+ end;
+ TClassInfo(FClasses.Objects[i]).Funcs.Add(pi);
+end;
+}
+constructor TWriter.Create;
+var
+ i: integer;
+begin
+ Units:=TStringList.Create;
+ FClasses:=TStringList.Create;
+ FClasses.Sorted:=True;
+ JavaPackage:='pas';
+ IncludeList:=TStringList.Create;
+ IncludeList.Duplicates:=dupIgnore;
+ ExcludeList:=TStringList.Create;
+ ExcludeList.Duplicates:=dupIgnore;
+
+ for i:=Low(ExcludeStd) to High(ExcludeStd) do
+ ExcludeList.Add(ExcludeStd[i]);
+ for i:=Low(ExcludeDelphi7) to High(ExcludeDelphi7) do
+ ExcludeList.Add(ExcludeDelphi7[i]);
+
+ FThisUnit:=TUnitDef.Create(nil, dtUnit);
+end;
+
+destructor TWriter.Destroy;
+var
+ i: integer;
+begin
+ for i:=0 to FClasses.Count - 1 do
+ FClasses.Objects[i].Free;
+ FClasses.Free;
+ Units.Free;
+ IncludeList.Free;
+ ExcludeList.Free;
+ FThisUnit.Free;
+ inherited Destroy;
+end;
+
+procedure TWriter.ProcessUnits;
+var
+ p: TPPUParser;
+ i: integer;
+ s, ss: string;
+ d: TDef;
+begin
+ if Units.Count = 0 then
+ raise Exception.Create('No unit name specified.');
+ if (OutPath <> '') and not DirectoryExists(OutPath) then
+ raise Exception.CreateFmt('Output path "%s" does not exist.', [OutPath]);
+ if (JavaOutPath <> '') and not DirectoryExists(JavaOutPath) then
+ raise Exception.CreateFmt('Output path "%s" does not exist.', [JavaOutPath]);
+ if LibName = '' then
+ LibName:=AnsiLowerCase(ChangeFileExt(Units[0], '')) + 'jni';
+
+ for i:=0 to IncludeList.Count - 1 do
+ IncludeList[i]:=Trim(IncludeList[i]);
+ IncludeList.Sorted:=True;
+ for i:=0 to ExcludeList.Count - 1 do
+ ExcludeList[i]:=Trim(ExcludeList[i]);
+ ExcludeList.Sorted:=True;
+
+ FThisUnit.Name:=LibName;
+ FThisUnit.AliasName:='system';
+
+ p:=TPPUParser.Create(SearchPath);
+ try
+ p.OnCheckItem:=@DoCheckItem;
+ for i:=0 to Units.Count - 1 do
+ IncludeList.Add(ChangeFileExt(ExtractFileName(Units[i]), ''));
+ for i:=0 to Units.Count - 1 do
+ p.Parse(ChangeFileExt(ExtractFileName(Units[i]), ''));
+
+ if OutPath <> '' then
+ OutPath:=IncludeTrailingPathDelimiter(OutPath);
+ if JavaOutPath <> '' then
+ JavaOutPath:=IncludeTrailingPathDelimiter(JavaOutPath);
+
+ FPkgDir:=JavaOutPath + StringReplace(JavaPackage, '.', DirectorySeparator, [rfReplaceAll]);
+ ForceDirectories(FPkgDir);
+ Fps:=TTextOutStream.Create(OutPath + LibName + '.pas', fmCreate);
+
+ Fps.WriteLn('library '+ LibName + ';');
+ Fps.WriteLn('{$ifdef fpc} {$mode objfpc} {$H+} {$endif}');
+
+ Fps.WriteLn;
+ Fps.WriteLn('uses');
+ Fps.WriteLn('{$ifndef FPC} Windows, {$endif} {$ifdef unix} cthreads, {$endif} SysUtils, SyncObjs,', 1);
+ s:='';
+ for i:=0 to p.Units.Count - 1 do begin
+ ProcessRules(p.Units[i]);
+ ss:=LowerCase(p.Units[i].Name);
+ if (ss ='system') or (ss = 'objpas') or (ss = 'sysutils') or (ss = 'syncobjs') or (ss = 'jni') then
+ continue;
+ if s <> '' then
+ s:=s + ', ';
+ s:=s + p.Units[i].Name;
+ end;
+ Fps.WriteLn(s + ', jni;', 1);
+
+ // Types
+ Fps.WriteLn;
+ Fps.WriteLn('type');
+ Fps.IncI;
+ Fps.WriteLn('_JNIString = {$ifdef FPC} unicodestring {$else} widestring {$endif};');
+ Fps.WriteLn('{$ifndef FPC} ptruint = cardinal; {$endif}');
+ Fps.WriteLn;
+ Fps.WriteLn('_TJavaClassInfo = record');
+ Fps.WriteLn('ClassRef: JClass;', 1);
+ Fps.WriteLn('ObjFieldId: JFieldId;', 1);
+ Fps.WriteLn('end;');
+ Fps.WriteLn('_PJavaClassInfo = ^_TJavaClassInfo;');
+ Fps.DecI;
+
+ Fps.WriteLn;
+ d:=TtypeDef.Create(nil, dtType);
+ TtypeDef(d).BasicType:=btString;
+ Fps.WriteLn(Format('var %s: _TJavaClassInfo;', [GetTypeInfoVar(d)]));
+ d.Free;
+
+ // Support functions
+ Fps.WriteLn;
+ Fps.WriteLn('function _StringFromJString(env: PJNIEnv; s: jstring): _JNIString;');
+ Fps.WriteLn('var');
+ Fps.WriteLn('p: PJChar;', 1);
+ Fps.WriteLn('c: JBoolean;', 1);
+ Fps.WriteLn('begin');
+ Fps.WriteLn('if s = nil then begin', 1);
+ Fps.WriteLn('Result:='''';', 2);
+ Fps.WriteLn('exit;', 2);
+ Fps.WriteLn('end;', 1);
+ Fps.WriteLn('p:=env^^.GetStringChars(env, s, c);', 1);
+ Fps.WriteLn('SetString(Result, PWideChar(p), env^^.GetStringLength(env, s));', 1);
+ Fps.WriteLn('env^^.ReleaseStringChars(env, s, p);', 1);
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('function _StringToJString(env: PJNIEnv; const s: _JNIString): jstring;');
+ Fps.WriteLn('begin');
+ Fps.WriteLn('Result:=env^^.NewString(env, PJChar(PWideChar(s)), Length(s));', 1);
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('function _CreateJavaObj(env: PJNIEnv; PasObj: pointer; const ci: _TJavaClassInfo): jobject;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('Result:=nil;');
+ Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);');
+ Fps.WriteLn('if Result = nil then exit;');
+ Fps.WriteLn('env^^.SetLongField(env, Result, ci.ObjFieldId, Int64(ptruint(PasObj)));');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('function _GetPasObj(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo; CheckNil: boolean): pointer;');
+ Fps.WriteLn('var pasobj: jlong;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('if jobj <> nil then');
+ Fps.WriteLn('pasobj:=env^^.GetLongField(env, jobj, ci.ObjFieldId)', 1);
+ Fps.WriteLn('else');
+ Fps.WriteLn('pasobj:=0;', 1);
+ Fps.WriteLn('if CheckNil and (pasobj = 0) then');
+ Fps.WriteLn('raise Exception.Create(''Attempt to access a released Pascal object.'');', 1);
+ Fps.WriteLn('Result:=pointer(ptruint(pasobj));');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _HandleJNIException(env: PJNIEnv);');
+ Fps.WriteLn('begin');
+ Fps.WriteLn('env^^.ThrowNew(env, env^^.FindClass(env, ''java/lang/Exception''), PAnsiChar(Utf8Encode(Exception(ExceptObject).Message)));', 1);
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _RaiseVarParamException(const VarName: string);');
+ Fps.WriteLn('begin');
+ Fps.WriteLn('raise Exception.CreateFmt(''An array with only single element must be passed as parameter "%s".'', [VarName]);', 1);
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('function _AllocMemory(env: PJNIEnv; jobj: jobject; size: jint): jlong;');
+ Fps.WriteLn('var p: pointer;');
+ Fps.WriteLn('begin');
+ Fps.WriteLn('GetMem(p, size);', 1);
+ Fps.WriteLn('FillChar(p^, size, 0);', 1);
+ Fps.WriteLn('Result:=ptruint(p);', 1);
+ Fps.WriteLn('end;');
+
+ // Method pointer support
+ Fps.WriteLn;
+ Fps.WriteLn('type');
+ Fps.IncI;
+ Fps.WriteLn('_TMethodPtrInfo = class');
+ Fps.IncI;
+ Fps.WriteLn('Obj: JObject;');
+ Fps.WriteLn('MethodId: JMethodID;');
+ Fps.WriteLn('Index, RefCnt: integer;');
+ Fps.WriteLn('RealMethod: TMethod;');
+ Fps.WriteLn('constructor Create(env: PJNIEnv; JavaObj: JObject; const AMethodName, AMethodSig: ansistring);');
+ Fps.WriteLn('procedure Release(env: PJNIEnv);');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.DecI;
+ Fps.WriteLn;
+ Fps.WriteLn('var _MethodPointers: array of _TMethodPtrInfo;');
+ Fps.WriteLn('var _MethodPointersCS: TCriticalSection;');
+ Fps.WriteLn;
+
+ Fps.WriteLn('constructor _TMethodPtrInfo.Create(env: PJNIEnv; JavaObj: JObject; const AMethodName, AMethodSig: ansistring);');
+ Fps.WriteLn('var c: JClass;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('RefCnt:=1;');
+ Fps.WriteLn('if (JavaObj = nil) or (AMethodName = '''') then exit;');
+ Fps.WriteLn('c:=env^^.GetObjectClass(env, JavaObj);');
+ Fps.WriteLn('if c = nil then exit;');
+ Fps.WriteLn('MethodId:=env^^.GetMethodID(env, c, PAnsiChar(AMethodName), PAnsiChar(AMethodSig));');
+ Fps.WriteLn('if MethodId = nil then raise Exception.CreateFmt(''Method "%s" does not exist or has wrong parameters.'', [AMethodName]);');
+ Fps.WriteLn('Obj:=env^^.NewGlobalRef(env, JavaObj);');
+ Fps.WriteLn('_MethodPointersCS.Enter;');
+ Fps.WriteLn('try');
+ Fps.IncI;
+ Fps.WriteLn('Index:=Length(_MethodPointers) + 1;');
+ Fps.WriteLn(Format('if Index > %d then raise Exception.Create(''Too many method pointers.'');', [MaxMethodPointers]));
+ Fps.WriteLn('SetLength(_MethodPointers, Index);');
+ Fps.WriteLn('_MethodPointers[Index - 1]:=Self;');
+ Fps.WriteLn('finally', -1);
+ Fps.WriteLn('_MethodPointersCS.Leave;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _TMethodPtrInfo.Release(env: PJNIEnv);');
+ Fps.WriteLn('var i: integer;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('i:=InterlockedDecrement(RefCnt);');
+ Fps.WriteLn('if i <> 0 then exit;');
+ Fps.WriteLn('if Index > 0 then begin');
+ Fps.IncI;
+ Fps.WriteLn('_MethodPointersCS.Enter;');
+ Fps.WriteLn('try');
+ Fps.IncI;
+ Fps.WriteLn('Dec(Index);');
+ Fps.WriteLn('_MethodPointers[Index]:=nil;');
+ Fps.WriteLn('Index:=Length(_MethodPointers);');
+ Fps.WriteLn('while (Index > 0) and (_MethodPointers[Index] = nil) do Dec(Index);');
+ Fps.WriteLn('SetLength(_MethodPointers, Index + 1);');
+ Fps.WriteLn('finally', -1);
+ Fps.WriteLn('_MethodPointersCS.Leave;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn('env^^.DeleteGlobalRef(env, Obj);');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn('Self.Destroy;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('procedure _RefMethodPtr(env: PJNIEnv; const m: TMethod; AddRef: boolean);');
+ Fps.WriteLn('var i: integer;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('i:=-integer(ptruint(m.Data));');
+ Fps.WriteLn(Format('if (i < 1) or (i > %d) then exit;', [MaxMethodPointers]));
+ Fps.WriteLn('_MethodPointersCS.Enter;');
+ Fps.WriteLn('try');
+ Fps.IncI;
+ Fps.WriteLn('with _MethodPointers[i - 1] do');
+ Fps.WriteLn('if AddRef then InterlockedIncrement(RefCnt) else Release(env);', 1);
+ Fps.WriteLn('finally', -1);
+ Fps.WriteLn('_MethodPointersCS.Leave;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ Fps.WriteLn;
+ Fps.WriteLn('function _CreateMethodPtrObject(env: PJNIEnv; const m: TMethod; const ci: _TJavaClassInfo): jobject;');
+ Fps.WriteLn('var i: integer;');
+ Fps.WriteLn('var mpi: _TMethodPtrInfo;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('_MethodPointersCS.Enter;');
+ Fps.WriteLn('try');
+ Fps.IncI;
+ Fps.WriteLn('i:=-integer(ptruint(m.Data));');
+ Fps.WriteLn(Format('if (i > 0) and (i <= %d) then begin', [MaxMethodPointers]));
+ Fps.WriteLn('mpi:=_MethodPointers[i - 1];', 1);
+ Fps.WriteLn('InterlockedIncrement(mpi.RefCnt);', 1);
+ Fps.WriteLn('end');
+ Fps.WriteLn('else begin');
+ Fps.WriteLn('mpi:=_TMethodPtrInfo.Create(env, nil, '''', '''');', 1);
+ Fps.WriteLn('mpi.RealMethod:=m;', 1);
+ Fps.WriteLn('end;');
+ Fps.WriteLn('finally', -1);
+ Fps.WriteLn('_MethodPointersCS.Leave;');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn('Result:=_CreateJavaObj(env, pointer(mpi), ci);');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ // Set support
+ Fps.WriteLn;
+ Fps.WriteLn('function _GetIntObjValue(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo): longint;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('if jobj = nil then raise Exception.Create(''Attempt to access a NULL set.'');');
+ Fps.WriteLn('Result:=env^^.GetIntField(env, jobj, ci.ObjFieldId);');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+ Fps.WriteLn;
+ Fps.WriteLn('function _CreateIntObj(env: PJNIEnv; Value: longint; const ci: _TJavaClassInfo): jobject;');
+ Fps.WriteLn('begin');
+ Fps.IncI;
+ Fps.WriteLn('Result:=nil;');
+ Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);');
+ Fps.WriteLn('if Result = nil then exit;');
+ Fps.WriteLn('env^^.SetIntField(env, Result, ci.ObjFieldId, Value);');
+ Fps.DecI;
+ Fps.WriteLn('end;');
+
+ // Write units
+ for i:=0 to p.Units.Count - 1 do
+ with TUnitDef(p.Units[i]) do begin
+ WriteUnit(TUnitDef(p.Units[i]));
+ end;
+
+ WriteOnLoad;
+
+ Fps.WriteLn;
+ Fps.WriteLn('begin');
+ Fps.WriteLn('IsMultiThread:=True;', 1);
+ Fps.WriteLn('_MethodPointersCS:=TCriticalSection.Create;', 1);
+ Fps.WriteLn('end.');
+ finally
+ Fps.Free;
+ p.Free;
+ end;
+end;
+
+end.
+