2
0

restool.lpr 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. program restool;
  2. {$R program.res}
  3. uses
  4. custapp, sysutils, classes, resource, elfreader, resreader, coffreader, machoreader, dfmreader,
  5. bitmapresource, stringtableresource, versionresource, groupiconresource, groupcursorresource,
  6. acceleratorsresource, groupresource;
  7. Type
  8. TRunMode = (rmList,rmExtract);
  9. { TRestool }
  10. TRestool = Class(TCustomApplication)
  11. private
  12. FRunMode : TRunMode;
  13. FResfile : TResources;
  14. FinputFile : String;
  15. FDestFile : String;
  16. FResName,FResType : String;
  17. FResIndex : integer;
  18. FStructured : Boolean;
  19. procedure DumpAllResources(var aDest: Text);
  20. procedure DumpResource(var aDest: Text; Res: TAbstractResource; Idx: integer; const Prefix: String='');
  21. function ProcessOptions: Boolean;
  22. procedure Usage(const aErr: String);
  23. procedure DumpOwnedResource(var aDest: Text; aOwner: TAbstractResource; const Prefix: String);
  24. procedure WriteResource(Res: TAbstractResource; const aDestFile: String);
  25. Protected
  26. procedure doRun; override;
  27. procedure dumpresourcefile(const aFileName: String; var aDest: Text);
  28. procedure ExtractResource(const aDestFile: String; aIdx: Integer);
  29. procedure ExtractResource(const aDestFile, aType, aName: String);
  30. public
  31. constructor Create(aOwner : TComponent); override;
  32. destructor destroy; override;
  33. class function restypename(aID: Integer; AddNumeric: Boolean): string;
  34. class function KnownTypeNameToID(aType : String) : Integer;
  35. end;
  36. constructor TRestool.Create(aOwner: TComponent);
  37. begin
  38. inherited Create(aOwner);
  39. FResfile:=TResources.Create;
  40. end;
  41. destructor TRestool.destroy;
  42. begin
  43. FreeAndNil(FResfile);
  44. inherited destroy;
  45. end;
  46. class function TRestool.restypename(aID : Integer; AddNumeric : Boolean) : string;
  47. begin
  48. case aID of
  49. RT_CURSOR : Result:='RT_CURSOR'; //Hardware-dependent cursor resource.
  50. RT_BITMAP : Result:='RT_BITMAP'; //Bitmap resource.
  51. RT_ICON : Result:='RT_ICON'; //Hardware-dependent icon resource.
  52. RT_MENU : Result:='RT_MENU'; //Menu resource.
  53. RT_DIALOG : Result:='RT_DIALOG'; //Dialog box.
  54. RT_STRING : Result:='RT_STRING'; //String-table entry.
  55. RT_FONTDIR : Result:='RT_FONTDIR'; //Font directory resource.
  56. RT_FONT : Result:='RT_FONT'; //Font resource.
  57. RT_ACCELERATOR : Result:='RT_ACCELERATOR'; //Accelerator table.
  58. RT_RCDATA : Result:='RT_RCDATA'; //Application-defined resource (raw data).
  59. RT_MESSAGETABLE : Result:='RT_MESSAGETABLE'; //Message-table entry.
  60. RT_GROUP_CURSOR : Result:='RT_GROUP_CURSOR'; //Hardware-independent cursor resource.
  61. RT_GROUP_ICON : Result:='RT_GROUP_ICON'; //Hardware-independent icon resource.
  62. RT_VERSION : Result:='RT_VERSION'; //Version resource.
  63. RT_DLGINCLUDE : Result:='RT_DLGINCLUDE'; //Never present in compiled form
  64. RT_PLUGPLAY : Result:='RT_PLUGPLAY'; //Plug and Play resource.
  65. RT_VXD : Result:='RT_VXD'; //VXD.
  66. RT_ANICURSOR : Result:='RT_ANICURSOR'; //Animated cursor.
  67. RT_ANIICON : Result:='RT_ANIICON'; //Animated icon.
  68. RT_HTML : Result:='RT_HTML'; //HTML.
  69. RT_MANIFEST : Result:='RT_MANIFEST'; //Microsoft Windows XP: Side-by-Side Assembly XML Manifest.
  70. RT_DLGINIT : Result:='RT_DLGINIT'; //Never present in compiled form
  71. else
  72. Result:='';
  73. end;
  74. if Result='' then
  75. Result:=IntToStr(aID)
  76. else if AddNumeric then
  77. Result:=Result+' ('+IntToStr(aId)+')';
  78. end;
  79. class function TRestool.KnownTypeNameToID(aType: String): Integer;
  80. begin
  81. case aType of
  82. 'RT_CURSOR' : Result:=RT_CURSOR; //Hardware-dependent cursor resource.
  83. 'RT_BITMAP' : Result:=RT_BITMAP; //Bitmap resource.
  84. 'RT_ICON' : Result:=RT_ICON; //Hardware-dependent icon resource.
  85. 'RT_MENU' : Result:=RT_MENU; //Menu resource.
  86. 'RT_DIALOG' : Result:=RT_DIALOG; //Dialog box.
  87. 'RT_STRING' : Result:=RT_STRING; //String-table entry.
  88. 'RT_FONTDIR' : Result:=RT_FONTDIR; //Font directory resource.
  89. 'RT_FONT' : Result:=RT_FONT; //Font resource.
  90. 'RT_ACCELERATOR' : Result:=RT_ACCELERATOR; //Accelerator table.
  91. 'RT_RCDATA' : Result:=RT_RCDATA; //Application-defined resource (raw data).
  92. 'RT_MESSAGETABLE' : Result:=RT_MESSAGETABLE; //Message-table entry.
  93. 'RT_GROUP_CURSOR' : Result:=RT_GROUP_CURSOR; //Hardware-independent cursor resource.
  94. 'RT_GROUP_ICON' : Result:=RT_GROUP_ICON; //Hardware-independent icon resource.
  95. 'RT_VERSION' : Result:=RT_VERSION; //Version resource.
  96. 'RT_DLGINCLUDE' : Result:=RT_DLGINCLUDE; //Never present in compiled form
  97. 'RT_PLUGPLAY' : Result:=RT_PLUGPLAY; //Plug and Play resource.
  98. 'RT_VXD' : Result:=RT_VXD; //VXD.
  99. 'RT_ANICURSOR' : Result:=RT_ANICURSOR; //Animated cursor.
  100. 'RT_ANIICON' : Result:=RT_ANIICON; //Animated icon.
  101. 'RT_HTML' : Result:=RT_HTML; //HTML.
  102. 'RT_MANIFEST' : Result:=RT_MANIFEST; //Microsoft Windows XP: Side-by-Side Assembly XML Manifest.
  103. 'RT_DLGINIT' : Result:=RT_DLGINIT; //Never present in compiled form
  104. else
  105. Result:=-1;
  106. end;
  107. end;
  108. procedure TRestool.DumpResource(var aDest : Text; Res : TAbstractResource; Idx : integer; const Prefix : String = '');
  109. var
  110. aType,aName : string;
  111. begin
  112. aName:=Res.Name.Name;
  113. if res.name.DescType=dtID then
  114. aName:='#'+aName;
  115. aType:=ResTypeName(res._Type.ID,True);
  116. Writeln(aDest,Prefix,Idx:3,' : Type: ',aType,' name: ',aName);
  117. end;
  118. procedure TRestool.DumpOwnedResource(var aDest : Text; aOwner : TAbstractResource; const Prefix : String);
  119. Var
  120. res : TAbstractResource;
  121. i : Integer;
  122. begin
  123. For I:=0 to FResFile.Count-1 do
  124. begin
  125. Res:=FResFile.Items[i];
  126. if Res.Owner=aOwner then
  127. begin
  128. DumpResource(aDest,Res,I,Prefix);
  129. if Res is TGroupResource then
  130. DumpOwnedResource(aDest,Res,' '+Prefix);
  131. end;
  132. end;
  133. end;
  134. procedure TRestool.DumpAllResources(var aDest : Text);
  135. Var
  136. res : TAbstractResource;
  137. i : Integer;
  138. begin
  139. For I:=0 to FResFile.Count-1 do
  140. begin
  141. Res:=FResFile.Items[i];
  142. DumpResource(aDest,Res,I);
  143. end;
  144. end;
  145. procedure TRestool.dumpresourcefile(const aFileName: String; var aDest : Text);
  146. begin
  147. FResFile.LoadFromFile(aFileName);
  148. Writeln(aDest,'File ',aFileName,' contains ',FResFile.Count,' resources:');
  149. if FStructured then
  150. DumpOwnedResource(aDest,Nil,'')
  151. else
  152. DumpAllResources(aDest);
  153. end;
  154. procedure TRestool.WriteResource(Res : TAbstractResource; const aDestFile : String);
  155. var
  156. aCount : Int64;
  157. S : TStream;
  158. begin
  159. if Res is TGroupCursorResource then
  160. S:=TGroupIconResource(Res).ItemData
  161. else if Res is TGroupIconResource then
  162. S:=TGroupIconResource(Res).ItemData
  163. else if Res is TBitmapResource then
  164. S:=TBitmapResource(Res).BitmapData
  165. else
  166. S:=Res.RawData;
  167. With TFileStream.Create(aDestFile,fmCreate) do
  168. try
  169. aCount:=CopyFrom(S,S.Size);
  170. Writeln(stdErr,'Write ',aCount,' bytes from resource data to file: ',aDestFile);
  171. finally
  172. Free;
  173. end;
  174. end;
  175. function TRestool.ProcessOptions: Boolean;
  176. const
  177. Short = 'h:i:n:t:m:xlo:s';
  178. Long : Array of string = ('help','index:','name:','type:','mode:','extract','output:','list','structured');
  179. var
  180. RM,Idx,Err : String;
  181. S : Array of string;
  182. begin
  183. Result:=False;
  184. Err:=CheckOptions(Short,Long);
  185. if (Err<>'') or HasOption('h','help') then
  186. begin
  187. Usage(Err);
  188. Exit;
  189. end;
  190. S:=GetNonOptions(Short,long);
  191. FDestFile:=GetOptionValue('o','output');
  192. FStructured:=HasOption('s','structured');
  193. if Length(S)>0 then
  194. FinputFile:=S[0]
  195. else if Length(S)>1 then
  196. FDestFile:=S[1];
  197. if HasOption('x','extract') then
  198. FRunMode:=rmExtract
  199. else if HasOption('l','list') then
  200. FRunMode:=rmList;
  201. if HasOption('m','mode') then
  202. begin
  203. rm:=GetOptionValue('m','mode');
  204. case RM of
  205. 'list' : FRunMode:=rmList;
  206. 'extract' : FRunMode:=rmExtract;
  207. else
  208. Usage('Invalid run mode: '+RM);
  209. Exit;
  210. end;
  211. end;
  212. if FRunMode=rmExtract then
  213. begin
  214. if HasOption('i','index') then
  215. begin
  216. Idx:=GetOptionValue('i','index');
  217. FResIndex:=StrToIntDef(Idx,-1);
  218. if FResIndex=-1 then
  219. begin
  220. Usage('Invalid (not numerical) value for index: '+Idx);
  221. Exit;
  222. end;
  223. end
  224. else
  225. begin
  226. FResIndex:=-1;
  227. FResName:=GetOptionValue('n','name');
  228. FResType:=GetOptionValue('t','type');
  229. if (FResName='') or (FResType='') then
  230. begin
  231. Usage(Format('Need both type (got: "%s") and name (got: "%s") for extracting a resource. ',[fResType,fresName]));
  232. Exit;
  233. end;
  234. end;
  235. if FDestFile='' then
  236. if FResIndex>0 then
  237. FDestFile:=ChangeFileExt(FInputFile,Format('-resource-%d.dat',[FResIndex]))
  238. else
  239. begin
  240. RM:=FResName;
  241. if RM[1]='#' then
  242. RM:=Copy(RM,2);
  243. FDestFile:=ChangeFileExt(FInputFile,Format('-resource-%s-%s.dat',[FResType,RM]))
  244. end;
  245. end;
  246. Result:=True;
  247. end;
  248. procedure TRestool.Usage(const aErr: String);
  249. begin
  250. If (aErr<>'') then
  251. Writeln('Error: ',aErr);
  252. Writeln('Usage : ',ExtractFileName(ParamStr(0)),' [options] [inputfile [outputfile]]');
  253. Writeln('Where options is one or more of:');
  254. Writeln('-h --help This message');
  255. Writeln('-i --index=IDX Index of resource to extract.');
  256. Writeln('-n --name=NAME Name of resource to extract');
  257. Writeln('-t --type=TYPE Type of resource to extract. Known type names (RT_RCDATA etc.) can be used.');
  258. Writeln('-l --list List resources in file (equivalent to -m list).');
  259. Writeln('-x --extract Extract a resource from file. Specify -i or -n and -t options. (equivalent to -m extract)');
  260. Writeln('-m --mode=MODE set mode to extract or list.');
  261. Writeln('-o --output=FILE Filename to extract a resource to (or specify the name as the second non-option argument.');
  262. Writeln(' If no filename is given, a default name is constructed from either index or Filename to extract a resource to (or specify the name as the second non-option argument.');
  263. Writeln('-s --structured List resources in structured form: resources are listed under their group.');
  264. ExitCode:=Ord(aErr<>'');
  265. end;
  266. procedure TRestool.doRun;
  267. var
  268. FOut : Text;
  269. begin
  270. Terminate;
  271. FInputFile:=ParamStr(0);
  272. if not ProcessOptions then
  273. Exit;
  274. Case FRunMode of
  275. rmList :
  276. begin
  277. if (FDestFile='') then
  278. dumpresourcefile(FInputFile,Output)
  279. else
  280. begin
  281. AssignFile(Fout,FDestFile);
  282. Rewrite(Fout);
  283. dumpresourcefile(FInputFile,Fout);
  284. CloseFile(Fout);
  285. end
  286. end;
  287. rmExtract:
  288. begin
  289. FResfile.LoadFromFile(FInputFile);
  290. if FResIndex>=0 then
  291. ExtractResource(FDestFile,FResIndex)
  292. else
  293. ExtractResource(FDestFile,FResType,FresName)
  294. end;
  295. end;
  296. end;
  297. procedure TRestool.ExtractResource(const aDestFile: String; aIdx: Integer);
  298. var
  299. Res : TAbstractResource;
  300. begin
  301. if (aIdx<0) or (aIdx>=FresFile.Count) then
  302. begin
  303. ExitCode:=2;
  304. Writeln(stdErr,'Resource with index ',aIdx,' not found. Max value for index: ',FresFile.Count-1);
  305. Exit;
  306. end;
  307. Res:=FResfile.Items[aIdx];
  308. WriteResource(Res,aDestFile);
  309. end;
  310. procedure TRestool.ExtractResource(const aDestFile, aType, aName: String);
  311. var
  312. I : integer;
  313. aTypeId,aID : TResID;
  314. Res : TAbstractResource;
  315. begin
  316. aTypeID:=0;
  317. aID:=0;
  318. I:=StrToIntDef(aType,-1);
  319. if (I<0) then
  320. I:=KnownTypeNameToID(aType);
  321. if I>=0 then
  322. aTypeID:=I;
  323. I:=StrToIntDef(aName,-1);
  324. if (I>=0) then
  325. aID:=I;
  326. if aTypeID>0 then
  327. begin
  328. if aID>0 then
  329. Res:=FResfile.Find(aTypeID,aID)
  330. else
  331. Res:=FResfile.Find(aTypeID,aName)
  332. end
  333. else
  334. begin
  335. if aID>0 then
  336. Res:=FResfile.Find(aType,aID)
  337. else
  338. Res:=FResfile.Find(aType,aName);
  339. end;
  340. if not Assigned(Res) then
  341. begin
  342. ExitCode:=2;
  343. Writeln(stdErr,'Resource with type ',aType,' and name ',aName,' not found.');
  344. end;
  345. WriteResource(Res,aDestFile);
  346. end;
  347. Var
  348. Application : TResTool;
  349. begin
  350. Application:=TResTool.Create(Nil);
  351. Application.Initialize;
  352. Application.Run;
  353. Application.Free;
  354. end.