DIRECTORY Atom USING [MakeAtom], NameSymbolTable USING [MakeName], NodeProps USING [DoSpecs, GetProp, PutProp], CreateNode, Rope USING [ROPE], RopeEdit USING [Substr], RopeReader USING [Backwards, BumpIndex, FreeRopeReader, Get, GetIndex, GetRopeReader, GetString, Peek, Position, Ref, SetIndex, SetPosition], T2FileOps, TiogaLooks USING [BaseRuns, Look, Looks, noLooks, Runs], TiogaLooksOps USING [Concat], TiogaLooksSupport USING [Short, NewBase], TiogaBasicClass USING [BasicClass], TiogaBranchClass USING [BranchClass, branchChildrenAtom, branchContentsAtom, defaultBranchClass, Lookup], TiogaItemClass USING [ItemClass], TiogaNode USING [BasicClassID, ItemClassID, Name, Offset, Ref, RefBranchNode, RefItemNode, RefTextNode, RefBoxNode, RefBasicNode, RefListNode], TiogaNodeOps USING [FetchBasicClass, FetchItemClass, LookupBasicID, LookupItemID, NewBasicNode, NewBranchNode, NewBoxNode, NewListNode, NewTextNode], TiogaTreeOps USING [LastSibling, Parent]; CreateNodeImpl: CEDAR MONITOR IMPORTS Atom, NameSymbolTable, NodeProps, RopeEdit, RopeReader, TiogaBranchClass, TiogaLooksOps, TiogaLooksSupport, TiogaNodeOps, TiogaTreeOps EXPORTS CreateNode SHARES TiogaNode = BEGIN OPEN CreateNode; fileFormatError: PUBLIC SIGNAL = CODE; -- raised for all format faults noBranchParseInfo: PUBLIC SIGNAL = CODE; -- raised when client does not supply BranchInfo CreateFromInfo: PUBLIC PROC [rope: Rope.ROPE, textStart, textLen, controlStart, controlLen: INT] RETURNS [node: TiogaNode.Ref] = { textBuffer: REF TEXT; control: RopeReader.Ref _ RopeReader.GetRopeReader[]; text: RopeReader.Ref _ RopeReader.GetRopeReader[]; info: SpanInfo; wholeTree: BOOL _ TRUE; [textBuffer, info] _ GetStuff[wholeTree]; info.externalRepRope _ rope; info.charsStart _ textStart; info.charsLen _ textLen; info.ctrlStart _ controlStart; info.ctrlLen _ controlLen; node _ CIR[NIL, info, wholeTree, textBuffer, control, text]; RopeReader.FreeRopeReader[control]; RopeReader.FreeRopeReader[text]; FreeStuff[textBuffer, info] }; CreateInternalRep: PUBLIC PROC [br: TiogaNode.RefBranchNode] = { brInfo: SpanInfo _ NARROW[NodeProps.GetProp[br, $BranchInfo]]; copy: SpanInfo; textBuffer: REF TEXT; control: RopeReader.Ref _ RopeReader.GetRopeReader[]; text: RopeReader.Ref _ RopeReader.GetRopeReader[]; wholeTree: BOOL _ TRUE; parent: TiogaNode.Ref; IF brInfo=NIL THEN ERROR noBranchParseInfo; IF (parent _ TiogaTreeOps.Parent[br])=NIL OR (parent _ TiogaTreeOps.Parent[parent])=NIL OR (parent _ TiogaTreeOps.Parent[parent])=NIL THEN wholeTree _ FALSE; [textBuffer, copy] _ GetStuff[wholeTree]; IF wholeTree THEN { copy^ _ brInfo^; brInfo _ copy }; [] _ CIR[br, brInfo, wholeTree, textBuffer, control, text]; RopeReader.FreeRopeReader[control]; RopeReader.FreeRopeReader[text]; FreeStuff[textBuffer, copy] }; CIR: PROC [br: TiogaNode.RefBranchNode, brInfo: SpanInfo, wholeTree: BOOL, textBuffer: REF TEXT, control, text: RopeReader.Ref] RETURNS [node: TiogaNode.Ref] = { NextOp: PROC RETURNS [T2FileOps.Op] = INLINE { RETURN[RopeReader.Get[control]] }; ReadB32: PROCEDURE [] RETURNS [n: INT] = { first, second, fourth: T2FileOps.LengthByte; third: T2FileOps.ThirdByte; card: T2FileOps.IntBytes; first _ LOOPHOLE[RopeReader.Backwards[control]]; card.first _ first.data; IF ~first.others THEN RETURN [LOOPHOLE[card]]; -- value within 7 bits so terminate second _ LOOPHOLE[RopeReader.Backwards[control]]; card.second _ second.data; IF ~second.others THEN RETURN [LOOPHOLE[card]]; -- value within 14 bits so terminate third _ LOOPHOLE[RopeReader.Backwards[control]]; card.thirdBottom _ third.dataBottom; card.thirdTop _ third.dataTop; IF ~third.others THEN RETURN [LOOPHOLE[card]]; -- value within 21 bits so terminate fourth _ LOOPHOLE[RopeReader.Backwards[control]]; card.fourth _ fourth.data; RETURN [LOOPHOLE[card]] }; -- full 28 bit value ReadF32: PROCEDURE [] RETURNS [n: INT] = { first, second, fourth: T2FileOps.LengthByte; third: T2FileOps.ThirdByte; card: T2FileOps.IntBytes; first _ LOOPHOLE[RopeReader.Get[control]]; card.first _ first.data; IF ~first.others THEN RETURN [LOOPHOLE[card]]; -- value within 7 bits so terminate second _ LOOPHOLE[RopeReader.Get[control]]; card.second _ second.data; IF ~second.others THEN RETURN [LOOPHOLE[card]]; -- value within 14 bits so terminate third _ LOOPHOLE[RopeReader.Get[control]]; card.thirdBottom _ third.dataBottom; card.thirdTop _ third.dataTop; IF ~third.others THEN RETURN [LOOPHOLE[card]]; -- value within 21 bits so terminate fourth _ LOOPHOLE[RopeReader.Get[control]]; card.fourth _ fourth.data; RETURN [LOOPHOLE[card]] }; -- full 28 bit value ReadAtom: PROCEDURE [] RETURNS [ATOM] = INLINE { RETURN[Atom.MakeAtom[ReadRope[ReadF32[], control]]] }; ReadFormat: PROC RETURNS [n: TiogaNode.Name] = { len: TiogaNode.Offset _ ReadF32[]; IF len>LAST[NAT] THEN ERROR; -- too big for a format name IF len > textBuffer.maxLength THEN textBuffer _ NEW[TEXT[len]]; textBuffer.length _ 0; textBuffer.length _ RopeReader.GetString[control, textBuffer, len]; n _ NameSymbolTable.MakeName[textBuffer] }; ReadContents: PROCEDURE [parent: TiogaNode.Ref, itemClassInfo: TiogaItemClass.ItemClass _ NIL] RETURNS [head: TiogaNode.Ref] = { previous, node: TiogaNode.Ref; IF op=T2FileOps.STARTBR THEN DO -- branches current: TiogaNode.RefBranchNode _ TiogaNodeOps.NewBranchNode[]; IF previous=NIL THEN head _ current ELSE { previous.next _ current; previous.last _ FALSE }; previous _ current; [] _ CIR[current, NIL, TRUE, textBuffer, control, text]; SELECT RopeReader.Peek[control] FROM T2FileOps.NODATA, T2FileOps.CLASSDATA, T2FileOps.ENDOFFILE => { [] _ NextOp[]; current.next _ parent; RETURN }; ENDCASE; ENDLOOP; IF op=T2FileOps.ITEMCONTENTSPECS THEN { -- itemClassInfo supplied by caller ERROR } -- put in the real thing once add getContents to item class ELSE DO SELECT op FROM >= T2FileOps.text => SELECT op FROM -- text, list, box, or basic <= T2FileOps.lastText => node _ ReadTextNode[op-T2FileOps.text]; <= T2FileOps.lastList => node _ ReadNonTextNode[op-T2FileOps.list, list]; <= T2FileOps.lastBox => node _ ReadNonTextNode[op-T2FileOps.box, box]; <= T2FileOps.lastBasic => node _ ReadNonTextNode[op-T2FileOps.basic, basic]; ENDCASE => EXIT; ENDCASE => EXIT; IF previous=NIL THEN head _ node ELSE { previous.next _ node; previous.last _ FALSE }; previous _ node; op _ NextOp[]; ENDLOOP; IF node#NIL THEN node.next _ parent }; KindOfNonTextNode: TYPE = { box, list, basic }; ReadNonTextNode: PROCEDURE [offset: CARDINAL, kind: KindOfNonTextNode] RETURNS [new: TiogaNode.Ref] = { isComment, doFmt, doClass: BOOL _ FALSE; itemClassID: TiogaNode.ItemClassID; itemClassInfo: TiogaItemClass.ItemClass; basicClassID: TiogaNode.BasicClassID; classData: Rope.ROPE; ls: TiogaNode.RefListNode; bx: TiogaNode.RefBoxNode; bs: TiogaNode.RefBasicNode; { OPEN T2FileOps; IF offset >= commentBit*2 THEN ERROR fileFormatError; IF offset >= commentBit THEN { isComment _ TRUE; offset _ offset-commentBit }; IF offset >= formatBit THEN { doFmt _ TRUE; offset _ offset-formatBit }; IF offset > 0 THEN doClass _ TRUE }; SELECT kind FROM box => { new _ bx _ TiogaNodeOps.NewBoxNode[ itemClassID _ TiogaNodeOps.LookupItemID[IF doClass THEN ReadAtom[] ELSE $Box, TRUE]]; itemClassInfo _ TiogaNodeOps.FetchItemClass[itemClassID] }; list => { new _ ls _ TiogaNodeOps.NewListNode[ itemClassID _ TiogaNodeOps.LookupItemID[IF doClass THEN ReadAtom[] ELSE $List, TRUE]]; itemClassInfo _ TiogaNodeOps.FetchItemClass[itemClassID] }; basic => new _ bs _ TiogaNodeOps.NewBasicNode[ basicClassID _ TiogaNodeOps.LookupBasicID[IF doClass THEN ReadAtom[] ELSE $Basic, TRUE]]; ENDCASE => ERROR; new.comment _ isComment; IF doFmt THEN new.format _ ReadFormat[]; op _ NextOp[]; ReadProperties[new]; SELECT kind FROM box => bx.contents _ ReadContents[bx, itemClassInfo]; list => ls.contents _ ReadContents[ls, itemClassInfo]; basic => NULL; ENDCASE => ERROR; SELECT op FROM T2FileOps.NODATA => NULL; T2FileOps.CLASSDATA => classData _ ReadRope[ReadF32[], control]; ENDCASE => ERROR; SELECT kind FROM box => { IF itemClassInfo.set=NIL THEN bx.data _ classData ELSE itemClassInfo.set[bx, $Restore, classData, FALSE] }; list => { IF itemClassInfo.set=NIL THEN ls.data _ classData ELSE itemClassInfo.set[ls, $Restore, classData, FALSE] }; basic => { basicClassInfo: TiogaBasicClass.BasicClass _ TiogaNodeOps.FetchBasicClass[basicClassID]; IF basicClassInfo.set=NIL THEN bs.data _ classData ELSE basicClassInfo.set[bs, $Restore, classData, FALSE] }; ENDCASE => ERROR }; ReadSpecs: PROCEDURE RETURNS [rope: Rope.ROPE, pos, len: INT] = { len _ ReadF32[]; [rope, pos] _ RopeReader.Position[control]; RopeReader.SetIndex[control, pos+len] }; ReadProp: PROCEDURE [n: TiogaNode.Ref] = { key: ATOM _ ReadAtom[]; rope: Rope.ROPE; len, pos: INT; val: REF; [rope, pos, len] _ ReadSpecs[]; val _ NodeProps.DoSpecs[key, rope, pos, len, n]; IF val # NIL THEN NodeProps.PutProp[n, key, val] }; ReadRope: PROCEDURE [len: INT, rdr: RopeReader.Ref] RETURNS [Rope.ROPE] = { rope: Rope.ROPE; pos: TiogaNode.Offset; [rope, pos] _ RopeReader.Position[rdr]; -- find out where the start is RopeReader.SetIndex[rdr, pos+len]; -- step reader over it RETURN [RopeEdit.Substr[rope, pos, len]] -- return it }; ReadRuns: PROCEDURE [] RETURNS [lookRuns: TiogaLooks.Runs] = { pos: TiogaNode.Offset _ 0; numRuns: TiogaNode.Offset _ ReadF32[]; WHILE numRuns > 0 DO num: NAT _ TiogaLooksSupport.Short[MIN[numRuns,LAST[NAT]]]; baseRuns: TiogaLooks.BaseRuns _ TiogaLooksSupport.NewBase[num]; len: TiogaNode.Offset _ pos; numRuns _ numRuns-num; FOR i: NAT IN [0..num) DO -- run looks: TiogaLooks.Looks _ TiogaLooks.noLooks; lookLen: TiogaNode.Offset; op: CHAR; IF (op _ NextOp[]) # T2FileOps.NOLOOKS THEN DO SELECT op FROM >= T2FileOps.lastLooksFirst => { c: CHAR _ 'a+(op - T2FileOps.lastLooksFirst); IF op > T2FileOps.lastLooksLast THEN SIGNAL fileFormatError; looks[c] _ TRUE; EXIT }; >= T2FileOps.addLooksFirst => { c: CHAR _ 'a+(op - T2FileOps.addLooksFirst); looks[c] _ TRUE }; ENDCASE => SIGNAL fileFormatError; op _ NextOp[]; ENDLOOP; lookLen _ ReadF32[]; baseRuns[i] _ [pos_pos+lookLen, looks]; ENDLOOP; lookRuns _ IF lookRuns=NIL THEN baseRuns ELSE TiogaLooksOps.Concat[lookRuns,baseRuns,len,pos-len]; ENDLOOP }; ReadTextNode: PROCEDURE [offset: CARDINAL] RETURNS [item: TiogaNode.RefTextNode] = { isComment, doRuns, doFmt, doClass, doProps: BOOLEAN _ FALSE; rdr: RopeReader.Ref; { OPEN T2FileOps; IF offset >= propsBit*2 THEN ERROR fileFormatError; IF offset >= propsBit THEN { doProps _ TRUE; offset _ offset-propsBit }; IF offset >= runsBit THEN { doRuns _ TRUE; offset _ offset-runsBit }; IF offset >= commentBit THEN { isComment _ TRUE; offset _ offset-commentBit }; IF offset >= formatBit THEN { doFmt _ TRUE; offset _ offset-formatBit }; IF offset > 0 THEN doClass _ TRUE }; item _ TiogaNodeOps.NewTextNode[ TiogaNodeOps.LookupItemID[IF doClass THEN ReadAtom[] ELSE $Text, TRUE]]; item.comment _ isComment; IF doFmt THEN item.format _ ReadFormat[]; IF doRuns THEN item.runs _ ReadRuns[]; rdr _ IF isComment THEN control ELSE text; item.rope _ ReadRope[ReadF32[], rdr]; RopeReader.BumpIndex[rdr, 1]; -- skip over CR IF doProps THEN { ReadProperties[item]; IF op # T2FileOps.ENDPROPS THEN ERROR fileFormatError; op _ NextOp[] }}; ReadProperties: PROC [n: TiogaNode.Ref] = { DO SELECT op FROM T2FileOps.PROPERTY => { ReadProp[n]; op _ NextOp[] }; T2FileOps.APPLICATION => { n.templateInfo _ application; op _ NextOp[] }; T2FileOps.FORMAL => { n.templateInfo _ formal; op _ NextOp[] }; ENDCASE => RETURN; ENDLOOP }; offset: CARDINAL; isComment, doFmt, doClass: BOOLEAN _ FALSE; branchClassInfo: TiogaBranchClass.BranchClass; nKids: INT _ 0; prev, current: TiogaNode.RefBranchNode; kidCtrlStart, kidTextStart: TiogaNode.Offset; op, childOp: T2FileOps.Op; IF brInfo # NIL THEN { -- otherwise, assume readers already set at correct positions RopeReader.SetPosition[text, brInfo.externalRepRope, brInfo.charsStart]; RopeReader.SetPosition[control, brInfo.externalRepRope, brInfo.ctrlStart] }; IF br=NIL THEN RETURN [ReadContents[NIL]]; -- we're being called to read a non-branch node op _ NextOp[]; -- start of the branch info IF op NOT IN [T2FileOps.branch..T2FileOps.lastBranch] THEN ERROR fileFormatError; -- supposed to be a branch offset _ op-T2FileOps.branch; { OPEN T2FileOps; IF offset >= commentBit THEN { isComment _ TRUE; offset _ offset-commentBit }; IF offset >= formatBit THEN { doFmt _ TRUE; offset _ offset-formatBit }; IF offset > 0 THEN doClass _ TRUE }; IF doClass THEN NodeProps.PutProp[br, $BranchClass, branchClassInfo _ TiogaBranchClass.Lookup[ReadAtom[]]] ELSE branchClassInfo _ TiogaBranchClass.defaultBranchClass; IF doFmt THEN br.format _ ReadFormat[]; br.comment _ isComment; op _ NextOp[]; ReadProperties[br]; IF op=T2FileOps.BRANCHCONTENTSPECS THEN { -- contents saved in class dependent manner Insert: PROC [item: TiogaNode.RefItemNode, previous: TiogaNode.RefItemNode _ NIL] = { IF br.contents=NIL THEN br.contents _ item ELSE { IF previous=NIL THEN previous _ NARROW[TiogaTreeOps.LastSibling[br.contents]]; previous.next _ item; previous.last _ FALSE }; item.next _ br; item.last _ TRUE }; rope: Rope.ROPE; start, len: INT; [rope, start, len] _ ReadSpecs[]; op _ NextOp[]; -- the op after the specs IF branchClassInfo.setContents=NIL THEN -- trouble. save the specs NodeProps.PutProp[br, TiogaBranchClass.branchContentsAtom, RopeEdit.Substr[rope, start, len]] ELSE branchClassInfo.setContents[br, rope, start, len, Insert] } ELSE br.contents _ NARROW[ReadContents[br]]; -- narrow to item node IF (childOp _ op)=T2FileOps.NOCHILD THEN { br.internalRepCreated _ TRUE; RETURN }; IF childOp=T2FileOps.CHILDSPECS THEN { -- children saved in class dependent manner Insert: PROC [child: TiogaNode.RefBranchNode, previous: TiogaNode.RefBranchNode _ NIL] = { IF br.child=NIL THEN br.child _ child ELSE { IF previous=NIL THEN previous _ NARROW[TiogaTreeOps.LastSibling[br.child]]; previous.next _ child; previous.last _ FALSE }; child.next _ br; child.last _ TRUE }; rope: Rope.ROPE; start, len: INT; [rope, start, len] _ ReadSpecs[]; IF branchClassInfo.setChildren=NIL THEN -- trouble. save the specs NodeProps.PutProp[br, TiogaBranchClass.branchChildrenAtom, RopeEdit.Substr[rope, start, len]] ELSE branchClassInfo.setChildren[br, rope, start, len, Insert]; br.internalRepCreated _ TRUE; RETURN }; IF childOp=T2FileOps.STARTC OR ((brInfo=NIL OR wholeTree) AND childOp=T2FileOps.ENDITEMS) THEN { DO -- parse a child each time through loop current _ TiogaNodeOps.NewBranchNode[]; IF prev=NIL THEN br.child _ current ELSE { prev.next _ current; prev.last _ FALSE }; current.next _ br; prev _ current; [] _ CIR[current, NIL, TRUE, textBuffer, control, text]; nKids _ nKids+1; IF RopeReader.Peek[control]=T2FileOps.ENDC THEN { [] _ NextOp[]; EXIT }; ENDLOOP; IF childOp=T2FileOps.ENDITEMS THEN { --read and discard ctrl&data lengths and num children op _ NextOp[]; -- actually is the first byte of number info THROUGH [0..nKids*2) DO -- tricky because numbers written backwards on the file byte: T2FileOps.LengthByte _ LOOPHOLE[op]; IF byte.others THEN ERROR; DO byte _ LOOPHOLE[op _ NextOp[]]; IF ~byte.others THEN EXIT; -- this is the last byte of the next number ENDLOOP; ENDLOOP; UNTIL nKids < 128 DO [] _ NextOp[]; nKids _ nKids/128; ENDLOOP }; br.internalRepCreated _ TRUE; RETURN }; IF childOp # T2FileOps.ENDITEMS THEN ERROR fileFormatError; kidCtrlStart _ RopeReader.GetIndex[control]; -- remember where the kids start kidTextStart _ RopeReader.GetIndex[text]; RopeReader.SetPosition[control, brInfo.externalRepRope, brInfo.ctrlStart+brInfo.ctrlLen]; nKids _ ReadB32[]; THROUGH [1..nKids] DO -- create children branch nodes to be converted later crntInfo: SpanInfo _ NEW[SpanInfoRec]; current _ TiogaNodeOps.NewBranchNode[]; IF prev=NIL THEN br.child _ current ELSE { prev.next _ current; prev.last _ FALSE }; current.next _ br; prev _ current; crntInfo.externalRepRope _ brInfo.externalRepRope; crntInfo.charsLen _ ReadB32[]; crntInfo.ctrlLen _ ReadB32[]; crntInfo.ctrlStart _ kidCtrlStart ; crntInfo.charsStart _ kidTextStart ; kidCtrlStart _ kidCtrlStart + crntInfo.ctrlLen; kidTextStart _ kidTextStart + crntInfo.charsLen; NodeProps.PutProp[current, $BranchInfo, crntInfo]; current.externalRepValid _ TRUE; current.internalRepCreated _ FALSE; ENDLOOP; br.internalRepCreated _ TRUE }; text1, text2, text3: REF TEXT; -- shared text buffers info1, info2, info3: SpanInfo; -- shared SpanInfo records GetSpanInfo: ENTRY PROC RETURNS [info: SpanInfo] = { ENABLE UNWIND => NULL; IF info3 # NIL THEN { info _ info3; info3 _ NIL } ELSE IF info2 # NIL THEN { info _ info2; info2 _ NIL } ELSE IF info1 # NIL THEN { info _ info1; info1 _ NIL } ELSE info _ NEW[SpanInfoRec] }; GetStuff: ENTRY PROC [spanInfo: BOOL] RETURNS [text: REF TEXT, info: SpanInfo] = INLINE { ENABLE UNWIND => NULL; IF text3 # NIL THEN { text _ text3; text3 _ NIL } ELSE IF text2 # NIL THEN { text _ text2; text2 _ NIL } ELSE IF text1 # NIL THEN { text _ text1; text1 _ NIL } ELSE text _ NEW[TEXT[100]]; IF ~spanInfo THEN RETURN; IF info3 # NIL THEN { info _ info3; info3 _ NIL } ELSE IF info2 # NIL THEN { info _ info2; info2 _ NIL } ELSE IF info1 # NIL THEN { info _ info1; info1 _ NIL } ELSE info _ NEW[SpanInfoRec] }; FreeSpanInfo: ENTRY PROC [info: SpanInfo] = { ENABLE UNWIND => NULL; IF info3 = info OR info2 = info OR info1 = info THEN ERROR; IF info3 = NIL THEN info3 _ info ELSE IF info2 = NIL THEN info2 _ info ELSE IF info1 = NIL THEN info1 _ info }; FreeStuff: ENTRY PROC [text: REF TEXT, info: SpanInfo] = INLINE { ENABLE UNWIND => NULL; IF text3 = text OR text2 = text OR text1 = text THEN ERROR; IF text3 = NIL THEN text3 _ text ELSE IF text2 = NIL THEN text2 _ text ELSE IF text1 = NIL THEN text1 _ text; IF info=NIL THEN RETURN; IF info3 = info OR info2 = info OR info1 = info THEN ERROR; IF info3 = NIL THEN info3 _ info ELSE IF info2 = NIL THEN info2 _ info ELSE IF info1 = NIL THEN info1 _ info }; END.  CreateNodeImpl.mesa Last edited by Paxton - August 30, 1983 9:58 am The primary client interface to the tree parser If at least 3 levels deep, do the whole thing. Else keep on doing incremental parsing. Needless to say, this heuristic can be changed if a better one comes along. If the whole tree is to be cracked then there is no need to plant information blocks on each branch. Instead, a copy of the initial branch info is created and passed around the tree, the information being modified to suit the branch about to be cracked. Read a 24 bit number packed as 1..4 bytes using the given character reader. Each character provides 7 data bits and a boolean indicating whether or not it is the last in the sequence. Read a 24 bit number packed as 1..4 bytes using the given character reader. Each character provides 7 data bits and a boolean indicating whether or not it is the last in the sequence. Change this to be like ReadFormat. Want to avoid the NEW ROPE unless it is a new atom. Insert: PROC [n: TiogaNode.Ref, previous: TiogaNode.Ref _ NIL] = { IF head=NIL THEN head _ n ELSE { IF previous=NIL THEN previous _ TiogaTreeOps.LastSibling[head]; previous.next _ n; previous.last _ FALSE }; node _ n; n.last _ TRUE }; rope: Rope.ROPE; start, len: INT; [rope, start, len] _ ReadSpecs[]; op _ NextOp[]; -- the op after the specs IF itemClassInfo.getContents=NIL THEN -- trouble. save the specs NodeProps.PutProp[parent, TiogaItemClass.itemContentsAtom, RopeEdit.Substr[rope, start, len]] ELSE itemClassInfo.getContents[TiogaNodeOps.NarrowToItemNode[parent], rope, start, len, Insert] } Read a rope using given reader - reader is assumed to be positioned ready to read first character read a single byte with top bit 0; then read sequence of bytes with top bit 1 can read until see byte with top bit 0 because quaranteed to have another number following Now read as many bytes as needed to store num children (have already read first one) Êî˜Jšœ™Jšœ/™/J™JšÏk ˜ ˜Jšœœ ˜Jšœœ ˜!Jšœ œ˜,Jšœ ˜ Jšœœœ˜Jšœ œ ˜Jšœ œ+œ7œ˜Jšœ ˜ Jšœ œ(˜8Jšœœ ˜Jšœœ˜)Jšœœ˜#JšœœS˜iJšœœ ˜!Jšœ œ€˜Jšœ œƒ˜•Jšœ œ˜)J˜—šœ œ˜Jšœ‡˜ŽJšœ œ œœ ˜<—J˜Jšœ œœÏc˜FJšœ œœž0˜YJ˜š Ïnœœœ œ0œ˜`Jšœ˜!Jšœ œœ˜Jšœ5˜5Jšœ2˜2Jšœ˜Jšœ œœ˜Jšœ)˜)Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœœ.˜Jšœ˜Jšœ œœ˜Jšœ5˜5Jšœ2˜2Jšœ œœ˜J˜Jšœœœœ˜+šœ$œœ(˜WJšœ(œœ œ˜EJ™VJ™K—Jšœ)˜)šœ œ$˜5J™þ—Jšœœ3˜;Jšœ#˜#Jšœ ˜ Jšœ˜J˜—šŸœœ0˜9Jšœ œœœ ˜EJšœ˜!J™š Ÿœœœœœ˜QJ˜—šŸœ œœœ˜*J™·Jšœ,˜,Jšœ˜Jšœ˜Jšœœ ˜0J˜Jšœ œœž$˜RJšœ œ ˜1J˜Jšœ œœž%˜TJšœœ ˜0J˜$J˜Jšœ œœž%˜SJšœ œ ˜1J˜Jšœœ ž˜/J˜—šŸœ œœœ˜*J™·Jšœ,˜,Jšœ˜Jšœ˜Jšœœ˜*J˜Jšœ œœž$˜RJšœ œ˜+J˜Jšœ œœž$˜TJšœœ˜*J˜$J˜Jšœ œœž%˜SJšœ œ˜+J˜Jšœœœž˜/J˜—š Ÿœ œœœœ˜0J™WJšœ0˜6J˜—šŸ œœœ˜0Jšœ"˜"Jš œœœœœž˜9Jšœœœœ˜?Jšœ˜JšœC˜CJšœ+˜+J˜—šŸ œ œCœ˜^Jšœ˜!Jšœ˜š œœœœž ˜+Jšœ@˜@Jš œ œœœ,œ˜\Jšœ˜Jšœœ œœ˜8šœ˜$šœ œ œ œ˜?Jšœ&œ˜/—Jšœ˜—Jš˜—šœœœž#˜KšŸœœ.œ™BJšœœœ ™šœ™Jšœ œœ+™?Jšœ#œ™+—Jšœœ™—Jšœ œ™Jšœ œ™J™!Jšœž™(šœœœž™AJšœ]™]—Jšœ]™aJšœž;˜C—šœ˜šœ˜šœœž˜@Jšœ@˜@JšœK˜KJšœF˜FJšœL˜LJšœœ˜—Jšœœ˜—Jšœ œœ ˜ Jšœ)œ˜5Jšœ˜Jšœ˜Jš˜—Jšœœœ˜&J˜—šœœ˜/J˜—šŸœ œ œ˜FJšœ˜ Jšœœœ˜(Jšœ#˜#Jšœ(˜(Jšœ%˜%Jšœœ˜J˜J˜J˜Jšœœ ˜Jšœœœ˜5Jšœœœ˜NJšœœ œ˜HJšœ œ œ˜$šœ˜šœ˜šœ#˜#Jš œ(œ œ œœ˜U—Jšœ;˜;—šœ ˜ šœ$˜$Jš œ(œ œ œœ˜V—Jšœ;˜;—šœ.˜.Jš œ*œ œ œ œ˜Y—Jšœœ˜—Jšœ˜Jšœœ˜(J˜J˜šœ˜Jšœ5˜5Jšœ6˜6Jšœ œ˜Jšœœ˜—šœ˜Jšœ œ˜Jšœ œ-˜@Jšœœ˜—šœ˜šœ˜šœœœ˜6Jšœ+œ˜4——šœ ˜ šœœœ˜6Jšœ+œ˜4——šœ ˜ JšœX˜Xšœœœ˜7Jšœ,œ˜5——Jšœœ˜—J˜—š Ÿ œ œœ œ œ˜AJšœ˜Jšœ+˜+Jšœ(˜(J˜—šŸœ œ˜*Jšœœ˜Jšœ œ˜Jšœ œ˜Jšœœ˜ Jšœ˜Jšœ0˜0Jšœœœ"˜3J˜—š Ÿœ œœœœ˜KJ™aJšœ œ˜Jšœ˜Jšœ(ž˜FJšœ#ž˜9Jšœ#ž ˜5J˜J˜—šŸœ œœ ˜>Jšœ˜Jšœ&˜&šœ ˜Jš œœœ œœ˜;J˜?Jšœ˜J˜š œœœ œž˜ J˜-Jšœ˜Jšœœ˜ šœœœ˜.šœ˜šœ ˜ Jšœœ&˜-Jšœœœ˜