fpcreslipo.pp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. {
  2. FPCResLipo - Free Pascal External Resource Thinner
  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. program fpcreslipo;
  12. {$MODE OBJFPC} {$H+}
  13. uses
  14. SysUtils, Classes, paramparser, msghandler, sourcehandler,
  15. resource, externalreader, externalwriter;
  16. const
  17. halt_no_err = 0;
  18. halt_param_err = 1;
  19. halt_read_err = 2;
  20. halt_write_err = 3;
  21. progname = 'fpcreslipo';
  22. progversion = '1.0';
  23. fpcversion = {$INCLUDE %FPCVERSION%};
  24. host_arch = {$INCLUDE %FPCTARGETCPU%};
  25. host_os = {$INCLUDE %FPCTARGETOS%};
  26. build_date = {$INCLUDE %DATE%};
  27. var
  28. params : TParameters = nil;
  29. sourcefiles : TSourceFiles = nil;
  30. outResources : TResources = nil;
  31. procedure ShowVersion;
  32. begin
  33. writeln(progname+' - external resource file thinner, version '+progversion+' ['+build_date+'], FPC '+fpcversion);
  34. writeln('Host platform: '+host_os+' - '+host_arch);
  35. writeln('Copyright (c) 2008 by Giulio Bernardi.');
  36. end;
  37. procedure ShowHelp;
  38. begin
  39. ShowVersion;
  40. writeln('Syntax: '+progname+' [options] <inputfile> [<inputfile>...] -o <outputfile>');
  41. writeln;
  42. writeln('Options:');
  43. writeln(' --help, -h, -? Show this screen.');
  44. writeln(' --version, -V Show program version.');
  45. writeln(' --verbose, -v Be verbose.');
  46. writeln(' --output, -o <x> Set the output file name.');
  47. writeln(' --endian, -e <x> Set shared file endianess (big, little)');
  48. writeln(' default is big');
  49. writeln;
  50. writeln('Example:');
  51. writeln(' '+progname+' myprog.i386.fpcres myprog.powerpc.fpcres -o myprog.fpcres');
  52. writeln;
  53. writeln(' strips common resources from the two input files and puts them in the');
  54. writeln(' output file');
  55. end;
  56. const
  57. SOutputFileAlreadySet = 'Output file name already set.';
  58. SUnknownParameter = 'Unknown parameter ''%s''';
  59. SArgumentMissing = 'Argument missing for option ''%s''';
  60. SUnknownEndianess = 'Unknown endianess ''%s''';
  61. SNoInputFiles = 'No input files';
  62. STooFewInputFiles = 'At least two input files must be specified';
  63. SNoOutputFile = 'No output file name specified';
  64. SCantOpenFile = 'Can''t open file ''%s''';
  65. SUnknownInputFormat = 'No known file format detected for file ''%s''';
  66. SCantCreateFile = 'Can''t create file ''%s''';
  67. function GetCurrentTimeMsec : longint;
  68. var h,m,s,ms : word;
  69. begin
  70. DecodeTime(Time,h,m,s,ms);
  71. Result:=h*3600*1000 + m*60*1000 + s*1000 + ms;
  72. end;
  73. procedure CheckInputFiles;
  74. begin
  75. if params.InputFiles.Count<2 then
  76. begin
  77. case params.InputFiles.Count of
  78. 0 : Messages.DoError(SNoInputFiles);
  79. 1 : Messages.DoError(STooFewInputFiles);
  80. end;
  81. halt(halt_param_err);
  82. end;
  83. end;
  84. procedure CheckOutputFile;
  85. begin
  86. if params.OutputFile<>'' then exit;
  87. Messages.DoError(SNoOutputFile);
  88. halt(halt_param_err);
  89. end;
  90. procedure ParseParams;
  91. var msg : string;
  92. begin
  93. Messages.DoVerbose('parsing command line parameters');
  94. msg:='';
  95. if ParamCount = 0 then
  96. begin
  97. ShowHelp;
  98. halt(halt_no_err);
  99. end;
  100. params:=TParameters.Create;
  101. try
  102. params.Parse;
  103. except
  104. on e : EOutputFileAlreadySetException do msg:=SOutputFileAlreadySet;
  105. on e : EUnknownParameterException do msg:=Format(SUnknownParameter,[e.Message]);
  106. on e : EArgumentMissingException do msg:=Format(SArgumentMissing,[e.Message]);
  107. on e : EUnknownEndianessException do msg:=Format(SUnknownEndianess,[e.Message]);
  108. end;
  109. Messages.Verbose:=params.Verbose;
  110. if msg<>'' then
  111. begin
  112. Messages.DoError(msg);
  113. halt(halt_param_err);
  114. end;
  115. if params.Version then
  116. begin
  117. ShowVersion;
  118. halt(halt_no_err);
  119. end;
  120. if params.Help then
  121. begin
  122. ShowHelp;
  123. halt(halt_no_err);
  124. end;
  125. CheckInputFiles;
  126. CheckOutputFile;
  127. Messages.DoVerbose('finished parsing command line parameters');
  128. end;
  129. procedure LoadSourceFiles;
  130. var msg : string;
  131. i : integer;
  132. begin
  133. msg:='';
  134. sourcefiles:=TSourceFiles.Create;
  135. try
  136. for i:=0 to params.InputFiles.Count-1 do
  137. sourcefiles.NewSourceFile(params.InputFiles[i]);
  138. except
  139. on e : ECantOpenFileException do msg:=Format(SCantOpenFile,[e.Message]);
  140. on e : EUnknownInputFormatException do msg:=Format(SUnknownInputFormat,[e.Message]);
  141. on e : Exception do
  142. begin
  143. if e.Message='' then msg:=e.ClassName
  144. else msg:=e.Message;
  145. end;
  146. end;
  147. if msg<>'' then
  148. begin
  149. Messages.DoError(msg);
  150. halt(halt_read_err);
  151. end;
  152. end;
  153. procedure ProcessFiles;
  154. begin
  155. Messages.DoVerbose('processing input files...');
  156. outResources:=TResources.Create;
  157. sourcefiles.Process(outResources);
  158. Messages.DoVerbose('input files processed.');
  159. end;
  160. function WriteOutputFile : boolean;
  161. var aStream : TFileStream;
  162. aWriter : TExternalResourceWriter;
  163. msg : string;
  164. begin
  165. if outResources.Count=0 then
  166. begin
  167. Result:=false;
  168. Messages.DoVerbose('Nothing to do');
  169. exit;
  170. end;
  171. Result:=true;
  172. Messages.DoVerbose(Format('Trying to create file %s...',[params.OutputFile]));
  173. try
  174. aStream:=TFileStream.Create(params.OutputFile,fmCreate or fmShareDenyWrite);
  175. except
  176. Messages.DoError(Format(SCantCreateFile,[params.OutputFile]));
  177. halt(halt_write_err);
  178. end;
  179. try
  180. aWriter:=TExternalResourceWriter.Create;
  181. aWriter.Endianess:=params.Endianess;
  182. try
  183. try
  184. outResources.WriteToStream(aStream,aWriter);
  185. except
  186. on e : Exception do
  187. begin
  188. if e.Message='' then msg:=e.ClassName
  189. else msg:=e.Message;
  190. Messages.DoError(msg);
  191. halt(halt_write_err);
  192. end;
  193. end;
  194. Messages.DoVerbose(Format('%d resources written.',[outResources.Count]));
  195. Messages.DoVerbose(Format('File %s written',[params.OutputFile]));
  196. finally
  197. aWriter.Free;
  198. end;
  199. finally
  200. aStream.Free;
  201. end;
  202. FreeAndNil(outResources);
  203. end;
  204. procedure UpdateFiles;
  205. var msg : string;
  206. begin
  207. try
  208. sourcefiles.Update;
  209. except
  210. on e : ECantCreateFileException do msg:=Format(SCantCreateFile,[e.Message]);
  211. on e : Exception do
  212. begin
  213. if e.Message='' then msg:=e.ClassName
  214. else msg:=e.Message;
  215. end;
  216. end;
  217. if msg<>'' then
  218. begin
  219. Messages.DoError(msg);
  220. halt(halt_write_err);
  221. end;
  222. end;
  223. procedure Cleanup;
  224. begin
  225. Messages.DoVerbose('Cleaning up');
  226. if OutResources<>nil then OutResources.Free;
  227. if SourceFiles<>nil then SourceFiles.Free;
  228. if Params<>nil then Params.Free;
  229. end;
  230. var before, elapsed : longint;
  231. begin
  232. try
  233. before:=GetCurrentTimeMsec;
  234. ParseParams;
  235. LoadSourceFiles;
  236. ProcessFiles;
  237. if WriteOutputFile then
  238. UpdateFiles;
  239. elapsed:=GetCurrentTimeMsec-before;
  240. if elapsed<0 then elapsed:=24*3600*1000 + elapsed;
  241. Messages.DoVerbose(Format('Time elapsed: %d.%d seconds',[elapsed div 1000,(elapsed mod 1000) div 10]));
  242. finally
  243. Cleanup;
  244. end;
  245. end.