DIRECTORY CrRPC, IO, Rope, SerializedFiling; SerializedFilingImpl: CEDAR PROGRAM IMPORTS CrRPC, IO, Rope EXPORTS SerializedFiling ~ BEGIN OPEN SerializedFiling; STREAM: TYPE ~ IO.STREAM; Error: PUBLIC ERROR [reason: ATOM, exp: ROPE] = CODE; GetSerializedFile: PUBLIC PROC [s: STREAM] RETURNS [sfout: SerializedFile] ~ { sfout.version ¬ CrRPC.GetCard32[s]; sfout.file ¬ GetSerializedTree[s]; }; PutSerializedFile: PUBLIC PROC [s: STREAM, sfin: SerializedFile] ~ { CrRPC.PutCard32[s, sfin.version]; PutSerializedTree[s, sfin.file]; }; GetRopeContents: PUBLIC PROC [sf: SerializedFile] RETURNS [contents: ROPE] ~ { contents ¬ NIL; FOR uL: StreamOfUnspecified ¬ sf.file.content.data, uL.rest WHILE uL#NIL DO rope: ROPE ¬ RopeFromSegment[segment: uL.first, lastByteIsSignificant: uL.rest # NIL OR sf.file.content.lastByteIsSignificant]; contents ¬ Rope.Concat[base: contents, rest: rope]; ENDLOOP; RETURN[contents]; }; SetRopeContents: PUBLIC PROC [sf: SerializedFile, contents: ROPE] RETURNS [new: SerializedFile] ~ { segment: Segment; [segment, sf.file.content.lastByteIsSignificant] ¬ SegmentFromRope[contents]; sf.file.content.data ¬ LIST[segment]; RETURN[sf]; }; GetAttributeAsRope: PUBLIC PROC [sf: SerializedFile, type: AttributeType] RETURNS [value: ROPE ¬ NIL] ~ { FOR i: CARDINAL IN [0..sf.file.attributes.length) DO attr: Attribute ¬ sf.file.attributes.body[i]; IF attr.type = type THEN { value ¬ RopeFromSegment[attr.value]; EXIT; }; ENDLOOP; RETURN[value]; }; SetAttributeFromRope: PUBLIC PROC [sf: SerializedFile, type: AttributeType, value: ROPE] RETURNS [new: SerializedFile] ~ { lastByteIsSignificant: BOOL ¬ FALSE; FOR i: CARDINAL IN [0..sf.file.attributes.length) DO IF sf.file.attributes.body[i].type = type THEN { [sf.file.attributes.body[i].value, lastByteIsSignificant] ¬ SegmentFromRope[value]; EXIT; }; ENDLOOP; IF lastByteIsSignificant THEN ERROR Error[$SetAttributeFromRope, "Attributes must be an even number of bytes"]; RETURN[sf]; }; GetRopeAttribute: PUBLIC PROC [sf: SerializedFile, type: AttributeType] RETURNS [value: ROPE] = { FOR i: CARDINAL IN [0..sf.file.attributes.length) DO attr: Attribute ¬ sf.file.attributes.body[i]; IF attr.type = type THEN { segment: Segment ~ sf.file.attributes.body[i].value; s: STREAM ¬ IO.ROS[]; FOR i: CARDINAL IN [0..segment.length) DO CrRPC.PutCard16[s, segment.body[i]]; ENDLOOP; value ¬ CrRPC.GetRope[IO.RIS[IO.RopeFromROS[s]]]; EXIT; }; ENDLOOP; RETURN[value]; }; SetRopeAttribute: PUBLIC PROC [sf: SerializedFile, type: AttributeType, value: ROPE] RETURNS [new: SerializedFile] = { FOR i: CARDINAL IN [0..sf.file.attributes.length) DO IF sf.file.attributes.body[i].type = type THEN { s: STREAM ¬ IO.ROS[]; CrRPC.PutRope[s, value]; sf.file.attributes.body[i].value ¬ SegmentFromRope[IO.RopeFromROS[s]].segment; EXIT; }; ENDLOOP; RETURN[sf]; }; GetVersionedRopeAttribute: PUBLIC PROC [sf: SerializedFile, type: AttributeType] RETURNS [version: CARD16 ¬ 0, value: ROPE ¬ NIL] = { FOR i: CARDINAL IN [0..sf.file.attributes.length) DO IF sf.file.attributes.body[i].type = type THEN { segment: Segment ¬ sf.file.attributes.body[i].value; s: STREAM ¬ IO.ROS[]; FOR i: CARDINAL IN [1..segment.length) DO CrRPC.PutCard16[s, segment.body[i]]; ENDLOOP; value ¬ CrRPC.GetRope[IO.RIS[IO.RopeFromROS[s]]]; version ¬ segment.body[0]; EXIT; }; ENDLOOP; RETURN[version, value]; }; SetVersionedRopeAttribute: PUBLIC PROC [sf: SerializedFile, type: AttributeType, version: CARD16, value: ROPE] RETURNS [new: SerializedFile] = { FOR i: CARDINAL IN [0..sf.file.attributes.length) DO IF sf.file.attributes.body[i].type = type THEN { s: STREAM ¬ IO.ROS[]; CrRPC.PutCard16[s, version]; CrRPC.PutRope[s, value]; sf.file.attributes.body[i].value ¬ SegmentFromRope[IO.RopeFromROS[s]].segment; EXIT; }; ENDLOOP; RETURN[sf]; }; RopeFromSegment: PUBLIC PROC [segment: Segment, lastByteIsSignificant: BOOLEAN ¬ TRUE] RETURNS [rope: ROPE] ~ { s: STREAM ¬ IO.ROS[]; FOR i: CARDINAL IN [0..segment.length) DO CrRPC.PutCard16[s, segment.body[i]]; ENDLOOP; rope ¬ IO.RopeFromROS[s]; IF NOT lastByteIsSignificant THEN -- remove last char rope ¬ Rope.Substr[base: rope, start: 0, len: Rope.Length[base: rope]-1]; }; SegmentFromRope: PUBLIC PROC [rope: ROPE] RETURNS [segment: Segment, lastByteIsSignificant: BOOLEAN] ~ { length8: CARDINAL ¬ Rope.Length[base: rope]; length16: CARDINAL ¬ (length8+1)/2; s: STREAM; segment ¬ NEW[SegmentObject[length16]]; lastByteIsSignificant ¬ length8 MOD 2 = 0; s ¬ IO.RIS[rope: IF lastByteIsSignificant THEN rope ELSE Rope.Concat[base: rope, rest: "\000"]]; FOR i: CARDINAL IN [0..length16) DO segment.body[i] ¬ CrRPC.GetCard16[s]; ENDLOOP; }; GetSerializedTree: PROC [s: CrRPC.STREAM] RETURNS [res: SerializedTree] ~ { res.attributes ¬ GetAttributeSequence[s]; res.content.data ¬ GetStreamOfUnspecified[s]; res.content.lastByteIsSignificant ¬ CrRPC.GetBool[s]; res.children ¬ GetSerializedTreeSequence[s]; }; PutSerializedTree: PROC [s: CrRPC.STREAM, val: SerializedTree] ~ { PutAttributeSequence[s, val.attributes]; PutStreamOfUnspecified[s, val.content.data]; CrRPC.PutBool[s, val.content.lastByteIsSignificant]; PutSerializedTreeSequence[s, val.children]; }; nextSegment: CARD16 ¬ 0; lastSegment: CARD16 ¬ 1; GetStreamOfUnspecified: PROC [s: CrRPC.STREAM] RETURNS [res: StreamOfUnspecified] ~ { tail: StreamOfUnspecified ¬ NIL; res ¬ NIL; DO type: CARD16 ¬ CrRPC.GetCard16[s]; seg: Segment ¬ GetSegment[s]; IF tail = NIL THEN {tail ¬ res ¬ LIST[seg];} ELSE {tail.rest ¬ LIST[seg]; tail ¬ tail.rest;}; IF type = lastSegment THEN EXIT; ENDLOOP; }; PutStreamOfUnspecified: PROC [s: CrRPC.STREAM, val: StreamOfUnspecified] ~ { IF val = NIL THEN { CrRPC.PutCard16[s, lastSegment]; PutSegment[s, NIL]; RETURN; }; FOR uL: StreamOfUnspecified ¬ val, uL.rest WHILE uL#NIL DO CrRPC.PutCard16[s, IF uL.rest=NIL THEN lastSegment ELSE nextSegment]; PutSegment[s, uL.first]; ENDLOOP; }; GetAttributeSequence: PROC [s: CrRPC.STREAM] RETURNS [res: AttributeSequence] ~ { length16: CARDINAL ~ CrRPC.GetCard16[s]; res ¬ NEW[AttributeSequenceObject[length16]]; FOR i15: CARDINAL IN [0..length16) DO res.body[i15].type ¬ CrRPC.GetCard32[s]; res.body[i15].value ¬ GetAttributeValue[s]; ENDLOOP; }; PutAttributeSequence: PROC [s: CrRPC.STREAM, val: AttributeSequence] ~ { IF val = NIL THEN { CrRPC.PutCard16[s, 0]; RETURN; }; CrRPC.PutCard16[s, val.length]; FOR i20: CARDINAL IN [0..val.length) DO CrRPC.PutCard32[s, val.body[i20].type]; PutAttributeValue[s, val.body[i20].value]; ENDLOOP; }; GetAttributeValue: PROC [s: CrRPC.STREAM] RETURNS [res: AttributeValue] ~ { length19: CARDINAL ~ CrRPC.GetCard16[s]; res ¬ NEW[AttributeValueObject[length19]]; FOR i18: CARDINAL IN [0..length19) DO res.body[i18] ¬ CrRPC.GetCard16[s]; ENDLOOP; }; PutAttributeValue: PROC [s: CrRPC.STREAM, val: AttributeValue] ~ { IF val = NIL THEN { CrRPC.PutCard16[s, 0]; RETURN; }; CrRPC.PutCard16[s, val.length]; FOR i25: CARDINAL IN [0..val.length) DO CrRPC.PutCard16[s, val.body[i25]]; ENDLOOP; }; GetSegment: PROC [s: CrRPC.STREAM] RETURNS [res: Segment] ~ { length24: CARDINAL ~ CrRPC.GetCard16[s]; res ¬ NEW[SegmentObject[length24]]; FOR i23: CARDINAL IN [0..length24) DO res.body[i23] ¬ CrRPC.GetCard16[s]; ENDLOOP; }; PutSegment: PROC [s: CrRPC.STREAM, val: Segment] ~ { IF val = NIL THEN { CrRPC.PutCard16[s, 0]; RETURN; }; CrRPC.PutCard16[s, val.length]; FOR i22: CARDINAL IN [0..val.length) DO CrRPC.PutCard16[s, val.body[i22]]; ENDLOOP; }; GetSerializedTreeSequence: PROC [s: CrRPC.STREAM] RETURNS [res: SerializedTreeSequence] ~ { length24: CARDINAL ~ CrRPC.GetCard16[s]; res ¬ NEW[SerializedTreeSequenceObject[length24]]; FOR i23: CARDINAL IN [0..length24) DO res.body[i23] ¬ GetSerializedTree[s]; ENDLOOP; }; PutSerializedTreeSequence: PROC [s: CrRPC.STREAM, val: SerializedTreeSequence] ~ { IF val = NIL THEN { CrRPC.PutCard16[s, 0]; RETURN; }; CrRPC.PutCard16[s, val.length]; FOR i22: CARDINAL IN [0..val.length) DO PutSerializedTree[s, val.body[i22]]; ENDLOOP; }; END. ^ SerializedFilingImpl.Mesa Copyright Σ 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Doug Terry, December 19, 1989 3:06:18 pm PST Willie-Sue, March 21, 1990 12:50:23 pm PST Willie-s, December 10, 1991 2:34 pm PST Exported procedures Reads a serialized file from the stream. Writes a serialized file to the stream. Returns the contents of the serialized file as a rope. Sets the contents of the serialized file. Finds an attribute of the given type and converts its value to a rope; returns NIL if no such attribute. Sets the value of the given attribute; does nothing if the serialized file does not contain an attribute of the specified type. Finds an attribute of the given type; uses CrRPC.GetRope.; returns NIL if no such attribute. Sets the value of the given attribute, using CrRPC.PutRope; does nothing if the serialized file does not contain an attribute of the specified type. Finds an attribute of the given type, the first CARD16 read is returned as version, the rest is read using CrRPC.GetRope; returns value = NIL if no such attribute. Sets the value of the given attribute; first outputs version, then uses CrRPC.PutRope does nothing if the serialized file does not contain an attribute of the specified type. Converts a segment to a rope. Note: this also works for AttributeValues. Note: This is probably not the most efficient way to do the conversion, but it is safe. Converts a rope to a segment. Note: This is probably not the most efficient way to do the conversion, but it is safe. Marshalling routines Note: In the Cedar type defintion, a StreamOfUnspecified is simply a sequence of segments. However, in the Courier specification it is an "array" of records where each record has a 16-bit type field followed by a segment. There is no length field at the beginning. The end of the array is indicated by a type=1 (lastSegment). Κ ₯–(cedarcode) style•NewlineDelimiter ™™Jšœ Οeœ=™HIcode™,K™*K™'K˜—šΟk ˜ K˜Kšžœ˜K˜K˜—K˜šΠlnœžœž˜#Kšžœ˜Kšžœ˜—šœž˜Kšžœ˜—˜Kšžœžœžœžœ˜Kš Οnœžœžœ žœžœžœ˜5—head™š  œžœžœžœžœ˜NK™(K˜#K˜"K˜K™—š œžœžœžœ˜DK™'K˜!Kšœ ˜ K˜K˜—K˜š  œžœžœžœ žœ˜NK™8Kšœ žœ˜šžœ9žœžœž˜KKšœžœGžœžœ)˜€K•StartOfExpansion([base: ROPE _ NIL, rest: ROPE _ NIL]˜3Kšžœ˜—Kšžœ ˜K˜K˜—š  œžœžœ žœžœ˜cK™)Kšœ˜K˜MKšœžœ ˜%Kšžœ˜ K˜K˜—š  œžœžœ+žœ žœžœ˜iK™hšžœžœžœ ž˜4K˜-šžœžœ˜K˜$Kšžœ˜K˜—Kšžœ˜—Kšžœ˜K˜K™—š  œžœžœ2žœžœ˜zK™Kšœžœžœ˜$šžœžœžœ ž˜4šžœ(žœ˜0K˜SKšžœ˜K˜—Kšžœ˜—KšžœžœžœL˜oKšžœ˜ K˜K™—š  œžœžœ+žœ žœ˜aK™\šžœžœžœ ž˜4K˜-šžœžœ˜Kšœ4˜4Kšœžœžœžœ˜šžœžœžœž˜)Kšœ$˜$Kšžœ˜—Kšœžœžœžœ˜1Kšžœ˜K˜—Kšžœ˜—Kšžœ˜K˜K˜—š  œžœžœ2žœžœ˜vK™;K™Xšžœžœžœ ž˜4šžœ(žœ˜0Kšœžœžœžœ˜Kšœ˜Kšœ3žœ˜NKšžœ˜K˜—Kšžœ˜—Kšžœ˜ K˜K˜—š œžœžœ+žœ žœ žœžœ˜…Kšœ£™£šžœžœžœ ž˜4šžœ(žœ˜0K˜4Kšœžœžœžœ˜šžœžœžœž˜)Kšœ$˜$Kšžœ˜—Kšœžœžœžœ˜1K˜Kšžœ˜K˜—Kšžœ˜—Kšžœ˜K˜K˜—š  œžœžœ4žœ žœžœ˜K™UK™Xšžœžœžœ ž˜4šžœ(žœ˜0Kšœžœžœžœ˜Kšœ˜Kšœ˜Kšœ3žœ˜NKšžœ˜K˜—Kšžœ˜—Kšžœ˜ K˜K˜—š œžœžœ+žœžœžœžœ˜oKšœI™IK™WKšœžœžœžœ˜šžœžœžœž˜)Kšœ$˜$Kšžœ˜—Kšœžœ˜šžœžœžœΟc˜6K–[base: ROPE]˜I—K˜K™—š  œžœžœžœžœ+žœ˜hK™K™WK–[base: ROPE]šœ žœ˜,K–[base: ROPE]šœ žœ˜#Kšœžœ˜ Kšœ žœ˜(Kšœ žœ˜*K–([base: ROPE _ NIL, rest: ROPE _ NIL]š œžœžœžœžœžœ(˜`šžœžœžœž˜#K˜%Kšžœ˜—K˜K™——™š œžœ žœžœ˜KK˜)K˜-K˜5K˜,K˜—K˜š œžœ žœ˜BKšœ(˜(Kšœ,˜,K˜4Kšœ+˜+K˜—J™JšœΘ™ΘJ™Kšœ žœ˜Kšœ žœ˜K˜š œžœ žœžœ˜UKšœžœ˜ Kšœžœ˜ šž˜Kšœžœ˜"K˜šžœž˜ Kšžœžœ˜Kšžœžœ˜0—Kšžœžœžœ˜ Kšžœ˜—K˜—K˜š œžœ žœ˜Lšžœžœžœ˜Kšœ ˜ Kšœžœ˜Kšžœ˜K˜—šžœ(žœžœž˜:Kš œžœ žœžœ žœ˜EKšœ˜Kšžœ˜—K˜—K˜š œžœ žœžœ˜QKšœ žœ˜(Kšœžœ$˜.šžœžœžœž˜%K˜(K˜+Kšžœ˜—K˜—K˜š œžœ žœ˜Hšžœžœžœ˜K˜Kšžœ˜K˜—K˜šžœžœžœž˜'K˜'Kšœ*˜*Kšžœ˜—K˜—K˜š œžœ žœžœ˜KKšœ žœ˜(Kšœžœ!˜+šžœžœžœž˜%K˜#Kšžœ˜—K˜—K˜š œžœ žœ˜Bšžœžœžœ˜K˜Kšžœ˜K˜—K˜šžœžœžœž˜'K˜"Kšžœ˜—K˜—K˜š  œžœ žœžœ˜=Kšœ žœ˜(Kšœžœ˜$šžœžœžœž˜%K˜#Kšžœ˜—K˜—K˜š  œžœ žœ˜4šžœžœžœ˜K˜Kšžœ˜K˜—K˜šžœžœžœž˜'K˜"Kšžœ˜—K˜—K˜š œžœ žœžœ"˜[Kšœ žœ˜(Kšœžœ)˜3šžœžœžœž˜%K˜%Kšžœ˜—K˜—K˜š œžœ žœ"˜Ršžœžœžœ˜K˜Kšžœ˜K˜—K˜šžœžœžœž˜'Kšœ$˜$Kšžœ˜—K˜—K˜K˜—Kšžœ˜—…— 2