|
| 1 | +(* |
| 2 | +(Resource Editor)= |
| 3 | +# Tool: Resource Editor |
| 4 | +Tool to inspect and edit resource files created by Simba's `TResourceWriter`: |
| 5 | + |
| 6 | +```{figure} ../../images/resource_editor.png |
| 7 | +``` |
| 8 | + |
| 9 | +These files usually end in a `.bin` extension and are an optimized way to store |
| 10 | +multiple compressed files for Simba to read from. |
| 11 | + |
| 12 | +This tool is also a little bit slow at doing certain things like loading the |
| 13 | +files bytes, adding and removing files/images because Simba is not optimized for |
| 14 | +what this tool does. |
| 15 | +*) |
| 16 | +{$I WaspLib/osrs.simba} |
| 17 | + |
| 18 | +var |
| 19 | + HEX_TABLE: TStringArray; |
| 20 | +function ToString(constref value: TByteArray): String; override; |
| 21 | +var |
| 22 | + i: Integer; |
| 23 | +begin |
| 24 | + for i := 0 to High(value)-1 do |
| 25 | + Result += HEX_TABLE[value[i]] + ' '; |
| 26 | + Result += HEX_TABLE[value[High(value)]]; |
| 27 | +end; |
| 28 | + |
| 29 | + |
| 30 | +type |
| 31 | + TResourceEditor = record |
| 32 | + Form: TLazForm; |
| 33 | + FileList: TLazListBox; |
| 34 | + Reader: TResourceReader; |
| 35 | + Dialog: TLazOpenDialog; |
| 36 | + FileData: TLazMemo; |
| 37 | + FileImage: TImageBox; |
| 38 | + SelectedResource, CompressionAlgo, CompressedSize, Uncompressed: TLazEdit; |
| 39 | + end; |
| 40 | + |
| 41 | +{$H-} |
| 42 | +procedure TResourceEditor.OnOpenClick(sender: TLazObject); |
| 43 | +begin |
| 44 | + if not Self.Dialog.Execute() then |
| 45 | + Exit; |
| 46 | + |
| 47 | + Self.FileList.Items.BeginUpdate(); |
| 48 | + Self.FileList.Clear(); |
| 49 | + Self.FileList.ItemIndex := -1; |
| 50 | + try |
| 51 | + Self.Reader := new TResourceReader(Self.Dialog.FileName); |
| 52 | + Self.SelectedResource.Text := Self.Dialog.FileName; |
| 53 | + Self.FileList.Items.AddStrings(Self.Reader.Names); |
| 54 | + except |
| 55 | + Self.SelectedResource.Text := ''; |
| 56 | + finally |
| 57 | + Self.FileList.Items.EndUpdate(); |
| 58 | + end; |
| 59 | +end; |
| 60 | + |
| 61 | +procedure TResourceEditor.OnAddFileClick(sender: TLazObject); |
| 62 | +var |
| 63 | + writer: TResourceWriter; |
| 64 | + name: String; |
| 65 | + i: Integer; |
| 66 | + data: TByteArray; |
| 67 | +begin |
| 68 | + if not Self.Dialog.Execute() then |
| 69 | + Exit; |
| 70 | + |
| 71 | + writer := new TResourceWriter(); |
| 72 | + for i := 0 to Self.Reader.Count-1 do |
| 73 | + begin |
| 74 | + data := Self.Reader.Load(i); |
| 75 | + writer.Add(Self.Reader.Name[i], @data[0], Length(data)); |
| 76 | + end; |
| 77 | + |
| 78 | + data := FileReadBytes(Self.Dialog.FileName); |
| 79 | + name := PathExtractName(Self.Dialog.FileName); |
| 80 | + writer.Add(name, @data[0], Length(data)); |
| 81 | + |
| 82 | + Self.Reader.Unload(); |
| 83 | + Self.Reader.Destroy(); |
| 84 | + FileDelete(Self.SelectedResource.Text); |
| 85 | + writer.Save(Self.SelectedResource.Text); |
| 86 | + Self.Reader := new TResourceReader(Self.SelectedResource.Text); |
| 87 | + Self.FileList.Items.Add(name); |
| 88 | + Self.FileList.ItemIndex := Self.FileList.Count-1; |
| 89 | +end; |
| 90 | + |
| 91 | +procedure TResourceEditor.OnAddImageClick(sender: TLazObject); |
| 92 | +var |
| 93 | + writer: TResourceWriter; |
| 94 | + name: String; |
| 95 | + i: Integer; |
| 96 | + data: TByteArray; |
| 97 | + img: TImage; |
| 98 | +begin |
| 99 | + if not Self.Dialog.Execute() then |
| 100 | + Exit; |
| 101 | + |
| 102 | + writer := new TResourceWriter(); |
| 103 | + for i := 0 to Self.Reader.Count-1 do |
| 104 | + begin |
| 105 | + data := Self.Reader.Load(i); |
| 106 | + writer.Add(Self.Reader.Name[i], @data[0], Length(data)); |
| 107 | + end; |
| 108 | + |
| 109 | + img := new TImage(Self.Dialog.FileName); |
| 110 | + name := PathExtractName(Self.Dialog.FileName); |
| 111 | + writer.AddImage(name, img); |
| 112 | + |
| 113 | + Self.Reader.Unload(); |
| 114 | + Self.Reader.Destroy(); |
| 115 | + FileDelete(Self.SelectedResource.Text); |
| 116 | + writer.Save(Self.SelectedResource.Text); |
| 117 | + Self.Reader := new TResourceReader(Self.SelectedResource.Text); |
| 118 | + Self.FileList.Items.Add(name); |
| 119 | + Self.FileList.ItemIndex := Self.FileList.Count-1; |
| 120 | +end; |
| 121 | + |
| 122 | +procedure TResourceEditor.OnRemoveClick(sender: TLazObject); |
| 123 | +var |
| 124 | + idx, i: Integer; |
| 125 | + writer: TResourceWriter; |
| 126 | + data: TByteArray; |
| 127 | +begin |
| 128 | + idx := Self.FileList.ItemIndex; |
| 129 | + if idx < 0 then Exit; |
| 130 | + |
| 131 | + Self.FileList.Items.Delete(idx); |
| 132 | + writer := new TResourceWriter(); |
| 133 | + |
| 134 | + for i := 0 to Self.Reader.Count-1 do |
| 135 | + begin |
| 136 | + if i = idx then Continue; |
| 137 | + data := Self.Reader.Load(i); |
| 138 | + writer.Add(Self.Reader.Name[i], @data[0], Length(data)); |
| 139 | + end; |
| 140 | + |
| 141 | + Self.Reader.Unload(); |
| 142 | + Self.Reader.Destroy(); |
| 143 | + FileDelete(Self.SelectedResource.Text); |
| 144 | + writer.Save(Self.SelectedResource.Text); |
| 145 | + Self.Reader := new TResourceReader(Self.SelectedResource.Text); |
| 146 | +end; |
| 147 | + |
| 148 | +procedure TResourceEditor.OnSelectionChange(sender: TLazObject; user: Boolean); |
| 149 | +var |
| 150 | + i: Integer; |
| 151 | + data: TByteArray; |
| 152 | +begin |
| 153 | + i := TLazListBox(sender).ItemIndex; |
| 154 | + try |
| 155 | + Self.FileImage.SetImage(Self.Reader.LoadImage(i)); |
| 156 | + except |
| 157 | + end; |
| 158 | + |
| 159 | + data := Self.Reader.Load(i); |
| 160 | + |
| 161 | + Self.FileData.Text := ToStr(data); |
| 162 | + |
| 163 | + case Self.Reader.CompressAlgo[i] of |
| 164 | + 0: Self.CompressionAlgo.Text := 'None'; |
| 165 | + 1: Self.CompressionAlgo.Text := 'SynLZ'; |
| 166 | + 2: Self.CompressionAlgo.Text := 'RleSynLZ'; |
| 167 | + end; |
| 168 | + |
| 169 | + Self.CompressedSize.Text := ToStr(Self.Reader.CompressedSize[i]); |
| 170 | + Self.Uncompressed.Text := ToStr(Self.Reader.UncompressedSize[i]); |
| 171 | +end; |
| 172 | +{$H+} |
| 173 | + |
| 174 | +var |
| 175 | + Editor: TResourceEditor; |
| 176 | + openBtn, addFileBtn, addImgBtn, removeBtn: TLazButton; |
| 177 | + i: Integer; |
| 178 | +begin |
| 179 | + for i := 0 to 255 do |
| 180 | + HEX_TABLE += IntToHex(i, 2); |
| 181 | + Editor.Dialog := TLazOpenDialog.Create(nil); |
| 182 | + Editor.Dialog.Width := 600; |
| 183 | + Editor.Dialog.Height := 800; |
| 184 | + Editor.Dialog.DefaultExt := '.bin'; |
| 185 | + Editor.Dialog.InitialDir := Map.Loader.CacheDir; |
| 186 | + Editor.Dialog.Options := [ELazOpenFileOptions.ShowHelp, ELazOpenFileOptions.ExtensionDifferent, ELazOpenFileOptions.FileMustExist]; |
| 187 | + |
| 188 | + Editor.Form := TLazForm.Create(); |
| 189 | + Editor.Form.Caption := 'Resource Editor'; |
| 190 | + Editor.Form.Height := 600; |
| 191 | + Editor.Form.Width := 800; |
| 192 | + Editor.Form.Position := ELazFormPosition.ScreenCenter; |
| 193 | + |
| 194 | + Editor.FileList := TLazListBox.CreateEx(Editor.Form, 'Compressed files:', 'Files stored in the resource file.', 20, 60, 220, Editor.Form.Height - 120); |
| 195 | + Editor.FileList.OnSelectionChange := @Editor.OnSelectionChange; |
| 196 | + |
| 197 | + openBtn := TLazButton.CreateEx(Editor.Form, 'Open .bin file', 'Open a resource file.', Editor.Form.Width div 2 - 120, Editor.FileList.Top + 20, 200); |
| 198 | + openBtn.OnClick := @Editor.OnOpenClick; |
| 199 | + |
| 200 | + Editor.SelectedResource := TLazEdit.CreateEx(Editor.Form, 'Selected resource:', 'Name of the currently selected resource file.', openBtn.Left, openBtn.Bottom + 20, 200); |
| 201 | + Editor.SelectedResource.ReadOnly := True; |
| 202 | + |
| 203 | + addFileBtn := TLazButton.CreateEx(Editor.Form, 'Add file', 'Adds and compresses a file into the resource file.', Editor.SelectedResource.Left, Editor.SelectedResource.Bottom + 80, 200); |
| 204 | + addFileBtn.OnClick := @Editor.OnAddFileClick; |
| 205 | + |
| 206 | + addImgBtn := TLazButton.CreateEx(Editor.Form, 'Add image', 'Adds and compresses an image into the resource file.', addFileBtn.Left, addFileBtn.Bottom + 10, 200); |
| 207 | + addImgBtn.OnClick := @Editor.OnAddImageClick; |
| 208 | + |
| 209 | + removeBtn := TLazButton.CreateEx(Editor.Form, 'Remove selected', 'Removes the selected file from the resource file.', addImgBtn.Left, addImgBtn.Bottom + 10, 200); |
| 210 | + removeBtn.OnClick := @Editor.OnRemoveClick; |
| 211 | + |
| 212 | + Editor.CompressionAlgo := TLazEdit.CreateEx(Editor.Form, 'Compression algorithm:', 'Compression algorithm used on this file', removeBtn.Left, removeBtn.Bottom + 80, 200); |
| 213 | + Editor.CompressionAlgo.ReadOnly := True; |
| 214 | + |
| 215 | + Editor.CompressedSize := TLazEdit.CreateEx(Editor.Form, 'Compressed size:', 'Compressed file size', Editor.CompressionAlgo.Left, Editor.CompressionAlgo.Bottom + 20, 200); |
| 216 | + Editor.CompressedSize.ReadOnly := True; |
| 217 | + |
| 218 | + Editor.Uncompressed := TLazEdit.CreateEx(Editor.Form, 'Original size:', 'Original file size', Editor.CompressedSize.Left, Editor.CompressedSize.Bottom + 20, 200); |
| 219 | + Editor.Uncompressed.ReadOnly := True; |
| 220 | + |
| 221 | + Editor.FileImage := TImageBox.CreateEx(Editor.Form, 'Image viewer:', 'View the file data as a TImage', Editor.Form.Width - 280, 60, 260, 260); |
| 222 | + Editor.FileData := TLazMemo.CreateEx(Editor.Form, 'File data:', 'View the file bytes', Editor.FileImage.Left, Editor.FileImage.Bottom + 20, 260, 200); |
| 223 | + Editor.FileData.Font.Name := 'Courier New'; |
| 224 | + Editor.FileData.ReadOnly := True; |
| 225 | + |
| 226 | + Editor.Form.ShowModal(); |
| 227 | +end. |
0 commit comments