<> <> <> DIRECTORY Environment USING [ Block, bitsPerByte, bitsPerWord, Byte, bytesPerPage, bytesPerWord, PageCount, wordsPerPage], FEPSIvOutput, FEPSMergerOps USING [OutputH], Inline USING [BITAND, BITSHIFT, HighHalf, LowByte, LowHalf], Interpress USING [ LongOperator, ShortNumber, shortNumberBias, ShortOperator, Token], NSFile USING [Access, Error, Handle, nullHandle], NSSegment USING [ ByteCount, defaultID, Map, Origin, PageCount, PageNumber, SetSizeInBytes], Runtime USING [CallDebugger], Space USING [Activate, Interval, Kill, nullInterval, Unmap], Stream USING [CompletionCode, Handle, GetBlock], XeroxCompress USING [PutBitsProc]; FEPSIvOutputImpl: PROGRAM IMPORTS Inline, NSFile, NSSegment, Runtime, Space, Stream EXPORTS FEPSIvOutput SHARES Interpress = BEGIN OPEN FEPSIvOutput, Env: Environment, IP: Interpress; <> <> <> <> <> <<=========>> <> <<=========>> readWrite: NSFile.Access = [read: TRUE, write: TRUE]; <<=====>> <> <<=====>> Window: TYPE = RECORD [page: NSSegment.PageNumber, size: NSSegment.PageCount]; <<================>> <> <<================>> bitBuf: CARDINAL ¬ 0; -- buffer containing word being build bitPos: CARDINAL ¬ 0; -- current bit position within bitBuf bufSize: Env.PageCount ¬ 0; -- size of buffer (ie., window) bufAddr: LONG POINTER TO CARDINAL ¬ NIL; -- start of buffer currWindow: Window ¬ [0, 0]; currWrdPtr: LONG POINTER TO CARDINAL ¬ NIL; -- pointer to current word file: NSFile.Handle ¬ NSFile.nullHandle; -- current file handle fileSize: NSSegment.PageCount ¬ 0; -- current size of file endWrdPtr: LONG POINTER TO CARDINAL ¬ NIL; -- pointer to last word in buffer growSize: NSSegment.PageCount ¬ 0; -- size file should grow by mapUnit: Space.Interval ¬ Space.nullInterval; -- current mapUnit <<======>> <> <<======>> Exception: PUBLIC SIGNAL [code: ExceptionKind] = CODE; <<==========>> <> <<==========>> <<=====>> AppendShortNumber: PROCEDURE [n: IP.ShortNumber] = BEGIN shortSeq: shortNumber IP.Token ¬ [shortNumber[number: n + IP.shortNumberBias]]; PutWord[shortSeq]; END; -- AppendShortNumber <<=====>> ByteAlign: PROCEDURE = INLINE BEGIN IF bitPos MOD Env.bitsPerByte # 0 THEN PutBits[0, 4]; END; -- ByteAlign <<=====>> BringNewWindow: PROCEDURE [window: Window] RETURNS [addr: LONG POINTER, endAddr: LONG POINTER, newWindow: Window] = BEGIN origin: NSSegment.Origin ¬ [ file, window.page, window.size, NSSegment.defaultID]; IF mapUnit.pointer # NIL THEN mapUnit.pointer ¬ Space.Unmap[mapUnit.pointer]; mapUnit ¬ NSSegment.Map[origin: origin, access: readWrite]; Space.Activate[mapUnit]; newWindow.page ¬ window.page; newWindow.size ¬ mapUnit.count; addr ¬ mapUnit.pointer; endAddr ¬ addr + (newWindow.size * Env.wordsPerPage); END; -- BringNewWindow <<=====>> GetNextWindow: PROCEDURE = BEGIN newPageNum: NSSegment.PageNumber ¬ currWindow.page + currWindow.size; <> IF newPageNum + bufSize > fileSize THEN { IF mapUnit.pointer # NIL THEN { -- unmap first in case of no resources mapUnit.pointer ¬ Space.Unmap[mapUnit.pointer]; mapUnit ¬ Space.nullInterval;}; fileSize ¬ GrowFileSize[fileSize, growSize];}; <> [bufAddr, endWrdPtr, currWindow] ¬ BringNewWindow[[newPageNum, bufSize]]; currWrdPtr ¬ bufAddr; END; -- GetNextWindow <<=====>> GrowFileSize: PROCEDURE [size: NSSegment.PageCount, incr: NSSegment.PageCount] RETURNS [newSize: NSSegment.PageCount] = BEGIN <> <> <> <> <> <> newIncr: NSSegment.PageCount ¬ incr; minSize: NSSegment.PageCount ¬ bufSize; NSSegment.SetSizeInBytes[ file: file, bytes: (size + newIncr) * Env.bytesPerPage ! NSFile.Error => { WITH errorRec: error SELECT FROM space => { IF errorRec.problem = mediumFull THEN { newIncr ¬ newIncr / 2; -- try getting smaller chunk IF newIncr < minSize THEN { <> SIGNAL Exception[noResources]; newIncr ¬ incr}; RETRY;} -- assume that we have enough now ELSE SIGNAL Exception[unknown]; } -- space ENDCASE => SIGNAL Exception[unknown]; }]; newSize ¬ size + newIncr; END; -- GrowFileSize <<=================>> <> <<=================>> <<=====>> CloseOutput: PUBLIC PROCEDURE = BEGIN byteSize: NSSegment.ByteCount; <> <> <> IF bitPos # 0 THEN currWrdPtr­ ¬ bitBuf; byteSize ¬ (currWindow.page * Env.bytesPerPage) + ((currWrdPtr - bufAddr) * Env.bytesPerWord); IF bitPos # 0 THEN byteSize ¬ byteSize + 1; IF mapUnit.pointer # NIL THEN mapUnit.pointer ¬ Space.Unmap[mapUnit.pointer]; mapUnit ¬ Space.nullInterval; NSSegment.SetSizeInBytes[file: file, bytes: byteSize]; END; -- CloseOutput <<=====>> EmptyOutput: PUBLIC PROCEDURE = BEGIN IF mapUnit.pointer # NIL THEN { Space.Kill[mapUnit]; mapUnit.pointer ¬ Space.Unmap[mapUnit.pointer];}; mapUnit ¬ Space.nullInterval; NSSegment.SetSizeInBytes[file: file, bytes: 0]; END; -- EmptyOutput <<===== >> GetCurrentPosition: PUBLIC PROCEDURE RETURNS [pos: Position] = BEGIN ByteAlign[]; pos.offset ¬ (currWrdPtr - bufAddr) * Env.bytesPerWord; IF bitPos # 0 THEN pos.offset ¬ pos.offset + 1; <> pos.page ¬ currWindow.page + (pos.offset / Env.bytesPerPage); pos.offset ¬ pos.offset MOD Env.bytesPerPage; END; -- GetCurrentPosition <<=====>> Initialize: PUBLIC PROCEDURE [ output: FEPSMergerOps.OutputH, initialSize: NSSegment.PageCount, growIncrement: NSSegment.PageCount, bufferSize: NSSegment.PageCount] = BEGIN origin: NSSegment.Origin; growSize ¬ growIncrement; bufSize ¬ bufferSize; file ¬ output.ivMasterH; fileSize ¬ GrowFileSize[0, MAX[initialSize, bufSize]]; <> origin ¬ [file: file, base: 0, count: bufSize]; mapUnit ¬ NSSegment.Map[origin: origin, access: readWrite]; <<***** TEMPORARY *****>> IF mapUnit.count # origin.count THEN Runtime.CallDebugger["Map unit mismatch in Initialize."L]; Space.Activate[mapUnit]; currWindow ¬ [0, mapUnit.count]; currWrdPtr ¬ bufAddr ¬ mapUnit.pointer; endWrdPtr ¬ bufAddr + (currWindow.size * Env.wordsPerPage); bitBuf ¬ 0; bitPos ¬ 0; END; -- Initialize <<===== >> PutBits: PUBLIC XeroxCompress.PutBitsProc = BEGIN remainder: INTEGER; currBitPos: INTEGER ¬ bitPos + bits; -- current bit position remainder ¬ Env.bitsPerWord - currBitPos; <> SELECT TRUE FROM (remainder > 0) => -- Incomplete BEGIN bitBuf ¬ bitBuf + Inline.BITSHIFT[val, remainder]; bitPos ¬ currBitPos; END; (remainder = 0) => -- Full BEGIN currWrdPtr­ ¬ bitBuf + val; currWrdPtr ¬ currWrdPtr + 1; IF currWrdPtr = endWrdPtr THEN GetNextWindow[]; bitBuf ¬ 0; bitPos ¬ 0; END; ENDCASE => -- Overflow BEGIN bitPos ¬ -remainder; currWrdPtr­ ¬ bitBuf + Inline.BITSHIFT[val, remainder]; bitBuf ¬ Inline.BITSHIFT[val, Env.bitsPerWord - bitPos]; currWrdPtr ¬ currWrdPtr + 1; IF currWrdPtr = endWrdPtr THEN GetNextWindow[]; END; END; -- PutBits <<===== >> PutByte: PUBLIC PROCEDURE [val: CARDINAL] = BEGIN <> ByteAlign[]; PutBits[val, 8]; END; -- PutByte <<=====>> PutWord: PUBLIC PROCEDURE [val: UNSPECIFIED] = BEGIN ByteAlign[]; PutBits[val, 16]; END; -- PutWord <<===== >> Retrieve: PUBLIC PROCEDURE [inputSH: Stream.Handle, byteCount: LONG CARDINAL] = BEGIN <> block: Env.Block; bytesMoved: CARDINAL ¬ 0; start: CARDINAL ¬ 0; LMin: PROC [l: LONG CARDINAL, c: CARDINAL] RETURNS [r: CARDINAL] = { IF l > c THEN r ¬ c ELSE r ¬ Inline.LowHalf[l]}; <> ByteAlign[]; <> IF bitPos # 0 THEN {currWrdPtr­ ¬ bitBuf; start ¬ 1} ELSE start ¬ 0; <> <> IF byteCount = LAST[LONG CARDINAL] THEN byteCount ¬ byteCount - 1; DO status: Stream.CompletionCode; endIndexPlusOne: CARDINAL; block.blockPointer ¬ LOOPHOLE[currWrdPtr]; block.startIndex ¬ start; endIndexPlusOne ¬ Inline.LowHalf[(endWrdPtr - currWrdPtr)] * Env.bytesPerWord; block.stopIndexPlusOne ¬ LMin[byteCount + block.startIndex, endIndexPlusOne]; [bytesMoved, status] ¬ Stream.GetBlock[inputSH, block]; byteCount ¬ byteCount - bytesMoved; currWrdPtr ¬ currWrdPtr + (block.startIndex + bytesMoved) / Env.bytesPerWord; <> IF currWrdPtr = endWrdPtr THEN {GetNextWindow[]; bitBuf ¬ 0; bitPos ¬ 0}; IF (status = endOfStream) OR byteCount = 0 THEN EXIT; start ¬ 0; ENDLOOP; -- while bytes left <> bitPos ¬ ((block.startIndex + bytesMoved) MOD Env.bytesPerWord) * Env.bitsPerByte; IF bitPos # 0 THEN bitBuf ¬ Inline.BITAND[currWrdPtr­, 177400B] ELSE bitBuf ¬ 0; END; -- Retrieve <<===== >> SetPosition: PUBLIC PROCEDURE [pos: Position] = BEGIN <> <<>> <> IF bitPos # 0 THEN currWrdPtr­ ¬ Inline.BITAND[currWrdPtr­, 377B] + bitBuf; <> IF pos.page + bufSize > fileSize THEN fileSize ¬ GrowFileSize[fileSize, growSize]; -- grow file <> [bufAddr, endWrdPtr, currWindow] ¬ BringNewWindow[[pos.page, bufSize]]; currWrdPtr ¬ bufAddr + (pos.offset / Env.bytesPerWord); <> bitPos ¬ Inline.LowHalf[(pos.offset MOD Env.bytesPerWord) * Env.bitsPerByte]; IF bitPos = 0 THEN bitBuf ¬ 0 ELSE {bitBuf ¬ Inline.BITAND[currWrdPtr­, 177400B]}; END; -- SetPosition <> <<===== >> IPIdentifier: PUBLIC PROCEDURE [s: LONG STRING] = BEGIN OPEN Inline; shortToken: shortSequence operatorOrSequence IP.Token ¬ [ operatorOrSequence[ shortSequence[ type: sequenceIdentifier, length: LowByte[LowHalf[s.length]]]]]; PutWord[shortToken]; FOR i: CARDINAL IN [0..s.length) DO PutByte[LOOPHOLE[s[i], Env.Byte]]; ENDLOOP; END; -- IPIdentifier <<=====>> IPInteger: PUBLIC PROCEDURE [n: LONG INTEGER, length: CARDINAL ¬ 0] = BEGIN IF (length = 1) OR (length = 0 AND n IN [-IP.shortNumberBias..(LAST[INTEGER] - IP.shortNumberBias)]) THEN AppendShortNumber[Inline.LowHalf[n]] ELSE { shortSeq: shortSequence operatorOrSequence IP.Token; IF length = 0 THEN length ¬ IF n IN [FIRST[INTEGER]..LAST[INTEGER]] THEN 2 ELSE 4; shortSeq ¬ [ operatorOrSequence[shortSequence[type: sequenceInteger, length: length]]]; PutWord[shortSeq]; IF length = 4 THEN PutWord[Inline.HighHalf[n]]; PutWord[Inline.LowHalf[n]]; }; END; -- IPInteger <<=====>> IPSeqCompressedPixel: PUBLIC PROCEDURE [size: LONG CARDINAL] = BEGIN longSeq: longSequence operatorOrSequence IP.Token ¬ [ operatorOrSequence[ longSequence[ type: sequenceCompressedPixelVector, lengthHigh: Inline.HighHalf[size], lengthLow: Inline.LowHalf[size]]]]; ptrToToken: LONG POINTER ¬ @longSeq; ptr: LONG POINTER TO LONG CARDINAL ¬ LOOPHOLE[ptrToToken]; PutWord[Inline.LowHalf[ptr­]]; PutWord[Inline.HighHalf[ptr­]]; END; -- IPSeqCompressedPixel <<=====>> OpOnly: PUBLIC PROCEDURE [code: Interpress.LongOperator] = BEGIN IF code IN IP.ShortOperator THEN { sOp: shortOperator operatorOrSequence IP.Token ¬ [ operatorOrSequence[shortOperator[operator: code]]]; pOp: POINTER TO PACKED ARRAY [0..1] OF Environment.Byte ¬ LOOPHOLE[@sOp]; PutByte[pOp[0]]} ELSE { lOp: longOperator operatorOrSequence IP.Token ¬ [ operatorOrSequence[longOperator[operator: code]]]; PutWord[lOp]; }; END; -- OpOnly END... LOG 20Nov84 - Okamoto - Changed FreeOutput to CloseOutput and added EmptyOutput. 22Jan85 - Okamoto - Changed so that mapUnit is unmapped before set size in EmptyOutput and GrowFileSize call in GetNextWindow. 10Jul85 - castillo - copyright notice.