Apple II
File Type Notes
_____________________________________________________________________________
                                                  Developer Technical Support


File Type:         $54 (84)
Auxiliary Type:    $DD3E

Full Name:     Medley Desktop Publishing Document
Short Name:    Medley Document

Written by:    Matt Deatherage & Eric Soldan                         May 1989

Files of this type and auxiliary type contain documents for Medley(TM).
_____________________________________________________________________________

Medley is a WYSIWYG application that integrates word processing, paint, and 
page layout programs, with the addition of a spelling checker and thesaurus.  
The page layout function supports various shapes for art and text areas.  Text 
automatically wraps around or within these areas, including irregularly shaped 
regions.  The word processor is full-featured, as is the paint program.  The 
dictionary has 80,000 words.

For more information on Medley, contact:

                Milliken Publishing Company
                1100 Research Blvd.
                St. Louis, MO  63132
                Attention:  Medley Technical Support
                (314) 991-4220

The Medley file format is copyrighted (C) 1988 by Milliken Publishing Company 
and is printed here with permission.

Definitions

The following definition is used in this document in addition to those defined 
for all Apple II file types:

C String    A series of ASCII bytes terminated with a byte of $00.  
            There is no count byte at the beginning, as is the case for 
            the String type (also referred to as a "Pascal string").


File Structure

Medley files are basically standard, single-linked tree structures.  There is 
a single object at the top of the tree, and other objects may branch off this 
parent object.  Each child object is linked to the parent by a pointer to the 
child contained within the parent object.  A non-standard thing about the 
Medley tree structure is that some objects may have regions or polygons 
associated with them.  The handles to these objects are stored in the parent 
object when in memory, but on disk these handles are quite meaningless.  
Because of this difference, the regions or polygons are simply appended to the 
parent object itself when written to disk.  The size of the region or polygon 
is added to the size of the parent object, giving an aggregate size for the 
complex object on disk.

The file is written to disk in an order based on a simple tree-walking 
algorithm.  This algorithm starts with the highest parent object and writes it 
to disk.  The parent object is checked for child objects.  If one exists, it 
is written to disk, and then it is checked for child objects.  This tree-
walking continues until an object runs out of children.  When that occurs, 
Medley backs up one tree level, writes the next child object to disk, and 
scans it for children.  This method continues until all objects are written to 
disk.

For example, if a parent object named A had two child objects named B and C, 
where B had children E and F, and C had children G and H, the objects would be 
written to disk in the following order:  A, B, D, E, C, F, G.  Figure 1 
illustrates this structure.
                                 _________
                                |         |
                                |    A    |
                                |_________|
                     |---------------|---------------|
                 ____|____                       ____|____ 
                |         |                     |         |
                |    B    |                     |    C    |
                |_________|                     |_________|
             |-------|-------|---------------|-------|-------|
         ____|____       ____|____       ____|____       ____|____
        |         |     |         |     |         |     |         |
        |    D    |     |    E    |     |    F    |     |    G    |
        |_________|     |_________|     |_________|     |_________|

             Figure 1-Example of Parent and Child Tree Structure

Some Medley objects, when in memory, have handles to other objects (such as 
regions or polygons) in them.  Since handles are meaningless on disk, Medley 
stores these complex objects in an aggregate form by writing the contents of 
each associated handle to disk following the regular object.

The Objects and Their Formats

All objects have a common 13-byte header, which is as follows:

type           (+000)    Byte    The type of the object.   Possible 
                                 values are:
                                 0 = Null Object (never saved to disk)
                                 1 = Root Object (never saved to disk)
                                 2 = File Object
                                 3 = Page Object
                                 4 = Paragraph Object
                                 5 = Area Object
                                 6 = Art Object
                                 10 = Document Dictionary Object.
                                 Objects 7, 8 and 9 are for posting 
                                 undo events.  Since these are not 
                                 saved to disk, they are irrelevant 
                                 for the file format.
numChildren    (+001)    Word    The number of children for this 
                                 object.  Children of the children 
                                 are not included.
endData        (+003)    Long    The size of this object on the 
                                 disk, not counting associated 
                                 handles (such as regions and 
                                 polygons).
reserved       (+007)    Long    Reserved; set to zero when 
                                 creating files.
objRefNum      (+011)    Word    The reference number of this 
                                 object, generally zero.

Each object has the header listed above followed by object-specific data.  For 
this reason, the description of each object will start with offset +013 (the 
byte following the header).

The File Object

rect           (+013)    4 Words Standard QuickDraw II rectangle, 
                                 giving the boundary rectangle for 
                                 the entire file.
pathName       (+021)  129 Bytes Class zero pathname for the 
                                 file on disk (used by the save 
                                 command).
saved          (+150)    Byte    This byte is 1 if no changes have 
                                 been made to the file since the last 
                                 save.
