DIRECTORY Environment USING [bytesPerPage, wordsPerPage], FileIO USING [Open, OpenFailed], IO USING [STREAM, Close, GetIndex, GetLength, UnsafeBlock, SetIndex, UnsafeGetBlock], PressFormat, PressReader, RealConvert USING [BcplToIeee], Rope USING [ROPE, FromProc]; PressReaderImpl: PROGRAM IMPORTS FileIO, IO, PF: PressFormat, RealConvert, Rope EXPORTS PressReader = BEGIN OPEN PressReader; ROPE: TYPE = Rope.ROPE; bytesPerPressRecord: CARDINAL = 512; indexDistanceThreshold: INT _ 500; Handle: PUBLIC TYPE = REF PressReaderRec; PressReaderRec: PUBLIC TYPE = RECORD [ stream1: IO.STREAM _ NIL, stream2: IO.STREAM _ NIL, nRecs: INT _ 0, nParts: INT _ 0, pdStart: INT _ 0, pdRecs: INT _ 0, currentPart: INT _ 0, pType: PartType, pStart: INT _ 0, pRecs: INT _ 0, padding: INT _ 0, atObject: BOOL _ FALSE, atDots: BOOL _ FALSE, dataPlace, dataLength: INT, entityStack: REF EntityStack _ NIL]; PressReaderError: PUBLIC ERROR [errorCode: ErrorCode] = CODE; bcplMaxLength: CARDINAL = 255; -- maximum length of a BCPL string BcplString: TYPE = LONG POINTER TO BcplStringBody; BcplStringBody: TYPE = MACHINE DEPENDENT RECORD [ body: PACKED ARRAY[0..0) OF CHARACTER ]; BcplReal: TYPE = MACHINE DEPENDENT RECORD [ sign: [0..1], exp: [0..377B], sigbit: [0..1], topmantissa: [0..77B], restofmantissa: [0..177777B] ]; EntityStack: TYPE = RECORD[start, length, data: INT _ 0, next: REF EntityStack _ NIL]; OpenPressFile: PUBLIC PROCEDURE [name: ROPE] RETURNS [handle: Handle] = { docDirV: PF.DDV; lengthInBytes: INT; handle _ NEW[PressReaderRec]; handle.stream1 _ FileIO.Open[fileName: name, accessOptions: read ! FileIO.OpenFailed => CHECKED {ERROR PressReaderError[FileNotAvailableForRead]} ]; handle.stream2 _ FileIO.Open[fileName: name, accessOptions: read ! FileIO.OpenFailed => CHECKED {ERROR PressReaderError[FileNotAvailableForRead]} ]; lengthInBytes _ handle.stream1.GetLength[]; IF lengthInBytes = 0 OR (lengthInBytes MOD bytesPerPressRecord # 0) THEN ERROR PressReaderError[FileNotAPressFile]; --bad length ReadBlock[handle, lengthInBytes-bytesPerPressRecord, [@docDirV, 0, SIZE[PF.DDV]*2]]; IF docDirV.Passwd # PF.PressPasswd THEN ERROR PressReaderError[FileNotAPressFile]; -- bad password handle.nRecs _ lengthInBytes/bytesPerPressRecord; IF docDirV.nRecs # handle.nRecs THEN ERROR PressReaderError[FileNotAPressFile]; --bad record count handle.nParts _ docDirV.nParts; handle.pdStart _ docDirV.pdStart; handle.pdRecs _ docDirV.pdRecs; }; -- OpenPressFile GetDocumentDirectory: PUBLIC PROCEDURE [handle: Handle] RETURNS [DocumentDirectory] = { docDirV: PF.DDV; IF handle = NIL THEN ERROR PressReaderError[BadHandle]; ReadBlock[handle, (handle.nRecs-1)*bytesPerPressRecord, [@docDirV, 0, SIZE[PF.DDV]*2]]; RETURN[NEW[DocumentDirectoryRec _ [ passwd: docDirV.Passwd, nRecs: docDirV.nRecs, nParts: docDirV.nParts, pdStart: docDirV.pdStart, pdRecs: docDirV.pdRecs, backP: docDirV.Backp, date: PF.DoubleToLC[docDirV.date], fCopy: docDirV.fCopy, lCopy: docDirV.lCopy, fPage: docDirV.fPage, lPage: docDirV.lPage, fileName: BcplStringToRope[ArrayCardinalToBcplString[@docDirV.FileStr]], creator: BcplStringToRope[ArrayCardinalToBcplString[@docDirV.CreatStr]], dateText: BcplStringToRope[ArrayCardinalToBcplString[@docDirV.DateStr]]]]]; }; -- GetDocumentDirectory GetParts: PUBLIC PROCEDURE [handle: Handle, partNumber: INT, pageProc: PageProc _ NIL, fontDirectoryProc: FontDirectoryProc _ NIL] = { partEntry: PF.PE; currentPart: INT; upToPart: INT; IF handle = NIL THEN ERROR PressReaderError[BadHandle]; IF partNumber = 0 THEN { currentPart _ 1; upToPart _ handle.nParts; } ELSE IF partNumber NOT IN [1..handle.nParts] THEN ERROR PressReaderError[PartNotFound] ELSE currentPart _ upToPart _ partNumber; WHILE currentPart <= upToPart DO ReadBlock[ handle, handle.pdStart*bytesPerPressRecord+(currentPart-1)*SIZE[PF.PE]*2, [@partEntry, 0, SIZE[PF.PE]*2]]; handle.pType _ SELECT LOOPHOLE[partEntry.Type, INTEGER] FROM PF.PETypePage => printedPage, PF.PETypeFont => fontDirectory, < 0 => private, > 1 => other, ENDCASE => ERROR PressReaderError[BadPartType]; handle.pStart _ partEntry.pStart; handle.pRecs _ partEntry.pRecs; handle.padding _ partEntry.Padding; SELECT handle.pType FROM printedPage => IF pageProc # NIL THEN pageProc[handle, [printedPage, partEntry.Type, handle.pStart, handle.pRecs, handle.padding]]; fontDirectory => IF fontDirectoryProc # NIL THEN fontDirectoryProc[handle, [fontDirectory, partEntry.Type, handle.pStart, handle.pRecs, handle.padding]]; ENDCASE => ERROR PressReaderError[BadPartType]; currentPart _ currentPart+1; ENDLOOP; }; -- GetParts GetFonts: PUBLIC PROCEDURE [handle: Handle, fontEntryProc: FontEntryProc _ NIL] = { fontEntry: PF.FE; partEntry: PF.PE; pStart, currentPart: INT; fontStart: INT _ 0; IF handle = NIL THEN ERROR PressReaderError[BadHandle]; IF fontEntryProc = NIL THEN RETURN; IF handle.pType # fontDirectory THEN { -- search all parts for FontDirectory FOR currentPart IN [0..handle.nParts) DO ReadBlock[handle, handle.pdStart*bytesPerPressRecord+currentPart*SIZE[PF.PE]*2, [@partEntry, 0, SIZE[PF.PE]*2]]; IF partEntry.Type = PF.PETypeFont THEN {pStart _ partEntry.pStart; EXIT;} REPEAT FINISHED => ERROR PressReaderError[NoFontDirectoryPart]; ENDLOOP; } ELSE pStart _ handle.pStart; DO ReadBlock[handle, pStart*bytesPerPressRecord+fontStart, [@fontEntry, 0, SIZE[PF.FE]*2]]; IF fontEntry.length = 0 THEN EXIT; IF fontEntry.fam[0] = 0 AND fontEntry.fam[1] = 0 AND fontEntry.destn = 255 THEN { handle.dataLength _ fontEntry.length-4; -- SIZE[length, set, fno, m, all-ones, zero] handle.dataPlace _ pStart*bytesPerPressRecord+fontStart+8; handle.atObject _ TRUE; fontEntryProc[[ length: fontEntry.length, fontSet: fontEntry.set, font: fontEntry.fno, firstChar: fontEntry.destm, lastChar: fontEntry.destn, family: NIL, face: [0, medium, regular, regular], source: 0, size: 0, rotation: 0 ]]; handle.atObject _ FALSE; } ELSE { fontEntryProc[[ length: fontEntry.length, fontSet: fontEntry.set, font: fontEntry.fno, firstChar: fontEntry.destm, lastChar: fontEntry.destn, family: BcplStringToRope[ArrayByteToBcplString[@fontEntry.fam]], face: DecodeFace[fontEntry.face], source: fontEntry.source, size: LOOPHOLE[fontEntry.siz, INTEGER], rotation: fontEntry.rotn ]]; }; fontStart _ fontStart+fontEntry.length*2; ENDLOOP; }; -- GetFonts GetPage: PUBLIC PROCEDURE [handle:Handle, entityProc: EntityProc _ NIL] = { temp: REF EntityStack; length: CARDINAL; entityTrailer: PF.EH; IF handle = NIL THEN ERROR PressReaderError[BadHandle]; IF handle.pType # printedPage THEN ERROR PressReaderError[CurrentPartNotAPage]; handle.entityStack _ NEW[EntityStack]; handle.entityStack.start _ (handle.pStart+handle.pRecs)*bytesPerPressRecord-handle.padding*2; DO ReadBlock[handle, handle.entityStack.start-SIZE[CARDINAL]*2, [@length, 0, SIZE[CARDINAL]*2]]; IF length = 0 THEN EXIT; temp _ NEW[EntityStack _ [start: handle.entityStack.start-length*2, next: handle.entityStack]]; handle.entityStack _ temp; ENDLOOP; handle.entityStack _ handle.entityStack.next; -- pop the empty entry on top WHILE handle.entityStack # NIL DO ReadBlock[handle, handle.entityStack.start-SIZE[PF.EH]*2, [@entityTrailer, 0, SIZE[PF.EH]*2]]; handle.entityStack.length _ entityTrailer.Length; handle.entityStack.data _ PF.DoubleToLC[entityTrailer.Dstart]; entityProc[handle, [ entityType: entityTrailer.Type, fontSet: entityTrailer.Fontset, dataStart: PF.DoubleToLC[entityTrailer.Dstart], dataLength: PF.DoubleToLC[entityTrailer.Dlength], Xe: entityTrailer.Xe, Ye: entityTrailer.Ye, xLeft: entityTrailer.Xleft, yBottom: entityTrailer.Ybottom, width: entityTrailer.Width, height: entityTrailer.Height, length: entityTrailer.Length]]; handle.entityStack _ handle.entityStack.next; ENDLOOP; }; -- GetPage GetCommands: PUBLIC PROCEDURE [handle:Handle, commandProcs: CommandProcs] = { length: CARDINAL; stringBuffer: PACKED ARRAY [0..256) OF CHARACTER; integerBuffer: INTEGER _ 0; value: INTEGER _ 0; rectangleBuffer: MACHINE DEPENDENT RECORD [width, height: INTEGER]; alternativeBuffer: MACHINE DEPENDENT RECORD [ ELtypes: CARDINAL, ELbytes, DLbytes: PF.Double]; opBuffer: MACHINE DEPENDENT RECORD [opcode: PF.BYTE, byteArg: PF.BYTE]; dataPlace, commandPlace, commandEnd: INT; dataLength: INT; dotsLength: PF.Double; IF handle = NIL THEN ERROR PressReaderError[BadHandle]; IF handle.entityStack = NIL THEN ERROR PressReaderError[NoEntity]; dataPlace _ handle.pStart*bytesPerPressRecord+handle.entityStack.data; commandPlace _ handle.entityStack.start-handle.entityStack.length*2; commandEnd _ commandPlace+(handle.entityStack.length-SIZE[PF.EH])*2; WHILE commandPlace < commandEnd DO ReadBlock[handle, commandPlace, [@opBuffer, 0, 2]]; -- read Opcode and one byte BEGIN OPEN opBuffer; SELECT opcode FROM IN [PF.EShowShort .. PF.ESkipShort) => { length _ opcode-PF.EShowShort+1; IF commandProcs.showCharactersProc # NIL THEN { stringBuffer[0] _ LOOPHOLE[opcode-PF.EShowShort+1, CHARACTER]; ReadBlock[handle, dataPlace, [@stringBuffer, 1, length+1]]; commandProcs.showCharactersProc[showCharactersShort, length, BcplStringToRope[ArrayCharacterToBcplString[@stringBuffer]]]; }; dataPlace _ dataPlace+length; commandPlace _ commandPlace+1; }; IN [PF.ESkipShort..PF.EShowSkip) => { length _ opcode-PF.ESkipShort+1; IF commandProcs.skipProc # NIL THEN commandProcs.skipProc[skipCharactersShort, length]; dataPlace _ dataPlace+length; commandPlace _ commandPlace+1; }; IN [PF.EShowSkip..PF.ESpaceXShort) => { length _ opcode-PF.EShowShort+1; IF commandProcs.showCharactersProc # NIL THEN { stringBuffer[0] _ LOOPHOLE[opcode-PF.EShowShort+1, CHARACTER]; ReadBlock[handle, dataPlace, [@stringBuffer, 1, length+1]]; commandProcs.showCharactersProc[showCharactersAndSkip, length, BcplStringToRope[ArrayCharacterToBcplString[@stringBuffer]]]; }; dataPlace _ dataPlace+length+1; -- skip byte commandPlace _ commandPlace+1; }; IN [PF.ESpaceXShort..PF.ESpaceYShort) => { IF commandProcs.spacingProc # NIL THEN commandProcs.spacingProc[setSpaceXShort, (opcode-PF.ESpaceXShort)*256+byteArg]; commandPlace _ commandPlace+2; }; IN [PF.ESpaceYShort..PF.EFont) => { IF commandProcs.spacingProc # NIL THEN commandProcs.spacingProc[setSpaceYShort, (opcode-PF.ESpaceXShort)*256+byteArg]; commandPlace _ commandPlace+2; }; IN [PF.EFont..PF.EShortMax] => { IF commandProcs.fontProc # NIL THEN { value _ opcode-PF.EFont; commandProcs.fontProc[value]; }; commandPlace _ commandPlace+1; }; PF.ENop, IN (PF.EShortMax..PF.ESkipControlImmediate) => { --available and spare IF commandProcs.noOpProc # NIL THEN commandProcs.noOpProc; commandPlace _ commandPlace+1; }; PF.ESkipControlImmediate => { IF commandProcs.skipProc # NIL THEN commandProcs.skipProc[skipControlBytesImmediate, byteArg]; commandPlace _ commandPlace+2+byteArg; }; PF.EAlternative => { IF commandProcs.alternativeProc # NIL THEN { ReadBlock[handle, commandPlace+1, [@alternativeBuffer, 0, 10]]; commandProcs.alternativeProc[alternativeBuffer.ELtypes, PF.DoubleToLC[alternativeBuffer.ELbytes], PF.DoubleToLC[alternativeBuffer.DLbytes]]; }; commandPlace _ commandPlace+11; }; PF.EOnlyOnCopy => { IF commandProcs.copyProc # NIL THEN commandProcs.copyProc[byteArg]; commandPlace _ commandPlace+2; }; PF.ESetX, PF.ESetY => { IF commandProcs.positionProc # NIL THEN { ReadBlock[handle, commandPlace+1, [@integerBuffer, 0, 2]]; commandProcs.positionProc[ SELECT opcode FROM PF.ESetX => setX, PF.ESetY => setY, ENDCASE => ERROR, integerBuffer]; }; commandPlace _ commandPlace+3; }; PF.EShow => { length _ byteArg; IF commandProcs.showCharactersProc # NIL THEN { stringBuffer[0] _ LOOPHOLE[byteArg, CHARACTER]; ReadBlock[handle, dataPlace, [@stringBuffer, 1, length+1]]; commandProcs.showCharactersProc[showCharacters, length, BcplStringToRope[ArrayCharacterToBcplString[@stringBuffer]]]; }; dataPlace _ dataPlace+length; commandPlace _ commandPlace+2; }; PF.ESkip => { IF commandProcs.skipProc # NIL THEN commandProcs.skipProc[skipCharacters, byteArg]; dataPlace _ dataPlace+byteArg; commandPlace _ commandPlace+2; }; PF.ESkipControl => { -- should get the type byte too ReadBlock[handle, commandPlace+1, [@integerBuffer, 0, 2]]; IF commandProcs.skipProc # NIL THEN commandProcs.skipProc[skipControlBytes, integerBuffer]; dataPlace _ dataPlace+integerBuffer; commandPlace _ commandPlace+4; }; PF.EShowImmediate => { IF commandProcs.showCharactersProc # NIL THEN { stringBuffer[0] _ LOOPHOLE[1, CHARACTER]; stringBuffer[1] _ LOOPHOLE[byteArg, CHARACTER]; commandProcs.showCharactersProc[showCharacterImmediate, 1, BcplStringToRope[ArrayCharacterToBcplString[@stringBuffer]]]; }; commandPlace _ commandPlace+2; }; PF.ESpaceX, PF.ESpaceY => { IF commandProcs.spacingProc # NIL THEN { ReadBlock[handle, commandPlace+1, [@integerBuffer, 0, 2]]; commandProcs.spacingProc[ SELECT opcode FROM PF.ESpaceX => setSpaceX, PF.ESpaceY => setSpaceY, ENDCASE => ERROR, integerBuffer]; }; commandPlace _ commandPlace+3; }; PF.EResetSpace => { IF commandProcs.spacingProc # NIL THEN commandProcs.spacingProc[resetSpace, 0]; commandPlace _ commandPlace+1; }; PF.ESpace => { IF commandProcs.spaceProc # NIL THEN commandProcs.spaceProc; commandPlace _ commandPlace+1; }; PF.ESetBright, PF.ESetHue, PF.ESetSat => { IF commandProcs.colorProc # NIL THEN commandProcs.colorProc[ SELECT opcode FROM PF.ESetBright => setBrightness, PF.ESetHue => setHue, PF.ESetSat => setSaturation, ENDCASE => ERROR, byteArg]; commandPlace _ commandPlace+2; }; PF.EShowObject => { ReadBlock[handle, commandPlace+1, [@integerBuffer, 0, 2]]; IF commandProcs.showObjectProc # NIL THEN { handle.atObject _ TRUE; handle.dataLength _ integerBuffer; handle.dataPlace _ dataPlace; commandProcs.showObjectProc[handle, integerBuffer]; }; handle.atObject _ FALSE; dataPlace _ dataPlace+integerBuffer*2; commandPlace _ commandPlace+3; }; PF.EShowDots, PF.EShowDotsOpaque => { ReadBlock[handle, commandPlace+1, [@dotsLength, 0, 4]]; dataLength _ PF.DoubleToLC[dotsLength]; IF commandProcs.showDotsProc # NIL THEN { handle.atDots _ TRUE; handle.dataPlace _ dataPlace; handle.dataLength _ dataLength; commandProcs.showDotsProc[ handle, SELECT opcode FROM PF.EShowDots => showDots, PF.EShowDotsOpaque => showDotsOpaque, ENDCASE => ERROR, dataLength]; }; dataPlace _ dataPlace+2*dataLength; commandPlace _ commandPlace+5; handle.atDots _ FALSE; }; PF.EShowRectangle => { IF commandProcs.showRectangleProc # NIL THEN { ReadBlock[handle, commandPlace+1, [@rectangleBuffer, 0, 4]]; commandProcs.showRectangleProc[rectangleBuffer.width, rectangleBuffer.height]; }; commandPlace _ commandPlace+5; }; ENDCASE => { IF commandProcs.badProc # NIL THEN commandProcs.badProc[opcode, commandPlace, dataPlace]; EXIT; }; END; ENDLOOP; -- opcode }; -- GetCommands GetObject: PUBLIC PROCEDURE [handle: Handle, objectProcs: ObjectProcs] = { dataLength: INT _ handle.dataLength; dataPlace: INT _ handle.dataPlace; objectBuffer: MACHINE DEPENDENT RECORD [command: CARDINAL, arg1, arg2: INTEGER]; curveBuffer: MACHINE DEPENDENT RECORD [cX, cY, bX, bY, aX, aY: BcplReal]; IF NOT handle.atObject THEN ERROR PressReaderError[NotAtObject]; WHILE dataLength > 0 DO ReadBlock[handle, dataPlace, [@objectBuffer, 0, 6]]; SELECT objectBuffer.command FROM PF.DMoveTo => { IF objectProcs.moveToProc # NIL THEN objectProcs.moveToProc[objectBuffer.arg1, objectBuffer.arg2]; dataPlace _ dataPlace+6; dataLength _ dataLength-3; }; PF.DDrawTo => { IF objectProcs.drawToProc # NIL THEN objectProcs.drawToProc[objectBuffer.arg1, objectBuffer.arg2]; dataPlace _ dataPlace+6; dataLength _ dataLength-3; }; PF.DDrawCurve => { IF objectProcs.drawCurveProc # NIL THEN { ReadBlock[handle, dataPlace+2, [@curveBuffer, 0, 24]]; objectProcs.drawCurveProc[ BcplToMesaReal[curveBuffer.cX], BcplToMesaReal[curveBuffer.cY], BcplToMesaReal[curveBuffer.bX], BcplToMesaReal[curveBuffer.bY], BcplToMesaReal[curveBuffer.aX], BcplToMesaReal[curveBuffer.aY]]; }; dataPlace _ dataPlace+26; dataLength _ dataLength-13; }; ENDCASE; ENDLOOP; }; -- GetObject GetDots: PUBLIC PROCEDURE [handle: Handle, dotProcs: DotProcs] = { dataLength: INT _ handle.dataLength; dataPlace: INT _ handle.dataPlace; opBuffer: MACHINE DEPENDENT RECORD [opcode: PF.BYTE, byteArg: PF.BYTE]; dotsLength: PF.Double; windowBuffer: MACHINE DEPENDENT RECORD [one, two, three, four: CARDINAL]; numberPages, pageNumber, byteOffset: INT; IF NOT handle.atDots THEN ERROR PressReaderError[NotAtDots]; WHILE dataLength > 0 DO ReadBlock[handle, dataPlace, [@opBuffer, 0, 2]]; SELECT opBuffer.opcode FROM 1 => { -- PF.DDotCode IF dotProcs.setCoding # NIL THEN { ReadBlock[handle, dataPlace+2, [@dotsLength, 0, 4]]; dotProcs.setCoding[opBuffer.byteArg, dotsLength.high, dotsLength.low]; }; dataPlace _ dataPlace+6; dataLength _ dataLength-3; }; 2 => { -- PF.DDotMode IF dotProcs.setMode # NIL THEN dotProcs.setMode[opBuffer.byteArg]; dataPlace _ dataPlace+2; dataLength _ dataLength-1; }; 0 => SELECT opBuffer.byteArg FROM PF.DDotWindow => { IF dotProcs.setWindow # NIL THEN { ReadBlock[handle, dataPlace+2, [@windowBuffer, 0, 8]]; dotProcs.setWindow[windowBuffer.one, windowBuffer.two, windowBuffer.three, windowBuffer.four]; }; dataPlace _ dataPlace+10; dataLength _ dataLength-5; }; PF.DDotSize => { IF dotProcs.setSize # NIL THEN { ReadBlock[handle, dataPlace+2, [@windowBuffer, 0, 4]]; dotProcs.setSize[windowBuffer.one, windowBuffer.two]; }; dataPlace _ dataPlace+6; dataLength _ dataLength-3; }; PF.DDotsFollow => { dataPlace _ dataPlace+2; dataLength _ dataLength-1; IF dotProcs.dotsFollow # NIL THEN { pageNumber _ dataPlace/Environment.bytesPerPage; byteOffset _ dataPlace MOD Environment.bytesPerPage; numberPages _ (dataLength+byteOffset+Environment.wordsPerPage-1) / Environment.wordsPerPage; dotProcs.dotsFollow[[file: handle.stream1, numberPages: numberPages, pageNumber: pageNumber, byteOffset: byteOffset, length: dataLength]]; }; dataLength _ 0; }; PF.DDotsFromFile => ERROR; PF.DDotsFromPressFile => ERROR; PF.DSampleProps => ERROR; ENDCASE => ERROR; ENDCASE => ERROR; ENDLOOP; }; -- GetDots ClosePressFile: PUBLIC PROCEDURE [handle: Handle] = { IF (handle # NIL) AND (handle.stream1 # NIL) THEN handle.stream1.Close[]; IF (handle # NIL) AND (handle.stream2 # NIL) THEN handle.stream2.Close[]; handle _ NIL; }; -- ClosePressFile DecodeFace: PROCEDURE [face: INT] RETURNS [fontFace: FontFace] = { IF face NOT IN [0..18) THEN RETURN [[face, medium, regular, regular]]; fontFace.encoding _ face; fontFace.slope _ IF (face MOD 2) = 0 THEN regular ELSE italic; face _ face - (face MOD 2); fontFace.weight _ SELECT (face MOD 6) FROM 0 => medium, 2 => bold, 4 => light, ENDCASE => ERROR; fontFace.expansion _ SELECT face - (face MOD 6) FROM 0 => regular, 6 => condensed, 12 => expanded, ENDCASE => ERROR; }; -- DecodeFace ReadBlock: PROCEDURE [handle: Handle, index: INT, ub: IO.UnsafeBlock] = --INLINE-- { ix1: INT _ handle.stream1.GetIndex[]; IF ABS[ix1-index] > indexDistanceThreshold THEN { s: IO.STREAM _ handle.stream1; handle.stream1 _ handle.stream2; handle.stream2 _ s; }; handle.stream1.SetIndex[index]; IF handle.stream1.UnsafeGetBlock[ub] # (ub.stopIndexPlusOne-ub.startIndex) THEN ERROR PressReaderError[AbortedBecauseGetFailed]; }; ArrayCardinalToBcplString: PROCEDURE [s: LONG POINTER TO ARRAY [0..0) OF CARDINAL] RETURNS [BcplString] = INLINE { RETURN[LOOPHOLE[s, BcplString]]; }; ArrayByteToBcplString: PROCEDURE [s: LONG POINTER TO PACKED ARRAY [0..0) OF PF.BYTE] RETURNS [BcplString] = INLINE { RETURN[LOOPHOLE[s, BcplString]]; }; ArrayCharacterToBcplString: PROCEDURE [s: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER] RETURNS [BcplString] = INLINE { RETURN[LOOPHOLE[s, BcplString]]; }; BcplStringToRope: PROCEDURE [t: BcplString] RETURNS [ROPE] = { lengthByte: PF.BYTE _ LOOPHOLE[t[0]]; len: INT _ lengthByte; i: INT _ 0; fromProc: SAFE PROCEDURE RETURNS[CHAR] = TRUSTED { RETURN[t.body[i _ i+1]]; }; IF len NOT IN[0..bcplMaxLength] THEN ERROR; RETURN [Rope.FromProc[len, fromProc]]; }; BcplToMesaReal: PROCEDURE [b: BcplReal] RETURNS [REAL] = INLINE { RETURN[RealConvert.BcplToIeee[LOOPHOLE[b]]]; }; END. &PressReaderImpl.mesa Last Modified by Shore; November 22, 1982 11:51 am Last Edited by: Beach, September 13, 1983 5:21 pm a graphically defined font Change Log Created by Shore; June 29, 1982 2:56 pm Changed by Shore; August 22, 1982 4:58 pm converted to formatted Tioga file revisions for Cedar 3.3 reduced number of SetIndex instructions Changed by Shore; August 26, 1982 9:30 am made Dots and Objects one level deeper to permit exit actions by the show Commands Changed by Shore; September 2, 1982 9:08 am made Parts individually gettable (partNumber parameter to GetParts) Changed by Shore; September 3, 1982 5:08 pm now pass up Dots Changed by Shore; October 12, 1982 9:11 pm updated for Cedar 3.4 Changed by Shore; November 14, 1982 3:02 pm changed to Cedar.Style and added node formats Κ/– "Cedar" style˜head1šΟc™Jš2™2J™1unitšΟk ˜ Jšœ žœ˜/Jšœžœ˜ JšžœžœžœE˜UJšœ ˜ Jšœ ˜ Jšœ žœ˜Jšœžœžœ ˜——šΟnœž˜Jšžœ žœžœ ˜6Jšžœž˜J˜Jšžœ ˜Jšžœžœžœ˜J˜Jšœžœ˜$Jšœžœ˜"J˜Jšœžœžœžœ˜)šœžœžœžœ˜&Jšœ žœžœžœ˜Jšœ žœžœžœ˜Jšœžœ˜Jšœžœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜Jšœ˜Jšœžœ˜Jšœžœ˜Jšœ žœ˜Jšœ žœžœ˜Jšœžœžœ˜Jšœžœ˜Jšœ žœžœ˜$—J˜Jšœžœžœžœ˜=J˜Jšœžœ"˜AJš œ žœžœžœžœ˜2Jš œžœžœž œžœ˜1Jš œžœžœžœž œ˜(J˜Jš œ žœžœž œžœ˜+Jšœd˜dJ˜Jš œ žœžœžœ žœžœ ˜^š Ÿ œžœž œžœžœ˜IJšœ žœžœ˜Jšœžœ˜J˜Jšœ žœ˜šœ@˜@Jšœžœžœ.˜S—šœ@˜@Jšœžœžœ.˜S—Jšœ+˜+J˜šžœžœžœž˜HJšžœ& ˜7—J˜JšœCžœžœžœ˜TJš žœžœ žœžœ&˜bJ˜Jšœ1˜1Jšžœžœžœ&˜bJ˜Jšœ˜Jšœ!˜!Jšœ˜Jšœ˜—šŸœžœž œžœ˜WJšœ žœžœ˜J˜Jšžœ žœžœžœ˜7JšœFžœžœžœ˜Wšžœžœ˜#Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœžœ˜#Jšœ˜Jšœ˜Jšœ˜Jšœ˜JšœH˜HJšœH˜HJšœK˜K—Jšœ˜—š Ÿœžœž œžœžœ)žœ˜†Jšœ žœžœ˜Jšœ žœ˜Jšœ žœ˜J˜Jšžœ žœžœžœ˜7J˜šžœžœ˜Jšœ˜Jšœ˜—Jš žœžœ žœžœžœžœ˜VJšžœ%˜)J˜šžœž˜ šœ ˜ Jšœ˜Jšœ3žœžœžœ˜AJšœžœžœžœ˜ —J˜šœžœžœžœž˜J˜šœ˜Jšœ˜Jšœ˜Jšœ žœ"˜/Jšœ žœ#˜1Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Jšœ-˜-Jšžœ˜—Jšœ ˜—šŸ œžœž œ0˜MJšœžœ˜Jš œžœžœ žœž œ˜1Jšœžœ˜Jšœžœ˜Jš œžœž œžœžœ˜Cšœžœž œžœ˜-Jšœ žœžœ ˜0—Jšœ žœž œžœ žœžœ žœžœ˜GJšœ%žœ˜)Jšœ žœ˜Jšœ žœ˜J˜Jšžœ žœžœžœ˜7Jšžœžœžœžœ˜BJ˜JšœF˜FJšœD˜DJšœ5žœžœžœ˜DJ˜šžœž˜"Jšœ4˜OJ˜šžœžœ ˜šžœž˜J˜šžœžœžœ˜(Jšœžœ˜ šžœ#žœžœ˜/Jšœžœžœž œ˜>Jšœ;˜;Jšœz˜zJšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜šžœžœ žœ˜%Jšœžœ˜ šžœžœžœ˜$Jšœ3˜3—Jšœ˜Jšœ˜Jšœ˜—J˜šžœžœ žœ˜'Jšœžœ˜ šžœ#žœžœ˜/Jšœžœžœž œ˜>Jšœ;˜;Jšœ|˜|Jšœ˜—Jšœ! ˜-Jšœ˜Jšœ˜—J˜šžœžœžœ˜*šžœžœž˜&Jšœ1žœ˜O—Jšœ˜Jšœ˜—J˜šžœžœžœ ˜$šžœžœž˜&Jšœ1žœ˜O—Jšœ˜Jšœ˜—J˜šžœžœžœ˜ šžœžœžœ˜%Jšœžœ˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜š žœžœžœ žœ˜Ošžœžœž˜#Jšœ˜—Jšœ˜Jšœ˜—J˜šžœ˜šžœžœž˜#Jšœ:˜:—Jšœ&˜&Jšœ˜—J˜šžœ˜šžœ žœžœ˜,Jšœ?˜?Jšœ8žœ(žœ(˜ŒJšœ˜—Jšœ˜Jšœ˜—J˜šžœ˜Jšžœžœžœ ˜CJšœ˜Jšœ˜—J˜šžœžœ ˜šžœžœžœ˜)Jšœ:˜:šœ˜šžœž˜Jšžœ˜Jšžœ˜Jšžœžœ˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—J˜šžœ ˜ Jšœ˜šžœ#žœžœ˜/Jšœžœ ž œ˜/Jšœ;˜;Jšœu˜uJšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜šžœ ˜ šžœžœž˜#Jšœ/˜/—Jšœ˜Jšœ˜Jšœ˜—J˜šžœ˜4Jšœ:˜:šžœžœž˜#Jšœ7˜7—Jšœ%˜%Jšœ˜Jšœ˜—J˜šžœ˜šžœ#žœžœ˜/Jšœžœž œ˜)Jšœžœ ž œ˜/Jšœx˜xJšœ˜—Jšœ˜Jšœ˜—J˜šžœ žœ ˜šžœžœžœ˜(Jšœ:˜:šœ˜šžœž˜Jšžœ˜Jšžœ˜Jšžœžœ˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—J˜šžœ˜šžœžœž˜&Jšœ(˜(—Jšœ˜Jšœ˜—J˜šžœ ˜Jšžœžœžœ˜˜>—Jšœ˜Jšœ˜Jšœ˜—J˜šžœ˜šžœžœžœ˜)Jšœ6˜6šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ —Jšœ˜—Jšœ˜Jšœ˜Jšœ˜—Jšžœ˜—Jšžœ˜—Jšœ ˜—šŸœžœž œ)˜BJšœ žœ˜$Jšœ žœ˜"Jšœ žœž œžœ žœžœ žœžœ˜GJšœ žœ˜Jš œžœž œžœžœ˜IJšœ%žœ˜)J˜Jšžœžœžœžœ˜<šžœž˜Jšœ0˜0šžœž˜šœ˜šžœžœžœ˜"Jšœ4˜4JšœF˜FJšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜šœ˜šžœžœž˜Jšœ#˜#—Jšœ˜Jšœ˜Jšœ˜—J˜šœžœž˜!šžœ˜šžœžœžœ˜"Jšœ6˜6Jšœ^˜^Jšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜šžœ˜šžœžœžœ˜ Jšœ6˜6Jšœ5˜5Jšœ˜—Jšœ˜Jšœ˜Jšœ˜—J˜šžœ˜Jšœ˜J˜šžœžœžœ˜#Jšœ0˜0Jšœžœ˜4Jšœ\˜\JšœŠ˜ŠJ˜—Jšœ˜Jšœ˜—J˜Jšžœžœ˜Jšžœžœ˜Jšžœžœ˜Jšžœžœ˜J˜—Jšžœžœ˜—Jšžœ˜—Jšœ ˜—šŸœžœž œ˜5Jš žœ žœžœžœžœ˜IJš žœ žœžœžœžœ˜IJšœ žœ˜ Jšœ˜—šŸ œž œžœžœ˜BJš žœžœžœ žœžœ$˜FJšœ˜Jš œžœžœžœ žœ˜>Jšœžœ˜šœžœžœž˜*Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšžœžœ˜—šœžœžœž˜4Jšœ ˜ Jšœ˜Jšœ˜Jšžœžœ˜—Jšœ ˜—š Ÿ œž œžœžœž œ˜TJšœžœ˜%šžœžœ%žœ˜1JšœžœžœG˜SJšœ˜—Jšœ˜šžœIž˜OJšžœ+˜0—Jšœ˜—šŸœž œžœžœžœžœžœžœ˜RJšžœžœžœžœ˜C—šŸœž œžœžœžœžœžœžœžœžœ˜TJšžœžœžœžœ˜C—šŸœž œžœžœžœžœžœžœž œ˜[Jšžœžœžœžœ˜D—šŸœž œžœžœ˜>Jšœ žœžœžœ˜%Jšœžœ˜Jšœžœ˜ Jš œ žœž œžœžœžœžœ˜NJ˜Jš žœžœžœžœžœ˜+Jšžœ ˜&Jšœ˜—š Ÿœž œžœžœžœ˜AJšžœžœ ˜/—J˜Jšžœ˜—š ™ Jšœ'™'J™™)J™!J™J™'—J™™)J™R—J™™+J™C—J™™+J™—J™™*J™—J™™+J™-———…—N$ky