T2FileOps.Mesa
Last Edited by: Paxton, August 19, 1983 11:20 am
File representation for Tioga2
File representation
file = text control properties trailer
text = characters of text nodes separated by CR's and padded with 0 at end if necessary
control = control information for parsing the file; starts with 0 to indicate end of plain text part of file
properties = {key value} -- both keys and values stored as ropes
trailer = -- 14 bytes at end of file
1 byte controlTrailerId, 1 byte (DataPaddedFlag | DataUnpaddedFlag), 1 byte version number, 1 byte of flags, 2 bytes for length of properties, 4 bytes for length of text, 4 bytes for length of file
Branch node
branch =
OP [if OP.class then className] [if OP.format then formatName] {prop}
(BRANCHCONTENTSPECS contentsSpecs | {item}) -- the contents of the branch
(NOCHILD -- branch has no children -- |
CHILDSPECS childSpecs -- class op will create children from the specs -- |
STARTC {child} ENDC -- the children will be parsed left to right when parse the parent -- |
ENDITEMS {child} ENDC {ctrlLen dataLen} numChildren -- can create unparsed children --)
The OP also includes a comment bit.
The ctrlLen dataLen pairs are in reverse order for the children. Thus when read from end, get info for first child first.
Need opcode after items since branches don't have a special starting code, and therefore we wouldn't be able to tell the end of the items from the beginning of the children if the first child didn't have comment or properties.
The STARTC&ENDC version is called "whole tree mode" and is used for branches inside list or box nodes and for branches nested more than 2 levels deep in the document tree. In this mode, the child branches are parsed at the same time the parent is parsed, so there is no need for control and data lengths. If the parent is stored in whole tree mode, the children must all be stored that way also. No child can begin with ENDC, so the parsing of the children can simply go on until it encounters an ENDC.
We put an ENDC after the children even in the case where we give the lengths and number of children info so that we can be sure to be able to parse a branch even if we don't know the length of the control information ahead of time.
Basic, Box, or List node
basic, box, or list = OP [if OP.class then className] [if OP.format then formatName] {prop}
(STARTBR {branch} | ITEMCONTENTSPECS contentsSpecs | {item | basic}) (NODATA | CLASSDATA data)
The OP includes bits saying whether or not there is a class name and a format name.
The OP also includes a bit saying whether or not this is a comment node.
If there is no class name, the class defaults to "Basic", "Box", or "List" respectively.
If there is no format name, the format defaults to "Default".
There are no contents for a basic node.
If the contents are branches, they are represented using whole tree mode as defined above. Notice that the contents are either all branches or all non-branches.
No branch, item, or basic can begin with NODATA or CLASSDATA, so the parsing of the contents can go on until it encounters one of these ops.
Text node
text = OP [if OP.class then className] [if OP.format then formatName]
[if OP.runs then runs] [if OP.comment then text] [if OP.props then {prop} ENDPROPS]
The OP has bits for presence of class name, format name, runs, and properties.
There is also a comment bit saying whether or not this is a comment node. If it is, the text appears in the control info.
Miscellaneous
item = text | box | list
prop = PROPERTY propertyName propertyValueSpecs | APPLICATION | FORMAL
runs = numberOfRuns {run}
run = (lookSeq | NOLOOKS) runLength
lookSeq = {addLooks} lastLooks
addlooks = BYTE [addLooksFirst..addLooksLast]
lastLooks = BYTE [lastLooksFirst..lastLooksLast]
T2FileOps: CEDAR DEFINITIONS = BEGIN
General definitions
classBit: CARDINAL = 1;    -- non-default class name
formatBit: CARDINAL = 2;   -- non-default format name
commentBit: CARDINAL = 4;  -- comment property set true
runsBit: CARDINAL = 8;    -- text node has looks runs
propsBit: CARDINAL = 16;   -- text node has properties
Op: TYPE = CHAR;
General ops
ENDOFFILE: Op = 0C;
NOCHILD: Op = ENDOFFILE+1;
BRANCHCONTENTSPECS: Op = NOCHILD+1;
CHILDSPECS: Op = BRANCHCONTENTSPECS+1;
ITEMCONTENTSPECS: Op = CHILDSPECS+1;
STARTC: Op = ITEMCONTENTSPECS+1;
ENDC: Op = STARTC+1;
STARTBR: Op = ENDC+1;
ENDITEMS: Op = STARTBR+1;
NODATA: Op = ENDITEMS+1;
CLASSDATA: Op = NODATA+1;
ENDPROPS: Op = CLASSDATA+1;
PROPERTY: Op = ENDPROPS+1;
APPLICATION: Op = PROPERTY+1;
FORMAL: Op = APPLICATION+1;
Looks related ops
numLooks: CARDINAL = 48; -- reserve extra 16 bits for future use such as OS character set
NOLOOKS: Op = FORMAL+1;
addLooksFirst: Op = NOLOOKS+1;
addLooksLast: Op = addLooksFirst+numLooks-1;
lastLooksFirst: Op = addLooksLast+1;
lastLooksLast: Op = lastLooksFirst+numLooks-1;
Branch nodes
branch: Op = lastLooksLast+1;
lastBranch: Op = branch+commentBit*2-1;
Text nodes
text: Op = lastBranch+1;
lastText: Op = text+propsBit*2-1;
List nodes
list: Op = lastText+1;
lastList: Op = list+commentBit*2-1;
Box nodes
box: Op = lastList+1;
lastBox: Op = box+commentBit*2-1;
Basic nodes
basic: Op = lastBox+1;
lastBasic: Op = basic+commentBit*2-1;
Lengths
lengths are given in as few bytes as possible according to following scheme
first bit of each byte tells if other bytes follow (up to 4 bytes max)
concat other 7 bits of bytes with leading 0's to form length
thus can represent lengths up to 2**28-1 if use 4 bytes
lengths of 127 or less fit in 1 byte
lengths in [128..4095] fit in 2 bytes
IntBytes: TYPE = MACHINE DEPENDENT RECORD [
first (0:9..15): [0..127] ← 0, -- first byte written on file
second (0:2..8): [0..127] ← 0, -- second byte written
thirdBottom (0:0..1): [0..3] ← 0, -- bottom bits of third byte written
thirdTop (1:11..15): [0..31] ← 0, -- top bits of third byte written
fourth (1:4..10): [0..127] ← 0, -- fourth byte written
unused (1:0..3): [0..15] ← 0 -- these are always 0
];
LengthByte: TYPE = MACHINE DEPENDENT RECORD [
unused (0:0..7): [0..255] ← 0,
others (0:8..8): BOOLEANFALSE, -- tells if other bytes are present
data (0:9..15): [0..127] ← 0];
ThirdByte: TYPE = MACHINE DEPENDENT RECORD [
unused (0:0..7): [0..255] ← 0,
others (0:8..8): BOOLEANFALSE,
dataTop (0:9..13): [0..31] ← 0, -- top 5 bits of data
dataBottom (0:14..15): [0..3] ← 0 -- bottom 2 bits of data
];
Trailer info
controlTrailerId: CHAR = 232C;
DataPaddedFlag: CHAR = 205C;
DataUnpaddedFlag: CHAR = 250C;
versionNumber: CHAR = 2C;
Trailer flags
isBranchFlagBit: CARDINAL = 1;
END.