writer.pas 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173
  1. {
  2. pas2jni - JNI bridge generator for Pascal.
  3. Copyright (c) 2013 by Yury Sidorov.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************}
  16. unit writer;
  17. {$mode objfpc}{$H+}
  18. interface
  19. //{$define DEBUG}
  20. {$ifdef DEBUG}
  21. {$ASSERTIONS ON}
  22. {$endif}
  23. uses
  24. Classes, SysUtils, def, contnrs, PPUParser;
  25. const
  26. MaxMethodPointers = 10000;
  27. type
  28. { TTextOutStream }
  29. TTextOutStream = class(TFileStream)
  30. private
  31. FIndent: integer;
  32. FIndStr: string;
  33. procedure SetIndednt(const AValue: integer);
  34. public
  35. procedure Write(const s: ansistring); overload;
  36. procedure WriteLn(const s: ansistring = ''; ExtraIndent: integer = 0);
  37. procedure IncI;
  38. procedure DecI;
  39. property Indent: integer read FIndent write SetIndednt;
  40. property SIndent: string read FIndStr;
  41. end;
  42. { TWriter }
  43. TWriter = class
  44. private
  45. Fjs, Fps: TTextOutStream;
  46. FClasses: TStringList;
  47. FPkgDir: string;
  48. FUniqueCnt: integer;
  49. FThisUnit: TUnitDef;
  50. function DoCheckItem(const ItemName: string): TCheckItemResult;
  51. procedure ProcessRules(d: TDef; const Prefix: string = '');
  52. function GetUniqueNum: integer;
  53. function DefToJniType(d: TDef; var err: boolean): string;
  54. function DefToJniSig(d: TDef): string;
  55. function DefToJavaType(d: TDef): string;
  56. function GetJavaClassPath(d: TDef; const AClassName: string = ''): string;
  57. function JniToPasType(d: TDef; const v: string; CheckNil: boolean): string;
  58. function PasToJniType(d: TDef; const v: string): string;
  59. function GetTypeInfoVar(ClassDef: TDef): string;
  60. function GetClassPrefix(ClassDef: TDef; const AClassName: string = ''): string;
  61. function IsJavaSimpleType(d: TDef): boolean;
  62. function GetProcDeclaration(d: TProcDef; const ProcName: string = ''): string;
  63. function GetJavaProcDeclaration(d: TProcDef; const ProcName: string = ''): string;
  64. function GetJniFuncType(d: TDef): string;
  65. function GetJavaClassName(cls: TDef; it: TDef): string;
  66. procedure RegisterPseudoClass(d: TDef);
  67. function GetPasIntType(Size: integer): string;
  68. // procedure AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType);
  69. function AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType): TProcDef;
  70. procedure AddNativeMethod(ParentDef: TDef; const JniName, Name, Signature: string);
  71. function GetProcSignature(d: TProcDef): string;
  72. procedure EHandlerStart;
  73. procedure EHandlerEnd(const EnvVarName: string; const ExtraCode: string = '');
  74. procedure WriteClassInfoVar(d: TDef);
  75. procedure WriteComment(d: TDef; const AType: string);
  76. procedure WriteClass(d: TDef; PreInfo: boolean);
  77. procedure WriteProc(d: TProcDef; Variable: TVarDef = nil; AParent: TDef = nil);
  78. procedure WriteVar(d: TVarDef; AParent: TDef = nil);
  79. procedure WriteConst(d: TConstDef);
  80. procedure WriteEnum(d: TDef);
  81. procedure WriteProcType(d: TProcDef; PreInfo: boolean);
  82. procedure WriteSet(d: TSetDef);
  83. procedure WriteUnit(u: TUnitDef);
  84. procedure WriteOnLoad;
  85. public
  86. SearchPath: string;
  87. LibName: string;
  88. JavaPackage: string;
  89. Units: TStringList;
  90. OutPath: string;
  91. JavaOutPath: string;
  92. IncludeList: TStringList;
  93. ExcludeList: TStringList;
  94. constructor Create;
  95. destructor Destroy; override;
  96. procedure ProcessUnits;
  97. end;
  98. implementation
  99. const
  100. JNIType: array[TBasicType] of string =
  101. ('', 'jshort', 'jbyte', 'jint', 'jshort', 'jlong', 'jint', 'jlong', 'jfloat', 'jdouble', 'jstring',
  102. 'jstring', 'jboolean', 'jchar', 'jchar', 'jint', 'jlong', 'jstring');
  103. JNITypeSig: array[TBasicType] of string =
  104. ('V', 'S', 'B', 'I', 'S', 'J', 'I', 'J', 'F', 'D', 'Ljava/lang/String;', 'Ljava/lang/String;',
  105. 'Z', 'C', 'C', 'I', 'J', 'Ljava/lang/String;');
  106. JavaType: array[TBasicType] of string =
  107. ('void', 'short', 'byte', 'int', 'short', 'long', 'int', 'long', 'float', 'double', 'String',
  108. 'String', 'boolean', 'char', 'char', 'int', 'long', 'String');
  109. TextIndent = 2;
  110. ExcludeStd: array[1..43] of string = (
  111. 'classes.TStream.ReadComponent', 'classes.TStream.ReadComponentRes', 'classes.TStream.WriteComponent', 'classes.TStream.WriteComponentRes',
  112. 'classes.TStream.WriteDescendent', 'classes.TStream.WriteDescendentRes', 'classes.TStream.WriteResourceHeader', 'classes.TStream.FixupResourceHeader',
  113. 'classes.TStream.ReadResHeader', 'classes.TComponent.WriteState', 'classes.TComponent.ExecuteAction', 'classes.TComponent.UpdateAction',
  114. 'classes.TComponent.GetEnumerator', 'classes.TComponent.VCLComObject', 'classes.TComponent.DesignInfo', 'classes.TComponent.Destroying',
  115. 'classes.TComponent.FreeNotification', 'classes.TComponent.RemoveFreeNotification', 'classes.TComponent.FreeOnRelease', 'classes.TComponent.SetSubComponent',
  116. 'system.TObject.newinstance', 'system.TObject.FreeInstance', 'system.TObject.SafeCallException', 'system.TObject.InitInstance',
  117. 'system.TObject.CleanupInstance', 'system.TObject.ClassInfo', 'system.TObject.AfterConstruction', 'system.TObject.BeforeDestruction',
  118. 'system.TObject.GetInterfaceEntry', 'system.TObject.GetInterfaceTable', 'system.TObject.MethodAddress', 'system.TObject.MethodName',
  119. 'system.TObject.FieldAddress', 'classes.TComponent.ComponentState', 'classes.TComponent.ComponentStyle', 'classes.TList.GetEnumerator',
  120. 'classes.TList.List', 'classes.TList.FPOAttachObserver', 'classes.TList.FPODetachObserver', 'classes.TList.FPONotifyObservers',
  121. 'classes.TPersistent.FPOAttachObserver', 'classes.TPersistent.FPODetachObserver', 'classes.TPersistent.FPONotifyObservers'
  122. );
  123. ExcludeDelphi7: array[1..25] of string = (
  124. 'system.TObject.StringMessageTable', 'system.TObject.GetInterfaceEntryByStr', 'system.TObject.UnitName', 'system.TObject.Equals',
  125. 'system.TObject.GetHashCode', 'system.TObject.ToString','classes.TStream.ReadByte', 'classes.TStream.ReadWord',
  126. 'classes.TStream.ReadDWord', 'classes.TStream.ReadQWord', 'classes.TStream.ReadAnsiString', 'classes.TStream.WriteByte',
  127. 'classes.TStream.WriteWord', 'classes.TStream.WriteDWord', 'classes.TStream.WriteQWord', 'classes.TStream.WriteAnsiString',
  128. 'classes.TCollection.Exchange', 'classes.TStrings.Equals', 'classes.TStrings.GetNameValue', 'classes.TStrings.ExtractName',
  129. 'classes.TStrings.TextLineBreakStyle', 'classes.TStrings.StrictDelimiter', 'classes.TStrings.GetEnumerator', 'classes.TStringList.OwnsObjects',
  130. 'classes.TList.AddList'
  131. );
  132. SUnsupportedType = '<unsupported type>';
  133. function JniCaliing: string;
  134. begin
  135. Result:='{$ifdef windows} stdcall {$else} cdecl {$endif};';
  136. end;
  137. { TTextOutStream }
  138. procedure TTextOutStream.SetIndednt(const AValue: integer);
  139. begin
  140. if FIndent = AValue then exit;
  141. FIndent:=AValue;
  142. SetLength(FIndStr, FIndent*TextIndent);
  143. if FIndent > 0 then
  144. FillChar(FIndStr[1], FIndent*TextIndent, ' ');
  145. end;
  146. procedure TTextOutStream.Write(const s: ansistring);
  147. begin
  148. WriteBuffer(PChar(s)^, Length(s));
  149. end;
  150. procedure TTextOutStream.WriteLn(const s: ansistring; ExtraIndent: integer);
  151. begin
  152. if s = '' then
  153. Write(LineEnding)
  154. else begin
  155. Indent:=Indent + ExtraIndent;
  156. try
  157. Write(FIndStr + s + LineEnding);
  158. finally
  159. Indent:=Indent - ExtraIndent;
  160. end;
  161. end;
  162. end;
  163. procedure TTextOutStream.IncI;
  164. begin
  165. Indent:=Indent + 1;
  166. end;
  167. procedure TTextOutStream.DecI;
  168. begin
  169. if Indent > 0 then
  170. Indent:=Indent - 1;
  171. end;
  172. type
  173. { TClassInfo }
  174. TClassInfo = class
  175. public
  176. Def: TDef;
  177. Funcs: TObjectList;
  178. IsCommonClass: boolean;
  179. constructor Create;
  180. destructor Destroy; override;
  181. end;
  182. TProcInfo = class
  183. public
  184. Name: string;
  185. JniName: string;
  186. JniSignature: string;
  187. end;
  188. { TClassInfo }
  189. constructor TClassInfo.Create;
  190. begin
  191. Funcs:=TObjectList.Create(True);
  192. end;
  193. destructor TClassInfo.Destroy;
  194. begin
  195. Funcs.Free;
  196. inherited Destroy;
  197. end;
  198. { TWriter }
  199. function TWriter.DefToJniType(d: TDef; var err: boolean): string;
  200. begin
  201. if d = nil then begin
  202. Result:=SUnsupportedType;
  203. err:=True;
  204. end
  205. else begin
  206. if not d.IsUsed then begin
  207. Result:='<excluded type> ' + d.Name;
  208. err:=True;
  209. end
  210. else
  211. case d.DefType of
  212. dtType:
  213. Result:=JNIType[TTypeDef(d).BasicType];
  214. dtClass, dtRecord, dtEnum:
  215. Result:='jobject';
  216. dtProcType:
  217. if poMethodPtr in TProcDef(d).ProcOpt then
  218. Result:='jobject'
  219. else begin
  220. Result:=SUnsupportedType + ' ' + d.Name;
  221. err:=True;
  222. end;
  223. dtSet:
  224. if TSetDef(d).Size <= 4 then
  225. Result:='jobject'
  226. else begin
  227. Result:=SUnsupportedType + ' ' + d.Name;
  228. err:=True;
  229. end;
  230. else begin
  231. Result:=SUnsupportedType + ' ' + d.Name;
  232. err:=True;
  233. d.SetNotUsed;
  234. end;
  235. end;
  236. end;
  237. end;
  238. function TWriter.DoCheckItem(const ItemName: string): TCheckItemResult;
  239. begin
  240. if IncludeList.IndexOf(ItemName) >= 0 then
  241. Result:=crInclude
  242. else
  243. if ExcludeList.IndexOf(ItemName) >= 0 then
  244. Result:=crExclude
  245. else
  246. Result:=crDefault;
  247. end;
  248. procedure TWriter.ProcessRules(d: TDef; const Prefix: string);
  249. var
  250. i: integer;
  251. s: string;
  252. begin
  253. s:=Prefix + d.Name;
  254. i:=IncludeList.IndexOf(s);
  255. if i >= 0 then begin
  256. i:=ptruint(IncludeList.Objects[i]);
  257. if (i = 0) or (d.Count = i - 1) then
  258. d.IsUsed:=True;
  259. end
  260. else
  261. if ExcludeList.IndexOf(s) >= 0 then begin
  262. d.SetNotUsed;
  263. end;
  264. if not (d.DefType in [dtUnit, dtClass, dtRecord]) then
  265. exit;
  266. s:=s + '.';
  267. for i:=0 to d.Count - 1 do
  268. ProcessRules(d[i], s);
  269. end;
  270. function TWriter.GetUniqueNum: integer;
  271. begin
  272. Inc(FUniqueCnt);
  273. Result:=FUniqueCnt;
  274. end;
  275. function TWriter.DefToJniSig(d: TDef): string;
  276. begin
  277. if d = nil then
  278. Result:=SUnsupportedType
  279. else
  280. case d.DefType of
  281. dtType:
  282. Result:=JNITypeSig[TTypeDef(d).BasicType];
  283. dtClass, dtRecord, dtProcType, dtSet, dtEnum:
  284. Result:='L' + GetJavaClassPath(d) + ';';
  285. else
  286. Result:=SUnsupportedType;
  287. end;
  288. end;
  289. function TWriter.DefToJavaType(d: TDef): string;
  290. begin
  291. if d = nil then
  292. Result:=SUnsupportedType
  293. else
  294. case d.DefType of
  295. dtType:
  296. Result:=JavaType[TTypeDef(d).BasicType];
  297. dtClass, dtRecord, dtProcType, dtSet, dtEnum:
  298. Result:=d.Name;
  299. else
  300. Result:=SUnsupportedType;
  301. end;
  302. end;
  303. function TWriter.GetJavaClassPath(d: TDef; const AClassName: string): string;
  304. var
  305. n: string;
  306. begin
  307. if AClassName = '' then
  308. n:=d.AliasName
  309. else
  310. n:=AClassName;
  311. Result:=StringReplace(JavaPackage, '.', '/', [rfReplaceAll]);
  312. if Result <> '' then
  313. Result:=Result + '/';
  314. if d.DefType = dtUnit then
  315. Result:=Result + n
  316. else
  317. Result:=Result + d.Parent.AliasName + '$' + n;
  318. end;
  319. procedure TWriter.WriteClass(d: TDef; PreInfo: boolean);
  320. var
  321. WrittenItems: TList;
  322. procedure _WriteConstructors(c: TClassDef; Written: TStringList);
  323. var
  324. i, j: integer;
  325. p: TProcDef;
  326. OldRet: TDef;
  327. s: string;
  328. begin
  329. if c = nil then
  330. exit;
  331. for i:=0 to c.Count - 1 do
  332. with c[i] do begin
  333. if (DefType = dtProc) and not c.IsPrivate and (TProcDef(c[i]).ProcType = ptConstructor) then begin
  334. p:=TProcDef(c[i]);
  335. j:=Written.IndexOf(p.Name);
  336. if (j < 0) or (Written.Objects[j] = c) then begin
  337. s:=p.Name + ':';
  338. for j:=0 to p.Count - 1 do
  339. s:=s + DefToJniSig(p[j]);
  340. if Written.IndexOf(s) < 0 then begin
  341. OldRet:=p.ReturnType;
  342. p.ReturnType:=d;
  343. p.Parent:=d;
  344. try
  345. WriteProc(p);
  346. finally
  347. p.ReturnType:=OldRet;
  348. p.Parent:=c;
  349. end;
  350. Written.Add(s);
  351. if not (poOverload in p.ProcOpt) then
  352. Written.AddObject(p.Name, c);
  353. end;
  354. end;
  355. end;
  356. end;
  357. _WriteConstructors(c.AncestorClass, Written);
  358. end;
  359. procedure WriteConstructors;
  360. var
  361. cc: TStringList;
  362. begin
  363. if not TClassDef(d).HasAbstractMethods then begin
  364. // Writing all constructors including parent's
  365. cc:=TStringList.Create;
  366. try
  367. cc.Sorted:=True;
  368. _WriteConstructors(TClassDef(d), cc);
  369. finally
  370. cc.Free;
  371. end;
  372. end;
  373. end;
  374. procedure _WriteReplacedItems(c: TClassDef);
  375. var
  376. i: integer;
  377. p: TReplDef;
  378. begin
  379. c:=c.AncestorClass;
  380. if c = nil then
  381. exit;
  382. if c.HasReplacedItems then begin
  383. for i:=0 to c.Count - 1 do
  384. with c[i] do begin
  385. p:=TReplDef(c[i]);
  386. if (DefType in ReplDefs) and ((p.IsReplaced) or p.IsReplImpl) then begin
  387. if p.ReplacedItem <> nil then
  388. WrittenItems.Add(p.ReplacedItem);
  389. if WrittenItems.IndexOf(p) >= 0 then
  390. continue;
  391. case p.DefType of
  392. dtProc:
  393. WriteProc(TProcDef(p), nil, d);
  394. dtProp, dtField:
  395. WriteVar(TVarDef(p), d);
  396. end;
  397. end;
  398. end;
  399. end;
  400. _WriteReplacedItems(c);
  401. end;
  402. procedure WriteReplacedItems;
  403. begin
  404. _WriteReplacedItems(TClassDef(d));
  405. end;
  406. procedure WriteItems(Regular, Replaced, ReplImpl: boolean);
  407. var
  408. i: integer;
  409. it: TReplDef;
  410. begin
  411. for i:=0 to d.Count - 1 do begin
  412. it:=TReplDef(d[i]);
  413. if not (it.DefType in ReplDefs) then
  414. continue;
  415. if not (it.IsReplImpl or it.IsReplaced) then begin
  416. if not Regular then
  417. continue;
  418. end
  419. else
  420. if (not Replaced and it.IsReplaced) or (not ReplImpl and it.IsReplImpl) then
  421. continue;
  422. if it.ReplacedItem <> nil then
  423. WrittenItems.Add(it.ReplacedItem);
  424. case it.DefType of
  425. dtProc:
  426. if TProcDef(it).ProcType <> ptConstructor then
  427. WriteProc(TProcDef(it));
  428. dtProp, dtField:
  429. WriteVar(TVarDef(it));
  430. end;
  431. end;
  432. end;
  433. var
  434. s, ss: string;
  435. RegularClass: boolean;
  436. begin
  437. if PreInfo then begin
  438. WriteClassInfoVar(d);
  439. if d.DefType = dtRecord then begin
  440. s:=d.Parent.Name + '.' + d.Name;
  441. Fps.WriteLn;
  442. Fps.WriteLn(Format('function _%s_CreateObj(env: PJNIEnv; const r: %s): jobject;', [GetClassPrefix(d), s]));
  443. Fps.WriteLn(Format('var pr: ^%s;', [s]));
  444. Fps.WriteLn('begin');
  445. Fps.IncI;
  446. Fps.WriteLn('New(pr); pr^:=r;');
  447. Fps.WriteLn(Format('Result:=_CreateJavaObj(env, pr, %s);', [GetTypeInfoVar(d)]));
  448. Fps.DecI;
  449. Fps.WriteLn('end;');
  450. Fps.WriteLn;
  451. ss:=Format('_%s_Free', [GetClassPrefix(d)]);
  452. Fps.WriteLn(Format('procedure %s(env: PJNIEnv; _self: JObject; r: jlong);', [ss]) + JniCaliing);
  453. Fps.WriteLn(Format('var pr: ^%s;', [s]));
  454. Fps.WriteLn('begin');
  455. Fps.WriteLn('pr:=pointer(ptruint(r));', 1);
  456. Fps.WriteLn('Dispose(pr);', 1);
  457. Fps.WriteLn('end;');
  458. AddNativeMethod(d, ss, 'Release', '(J)V');
  459. end;
  460. exit;
  461. end;
  462. // Java
  463. case d.DefType of
  464. dtClass:
  465. s:='class';
  466. dtRecord:
  467. s:='record';
  468. else
  469. s:='';
  470. end;
  471. WriteComment(d, s);
  472. s:='public static class ' + GetJavaClassName(d, nil) + ' extends ';
  473. if d.DefType = dtClass then
  474. with TClassDef(d) do begin
  475. if AncestorClass <> nil then begin
  476. ss:=AncestorClass.Name;
  477. if ImplementsReplacedItems then
  478. ss:='__' + ss;
  479. s:=s + ss;
  480. end
  481. else
  482. s:=s + 'PascalObject';
  483. end
  484. else
  485. s:=s + Format('%s.system.Record', [JavaPackage]);
  486. Fjs.WriteLn(s + ' {');
  487. Fjs.IncI;
  488. if d.DefType = dtRecord then begin
  489. Fjs.WriteLn('private native void Release(long pasobj);');
  490. Fjs.WriteLn(Format('public %s() { }', [d.Name]));
  491. Fjs.WriteLn(Format('public void Free() { Release(_pasobj); super.Free(); }', [d.Name]));
  492. Fjs.WriteLn(Format('public int Size() { return %d; }', [TRecordDef(d).Size]));
  493. end;
  494. WrittenItems:=TList.Create;
  495. try
  496. RegularClass:=(d.DefType = dtClass) and not TClassDef(d).HasReplacedItems;
  497. if RegularClass then
  498. WriteConstructors;
  499. // Write regular items
  500. WriteItems(True, False, RegularClass);
  501. if RegularClass and TClassDef(d).ImplementsReplacedItems then
  502. // Write implementation wrappers for replaced mehods
  503. WriteReplacedItems;
  504. Fjs.DecI;
  505. Fjs.WriteLn('}');
  506. Fjs.WriteLn;
  507. if (d.DefType = dtClass) and (TClassDef(d).HasReplacedItems) then begin
  508. // Write replaced items
  509. Fjs.WriteLn(Format('public static class %s extends __%0:s {', [d.AliasName]));
  510. Fjs.IncI;
  511. WriteConstructors;
  512. WriteItems(False, True, True);
  513. if TClassDef(d).ImplementsReplacedItems then
  514. // Write implementation wrappers for replaced mehods
  515. WriteReplacedItems;
  516. Fjs.DecI;
  517. Fjs.WriteLn('}');
  518. Fjs.WriteLn;
  519. end;
  520. finally
  521. WrittenItems.Free;
  522. end;
  523. end;
  524. procedure TWriter.WriteProc(d: TProcDef; Variable: TVarDef; AParent: TDef);
  525. var
  526. i, j, ClassIdx: integer;
  527. s, ss: string;
  528. err, tf: boolean;
  529. pi: TProcInfo;
  530. ci: TClassInfo;
  531. IsTObject: boolean;
  532. tempvars: TStringList;
  533. vd: TVarDef;
  534. UseTempObjVar: boolean;
  535. ItemDef: TDef;
  536. begin
  537. ASSERT(d.DefType = dtProc);
  538. if d.IsPrivate or not d.IsUsed then
  539. exit;
  540. IsTObject:=(d.Parent.DefType = dtClass) and (TClassDef(d.Parent).AncestorClass = nil);
  541. if (d.ProcType = ptDestructor) and not IsTObject then
  542. exit;
  543. if Variable <> nil then
  544. ItemDef:=Variable
  545. else
  546. ItemDef:=d;
  547. tempvars:=nil;
  548. pi:=TProcInfo.Create;
  549. with d do
  550. try
  551. pi.Name:=Name;
  552. s:=GetClassPrefix(d.Parent) + pi.Name;
  553. pi.JniName:=s;
  554. pi.JniSignature:=GetProcSignature(d);
  555. if AParent = nil then begin
  556. // Checking duplicate name and duplicate params
  557. ClassIdx:=FClasses.IndexOf(GetJavaClassName(d.Parent, ItemDef));
  558. if ClassIdx >= 0 then begin
  559. ci:=TClassInfo(FClasses.Objects[ClassIdx]);
  560. j:=1;
  561. ss:=Copy(pi.JniSignature, 1, Pos(')', pi.JniSignature));
  562. repeat
  563. err:=False;
  564. for i:=0 to ci.Funcs.Count - 1 do
  565. with TProcInfo(ci.Funcs[i]) do
  566. if CompareText(JniName, pi.JniName) = 0 then begin
  567. Inc(j);
  568. pi.JniName:=Format('%s_%d', [s, j]);
  569. err:=True;
  570. break;
  571. end
  572. else
  573. if (CompareText(Name, pi.Name) = 0) and (ss = Copy(JniSignature, 1, Pos(')', JniSignature))) then
  574. // Duplicate params
  575. exit;
  576. until not err;
  577. end;
  578. err:=False;
  579. if ProcType in [ptFunction, ptConstructor] then
  580. s:='function'
  581. else
  582. s:='procedure';
  583. s:=s + ' ' + pi.JniName + '(_env: PJNIEnv; _jobj: jobject';
  584. UseTempObjVar:=(ProcType = ptProcedure) and (Variable <> nil) and (Variable.VarType <> nil) and (Variable.VarType.DefType = dtProcType) and (Variable.Parent.DefType <> dtUnit);
  585. for j:=0 to Count - 1 do
  586. with TVarDef(Items[j]) do begin
  587. s:=s + '; ' + Name + ': ';
  588. if VarOpt * [voVar, voOut] = [] then
  589. s:=s + DefToJniType(VarType, err)
  590. else begin
  591. s:=s + 'jarray';
  592. if tempvars = nil then
  593. tempvars:=TStringList.Create;
  594. if VarType = nil then
  595. err:=True
  596. else
  597. Tag:=tempvars.AddObject('__tmp_' + Name, d.Items[j]) + 1;
  598. end;
  599. end;
  600. s:=s + ')';
  601. if ProcType in [ptFunction, ptConstructor] then
  602. s:=s + ': ' + DefToJniType(ReturnType, err);
  603. s:=s + '; ' + JniCaliing;
  604. if err then begin
  605. d.SetNotUsed;
  606. s:='// ' + s;
  607. end;
  608. Fps.WriteLn;
  609. Fps.WriteLn(s);
  610. if err then
  611. exit;
  612. if (tempvars <> nil) or UseTempObjVar then begin
  613. s:='';
  614. Fps.WriteLn('var');
  615. Fps.IncI;
  616. if tempvars <> nil then begin
  617. for i:=0 to tempvars.Count - 1 do begin
  618. vd:=TVarDef(tempvars.Objects[i]);
  619. Fps.WriteLn(Format('%s: %s;', [tempvars[i], vd.VarType.Name]));
  620. if IsJavaSimpleType(vd.VarType) then begin
  621. Fps.WriteLn(Format('%s_arr: P%s;', [tempvars[i], DefToJniType(vd.VarType, err)]));
  622. if s = '' then
  623. s:='__iscopy: JBoolean;';
  624. end;
  625. end;
  626. if s <> '' then
  627. Fps.WriteLn(s);
  628. end;
  629. if UseTempObjVar then
  630. Fps.WriteLn('__objvar: ' + d.Parent.Name + ';');
  631. Fps.DecI;
  632. end;
  633. Fps.WriteLn('begin');
  634. Fps.IncI;
  635. EHandlerStart;
  636. tf:=False;
  637. // Assign var parameter values to local vars
  638. if tempvars <> nil then begin
  639. for i:=0 to tempvars.Count - 1 do begin
  640. vd:=TVarDef(tempvars.Objects[i]);
  641. Fps.WriteLn(Format('if _env^^.GetArrayLength(_env, %s) <> 1 then _RaiseVarParamException(''%s'');', [vd.Name, vd.Name]));
  642. if IsJavaSimpleType(vd.VarType) then begin
  643. Fps.WriteLn(Format('%s_arr:=_env^^.Get%sArrayElements(_env, %s, __iscopy);', [tempvars[i], GetJniFuncType(vd.VarType), vd.Name]));
  644. Fps.WriteLn(Format('if %s_arr = nil then _RaiseVarParamException(''%s'');', [tempvars[i], vd.Name]));
  645. s:=tempvars[i] + '_arr^';
  646. tf:=True;
  647. end
  648. else
  649. s:=Format('_env^^.GetObjectArrayElement(_env, %s, 0)', [vd.Name]);
  650. if voVar in vd.VarOpt then
  651. Fps.WriteLn(tempvars[i] + ':=' + JniToPasType(vd.VarType, s, False) + ';');
  652. end;
  653. end;
  654. if tf then begin
  655. Fps.WriteLn('try');
  656. Fps.IncI;
  657. end;
  658. s:='';
  659. if Parent.DefType = dtUnit then
  660. s:=Parent.Name + '.'
  661. else
  662. if ProcType = ptConstructor then
  663. s:=Parent.Parent.Name + '.' + Parent.Name + '.'
  664. else
  665. s:=JniToPasType(d.Parent, '_jobj', True) + '.';
  666. if Variable = nil then begin
  667. // Regular proc
  668. s:=s + pi.Name;
  669. if Count > 0 then begin
  670. s:=s + '(';
  671. for j:=0 to Count - 1 do begin
  672. vd:=TVarDef(Items[j]);
  673. if vd.Tag <> 0 then
  674. ss:=tempvars[vd.Tag - 1]
  675. else begin
  676. ss:=Items[j].Name;
  677. ss:=JniToPasType(vd.VarType, ss, False);
  678. end;
  679. if j <> 0 then
  680. s:=s + ', ';
  681. s:=s + ss;
  682. end;
  683. s:=s + ')';
  684. end;
  685. end
  686. else begin
  687. // Var access
  688. if UseTempObjVar then begin
  689. System.Delete(s, Length(s), 1);
  690. Fps.WriteLn('__objvar:=' + s + ';');
  691. s:='__objvar.';
  692. end;
  693. s:=s + Variable.Name;
  694. if Variable.IndexType <> nil then begin
  695. ASSERT(Count >= 1);
  696. i:=1;
  697. s:=Format('%s[%s]', [s, JniToPasType(TVarDef(Items[0]).VarType, Items[0].Name, False)]);
  698. end
  699. else
  700. i:=0;
  701. if ProcType = ptProcedure then begin
  702. ASSERT(Count = i + 1);
  703. if Variable.VarType.DefType = dtProcType then begin
  704. Fps.WriteLn(Format('_RefMethodPtr(_env, TMethod(%s), False);', [s]));
  705. ss:=Format('_RefMethodPtr(_env, TMethod(%s), True);', [s]);
  706. end;
  707. s:=s + ':=' + JniToPasType(TVarDef(Items[i]).VarType, Items[i].Name, False);
  708. end;
  709. end;
  710. if ProcType in [ptFunction, ptConstructor] then
  711. s:='Result:=' + PasToJniType(ReturnType, s);
  712. s:=s + ';';
  713. Fps.WriteLn(s);
  714. if (Variable <> nil) and UseTempObjVar then
  715. Fps.WriteLn(ss);
  716. // Return var/out parameters
  717. if tempvars <> nil then begin
  718. for i:=0 to tempvars.Count - 1 do begin
  719. vd:=TVarDef(tempvars.Objects[i]);
  720. if IsJavaSimpleType(vd.VarType) then
  721. Fps.WriteLn(Format('%s_arr^:=%s;', [tempvars[i], PasToJniType(vd.VarType, tempvars[i])]))
  722. else
  723. Fps.WriteLn(Format('_env^^.SetObjectArrayElement(_env, %s, 0, %s);', [vd.Name, PasToJniType(vd.VarType, tempvars[i])]));
  724. end;
  725. end;
  726. if IsTObject and ( (ProcType = ptDestructor) or (CompareText(Name, 'Free') = 0) ) then
  727. Fps.WriteLn(Format('_env^^.SetLongField(_env, _jobj, %s.ObjFieldId, 0);', [GetTypeInfoVar(d.Parent)]));
  728. if tf then begin
  729. Fps.WriteLn('finally', -1);
  730. if tempvars <> nil then begin
  731. for i:=0 to tempvars.Count - 1 do begin
  732. vd:=TVarDef(tempvars.Objects[i]);
  733. if IsJavaSimpleType(vd.VarType) then
  734. Fps.WriteLn(Format('_env^^.Release%sArrayElements(_env, %s, %s_arr, 0);', [JavaType[TTypeDef(vd.VarType).BasicType], vd.Name, tempvars[i]]));
  735. end;
  736. end;
  737. Fps.DecI;
  738. Fps.WriteLn('end;');
  739. end;
  740. s:='';
  741. if ProcType in [ptFunction, ptConstructor] then begin
  742. s:='0';
  743. if (ReturnType.DefType = dtType) and (TTypeDef(ReturnType).BasicType <= btDouble) then
  744. s:='0'
  745. else
  746. s:=Format('%s(0)', [DefToJniType(ReturnType, err)]);
  747. s:='Result:=' + s + ';';
  748. end;
  749. EHandlerEnd('_env', s);
  750. Fps.DecI;
  751. Fps.WriteLn('end;');
  752. AParent:=d.Parent;
  753. end
  754. else
  755. ClassIdx:=FClasses.IndexOf(GetJavaClassName(AParent, ItemDef));
  756. if ClassIdx < 0 then begin
  757. ci:=TClassInfo.Create;
  758. ci.Def:=AParent;
  759. s:=GetJavaClassName(AParent, ItemDef);
  760. ci.IsCommonClass:=s <> AParent.Name;
  761. ClassIdx:=FClasses.AddObject(s, ci);
  762. end;
  763. TClassInfo(FClasses.Objects[ClassIdx]).Funcs.Add(pi);
  764. pi:=nil;
  765. // Java part
  766. s:=GetJavaProcDeclaration(d) + ';';
  767. if (Parent.DefType = dtUnit) or (ProcType = ptConstructor) then
  768. s:='static ' + s;
  769. if Variable = nil then
  770. Fjs.WriteLn('// ' + GetProcDeclaration(d));
  771. if poPrivate in ProcOpt then
  772. ss:='private'
  773. else
  774. if poProtected in ProcOpt then
  775. ss:='protected'
  776. else
  777. ss:='public';
  778. Fjs.WriteLn(ss + ' native ' + s);
  779. finally
  780. pi.Free;
  781. tempvars.Free;
  782. end;
  783. end;
  784. procedure TWriter.WriteVar(d: TVarDef; AParent: TDef);
  785. var
  786. pd: TProcDef;
  787. t: TTypeDef;
  788. s: string;
  789. begin
  790. if not d.IsUsed then
  791. exit;
  792. if d.VarType <> nil then begin
  793. case d.DefType of
  794. dtVar:
  795. s:='var';
  796. dtProp:
  797. s:='property';
  798. else
  799. s:='';
  800. end;
  801. s:=Trim(s + ' ' + d.Name);
  802. if d.IndexType <> nil then
  803. s:=s + '[]';
  804. Fjs.WriteLn(Format('// %s: %s', [s, d.VarType.Name]));
  805. end;
  806. if voRead in d.VarOpt then begin
  807. pd:=TProcDef.Create(nil, dtProc);
  808. try
  809. pd.IsUsed:=True;
  810. pd.Parent:=d.Parent;
  811. pd.ProcType:=ptFunction;
  812. pd.Name:='get' + d.Name;
  813. pd.ReturnType:=d.VarType;
  814. if d.IndexType <> nil then
  815. with TVarDef.Create(pd, dtParam) do begin
  816. Name:='_Index';
  817. AliasName:='Index';
  818. VarType:=d.IndexType;
  819. VarOpt:=[voRead];
  820. end;
  821. WriteProc(pd, d, AParent);
  822. finally
  823. pd.Free;
  824. end;
  825. end;
  826. if voWrite in d.VarOpt then begin
  827. pd:=TProcDef.Create(nil, dtProc);
  828. try
  829. pd.IsUsed:=True;
  830. pd.Parent:=d.Parent;
  831. pd.ProcType:=ptProcedure;
  832. pd.Name:='set' + d.Name;
  833. if d.IndexType <> nil then
  834. with TVarDef.Create(pd, dtParam) do begin
  835. Name:='_Index';
  836. AliasName:='Index';
  837. VarType:=d.IndexType;
  838. VarOpt:=[voRead];
  839. end;
  840. with TVarDef.Create(pd, dtParam) do begin
  841. Name:='_Value';
  842. AliasName:='Value';
  843. VarType:=d.VarType;
  844. VarOpt:=[voRead];
  845. end;
  846. t:=TTypeDef.Create(nil, dtType);
  847. try
  848. t.BasicType:=btVoid;
  849. pd.ReturnType:=t;
  850. WriteProc(pd, d, AParent);
  851. finally
  852. t.Free;
  853. end;
  854. finally
  855. pd.Free;
  856. end;
  857. end;
  858. end;
  859. procedure TWriter.WriteConst(d: TConstDef);
  860. var
  861. s, v: string;
  862. begin
  863. if not d.IsUsed then
  864. exit;
  865. v:=d.Value;
  866. if d.VarType = nil then begin
  867. if Copy(d.Value, 1, 1) = '"' then
  868. s:='String'
  869. else
  870. s:='double';
  871. end
  872. else begin
  873. s:=DefToJavaType(d.VarType);
  874. if d.VarType.DefType = dtType then
  875. case TTypeDef(d.VarType).BasicType of
  876. btLongWord, btInt64:
  877. v:=v + 'L';
  878. btBoolean:
  879. if v = '1' then
  880. v:='true'
  881. else
  882. v:='false';
  883. end;
  884. end;
  885. Fjs.WriteLn(Format('public static final %s %s = %s;', [s, d.Name, v]));
  886. end;
  887. procedure TWriter.WriteEnum(d: TDef);
  888. var
  889. i: integer;
  890. s: string;
  891. begin
  892. if not d.IsUsed then
  893. exit;
  894. RegisterPseudoClass(d);
  895. WriteComment(d, 'enum');
  896. Fjs.WriteLn(Format('public enum %s {', [d.Name]));
  897. Fjs.IncI;
  898. for i:=0 to d.Count - 1 do begin
  899. s:=Format('%s (%s)', [d[i].Name, TConstDef(d[i]).Value]);
  900. if i <> d.Count - 1 then
  901. s:=s + ','
  902. else
  903. s:=s + ';';
  904. Fjs.WriteLn(s);
  905. end;
  906. Fjs.WriteLn;
  907. Fjs.WriteLn('private final int Value;');
  908. Fjs.WriteLn(Format('%s(int v) { Value=v; }', [d.Name]));
  909. Fjs.WriteLn('public int Ord() { return Value; }');
  910. Fjs.DecI;
  911. Fjs.WriteLn('}');
  912. Fjs.WriteLn;
  913. end;
  914. procedure TWriter.WriteProcType(d: TProcDef; PreInfo: boolean);
  915. procedure _AccessSimpleArray(vd: TVarDef; VarIndex: integer; DoSet: boolean);
  916. begin
  917. with vd do begin
  918. Fps.WriteLn(Format('_tmp_%s:=_env^^.Get%sArrayElements(_env, _args[%d].L, PJBoolean(nil)^);', [Name, GetJniFuncType(VarType), VarIndex]));
  919. Fps.WriteLn(Format('if _tmp_%s <> nil then', [Name]));
  920. if DoSet then
  921. Fps.WriteLn(Format('_tmp_%s^:=%s;', [Name, PasToJniType(VarType, Name)]), 1)
  922. else
  923. Fps.WriteLn(Format('%s:=%s;', [Name, JniToPasType(VarType, '_tmp_' + Name + '^', False)]), 1);
  924. Fps.WriteLn(Format('_env^^.Release%sArrayElements(_env, _args[%d].L, _tmp_%s, 0);', [GetJniFuncType(VarType), VarIndex, Name]));
  925. end;
  926. end;
  927. var
  928. vd: TVarDef;
  929. i: integer;
  930. s, ss: string;
  931. err: boolean;
  932. begin
  933. if not d.IsUsed or not (poMethodPtr in d.ProcOpt) then
  934. exit;
  935. if PreInfo then begin
  936. WriteClassInfoVar(d);
  937. // Handler proc
  938. Fps.WriteLn;
  939. vd:=TVarDef.Create(nil, dtParam);
  940. try
  941. vd.Name:='_data';
  942. vd.VarType:=TTypeDef.Create(nil, dtType);
  943. with TTypeDef(vd.VarType) do begin
  944. Name:='pointer';
  945. BasicType:=btPointer;
  946. end;
  947. d.Insert(0, vd);
  948. Fps.WriteLn(GetProcDeclaration(d, Format('%sHandler', [GetClassPrefix(d)])) + ';');
  949. finally
  950. vd.VarType.Free;
  951. vd.Free;
  952. end;
  953. Fps.WriteLn('var');
  954. Fps.IncI;
  955. Fps.WriteLn('_env: PJNIEnv;');
  956. Fps.WriteLn('_mpi: _TMethodPtrInfo;');
  957. if d.Count > 0 then begin
  958. Fps.WriteLn(Format('_args: array[0..%d] of jvalue;', [d.Count - 1]));
  959. for i:=0 to d.Count - 1 do
  960. with TVarDef(d[i]) do
  961. if (VarOpt * [voOut, voVar] <> []) and IsJavaSimpleType(VarType) then
  962. Fps.WriteLn(Format('_tmp_%s: P%s;', [Name, DefToJniType(VarType, err)]));
  963. end;
  964. Fps.DecI;
  965. Fps.WriteLn('begin');
  966. Fps.IncI;
  967. Fps.WriteLn('CurJavaVM^^.GetEnv(CurJavaVM, @_env, JNI_VERSION_1_6);');
  968. Fps.WriteLn('_MethodPointersCS.Enter;');
  969. Fps.WriteLn('try');
  970. Fps.WriteLn('_mpi:=_TMethodPtrInfo(_MethodPointers[-integer(ptruint(_data)) - 1]);', 1);
  971. Fps.WriteLn('finally');
  972. Fps.WriteLn('_MethodPointersCS.Leave;', 1);
  973. Fps.WriteLn('end;');
  974. for i:=0 to d.Count - 1 do
  975. with TVarDef(d[i]) do begin
  976. if VarOpt * [voOut, voVar] = [] then begin
  977. s:='L';
  978. if VarType.DefType = dtType then
  979. s:=Copy(JNITypeSig[TTypeDef(VarType).BasicType], 1, 1);
  980. ss:=PasToJniType(VarType, Name);
  981. end
  982. else begin
  983. s:='L';
  984. if IsJavaSimpleType(VarType) then
  985. ss:=Format('_env^^.New%sArray(_env, 1)', [GetJniFuncType(VarType)])
  986. else begin
  987. if voVar in VarOpt then
  988. ss:=PasToJniType(VarType, Name)
  989. else
  990. ss:='nil';
  991. ss:=Format('_env^^.NewObjectArray(_env, 1, %s.ClassRef, %s)', [GetTypeInfoVar(VarType), ss]);
  992. end;
  993. end;
  994. Fps.WriteLn(Format('_args[%d].%s:=%s;', [i, s, ss]));
  995. if (voVar in VarOpt) and IsJavaSimpleType(VarType) then
  996. _AccessSimpleArray(TVarDef(d[i]), i, True);
  997. end;
  998. if d.Count > 0 then
  999. s:='@_args'
  1000. else
  1001. s:='nil';
  1002. // Calling Java handler
  1003. s:=Format('_env^^.Call%sMethodA(_env, _mpi.Obj, _mpi.MethodId, %s)', [GetJniFuncType(d.ReturnType), s]);
  1004. if d.ProcType = ptFunction then
  1005. s:=Format('Result:=%s', [JniToPasType(d.ReturnType, s, False)]);
  1006. Fps.WriteLn(s + ';');
  1007. // Processing var/out parameters
  1008. for i:=0 to d.Count - 1 do
  1009. with TVarDef(d[i]) do
  1010. if VarOpt * [voOut, voVar] <> [] then
  1011. if IsJavaSimpleType(VarType) then
  1012. _AccessSimpleArray(TVarDef(d[i]), i, False)
  1013. else begin
  1014. s:=Format('_env^^.GetObjectArrayElement(_env, _args[%d].L, 0)', [i]);
  1015. Fps.WriteLn(Format('%s:=%s;', [Name, JniToPasType(VarType, s, False)]));
  1016. end;
  1017. Fps.DecI;
  1018. Fps.WriteLn('end;');
  1019. // Get handler proc
  1020. Fps.WriteLn;
  1021. Fps.WriteLn(Format('function %sGetHandler(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo): %s.%s;',
  1022. [GetClassPrefix(d), d.Parent.Name, d.Name]));
  1023. Fps.WriteLn('var mpi: _TMethodPtrInfo;');
  1024. Fps.WriteLn('begin');
  1025. Fps.IncI;
  1026. Fps.WriteLn('Result:=nil;');
  1027. Fps.WriteLn('mpi:=_TMethodPtrInfo(_GetPasObj(env, jobj, ci, False));');
  1028. Fps.WriteLn('if mpi = nil then exit;');
  1029. Fps.WriteLn('if mpi.Index = 0 then');
  1030. Fps.WriteLn('TMethod(Result):=mpi.RealMethod', 1);
  1031. Fps.WriteLn('else');
  1032. Fps.WriteLn('with TMethod(Result) do begin', 1);
  1033. Fps.WriteLn('Data:=pointer(ptruint(-integer(mpi.Index)));', 2);
  1034. Fps.WriteLn(Format('Code:=@%sHandler;', [GetClassPrefix(d)]), 2);
  1035. Fps.WriteLn('end;', 1);
  1036. Fps.DecI;
  1037. Fps.WriteLn('end;');
  1038. exit;
  1039. end;
  1040. err:=False;
  1041. WriteComment(d, 'procedural type');
  1042. RegisterPseudoClass(d);
  1043. Fjs.WriteLn(Format('/* Pascal prototype: %s */', [GetProcDeclaration(d, 'Execute')]));
  1044. Fjs.WriteLn(Format('/* Java prototype: %s */', [GetJavaProcDeclaration(d, 'Execute')]));
  1045. Fjs.WriteLn(Format('public static class %s extends %s.system.MethodPtr {', [d.Name, JavaPackage]));
  1046. Fjs.IncI;
  1047. Fjs.WriteLn(Format('private String HandlerSig = "%s";', [GetProcSignature(d)]));
  1048. Fjs.WriteLn(Format('public %s(Object Obj, String MethodName) { Init(Obj, MethodName, HandlerSig); }', [d.Name]));
  1049. Fjs.WriteLn(Format('public %s() { Init(this, "Execute", HandlerSig); }', [d.Name]));
  1050. Fjs.WriteLn(Format('protected %s throws NoSuchMethodException { throw new NoSuchMethodException(); }', [GetJavaProcDeclaration(d, 'Execute')]));
  1051. Fjs.DecI;
  1052. Fjs.WriteLn('}');
  1053. Fjs.WriteLn;
  1054. end;
  1055. procedure TWriter.WriteSet(d: TSetDef);
  1056. begin
  1057. if not d.IsUsed then
  1058. exit;
  1059. if d.ElType = nil then
  1060. raise Exception.Create('No element type.');
  1061. WriteComment(d, '');
  1062. Fjs.WriteLn(Format('/* set of %s */', [d.ElType.Name]));
  1063. if d.Size > 4 then begin
  1064. Fjs.WriteLn('/* Set size more than 32 bits is not supported */');
  1065. exit;
  1066. end;
  1067. RegisterPseudoClass(d);
  1068. Fjs.WriteLn(Format('public static class %s extends %s.system.Set<%s,%s> {', [d.Name, JavaPackage, d.Name, d.ElType.Name]));
  1069. Fjs.IncI;
  1070. Fjs.WriteLn(Format('protected byte Size() { return %d; }', [d.Size]));
  1071. Fjs.WriteLn(Format('protected int Base() { return %d; }', [d.Base]));
  1072. Fjs.WriteLn(Format('protected int ElMax() { return %d; }', [d.ElMax]));
  1073. Fjs.WriteLn(Format('protected int Ord(%s Element) { return Element.Ord(); }', [d.ElType.Name]));
  1074. Fjs.WriteLn(Format('public %s() { }', [d.Name]));
  1075. Fjs.WriteLn(Format('public %s(%s... Elements) { super(Elements); }', [d.Name, d.ElType.Name]));
  1076. Fjs.WriteLn(Format('public %0:s(%0:s... Elements) { super(Elements); }', [d.Name]));
  1077. 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]));
  1078. 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]));
  1079. Fjs.DecI;
  1080. Fjs.WriteLn('}');
  1081. Fjs.WriteLn;
  1082. end;
  1083. procedure TWriter.WriteUnit(u: TUnitDef);
  1084. var
  1085. d: TDef;
  1086. i: integer;
  1087. begin
  1088. if u.Processed then
  1089. exit;
  1090. u.Processed:=True;
  1091. if not u.IsUsed then
  1092. exit;
  1093. for i:=0 to High(u.UsedUnits) do
  1094. WriteUnit(u.UsedUnits[i]);
  1095. Fps.WriteLn;
  1096. Fps.WriteLn(Format('{ Unit %s }', [u.Name]));
  1097. u.Name:=LowerCase(u.Name);
  1098. Fjs:=TTextOutStream.Create(IncludeTrailingPathDelimiter(FPkgDir) + u.Name + '.java', fmCreate);
  1099. try
  1100. Fjs.WriteLn(Format('package %s;', [JavaPackage]));
  1101. if Length(u.UsedUnits) > 0 then begin
  1102. Fjs.WriteLn;
  1103. for i:=0 to High(u.UsedUnits) do
  1104. if u.UsedUnits[i].IsUsed then
  1105. Fjs.WriteLn(Format('import %s.%s.*;', [JavaPackage, LowerCase(u.UsedUnits[i].Name)]));
  1106. end;
  1107. Fjs.WriteLn;
  1108. Fjs.WriteLn('public class ' + u.Name + ' {');
  1109. Fjs.IncI;
  1110. if u.Name = 'system' then begin
  1111. Fjs.WriteLn('static private boolean _JniLibLoaded = false;');
  1112. Fjs.WriteLn('public static void InitJni() {');
  1113. Fjs.WriteLn('if (!_JniLibLoaded) {', 1);
  1114. Fjs.WriteLn('_JniLibLoaded=true;', 2);
  1115. Fjs.WriteLn(Format('System.loadLibrary("%s");', [LibName]), 2);
  1116. Fjs.WriteLn('}', 1);
  1117. Fjs.WriteLn('}');
  1118. // Support functions
  1119. Fjs.WriteLn('public native static long AllocMemory(int Size);');
  1120. AddNativeMethod(u, '_AllocMemory', 'AllocMemory', '(I)J');
  1121. // Base object
  1122. Fjs.WriteLn;
  1123. Fjs.WriteLn('public static class PascalObject {');
  1124. Fjs.IncI;
  1125. Fjs.WriteLn(Format('static { %s.system.InitJni(); }', [JavaPackage]));
  1126. Fjs.WriteLn('protected long _pasobj = 0;');
  1127. Fjs.DecI;
  1128. Fjs.WriteLn('}');
  1129. Fjs.WriteLn;
  1130. Fjs.WriteLn('public static long Pointer(PascalObject obj) { return obj._pasobj; }');
  1131. // Record
  1132. Fjs.WriteLn;
  1133. Fjs.WriteLn('public static class Record extends PascalObject {');
  1134. Fjs.IncI;
  1135. Fjs.WriteLn('protected void finalize() { Free(); }');
  1136. Fjs.WriteLn('public Record() { _pasobj = AllocMemory(Size()); }');
  1137. Fjs.WriteLn('public void Free() { _pasobj = 0; }');
  1138. Fjs.WriteLn('public int Size() { return 0; }');
  1139. Fjs.DecI;
  1140. Fjs.WriteLn('}');
  1141. // Method pointer base class
  1142. d:=TClassDef.Create(FThisUnit, dtClass);
  1143. d.Name:='_TMethodPtrInfo';
  1144. d.AliasName:='MethodPtr';
  1145. WriteClassInfoVar(d);
  1146. Fps.WriteLn;
  1147. Fps.WriteLn('procedure _TMethodPtrInfo_Init(env: PJNIEnv; _self, JavaObj: JObject; AMethodName, AMethodSig: jstring);' + JniCaliing);
  1148. Fps.WriteLn('var mpi: _TMethodPtrInfo;');
  1149. Fps.WriteLn('begin');
  1150. Fps.IncI;
  1151. EHandlerStart;
  1152. Fps.WriteLn('mpi:=_TMethodPtrInfo.Create(env, JavaObj, ansistring(_StringFromJString(env, AMethodName)), ansistring(_StringFromJString(env, AMethodSig)));');
  1153. Fps.WriteLn(Format('env^^.SetLongField(env, _self, %s.ObjFieldId, Int64(ptruint(mpi)));', [GetTypeInfoVar(d)]));
  1154. EHandlerEnd('env');
  1155. Fps.DecI;
  1156. Fps.WriteLn('end;');
  1157. AddNativeMethod(d, '_TMethodPtrInfo_Init', 'Init', Format('(Ljava/lang/Object;%s%s)V', [JNITypeSig[btString], JNITypeSig[btString]]));
  1158. Fps.WriteLn;
  1159. Fps.WriteLn('procedure _TMethodPtrInfo_Release(env: PJNIEnv; _self: JObject);' + JniCaliing);
  1160. Fps.WriteLn('begin');
  1161. Fps.IncI;
  1162. EHandlerStart;
  1163. Fps.WriteLn(Format('_TMethodPtrInfo(_GetPasObj(env, _self, %s, True)).Release(env);', [GetTypeInfoVar(d)]));
  1164. EHandlerEnd('env');
  1165. Fps.DecI;
  1166. Fps.WriteLn('end;');
  1167. AddNativeMethod(d, '_TMethodPtrInfo_Release', 'Release', '()V');
  1168. Fjs.WriteLn;
  1169. Fjs.WriteLn('public static class MethodPtr extends PascalObject {');
  1170. Fjs.IncI;
  1171. Fjs.WriteLn('private native void Release();');
  1172. Fjs.WriteLn('protected void finalize() { if (_pasobj != 0) Release(); }');
  1173. Fjs.WriteLn('protected native void Init(Object Obj, String MethodName, String MethodSignature);');
  1174. Fjs.DecI;
  1175. Fjs.WriteLn('}');
  1176. Fjs.WriteLn;
  1177. // Set base class
  1178. Fjs.WriteLn('public static class Set<TS extends Set<?,?>,TE> {');
  1179. Fjs.IncI;
  1180. Fjs.WriteLn('protected int Value = 0;');
  1181. Fjs.WriteLn('protected byte Size() { return 0; }');
  1182. Fjs.WriteLn('protected int Base() { return 0; }');
  1183. Fjs.WriteLn('protected int ElMax() { return 0; }');
  1184. Fjs.WriteLn('protected int Ord(TE Element) { return 0; }');
  1185. Fjs.WriteLn('protected int GetMask(TE Element) {');
  1186. Fjs.IncI;
  1187. Fjs.WriteLn('return 1 << (Ord(Element) - Base());');
  1188. Fjs.DecI;
  1189. Fjs.WriteLn('}');
  1190. Fjs.WriteLn('public Set() { }');
  1191. Fjs.WriteLn('public Set(TE... Elements) { Include(Elements); }');
  1192. Fjs.WriteLn('public Set(TS... Elements) { for (TS e : Elements) Include(e); }');
  1193. Fjs.WriteLn('public void Include(TE... Elements) { for (TE e: Elements) Value = Value | GetMask(e); }');
  1194. Fjs.WriteLn('public void Include(TS s) { Value=Value | s.Value; }');
  1195. Fjs.WriteLn('public void Exclude(TE... Elements) { for (TE e: Elements) Value = Value & ~GetMask(e); }');
  1196. Fjs.WriteLn('public void Exclude(TS s) { Value=Value & ~s.Value; }');
  1197. Fjs.WriteLn('public void Assign(TS s) { Value=s.Value; }');
  1198. Fjs.WriteLn('public void Intersect(TS s) { Value=Value & s.Value; }');
  1199. Fjs.WriteLn('public boolean Compare(TS s) { return Value == s.Value; }');
  1200. Fjs.WriteLn('public boolean Has(TE Element) { return (Value & GetMask(Element)) != 0; }');
  1201. Fjs.DecI;
  1202. Fjs.WriteLn('}');
  1203. Fjs.WriteLn;
  1204. end;
  1205. Fjs.WriteLn(Format('static { %s.system.InitJni(); }', [JavaPackage]));
  1206. Fjs.WriteLn;
  1207. // First pass
  1208. for i:=0 to u.Count - 1 do begin
  1209. d:=u[i];
  1210. if not d.IsUsed then
  1211. continue;
  1212. case d.DefType of
  1213. dtSet, dtEnum:
  1214. WriteClassInfoVar(d);
  1215. dtClass, dtRecord:
  1216. WriteClass(d, True);
  1217. dtProcType:
  1218. WriteProcType(TProcDef(d), True);
  1219. end;
  1220. end;
  1221. // Second pass
  1222. for i:=0 to u.Count - 1 do begin
  1223. d:=u[i];
  1224. if not d.IsUsed then
  1225. continue;
  1226. case d.DefType of
  1227. dtClass, dtRecord:
  1228. WriteClass(d, False);
  1229. dtProc:
  1230. WriteProc(TProcDef(d));
  1231. dtVar, dtProp:
  1232. WriteVar(TVarDef(d));
  1233. dtEnum:
  1234. WriteEnum(d);
  1235. dtProcType:
  1236. WriteProcType(TProcDef(d), False);
  1237. dtSet:
  1238. WriteSet(TSetDef(d));
  1239. dtConst:
  1240. WriteConst(TConstDef(d));
  1241. end;
  1242. end;
  1243. Fjs.DecI;
  1244. Fjs.WriteLn('}');
  1245. finally
  1246. Fjs.Free;
  1247. end;
  1248. end;
  1249. procedure TWriter.WriteOnLoad;
  1250. var
  1251. i, j: integer;
  1252. ci: TClassInfo;
  1253. s, ss, fn: string;
  1254. d: TTypeDef;
  1255. begin
  1256. if FClasses.Count = 0 then
  1257. exit;
  1258. Fps.WriteLn;
  1259. Fps.WriteLn('function JNI_OnLoad(vm: PJavaVM; reserved: pointer): jint;' + JniCaliing);
  1260. Fps.WriteLn('const');
  1261. for i:=0 to FClasses.Count - 1 do begin
  1262. ci:=TClassInfo(FClasses.Objects[i]);
  1263. if ci.Funcs.Count = 0 then
  1264. continue;
  1265. Fps.WriteLn(Format(' _%sNativeMethods: array[0..%d] of JNINativeMethod = (', [GetClassPrefix(ci.Def, FClasses[i]), ci.Funcs.Count - 1]));
  1266. for j:=0 to ci.Funcs.Count - 1 do begin
  1267. with TProcInfo(ci.Funcs[j]) do
  1268. Fps.Write(Format(' (name: ''%s''; signature: ''%s''; fnPtr: @%s)', [Name, JniSignature, JniName]));
  1269. if j < ci.Funcs.Count - 1 then
  1270. Fps.Write(',');
  1271. Fps.WriteLn;
  1272. end;
  1273. Fps.WriteLn(' );');
  1274. end;
  1275. Fps.WriteLn;
  1276. Fps.WriteLn('var');
  1277. Fps.IncI;
  1278. Fps.WriteLn('env: PJNIEnv;');
  1279. Fps.WriteLn;
  1280. Fps.WriteLn('function _Reg(ClassName: PAnsiChar; Methods: PJNINativeMethod; Count: integer; ci: _PJavaClassInfo; const FieldName: ansistring = ''_pasobj''; const FieldSig: ansistring = ''J''): boolean;');
  1281. Fps.WriteLn('var');
  1282. Fps.WriteLn('c: jclass;', 1);
  1283. Fps.WriteLn('begin');
  1284. Fps.IncI;
  1285. Fps.WriteLn('Result:=False;');
  1286. Fps.WriteLn('c:=env^^.FindClass(env, ClassName);');
  1287. Fps.WriteLn('if c = nil then exit;');
  1288. Fps.WriteLn('Result:=(Count = 0) or (env^^.RegisterNatives(env, c, Methods, Count) = 0);');
  1289. Fps.WriteLn('if Result and (ci <> nil) then begin');
  1290. Fps.IncI;
  1291. Fps.WriteLn('ci^.ClassRef:=env^^.NewGlobalRef(env, c);');
  1292. Fps.WriteLn('Result:=ci^.ClassRef <> nil;');
  1293. Fps.WriteLn('if Result and (FieldName <> '''') then begin');
  1294. Fps.WriteLn('ci^.ObjFieldId:=env^^.GetFieldID(env, ci^.ClassRef, PAnsiChar(FieldName), PAnsiChar(FieldSig));', 1);
  1295. Fps.WriteLn('Result:=ci^.ObjFieldId <> nil;', 1);
  1296. Fps.WriteLn('end;');
  1297. Fps.DecI;
  1298. Fps.WriteLn('end;');
  1299. Fps.DecI;
  1300. Fps.WriteLn('end;');
  1301. Fps.WriteLn;
  1302. Fps.WriteLn('begin', -1);
  1303. Fps.WriteLn('Result:=JNI_ERR;');
  1304. Fps.WriteLn('if vm^^.GetEnv(vm, @env, JNI_VERSION_1_6) <> JNI_OK then exit;');
  1305. Fps.WriteLn('CurJavaVM:=vm;');
  1306. d:=TTypeDef.Create(nil, dtType);
  1307. try
  1308. d.BasicType:=btString;
  1309. s:=JNITypeSig[d.BasicType];
  1310. s:=Copy(s, 2, Length(s) - 2);
  1311. Fps.WriteLn(Format('if not _Reg(''%s'', nil, 0, @%s, '''', '''') then exit;',
  1312. [s, GetTypeInfoVar(d)]));
  1313. finally
  1314. d.Free;
  1315. end;
  1316. for i:=0 to FClasses.Count - 1 do begin
  1317. ci:=TClassInfo(FClasses.Objects[i]);
  1318. s:=GetTypeInfoVar(ci.Def);
  1319. if (s = '') or (ci.IsCommonClass) then
  1320. s:='nil'
  1321. else
  1322. s:='@' + s;
  1323. if ci.Funcs.Count = 0 then
  1324. ss:='nil'
  1325. else
  1326. ss:=Format('@_%sNativeMethods', [GetClassPrefix(ci.Def, FClasses[i])]);
  1327. fn:='';
  1328. if ci.Def <> nil then
  1329. if ci.Def.DefType in [dtSet, dtEnum] then
  1330. fn:=', ''Value'', ''I''';
  1331. Fps.WriteLn(Format('if not _Reg(''%s'', %s, %d, %s%s) then exit;',
  1332. [GetJavaClassPath(ci.Def, FClasses[i]), ss, ci.Funcs.Count, s, fn]));
  1333. end;
  1334. Fps.WriteLn('Result:=JNI_VERSION_1_6;');
  1335. Fps.DecI;
  1336. Fps.WriteLn('end;');
  1337. Fps.WriteLn;
  1338. Fps.WriteLn('exports JNI_OnLoad;');
  1339. end;
  1340. function TWriter.JniToPasType(d: TDef; const v: string; CheckNil: boolean): string;
  1341. var
  1342. n: string;
  1343. begin
  1344. Result:=v;
  1345. if d = nil then
  1346. exit;
  1347. case d.DefType of
  1348. dtType:
  1349. with TTypeDef(d) do
  1350. case BasicType of
  1351. btString, btWideString:
  1352. begin
  1353. Result:=Format('_StringFromJString(_env, %s)', [Result]);
  1354. if BasicType <> btWideString then
  1355. Result:=Format('%s(%s)', [d.Name, Result]);
  1356. end;
  1357. btBoolean:
  1358. Result:=Format('LongBool(%s)', [Result]);
  1359. btChar:
  1360. Result:=Format('char(widechar(%s))', [Result]);
  1361. btWideChar:
  1362. Result:=Format('widechar(%s)', [Result]);
  1363. btPointer:
  1364. Result:=Format('pointer(ptruint(%s))', [Result]);
  1365. btGuid:
  1366. Result:=Format('StringToGUID(ansistring(_StringFromJString(_env, %s)))', [Result]);
  1367. else
  1368. Result:=Format('%s(%s)', [d.Name, Result]);
  1369. end;
  1370. dtClass:
  1371. begin
  1372. if CheckNil then
  1373. n:='True'
  1374. else
  1375. n:='False';
  1376. Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d), n]);
  1377. end;
  1378. dtRecord:
  1379. Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, True)^)', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
  1380. dtProcType:
  1381. Result:=Format('%sGetHandler(_env, %s, %s)', [GetClassPrefix(d), Result, GetTypeInfoVar(d)]);
  1382. dtEnum:
  1383. Result:=Format('%s.%s(_GetIntObjValue(_env, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
  1384. dtSet:
  1385. Result:=Format('%s.%s(%s(_GetIntObjValue(_env, %s, %s)))', [d.Parent.Name, d.Name, GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
  1386. end;
  1387. end;
  1388. function TWriter.PasToJniType(d: TDef; const v: string): string;
  1389. begin
  1390. Result:=v;
  1391. if d = nil then
  1392. exit;
  1393. case d.DefType of
  1394. dtType:
  1395. with TTypeDef(d) do
  1396. case BasicType of
  1397. btString, btWideString:
  1398. Result:=Format('_StringToJString(_env, _JNIString(%s))', [Result]);
  1399. btBoolean:
  1400. Result:=Format('jboolean(LongBool(%s))', [Result]);
  1401. btChar:
  1402. Result:=Format('jchar(widechar(%s))', [Result]);
  1403. btWideChar:
  1404. Result:=Format('jchar(%s)', [Result]);
  1405. btEnum:
  1406. Result:=Format('jint(%s)', [Result]);
  1407. btPointer:
  1408. Result:=Format('ptruint(pointer(%s))', [Result]);
  1409. btGuid:
  1410. Result:=Format('_StringToJString(_env, _JNIString(GUIDToString(%s)))', [Result]);
  1411. end;
  1412. dtClass:
  1413. Result:=Format('_CreateJavaObj(_env, %s, %s)', [Result, GetTypeInfoVar(d)]);
  1414. dtRecord:
  1415. Result:=Format('_%s_CreateObj(_env, %s)', [GetClassPrefix(d), Result]);
  1416. dtProcType:
  1417. Result:=Format('_CreateMethodPtrObject(_env, TMethod(%s), %s)', [Result, GetTypeInfoVar(d)]);
  1418. dtEnum:
  1419. Result:=Format('_CreateIntObj(_env, longint(%s), %s)', [Result, GetTypeInfoVar(d)]);
  1420. dtSet:
  1421. Result:=Format('_CreateIntObj(_env, %s(%s), %s)', [GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
  1422. end;
  1423. end;
  1424. function TWriter.GetTypeInfoVar(ClassDef: TDef): string;
  1425. begin
  1426. if ClassDef.DefType = dtUnit then
  1427. Result:=''
  1428. else
  1429. if ClassDef.DefType = dtType then
  1430. Result:='_Java_' + JavaType[TTypeDef(ClassDef).BasicType] + '_Info'
  1431. else
  1432. Result:='_JNI_' + ClassDef.Parent.Name + '_' + ClassDef.Name + '_Info';
  1433. end;
  1434. function TWriter.GetClassPrefix(ClassDef: TDef; const AClassName: string): string;
  1435. begin
  1436. if AClassName = '' then
  1437. Result:=ClassDef.Name
  1438. else
  1439. Result:=AClassName;
  1440. Result:=Result + '_';
  1441. if ClassDef.DefType <> dtUnit then
  1442. Result:=ClassDef.Parent.Name + '_' + Result;
  1443. Result:='JNI_' + Result;
  1444. end;
  1445. function TWriter.IsJavaSimpleType(d: TDef): boolean;
  1446. begin
  1447. Result:=(d <> nil) and (d.DefType = dtType) and (Length(JNITypeSig[TTypeDef(d).BasicType]) = 1);
  1448. end;
  1449. function TWriter.GetProcDeclaration(d: TProcDef; const ProcName: string): string;
  1450. var
  1451. s, ss: string;
  1452. j: integer;
  1453. begin
  1454. with d do begin
  1455. if Count > 0 then
  1456. s:='('
  1457. else
  1458. s:='';
  1459. for j:=0 to Count - 1 do
  1460. with TVarDef(Items[j]) do begin
  1461. if j > 0 then
  1462. s:=s + '; ';
  1463. if voVar in VarOpt then
  1464. s:=s + 'var '
  1465. else
  1466. if voOut in VarOpt then
  1467. s:=s + 'out '
  1468. else
  1469. if voConst in VarOpt then
  1470. s:=s + 'const ';
  1471. s:=s + Name + ': ' + VarType.Name;
  1472. end;
  1473. if Count > 0 then
  1474. s:=s + ')';
  1475. case ProcType of
  1476. ptConstructor:
  1477. ss:='constructor';
  1478. ptDestructor:
  1479. ss:='destructor';
  1480. ptProcedure:
  1481. ss:='procedure';
  1482. ptFunction:
  1483. ss:='function';
  1484. else
  1485. ss:='';
  1486. end;
  1487. if ProcType in [ptConstructor, ptFunction] then
  1488. s:=s + ': ' + ReturnType.Name;
  1489. ss:=ss + ' ';
  1490. if ProcName <> '' then
  1491. ss:=ss + ProcName
  1492. else
  1493. ss:=ss + Name;
  1494. Result:=ss + s;
  1495. end;
  1496. end;
  1497. function TWriter.GetJavaProcDeclaration(d: TProcDef; const ProcName: string): string;
  1498. var
  1499. s: string;
  1500. j: integer;
  1501. begin
  1502. with d do begin
  1503. if ProcName <> '' then
  1504. s:=ProcName
  1505. else
  1506. s:=AliasName;
  1507. s:=DefToJavaType(ReturnType) + ' ' + s + '(';
  1508. for j:=0 to Count - 1 do
  1509. with TVarDef(Items[j]) do begin
  1510. if j > 0 then
  1511. s:=s + ', ';
  1512. s:=s + DefToJavaType(VarType);
  1513. if VarOpt * [voVar, voOut] <> [] then
  1514. s:=s + '[]';
  1515. s:=s + ' ' + AliasName;
  1516. end;
  1517. s:=s + ')';
  1518. end;
  1519. Result:=s;
  1520. end;
  1521. function TWriter.GetJniFuncType(d: TDef): string;
  1522. begin
  1523. if IsJavaSimpleType(d) then begin
  1524. Result:=JavaType[TTypeDef(d).BasicType];
  1525. Result[1]:=UpCase(Result[1]);
  1526. end
  1527. else
  1528. Result:='Object';
  1529. end;
  1530. function TWriter.GetJavaClassName(cls: TDef; it: TDef): string;
  1531. begin
  1532. Result:=cls.AliasName;
  1533. if (cls.DefType <> dtClass) or ((it <> nil) and not (it.DefType in ReplDefs)) then
  1534. exit;
  1535. with TClassDef(cls) do begin
  1536. if not (HasReplacedItems or ImplementsReplacedItems) then
  1537. exit;
  1538. if ImplementsReplacedItems and not HasReplacedItems then
  1539. exit;
  1540. if it <> nil then
  1541. with TReplDef(it) do begin
  1542. if (it.DefType = dtProc) and (TProcDef(it).ProcType = ptConstructor) then
  1543. exit;
  1544. if IsReplaced or IsReplImpl then
  1545. exit;
  1546. end;
  1547. end;
  1548. Result:='__' + Result;
  1549. end;
  1550. procedure TWriter.RegisterPseudoClass(d: TDef);
  1551. var
  1552. ci: TClassInfo;
  1553. begin
  1554. if FClasses.IndexOf(d.Name) < 0 then begin
  1555. ci:=TClassInfo.Create;
  1556. ci.Def:=d;
  1557. FClasses.AddObject(d.Name, ci);
  1558. end;
  1559. end;
  1560. function TWriter.GetPasIntType(Size: integer): string;
  1561. begin
  1562. case Size of
  1563. 1: Result:='byte';
  1564. 2: Result:='word';
  1565. else
  1566. Result:='cardinal';
  1567. end;
  1568. end;
  1569. function TWriter.AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType): TProcDef;
  1570. var
  1571. i: integer;
  1572. vd: TVarDef;
  1573. begin
  1574. Result:=TProcDef.Create(ParentDef, dtProc);
  1575. Result.Name:=JniName;
  1576. Result.AliasName:=Name;
  1577. if RetType = btVoid then
  1578. Result.ProcType:=ptProcedure
  1579. else
  1580. Result.ProcType:=ptFunction;
  1581. for i:=0 to High(Params) do begin
  1582. vd:=TVarDef.Create(Result, dtParam);
  1583. vd.Name:=Format('p%d', [i + 1]);
  1584. vd.VarType:=TTypeDef.Create(vd, dtType);
  1585. TTypeDef(vd.VarType).BasicType:=Params[i];
  1586. end;
  1587. Result.ReturnType:=TTypeDef.Create(ParentDef, dtType);
  1588. TTypeDef(Result.ReturnType).BasicType:=RetType;
  1589. end;
  1590. procedure TWriter.AddNativeMethod(ParentDef: TDef; const JniName, Name, Signature: string);
  1591. var
  1592. i: integer;
  1593. ci: TClassInfo;
  1594. pi: TProcInfo;
  1595. begin
  1596. pi:=TProcInfo.Create;
  1597. pi.Name:=Name;
  1598. pi.JniName:=JniName;
  1599. pi.JniSignature:=Signature;
  1600. i:=FClasses.IndexOf(ParentDef.AliasName);
  1601. if i < 0 then begin
  1602. ci:=TClassInfo.Create;
  1603. ci.Def:=ParentDef;
  1604. i:=FClasses.AddObject(ParentDef.AliasName, ci);
  1605. end;
  1606. TClassInfo(FClasses.Objects[i]).Funcs.Add(pi);
  1607. end;
  1608. function TWriter.GetProcSignature(d: TProcDef): string;
  1609. var
  1610. j: integer;
  1611. begin
  1612. Result:='(';
  1613. for j:=0 to d.Count - 1 do
  1614. with TVarDef(d[j]) do begin
  1615. if VarOpt * [voVar, voOut] <> [] then
  1616. Result:=Result + '[';
  1617. Result:=Result + DefToJniSig(VarType);
  1618. end;
  1619. Result:=Result + ')' + DefToJniSig(d.ReturnType);
  1620. end;
  1621. procedure TWriter.EHandlerStart;
  1622. begin
  1623. Fps.WriteLn('try');
  1624. Fps.IncI;
  1625. end;
  1626. procedure TWriter.EHandlerEnd(const EnvVarName: string; const ExtraCode: string);
  1627. begin
  1628. Fps.WriteLn('except', -1);
  1629. Fps.WriteLn(Format('_HandleJNIException(%s);', [EnvVarName]));
  1630. if ExtraCode <> '' then
  1631. Fps.WriteLn(ExtraCode);
  1632. Fps.DecI;
  1633. Fps.WriteLn('end;');
  1634. end;
  1635. procedure TWriter.WriteClassInfoVar(d: TDef);
  1636. begin
  1637. Fps.WriteLn;
  1638. Fps.WriteLn(Format('var %s: _TJavaClassInfo;', [GetTypeInfoVar(d)]));
  1639. end;
  1640. procedure TWriter.WriteComment(d: TDef; const AType: string);
  1641. begin
  1642. Fps.WriteLn;
  1643. Fps.WriteLn(Format('{ %s }', [d.Name]));
  1644. Fjs.WriteLn(Format('/* %s %s */', [AType, d.Name]));
  1645. {$ifdef DEBUG}
  1646. Fjs.WriteLn(Format('/* Ref count: %d */', [d.RefCnt]));
  1647. {$endif}
  1648. end;
  1649. {
  1650. procedure TWriter.AddCustomProc(ParentDef: TDef; const JniName, Name: string; RetType: TBasicType; const Params: array of TBasicType);
  1651. var
  1652. i: integer;
  1653. ci: TClassInfo;
  1654. pi: TProcInfo;
  1655. begin
  1656. pi:=TProcInfo.Create;
  1657. pi.Name:=Name;
  1658. pi.JniName:=JniName;
  1659. pi.JniSignature:='(';
  1660. for i:=0 to High(Params) do
  1661. pi.JniSignature:=pi.JniSignature + JNITypeSig[Params[i]];
  1662. pi.JniSignature:=pi.JniSignature + ')';
  1663. pi.JniSignature:=pi.JniSignature + JNITypeSig[RetType];
  1664. i:=FClasses.IndexOf(ParentDef.Name);
  1665. if i < 0 then begin
  1666. ci:=TClassInfo.Create;
  1667. ci.Def:=ParentDef;
  1668. i:=FClasses.AddObject(ParentDef.Name, ci);
  1669. end;
  1670. TClassInfo(FClasses.Objects[i]).Funcs.Add(pi);
  1671. end;
  1672. }
  1673. constructor TWriter.Create;
  1674. var
  1675. i: integer;
  1676. begin
  1677. Units:=TStringList.Create;
  1678. FClasses:=TStringList.Create;
  1679. FClasses.Sorted:=True;
  1680. JavaPackage:='pas';
  1681. IncludeList:=TStringList.Create;
  1682. IncludeList.Duplicates:=dupIgnore;
  1683. ExcludeList:=TStringList.Create;
  1684. ExcludeList.Duplicates:=dupIgnore;
  1685. for i:=Low(ExcludeStd) to High(ExcludeStd) do
  1686. ExcludeList.Add(ExcludeStd[i]);
  1687. for i:=Low(ExcludeDelphi7) to High(ExcludeDelphi7) do
  1688. ExcludeList.Add(ExcludeDelphi7[i]);
  1689. FThisUnit:=TUnitDef.Create(nil, dtUnit);
  1690. end;
  1691. destructor TWriter.Destroy;
  1692. var
  1693. i: integer;
  1694. begin
  1695. for i:=0 to FClasses.Count - 1 do
  1696. FClasses.Objects[i].Free;
  1697. FClasses.Free;
  1698. Units.Free;
  1699. IncludeList.Free;
  1700. ExcludeList.Free;
  1701. FThisUnit.Free;
  1702. inherited Destroy;
  1703. end;
  1704. procedure TWriter.ProcessUnits;
  1705. var
  1706. p: TPPUParser;
  1707. i: integer;
  1708. s, ss: string;
  1709. d: TDef;
  1710. begin
  1711. if Units.Count = 0 then
  1712. raise Exception.Create('No unit name specified.');
  1713. if (OutPath <> '') and not DirectoryExists(OutPath) then
  1714. raise Exception.CreateFmt('Output path "%s" does not exist.', [OutPath]);
  1715. if (JavaOutPath <> '') and not DirectoryExists(JavaOutPath) then
  1716. raise Exception.CreateFmt('Output path "%s" does not exist.', [JavaOutPath]);
  1717. if LibName = '' then
  1718. LibName:=AnsiLowerCase(ChangeFileExt(Units[0], '')) + 'jni';
  1719. for i:=0 to IncludeList.Count - 1 do
  1720. IncludeList[i]:=Trim(IncludeList[i]);
  1721. IncludeList.Sorted:=True;
  1722. for i:=0 to ExcludeList.Count - 1 do
  1723. ExcludeList[i]:=Trim(ExcludeList[i]);
  1724. ExcludeList.Sorted:=True;
  1725. FThisUnit.Name:=LibName;
  1726. FThisUnit.AliasName:='system';
  1727. p:=TPPUParser.Create(SearchPath);
  1728. try
  1729. p.OnCheckItem:=@DoCheckItem;
  1730. for i:=0 to Units.Count - 1 do
  1731. IncludeList.Add(ChangeFileExt(ExtractFileName(Units[i]), ''));
  1732. for i:=0 to Units.Count - 1 do
  1733. p.Parse(ChangeFileExt(ExtractFileName(Units[i]), ''));
  1734. if OutPath <> '' then
  1735. OutPath:=IncludeTrailingPathDelimiter(OutPath);
  1736. if JavaOutPath <> '' then
  1737. JavaOutPath:=IncludeTrailingPathDelimiter(JavaOutPath);
  1738. FPkgDir:=JavaOutPath + StringReplace(JavaPackage, '.', DirectorySeparator, [rfReplaceAll]);
  1739. ForceDirectories(FPkgDir);
  1740. Fps:=TTextOutStream.Create(OutPath + LibName + '.pas', fmCreate);
  1741. Fps.WriteLn('library '+ LibName + ';');
  1742. Fps.WriteLn('{$ifdef fpc} {$mode objfpc} {$H+} {$endif}');
  1743. Fps.WriteLn;
  1744. Fps.WriteLn('uses');
  1745. Fps.WriteLn('{$ifndef FPC} Windows, {$endif} {$ifdef unix} cthreads, {$endif} SysUtils, SyncObjs,', 1);
  1746. s:='';
  1747. for i:=0 to p.Units.Count - 1 do begin
  1748. ProcessRules(p.Units[i]);
  1749. ss:=LowerCase(p.Units[i].Name);
  1750. if (ss ='system') or (ss = 'objpas') or (ss = 'sysutils') or (ss = 'syncobjs') or (ss = 'jni') then
  1751. continue;
  1752. if s <> '' then
  1753. s:=s + ', ';
  1754. s:=s + p.Units[i].Name;
  1755. end;
  1756. Fps.WriteLn(s + ', jni;', 1);
  1757. // Types
  1758. Fps.WriteLn;
  1759. Fps.WriteLn('type');
  1760. Fps.IncI;
  1761. Fps.WriteLn('_JNIString = {$ifdef FPC} unicodestring {$else} widestring {$endif};');
  1762. Fps.WriteLn('{$ifndef FPC} ptruint = cardinal; {$endif}');
  1763. Fps.WriteLn;
  1764. Fps.WriteLn('_TJavaClassInfo = record');
  1765. Fps.WriteLn('ClassRef: JClass;', 1);
  1766. Fps.WriteLn('ObjFieldId: JFieldId;', 1);
  1767. Fps.WriteLn('end;');
  1768. Fps.WriteLn('_PJavaClassInfo = ^_TJavaClassInfo;');
  1769. Fps.DecI;
  1770. Fps.WriteLn;
  1771. d:=TtypeDef.Create(nil, dtType);
  1772. TtypeDef(d).BasicType:=btString;
  1773. Fps.WriteLn(Format('var %s: _TJavaClassInfo;', [GetTypeInfoVar(d)]));
  1774. d.Free;
  1775. // Support functions
  1776. Fps.WriteLn;
  1777. Fps.WriteLn('function _StringFromJString(env: PJNIEnv; s: jstring): _JNIString;');
  1778. Fps.WriteLn('var');
  1779. Fps.WriteLn('p: PJChar;', 1);
  1780. Fps.WriteLn('c: JBoolean;', 1);
  1781. Fps.WriteLn('begin');
  1782. Fps.WriteLn('if s = nil then begin', 1);
  1783. Fps.WriteLn('Result:='''';', 2);
  1784. Fps.WriteLn('exit;', 2);
  1785. Fps.WriteLn('end;', 1);
  1786. Fps.WriteLn('p:=env^^.GetStringChars(env, s, c);', 1);
  1787. Fps.WriteLn('SetString(Result, PWideChar(p), env^^.GetStringLength(env, s));', 1);
  1788. Fps.WriteLn('env^^.ReleaseStringChars(env, s, p);', 1);
  1789. Fps.WriteLn('end;');
  1790. Fps.WriteLn;
  1791. Fps.WriteLn('function _StringToJString(env: PJNIEnv; const s: _JNIString): jstring;');
  1792. Fps.WriteLn('begin');
  1793. Fps.WriteLn('Result:=env^^.NewString(env, PJChar(PWideChar(s)), Length(s));', 1);
  1794. Fps.WriteLn('end;');
  1795. Fps.WriteLn;
  1796. Fps.WriteLn('function _CreateJavaObj(env: PJNIEnv; PasObj: pointer; const ci: _TJavaClassInfo): jobject;');
  1797. Fps.WriteLn('begin');
  1798. Fps.IncI;
  1799. Fps.WriteLn('Result:=nil;');
  1800. Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);');
  1801. Fps.WriteLn('if Result = nil then exit;');
  1802. Fps.WriteLn('env^^.SetLongField(env, Result, ci.ObjFieldId, Int64(ptruint(PasObj)));');
  1803. Fps.DecI;
  1804. Fps.WriteLn('end;');
  1805. Fps.WriteLn;
  1806. Fps.WriteLn('function _GetPasObj(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo; CheckNil: boolean): pointer;');
  1807. Fps.WriteLn('var pasobj: jlong;');
  1808. Fps.WriteLn('begin');
  1809. Fps.IncI;
  1810. Fps.WriteLn('if jobj <> nil then');
  1811. Fps.WriteLn('pasobj:=env^^.GetLongField(env, jobj, ci.ObjFieldId)', 1);
  1812. Fps.WriteLn('else');
  1813. Fps.WriteLn('pasobj:=0;', 1);
  1814. Fps.WriteLn('if CheckNil and (pasobj = 0) then');
  1815. Fps.WriteLn('raise Exception.Create(''Attempt to access a released Pascal object.'');', 1);
  1816. Fps.WriteLn('Result:=pointer(ptruint(pasobj));');
  1817. Fps.DecI;
  1818. Fps.WriteLn('end;');
  1819. Fps.WriteLn;
  1820. Fps.WriteLn('procedure _HandleJNIException(env: PJNIEnv);');
  1821. Fps.WriteLn('begin');
  1822. Fps.WriteLn('env^^.ThrowNew(env, env^^.FindClass(env, ''java/lang/Exception''), PAnsiChar(Utf8Encode(Exception(ExceptObject).Message)));', 1);
  1823. Fps.WriteLn('end;');
  1824. Fps.WriteLn;
  1825. Fps.WriteLn('procedure _RaiseVarParamException(const VarName: string);');
  1826. Fps.WriteLn('begin');
  1827. Fps.WriteLn('raise Exception.CreateFmt(''An array with only single element must be passed as parameter "%s".'', [VarName]);', 1);
  1828. Fps.WriteLn('end;');
  1829. Fps.WriteLn;
  1830. Fps.WriteLn('function _AllocMemory(env: PJNIEnv; jobj: jobject; size: jint): jlong;');
  1831. Fps.WriteLn('var p: pointer;');
  1832. Fps.WriteLn('begin');
  1833. Fps.WriteLn('GetMem(p, size);', 1);
  1834. Fps.WriteLn('FillChar(p^, size, 0);', 1);
  1835. Fps.WriteLn('Result:=ptruint(p);', 1);
  1836. Fps.WriteLn('end;');
  1837. // Method pointer support
  1838. Fps.WriteLn;
  1839. Fps.WriteLn('type');
  1840. Fps.IncI;
  1841. Fps.WriteLn('_TMethodPtrInfo = class');
  1842. Fps.IncI;
  1843. Fps.WriteLn('Obj: JObject;');
  1844. Fps.WriteLn('MethodId: JMethodID;');
  1845. Fps.WriteLn('Index, RefCnt: integer;');
  1846. Fps.WriteLn('RealMethod: TMethod;');
  1847. Fps.WriteLn('constructor Create(env: PJNIEnv; JavaObj: JObject; const AMethodName, AMethodSig: ansistring);');
  1848. Fps.WriteLn('procedure Release(env: PJNIEnv);');
  1849. Fps.DecI;
  1850. Fps.WriteLn('end;');
  1851. Fps.DecI;
  1852. Fps.WriteLn;
  1853. Fps.WriteLn('var _MethodPointers: array of _TMethodPtrInfo;');
  1854. Fps.WriteLn('var _MethodPointersCS: TCriticalSection;');
  1855. Fps.WriteLn;
  1856. Fps.WriteLn('constructor _TMethodPtrInfo.Create(env: PJNIEnv; JavaObj: JObject; const AMethodName, AMethodSig: ansistring);');
  1857. Fps.WriteLn('var c: JClass;');
  1858. Fps.WriteLn('begin');
  1859. Fps.IncI;
  1860. Fps.WriteLn('RefCnt:=1;');
  1861. Fps.WriteLn('if (JavaObj = nil) or (AMethodName = '''') then exit;');
  1862. Fps.WriteLn('c:=env^^.GetObjectClass(env, JavaObj);');
  1863. Fps.WriteLn('if c = nil then exit;');
  1864. Fps.WriteLn('MethodId:=env^^.GetMethodID(env, c, PAnsiChar(AMethodName), PAnsiChar(AMethodSig));');
  1865. Fps.WriteLn('if MethodId = nil then raise Exception.CreateFmt(''Method "%s" does not exist or has wrong parameters.'', [AMethodName]);');
  1866. Fps.WriteLn('Obj:=env^^.NewGlobalRef(env, JavaObj);');
  1867. Fps.WriteLn('_MethodPointersCS.Enter;');
  1868. Fps.WriteLn('try');
  1869. Fps.IncI;
  1870. Fps.WriteLn('Index:=Length(_MethodPointers) + 1;');
  1871. Fps.WriteLn(Format('if Index > %d then raise Exception.Create(''Too many method pointers.'');', [MaxMethodPointers]));
  1872. Fps.WriteLn('SetLength(_MethodPointers, Index);');
  1873. Fps.WriteLn('_MethodPointers[Index - 1]:=Self;');
  1874. Fps.WriteLn('finally', -1);
  1875. Fps.WriteLn('_MethodPointersCS.Leave;');
  1876. Fps.DecI;
  1877. Fps.WriteLn('end;');
  1878. Fps.DecI;
  1879. Fps.WriteLn('end;');
  1880. Fps.WriteLn;
  1881. Fps.WriteLn('procedure _TMethodPtrInfo.Release(env: PJNIEnv);');
  1882. Fps.WriteLn('var i: integer;');
  1883. Fps.WriteLn('begin');
  1884. Fps.IncI;
  1885. Fps.WriteLn('i:=InterlockedDecrement(RefCnt);');
  1886. Fps.WriteLn('if i <> 0 then exit;');
  1887. Fps.WriteLn('if Index > 0 then begin');
  1888. Fps.IncI;
  1889. Fps.WriteLn('_MethodPointersCS.Enter;');
  1890. Fps.WriteLn('try');
  1891. Fps.IncI;
  1892. Fps.WriteLn('Dec(Index);');
  1893. Fps.WriteLn('_MethodPointers[Index]:=nil;');
  1894. Fps.WriteLn('Index:=Length(_MethodPointers);');
  1895. Fps.WriteLn('while (Index > 0) and (_MethodPointers[Index] = nil) do Dec(Index);');
  1896. Fps.WriteLn('SetLength(_MethodPointers, Index + 1);');
  1897. Fps.WriteLn('finally', -1);
  1898. Fps.WriteLn('_MethodPointersCS.Leave;');
  1899. Fps.DecI;
  1900. Fps.WriteLn('end;');
  1901. Fps.WriteLn('env^^.DeleteGlobalRef(env, Obj);');
  1902. Fps.DecI;
  1903. Fps.WriteLn('end;');
  1904. Fps.WriteLn('Self.Destroy;');
  1905. Fps.DecI;
  1906. Fps.WriteLn('end;');
  1907. Fps.WriteLn;
  1908. Fps.WriteLn('procedure _RefMethodPtr(env: PJNIEnv; const m: TMethod; AddRef: boolean);');
  1909. Fps.WriteLn('var i: integer;');
  1910. Fps.WriteLn('begin');
  1911. Fps.IncI;
  1912. Fps.WriteLn('i:=-integer(ptruint(m.Data));');
  1913. Fps.WriteLn(Format('if (i < 1) or (i > %d) then exit;', [MaxMethodPointers]));
  1914. Fps.WriteLn('_MethodPointersCS.Enter;');
  1915. Fps.WriteLn('try');
  1916. Fps.IncI;
  1917. Fps.WriteLn('with _MethodPointers[i - 1] do');
  1918. Fps.WriteLn('if AddRef then InterlockedIncrement(RefCnt) else Release(env);', 1);
  1919. Fps.WriteLn('finally', -1);
  1920. Fps.WriteLn('_MethodPointersCS.Leave;');
  1921. Fps.DecI;
  1922. Fps.WriteLn('end;');
  1923. Fps.DecI;
  1924. Fps.WriteLn('end;');
  1925. Fps.WriteLn;
  1926. Fps.WriteLn('function _CreateMethodPtrObject(env: PJNIEnv; const m: TMethod; const ci: _TJavaClassInfo): jobject;');
  1927. Fps.WriteLn('var i: integer;');
  1928. Fps.WriteLn('var mpi: _TMethodPtrInfo;');
  1929. Fps.WriteLn('begin');
  1930. Fps.IncI;
  1931. Fps.WriteLn('_MethodPointersCS.Enter;');
  1932. Fps.WriteLn('try');
  1933. Fps.IncI;
  1934. Fps.WriteLn('i:=-integer(ptruint(m.Data));');
  1935. Fps.WriteLn(Format('if (i > 0) and (i <= %d) then begin', [MaxMethodPointers]));
  1936. Fps.WriteLn('mpi:=_MethodPointers[i - 1];', 1);
  1937. Fps.WriteLn('InterlockedIncrement(mpi.RefCnt);', 1);
  1938. Fps.WriteLn('end');
  1939. Fps.WriteLn('else begin');
  1940. Fps.WriteLn('mpi:=_TMethodPtrInfo.Create(env, nil, '''', '''');', 1);
  1941. Fps.WriteLn('mpi.RealMethod:=m;', 1);
  1942. Fps.WriteLn('end;');
  1943. Fps.WriteLn('finally', -1);
  1944. Fps.WriteLn('_MethodPointersCS.Leave;');
  1945. Fps.DecI;
  1946. Fps.WriteLn('end;');
  1947. Fps.WriteLn('Result:=_CreateJavaObj(env, pointer(mpi), ci);');
  1948. Fps.DecI;
  1949. Fps.WriteLn('end;');
  1950. // Set support
  1951. Fps.WriteLn;
  1952. Fps.WriteLn('function _GetIntObjValue(env: PJNIEnv; jobj: jobject; const ci: _TJavaClassInfo): longint;');
  1953. Fps.WriteLn('begin');
  1954. Fps.IncI;
  1955. Fps.WriteLn('if jobj = nil then raise Exception.Create(''Attempt to access a NULL set.'');');
  1956. Fps.WriteLn('Result:=env^^.GetIntField(env, jobj, ci.ObjFieldId);');
  1957. Fps.DecI;
  1958. Fps.WriteLn('end;');
  1959. Fps.WriteLn;
  1960. Fps.WriteLn('function _CreateIntObj(env: PJNIEnv; Value: longint; const ci: _TJavaClassInfo): jobject;');
  1961. Fps.WriteLn('begin');
  1962. Fps.IncI;
  1963. Fps.WriteLn('Result:=nil;');
  1964. Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);');
  1965. Fps.WriteLn('if Result = nil then exit;');
  1966. Fps.WriteLn('env^^.SetIntField(env, Result, ci.ObjFieldId, Value);');
  1967. Fps.DecI;
  1968. Fps.WriteLn('end;');
  1969. // Write units
  1970. for i:=0 to p.Units.Count - 1 do
  1971. with TUnitDef(p.Units[i]) do begin
  1972. WriteUnit(TUnitDef(p.Units[i]));
  1973. end;
  1974. WriteOnLoad;
  1975. Fps.WriteLn;
  1976. Fps.WriteLn('begin');
  1977. Fps.WriteLn('IsMultiThread:=True;', 1);
  1978. Fps.WriteLn('_MethodPointersCS:=TCriticalSection.Create;', 1);
  1979. Fps.WriteLn('end.');
  1980. finally
  1981. Fps.Free;
  1982. p.Free;
  1983. end;
  1984. end;
  1985. end.