System Error Alert Table: Difference between revisions

From Computers Wiki
Jump to navigationJump to search
(Create page)
 
(Create script for reading DSAT)
Line 9: Line 9:
ResEdit doesn't support <code>DSAT</code> and only shows a hex editor despite having a custom icon for the resource type.
ResEdit doesn't support <code>DSAT</code> and only shows a hex editor despite having a custom icon for the resource type.


Here is an extremely rough Python script for dumping the alerts, their IDs, and their error messages. Copy-paste the hex editor output from ResEdit into a text file, then pass its filename to this script:
TODO: write a Python script to extract this info from a hex dump and create a wikitable

<div class="toccolours mw-collapsible mw-collapsed">
'''<code>dsat.py</code> contents'''
<syntaxhighlight lang="python" class="mw-collapsible-content">
from argparse import ArgumentParser
from pathlib import Path
import struct
from typing import NamedTuple

parser = ArgumentParser()
parser.add_argument('hexfilepath')
buffer = bytes.fromhex(Path(parser.parse_args().hexfilepath).read_text())
offset = 0

def read_short():
global offset
number = int.from_bytes(buffer[offset:offset + 2])
offset += 2
return number

definition_count = read_short()
definitions: dict[int, 'Definition']

class Alert(NamedTuple):
text1_id: int
text2_id: int
icon_id: int
proc_id: int
button_layout_id: int

@property
def text1(self):
return definitions[self.text1_id].as_text().replace('/', '\n') if self.text1_id else None

@property
def text2(self):
return definitions[self.text2_id].as_text().replace('/', '\n') if self.text2_id else None

@property
def text(self):
if not self.text1:
return None

if self.text2:
return self.text1 + '\n' + self.text2

return self.text1

class Definition(NamedTuple):
id: int
data: bytes

def as_alert(self):
return Alert(*struct.unpack('>HHHHH', self.data))

def as_text(self):
return self.data[4:-1].decode('ascii')

def read_definition():
global offset
id = read_short()
length = read_short()
data = buffer[offset:offset + length]
offset += length
return Definition(id, data)

default_alert = read_definition().as_alert()
definitions = {(definition := read_definition()).id: definition
for _ in range(definition_count)}

for error_id, definition in definitions.items():
if len(definition.data) == 10:
alert = definition.as_alert()
try:
print(error_id, '-', alert.text)
except (KeyError, UnicodeDecodeError):
pass
</syntaxhighlight>
</div>


== Contents in different system versions ==
== Contents in different system versions ==

Revision as of 00:27, 25 September 2025

The System Error Alert Table (resource type DSAT, allegedly short for Deep Shit Alert Table) describes startup text and fatal error dialogs for the classic Mac OS.

Specification

See Inside Macintosh: Operating System Utilities, Chapter 2 - System Error Handler, The System Error Alert Table Resource.

Reading it

ResEdit doesn't support DSAT and only shows a hex editor despite having a custom icon for the resource type.

Here is an extremely rough Python script for dumping the alerts, their IDs, and their error messages. Copy-paste the hex editor output from ResEdit into a text file, then pass its filename to this script:

dsat.py contents

from argparse import ArgumentParser
from pathlib import Path
import struct
from typing import NamedTuple

parser = ArgumentParser()
parser.add_argument('hexfilepath')
buffer = bytes.fromhex(Path(parser.parse_args().hexfilepath).read_text())
offset = 0

def read_short():
    global offset
    number = int.from_bytes(buffer[offset:offset + 2])
    offset += 2
    return number

definition_count = read_short()
definitions: dict[int, 'Definition']

class Alert(NamedTuple):
    text1_id: int
    text2_id: int
    icon_id: int
    proc_id: int
    button_layout_id: int

    @property
    def text1(self):
        return definitions[self.text1_id].as_text().replace('/', '\n') if self.text1_id else None

    @property
    def text2(self):
        return definitions[self.text2_id].as_text().replace('/', '\n') if self.text2_id else None

    @property
    def text(self):
        if not self.text1:
            return None

        if self.text2:
            return self.text1 + '\n' + self.text2

        return self.text1

class Definition(NamedTuple):
    id: int
    data: bytes

    def as_alert(self):
        return Alert(*struct.unpack('>HHHHH', self.data))

    def as_text(self):
        return self.data[4:-1].decode('ascii')

def read_definition():
    global offset
    id = read_short()
    length = read_short()
    data = buffer[offset:offset + length]
    offset += length
    return Definition(id, data)

default_alert = read_definition().as_alert()
definitions = {(definition := read_definition()).id: definition
               for _ in range(definition_count)}

for error_id, definition in definitions.items():
    if len(definition.data) == 10:
        alert = definition.as_alert()
        try:
            print(error_id, '-', alert.text)
        except (KeyError, UnicodeDecodeError):
            pass

Contents in different system versions

TODO: make that utility first