windowPtr      (+151)    Long    Pointer to the window for this 
                                 file.  When creating files, set to 
                                 zero.
wndwNameIndx   (+155)    Byte    Index into table of window 
                                 names.  Set to zero when creating 
                                 files
windowOrigin   (+156)    2 Words QuickDraw II point 
                                 representing the global origin of 
                                 this file's window.
windowSize.h   (+160)    Word    Height of window in pixels.  
                                 Add to top edge of window to get 
                                 bottom edge of window.
windowSize.v   (+162)    Word    Height of window in pixels.  
                                 Add to left of window to get right 
                                 edge of window.
COrigin        (+164)    Long    QuickDraw II point representing the 
                                 scroll bar origin of this file's 
                                 window.  When creating files, set 
                                 this to whatever origin you wish 
                                 Medley to display.  Make sure that 
                                 the coordinate is valid.
editHndl       (+168)    Long    Handle to the paragraph containing 
                                 the cursor.  This is converted to a 
                                 child number on disk, since handles 
                                 on disk are meaningless.
editOffset     (+172)    Word    Offset to the cursor within the 
                                 paragraph pointed to by editHndl.
cursor         (+174)    4 Words Standard QuickDraw II rectangle, 
                                 giving the rectangle used for the 
                                 insert cursor.  This can be set to a 
                                 null rectangle when creating files, 
                                 and will be calculated when the file 
                                 is loaded.
showAllBorders (+182)    Byte    If this is set to one, then 
                                 all area borders will display, 
                                 regardless of each area's border 
                                 display setting.
updateRect     (+183)    4 Words Standard QuickDraw II 
                                 rectangle used for posting specific 
                                 updates for the interruptible word 
                                 processor.  When creating files, set 
                                 this to a null rectangle.
topMrgn        (+191)    Fixed   The top margin in inches.
bottomMrgn     (+195)    Fixed   The bottom margin in inches.
leftMrgn       (+199)    Fixed   The left margin in inches.
rightMrgn      (+203)    Fixed   The right margin in inches.
gutterMrgn     (+207)    Fixed   The gutter margin in inches.
pageWidth      (+211)    Fixed   The width of the page in inches.
pageHeight     (+215)    Fixed   The height of the page in 
                                 inches.
selectPage     (+219)    Word    The active page for area 
                                 editing.
numSelected    (+221)    Word    The number of areas currently 
                                 selected by the user.
sizingDot      (+223)    Word    The sizing dot number of an area 
                                 that was last clicked.  This sizing 
                                 dot will be used as the current 
                                 sizing dot when the arrows are used 
                                 to size an area.
effectivePage  (+225)    Word    The page number of the page 
                                 the user was effectively editing.  
                                 This is different from selectPage 
                                 when the user was editing global 
                                 areas at save time, for global areas 
                                 are treated as on page zero.
printRecord    (+227)  140 Bytes A standard IIGS Print 
                                 Manager print record; the one in use 
                                 for this document at save time.  
                                 This field can be undefined, if the 
                                 printRecordDefined field is zero.
interruptMode  (+367)    Word    Currently undocumented.  (Set 
                                 to zero.)
editScroll     (+369)    Byte    Currently undocumented.  (Set to 
                                 zero.)
firstHndl      (+370)    Long    Handle where wrap-around regions 
                                 should actually start; i.e., where 
                                 an update is needed.  When creating 
                                 files, set this to zero.
firstMrn       (+374)    Word    MiniRect number (line number of 
                                 paragraph) where wrap-around regions 
                                 should actually start; i.e., where 
                                 an update is needed.  When creating 
                                 files, set this to zero.
selectMode     (+376)    Word    Some text is selected if this is 
                                 1.  Each paragraph will indicate the 
                                 range of characters selected within 
                                 that paragraph.  This allows the 
                                 screen update routine to quickly 
                                 determine which characters in a 
                                 paragraph should be drawn selected.
showPgphMarks  (+378)    Byte    Indicates whether paragraph 
                                 marks are currently being shown.
showSpaces     (+379)    Byte    Indicates whether spaces are 
                                 shown with marks and tabs are shown 
                                 with arrows.
showMoveChangeInfo
               (+380)    Byte    Indicates whether the Move/Change window 
                                 is active.
moveChangeInfoRect
               (+381)    4 Words Standard QuickDraw II Rectangle giving 
                                 the position of the Move/Change 
                                 window.
addNewUndo     (+389)    Byte    Currently undocumented.
revNum         (+390)    Word    Revision number of the version of 
                                 Medley that created this file.  For 
                                 files created following this 
                                 standard, use $0100 (for Medley 
                                 2.0).
showRulers     (+392)    Byte    Indicates whether the rulers are 
                                 showing.
windowType     (+393)    Word    The type of window this is.  0 = 
                                 document, 1 = clipboard.  When 
                                 creating files, set this to zero.
