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]; 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. dFEPSIvOutputImpl.mesa Copyright (C) 1985 by Xerox Corporation. All rights reserved. last edited by castillo 10-Jul-85 9:57:12 This module exports the interface FEPSIvOutput. The procedures in the interface implements the FEPS output routines whose primary function is to write data to the output interleaved master. This implementation uses NS Filing routines to do the I/O. ========= CONSTANTS ========= ===== TYPES ===== ================ GLOBAL VARIABLES ================ ====== SIGNAL ====== ========== PROCEDURES ========== ===== ===== ===== ===== see if we have enough pages allocated to the file change mapping ===== This routine will increase the size of a file by "incr". If the request cannot be satisfied, then the increment is reduced by two. If the increment is bufSize and there is still no enough disk space, then signal is raised. The routine catching the signal may wait until disk space is available. indicate that we can't ================= PUBLIC PROCEDURES ================= ===== flush out bit buffer Assume that it is byte aligned now (kluge because we know it is true due to its use). ===== ===== Get the nearest page ===== create the mapUnit and map to start of file ***** TEMPORARY ***** ===== Processing is funtion of resulting buffer word position ===== see if at byte boundary ===== ===== Retrieve byteCount bytes from stream to output byte align flush out current bit buffer if not word aligned kluge to avoid overflow in case byteCount is LAST[LONG CARDINAL] If so, it is assumed to mean retrieve til EOF. if output buffer is full, get a new one if one byte is left over, write it out to buffer ===== Set the output to the specified position Make sure current bit buffer is written out see if we have enough pages allocated to the file change mapping see if at word boundary Interpress output routines ===== ===== ===== ===== Ê ¥˜Jšœ™Jšœ>™>Jšœ,™,J˜šÏk ˜ šœ œ˜J˜MJ˜—J˜ Jšœœ ˜Jšœœœœ˜<šœ œ˜J˜B—Jšœœ%˜1šœ œ˜J˜J—Jšœœ˜Jšœœ1˜Jš˜J˜ J˜7Jšœ œ˜/Jšœ™J˜=Jšœœ˜-JšœŸ˜——˜Jšœ™šž œœ œ˜J˜@J˜FJš˜J˜J˜J˜J˜Jšœœ˜6Jšœ+™+J˜/J˜;Jšœ™šœ˜$J˜:—J˜J˜ J˜'J˜;J˜ J˜ JšœŸ ˜——˜Jšœ ™ šžœœ˜+Jš˜Jšœ œ˜Jšœ œŸ˜=J˜)Jšœ7™7šœœ˜šœŸ ˜!Jš˜Jšœœ˜2J˜Jšœ˜—šœŸ˜Jš˜J˜J˜Jšœœ˜/J˜ J˜ Jšœ˜—šœŸ ˜Jš˜J˜Jšœœ˜7Jšœœ ˜8J˜Jšœœ˜/Jšœ˜————˜JšœŸ ˜—˜Jšœ™šžœœ œœ˜+Jš˜Jšœ™J˜ J˜JšœŸ ˜——˜Jšœ™šžœœ œ œ˜.Jšœ œŸ ˜5——˜Jšœ™š žœœ œ%œœ˜OJš˜Jšœ.™.J˜Jšœ œ˜Jšœœ˜——˜šžœœœœœœœ˜DJšœœœ˜0——J˜˜Jšœ ™ J˜ Jšœ0™0Jšœ œ#œ ˜DJšœ@™@Jšœ.™.Jš œ œœœœ˜Bš˜J˜Jšœœ˜Jšœœ ˜*J˜˜J˜<—J˜MJ˜7J˜#J˜MJšœ'™'Jšœœ+˜IJšœœœœ˜5J˜ JšœŸ˜—Jšœ0™0˜Jšœ!œ%˜I—Jšœ œœ˜?Jšœ ˜JšœŸ ˜—˜Jšœ ™ šž œœ œ˜/Jš˜Jšœ(™(J™Jšœ+™+Jšœ œœ˜KJšœ1™1šœ˜%Jšœ.Ÿ ˜:—Jšœ™J˜GJ˜7Jšœ™Jšœ$œ&˜MJšœ œ ˜Jšœœ˜4JšœŸ˜——˜Jšœ™—˜Jšœ™š ž œœ œœœ˜1Jšœœ˜šœ-œ ˜9J˜J˜J˜@—J˜Jš œœœœ œœ˜OJšœŸ˜——˜Jšœ™š ž œœ œœœ œ˜EJš˜šœ ˜š˜˜ Jš œœœœœœ˜E——Jšœ%˜)—šœ˜Jšœ+œ˜4šœ ˜Jšœ œœœœœœœœ˜?—˜ J˜J—J˜Jšœ œ˜/J˜J˜—JšœŸ ˜——˜Jšœ™š žœœ œœœ˜>Jš˜šœ)œ ˜5J˜J˜ J˜GJ˜#—Jšœ œœ ˜$Jš œœœœœœœ ˜:J˜J˜JšœŸ˜——˜Jšœ™šžœœ œ"˜:Jš˜šœœœœ˜"šœ&œ ˜2J˜3—Jš œœœœœœœ˜IJ˜—šœ˜šœ%œ ˜1J˜2—J˜ J˜—JšœŸ ˜——˜Jšœ˜J˜—Jšœ˜J˜LJ˜J˜&—…—'È;Ñ