1 unit reMainUnit;
2 
3 {$mode objfpc}{$H+}
4 
5 interface
6 
7 uses
8   SysUtils, resource, LazUTF8, SynEdit, Forms, Controls, Dialogs, ComCtrls,
9   ActnList, Menus, ExtCtrls, Grids, bitmapresource, versionresource,
10   groupiconresource, Classes;
11 
12 type
13 
14   { TreMainForm }
15 
16   TreMainForm = class(TForm)
17     fileSave: TAction;
18     HeaderControl1: THeaderControl;
19     hlpAbout: TAction;
20     fileExit: TAction;
21     fileOpen: TAction;
22     ActionList1: TActionList;
23     Image1: TImage;
24     ImageList1: TImageList;
25     MainMenu1: TMainMenu;
26     MenuItem1: TMenuItem;
27     MenuItem2: TMenuItem;
28     MenuItem3: TMenuItem;
29     MenuItem4: TMenuItem;
30     MenuItem5: TMenuItem;
31     MenuItem6: TMenuItem;
32     OpenDialog1: TOpenDialog;
33     PageControl1: TPageControl;
34     Splitter1: TSplitter;
35     StatusBar1: TStatusBar;
36     StringGrid1: TStringGrid;
37     SynEdit1: TSynEdit;
38     tabBinary: TTabSheet;
39     tabString: TTabSheet;
40     tabImage: TTabSheet;
41     ToolBar1: TToolBar;
42     ToolButton1: TToolButton;
43     ToolButton2: TToolButton;
44     ToolButton3: TToolButton;
45     ToolButton4: TToolButton;
46     TreeView1: TTreeView;
47     procedure fileExitExecute(Sender: TObject);
48     procedure fileOpenExecute(Sender: TObject);
49     procedure FormCreate(Sender: TObject);
50     procedure FormDestroy(Sender: TObject);
51     procedure HeaderControl1SectionResize(HeaderControl: TCustomHeaderControl;
52       Section: THeaderSection);
53     procedure hlpAboutExecute(Sender: TObject);
54     procedure Splitter1ChangeBounds(Sender: TObject);
55     procedure TreeView1SelectionChanged(Sender: TObject);
56   private
57     Res:TResources;
58     procedure ClearDisplay;
59     procedure LoadVersionResource(V:TVersionResource);
60     procedure LoadBitmapResource(B:TBitmapResource);
61     procedure LoadGroupIconResource(G:TGroupIconResource);
62     procedure LoadResourceAsBinary(R: TAbstractResource);
63   public
64     procedure OpenFile(const AFileName:string);
65   end;
66 
67 var
68   reMainForm: TreMainForm;
69 
70 implementation
71 
72 {$R *.lfm}
73 
74 uses
75   winpeimagereader, elfreader, resreader, reAboutUnit, reConstsUnit;
76 
77 { TreMainForm }
78 
79 procedure TreMainForm.fileExitExecute(Sender: TObject);
80 begin
81   Close;
82 end;
83 
84 procedure TreMainForm.fileOpenExecute(Sender: TObject);
85 begin
86   if OpenDialog1.Execute then
87     OpenFile(UTF8ToSys(OpenDialog1.FileName));
88 end;
89 
90 procedure TreMainForm.FormCreate(Sender: TObject);
91 begin
92   Caption:=sResourceExplorer;
93 
94   fileSave.Caption:=sSaveResource; //'Save resource...'
95   hlpAbout.Caption:=sAbout; //'About...'
96   fileExit.Caption:=sExit; //'Exit'
97   fileOpen.Caption:=sOpen; //'Open...'
98   MenuItem1.Caption:=sFile;
99   MenuItem2.Caption:=sHelp;
100   tabString.Caption:=sStrings;
101   tabImage.Caption:=sImage;
102   HeaderControl1.Sections[0].Text := sResources;
103 
104   {$IFDEF Windows}
105   OpenDialog1.Filter := sAllFilesExcutableFilesExeExeDLLDllDll;
106   {$ELSE}
107   OpenDialog1.Filter := sAllFilesSharedLibSoSo;
108   {$ENDIF}
109   Splitter1ChangeBounds(nil);
110   SynEdit1.Gutter.Visible := False;
111   ClearDisplay;
112 end;
113 
114 procedure TreMainForm.FormDestroy(Sender: TObject);
115 begin
116   if Assigned(Res) then Res.Free;
117 end;
118 
119 procedure TreMainForm.HeaderControl1SectionResize(
120   HeaderControl: TCustomHeaderControl; Section: THeaderSection);
121 begin
122   TreeView1.Width:=HeaderControl1.Sections[0].Width;
123   HeaderControl1.Sections[1].Width:=Width -  TreeView1.Width;
124 end;
125 
126 procedure TreMainForm.hlpAboutExecute(Sender: TObject);
127 begin
128   reAboutForm:=TreAboutForm.Create(Application);
129   reAboutForm.ShowModal;
130   reAboutForm.Free;
131 end;
132 
133 procedure TreMainForm.Splitter1ChangeBounds(Sender: TObject);
134 begin
135   HeaderControl1.Sections[0].Width:=TreeView1.Width;
136   HeaderControl1.Sections[1].Width:=Width -  TreeView1.Width;
137 end;
138 
139 procedure TreMainForm.TreeView1SelectionChanged(Sender: TObject);
140 var
141   ResItem:TAbstractResource;
142 begin
143   if Assigned(TreeView1.Selected) then ClearDisplay;
144   if Assigned(TreeView1.Selected) and Assigned(TreeView1.Selected.Data) then
145   begin
146     ResItem:=TAbstractResource(TreeView1.Selected.Data);
147     HeaderControl1.Sections[1].Text:=ResItem.ClassName + ' : ' + ResItem.Name.Name;
148     if ResItem is TVersionResource then
149       LoadVersionResource(ResItem as TVersionResource)
150     else
151     if ResItem is TBitmapResource then
152       LoadBitmapResource(ResItem as TBitmapResource)
153     else
154     if ResItem is TGroupIconResource then
155       LoadGroupIconResource(ResItem as TGroupIconResource)
156     else
157       LoadResourceAsBinary(ResItem);
158   end;
159 end;
160 
161 
162 procedure TreMainForm.ClearDisplay;
163 begin
164   StringGrid1.Clean;
165   StringGrid1.Visible := False;
166   Image1.Picture.Clear;
167   SynEdit1.Lines.Clear;
168 end;
169 
170 procedure TreMainForm.LoadVersionResource(V: TVersionResource);
171 var
172   i,j, k:integer;
173 begin
174   PageControl1.ActivePage:=tabString;
175   StringGrid1.Visible := True;
176   k:=0;
177   StringGrid1.RowCount:=0;
178   StringGrid1.ColCount:=2;
179   for i:=0 to V.StringFileInfo.Count-1 do
180   begin
181     for j:=0 to V.StringFileInfo[i].Count-1 do
182     begin
183       StringGrid1.RowCount:=StringGrid1.RowCount + 1;
184       StringGrid1.Cells[0, k]:=SysToUTF8(V.StringFileInfo[i].Keys[j]);
185       StringGrid1.Cells[1, k]:=SysToUTF8(V.StringFileInfo[i].ValuesByIndex[j]);
186       inc(k);
187     end;
188   end;
189 end;
190 
191 procedure TreMainForm.LoadBitmapResource(B: TBitmapResource);
192 begin
193   PageControl1.ActivePage:=tabImage;
194   B.BitmapData.Position:=0;
195   Image1.Picture.Bitmap.LoadFromStream(B.BitmapData);
196   //
197 end;
198 
199 procedure TreMainForm.LoadGroupIconResource(G: TGroupIconResource);
200 begin
201   //ToDo: implement proper method to display
202   LoadResourceAsBinary(G);
203 end;
204 
205 procedure TreMainForm.LoadResourceAsBinary(R: TAbstractResource);
206 var
207   Offset, Size, BytesRead: Int64;
208   Buf: Array[0..15] of Byte;
209   Line, BinLine, AscLine: ShortString;
210   i: Integer;
211 begin
212   PageControl1.ActivePage:=tabBinary;
213   //writeln('TreMainForm.LoadResourceAsBinary');
214   //writeln('  ClassName      = ',R.ClassName);
215   //writeln('  DataSize       = ',R.DataSize);
216   //writeln('  R.RawData.Size = ',R.RawData.Size);
217   //writeln('  DataOffset     = ',R.DataOffset);
218   //writeln('  DataVersion    = ',R.DataVersion);
219   SynEdit1.Lines.BeginUpdate;
220   try
221     Offset := 0;
222     R.RawData.Position := 0;
223     Size := R.RawData.Size;
224     while (Offset < Size) do
225     begin
226       FillChar(Buf{%H-}, SizeOf(Buf), #0);
227       BytesRead := R.RawData.Read(Buf[0], SizeOf(Buf));
228       //writeln('    BytesRead = ',BytesRead);
229       Line := '';
230       BinLine := '';
231       Ascline := '';
232       for i := 0 to BytesRead - 1 do
233       begin
234         BinLine := BinLine + IntToHex(Buf[i],2) + #32;
235         if (Buf[i] in [32..127]) then
236           AscLine := AscLine + Char(Buf[i])
237         else
238           AscLine := AscLine + #32;
239       end;
240       for i := (BytesRead + 1) to SizeOf(Buf) do
241       begin
242         BinLine := BinLine + '   ';
243         AscLine := AscLine + ' ';
244       end;
245       Line := IntToHex(Offset, 8) + #32;
246       Line := Line + BinLine + #32 + AscLine + LineEnding;
247       //writeln('    Line = ',Line);
248       SynEdit1.Lines.Add(Line);
249       Inc(Offset, SizeOf(Buf));
250     end;
251   finally
252     SynEdit1.Lines.EndUpdate;
253   end;
254 end;
255 
256 procedure TreMainForm.OpenFile(const AFileName: string);
257 var
258   Ext:string;
259   Reader:TAbstractResourceReader;
260   i:integer;
261   Root, ResNode:TTreeNode;
262 begin
263   if not FileExists(AFileName) then exit;
264   Ext:=LowerCase(ExtractFileExt(AFileName));
265   if (Ext = '.exe') or (Ext = '.dll') then
266     Reader:=TWinPEImageResourceReader.Create
267   else
268   if (Ext = '.res')then
269     Reader:=TResResourceReader.Create
270   else
271   if (Ext = '.o')then
272     Reader:=TResResourceReader.Create
273   else
274   if (Ext = '')then
275     Reader:=TElfResourceReader.Create;
276 
277   TreeView1.Items.Clear;
278   ClearDisplay;
279   if Assigned(Res) then
280     FreeAndNil(Res);
281 
282   if not Assigned(Reader) then exit;
283 
284   Res:=TResources.Create;
285   try
286     Res.LoadFromFile(AFileName, Reader);
287 
288     for i:=0 to Res.Count-1 do
289     begin
290       Root:=TreeView1.Items.FindTopLvlNode(Res[i].ClassName);
291       if not Assigned(Root) then
292         Root:=TreeView1.Items.AddChild(nil, Res[i].ClassName);
293       ResNode:=TreeView1.Items.AddChild(Root, Res[i].Name.Name);
294       ResNode.Data:=Res[i];
295     end;
296   finally
297     Reader.Free;
298   end;
299 
300   StatusBar1.SimpleText:=AFileName;
301 end;
302 
303 end.
304 
305