-- 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.