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
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;
Exported procedures
GetSerializedFile: PUBLIC PROC [s: STREAM] RETURNS [sfout: SerializedFile] ~ {
Reads a serialized file from the stream.
sfout.version ¬ CrRPC.GetCard32[s];
sfout.file ¬ GetSerializedTree[s];
};
PutSerializedFile: PUBLIC PROC [s: STREAM, sfin: SerializedFile] ~ {
Writes a serialized file to the stream.
CrRPC.PutCard32[s, sfin.version];
PutSerializedTree[s, sfin.file];
};
GetRopeContents: PUBLIC PROC [sf: SerializedFile] RETURNS [contents: ROPE] ~ {
Returns the contents of the serialized file as a 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] ~ {
Sets the contents of the serialized file.
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] ~ {
Finds an attribute of the given type and converts its value to a rope; returns NIL if no such attribute.
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] ~ {
Sets the value of the given attribute; does nothing if the serialized file does not contain an attribute of the specified type.
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] = {
Finds an attribute of the given type; uses CrRPC.GetRope.; returns NIL if no such attribute.
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] = {
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.
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] = {
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.
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] = {
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.
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] ~ {
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.
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] ~ {
Converts a rope to a segment.
Note: This is probably not the most efficient way to do the conversion, but it is safe.
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;
};
Marshalling routines
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];
};
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).
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.