fpcres.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. {
  2. FPCRes - Free Pascal Resource Converter
  3. Part of the Free Pascal distribution
  4. Copyright (C) 2008 by Giulio Bernardi
  5. See the file COPYING, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. { Note: This program is not the old fpcres by Simon Kissel }
  12. program fpcres;
  13. {$MODE OBJFPC} {$H+}
  14. uses
  15. SysUtils, Classes, paramparser, target, msghandler, sourcehandler,
  16. closablefilestream, resource,
  17. //readers
  18. resreader, coffreader, winpeimagereader, elfreader, machoreader,
  19. externalreader, dfmreader, tlbreader,
  20. //writers
  21. reswriter, coffwriter, xcoffwriter, elfwriter, machowriter, externalwriter,
  22. //misc
  23. elfconsts, cofftypes, machotypes, externaltypes
  24. ;
  25. const
  26. halt_no_err = 0;
  27. halt_param_err = 1;
  28. halt_read_err = 2;
  29. halt_write_err = 3;
  30. progname = 'fpcres';
  31. progversion = '2.0'; //to distinguish from the old fpcres
  32. fpcversion = {$INCLUDE %FPCVERSION%};
  33. host_arch = {$INCLUDE %FPCTARGETCPU%};
  34. host_os = {$INCLUDE %FPCTARGETOS%};
  35. build_date = {$INCLUDE %DATE%};
  36. var
  37. params : TParameters = nil;
  38. resources : TResources = nil;
  39. sourcefiles : TSourceFiles = nil;
  40. procedure ShowVersion;
  41. begin
  42. writeln(progname+' - resource file converter, version '+progversion+' ['+build_date+'], FPC '+fpcversion);
  43. writeln('Host platform: '+host_os+' - '+host_arch);
  44. writeln('Copyright (c) 2008 by Giulio Bernardi.');
  45. end;
  46. procedure ShowHelp;
  47. begin
  48. ShowVersion;
  49. writeln('Syntax: '+progname+' [options] <inputfile> [<inputfile>...] [-o <outputfile>]');
  50. writeln;
  51. writeln('Options:');
  52. writeln(' --help, -h, -? Show this screen.');
  53. writeln(' --version, -V Show program version.');
  54. writeln(' --verbose, -v Be verbose.');
  55. writeln(' --input, -i <x> Ignored for compatibility.');
  56. writeln(' --output, -o <x> Set the output file name.');
  57. writeln(' -of <format> Set the output file format. Supported formats:');
  58. writeln(' res, elf, coff, mach-o, external');
  59. writeln(' --arch, -a <name> Set object file architecture. Supported architectures:');
  60. writeln(' i386, x86_64, arm (coff)');
  61. writeln(' i386, x86_64, powerpc, powerpc64, arm, armeb, m68k,');
  62. writeln(' sparc, alpha, ia64, mips, mipsel (elf)');
  63. writeln(' i386, x86_64, powerpc, powerpc64, arm, aarch64 (mach-o)');
  64. writeln(' bigendian, littleendian (external)');
  65. writeln(' --subarch, -s <name> Set object file sub-architecture. Supported values:');
  66. writeln(' arm: all, v4t, v6, v5tej, xscale, v7');
  67. writeln(' other architectures: all');
  68. writeln(' @<file> Read more options from file <file>');
  69. writeln('Default output target: '+TargetToStr(currenttarget));
  70. end;
  71. const
  72. SOutputFileAlreadySet = 'Output file name already set.';
  73. SUnknownParameter = 'Unknown parameter ''%s''';
  74. SArgumentMissing = 'Argument missing for option ''%s''';
  75. SUnknownObjFormat = 'Unknown file format ''%s''';
  76. SUnknownMachine = 'Unknown architecture ''%s''';
  77. SFormatArchMismatch = 'Architecture %s is not available for %s format';
  78. SNoInputFiles = 'No input files';
  79. SNoOutputFile = 'No output file name specified';
  80. SCannotReadConfFile ='Can''t read config file ''%s''';
  81. SCantOpenFile = 'Can''t open file ''%s''';
  82. SUnknownInputFormat = 'No known file format detected for file ''%s''';
  83. SCantCreateFile = 'Can''t create file ''%s''';
  84. function GetCurrentTimeMsec : longint;
  85. var h,m,s,ms : word;
  86. begin
  87. DecodeTime(Time,h,m,s,ms);
  88. Result:=h*3600*1000 + m*60*1000 + s*1000 + ms;
  89. end;
  90. procedure CheckTarget;
  91. begin
  92. //if user explicitally set a format, use it
  93. if params.Target.objformat<>ofNone then
  94. CurrentTarget.objformat:=params.Target.objformat;
  95. //if no machine was specified, check if current is ok for this format,
  96. //otherwise pick the default one for that format
  97. if params.Target.machine=mtNone then
  98. begin
  99. if not (CurrentTarget.machine in ObjFormats[CurrentTarget.objformat].machines) then
  100. begin
  101. CurrentTarget.machine:=GetDefaultMachineForFormat(CurrentTarget.objformat);
  102. CurrentTarget.submachine:=GetDefaultSubMachineForMachine(currentTarget.machine);
  103. end
  104. end
  105. else
  106. begin
  107. CurrentTarget.machine:=params.Target.machine;
  108. CurrentTarget.submachine:=params.Target.submachine;
  109. end;
  110. if not (CurrentTarget.machine in ObjFormats[CurrentTarget.objformat].machines) then
  111. begin
  112. Messages.DoError(Format(SFormatArchMismatch,[
  113. MachineToStr(CurrentTarget.machine),ObjFormatToStr(CurrentTarget.objformat)]));
  114. halt(halt_param_err);
  115. end;
  116. Messages.DoVerbose('target set to '+TargetToStr(CurrentTarget));
  117. end;
  118. procedure CheckInputFiles;
  119. begin
  120. if params.InputFiles.Count=0 then
  121. begin
  122. Messages.DoError(SNoInputFiles);
  123. halt(halt_param_err);
  124. end;
  125. end;
  126. procedure CheckOutputFile;
  127. var tmp : string;
  128. begin
  129. if params.OutputFile<>'' then exit;
  130. if params.InputFiles.Count>1 then
  131. begin
  132. Messages.DoError(SNoOutputFile);
  133. halt(halt_param_err);
  134. end;
  135. tmp:=ChangeFileExt(ExtractFileName(params.InputFiles[0]),
  136. ObjFormats[CurrentTarget.objformat].ext);
  137. if lowercase(tmp)=lowercase(params.InputFiles[0]) then
  138. tmp:=tmp+ObjFormats[CurrentTarget.objformat].ext;
  139. params.OutputFile:=tmp;
  140. end;
  141. procedure ParseParams;
  142. var msg : string;
  143. begin
  144. Messages.DoVerbose('parsing command line parameters');
  145. msg:='';
  146. if ParamCount = 0 then
  147. begin
  148. ShowHelp;
  149. halt(halt_no_err);
  150. end;
  151. params:=TParameters.Create;
  152. try
  153. params.Parse;
  154. except
  155. on e : EOutputFileAlreadySetException do msg:=SOutputFileAlreadySet;
  156. on e : EUnknownParameterException do msg:=Format(SUnknownParameter,[e.Message]);
  157. on e : EArgumentMissingException do msg:=Format(SArgumentMissing,[e.Message]);
  158. on e : EUnknownObjFormatException do msg:=Format(SUnknownObjFormat,[e.Message]);
  159. on e : EUnknownMachineException do msg:=Format(SUnknownMachine,[e.Message]);
  160. on e : ECannotReadConfFile do msg:=Format(SCannotReadConfFile,[e.Message]);
  161. end;
  162. Messages.Verbose:=params.Verbose;
  163. if msg<>'' then
  164. begin
  165. Messages.DoError(msg);
  166. halt(halt_param_err);
  167. end;
  168. if params.Version then
  169. begin
  170. ShowVersion;
  171. halt(halt_no_err);
  172. end;
  173. if params.Help then
  174. begin
  175. ShowHelp;
  176. halt(halt_no_err);
  177. end;
  178. CheckTarget;
  179. CheckInputFiles;
  180. CheckOutputFile;
  181. Messages.DoVerbose('finished parsing command line parameters');
  182. end;
  183. procedure LoadSourceFiles;
  184. var msg : string;
  185. begin
  186. msg:='';
  187. resources:=TResources.Create;
  188. sourcefiles:=TSourceFiles.Create;
  189. sourcefiles.FileList.AddStrings(params.InputFiles);
  190. try
  191. sourcefiles.Load(resources);
  192. except
  193. on e : ECantOpenFileException do msg:=Format(SCantOpenFile,[e.Message]);
  194. on e : EUnknownInputFormatException do msg:=Format(SUnknownInputFormat,[e.Message]);
  195. on e : Exception do
  196. begin
  197. if e.Message='' then msg:=e.ClassName
  198. else msg:=e.Message;
  199. end;
  200. end;
  201. if msg<>'' then
  202. begin
  203. Messages.DoError(msg);
  204. halt(halt_read_err);
  205. end;
  206. end;
  207. function SetUpResWriter : TResResourceWriter;
  208. begin
  209. Result:=TResResourceWriter.Create;
  210. end;
  211. function SetUpElfWriter : TElfResourceWriter;
  212. begin
  213. Result:=TElfResourceWriter.Create;
  214. case CurrentTarget.machine of
  215. // mtnone :
  216. mti386 : Result.MachineType:=emti386;
  217. mtx86_64 : Result.MachineType:=emtx86_64;
  218. mtppc : Result.MachineType:=emtppc;
  219. mtppc64 : Result.MachineType:=emtppc64;
  220. mtarm : Result.MachineType:=emtarm;
  221. mtarmeb : Result.MachineType:=emtarmeb;
  222. mtm68k : Result.MachineType:=emtm68k;
  223. mtsparc : Result.MachineType:=emtsparc;
  224. mtalpha : Result.MachineType:=emtalpha;
  225. mtia64 : Result.MachineType:=emtia64;
  226. mtmips : Result.MachineType:=emtmips;
  227. mtmipsel : Result.MachineType:=emtmipsel;
  228. mtppc64le : Result.MachineType:=emtppc64le;
  229. mtaarch64 : Result.MachineType:=emtaarch64;
  230. end;
  231. end;
  232. function SetUpCoffWriter : TCoffResourceWriter;
  233. begin
  234. Result:=TCoffResourceWriter.Create;
  235. case CurrentTarget.machine of
  236. // mtnone :
  237. mti386 : Result.MachineType:=cmti386;
  238. mtarm : Result.MachineType:=cmtarm;
  239. mtx86_64 : Result.MachineType:=cmtx8664;
  240. end;
  241. end;
  242. function SetUpXCoffWriter : TCoffResourceWriter;
  243. begin
  244. Result:=TXCoffResourceWriter.Create;
  245. case CurrentTarget.machine of
  246. // mtnone :
  247. mtppc : Result.MachineType:=cmtppc32aix;
  248. // mtppc64 : Result.MachineType:=cmtppc64aix;
  249. end;
  250. end;
  251. function SetUpMachOWriter : TMachOResourceWriter;
  252. const
  253. ArmSubMachine2MachOSubMachine: array[TSubMachineTypeArm] of TMachOSubMachineTypeArm =
  254. (msmarm_all,msmarm_v4t,msmarm_v6,msmarm_v5tej,msmarm_xscale,msmarm_v7);
  255. var
  256. MachOSubMachineType: TMachoSubMachineType;
  257. begin
  258. Result:=TMachOResourceWriter.Create;
  259. case CurrentTarget.machine of
  260. // mtnone :
  261. mti386 :
  262. begin
  263. Result.MachineType:=mmti386;
  264. MachOSubMachineType.f386SubType:=msm386_all;
  265. end;
  266. mtx86_64 :
  267. begin
  268. Result.MachineType:=mmtx86_64;
  269. MachOSubMachineType.fX64SubType:=msmx64_all;
  270. end;
  271. mtppc :
  272. begin
  273. Result.MachineType:=mmtpowerpc;
  274. MachOSubMachineType.fPpcSubType:=msmppc_all;
  275. end;
  276. mtppc64 :
  277. begin
  278. Result.MachineType:=mmtpowerpc64;
  279. MachOSubMachineType.fPpc64SubType:=msmppc64_all;
  280. end;
  281. mtarm :
  282. begin
  283. Result.MachineType:=mmtarm;
  284. MachOSubMachineType.fArmSubType:=ArmSubMachine2MachOSubMachine[CurrentTarget.submachine.subarm];
  285. end;
  286. mtaarch64 :
  287. begin
  288. Result.MachineType:=mmtarm64;
  289. MachOSubMachineType.fArm64SubType:=msmaarch64_all;
  290. end;
  291. end;
  292. Result.SubMachineType:=MachOSubMachineType;
  293. end;
  294. function SetUpExternalWriter : TExternalResourceWriter;
  295. begin
  296. Result:=TExternalResourceWriter.Create;
  297. case CurrentTarget.machine of
  298. // mtnone :
  299. mtBigEndian : Result.Endianess:=EXT_ENDIAN_BIG;
  300. mtLittleEndian : Result.Endianess:=EXT_ENDIAN_LITTLE;
  301. end;
  302. end;
  303. procedure WriteOutputFile;
  304. var aStream : TClosableFileStream;
  305. aWriter : TAbstractResourceWriter;
  306. msg : string;
  307. begin
  308. Messages.DoVerbose(Format('Trying to create output file %s...',[params.OutputFile]));
  309. try
  310. aStream:=TClosableFileStream.Create(params.OutputFile,fmCreate or fmShareDenyWrite);
  311. except
  312. Messages.DoError(Format(SCantCreateFile,[params.OutputFile]));
  313. halt(halt_write_err);
  314. end;
  315. try
  316. Messages.DoVerbose('Setting up resource writer...');
  317. case CurrentTarget.objformat of
  318. ofRes : aWriter:=SetUpResWriter;
  319. ofElf : aWriter:=SetUpElfWriter;
  320. ofCoff : aWriter:=SetUpCoffWriter;
  321. ofXCoff : aWriter:=SetUpXCoffWriter;
  322. ofMachO : aWriter:=SetUpMachOWriter;
  323. ofExt : aWriter:=SetUpExternalWriter;
  324. end;
  325. try
  326. Messages.DoVerbose(Format('Writing output file %s...',[params.OutputFile]));
  327. try
  328. resources.WriteToStream(aStream,aWriter);
  329. except
  330. on e : Exception do
  331. begin
  332. if e.Message='' then msg:=e.ClassName
  333. else msg:=e.Message;
  334. Messages.DoError(msg);
  335. halt(halt_write_err);
  336. end;
  337. end;
  338. Messages.DoVerbose(Format('Output file %s written',[params.OutputFile]));
  339. finally
  340. aWriter.Free;
  341. end;
  342. finally
  343. aStream.Free;
  344. end;
  345. end;
  346. procedure Cleanup;
  347. begin
  348. Messages.DoVerbose('Cleaning up');
  349. if Resources<>nil then Resources.Free;
  350. if SourceFiles<>nil then SourceFiles.Free;
  351. if Params<>nil then Params.Free;
  352. end;
  353. var before, elapsed : longint;
  354. begin
  355. try
  356. before:=GetCurrentTimeMsec;
  357. ParseParams;
  358. LoadSourceFiles;
  359. WriteOutputFile;
  360. elapsed:=GetCurrentTimeMsec-before;
  361. if elapsed<0 then elapsed:=24*3600*1000 + elapsed;
  362. Messages.DoVerbose(Format('Time elapsed: %d.%d seconds',[elapsed div 1000,(elapsed mod 1000) div 10]));
  363. finally
  364. Cleanup;
  365. end;
  366. end.