wezm.net/v2/content/posts/2023/derez/index.md
2023-03-20 15:21:36 +10:00

182 lines
8.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

+++
title = "How to use DeRez"
date = 2023-03-20T12:44:38+10:00
#[extra]
#updated = 2023-03-01T21:54:06+10:00
+++
After my post on trying to run
[Rust on Classic Mac OS post](@/posts/2023/rust-on-ppc-classic-mac-os/index.md) I continued trying to
find a modern language that I can use to build classic Mac OS software. I've
had some success with [Nim] and built a little
[temperature converter application][nim-temp-src]. As part of this I wanted to be able to use
[ResEdit] to edit the layout of the dialog. The problem was that I need a way
to convert the modified resources back into the textual representation used in
the source code. In this post I describe how I did this with `DeRez`.
<!-- more -->
{{ video(video="posts/2023/derez/mac-nim-temp.mp4", height=227, poster="png", preload="auto", alt="Video of the temperature converter application.", caption="Video of the temperature converter application.") }}
To build the temperature converter I started with the [Dialog sample] from
[Retro68], which looks like this:
{{ figure(image="posts/2023/derez/Dialog.png", link="posts/2023/derez/Dialog.png", pixelated=true, alt="TODO", caption="Dialog Sample") }}
I opened it up in ResEdit and edited the `DITL` (Dialog Template) resource to
add the icon and temperature fields. I also added a new `ICON` resource and
drew a little thermometer:
{{ figure(image="posts/2023/derez/DITL.png", link="posts/2023/derez/DITL.png", pixelated=true, alt="Screenshot of the ResEdit DITL editor editing the DITL resource for my temperature converter.", caption="Editing DITL resource in ResEdit") }}
With the changes made, I now wanted to convert the binary resources stored in
the resource fork back into the [textual format used in the source code][dialog.r].
I believe the format is called `Rez`, here's a snippet of it:
```
resource 'DITL' (128) {
{
{ 190-10-20, 320-10-80, 190-10, 320-10 },
Button { enabled, "Quit" };
{ 190-10-20-5, 320-10-80-5, 190-10+5, 320-10+5 },
UserItem { enabled };
{ 10, 10, 30, 310 },
StaticText { enabled, "Static Text Item" };
{ 40, 10, 56, 310 },
EditText { enabled, "Edit Text Item" };
{ 70, 10, 86, 310 },
CheckBox { enabled, "Check Box" };
{ 90, 10, 106, 310 },
RadioButton { enabled, "Radio 1" };
{ 110, 10, 126, 310 },
RadioButton { enabled, "Radio 2" };
}
};
```
This turned out to be a bit of journey and the motivation for this blog post.
As part of the [Macintosh Programmers Workshop][mpw] (MPW) theres is a tool
called `DeRez` that does what I want. First up I had to work out how to operate
MPW. It's an editable shell where you run commands with ⌘-Return. Once I worked
that out I could run `DeRez` on my edited application but I only got the
fullback hexadecimal representation of the resources, not the structured output
I wanted:
```
data 'DITL' (128) {
$"0007 0000 0000 00A0 00E6 00B4 0136 0404" /* ....... .æ.´.6.. */
$"5175 6974 0000 0000 009B 00E1 00B9 013B" /* Quit.....›.á.¹.; */
$"0000 0000 0000 0046 000A 005A 0136 0808" /* .......F...Z.6.. */
$"4865 6C6C 6F20 5E30 0000 0000 001E 000A" /* Hello ^0........ */
$"003E 002A A002 0597 0000 0000 0014 0032" /* .>.* ..—.......2 */
$"0024 007D 8807 4365 6C73 6975 7300 0000" /* .$.}ˆ.Celsius... */
$"0000 0014 00AA 0024 00F5 8809 4661 7265" /* .....ª.$.õˆÆFare */
$"6E68 6569 7400 0000 0000 0029 0036 0039" /* nheit......).6.9 */
$"0081 1009 4564 6974 2054 6578 7400 0000" /* ..ÆEdit Text... */
$"0000 002B 00AE 003B 00F9 1009 4564 6974" /* ...+.®.;.ù.ÆEdit */
$"2054 6578 7400" /* Text. */
};
```
`Help DeRez` in MPW didn't shed much light on the problem but after a lot of
searching online I eventually found some extra details in the [man page for
`DeRez`][DeRez man] shipped on Mac OS X. Specifically:
> The type declarations for the standard
> Macintosh resources are contained in the `Carbon.r` resource header file,
> contained in the Carbon framework. You may use the ${RIncludes} shell
> environment variable to define a default path to resource header files.
> If you do not specify any type declaration files, `DeRez` produces data
> statements in hexadecimal form.
and
> You can also specify resource description
> files containing type declarations. For each type declaration file on
> the command line, DeRez applies the following search rules:
>
> 1. DeRez tries to open the file with the name specified as is.
>
> 2. If rule 1 fails and the filename contains no colons or begins with a
> colon, DeRez appends the filename to each of the pathnames specified by
> the {RIncludes} environment variable and tries to open the file.
With this information I was able to construct a command that worked:
```
DeRez -i 'Macintosh HD:MPW-GM:Interfaces&Libraries:Interfaces:RIncludes:' "Macintosh HD:Retro68:Retro68App" Carbon.r
```
`-i` sets the include path for type declarations and `Carbon.r` tells it to use
that file for resource descriptions. Running the command I was now rewarded
with textual resources:
{{ figure(image="posts/2023/derez/MPW.png", link="posts/2023/derez/MPW.png", pixelated=true, alt="TODO", caption="DeRez output in MPW") }}
To get the text out of the VM I copied and pasted it into a new document in
[BBEdit] (version 5.0) and saved it with Unix line endings to the Unix folder
that [SheepShaver] shares with the host and with that I was able to update the
[resource file in my temperature converter project][my dialog.r].
### Honorable Mention
Whilst trying to work out how to do all this I was also reminded of Ninji's
[mpw-emu] project ([detailed write-up on their blog][mpw-emu-blog]). It
combines an emulator with implementations of library functions in order to be
able to run MPW tools directly (outside a Mac OS emulator). It has gained
support for `DeRez` so you can run `DeRez` directly on a host system like
Linux.
I [MacBinaried][MacBinary] `DeRez` in SheepShaver and copied it to my Linux host. Then with a bit
of fussing with `mpw-emu` Rust code I was able to run it:
```
$ mpw-emu ~/Documents/Classic\ Mac/Shared\ 2/DeRez.bin
[2023-03-20T02:11:07Z ERROR emulator] Unimplemented call to InterfaceLib::SetFScaleDisable @10012C6C
[2023-03-20T02:11:07Z ERROR stdio] Unimplemented format character: P
[2023-03-20T02:11:07Z ERROR emulator] Unimplemented call to InterfaceLib::SecondsToDate @1000B2A4
### /home/wmoore/Documents/Classic Mac/Shared 2/DeRez.bin - No filename to de-compile was specified.
### /home/wmoore/Documents/Classic Mac/Shared 2/DeRez.bin - Usage: /home/wmoore/Documents/Classic Mac/Shared 2/DeRez.bin resourceFile [-c] [-d name[=value]] [-e] [-i path] [-m n] [-noResolve [output | include]] [-only type[(id[:id])]] [-p] [-rd] [-s type[(id[:id])]] [-script japanese | tradChinese | simpChinese | korean] [-u name] [file…].
```
Amazing!
Unfortunately I don't think `DeRez` will work this way outside a macOS host. It
needs to be able to read the resource fork of the application I edited with
ResEdit and that is not preserved on Linux:
```
$ mpw-emu ~/Documents/Classic\ Mac/Shared\ 2/DeRez.bin Dialog.APPL
[2023-03-20T02:14:05Z ERROR emulator] Unimplemented call to InterfaceLib::SetFScaleDisable @10012C6C
[2023-03-20T02:14:05Z ERROR stdio] Unimplemented format character: P
[2023-03-20T02:14:05Z ERROR emulator] Unimplemented call to InterfaceLib::SecondsToDate @1000B2A4
### /home/wmoore/Documents/Classic Mac/Shared 2/DeRez.bin - The resource fork of "Dialog.APPL" is empty and uninitialized.
```
If you're on macOS I think that this would actually work. Although now I think
about it Xcode ships (or at least used to) a native version of `DeRez` so now
I'm not sure what Ninji's motivation for making it work in `mpw-emu` was.
Perhaps it is possible to use on Linux somehow...
[Nim]: https://nim-lang.org/
[ResEdit]: https://en.wikipedia.org/wiki/ResEdit
[Retro68]: https://github.com/autc04/Retro68
[Dialog sample]: https://github.com/autc04/Retro68/tree/5f882506013a0a8a4335350197a1b7c91763494e/Samples/Dialog
[dialog.r]: https://github.com/autc04/Retro68/blob/5f882506013a0a8a4335350197a1b7c91763494e/Samples/Dialog/dialog.r
[DeRez man]: https://www.manpagez.com/man/1/DeRez/
[BBEdit]: http://www.barebones.com/products/bbedit/index.html
[SheepShaver]: https://sheepshaver.cebix.net/
[my dialog.r]: https://github.com/wezm/classic-mac-nim/blob/39e6ed7c2b31c20b775782319cde8ae5a43e1512/dialog.r
[mpw-emu]: https://github.com/Treeki/mpw-emu
[mpw-emu-blog]: https://wuffs.org/blog/emulating-mac-compilers
[mpw]: https://en.wikipedia.org/wiki/Macintosh_Programmer%27s_Workshop
[MacBinary]: https://en.wikipedia.org/wiki/MacBinary
[nim-temp-src]: https://github.com/wezm/classic-mac-nim/tree/39e6ed7c2b31c20b775782319cde8ae5a43e1512