-- FileReaderImpl.Mesa
-- written by Paxton. March 1981
Last Edited by: Maxwell, August 19, 1983 1:43 pm
DIRECTORY
CIFS,
Directory,
File,
T1FileOps,
FileReader,
IO,
PropertyTypes,
Rope,
RopeFrom,
RopeIO,
RopeReader,
System,
T2FileOps;
FileReaderImpl: CEDAR MONITOR
IMPORTS Rope, RopeFrom, RopeIO, RopeReader, CIFS, Directory
EXPORTS FileReader =
BEGIN OPEN FileReader;
-- ***** Operations for opening file
Open: PUBLIC PROC [fileName: Rope.ROPE, start, len: Offset]
RETURNS [reply:Reply, fh: CIFS.OpenFile, createDate: System.GreenwichMeanTime]={
file: File.Capability ← CIFS.GetFC[fh ← CIFS.Open[fileName, CIFS.read]];
[reply, createDate] ← OpenC[file, start, len] };
OpenC: PUBLIC PROC [file: File.Capability, start, len: Offset]
RETURNS [reply:Reply, createDate: System.GreenwichMeanTime] = TRUSTED {
Substr: PROC [start, len: Offset] RETURNS [Rope.ROPE] = TRUSTED {
RETURN [RopeFrom.File[file, start, len, fileLen]] };
dummy: STRING ← [40];
fileLen: Offset;
[createDate: createDate, byteLength: fileLen] ← Directory.GetProps[file: file, name: dummy];
reply ← DoOpen[fileLen, start, len, Substr] };
DoOpen: PROC [
totLen, start, len: Offset,
Substr: PROC [start, len: Offset] RETURNS [Rope.ROPE]]
RETURNS [reply: Reply] = {
FakeFile: PROC = {
constructs a T1 style simple file
textRope: Rope.ROPE ← Substr[start, len];
reply.fileType ← Simple;
IF reply.text=NIL THEN reply.text ← RopeReader.Create[];
IF reply.comment=NIL THEN reply.comment ← RopeReader.Create[];
RopeReader.SetPosition[reply.text, textRope];
RopeReader.SetPosition[reply.control, PhonyControl[len]] };
{ -- for EXIT
commentStart, end, commentLen, controlLen, propsLen, propsStart: Offset;
endSize: NAT = T1FileOps.endSize;
endRope: Rope.ROPE;
pad:CARDINAL;
reply ← GetReply[];
start ← MAX[0, MIN[start, totLen]];
len ← MAX[0, MIN[len, totLen-start]];
end ← start+len;
reply.control ← RopeReader.GetRopeReader[];
IF len <= endSize THEN GOTO FakeIt;
RopeReader.SetPosition[reply.control, Substr[end-endSize, endSize]]; -- 'control' reads the trailer
[reply.fileType, pad] ← ReadControlTrailerId[reply.control];
SELECT reply.fileType FROM
Tioga1 => {
IF (propsLen ← ReadLen[reply.control]) NOT IN [0..len-endSize) THEN GOTO FakeIt;
IF (commentStart ← ReadLen[reply.control]) NOT IN [0..len-endSize) THEN GOTO FakeIt;
IF ReadLen[reply.control] # len THEN GOTO FakeIt;
endRope ← Substr[start+commentStart, len-commentStart]; -- comment and control
reply.comment ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reply.comment, endRope];
IF ~ReadCommentHeaderId[reply.comment] THEN GOTO FakeIt;
commentLen ← ReadLen[reply.comment];
RopeReader.SetPosition[reply.control, endRope, commentLen];
IF ~ReadControlHeaderId[reply.control] THEN GOTO FakeIt;
controlLen ← ReadLen[reply.control];
IF commentStart+commentLen+controlLen # len THEN GOTO FakeIt;
reply.text ← RopeReader.GetRopeReader[];
RopeReader.SetPosition[reply.text, Substr[start, commentStart]] };
Tioga2 => {
reply.version ← RopeReader.Get[reply.control];
reply.flags ← RopeReader.Get[reply.control];
IF (propsStart ← ReadCard[reply.control]) NOT IN [0..len-endSize] THEN GOTO FakeIt;
IF (reply.controlStart ← ReadLen[reply.control]) NOT IN [0..len-endSize) THEN GOTO FakeIt;
IF ReadLen[reply.control] # len THEN GOTO FakeIt;-- supposed length # actual length
reply.controlStart ← start + reply.controlStart;
reply.text ← reply.control ← NIL;
reply.textLen ← reply.controlStart - pad;
reply.controlStart ← reply.controlStart + T1FileOps.fileIdSize;
reply.controlLen ← propsStart - T1FileOps.fileIdSize;
reply.textStart ← start;
reply.fileRope ← Substr[0, len] };
ENDCASE => GOTO FakeIt;
EXITS FakeIt => FakeFile[] -- build a Fake Tioga1 file structure
}};
ReadControlHeaderId: PROC [control: RopeReader.Ref] RETURNS [BOOLEAN] = {
OPEN T1FileOps;
FOR i:NAT IN [0..fileIdSize) DO
IF RopeReader.Get[control] # controlHeaderId[i] THEN RETURN[FALSE];
ENDLOOP;
RETURN [TRUE] };
ReadCommentHeaderId: PROC [comment: RopeReader.Ref] RETURNS [BOOLEAN] = {
FOR i:NAT IN [0..T1FileOps.fileIdSize) DO
IF RopeReader.Get[comment] # T1FileOps.commentHeaderId[i] THEN RETURN[FALSE];
ENDLOOP;
RETURN [TRUE] };
ReadLen: PROC [rdr: RopeReader.Ref] RETURNS [Offset] = { OPEN RopeReader;
start: PACKED ARRAY [0..3] OF CHARACTER;
start[0] ← Get[rdr]; start[1] ← Get[rdr]; start[2] ← Get[rdr]; start[3] ← Get[rdr];
RETURN [LOOPHOLE[start]] };
ReadCard: PROC [rdr: RopeReader.Ref] RETURNS [CARDINAL] = { OPEN RopeReader;
start: PACKED ARRAY [0..1] OF CHARACTER;
start[0] ← Get[rdr]; start[1] ← Get[rdr];
RETURN [LOOPHOLE[start]] };
ReadControlTrailerId: PROC [control: RopeReader.Ref] RETURNS [FileType, CARDINAL] = {
SELECT RopeReader.Get[control] FROM
T1FileOps.controlTrailerId[0] => {
IF RopeReader.Get[control] # T1FileOps.controlTrailerId[1] THEN RETURN[Simple, 0];
RETURN [Tioga1, 0] };
T2FileOps.controlTrailerId => {
SELECT RopeReader.Get[control] FROM
T2FileOps.DataPaddedFlag => RETURN [Tioga2, 1];
T2FileOps.DataUnpaddedFlag => RETURN [Tioga2, 0];
ENDCASE => RETURN[Simple, 0] };
ENDCASE => RETURN[Simple, 0] };
PhonyControl: PROC [len: Offset] RETURNS [r: Rope.ROPE] = {
OPEN T1FileOps;
first, second, fourth: LengthByte;
third: ThirdByte;
lenBytes: IntBytes ← LOOPHOLE[len];
r ← RopeFrom.Character[startNode]; -- start root node
r ← RopeFrom.FlatAppendByte[r, 0]; -- null type for root
r ← RopeFrom.FlatAppendChar[r, terminalTextNode];
r ← RopeFrom.FlatAppendByte[r, 0]; -- null type for node
r ← RopeFrom.FlatAppendChar[r, rope]; -- rope for node
-- length of rope for node
IF lenBytes.fourth # 0 THEN {
fourth.data ← lenBytes.fourth;
first.others ← second.others ← third.others ← TRUE };
IF lenBytes.thirdTop # 0 OR lenBytes.thirdBottom # 0 THEN {
third.dataTop ← lenBytes.thirdTop;
third.dataBottom ← lenBytes.thirdBottom;
first.others ← second.others ← TRUE };
IF lenBytes.second # 0 THEN {
second.data ← lenBytes.second; first.others ← TRUE };
first.data ← lenBytes.first;
r ← RopeFrom.FlatAppendByte[r, first];
IF first.others THEN {
r ← RopeFrom.FlatAppendByte[r, second];
IF second.others THEN {
r ← RopeFrom.FlatAppendByte[r, third];
IF third.others THEN {
r ← RopeFrom.FlatAppendByte[r, fourth] }}};
r ← RopeFrom.FlatAppendChar[r, endNode]; -- end of root
r ← RopeFrom.FlatAppendChar[r, endOfFile]};
-- **** Read from rope instead of file
FromRope: PUBLIC PROC [rope: Rope.ROPE, start, len: Offset]
RETURNS [reply:Reply] = {
Substr: PROC [start, len: Offset] RETURNS [Rope.ROPE] = {
RETURN [Rope.Substr[rope, start, len]] };
reply ← DoOpen[Rope.Size[rope], start, len, Substr];
};
-- **** Read from IO stream
FromStream: PUBLIC PROC [stream: IO.Handle, len: Offset]
RETURNS [reply:Reply] = {
rope: Rope.ROPE ← RopeIO.GetRope[stream, len];
reply ← FromRope[rope, 0, Rope.Size[rope]] };
-- **** Miscellaneous
reply1, reply2, reply3: Reply;
GetReply: ENTRY PROC RETURNS [reply: Reply] = {
ENABLE UNWIND => NULL;
IF reply3 # NIL THEN { reply ← reply3; reply3 ← NIL }
ELSE IF reply2 # NIL THEN { reply ← reply2; reply2 ← NIL }
ELSE IF reply1 # NIL THEN { reply ← reply1; reply1 ← NIL }
ELSE reply ← NEW[ReplyRec] };
FreeReply: PUBLIC ENTRY PROC [reply: Reply] = {
ENABLE UNWIND => NULL;
IF reply3 = reply OR reply2 = reply OR reply1 = reply THEN ERROR;
IF reply.control # NIL THEN { RopeReader.FreeRopeReader[reply.control]; reply.control ← NIL };
IF reply.comment # NIL THEN { RopeReader.FreeRopeReader[reply.comment]; reply.comment ← NIL };
IF reply.text # NIL THEN { RopeReader.FreeRopeReader[reply.text]; reply.text ← NIL };
reply.fileRope ← NIL;
IF reply3 = NIL THEN reply3 ← reply
ELSE IF reply2 = NIL THEN reply2 ← reply
ELSE IF reply1 = NIL THEN reply1 ← reply };
END.