auxDictPath    (+395)  129 Bytes Class zero GS/OS pathname 
                                 to the auxiliary dictionary file for 
                                 this document.  When creating files, 
                                 set this to a null pathname (a 
                                 length byte of zero).
grayScale      (+524)    Word    Whether or not grayScale mode is 
                                 active.  Zero for color, one for 
                                 grayScale.
printRecordDefined
               (+526)    Word    Non-zero if a print record is defined.  
                                 This is used because the Printer and 
                                 Port drivers must be loaded before 
                                 calling PrDefault or PrValidate, and 
                                 that means the boot disk must be on 
                                 line.  If Medley knows the print 
                                 record is good, it proceeds without 
                                 calling the Print Manager.
evenPageNumText
               (+528)   48 Bytes The text for even-numbered pages to be 
                                 displayed by the page number.
oddPageNumText
               (+576)   48 Bytes The text for odd-numbered pages to be 
                                 displayed by the page number.
pageNumInfo    (+624)   32 Words A word for each of the 
                                 pages possible in the file, through 
                                 the absolute maximum of thirty-two.
affectPageRange(+688)    2 Bytes The range of pages 
                                 affected by the Medley "Change Page 
                                 Numbers" command.  The first byte is 
                                 the beginning page; the second byte 
                                 is the ending page.
pageNumFont    (+690)    4 Bytes A Font Manager FontID, 
                                 identifying the font used for the 
                                 page numbers.  This is a two-byte 
                                 font family number, followed by a 
                                 one-byte font style and one-byte 
                                 font size.
startPageNum   (+694)    Word    The page number of the first 
                                 page.  This is a zero-based counter; 
                                 page one is represented as zero.
offsetFromEdge (+696)    Word    The distance in points that 
                                 the page numbering text appears from 
                                 the edge of the paper.

Note:    The following three fields are in Medley 2.0 files, but do not 
         exist in Medley 1.0 files.  If you are reading a 1.0 file, the 
         value of revNum will be $0000.  If reading a 1.0 File Object, 
         resize it to 2.0 size (including the three fields below) and 
         initialize their values to the values given below.

maxNumPages    (+698)    Word    The maximum number of pages in 
                                 this document.  When creating new 
                                 files, initialize this to 32 ($20) 
                                 unless condensed (below) is non-
                                 zero.  If condensed is non-zero, you 
                                 really have to hurt yourself to get 
                                 this field right.  Below is the 
                                 algorithm Medley uses to calculate 
                                 this field (in something close but 
                                 not exactly related to pseudo-code).  
                                 Please recall that all variables 
                                 relating to the margins (taken from 
                                 the file object) are Fixed.

