<> <> <> <> <> <> <> <> <> DIRECTORY BasicTime USING [GMT], TiogaFile USING [commentHeaderId, controlHeaderId, controlTrailerId, endNode, endOfFile, endSize, FileId, fileIdSize, IntBytes, LengthByte, rope, startNode, terminalTextNode, ThirdByte], FileReader USING [], FS USING [GetInfo, Open, OpenFile], IO USING [STREAM], RefText USING [AppendChar], Rope USING [FromRefText, ROPE, Size, Substr], RopeIO USING [FromFileC, GetRope], RopeReader USING [Create, Get, GetRope, Ref, SetPosition]; FileReaderImpl: CEDAR PROGRAM IMPORTS FS, Rope, RopeIO, RopeReader, RefText EXPORTS FileReader = BEGIN OPEN FileReader; ROPE: TYPE ~ Rope.ROPE; <<***** Operations for opening file>> Open: PUBLIC PROC [fileName: ROPE, start, len: INT] RETURNS [control, comment, text: RopeReader.Ref, tiogaFile: BOOL, fh: FS.OpenFile, createDate: BasicTime.GMT] = { fh _ FS.Open[fileName]; [control, comment, text, tiogaFile, createDate] _ OpenC[fh, start, len]; }; OpenC: PUBLIC PROC [file: FS.OpenFile, start, len: INT] RETURNS [control, comment, text: RopeReader.Ref, tiogaFile: BOOL, createDate: BasicTime.GMT] = { Substr: PROC [start, len: INT] RETURNS [Rope.ROPE] = { RETURN [RopeIO.FromFileC[openFile: file, start: start, len: len]]; }; fileLen: INT; [bytes: fileLen, created: createDate] _ FS.GetInfo[file]; [control, comment, text, tiogaFile] _ DoOpen[fileLen, start, len, Substr]; }; DoOpen: PROC [size, start, len: INT, Substr: PROC [start, len: INT] RETURNS [ROPE]] RETURNS [control, comment, text: RopeReader.Ref, tiogaFile: BOOL] = { text _ RopeReader.Create[]; comment _ RopeReader.Create[]; control _ RopeReader.Create[]; tiogaFile _ TRUE; { -- for EXIT trailerLen: INT ~ TiogaFile.endSize; propsLen, textLen, fileLen, commentLen, controlLen: INT; commentStart, controlStart, trailerStart: INT; start _ MAX[0, MIN[start, size]]; len _ MAX[0, MIN[len, size-start]]; IF NOT len>trailerLen THEN GOTO FakeIt; trailerStart _ start+len-trailerLen; RopeReader.SetPosition[control, Substr[trailerStart, trailerLen]]; IF NOT ReadFileId[control, TiogaFile.controlTrailerId] THEN GOTO FakeIt; IF NOT (propsLen _ ReadLen[control]) IN [0..len-trailerLen) THEN GOTO FakeIt; IF NOT (textLen _ ReadLen[control]) IN [0..len-trailerLen) THEN GOTO FakeIt; IF NOT (fileLen _ ReadLen[control])=len THEN GOTO FakeIt; commentStart _ start+textLen; RopeReader.SetPosition[comment, Substr[commentStart, trailerStart-commentStart]]; IF NOT ReadFileId[comment, TiogaFile.commentHeaderId] THEN GOTO FakeIt; commentLen _ ReadLen[comment]; controlStart _ commentStart+commentLen; RopeReader.SetPosition[control, Substr[controlStart, trailerStart-controlStart]]; IF NOT ReadFileId[control, TiogaFile.controlHeaderId] THEN GOTO FakeIt; controlLen _ ReadLen[control]; IF NOT (textLen+commentLen+controlLen)=fileLen THEN GOTO FakeIt; RopeReader.SetPosition[text, Substr[start, textLen]]; EXITS FakeIt => { RopeReader.SetPosition[text, Substr[start, len]]; RopeReader.SetPosition[comment, NIL]; RopeReader.SetPosition[control, PhonyControl[len]]; tiogaFile _ FALSE; }; }; }; ReadFileId: PROC [rdr: RopeReader.Ref, fileId: TiogaFile.FileId] RETURNS [BOOL] = { FOR i: NAT IN [0..TiogaFile.fileIdSize) DO IF RopeReader.Get[rdr]#fileId[i] THEN RETURN[FALSE]; ENDLOOP; RETURN [TRUE]; }; ReadLen: PROC [rdr: RopeReader.Ref] RETURNS [INT] = { len: PACKED ARRAY [0..4) OF CHAR; len[0] _ RopeReader.Get[rdr]; len[1] _ RopeReader.Get[rdr]; len[2] _ RopeReader.Get[rdr]; len[3] _ RopeReader.Get[rdr]; RETURN [LOOPHOLE[len]]; }; PutInt: PROC [put: PROC [CHAR], val: INT] ~ { intBytes: TiogaFile.IntBytes ~ LOOPHOLE[val]; boundsCheck: [0..0] ~ intBytes.unused; first, second, fourth: TiogaFile.LengthByte; third: TiogaFile.ThirdByte; IF intBytes.fourth#0 THEN { fourth.data _ intBytes.fourth; first.others _ second.others _ third.others _ TRUE; }; IF intBytes.thirdTop#0 OR intBytes.thirdBottom#0 THEN { third.dataTop _ intBytes.thirdTop; third.dataBottom _ intBytes.thirdBottom; first.others _ second.others _ TRUE; }; IF intBytes.second#0 THEN { second.data _ intBytes.second; first.others _ TRUE; }; first.data _ intBytes.first; put[LOOPHOLE[first]]; IF first.others THEN { put[LOOPHOLE[second]]; IF second.others THEN { put[LOOPHOLE[third]]; IF third.others THEN { put[LOOPHOLE[fourth]] }; }; }; }; PhonyControl: PROC [len: INT] RETURNS [ROPE] = { text: REF TEXT _ NEW[TEXT[16]]; Put: PROC [c: CHAR] ~ { text _ RefText.AppendChar[text, c] }; Put[TiogaFile.startNode]; -- start root node Put[VAL[0]]; -- null type for root Put[TiogaFile.terminalTextNode]; Put[VAL[0]]; -- null type for node Put[TiogaFile.rope]; -- rope for node PutInt[Put, len]; -- length of rope for node Put[TiogaFile.endNode]; -- end of root Put[TiogaFile.endOfFile]; RETURN[Rope.FromRefText[text]]; }; <<**** Read from rope instead of file>> FromRope: PUBLIC PROC [rope: ROPE, start: INT _ 0, len: INT _ INT.LAST] RETURNS [control, comment, text: RopeReader.Ref, tiogaFile: BOOL] = { Substr: PROC [start, len: INT] RETURNS [ROPE] = { RETURN [Rope.Substr[rope, start, len]]; }; size: INT ~ Rope.Size[rope]; start _ MAX[0, MIN[start, size]]; len _ MAX[0, MIN[len, size-start]]; [control, comment, text, tiogaFile] _ DoOpen[size, start, len, Substr]; }; <<**** Read from IO stream >> FromStream: PUBLIC PROC [stream: IO.STREAM, len: INT] RETURNS [control, comment, text: RopeReader.Ref, tiogaFile: BOOL] = { rope: ROPE ~ RopeIO.GetRope[stream, len]; RETURN FromRope[rope]; }; END.