Although originally intended by Bill Atkinson, the HyperCard file format has never been officially published. The instructions in this file are simply what was deduced by looking at various existing stacks and their differences.
Warning: The information in this document is not complete enough to allow the creation of new HyperCard stacks, but maybe it can be helpful in reading existing stacks and extracting precious data to keep it from being lost.
Being a file format from Classic MacOS (shipped 1987 through 2004), many of the data types are from that area. All text is encoded in the MacRoman text encoding, and many flags and data types are from the Quickdraw headers, or based on them. All data is stored in Big-Endian format (like the Motorola 68000 used to do).
A HyperCard stack is a stream of blocks, with a four-character type code and a 4-byte signed ID number, terminated by a 'TAIL' block. Each block has the following basic layout:
4 byte | Block size including size, type and ID. |
4 bytes | Block type |
4 bytes | Block ID number |
n bytes | Block data |
There is one block in the file representing the stack object:
4 byte | Block size including size, type and ID. | ||
4 bytes | Block type 'STAK' | ||
4 bytes | Block ID number -1 | ||
32 bytes | There be Tygers | ||
4 bytes | Number of cards in this stack. | ||
4 bytes | The ID of one card in the stack (why?). | ||
4 bytes | The ID of the 'LIST' block in the stack. | ||
16 bytes | There be Tygers | ||
2 bytes | The User Level setting (1 ... 5) to run this stack under. | ||
2 bytes | There be Tygers | ||
2 bytes | Flags: Bit 10 is cantPeek, 11 is cantAbort, 13 is privateAccess, 14 is cantDelete, 15 is cantModify. | ||
18 bytes | There be Tygers | ||
16 bytes | Three 4-byte NumVersion entries containing the HyperCard version numbers that created, last edited or compacted this stack. | ||
328 bytes | There be Tygers | ||
2 bytes | The height in pixels of cards in this stack. | ||
2 bytes | The width in pixels of cards in this stack. | ||
262 bytes | There be Tygers | ||
For each Pattern: (40 patterns, 320 bytes)
| |||
512 bytes | There be Tygers | ||
n bytes | Stack script as a C string, terminated by a NULL byte. |
Styles for multi-styled text fields are stored as style formats in the style table block of the stack, and only referenced throughout the stack. Here's how the style table looks:
4 byte | Block size including size, type and ID. | ||||||||||
4 bytes | Block type 'STBL' | ||||||||||
4 bytes | Block ID number | ||||||||||
4 bytes | There be Tygers | ||||||||||
4 bytes | Number of styles | ||||||||||
For each style:
|
Since font IDs are not persistent across systems, HyperCard contains a table mapping font names to IDs, so it can get away with storing font IDs in the stack file, but still map the ID to the new one when it changes. The table looks like this
4 byte | Block size including size, type and ID. | ||||||||
4 bytes | Block type 'FTBL' | ||||||||
4 bytes | Block ID number | ||||||||
6 bytes | There be Tygers | ||||||||
2 bytes | Number of fonts | ||||||||
4 bytes | There be Tygers | ||||||||
For each font:
|
Cards may be stored in an arbitrary order in a stack, so there is list of pages that, among other things, contains an ordered list of the card IDs in this stack. To speed up insertions/deletions of cards in large stacks, this list has been segmented. There is one 'LIST' block listing all page tables, and then a bunch of page table blocks listing the cards in order. Here's the list block's format:
4 byte | Block size including size, type and ID. | ||||
4 bytes | Block type 'LIST' | ||||
4 bytes | Block ID number | ||||
4 bytes | Number of page tables | ||||
8 bytes | There be Tygers | ||||
2 bytes | Size of card blocks | ||||
16 bytes | There be Tygers | ||||
For each page table:
|
The page table stores the order of the cards in the stack (because the actual card data is kept in an arbitrary order in the file) and is segmented into several blocks. Each block looks like the following:
4 bytes | Block size including size, type and ID. | ||||||
4 bytes | Block type 'PAGE' | ||||||
4 bytes | Block ID number | ||||||
12 bytes | There be Tygers | ||||||
For each card (get the count from the STAK block):
|
Both cards and backgrounds are stored in the following kind of block:
4 bytes | Block size including size, type and ID. | ||||||||||||||||||||||||||||||||||||||
4 bytes | Block type 'CARD' or 'BKGD' | ||||||||||||||||||||||||||||||||||||||
4 bytes | Block ID number | ||||||||||||||||||||||||||||||||||||||
4 bytes | There be Tygers | ||||||||||||||||||||||||||||||||||||||
4 bytes | ID of BMAP block for card picture (0 means all transparent) | ||||||||||||||||||||||||||||||||||||||
2 bytes | Flags. Bit 14 is cantDelete, 13 is hide card picture, 11 is dontSearch, | ||||||||||||||||||||||||||||||||||||||
14 bytes | There be Tygers | ||||||||||||||||||||||||||||||||||||||
4 bytes | ID of background for this card | ||||||||||||||||||||||||||||||||||||||
2 bytes | Number of parts on this card | ||||||||||||||||||||||||||||||||||||||
6 bytes | There be Tygers | ||||||||||||||||||||||||||||||||||||||
2 bytes | Number of part contents on this card | ||||||||||||||||||||||||||||||||||||||
4 bytes | Script Type: If 0 HyperTalk, if 'WOSA' the card has a compiled OSA language script (e.g. AppleScript). | ||||||||||||||||||||||||||||||||||||||
For each part:
| |||||||||||||||||||||||||||||||||||||||
For each part content entry:
| |||||||||||||||||||||||||||||||||||||||
n bytes | Name of the card as a zero-terminated C string. | ||||||||||||||||||||||||||||||||||||||
n bytes | Script of the card as a zero-terminated C string. | ||||||||||||||||||||||||||||||||||||||
Optional OSA script data:
|
If you have found out more about this file format, feel free to amend this document and let us know.