Extracting ROM Resources

Hello! I'm in the early stages of implementing a program that will be able to run AfterDark screen saver modules on modern systems. Ultimately I'd like to support other screen savers and be able run them as modules for "real" screen saves, such as under OSX.

I hope to soon have made enough progress that its worth me making the source available and have a web page with some documentation.

The reason for this post, however, is to share a program I wrote as part of this development along with some observations. All of the source is in a single .p file so I can include inline here, but I also have a Think Pascal project and executable file (that runs under MasOS 8.5 at least and should work on other systems.) The project was built with Think Pascal 4.5d4, but the code should likely compile with other versions. I am attaching the files to this post.

The output of this program is a ResEdit file containing, what should be, all of the resources that are in ROM. These should be the ROM versions and not include versions that are newer and included in the System file.

My motivation for this is that I found my self needing the 'clut' resources from classic MacOS. These can be found with resource IDs 1, 2, 4, and 8, where the ID corresponds the bit depth. I stared out digging in the system file with ResEdit, but no luck. Looking in Inside Macintosh I found that these resources are in ROM. So I wrote a quick program to grab them. No luck either, as I learned that by default the ROM resources aren't searched by GetResource.

I then stumbled on RGetResource which does search the ROM resource map. Unfortunately that still didn't do the trick for me for two reasons: 1) if there was a version of the resource in the System file it returns that one, and 2) by this point I was determined to extract all of the resources in the ROM. Hence, this program.

The code isn't the best, no UI, and I don't check for error it seems to do the trick. I found I needed to use a couple of LowMem globals, but they are documented and have accessor functions. I also discovered they needed to be called a bunch as they are reset to the default values after each call to the Resource Manager.

(Just noticed that Pascal isn't a suppoerted code type here. That's somewhat disappointing.)

Code:
program romextract;

    uses
        LowMem;

    type
        ResArray = array[1..1] of OSType;
        ResArrayPtr = ^ResArray;

    var
        gMyResFile: integer;
        gNewResFile: integer;
        gMyErr: OSErr;
        gFilename: Str32;
        gMyFSSpec: FSSpec;
        gAppSignature: OSType;
        gFileType: OSType;
        gNResTypes: integer;
        gResTypeTable: ResArrayPtr;
        iResType: integer;
        gTheType: ResType;

    function MyCreateResourceFork (myFSSpec: FSSpec; signature: OSType; fileType: OSType): OSErr;
    begin
        FSpCreateResFile(myFSSpec, signature, fileType, -1);
        myCreateResourceFork := ResError;
    end;

    procedure RUseResFile (fileNum: integer);
    begin
        LMSetROMMapInsert(1);
        UseResFile(fileNum);
    end;

    function RCountTypes: integer;
    begin
        LMSetROMMapInsert(1);
        RCountTypes := CountTypes;
    end;

    procedure RGetIndType (var theType: ResType; index: integer);
    begin
        LMSetROMMapInsert(1);
        GetIndType(theType, index);
    end;

    procedure CopyResToFile (h: Handle; f: integer);
        var
            localId: integer;
            localType: ResType;
            localName: Str255;
            newRes: Handle;
            localErr: OSErr;
            oldResFile: integer;
    begin
        LoadResource(h);
        GetResInfo(h, localId, localType, localName);
        oldResFile := CurResFile;
        RUseResFile(f);
        newRes := h;
        localErr := HandToHand(newRes);
        AddResource(newRes, localType, localId, localName);
        WriteResource(newRes);
        UpdateResFile(f);
        ReleaseResource(newRes);
        RUseResFile(oldResFile);
    end;

    procedure CopyRomResources (theType: ResType; resFile: integer);
        var
            i: integer;
            resH: Handle;
            homeFile: integer;
    begin
        for i := -32768 to 32767 do
            begin
                SetResLoad(false);
{ RGetResoure returns the system file version if there is one, uncomment if that is what you want}
{resH := RGetResource(theType, i);}

{Comment out these two lines if you uncomment RGetResource}
                LMSetROMMapInsert(1);
                resH := GetResource(theType, i);

                SetResLoad(true);

                if (resH <> nil) then
                    begin
                        LMSetROMMapInsert(1);
                        homeFile := HomeResFile(resH);

{ homeFile is equal to 1 for ROM resources}
                        if (homeFile = 1) then
                            begin
                                CopyResToFile(resH, resFile);
                            end;
                    end;
            end;
    end;

begin
    gFilename := 'rom_resources.rsrc';
{ make it a ResEdit file}
    gAppSignature := 'RSED';
    gFileType := 'rsrc';

    gMyResFile := CurResFile;
    gMyErr := FSMakeFSSpec(0, 0, gFilename, gMyFSSpec);
    gMyErr := MyCreateResourceFork(gMyFSSpec, gAppSignature, gFileType);

    gNewResFile := FSpOpenResFile(gMyFSSpec, fsRdWrPerm);

    RUseResFile(0);

    gNResTypes := RCountTypes;

    gResTypeTable := ResArrayPtr(NewPtr(SizeOf(ResArray) * gNResTypes));

    for iResType := 1 to gNResTypes do
        begin
            RGetIndType(gResTypeTable^[iResType], iResType);
        end;

    for iResType := 1 to gNResTypes do
        begin
            CopyRomResources(gResTypeTable^[iResType], gNewResFIle);
        end;

    DisposePtr(Ptr(gResTypeTable));
    CloseResFile(gNewResFile);
end.
 

Attachments

  • RomRsrcExtractor.sit.hqx
    99.5 KB · Views: 1

joevt

Well-known member
I use Resorcerer for this purpose. It has an option in the preferences to enable loading resources from ROM. The option creates a file in the System Folder. If you open that file in Resorcerer then it shows the ROM resources. There's a classic macOS version and a Mac OS X version.

If you have a copy of the ROM, then https://github.com/elliotnunn/tbxi can extract each resource as a binary file (using Linux or modern macOS). A resource file could be created from the results using xxd and Rez.
 
I completely forgot that Resourserer existed! I'll give it a try next time. I've never used it before. ResEdit was much more in my price range when I was programming originally.
 
Top