workHeight := topMrgn + bottomMrgn
if [condensed is non-zero] then workHeight := workHeight * 2
workHeight := pageHeight - workHeight
workHeight := workHeight * [pixels per vertical inch]
workHeight := workHeight + $0000FFFF
[this counts a fractional point as a whole point]
i := HiWord(workHeight) [this gives the integer portion]
i := i + 3 [accounts for 3-pixel page breaks]
i := (16384 - 208) / i [gives number of pages in conceptual 
drawing space.  Since Medley allows 48-point characters plus 
leading, the tallest a text rectangle may be is 208 pixels.  Text 
that does not fit in maxNumPages is kept around in a non-
displayable, non-editable, non-printable page.  Any shortening of 
the document will cause some or all of the previously non-
displayed text to flow up into the document.]
i := min(32,i) [32 is the absolute maximum number of pages Medley 
allows due to QuickDraw's conceptual drawing space limitations.]

maxNumPages := i

condensed      (+700)    Word    Indicates whether the document is 
                                 designed to use condensed printing.  
                                 If non-zero, the document is 
                                 designed to use condensed printing.  
                                 When creating files, it is easiest 
                                 not to deal with condensed printing, 
                                 so set this field to zero.  However, 
                                 if you wish to create a document 
                                 that Medley may edit and print as 
                                 condensed, you must correctly relate 
                                 this field to the previous one by 
                                 the algorithm given above.
reserved       (+702)    6 Bytes These six bytes should be set 
                                 to zero.


The Page Object

Pages are the first-level children of files.  There is one page object for 
each page in a document (file object).

rect           (+013)    4 Words Standard QuickDraw II rectangle 
                                 giving the boundary rectangle for 
                                 this page.
wrapDir        (+021)    Byte    The direction of word-wrapping.
                                 1 = Down, 2 = across.
rgn            (+022)    Long    Handle to the region for this page in 
                                 memory.  The region is the page 
                                 rectangle less any areas on that 
                                 page.  Global areas are not 
                                 subtracted from this region.  They 
                                 are subtracted from the page 
                                 rectangle for the global page (page 
                                 zero).  On disk, where the page 
                                 region would be written, you can 
                                 write a 10, followed by the 
                                 rectangle for the page.  This is a 
                                 rectangular region.  The aggregate 
                                 size of the page object on disk must 
                                 include these 10 bytes.  This is 
                                 assuming, of course, that there are 
                                 no areas on that page to make the 
                                 page region non-rectangular.
hideGlobalArt  (+026)    Byte    A non-zero value indicates 
                                 that global art is not displayed on 
                                 this page.
hideGlobalPageParts
               (+027)    Byte    A non-zero value indicates that global 
                                 page parts are not displayed on this 
                                 page.

The Paragraph Object

Paragraphs are the children of the file object; they are not the children of 
page objects since a paragraph may be seen on more than one page or page part.  
Paragraph objects are, however, stored on disk immediately following page 
objects and their children.  Paragraph objects are first-level objects also.

wrapHere       (+013)    Word    Insertion offset point in 
                                 paragraph data where wrapping should 
                                 continue.  For wrapping from 
                                 beginning of paragraph, set this 
                                 field to zero.
fullWrap       (+015)    Word    Same as wrapHere, but indicates at 
                                 what point miniRect construction or 
                                 reconstruction must continue.  
                                 Again, for full-wrapping of a 
                                 paragraph, set to zero.
rulerOffset    (+017)    Word    Offset in bytes from beginning 
                                 of paragraph object to indicate 
                                 where the ruler starts.  (The ruler 
                                 is just before the character data, 
                                 just after the miniRects.)  If there 
                                 is no ruler, then the default ruler 
                                 is used by Medley.  (If the 
                                 dataOffset value is the same as the 
                                 rulerOffset, then there is no ruler, 
                                 and the default ruler will be used.)  
                                 The default ruler has tabs at each 
                                 1/2 inch mark, no indent or 
                                 paragraph indent, and the right 
                                 margin is at maximum.
dataOffset     (+019)    Word    Offset in bytes from beginning 
                                 of paragraph object to indicate 
                                 where character data starts.  If 
                                 there are no miniRects built yet 
                                 (probable if file is being created 
                                 outside Medley) and there is no 
                                 ruler, then this value will be a 32.
numRects       (+021)    Word    The number of discrete text 
                                 rectangles in this paragraph.  When 
                                 creating a file, set fullWrap to 
                                 zero, and numRects to zero, and 
                                 place your character data starting 
                                 at byte 32 of a paragraph object, 
                                 and the rectangles will be built 
                                 when the file is loaded by Medley as 
                                 wrap occurs.
begInvOffset   (+023)    Word    Offset from the beginning of 
                                 the character data where inverse 
                                 text starts in this paragraph.
endInvOffset   (+025)    Word    Offset from the beginning of 
                                 the character data where inverse 
                                 text ends in this paragraph.
topLeading     (+027)    Byte    The number of pixels leading 
                                 above each line in this paragraph.
botLeading     (+028)    Byte    The number of pixels leading 
                                 below each line in this paragraphs.
begPgphGap     (+029)    Byte    The number of pixels extra 
                                 leading above this paragraph.
endPgphGap     (+030)    Byte    The number of pixels extra 
                                 leading below this paragraph.
flags          (+031)  Flag Byte Bits 0 and 1 are used to 
                                 indicate justify mode.
                                 00 = left justify.
                                 01 = right justify.
                                 10 = center justify.
                                 11 = full justify.
                                 Bit 7 indicates a page-break after
                                 this paragraph.
miniRects      (+032)  MiniRects Any miniRects, if any, are 
                                 contained here.  The number of 
                                 miniRects is given by numRects 
                                 above.

MiniRects have the following format:

miniRect.rect  (+000)    4 Words Standard QuickDraw II 
                                 rectangle that is calculated by the 
                                 wordWrap routine to bound a line of 
                                 text.
mr.begOffset   (+008)    Word    Offset from start of character 
                                 data to the first character this 
                                 miniRect bounds.
mr.endOffset   (+010)    Word    Offset from start of character 
                                 data to just past the last character 
                                 this miniRect bounds.

A Ruler in the document will be after the miniRects, if there are 
any.  The offset to the Ruler is given by rulerOffset.  Rulers are 
formatted as follows:

leftPgphMrgn   (+000)    Byte    The left margin for this 
                                 paragraph, in sixteenths of an inch.
rightPgphMrgn  (+001)    Byte    The right margin for this 
                                 paragraph, in sixteenths of an inch.  
                                 This is an offset from the default 
                                 right margin from Medley's "Set 
                                 margins" command.  For example, the 
                                 value 16 represents a right margin 
                                 one inch to the left of the default 
                                 right margin.
pgphIndent     (+002)    Byte    The indentation for this 
                                 paragraph, in sixteenths of an inch.
numTabs        (+003)    Byte    The number of tabs in this ruler.
tabs           (+004)    Tabs    There are numTabs of these.

Tabs are formatted as follows:

tab            Flag Word         Tabs consist of a high byte of flags 
                                 and low byte of position.  The bits 
                                 are assigned as follows:
                                 Bits 15-12 = Reserved; set to zero.
                                 Bits 11-10 = Tab Leader style:
                                            00 = No leader
                                            01 = Leader of dots (.......)
                                            10 = Leader of dashes ( - - )
                                            11 = Solid Leader (_________)
                                 Bits 9-8 = Tab Type:
                                            00 = Left Tab
                                            01 = Right Tab
                                            10 = Center Tab
                                            11 = Decimal Tab
                                 Bits 7-0 = Byte value; the 
                                            position of this tab as an 
                                            offset from the left 
                                            margin in sixteenths of an 
                                            inch.  A value of sixteen 
                                            indicates a tab one inch 
                                            to the right of the left 
                                            margin.

Following miniRects and rulers is the actual character data for 
this paragraph.  This is all Bytes.  However, a Byte value of 
$01 through $07 indicates the beginning of a Font Escape.  Font 
Escapes indicate changes in style or size of the text, and are 
formatted as follows:

FontEscape     (+000)    Byte    An indication of the type of 
                                 text the following fontID affects:
                                 1 = Regular Text
                                 2 = Superscript Text
                                 3 = Subscript Text
                                 4-7 = Reserved; do not use
fontID         (+001)    4 Bytes A Font Manager FontID, 
                                 identifying the font used for the 
                                 page numbers.  This is a two-byte 
                                 font family number, followed by a 
                                 one-byte font style and one-byte 
                                 font size.

The text portion of a paragraph always begins with a Font Escape 
and ends with the end-of-paragraph character Byte $A6.  This 
makes the minimum size of a paragraph (assuming no miniRects or 
rulers) thirty-eight bytes (32 bytes for the Paragraph Object, 
five bytes for the Font Escape and one byte for the $A6).


The Area Object

Area Objects are the children of pages or paragraphs.

type           (+013)    Byte    The type of area this area object 
                                 describes.  Possible values are:
                                 0 = Null Area
                                 1 = Group Area
                                 2 = Rectangular Area
                                 3 = Round Rectangular Area
                                 4 = Oval Area
                                 5 = Polygon Area
select         (+014)    Byte    This value is one if this area is 
                                 selected.
showBorder     (+015)    Byte    This value is one if the border 
                                 of this area is showing.
contentType    (+016)    Byte    0 = Art, 1 = Wrap Down,
                                 2 = Wrap Across.
rgn            (+017)    Long    Handle to the region that describes the 
                                 shape of this area.  On disk, this 
                                 region is at the end of this object 
                                 (see the Reading The File section of 
                                 this Note).
interiorRgn    (+021)    Long    Handle to the regions that 
                                 describes the interior of this area.  
                                 On disk, this region is at the end 
                                 of this object (see the Reading The 
                                 File section of this Note).
sizingRgn      (+025)    Long    Handle that contains all the 
                                 sizing dots.  It is too slow to draw 
                                 them one at a time.  Also, detecting 
                                 that the user clicked in a sizing 
                                 dot can be done quickly -- just not 
                                 which one.
flags          (+029)    Word    Only bit zero of this word is 
                                 significant; if set it indicates 
                                 this area should be printed to 
                                 LaserWriters in gray-scale.  All 
                                 other bits of this word should be 
                                 zero.
reserved       (+031)    Word    Reserved for Milliken.  Set to 
                                 zero.

At this point is the description of the area itself.  This 
description varies on the type field above:

For rectangles (type = 2):

rect           (+033)    4 Words Standard QuickDraw II rectangle 
                                 describing the rectangle for this 
                                 area.
For round rectangle (type = 3):

rect           (+033)    4 Words Standard QuickDraw II rectangle 
                                 describing the boundary rectangle 
                                 for the round rect.
height         (+041)    Word    The height of the oval portion of 
                                 the rectangle.
width          (+043)    Word    The width of the oval portion of the 
                                 rectangle.

For ovals (type = 4):

oval           (+033)    4 Words A standard QuickDraw II rectangle 
                                 describing the bounding rectangle 
                                 for this oval.  The oval drawn is 
                                 the ellipse inscribed in this 
                                 rectangle.

For Polygons (type = 5):

polygon        (+033)    Bytes   A handle to a QuickDraw II 
                                 polygon.  This handle may be passed 
                                 to QD Polygon routines.  On disk, 
                                 this polygon is appended to the end 
                                 of this object (see the Reading The 
                                 File section on this Note).

These objects are the last items in the area object.

The Art Object

Art Objects are the children of pages, paragraphs or areas.

BBox           (+013)    4 Words A standard QuickDraw II rectangle 
                                 representing the bounding box of 
                                 this art object.
offsetFromRgn  (+021)    2 Words Normally zero.  The area 
                                 containing an art image can be grown 
                                 and shrunk.  The art within it is 
                                 not clipped to the bounding 
                                 rectangle of the area until the user 
                                 deselects the area.  (If it is saved 
                                 to disk while selected, then it is 
                                 saved unclipped).  This allows the 
                                 user to experiment with different 
                                 shapes without clipping the drawing 
                                 within.  If the drawing is to the 
                                 left of the left edge of the area, 
                                 or is above the top edge, then this 
                                 offset indicates by how much.
artImage       (+025)    Bytes   The actual bitmap of the art 
                                 image.

The Document Dictionary Object

The Document Dictionary Object is the very last child of the file object, and 
contains all the words the spelling checker should ignore even though they are 
not in the main dictionary.

count          (+013)    Word    The number of word entries in this 
                                 dictionary object.
wordList       (+015)    Word Entries    List of dictionary word 
                                         entries.

The format of word entries is as follows:

recordLength   (+000)    Byte    The length of this record.
replaceFlag    (+001)    Byte    Reserved, set to zero.
newWord        (+002)    C String    The word in question.  This 
                                     word should be counted as spelled 
                                     correctly, and is not in the Main or 
                                     Auxiliary Dictionary.  

The length of a record is the length of string plus three bytes 
(one for recordLength, one for replaceFlag, and a zero termination 
byte).


Reading the File

When reading a Medley file, objects with regions or polygons will have to be 
treated specially, since the handles in the objects are invalid and the 
regions or polygons actually follow the object in the disk file.

A sequence for reconstructing Medley files in memory is as follows:

    1.  Open the file, or set the mark to zero on an open file.
    2.  Start with a handle that is 13 ($0D) bytes long.  Pass this 
        handle to the routine starting in step three.
    3.  Save the handle passed to this routine, and read four bytes 
        from disk.  This Long is the total size of an object, including 
        any regions or polygons appended.
    4.  Read the 13-byte object header into the handle passed to this 
        routine.  The endData field of the header gives the size of the 
        object, minus any associated regions or polygons.  Resize the 
        object's handle (the handle passed to you) to this size.
    5.  Read the rest of the object (endData - 13 bytes) into the 
        object's handle.
    6.  Save the value of numChildren in a local variable and set the 
        numChildren field in the object header to zero.  The field in 
        the header represents the number of children read from disk; 
        setting this to zero properly indicates that you haven't read 
        any of the children yet.
    7.  Look at the object type field.  If the object is a file, area, 
        or page object, it may have a region associated with it.  If the 
        object is an area object, it may also have a polygon associated 
        with it (if the area type field indicates this is so).  You can 
        tell if the object has any appended structures by comparing the 
        total object size (read in step three) with the endData field 
        (read in step four); if an object has no appended structures, 
        the two values will be the same.

        If there are structures appended to the object, first zero all 
        the handles to the regions inside the object.  This allows 
        elegant error recovery if an error occurs while reading the 
        region or polygon.   When the handles are zeroed, read the next 
        two bytes from the disk.  This Word is the size of the region or 
        polygon in bytes.  Create a handle of that size, place it in the 
        object's field for this handle, and place the size Word in the 
        first two bytes of the new handle.  Now read the object from 
        disk into the new handle starting at the beginning +002 (past 
        the size Word).

        Continue in this fashion until all appended regions or polygons 
        have been read from disk.  Any appended structures will be 
        stored in the same order as their handles occur in the object.

        Note:    By zeroing the handles before reading the objects, you 
                 can return from this function with an error, and the 
                 calling routine will be able to dispose of all handles 
                 that were actually created.  The calling routine will know 
                 if a handle was actually created or not by examining the 
                 handle field in the object; NIL handles were not created.

    8.  Execute a loop for the old number of children (0 to 
        oldNumChildren-1):
    9.  Create an object that is 13 ($0D) bytes long.  Add this handle 
        to the end of the parent object that was last read.  Increment 
        the number of children.  You have just added a child into the 
        child table for an object.
   10.  Call the recursive subroutine beginning in step three, passing 
        it the handle you just created.  If it returns an error, return 
        the error.  This gets you out of the recursion with the correct 
        error, no matter how many levels deep you are.
   11.  Keep looping until out of children to read.  The EOF condition 
        does not have to be checked, since you will run out of children 
        when you reach the end of the file.  If an EOF is reached before 
        you read all the children, you did something wrong.
   12.  Return no error--the file was successfully read.
   13.  When done with all this, you will return to the code just 
        beyond step two, where you first called the recursive subroutine 
        at step three.  If an error is returned, dispose of all the 
        handles created by the recursive function.  Even if the file 
        read is aborted, the tree is complete for as much as was read.  
        (This is why the numChildren field is incremented as you read 
        the file.)  An alternate way to handle this is to use a 
        different userID for the handles created when reading the file; 
        this allows you to dispose of all of them with one DisposeAll 
        call.
  14.   Close the file if you opened it, or reset the mark to its 
        previous position if it was already open.

The entire file does not have to be read from disk.  By using the size field, 
you can skip to the next object in the file.  Using this technique, you can 
scan the file for whatever it is that interests you.

Note:    You may have noticed that objects successfully created in 
         memory will have a table of handles to children at the end.  
         Objects on disk will not have these handles, since the handles on 
         disk are meaningless.  The child handle table is reconstructed as 
         the file is loaded into memory.


Object Ordering

The file object is the first you will encounter in a Medley file.  Its 
children are ordered as follows:

Page Object--Page #0.  This is the global page object, containing all global 
                       areas.
Page Object--Page #1.  This is the page object for page #1; it must exist.

Other objects are optional, but will appear in the following order:

Page #2 through Page #n
Paragraph #1 through Paragraph #n
Dictionary Object


Some Example Structures

Medley was written mostly in C.  Below are some structures relevant to C 
programs reading Medley files.  Descriptions of the fields may be found 
earlier in this Note.

#define NULLOBJ       0    /* Object type assignments. */
#define ROOTOBJ       1    /* These are used in the deskObj 'types' field. */
#define FILEOBJ       2
#define PAGEOBJ       3
#define PGPHOBJ       4
#define AREAOBJ       5
#define ARTOBJ        6
#define DOCDICTOBJ    10

#define AREANULL      0    /* Area object sub-type assignments. */
#define AREAGROUP     1    /* These are used in the areaObj 'types' field. */
#define AREARECT      2
#define AREARRECT     3
#define AREAOVAL      4
#define AREAPOLY      5


#define medleyMainType    0x54
#define medleyAuxType     0xDD3E
#define medleyInfo        1
#define auxDictType       2


#define ARTCONTENT    0    /* These are used in the 'contentType' field of 
                              area objects.*/
#define WWDOWN        1
#define WWACROSS      2
#define LWGRAYSCALE   0x0001


#define SAMEESC       0    /* These are used in paragraph objects. */
#define FONTESC       1
#define SUPERESC      2
#define SUBESC        3
#define ESCAPES       7


#define SIZEFONTESC   5    /* More paragraph equates. */
#define ENDPGPHCHR    0xA6
#define TABCHR        9
#define SOFTHYPHEN    30
#define STICKYSPACE   31


#define PAGEBREAK     0x80  /* These are used in the pgphObj 'flags' field. */
#define LEFTJUST      0x00
#define RIGHTJUST     0x01
#define CENTERJUST    0x02
#define FULLJUST      0x03
#define JUSTTYPES     0x03

#define LEFTTAB       0x00  /* These are used in the ruler field of paragraph 
                               objects.  */
#define RIGHTTAB      0x01
#define CENTERTAB     0x02
#define DECIMALTAB    0x03
#define TABTYPES      0x03
#define NOLEADER      0x00
#define DOTSLEADER    0x01
#define DASHESLEADER  0x02
#define SOLIDLEADER   0x03

typedef struct Ruler {
       unsigned char    leftPgphMrgn;
       unsigned char    rightPgphMrgn;
       unsigned char    pgphIndent;
       unsigned char    numTabs;
       unsigned int     tab[];
} Ruler;

#define NEWREVNUM 0x0100


typedef union URect {
       Rect     rect;
       struct {
              long    p1;
              long    p2;
       } point;
       struct {
              Point   p1;
              Point   p2;
       } ele;
} URect;

typedef union UPoint {
       Point   ele;
       long    point;
} UPoint;

typedef struct region {
       unsigned int    size;
       union URect     BBox;
       int             data[];
} region;

typedef struct polygon {
       int             size;
       union URect     BBox;
       union UPoint    point[];
} polygon;

typedef union ourFontID {
       unsigned long    fid;
       struct {
              unsigned int    famNum;
              char            fontStyle;
              char            fontSize;
       } f;
} ourFontID;

struct deskObj {
      char             type;           $00
      unsigned int     numChildren;    $01
      unsigned long    endData;        $03
      unsigned long    reserved;       $07
      unsigned int     objRefNum;      $0B
                                       $0D

    union d {
        data[];           /*  Plain label object access field.  */

        struct file {           /*  Level 1 objects are files.  */
              union URect       rect;                    /* $0D */
              char              pathName[129];           /* $15 */
              char              saved;                   /* $96 */
              GrafPortPtr       windowPtr;               /* $97 */
              char              windowNameIndx;          /* $9B */
              long              windowOrigin;            /* $9C */
              long              windowSize;              /* $A0 */
              long              COrigin;                 /* $A4 */
              struct deskObj    **editHndl;              /* $A8 */
              unsigned int      editOffset;              /* $AC */
              union URect       cursor;                  /* $AE */
              char              showAllBorders;          /* $B6 */
              union URect       updateRect;              /* $B7 */
              unsigned long     topMrgn;                 /* $BF */
              unsigned long     bottomMrgn;              /* $C3 */
              unsigned long     leftMrgn;                /* $C7 */
              unsigned long     rightMrgn;               /* $CB */
              unsigned long     gutterMrgn;              /* $CF */
              unsigned long     pageWidth;               /* $D3 */
              unsigned long     pageHeight;              /* $D7 */
              int               selectPage;              /* $DB */
              int               numSelected;             /* $DD */
              int               sizingDot;               /* $DF */
              int               effectivePage;           /* $E1 */
              PrRec             printRecord;             /* $E3 */
              int               interruptMode;           /* $16F */
              char              editScroll;              /* $171 */
              struct deskObj    **firstHndl;             /* $172 */
              int               firstMrn;                /* $176 */
              unsigned int      selectMode;              /* $178 */
              char              showPgphMarks;           /* $17A */
              char              showSpaces;              /* $17B */
              char              showMoveChangeInfo;      /* $17C */
              union URect       moveChangeInfoRect;      /* $17D */
              char              addNewUndo;              /* $185 */
              unsigned int      revNum;                  /* $186 */
              char              showRulers;              /* $188 */
              unsigned int      windowType;              /* $189 */
              char              auxDictPathname[129];    /* $18B */
              unsigned int      grayScale;               /* $20C */
              unsigned int      printRecordDefined;      /* $20E */
              char              evenPageNumText[48];     /* $210 */
              char              oddPageNumText[48];      /* $240 */
              unsigned int      pageNumInfo[MAXNUMPAGES];/* $270 */
              unsigned int      affectPageRange;         /* $2B0 */
              ourFontID         pageNumFont;             /* $2B2 */
              unsigned int      startPageNum;            /* $2B6 */
              unsigned int      offsetFromEdge;          /* $2B8 */
              unsigned int      maxNumPages;             /* $2BA */
              unsigned int      condensed;               /* $2BC */
              char              reserved[6];             /* $2BE */
        } file;                                          /* $2C4 */

        struct page {
              union URect       rect;                    /* $0D */
              char              wrapDir;                 /* $15 */
              region            **rgn;                   /* $16 */
              char              hideGlobalArt;           /* $1A */
              char              hideGlobalPageParts;     /* $1B */
        } page;                                          /* $1C */

        struct pgph {          /*  Must be level 2 or greater.  */
              unsigned int      wrapHere;                /* $0D */
              unsigned int      fullWrap;                /* $0F */
              unsigned int      rulerOffset;             /* $11 */
              unsigned int      dataOffset;              /* $13 */
              unsigned int      numRects;                /* $15 */
              unsigned int      begInvOffset;            /* $17 */
              unsigned int      endInvOffset;            /* $19 */
              char              topLeading;              /* $1B */
              char              botLeading;              /* $1C */
              char              begPgphGap;              /* $1D */
              char              endPgphGap;              /* $1E */
              char              flags;                   /* $1F */
            struct miniRect {                            /* $20 */
                  union URect     rect;
                  unsigned int    begOffset;
                  unsigned int    endOffset;
            } miniRect[];
/*    Ruler goes here if there is a custom ruler for this paragraph.*/
/*    Text starts after the ruler.  Text always 
      starts with a fontEsc.  A fontEsc is 5 bytes, 
      a typeByte followed by the fontID.  Text 
      always ends with end-of-pgph chr. */
        } pgph;                                          /* $20 */

        struct area {
              char              type;                    /* $0D */
              char              select;                  /* $0E */
              char              showBorder;              /* $0F */
              char              contentType;             /* $10 */
              region            **rgn;                   /* $11 */
              region            **interiorRgn;           /* $15 */
              region            **sizingRgn;             /* $19 */
              unsigned int      flags;                   /* $1D */
              unsigned int      reserved;                /* $1F */
            union obj {
                union  URect    rect;                    /* $21 */
                struct rrect {
                       union URect     rect;             /* $21 */
                       int             height;           /* $29 */
                       int             width;            /* $2B */
                } rrect;
                union  URect    oval;                    /* $21 */
                polygon         **poly;                  /* $21 */
            } obj;
        } area;                                          /* $2D */

        struct art {
              union URect     BBox;                      /* $0D */
              union UPoint    offsetFromRgn;             /* $15 */
              char            artImage[];                /* $19 */
        } art;

        struct docDict {
              unsigned int    count;                     /* $0D */
              char            wordList[]                 /* $0F */
        } docDict;                                       /* $0F */

    } d;
};